Commit 1a07f2d9 authored by Lee Susman's avatar Lee Susman Committed by Martin K. Petersen

scsi: ufs: add trace event for ufs commands

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: default avatarLee Susman <lsusman@codeaurora.org>
Signed-off-by: default avatarSubhash Jadavani <subhashj@codeaurora.org>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 911a0771
...@@ -293,6 +293,41 @@ static inline void ufshcd_remove_non_printable(char *val) ...@@ -293,6 +293,41 @@ static inline void ufshcd_remove_non_printable(char *val)
*val = ' '; *val = ' ';
} }
static void ufshcd_add_command_trace(struct ufs_hba *hba,
unsigned int tag, const char *str)
{
sector_t lba = -1;
u8 opcode = 0;
u32 intr, doorbell;
struct ufshcd_lrb *lrbp;
int transfer_len = -1;
if (!trace_ufshcd_command_enabled())
return;
lrbp = &hba->lrb[tag];
if (lrbp->cmd) { /* data phase exists */
opcode = (u8)(*lrbp->cmd->cmnd);
if ((opcode == READ_10) || (opcode == WRITE_10)) {
/*
* Currently we only fully trace read(10) and write(10)
* commands
*/
if (lrbp->cmd->request && lrbp->cmd->request->bio)
lba =
lrbp->cmd->request->bio->bi_iter.bi_sector;
transfer_len = be32_to_cpu(
lrbp->ucd_req_ptr->sc.exp_data_transfer_len);
}
}
intr = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
trace_ufshcd_command(dev_name(hba->dev), str, tag,
doorbell, transfer_len, intr, lba, opcode);
}
static void ufshcd_print_host_regs(struct ufs_hba *hba) static void ufshcd_print_host_regs(struct ufs_hba *hba)
{ {
/* /*
...@@ -1166,6 +1201,7 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) ...@@ -1166,6 +1201,7 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL); ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
/* Make sure that doorbell is committed immediately */ /* Make sure that doorbell is committed immediately */
wmb(); wmb();
ufshcd_add_command_trace(hba, task_tag, "send");
} }
/** /**
...@@ -3955,6 +3991,7 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, ...@@ -3955,6 +3991,7 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
lrbp = &hba->lrb[index]; lrbp = &hba->lrb[index];
cmd = lrbp->cmd; cmd = lrbp->cmd;
if (cmd) { if (cmd) {
ufshcd_add_command_trace(hba, index, "complete");
result = ufshcd_transfer_rsp_status(hba, lrbp); result = ufshcd_transfer_rsp_status(hba, lrbp);
scsi_dma_unmap(cmd); scsi_dma_unmap(cmd);
cmd->result = result; cmd->result = result;
...@@ -3966,8 +4003,11 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, ...@@ -3966,8 +4003,11 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
__ufshcd_release(hba); __ufshcd_release(hba);
} else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE || } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE ||
lrbp->command_type == UTP_CMD_TYPE_UFS_STORAGE) { lrbp->command_type == UTP_CMD_TYPE_UFS_STORAGE) {
if (hba->dev_cmd.complete) if (hba->dev_cmd.complete) {
ufshcd_add_command_trace(hba, index,
"dev_complete");
complete(hba->dev_cmd.complete); complete(hba->dev_cmd.complete);
}
} }
} }
......
...@@ -219,6 +219,44 @@ DEFINE_EVENT(ufshcd_template, ufshcd_init, ...@@ -219,6 +219,44 @@ DEFINE_EVENT(ufshcd_template, ufshcd_init,
TP_PROTO(const char *dev_name, int err, s64 usecs, TP_PROTO(const char *dev_name, int err, s64 usecs,
int dev_state, int link_state), int dev_state, int link_state),
TP_ARGS(dev_name, err, usecs, dev_state, 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) */ #endif /* if !defined(_TRACE_UFS_H) || defined(TRACE_HEADER_MULTI_READ) */
/* This part must be outside protection */ /* This part must be outside protection */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment