scsi: ufs: add queue fullness statistics
Add more statistics to allow tracking of tags occupancy upon sending a new request. The statistics is kept separately for 4 types of requests: read, write, urgent and flush. All will consist only of data requests (eg. read, write, urgent). This statistic is an enhancement of current tag statistic and uses same infrastructure. Change-Id: If5cea4aec4e94081d568a3661584b31665becfc6 Signed-off-by: Dolev Raviv <draviv@codeaurora.org> [subhashj@codeaurora.org: resolved trivial merge conflicts] Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
This commit is contained in:
parent
8045d7daab
commit
0c8a317ea9
3 changed files with 113 additions and 35 deletions
|
@ -169,15 +169,17 @@ static void ufsdbg_setup_fault_injection(struct ufs_hba *hba)
|
|||
#endif /* CONFIG_UFS_FAULT_INJECTION */
|
||||
|
||||
#define BUFF_LINE_CAPACITY 16
|
||||
#define TAB_CHARS 8
|
||||
|
||||
static int ufsdbg_tag_stats_show(struct seq_file *file, void *data)
|
||||
{
|
||||
struct ufs_hba *hba = (struct ufs_hba *)file->private;
|
||||
struct ufs_stats *ufs_stats;
|
||||
int i;
|
||||
int i, j;
|
||||
int max_depth;
|
||||
bool is_tag_empty = true;
|
||||
unsigned long flags;
|
||||
char *sep = " | * | ";
|
||||
|
||||
if (!hba)
|
||||
goto exit;
|
||||
|
@ -186,27 +188,44 @@ static int ufsdbg_tag_stats_show(struct seq_file *file, void *data)
|
|||
|
||||
if (!ufs_stats->enabled) {
|
||||
pr_debug("%s: ufs statistics are disabled\n", __func__);
|
||||
seq_puts(file, "ufs statistics are disabled");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
max_depth = hba->nutrs;
|
||||
|
||||
pr_debug("%s: UFS tag statistics:\n", __func__);
|
||||
pr_debug("%s: Max tagged command queue depth is %d",
|
||||
__func__, max_depth);
|
||||
|
||||
spin_lock_irqsave(hba->host->host_lock, flags);
|
||||
/* Header */
|
||||
seq_printf(file, " Tag Stat\t\t%s Queue Fullness\n", sep);
|
||||
for (i = 0; i < TAB_CHARS * (TS_NUM_STATS + 4); i++) {
|
||||
seq_puts(file, "-");
|
||||
if (i == (TAB_CHARS * 3 - 1))
|
||||
seq_puts(file, sep);
|
||||
}
|
||||
seq_printf(file,
|
||||
"\n #\tnum uses\t%s\t #\tAll\t Read\t Write\t Urgent\t Flush\n",
|
||||
sep);
|
||||
|
||||
for (i = 0 ; i < max_depth ; ++i) {
|
||||
if (hba->ufs_stats.tag_stats[i] != 0) {
|
||||
is_tag_empty = false;
|
||||
seq_printf(file,
|
||||
"%s: Dispatched tag %d - %llu times\n",
|
||||
__func__, i, ufs_stats->tag_stats[i]);
|
||||
/* values */
|
||||
for (i = 0; i < max_depth; i++) {
|
||||
if (ufs_stats->tag_stats[i][0] <= 0 &&
|
||||
ufs_stats->tag_stats[i][1] <= 0 &&
|
||||
ufs_stats->tag_stats[i][2] <= 0 &&
|
||||
ufs_stats->tag_stats[i][3] <= 0 &&
|
||||
ufs_stats->tag_stats[i][4] <= 0)
|
||||
continue;
|
||||
|
||||
pr_debug("%s: Dispatched tag %d - %llu times\n",
|
||||
__func__, i, ufs_stats->tag_stats[i]);
|
||||
is_tag_empty = false;
|
||||
seq_printf(file, " %d\t ", i);
|
||||
for (j = 0; j < TS_NUM_STATS; j++) {
|
||||
seq_printf(file, "%llu\t ", ufs_stats->tag_stats[i][j]);
|
||||
if (j == 0)
|
||||
seq_printf(file, "\t%s\t %d\t%llu\t ", sep, i,
|
||||
ufs_stats->tag_stats[i][j+1] +
|
||||
ufs_stats->tag_stats[i][j+2] +
|
||||
ufs_stats->tag_stats[i][j+3]);
|
||||
}
|
||||
seq_puts(file, "\n");
|
||||
}
|
||||
spin_unlock_irqrestore(hba->host->host_lock, flags);
|
||||
|
||||
|
@ -229,7 +248,7 @@ static ssize_t ufsdbg_tag_stats_write(struct file *filp,
|
|||
struct ufs_hba *hba = filp->f_mapping->host->i_private;
|
||||
struct ufs_stats *ufs_stats;
|
||||
int val = 0;
|
||||
int ret;
|
||||
int ret, bit = 0;
|
||||
unsigned long flags;
|
||||
|
||||
ret = kstrtoint_from_user(ubuf, cnt, 0, &val);
|
||||
|
@ -248,8 +267,15 @@ static ssize_t ufsdbg_tag_stats_write(struct file *filp,
|
|||
ufs_stats->enabled = true;
|
||||
pr_debug("%s: Enabling & Resetting UFS tag statistics",
|
||||
__func__);
|
||||
memset(ufs_stats->tag_stats, 0,
|
||||
sizeof(*ufs_stats->tag_stats) * hba->nutrs);
|
||||
memset(hba->ufs_stats.tag_stats[0], 0,
|
||||
sizeof(**hba->ufs_stats.tag_stats) *
|
||||
TS_NUM_STATS * hba->nutrs);
|
||||
|
||||
/* initialize current queue depth */
|
||||
ufs_stats->q_depth = 0;
|
||||
for_each_set_bit_from(bit, &hba->outstanding_reqs, hba->nutrs)
|
||||
ufs_stats->q_depth++;
|
||||
pr_debug("%s: Enabled UFS tag statistics", __func__);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(hba->host->host_lock, flags);
|
||||
|
@ -264,19 +290,29 @@ static const struct file_operations ufsdbg_tag_stats_fops = {
|
|||
|
||||
static int ufshcd_init_tag_statistics(struct ufs_hba *hba)
|
||||
{
|
||||
struct ufs_stats *stats = &hba->ufs_stats;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
hba->ufs_stats.tag_stats = kzalloc(hba->nutrs * sizeof(u64),
|
||||
GFP_KERNEL);
|
||||
if (!hba->ufs_stats.tag_stats) {
|
||||
dev_err(hba->dev,
|
||||
"%s: Unable to allocate UFS tag_stats", __func__);
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
stats->enabled = false;
|
||||
stats->tag_stats = kzalloc(sizeof(*stats->tag_stats) * hba->nutrs,
|
||||
GFP_KERNEL);
|
||||
if (!hba->ufs_stats.tag_stats)
|
||||
goto no_mem;
|
||||
|
||||
hba->ufs_stats.enabled = false;
|
||||
stats->tag_stats[0] = kzalloc(sizeof(**stats->tag_stats) *
|
||||
TS_NUM_STATS * hba->nutrs, GFP_KERNEL);
|
||||
if (!stats->tag_stats[0])
|
||||
goto no_mem;
|
||||
|
||||
for (i = 1; i < hba->nutrs; i++)
|
||||
stats->tag_stats[i] = &stats->tag_stats[0][i * TS_NUM_STATS];
|
||||
|
||||
goto exit;
|
||||
|
||||
no_mem:
|
||||
dev_err(hba->dev, "%s: Unable to allocate UFS tag_stats", __func__);
|
||||
ret = -ENOMEM;
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* This code is based on drivers/scsi/ufs/ufshcd.c
|
||||
* Copyright (C) 2011-2013 Samsung India Software Operations
|
||||
* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Authors:
|
||||
* Santosh Yaraganavi <santosh.sy@samsung.com>
|
||||
|
@ -51,19 +51,47 @@
|
|||
#ifdef CONFIG_DEBUG_FS
|
||||
#define UFSHCD_UPDATE_TAG_STATS(hba, tag) \
|
||||
do { \
|
||||
if (hba->ufs_stats.enabled) { \
|
||||
hba->ufs_stats.tag_stats[tag]++; \
|
||||
} \
|
||||
} while (0);
|
||||
struct request *rq = hba->lrb[task_tag].cmd ? \
|
||||
hba->lrb[task_tag].cmd->request : NULL; \
|
||||
u64 **tag_stats = hba->ufs_stats.tag_stats; \
|
||||
int rq_type = -1; \
|
||||
if (!hba->ufs_stats.enabled) \
|
||||
break; \
|
||||
tag_stats[tag][TS_TAG]++; \
|
||||
if (!rq) \
|
||||
break; \
|
||||
WARN_ON(hba->ufs_stats.q_depth > hba->nutrs); \
|
||||
if (rq_data_dir(rq) == READ) \
|
||||
rq_type = (rq->cmd_flags & REQ_URGENT) ?\
|
||||
TS_URGENT : TS_READ; \
|
||||
else if (rq_data_dir(rq) == WRITE) \
|
||||
rq_type = TS_WRITE; \
|
||||
else if (rq->cmd_flags & REQ_FLUSH) \
|
||||
rq_type = TS_FLUSH; \
|
||||
else \
|
||||
break; \
|
||||
tag_stats[hba->ufs_stats.q_depth++][rq_type]++; \
|
||||
} while (0)
|
||||
|
||||
#define UFSHCD_UPDATE_TAG_STATS_COMPLETION(hba, cmd) \
|
||||
do { \
|
||||
struct request *rq = cmd ? cmd->request : NULL; \
|
||||
if (cmd->request && \
|
||||
((rq_data_dir(rq) == READ) || \
|
||||
(rq_data_dir(rq) == WRITE) || \
|
||||
(rq->cmd_flags & REQ_FLUSH))) \
|
||||
hba->ufs_stats.q_depth--; \
|
||||
} while (0)
|
||||
|
||||
#define UFSDBG_ADD_DEBUGFS(hba) ufsdbg_add_debugfs(hba);
|
||||
|
||||
#define UFSDBG_REMOVE_DEBUGFS(hba) ufsdbg_remove_debugfs(hba);
|
||||
|
||||
#else
|
||||
#define UFSHCD_UPDATE_TAG_STATS(hba, tag) do {} while (0);
|
||||
#define UFSDBG_ADD_DEBUGFS(hba) do {} while (0);
|
||||
#define UFSDBG_REMOVE_DEBUGFS(hba) do {} while (0);
|
||||
#define UFSHCD_UPDATE_TAG_STATS(hba, tag)
|
||||
#define UFSHCD_UPDATE_TAG_STATS_COMPLETION(hba, cmd)
|
||||
#define UFSDBG_ADD_DEBUGFS(hba)
|
||||
#define UFSDBG_REMOVE_DEBUGFS(hba)
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -934,7 +962,7 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
|
|||
ufshcd_clk_scaling_start_busy(hba);
|
||||
__set_bit(task_tag, &hba->outstanding_reqs);
|
||||
ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
|
||||
UFSHCD_UPDATE_TAG_STATS(hba, task_tag)
|
||||
UFSHCD_UPDATE_TAG_STATS(hba, task_tag);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3467,6 +3495,7 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
|
|||
lrbp = &hba->lrb[index];
|
||||
cmd = lrbp->cmd;
|
||||
if (cmd) {
|
||||
UFSHCD_UPDATE_TAG_STATS_COMPLETION(hba, cmd);
|
||||
result = ufshcd_transfer_rsp_status(hba, lrbp);
|
||||
scsi_dma_unmap(cmd);
|
||||
cmd->result = result;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
* This code is based on drivers/scsi/ufs/ufshcd.h
|
||||
* Copyright (C) 2011-2013 Samsung India Software Operations
|
||||
* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Authors:
|
||||
* Santosh Yaraganavi <santosh.sy@samsung.com>
|
||||
|
@ -337,8 +338,9 @@ struct ufs_init_prefetch {
|
|||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct ufs_stats {
|
||||
u64 *tag_stats;
|
||||
bool enabled;
|
||||
u64 **tag_stats;
|
||||
int q_depth;
|
||||
};
|
||||
|
||||
struct debugfs_files {
|
||||
|
@ -351,6 +353,17 @@ struct debugfs_files {
|
|||
struct fault_attr fail_attr;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* tag stats statistics types */
|
||||
enum ts_types {
|
||||
TS_NOT_SUPPORTED = -1,
|
||||
TS_TAG = 0,
|
||||
TS_READ = 1,
|
||||
TS_WRITE = 2,
|
||||
TS_URGENT = 3,
|
||||
TS_FLUSH = 4,
|
||||
TS_NUM_STATS = 5,
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Reference in a new issue