Use the ftrace infrastructure to conditionally trace UFS UIC command events. New trace event "ufshcd_uic_command" is created, which samples the following UFS UIC command data: - Device name - Optional identification string - UIC command opcode - UIC command argument1 - UIC command argument2 - UIC command argement3 - UIC command execution result Usage: echo 1 > /sys/kernel/debug/tracing/events/ufs/enable cat /sys/kernel/debug/tracing/trace_pipe Signed-off-by: Stanley Chu <stanley.chu@xxxxxxxxxxxx> --- drivers/scsi/ufs/ufshcd.c | 29 +++++++++++++++++++++++++++++ include/trace/events/ufs.h | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index c197a3315d21..181617966658 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -339,6 +339,27 @@ static void ufshcd_add_tm_upiu_trace(struct ufs_hba *hba, unsigned int tag, &descp->input_param1); } +static void ufshcd_add_uic_command_trace(struct ufs_hba *hba, + struct uic_command *ucmd, + const char *str) +{ + u32 cmd; + + if (!trace_ufshcd_uic_command_enabled()) + return; + + if (!strcmp(str, "uic_send")) + cmd = ucmd->command; + else + cmd = ufshcd_readl(hba, REG_UIC_COMMAND); + + trace_ufshcd_uic_command(dev_name(hba->dev), str, cmd, + ucmd->result, + ufshcd_readl(hba, REG_UIC_COMMAND_ARG_1), + ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2), + ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3)); +} + static void ufshcd_add_command_trace(struct ufs_hba *hba, unsigned int tag, const char *str) { @@ -2054,6 +2075,8 @@ ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) /* Write UIC Cmd */ ufshcd_writel(hba, uic_cmd->command & COMMAND_OPCODE_MASK, REG_UIC_COMMAND); + + ufshcd_add_uic_command_trace(hba, uic_cmd, "uic_send"); } /** @@ -2080,6 +2103,9 @@ ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) hba->active_uic_cmd = NULL; spin_unlock_irqrestore(hba->host->host_lock, flags); + uic_cmd->result = ret; + ufshcd_add_uic_command_trace(hba, uic_cmd, "uic_complete"); + return ret; } @@ -3760,6 +3786,9 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd) ret = (status != PWR_OK) ? status : -1; } out: + cmd->result = ret; + ufshcd_add_uic_command_trace(hba, cmd, "uic_complete"); + if (ret) { ufshcd_print_host_state(hba); ufshcd_print_pwr_info(hba); diff --git a/include/trace/events/ufs.h b/include/trace/events/ufs.h index 5f300739240d..cf8d568d5a13 100644 --- a/include/trace/events/ufs.h +++ b/include/trace/events/ufs.h @@ -249,6 +249,39 @@ TRACE_EVENT(ufshcd_command, ) ); +TRACE_EVENT(ufshcd_uic_command, + TP_PROTO(const char *dev_name, const char *str, u32 cmd, int result, + u32 arg1, u32 arg2, u32 arg3), + + TP_ARGS(dev_name, str, cmd, result, arg1, arg2, arg3), + + TP_STRUCT__entry( + __string(dev_name, dev_name) + __string(str, str) + __field(u32, cmd) + __field(int, result) + __field(u32, arg1) + __field(u32, arg2) + __field(u32, arg3) + ), + + TP_fast_assign( + __assign_str(dev_name, dev_name); + __assign_str(str, str); + __entry->cmd = cmd; + __entry->result = result; + __entry->arg1 = arg1; + __entry->arg2 = arg2; + __entry->arg3 = arg3; + ), + + TP_printk( + "%s: %s: cmd: 0x%x, arg1: 0x%x, arg2: 0x%x, arg3: 0x%x, result: %d", + __get_str(str), __get_str(dev_name), __entry->cmd, + __entry->arg1, __entry->arg2, __entry->arg3, __entry->result + ) +); + TRACE_EVENT(ufshcd_upiu, TP_PROTO(const char *dev_name, const char *str, void *hdr, void *tsf), -- 2.18.0