Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 23f6b299 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "scsi: ufs: add queue fullness statistics"

parents 5e569f5b 8d8b0045
Loading
Loading
Loading
Loading
+63 −27
Original line number Diff line number Diff line
@@ -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;
	/* 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,
				 "%s: Dispatched tag %d - %llu times\n",
				__func__, i, ufs_stats->tag_stats[i]);
		"\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;

			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),
	stats->enabled = false;
	stats->tag_stats = kzalloc(sizeof(*stats->tag_stats) * hba->nutrs,
			GFP_KERNEL);
	if (!hba->ufs_stats.tag_stats) {
		dev_err(hba->dev,
			"%s: Unable to allocate UFS tag_stats", __func__);
		ret = -ENOMEM;
		goto exit;
	}
	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;
}
+38 −9
Original line number Diff line number Diff line
@@ -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, The Linux Foundation. All rights reserved.
 * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
 *
 * Authors:
 *	Santosh Yaraganavi <santosh.sy@samsung.com>
@@ -50,19 +50,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

@@ -888,7 +916,7 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
{
	__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);
}

/**
@@ -3285,6 +3313,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;
+14 −1
Original line number Diff line number Diff line
@@ -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>
@@ -206,8 +207,9 @@ struct ufs_dev_cmd {

#ifdef CONFIG_DEBUG_FS
struct ufs_stats {
	u64 *tag_stats;
	bool enabled;
	u64 **tag_stats;
	int q_depth;
};

struct debugfs_files {
@@ -220,6 +222,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

/**