mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
1a07f2d96e
Use the ftrace infrastructure to conditionally trace ufs command events. New trace event is created, which samples the following ufs command data: - device name - optional identification string - task tag - doorbell register - number of transfer bytes - interrupt status register - request start LBA - command opcode Currently we only fully trace read(10) and write(10) commands. All other commands which pass through ufshcd_send_command() will be printed with "-1" in the lba and transfer_len fields. Usage: echo 1 > /sys/kernel/debug/tracing/events/ufs/enable cat /sys/kernel/debug/tracing/trace_pipe Signed-off-by: Lee Susman <lsusman@codeaurora.org> Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
263 lines
6.9 KiB
C
263 lines
6.9 KiB
C
/*
|
|
* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
* only version 2 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#undef TRACE_SYSTEM
|
|
#define TRACE_SYSTEM ufs
|
|
|
|
#if !defined(_TRACE_UFS_H) || defined(TRACE_HEADER_MULTI_READ)
|
|
#define _TRACE_UFS_H
|
|
|
|
#include <linux/tracepoint.h>
|
|
|
|
#define UFS_LINK_STATES \
|
|
EM(UIC_LINK_OFF_STATE) \
|
|
EM(UIC_LINK_ACTIVE_STATE) \
|
|
EMe(UIC_LINK_HIBERN8_STATE)
|
|
|
|
#define UFS_PWR_MODES \
|
|
EM(UFS_ACTIVE_PWR_MODE) \
|
|
EM(UFS_SLEEP_PWR_MODE) \
|
|
EMe(UFS_POWERDOWN_PWR_MODE)
|
|
|
|
#define UFSCHD_CLK_GATING_STATES \
|
|
EM(CLKS_OFF) \
|
|
EM(CLKS_ON) \
|
|
EM(REQ_CLKS_OFF) \
|
|
EMe(REQ_CLKS_ON)
|
|
|
|
/* Enums require being exported to userspace, for user tool parsing */
|
|
#undef EM
|
|
#undef EMe
|
|
#define EM(a) TRACE_DEFINE_ENUM(a);
|
|
#define EMe(a) TRACE_DEFINE_ENUM(a);
|
|
|
|
UFS_LINK_STATES;
|
|
UFS_PWR_MODES;
|
|
UFSCHD_CLK_GATING_STATES;
|
|
|
|
/*
|
|
* Now redefine the EM() and EMe() macros to map the enums to the strings
|
|
* that will be printed in the output.
|
|
*/
|
|
#undef EM
|
|
#undef EMe
|
|
#define EM(a) { a, #a },
|
|
#define EMe(a) { a, #a }
|
|
|
|
TRACE_EVENT(ufshcd_clk_gating,
|
|
|
|
TP_PROTO(const char *dev_name, int state),
|
|
|
|
TP_ARGS(dev_name, state),
|
|
|
|
TP_STRUCT__entry(
|
|
__string(dev_name, dev_name)
|
|
__field(int, state)
|
|
),
|
|
|
|
TP_fast_assign(
|
|
__assign_str(dev_name, dev_name);
|
|
__entry->state = state;
|
|
),
|
|
|
|
TP_printk("%s: gating state changed to %s",
|
|
__get_str(dev_name),
|
|
__print_symbolic(__entry->state, UFSCHD_CLK_GATING_STATES))
|
|
);
|
|
|
|
TRACE_EVENT(ufshcd_clk_scaling,
|
|
|
|
TP_PROTO(const char *dev_name, const char *state, const char *clk,
|
|
u32 prev_state, u32 curr_state),
|
|
|
|
TP_ARGS(dev_name, state, clk, prev_state, curr_state),
|
|
|
|
TP_STRUCT__entry(
|
|
__string(dev_name, dev_name)
|
|
__string(state, state)
|
|
__string(clk, clk)
|
|
__field(u32, prev_state)
|
|
__field(u32, curr_state)
|
|
),
|
|
|
|
TP_fast_assign(
|
|
__assign_str(dev_name, dev_name);
|
|
__assign_str(state, state);
|
|
__assign_str(clk, clk);
|
|
__entry->prev_state = prev_state;
|
|
__entry->curr_state = curr_state;
|
|
),
|
|
|
|
TP_printk("%s: %s %s from %u to %u Hz",
|
|
__get_str(dev_name), __get_str(state), __get_str(clk),
|
|
__entry->prev_state, __entry->curr_state)
|
|
);
|
|
|
|
TRACE_EVENT(ufshcd_auto_bkops_state,
|
|
|
|
TP_PROTO(const char *dev_name, const char *state),
|
|
|
|
TP_ARGS(dev_name, state),
|
|
|
|
TP_STRUCT__entry(
|
|
__string(dev_name, dev_name)
|
|
__string(state, state)
|
|
),
|
|
|
|
TP_fast_assign(
|
|
__assign_str(dev_name, dev_name);
|
|
__assign_str(state, state);
|
|
),
|
|
|
|
TP_printk("%s: auto bkops - %s",
|
|
__get_str(dev_name), __get_str(state))
|
|
);
|
|
|
|
DECLARE_EVENT_CLASS(ufshcd_profiling_template,
|
|
TP_PROTO(const char *dev_name, const char *profile_info, s64 time_us,
|
|
int err),
|
|
|
|
TP_ARGS(dev_name, profile_info, time_us, err),
|
|
|
|
TP_STRUCT__entry(
|
|
__string(dev_name, dev_name)
|
|
__string(profile_info, profile_info)
|
|
__field(s64, time_us)
|
|
__field(int, err)
|
|
),
|
|
|
|
TP_fast_assign(
|
|
__assign_str(dev_name, dev_name);
|
|
__assign_str(profile_info, profile_info);
|
|
__entry->time_us = time_us;
|
|
__entry->err = err;
|
|
),
|
|
|
|
TP_printk("%s: %s: took %lld usecs, err %d",
|
|
__get_str(dev_name), __get_str(profile_info),
|
|
__entry->time_us, __entry->err)
|
|
);
|
|
|
|
DEFINE_EVENT(ufshcd_profiling_template, ufshcd_profile_hibern8,
|
|
TP_PROTO(const char *dev_name, const char *profile_info, s64 time_us,
|
|
int err),
|
|
TP_ARGS(dev_name, profile_info, time_us, err));
|
|
|
|
DEFINE_EVENT(ufshcd_profiling_template, ufshcd_profile_clk_gating,
|
|
TP_PROTO(const char *dev_name, const char *profile_info, s64 time_us,
|
|
int err),
|
|
TP_ARGS(dev_name, profile_info, time_us, err));
|
|
|
|
DEFINE_EVENT(ufshcd_profiling_template, ufshcd_profile_clk_scaling,
|
|
TP_PROTO(const char *dev_name, const char *profile_info, s64 time_us,
|
|
int err),
|
|
TP_ARGS(dev_name, profile_info, time_us, err));
|
|
|
|
DECLARE_EVENT_CLASS(ufshcd_template,
|
|
TP_PROTO(const char *dev_name, int err, s64 usecs,
|
|
int dev_state, int link_state),
|
|
|
|
TP_ARGS(dev_name, err, usecs, dev_state, link_state),
|
|
|
|
TP_STRUCT__entry(
|
|
__field(s64, usecs)
|
|
__field(int, err)
|
|
__string(dev_name, dev_name)
|
|
__field(int, dev_state)
|
|
__field(int, link_state)
|
|
),
|
|
|
|
TP_fast_assign(
|
|
__entry->usecs = usecs;
|
|
__entry->err = err;
|
|
__assign_str(dev_name, dev_name);
|
|
__entry->dev_state = dev_state;
|
|
__entry->link_state = link_state;
|
|
),
|
|
|
|
TP_printk(
|
|
"%s: took %lld usecs, dev_state: %s, link_state: %s, err %d",
|
|
__get_str(dev_name),
|
|
__entry->usecs,
|
|
__print_symbolic(__entry->dev_state, UFS_PWR_MODES),
|
|
__print_symbolic(__entry->link_state, UFS_LINK_STATES),
|
|
__entry->err
|
|
)
|
|
);
|
|
|
|
DEFINE_EVENT(ufshcd_template, ufshcd_system_suspend,
|
|
TP_PROTO(const char *dev_name, int err, s64 usecs,
|
|
int dev_state, int link_state),
|
|
TP_ARGS(dev_name, err, usecs, dev_state, link_state));
|
|
|
|
DEFINE_EVENT(ufshcd_template, ufshcd_system_resume,
|
|
TP_PROTO(const char *dev_name, int err, s64 usecs,
|
|
int dev_state, int link_state),
|
|
TP_ARGS(dev_name, err, usecs, dev_state, link_state));
|
|
|
|
DEFINE_EVENT(ufshcd_template, ufshcd_runtime_suspend,
|
|
TP_PROTO(const char *dev_name, int err, s64 usecs,
|
|
int dev_state, int link_state),
|
|
TP_ARGS(dev_name, err, usecs, dev_state, link_state));
|
|
|
|
DEFINE_EVENT(ufshcd_template, ufshcd_runtime_resume,
|
|
TP_PROTO(const char *dev_name, int err, s64 usecs,
|
|
int dev_state, int link_state),
|
|
TP_ARGS(dev_name, err, usecs, dev_state, link_state));
|
|
|
|
DEFINE_EVENT(ufshcd_template, ufshcd_init,
|
|
TP_PROTO(const char *dev_name, int err, s64 usecs,
|
|
int dev_state, int link_state),
|
|
TP_ARGS(dev_name, err, usecs, dev_state, link_state));
|
|
|
|
TRACE_EVENT(ufshcd_command,
|
|
TP_PROTO(const char *dev_name, const char *str, unsigned int tag,
|
|
u32 doorbell, int transfer_len, u32 intr, u64 lba,
|
|
u8 opcode),
|
|
|
|
TP_ARGS(dev_name, str, tag, doorbell, transfer_len, intr, lba, opcode),
|
|
|
|
TP_STRUCT__entry(
|
|
__string(dev_name, dev_name)
|
|
__string(str, str)
|
|
__field(unsigned int, tag)
|
|
__field(u32, doorbell)
|
|
__field(int, transfer_len)
|
|
__field(u32, intr)
|
|
__field(u64, lba)
|
|
__field(u8, opcode)
|
|
),
|
|
|
|
TP_fast_assign(
|
|
__assign_str(dev_name, dev_name);
|
|
__assign_str(str, str);
|
|
__entry->tag = tag;
|
|
__entry->doorbell = doorbell;
|
|
__entry->transfer_len = transfer_len;
|
|
__entry->intr = intr;
|
|
__entry->lba = lba;
|
|
__entry->opcode = opcode;
|
|
),
|
|
|
|
TP_printk(
|
|
"%s: %s: tag: %u, DB: 0x%x, size: %d, IS: %u, LBA: %llu, opcode: 0x%x",
|
|
__get_str(str), __get_str(dev_name), __entry->tag,
|
|
__entry->doorbell, __entry->transfer_len,
|
|
__entry->intr, __entry->lba, (u32)__entry->opcode
|
|
)
|
|
);
|
|
|
|
#endif /* if !defined(_TRACE_UFS_H) || defined(TRACE_HEADER_MULTI_READ) */
|
|
|
|
/* This part must be outside protection */
|
|
#include <trace/define_trace.h>
|