summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDolev Raviv <draviv@codeaurora.org>2014-01-12 13:51:23 +0200
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 10:56:30 -0700
commit0c8a317ea9cd7c5cfd541ce49df692d715d50b81 (patch)
tree5eb08d69b34e9fb136761b9f17603e98645a364d
parent8045d7daabeeb1e59a94164e1adc4a5d0238abb1 (diff)
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>
-rw-r--r--drivers/scsi/ufs/debugfs.c90
-rw-r--r--drivers/scsi/ufs/ufshcd.c47
-rw-r--r--drivers/scsi/ufs/ufshcd.h15
3 files changed, 115 insertions, 37 deletions
diff --git a/drivers/scsi/ufs/debugfs.c b/drivers/scsi/ufs/debugfs.c
index bdafdc85405a..d8c3bcda9ca8 100644
--- a/drivers/scsi/ufs/debugfs.c
+++ b/drivers/scsi/ufs/debugfs.c
@@ -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);
-
- 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]);
-
- pr_debug("%s: Dispatched tag %d - %llu times\n",
- __func__, i, ufs_stats->tag_stats[i]);
+ /* 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);
+
+ /* 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;
+
+ 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;
+
+ 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];
- hba->ufs_stats.enabled = false;
+ goto exit;
+no_mem:
+ dev_err(hba->dev, "%s: Unable to allocate UFS tag_stats", __func__);
+ ret = -ENOMEM;
exit:
return ret;
}
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 2ab908220a81..108976bc9ef6 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -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;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index bca139f9b979..c5427a3e6d36 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -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
/**