[PATCH v1 2/2] mmc: core: Let BKOPS timeout readable/writable via sysfs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Bean Huo <beanhuo@xxxxxxxxxx>

For special cases, the application in the userspace wants to change
BKOPS operation timeout value, also, wants eMMC back to R1_STATE_TRAN
after BKOPS timeouts. A fixed BKOPS timeout value(120s) is no longer
feasible, therefore, it is better to let the user controls its timeout
value.

Signed-off-by: Bean Huo <beanhuo@xxxxxxxxxx>
---
 drivers/mmc/core/mmc.c     | 32 ++++++++++++++++++++++++++++++++
 drivers/mmc/core/mmc_ops.c |  3 +--
 include/linux/mmc/card.h   |  1 +
 3 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 838726b68ff3..617ff18b5b0e 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -29,6 +29,7 @@
 #define DEFAULT_CMD6_TIMEOUT_MS	500
 #define MIN_CACHE_EN_TIMEOUT_MS 1600
 #define CACHE_FLUSH_TIMEOUT_MS 30000 /* 30s */
+#define MMC_BKOPS_TIMEOUT_MS	(120 * 1000) /* 120s */
 
 static const unsigned int tran_exp[] = {
 	10000,		100000,		1000000,	10000000,
@@ -836,6 +837,35 @@ static ssize_t mmc_dsr_show(struct device *dev,
 
 static DEVICE_ATTR(dsr, S_IRUGO, mmc_dsr_show, NULL);
 
+static ssize_t bkops_timeout_ms_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct mmc_card *card = mmc_dev_to_card(dev);
+	return sysfs_emit(buf, "%d\n", card->bkops_timeout_ms);
+}
+
+static ssize_t bkops_timeout_ms_store(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t len)
+{
+	struct mmc_card *card = mmc_dev_to_card(dev);
+	unsigned int new;
+	int ret;
+
+	ret = kstrtouint(buf, 0, &new);
+	if (ret < 0)
+		return ret;
+
+	if (new == 0)
+		return -EINVAL;
+
+	card->bkops_timeout_ms = new;
+
+	return len;
+}
+
+static DEVICE_ATTR_RW(bkops_timeout_ms);
+
 static struct attribute *mmc_std_attrs[] = {
 	&dev_attr_cid.attr,
 	&dev_attr_csd.attr,
@@ -862,6 +892,7 @@ static struct attribute *mmc_std_attrs[] = {
 	&dev_attr_rca.attr,
 	&dev_attr_dsr.attr,
 	&dev_attr_cmdq_en.attr,
+	&dev_attr_bkops_timeout_ms.attr,
 	NULL,
 };
 ATTRIBUTE_GROUPS(mmc_std);
@@ -1624,6 +1655,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		card->ocr = ocr;
 		card->type = MMC_TYPE_MMC;
 		card->rca = 1;
+		card->bkops_timeout_ms = MMC_BKOPS_TIMEOUT_MS;
 		memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
 	}
 
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 0c54858e89c0..9af5e4671de2 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -19,7 +19,6 @@
 #include "host.h"
 #include "mmc_ops.h"
 
-#define MMC_BKOPS_TIMEOUT_MS		(120 * 1000) /* 120s */
 #define MMC_SANITIZE_TIMEOUT_MS		(240 * 1000) /* 240s */
 
 static const u8 tuning_blk_pattern_4bit[] = {
@@ -958,7 +957,7 @@ void mmc_run_bkops(struct mmc_card *card)
 	 * urgent levels by using an asynchronous background task, when idle.
 	 */
 	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-			 EXT_CSD_BKOPS_START, 1, MMC_BKOPS_TIMEOUT_MS);
+			 EXT_CSD_BKOPS_START, 1, card->bkops_timeout_ms);
 	/*
 	 * If the BKOPS timed out, the card is probably still busy in the
 	 * R1_STATE_PRG. Rather than continue to wait, let's try to abort
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 74e6c0624d27..9e038d212067 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -294,6 +294,7 @@ struct mmc_card {
 
 	bool			reenable_cmdq;	/* Re-enable Command Queue */
 
+	unsigned int            bkops_timeout_ms;
 	unsigned int		erase_size;	/* erase size in sectors */
  	unsigned int		erase_shift;	/* if erase unit is power 2 */
  	unsigned int		pref_erase;	/* in sectors */
-- 
2.25.1




[Index of Archives]     [Linux Memonry Technology]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux