Loading drivers/mmc/core/bus.c +1 −0 Original line number Diff line number Diff line Loading @@ -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; } Loading drivers/mmc/core/core.c +80 −2 Original line number Diff line number Diff line Loading @@ -857,6 +857,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 Loading Loading @@ -896,10 +967,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: Loading Loading @@ -932,6 +1006,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; Loading Loading @@ -965,6 +1041,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); Loading Loading @@ -1496,6 +1573,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: Loading drivers/mmc/core/debugfs.c +90 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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: Loading include/linux/mmc/card.h +36 −0 Original line number Diff line number Diff line Loading @@ -272,12 +272,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; }; Loading include/linux/mmc/core.h +2 −0 Original line number Diff line number Diff line Loading @@ -208,6 +208,8 @@ extern int mmc_cache_barrier(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 Loading Loading
drivers/mmc/core/bus.c +1 −0 Original line number Diff line number Diff line Loading @@ -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; } Loading
drivers/mmc/core/core.c +80 −2 Original line number Diff line number Diff line Loading @@ -857,6 +857,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 Loading Loading @@ -896,10 +967,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: Loading Loading @@ -932,6 +1006,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; Loading Loading @@ -965,6 +1041,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); Loading Loading @@ -1496,6 +1573,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: Loading
drivers/mmc/core/debugfs.c +90 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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: Loading
include/linux/mmc/card.h +36 −0 Original line number Diff line number Diff line Loading @@ -272,12 +272,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; }; Loading
include/linux/mmc/core.h +2 −0 Original line number Diff line number Diff line Loading @@ -208,6 +208,8 @@ extern int mmc_cache_barrier(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 Loading