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

Commit 5475671b authored by Dov Levenglick's avatar Dov Levenglick
Browse files

mmc: core: Add MMC BKOPS statistics and debugfs ability to print them



The BKOPS statistics are used for BKOPS unit tests and APT tests
to determine test success or failure.
The BKOPS statstics provide the following information:
The number of times BKOPS were issued according to its severity level
The number of times manual BKOPS was started/stopped (HPI)
The number of times auto BKOPS was enabled/disabled

In order to enable and reset the statistics:
echo 1 > /sys/kernel/debug/mmc0/mmc0:0001/bkops_stats
In order to disable the statistics:
echo 0 > /sys/kernel/debug/mmc0/mmc0:0001/bkops_stats
In order to view the statistics:
cat /sys/kernel/debug/mmc0/mmc0:0001/bkops_stats

Change-Id: Ib84319aedfb49dc022bc27efbda842a5db38c7e9
Signed-off-by: default avatarYaniv Gardi <ygardi@codeaurora.org>
Signed-off-by: default avatarDov Levenglick <dovl@codeaurora.org>
parent 217cf955
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -299,6 +299,7 @@ struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type)
	card->dev.type = type;

	spin_lock_init(&card->wr_pack_stats.lock);
	spin_lock_init(&card->bkops.stats.lock);

	return card;
}
+80 −2
Original line number Diff line number Diff line
@@ -864,6 +864,77 @@ static void mmc_start_cmdq_request(struct mmc_host *host,
				__func__);
}

/**
 *	mmc_blk_init_bkops_statistics - initialize bkops statistics
 *	@card: MMC card to start BKOPS
 *
 *	Initialize and enable the bkops statistics
 */
void mmc_blk_init_bkops_statistics(struct mmc_card *card)
{
	int i;
	struct mmc_bkops_stats *stats;

	if (!card)
		return;

	stats = &card->bkops.stats;
	spin_lock(&stats->lock);

	stats->manual_start = 0;
	stats->hpi = 0;
	stats->auto_start = 0;
	stats->auto_stop = 0;
	for (i = 0 ; i < MMC_BKOPS_NUM_SEVERITY_LEVELS ; i++)
		stats->level[i] = 0;
	stats->enabled = true;

	spin_unlock(&stats->lock);
}
EXPORT_SYMBOL(mmc_blk_init_bkops_statistics);

static void mmc_update_bkops_hpi(struct mmc_bkops_stats *stats)
{
	spin_lock_irq(&stats->lock);
	if (stats->enabled)
		stats->hpi++;
	spin_unlock_irq(&stats->lock);
}

static void mmc_update_bkops_start(struct mmc_bkops_stats *stats)
{
	spin_lock_irq(&stats->lock);
	if (stats->enabled)
		stats->manual_start++;
	spin_unlock_irq(&stats->lock);
}

static void mmc_update_bkops_auto_on(struct mmc_bkops_stats *stats)
{
	spin_lock_irq(&stats->lock);
	if (stats->enabled)
		stats->auto_start++;
	spin_unlock_irq(&stats->lock);
}

static void mmc_update_bkops_auto_off(struct mmc_bkops_stats *stats)
{
	spin_lock_irq(&stats->lock);
	if (stats->enabled)
		stats->auto_stop++;
	spin_unlock_irq(&stats->lock);
}

static void mmc_update_bkops_level(struct mmc_bkops_stats *stats,
					unsigned level)
{
	BUG_ON(level >= MMC_BKOPS_NUM_SEVERITY_LEVELS);
	spin_lock_irq(&stats->lock);
	if (stats->enabled)
		stats->level[level]++;
	spin_unlock_irq(&stats->lock);
}

/**
 *	mmc_set_auto_bkops - set auto BKOPS for supported cards
 *	@card: MMC card to start BKOPS
@@ -903,10 +974,13 @@ int mmc_set_auto_bkops(struct mmc_card *card, bool enable)
		pr_err("%s: %s: error in setting auto bkops to %d (%d)\n",
			mmc_hostname(card->host), __func__, enable, ret);
	} else {
		if (enable)
		if (enable) {
			mmc_card_set_auto_bkops(card);
		else
			mmc_update_bkops_auto_on(&card->bkops.stats);
		} else {
			mmc_card_clr_auto_bkops(card);
			mmc_update_bkops_auto_off(&card->bkops.stats);
		}
		card->ext_csd.bkops_en = bkops_en;
	}
out:
@@ -939,6 +1013,8 @@ void mmc_check_bkops(struct mmc_card *card)
		return;
	}

	mmc_update_bkops_level(&card->bkops.stats,
				card->ext_csd.raw_bkops_status);
	if (card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2)
		return;

@@ -972,6 +1048,7 @@ void mmc_start_manual_bkops(struct mmc_card *card)
				mmc_hostname(card->host), err);
	} else {
		mmc_card_set_doing_bkops(card);
		mmc_update_bkops_start(&card->bkops.stats);
		card->bkops.needs_manual = false;
	}
	mmc_release_host(card->host);
@@ -1499,6 +1576,7 @@ int mmc_stop_bkops(struct mmc_card *card)
	 */
	if (!err || (err == -EINVAL)) {
		mmc_card_clr_doing_bkops(card);
		mmc_update_bkops_hpi(&card->bkops.stats);
		err = 0;
	}
out:
+90 −0
Original line number Diff line number Diff line
@@ -619,6 +619,89 @@ static const struct file_operations mmc_dbg_wr_pack_stats_fops = {
	.write		= mmc_wr_pack_stats_write,
};

static int mmc_bkops_stats_read(struct seq_file *file, void *data)
{
	struct mmc_card *card = file->private;
	struct mmc_bkops_stats *stats;
	int i;

	if (!card)
		return -EINVAL;

	stats = &card->bkops.stats;

	if (!stats->enabled) {
		pr_info("%s: bkops statistics are disabled\n",
			 mmc_hostname(card->host));
		goto exit;
	}

	spin_lock(&stats->lock);

	seq_printf(file, "%s: bkops statistics:\n",
			mmc_hostname(card->host));
	seq_printf(file, "%s: BKOPS: sent START_BKOPS to device: %u\n",
			mmc_hostname(card->host), stats->manual_start);
	seq_printf(file, "%s: BKOPS: stopped due to HPI: %u\n",
			mmc_hostname(card->host), stats->hpi);
	seq_printf(file, "%s: BKOPS: sent AUTO_EN set to 1: %u\n",
			mmc_hostname(card->host), stats->auto_start);
	seq_printf(file, "%s: BKOPS: sent AUTO_EN set to 0: %u\n",
			mmc_hostname(card->host), stats->auto_stop);

	for (i = 0 ; i < MMC_BKOPS_NUM_SEVERITY_LEVELS ; ++i)
		seq_printf(file, "%s: BKOPS: due to level %d: %u\n",
			 mmc_hostname(card->host), i, stats->level[i]);

	spin_unlock(&stats->lock);

exit:

	return 0;
}

static ssize_t mmc_bkops_stats_write(struct file *filp,
				      const char __user *ubuf, size_t cnt,
				      loff_t *ppos)
{
	struct mmc_card *card = filp->f_mapping->host->i_private;
	int value;
	struct mmc_bkops_stats *stats;
	int err;

	if (!card)
		return cnt;

	stats = &card->bkops.stats;

	err = kstrtoint_from_user(ubuf, cnt, 0, &value);
	if (err) {
		pr_err("%s: %s: error parsing input from user (%d)\n",
				mmc_hostname(card->host), __func__, err);
		return err;
	}
	if (value) {
		mmc_blk_init_bkops_statistics(card);
	} else {
		spin_lock(&stats->lock);
		stats->enabled = false;
		spin_unlock(&stats->lock);
	}

	return cnt;
}

static int mmc_bkops_stats_open(struct inode *inode, struct file *file)
{
	return single_open(file, mmc_bkops_stats_read, inode->i_private);
}

static const struct file_operations mmc_dbg_bkops_stats_fops = {
	.open		= mmc_bkops_stats_open,
	.read		= seq_read,
	.write		= mmc_bkops_stats_write,
};

void mmc_add_card_debugfs(struct mmc_card *card)
{
	struct mmc_host	*host = card->host;
@@ -657,6 +740,13 @@ void mmc_add_card_debugfs(struct mmc_card *card)
					 &mmc_dbg_wr_pack_stats_fops))
			goto err;

	if (mmc_card_mmc(card) && (card->ext_csd.rev >= 5) &&
	    (mmc_card_support_auto_bkops(card) ||
	     mmc_card_configured_manual_bkops(card)))
		if (!debugfs_create_file("bkops_stats", S_IRUSR, root, card,
					 &mmc_dbg_bkops_stats_fops))
			goto err;

	return;

err:
+36 −0
Original line number Diff line number Diff line
@@ -268,12 +268,48 @@ struct mmc_part {
#define MMC_BLK_DATA_AREA_RPMB	(1<<3)
};

enum {
	MMC_BKOPS_NO_OP,
	MMC_BKOPS_NOT_CRITICAL,
	MMC_BKOPS_PERF_IMPACT,
	MMC_BKOPS_CRITICAL,
	MMC_BKOPS_NUM_SEVERITY_LEVELS,
};

/**
 * struct mmc_bkops_stats - BKOPS statistics
 * @lock: spinlock used for synchronizing the debugfs and the runtime accesses
 *	to this structure. No need to call with spin_lock_irq api
 * @manual_start: number of times START_BKOPS was sent to the device
 * @hpi: number of times HPI was sent to the device
 * @auto_start: number of times AUTO_EN was set to 1
 * @auto_stop: number of times AUTO_EN was set to 0
 * @level: number of times the device reported the need for each level of
 *	bkops handling
 * @enabled: control over whether statistics should be gathered
 *
 * This structure is used to collect statistics regarding the bkops
 * configuration and use-patterns. It is collected during runtime and can be
 * shown to the user via a debugfs entry.
 */
struct mmc_bkops_stats {
	spinlock_t	lock;
	unsigned int	manual_start;
	unsigned int	hpi;
	unsigned int	auto_start;
	unsigned int	auto_stop;
	unsigned int	level[MMC_BKOPS_NUM_SEVERITY_LEVELS];
	bool		enabled;
};

/**
 * struct mmc_bkops_info - BKOPS data
 * @stats: statistic information regarding bkops
 * @need_manual: indication whether have to send START_BKOPS
 *	to the device
 */
struct mmc_bkops_info {
	struct mmc_bkops_stats stats;
	bool needs_manual;
};

+2 −0
Original line number Diff line number Diff line
@@ -207,6 +207,8 @@ extern int mmc_flush_cache(struct mmc_card *);

extern int mmc_detect_card_removed(struct mmc_host *host);

extern void mmc_blk_init_bkops_statistics(struct mmc_card *card);

/**
 *	mmc_claim_host - exclusively claim a host
 *	@host: mmc host to claim