All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] mmc: core: Add cache control for eMMC4.5 device
@ 2011-09-08  7:29 Seungwon Jeon
  2011-10-05 11:47 ` Adrian Hunter
  0 siblings, 1 reply; 8+ messages in thread
From: Seungwon Jeon @ 2011-09-08  7:29 UTC (permalink / raw)
  To: linux-mmc; +Cc: cjb, linux-samsung-soc, kgene.kim, dh.han, Seungwon Jeon

This patch adds cache feature of eMMC4.5 Spec.
If device supports cache capability, host can utilize some specific
operations.

Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
This patch is base on [PATCH v3] mmc: core: Add default timeout value for CMD6

 drivers/mmc/card/block.c |   14 ++++++----
 drivers/mmc/core/core.c  |   62 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/mmc/core/mmc.c   |   23 +++++++++++++++++
 include/linux/mmc/card.h |    2 +
 include/linux/mmc/core.h |    2 +
 include/linux/mmc/host.h |    3 ++
 include/linux/mmc/mmc.h  |    3 ++
 7 files changed, 103 insertions(+), 6 deletions(-)

diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index e702c61..84fa4bb 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -779,16 +779,18 @@ out:
 static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
 {
 	struct mmc_blk_data *md = mq->data;
+	struct mmc_card *card = md->queue.card;
+	int ret = 0;
+
+	ret = mmc_flush_cache(card);
+	if (ret)
+		ret = -EIO;

-	/*
-	 * No-op, only service this because we need REQ_FUA for reliable
-	 * writes.
-	 */
 	spin_lock_irq(&md->lock);
-	__blk_end_request_all(req, 0);
+	__blk_end_request_all(req, ret);
 	spin_unlock_irq(&md->lock);

-	return 1;
+	return ret ? 0 : 1;
 }

 /*
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 557856b..14c2431 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1987,6 +1987,64 @@ int mmc_card_can_sleep(struct mmc_host *host)
 }
 EXPORT_SYMBOL(mmc_card_can_sleep);

+/*
+ * Flush the cache to the non-volatile storage.
+ */
+int mmc_flush_cache(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = 0;
+
+	if (!(host->caps & MMC_CAP_CACHE_CTRL))
+		return err;
+
+	if (mmc_card_mmc(card) &&
+			(card->ext_csd.cache_size > 0) &&
+			(card->ext_csd.cache_ctrl & 1)) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_FLUSH_CACHE, 1, 0);
+		if (err)
+			pr_err("%s: cache flush error %d\n",
+					mmc_hostname(card->host), err);
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(mmc_flush_cache);
+
+/*
+ * Turn the cache ON/OFF.
+ * Turning the cache OFF shall trigger flushing of the data
+ * to the non-volatile storage.
+ */
+int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
+{
+	struct mmc_card *card = host->card;
+	int err = 0;
+
+	if (!(host->caps & MMC_CAP_CACHE_CTRL))
+		return err;
+
+	if (card && mmc_card_mmc(card) &&
+			(card->ext_csd.cache_size > 0)) {
+		enable = !!enable;
+
+		if (card->ext_csd.cache_ctrl ^ enable)
+			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+					EXT_CSD_CACHE_CTRL, enable, 0);
+		if (err)
+			pr_err("%s: cache %s error %d\n",
+					mmc_hostname(card->host),
+					enable ? "on" : "off",
+					err);
+		else
+			card->ext_csd.cache_ctrl = enable;
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(mmc_cache_ctrl);
+
 #ifdef CONFIG_PM

 /**
@@ -2001,6 +2059,9 @@ int mmc_suspend_host(struct mmc_host *host)
 		cancel_delayed_work(&host->disable);
 	cancel_delayed_work(&host->detect);
 	mmc_flush_scheduled_work();
+	err = mmc_cache_ctrl(host, 0);
+	if (err)
+		goto out;

 	mmc_bus_get(host);
 	if (host->bus_ops && !host->bus_dead) {
@@ -2025,6 +2086,7 @@ int mmc_suspend_host(struct mmc_host *host)
 	if (!err && !mmc_card_keep_power(host))
 		mmc_power_off(host);

+out:
 	return err;
 }

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index ea58a0c..035112b 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -419,6 +419,12 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
 		 */
 		card->ext_csd.generic_cmd6_time = 0;

+	card->ext_csd.cache_size =
+		ext_csd[EXT_CSD_CACHE_SIZE + 0] << 0 |
+		ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 |
+		ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 |
+		ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24;
+
 out:
 	return err;
 }
@@ -851,6 +857,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		}
 	}

+	/*
+	 * If cache size is higher than 0, this indicates
+	 * the the existence of cache and it can be turned on.
+	 */
+	if ((host->caps & MMC_CAP_CACHE_CTRL) &&
+			card->ext_csd.cache_size > 0) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_CACHE_CTRL, 1, 0);
+		if (err && err != -EBADMSG)
+			goto free_card;
+
+		/*
+		 * Only if no error, cache is turned on successfully.
+		 */
+		card->ext_csd.cache_ctrl = err ? 0 : 1;
+	}
+
 	if (!oldcard)
 		host->card = card;

diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index b713abf..519660b 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -50,6 +50,7 @@ struct mmc_ext_csd {
 	u8			rel_sectors;
 	u8			rel_param;
 	u8			part_config;
+	u8			cache_ctrl;
 	unsigned int		part_time;		/* Units: ms */
 	unsigned int		sa_timeout;		/* Units: 100ns */
 	unsigned int		generic_cmd6_time;	/* Units: 10ms */
@@ -65,6 +66,7 @@ struct mmc_ext_csd {
 	unsigned long long	enhanced_area_offset;	/* Units: Byte */
 	unsigned int		enhanced_area_size;	/* Units: KB */
 	unsigned int		boot_size;		/* in bytes */
+	unsigned int		cache_size;		/* Units: KB */
 	u8			raw_partition_support;	/* 160 */
 	u8			raw_erased_mem_count;	/* 181 */
 	u8			raw_ext_csd_structure;	/* 194 */
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index b8b1b7a..45b4acf 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -171,6 +171,8 @@ extern void mmc_release_host(struct mmc_host *host);
 extern void mmc_do_release_host(struct mmc_host *host);
 extern int mmc_try_claim_host(struct mmc_host *host);

+extern int mmc_flush_cache(struct mmc_card *);
+
 /**
  *	mmc_claim_host - exclusively claim a host
  *	@host: mmc host to claim
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 4c4bddf..6d0006d 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -230,6 +230,7 @@ struct mmc_host {
 #define MMC_CAP_MAX_CURRENT_600	(1 << 28)	/* Host max current limit is 600mA */
 #define MMC_CAP_MAX_CURRENT_800	(1 << 29)	/* Host max current limit is 800mA */
 #define MMC_CAP_CMD23		(1 << 30)	/* CMD23 supported. */
+#define MMC_CAP_CACHE_CTRL		(1 << 31)	/* Allow cache control. */

 	mmc_pm_flag_t		pm_caps;	/* supported pm features */

@@ -335,6 +336,8 @@ extern int mmc_power_restore_host(struct mmc_host *host);
 extern void mmc_detect_change(struct mmc_host *, unsigned long delay);
 extern void mmc_request_done(struct mmc_host *, struct mmc_request *);

+extern int mmc_cache_ctrl(struct mmc_host *, u8);
+
 static inline void mmc_signal_sdio_irq(struct mmc_host *host)
 {
 	host->ops->enable_sdio_irq(host, 0);
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index e869f00..b7fa9f7 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -270,6 +270,8 @@ struct _mmc_csd {
  * EXT_CSD fields
  */

+#define EXT_CSD_FLUSH_CACHE		32	/* W */
+#define EXT_CSD_CACHE_CTRL		33	/* R/W */
 #define EXT_CSD_PARTITION_ATTRIBUTE	156	/* R/W */
 #define EXT_CSD_PARTITION_SUPPORT	160	/* RO */
 #define EXT_CSD_WR_REL_PARAM		166	/* RO */
@@ -294,6 +296,7 @@ struct _mmc_csd {
 #define EXT_CSD_SEC_FEATURE_SUPPORT	231	/* RO */
 #define EXT_CSD_TRIM_MULT		232	/* RO */
 #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
+#define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */

 /*
  * EXT_CSD field definitions
--
1.7.0.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH] mmc: core: Add cache control for eMMC4.5 device
  2011-09-08  7:29 [PATCH] mmc: core: Add cache control for eMMC4.5 device Seungwon Jeon
@ 2011-10-05 11:47 ` Adrian Hunter
  2011-10-06  4:38   ` Seungwon Jeon
  0 siblings, 1 reply; 8+ messages in thread
From: Adrian Hunter @ 2011-10-05 11:47 UTC (permalink / raw)
  To: Seungwon Jeon; +Cc: linux-mmc, cjb, linux-samsung-soc, kgene.kim, dh.han

On 08/09/11 10:29, Seungwon Jeon wrote:
> This patch adds cache feature of eMMC4.5 Spec.
> If device supports cache capability, host can utilize some specific
> operations.
>
> Signed-off-by: Seungwon Jeon<tgih.jun@samsung.com>
> ---
> This patch is base on [PATCH v3] mmc: core: Add default timeout value for CMD6
>
>   drivers/mmc/card/block.c |   14 ++++++----
>   drivers/mmc/core/core.c  |   62 ++++++++++++++++++++++++++++++++++++++++++++++
>   drivers/mmc/core/mmc.c   |   23 +++++++++++++++++
>   include/linux/mmc/card.h |    2 +
>   include/linux/mmc/core.h |    2 +
>   include/linux/mmc/host.h |    3 ++
>   include/linux/mmc/mmc.h  |    3 ++
>   7 files changed, 103 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
> index e702c61..84fa4bb 100644
> --- a/drivers/mmc/card/block.c
> +++ b/drivers/mmc/card/block.c
> @@ -779,16 +779,18 @@ out:
>   static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
>   {
>   	struct mmc_blk_data *md = mq->data;
> +	struct mmc_card *card = md->queue.card;
> +	int ret = 0;
> +
> +	ret = mmc_flush_cache(card);
> +	if (ret)
> +		ret = -EIO;
>
> -	/*
> -	 * No-op, only service this because we need REQ_FUA for reliable
> -	 * writes.
> -	 */
>   	spin_lock_irq(&md->lock);
> -	__blk_end_request_all(req, 0);
> +	__blk_end_request_all(req, ret);
>   	spin_unlock_irq(&md->lock);
>
> -	return 1;
> +	return ret ? 0 : 1;
>   }
>
>   /*
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index 557856b..14c2431 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -1987,6 +1987,64 @@ int mmc_card_can_sleep(struct mmc_host *host)
>   }
>   EXPORT_SYMBOL(mmc_card_can_sleep);
>
> +/*
> + * Flush the cache to the non-volatile storage.
> + */
> +int mmc_flush_cache(struct mmc_card *card)
> +{
> +	struct mmc_host *host = card->host;
> +	int err = 0;
> +
> +	if (!(host->caps&  MMC_CAP_CACHE_CTRL))
> +		return err;
> +
> +	if (mmc_card_mmc(card)&&
> +			(card->ext_csd.cache_size>  0)&&
> +			(card->ext_csd.cache_ctrl&  1)) {
> +		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +				EXT_CSD_FLUSH_CACHE, 1, 0);
> +		if (err)
> +			pr_err("%s: cache flush error %d\n",
> +					mmc_hostname(card->host), err);
> +	}
> +
> +	return err;
> +}
> +EXPORT_SYMBOL(mmc_flush_cache);
> +
> +/*
> + * Turn the cache ON/OFF.
> + * Turning the cache OFF shall trigger flushing of the data
> + * to the non-volatile storage.
> + */
> +int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
> +{
> +	struct mmc_card *card = host->card;
> +	int err = 0;
> +
> +	if (!(host->caps&  MMC_CAP_CACHE_CTRL))
> +		return err;
> +

This patch does not cover code paths for removable cards.
For clarity and in case a platform does not set non-removable
flags for eMMC, a check is needed here e.g.

	if (mmc_card_is_removable(host))
		return 0;

> +	if (card&&  mmc_card_mmc(card)&&
> +			(card->ext_csd.cache_size>  0)) {
> +		enable = !!enable;
> +
> +		if (card->ext_csd.cache_ctrl ^ enable)
> +			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +					EXT_CSD_CACHE_CTRL, enable, 0);
> +		if (err)
> +			pr_err("%s: cache %s error %d\n",
> +					mmc_hostname(card->host),
> +					enable ? "on" : "off",
> +					err);
> +		else
> +			card->ext_csd.cache_ctrl = enable;
> +	}
> +
> +	return err;
> +}
> +EXPORT_SYMBOL(mmc_cache_ctrl);
> +
>   #ifdef CONFIG_PM
>
>   /**
> @@ -2001,6 +2059,9 @@ int mmc_suspend_host(struct mmc_host *host)
>   		cancel_delayed_work(&host->disable);
>   	cancel_delayed_work(&host->detect);
>   	mmc_flush_scheduled_work();
> +	err = mmc_cache_ctrl(host, 0);
> +	if (err)
> +		goto out;
>
>   	mmc_bus_get(host);
>   	if (host->bus_ops&&  !host->bus_dead) {
> @@ -2025,6 +2086,7 @@ int mmc_suspend_host(struct mmc_host *host)
>   	if (!err&&  !mmc_card_keep_power(host))
>   		mmc_power_off(host);
>
> +out:
>   	return err;
>   }
>
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index ea58a0c..035112b 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -419,6 +419,12 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
>   		 */
>   		card->ext_csd.generic_cmd6_time = 0;
>
> +	card->ext_csd.cache_size =
> +		ext_csd[EXT_CSD_CACHE_SIZE + 0]<<  0 |
> +		ext_csd[EXT_CSD_CACHE_SIZE + 1]<<  8 |
> +		ext_csd[EXT_CSD_CACHE_SIZE + 2]<<  16 |
> +		ext_csd[EXT_CSD_CACHE_SIZE + 3]<<  24;
> +
>   out:
>   	return err;
>   }
> @@ -851,6 +857,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>   		}
>   	}
>
> +	/*
> +	 * If cache size is higher than 0, this indicates
> +	 * the the existence of cache and it can be turned on.
> +	 */
> +	if ((host->caps&  MMC_CAP_CACHE_CTRL)&&
> +			card->ext_csd.cache_size>  0) {
> +		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +				EXT_CSD_CACHE_CTRL, 1, 0);
> +		if (err&&  err != -EBADMSG)
> +			goto free_card;
> +
> +		/*
> +		 * Only if no error, cache is turned on successfully.
> +		 */
> +		card->ext_csd.cache_ctrl = err ? 0 : 1;
> +	}
> +
>   	if (!oldcard)
>   		host->card = card;
>
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index b713abf..519660b 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -50,6 +50,7 @@ struct mmc_ext_csd {
>   	u8			rel_sectors;
>   	u8			rel_param;
>   	u8			part_config;
> +	u8			cache_ctrl;
>   	unsigned int		part_time;		/* Units: ms */
>   	unsigned int		sa_timeout;		/* Units: 100ns */
>   	unsigned int		generic_cmd6_time;	/* Units: 10ms */
> @@ -65,6 +66,7 @@ struct mmc_ext_csd {
>   	unsigned long long	enhanced_area_offset;	/* Units: Byte */
>   	unsigned int		enhanced_area_size;	/* Units: KB */
>   	unsigned int		boot_size;		/* in bytes */
> +	unsigned int		cache_size;		/* Units: KB */
>   	u8			raw_partition_support;	/* 160 */
>   	u8			raw_erased_mem_count;	/* 181 */
>   	u8			raw_ext_csd_structure;	/* 194 */
> diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
> index b8b1b7a..45b4acf 100644
> --- a/include/linux/mmc/core.h
> +++ b/include/linux/mmc/core.h
> @@ -171,6 +171,8 @@ extern void mmc_release_host(struct mmc_host *host);
>   extern void mmc_do_release_host(struct mmc_host *host);
>   extern int mmc_try_claim_host(struct mmc_host *host);
>
> +extern int mmc_flush_cache(struct mmc_card *);
> +
>   /**
>    *	mmc_claim_host - exclusively claim a host
>    *	@host: mmc host to claim
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 4c4bddf..6d0006d 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -230,6 +230,7 @@ struct mmc_host {
>   #define MMC_CAP_MAX_CURRENT_600	(1<<  28)	/* Host max current limit is 600mA */
>   #define MMC_CAP_MAX_CURRENT_800	(1<<  29)	/* Host max current limit is 800mA */
>   #define MMC_CAP_CMD23		(1<<  30)	/* CMD23 supported. */
> +#define MMC_CAP_CACHE_CTRL		(1<<  31)	/* Allow cache control. */
>
>   	mmc_pm_flag_t		pm_caps;	/* supported pm features */
>
> @@ -335,6 +336,8 @@ extern int mmc_power_restore_host(struct mmc_host *host);
>   extern void mmc_detect_change(struct mmc_host *, unsigned long delay);
>   extern void mmc_request_done(struct mmc_host *, struct mmc_request *);
>
> +extern int mmc_cache_ctrl(struct mmc_host *, u8);
> +
>   static inline void mmc_signal_sdio_irq(struct mmc_host *host)
>   {
>   	host->ops->enable_sdio_irq(host, 0);
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index e869f00..b7fa9f7 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -270,6 +270,8 @@ struct _mmc_csd {
>    * EXT_CSD fields
>    */
>
> +#define EXT_CSD_FLUSH_CACHE		32	/* W */
> +#define EXT_CSD_CACHE_CTRL		33	/* R/W */
>   #define EXT_CSD_PARTITION_ATTRIBUTE	156	/* R/W */
>   #define EXT_CSD_PARTITION_SUPPORT	160	/* RO */
>   #define EXT_CSD_WR_REL_PARAM		166	/* RO */
> @@ -294,6 +296,7 @@ struct _mmc_csd {
>   #define EXT_CSD_SEC_FEATURE_SUPPORT	231	/* RO */
>   #define EXT_CSD_TRIM_MULT		232	/* RO */
>   #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
> +#define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
>
>   /*
>    * EXT_CSD field definitions
> --
> 1.7.0.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: [PATCH] mmc: core: Add cache control for eMMC4.5 device
  2011-10-05 11:47 ` Adrian Hunter
@ 2011-10-06  4:38   ` Seungwon Jeon
  2011-10-06  5:21     ` Andrei E. Warkentin
  2011-10-06  7:06     ` Adrian Hunter
  0 siblings, 2 replies; 8+ messages in thread
From: Seungwon Jeon @ 2011-10-06  4:38 UTC (permalink / raw)
  To: 'Adrian Hunter'
  Cc: linux-mmc, cjb, linux-samsung-soc, kgene.kim, dh.han

Adrian Hunter wrote:
> On 08/09/11 10:29, Seungwon Jeon wrote:
> > This patch adds cache feature of eMMC4.5 Spec.
> > If device supports cache capability, host can utilize some specific
> > operations.
> >
> > Signed-off-by: Seungwon Jeon<tgih.jun@samsung.com>
> > ---
> > This patch is base on [PATCH v3] mmc: core: Add default timeout value
> for CMD6
> >
> >   drivers/mmc/card/block.c |   14 ++++++----
> >   drivers/mmc/core/core.c  |   62
> ++++++++++++++++++++++++++++++++++++++++++++++
> >   drivers/mmc/core/mmc.c   |   23 +++++++++++++++++
> >   include/linux/mmc/card.h |    2 +
> >   include/linux/mmc/core.h |    2 +
> >   include/linux/mmc/host.h |    3 ++
> >   include/linux/mmc/mmc.h  |    3 ++
> >   7 files changed, 103 insertions(+), 6 deletions(-)
> >
> > diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
> > index e702c61..84fa4bb 100644
> > --- a/drivers/mmc/card/block.c
> > +++ b/drivers/mmc/card/block.c
> > @@ -779,16 +779,18 @@ out:
> >   static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request
> *req)
> >   {
> >   	struct mmc_blk_data *md = mq->data;
> > +	struct mmc_card *card = md->queue.card;
> > +	int ret = 0;
> > +
> > +	ret = mmc_flush_cache(card);
> > +	if (ret)
> > +		ret = -EIO;
> >
> > -	/*
> > -	 * No-op, only service this because we need REQ_FUA for reliable
> > -	 * writes.
> > -	 */
> >   	spin_lock_irq(&md->lock);
> > -	__blk_end_request_all(req, 0);
> > +	__blk_end_request_all(req, ret);
> >   	spin_unlock_irq(&md->lock);
> >
> > -	return 1;
> > +	return ret ? 0 : 1;
> >   }
> >
> >   /*
> > diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> > index 557856b..14c2431 100644
> > --- a/drivers/mmc/core/core.c
> > +++ b/drivers/mmc/core/core.c
> > @@ -1987,6 +1987,64 @@ int mmc_card_can_sleep(struct mmc_host *host)
> >   }
> >   EXPORT_SYMBOL(mmc_card_can_sleep);
> >
> > +/*
> > + * Flush the cache to the non-volatile storage.
> > + */
> > +int mmc_flush_cache(struct mmc_card *card)
> > +{
> > +	struct mmc_host *host = card->host;
> > +	int err = 0;
> > +
> > +	if (!(host->caps&  MMC_CAP_CACHE_CTRL))
> > +		return err;
> > +
> > +	if (mmc_card_mmc(card)&&
> > +			(card->ext_csd.cache_size>  0)&&
> > +			(card->ext_csd.cache_ctrl&  1)) {
> > +		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > +				EXT_CSD_FLUSH_CACHE, 1, 0);
> > +		if (err)
> > +			pr_err("%s: cache flush error %d\n",
> > +					mmc_hostname(card->host), err);
> > +	}
> > +
> > +	return err;
> > +}
> > +EXPORT_SYMBOL(mmc_flush_cache);
> > +
> > +/*
> > + * Turn the cache ON/OFF.
> > + * Turning the cache OFF shall trigger flushing of the data
> > + * to the non-volatile storage.
> > + */
> > +int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
> > +{
> > +	struct mmc_card *card = host->card;
> > +	int err = 0;
> > +
> > +	if (!(host->caps&  MMC_CAP_CACHE_CTRL))
> > +		return err;
> > +
> 
> This patch does not cover code paths for removable cards.
> For clarity and in case a platform does not set non-removable
> flags for eMMC, a check is needed here e.g.
> 
> 	if (mmc_card_is_removable(host))
> 		return 0;
> 
Is it worry about normal MMC card type and?
Then, "card->ext_csd.cache_size" is a good condition for deciding cache control.
Or even though eMMC should be non-removable type, platform does not set non-removable for eMMC type mistakenly?
I can't catch the meaning exactly.
Please let me know.

Thanks.
Beset regards,
Seungwon Jeon.

> > +	if (card&&  mmc_card_mmc(card)&&
> > +			(card->ext_csd.cache_size>  0)) {
> > +		enable = !!enable;
> > +
> > +		if (card->ext_csd.cache_ctrl ^ enable)
> > +			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > +					EXT_CSD_CACHE_CTRL, enable, 0);
> > +		if (err)
> > +			pr_err("%s: cache %s error %d\n",
> > +					mmc_hostname(card->host),
> > +					enable ? "on" : "off",
> > +					err);
> > +		else
> > +			card->ext_csd.cache_ctrl = enable;
> > +	}
> > +
> > +	return err;
> > +}
> > +EXPORT_SYMBOL(mmc_cache_ctrl);
> > +
> >   #ifdef CONFIG_PM
> >
> >   /**
> > @@ -2001,6 +2059,9 @@ int mmc_suspend_host(struct mmc_host *host)
> >   		cancel_delayed_work(&host->disable);
> >   	cancel_delayed_work(&host->detect);
> >   	mmc_flush_scheduled_work();
> > +	err = mmc_cache_ctrl(host, 0);
> > +	if (err)
> > +		goto out;
> >
> >   	mmc_bus_get(host);
> >   	if (host->bus_ops&&  !host->bus_dead) {
> > @@ -2025,6 +2086,7 @@ int mmc_suspend_host(struct mmc_host *host)
> >   	if (!err&&  !mmc_card_keep_power(host))
> >   		mmc_power_off(host);
> >
> > +out:
> >   	return err;
> >   }
> >
> > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> > index ea58a0c..035112b 100644
> > --- a/drivers/mmc/core/mmc.c
> > +++ b/drivers/mmc/core/mmc.c
> > @@ -419,6 +419,12 @@ static int mmc_read_ext_csd(struct mmc_card *card,
> u8 *ext_csd)
> >   		 */
> >   		card->ext_csd.generic_cmd6_time = 0;
> >
> > +	card->ext_csd.cache_size =
> > +		ext_csd[EXT_CSD_CACHE_SIZE + 0]<<  0 |
> > +		ext_csd[EXT_CSD_CACHE_SIZE + 1]<<  8 |
> > +		ext_csd[EXT_CSD_CACHE_SIZE + 2]<<  16 |
> > +		ext_csd[EXT_CSD_CACHE_SIZE + 3]<<  24;
> > +
> >   out:
> >   	return err;
> >   }
> > @@ -851,6 +857,23 @@ static int mmc_init_card(struct mmc_host *host, u32
> ocr,
> >   		}
> >   	}
> >
> > +	/*
> > +	 * If cache size is higher than 0, this indicates
> > +	 * the the existence of cache and it can be turned on.
> > +	 */
> > +	if ((host->caps&  MMC_CAP_CACHE_CTRL)&&
> > +			card->ext_csd.cache_size>  0) {
> > +		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> > +				EXT_CSD_CACHE_CTRL, 1, 0);
> > +		if (err&&  err != -EBADMSG)
> > +			goto free_card;
> > +
> > +		/*
> > +		 * Only if no error, cache is turned on successfully.
> > +		 */
> > +		card->ext_csd.cache_ctrl = err ? 0 : 1;
> > +	}
> > +
> >   	if (!oldcard)
> >   		host->card = card;
> >
> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> > index b713abf..519660b 100644
> > --- a/include/linux/mmc/card.h
> > +++ b/include/linux/mmc/card.h
> > @@ -50,6 +50,7 @@ struct mmc_ext_csd {
> >   	u8			rel_sectors;
> >   	u8			rel_param;
> >   	u8			part_config;
> > +	u8			cache_ctrl;
> >   	unsigned int		part_time;		/* Units: ms */
> >   	unsigned int		sa_timeout;		/* Units: 100ns */
> >   	unsigned int		generic_cmd6_time;	/* Units: 10ms */
> > @@ -65,6 +66,7 @@ struct mmc_ext_csd {
> >   	unsigned long long	enhanced_area_offset;	/* Units: Byte */
> >   	unsigned int		enhanced_area_size;	/* Units: KB */
> >   	unsigned int		boot_size;		/* in bytes */
> > +	unsigned int		cache_size;		/* Units: KB */
> >   	u8			raw_partition_support;	/* 160 */
> >   	u8			raw_erased_mem_count;	/* 181 */
> >   	u8			raw_ext_csd_structure;	/* 194 */
> > diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
> > index b8b1b7a..45b4acf 100644
> > --- a/include/linux/mmc/core.h
> > +++ b/include/linux/mmc/core.h
> > @@ -171,6 +171,8 @@ extern void mmc_release_host(struct mmc_host *host);
> >   extern void mmc_do_release_host(struct mmc_host *host);
> >   extern int mmc_try_claim_host(struct mmc_host *host);
> >
> > +extern int mmc_flush_cache(struct mmc_card *);
> > +
> >   /**
> >    *	mmc_claim_host - exclusively claim a host
> >    *	@host: mmc host to claim
> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> > index 4c4bddf..6d0006d 100644
> > --- a/include/linux/mmc/host.h
> > +++ b/include/linux/mmc/host.h
> > @@ -230,6 +230,7 @@ struct mmc_host {
> >   #define MMC_CAP_MAX_CURRENT_600	(1<<  28)	/* Host max current
> limit is 600mA */
> >   #define MMC_CAP_MAX_CURRENT_800	(1<<  29)	/* Host max current
> limit is 800mA */
> >   #define MMC_CAP_CMD23		(1<<  30)	/* CMD23 supported. */
> > +#define MMC_CAP_CACHE_CTRL		(1<<  31)	/* Allow cache
> control. */
> >
> >   	mmc_pm_flag_t		pm_caps;	/* supported pm features */
> >
> > @@ -335,6 +336,8 @@ extern int mmc_power_restore_host(struct mmc_host
> *host);
> >   extern void mmc_detect_change(struct mmc_host *, unsigned long delay);
> >   extern void mmc_request_done(struct mmc_host *, struct mmc_request *);
> >
> > +extern int mmc_cache_ctrl(struct mmc_host *, u8);
> > +
> >   static inline void mmc_signal_sdio_irq(struct mmc_host *host)
> >   {
> >   	host->ops->enable_sdio_irq(host, 0);
> > diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> > index e869f00..b7fa9f7 100644
> > --- a/include/linux/mmc/mmc.h
> > +++ b/include/linux/mmc/mmc.h
> > @@ -270,6 +270,8 @@ struct _mmc_csd {
> >    * EXT_CSD fields
> >    */
> >
> > +#define EXT_CSD_FLUSH_CACHE		32	/* W */
> > +#define EXT_CSD_CACHE_CTRL		33	/* R/W */
> >   #define EXT_CSD_PARTITION_ATTRIBUTE	156	/* R/W */
> >   #define EXT_CSD_PARTITION_SUPPORT	160	/* RO */
> >   #define EXT_CSD_WR_REL_PARAM		166	/* RO */
> > @@ -294,6 +296,7 @@ struct _mmc_csd {
> >   #define EXT_CSD_SEC_FEATURE_SUPPORT	231	/* RO */
> >   #define EXT_CSD_TRIM_MULT		232	/* RO */
> >   #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
> > +#define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
> >
> >   /*
> >    * EXT_CSD field definitions
> > --
> > 1.7.0.4
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] mmc: core: Add cache control for eMMC4.5 device
  2011-10-06  4:38   ` Seungwon Jeon
@ 2011-10-06  5:21     ` Andrei E. Warkentin
  2011-10-06  8:22       ` Seungwon Jeon
  2011-10-06  7:06     ` Adrian Hunter
  1 sibling, 1 reply; 8+ messages in thread
From: Andrei E. Warkentin @ 2011-10-06  5:21 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: Adrian Hunter, linux-mmc, cjb, linux-samsung-soc, kgene.kim, dh.han

Hi Seungwon,

2011/10/6 Seungwon Jeon <tgih.jun@samsung.com>:
> Adrian Hunter wrote:
>> On 08/09/11 10:29, Seungwon Jeon wrote:
>> > This patch adds cache feature of eMMC4.5 Spec.
>> > If device supports cache capability, host can utilize some specific
>> > operations.
>> >
>> > Signed-off-by: Seungwon Jeon<tgih.jun@samsung.com>
>> > ---

I don't think eMMC 4.5 is public yet, so could you elaborate on the
volatile cache? I am
in particular interested in how the volatile cache affects reliable
writes (I would assume it doesn't
affect them at all).

A

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] mmc: core: Add cache control for eMMC4.5 device
  2011-10-06  4:38   ` Seungwon Jeon
  2011-10-06  5:21     ` Andrei E. Warkentin
@ 2011-10-06  7:06     ` Adrian Hunter
  2011-10-06  8:48       ` Seungwon Jeon
  1 sibling, 1 reply; 8+ messages in thread
From: Adrian Hunter @ 2011-10-06  7:06 UTC (permalink / raw)
  To: Seungwon Jeon; +Cc: linux-mmc, cjb, linux-samsung-soc, kgene.kim, dh.han

On 06/10/11 07:38, Seungwon Jeon wrote:
> Adrian Hunter wrote:
>> On 08/09/11 10:29, Seungwon Jeon wrote:
>>> This patch adds cache feature of eMMC4.5 Spec.
>>> If device supports cache capability, host can utilize some specific
>>> operations.
>>>
>>> Signed-off-by: Seungwon Jeon<tgih.jun@samsung.com>
>>> ---
>>> This patch is base on [PATCH v3] mmc: core: Add default timeout value
>> for CMD6
>>>
>>>    drivers/mmc/card/block.c |   14 ++++++----
>>>    drivers/mmc/core/core.c  |   62
>> ++++++++++++++++++++++++++++++++++++++++++++++
>>>    drivers/mmc/core/mmc.c   |   23 +++++++++++++++++
>>>    include/linux/mmc/card.h |    2 +
>>>    include/linux/mmc/core.h |    2 +
>>>    include/linux/mmc/host.h |    3 ++
>>>    include/linux/mmc/mmc.h  |    3 ++
>>>    7 files changed, 103 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
>>> index e702c61..84fa4bb 100644
>>> --- a/drivers/mmc/card/block.c
>>> +++ b/drivers/mmc/card/block.c
>>> @@ -779,16 +779,18 @@ out:
>>>    static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request
>> *req)
>>>    {
>>>    	struct mmc_blk_data *md = mq->data;
>>> +	struct mmc_card *card = md->queue.card;
>>> +	int ret = 0;
>>> +
>>> +	ret = mmc_flush_cache(card);
>>> +	if (ret)
>>> +		ret = -EIO;
>>>
>>> -	/*
>>> -	 * No-op, only service this because we need REQ_FUA for reliable
>>> -	 * writes.
>>> -	 */
>>>    	spin_lock_irq(&md->lock);
>>> -	__blk_end_request_all(req, 0);
>>> +	__blk_end_request_all(req, ret);
>>>    	spin_unlock_irq(&md->lock);
>>>
>>> -	return 1;
>>> +	return ret ? 0 : 1;
>>>    }
>>>
>>>    /*
>>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>>> index 557856b..14c2431 100644
>>> --- a/drivers/mmc/core/core.c
>>> +++ b/drivers/mmc/core/core.c
>>> @@ -1987,6 +1987,64 @@ int mmc_card_can_sleep(struct mmc_host *host)
>>>    }
>>>    EXPORT_SYMBOL(mmc_card_can_sleep);
>>>
>>> +/*
>>> + * Flush the cache to the non-volatile storage.
>>> + */
>>> +int mmc_flush_cache(struct mmc_card *card)
>>> +{
>>> +	struct mmc_host *host = card->host;
>>> +	int err = 0;
>>> +
>>> +	if (!(host->caps&   MMC_CAP_CACHE_CTRL))
>>> +		return err;
>>> +
>>> +	if (mmc_card_mmc(card)&&
>>> +			(card->ext_csd.cache_size>   0)&&
>>> +			(card->ext_csd.cache_ctrl&   1)) {
>>> +		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>>> +				EXT_CSD_FLUSH_CACHE, 1, 0);
>>> +		if (err)
>>> +			pr_err("%s: cache flush error %d\n",
>>> +					mmc_hostname(card->host), err);
>>> +	}
>>> +
>>> +	return err;
>>> +}
>>> +EXPORT_SYMBOL(mmc_flush_cache);
>>> +
>>> +/*
>>> + * Turn the cache ON/OFF.
>>> + * Turning the cache OFF shall trigger flushing of the data
>>> + * to the non-volatile storage.
>>> + */
>>> +int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
>>> +{
>>> +	struct mmc_card *card = host->card;
>>> +	int err = 0;
>>> +
>>> +	if (!(host->caps&   MMC_CAP_CACHE_CTRL))
>>> +		return err;
>>> +
>>
>> This patch does not cover code paths for removable cards.
>> For clarity and in case a platform does not set non-removable
>> flags for eMMC, a check is needed here e.g.
>>
>> 	if (mmc_card_is_removable(host))
>> 		return 0;
>>
> Is it worry about normal MMC card type and?
> Then, "card->ext_csd.cache_size" is a good condition for deciding cache control.
> Or even though eMMC should be non-removable type, platform does not set non-removable for eMMC type mistakenly?

Yes.  Looking at mmc_pm_notify() and mmc_attach_bus_ops() it seems that an eMMC 
will get powered off before suspend if the MMC_CAP_NONREMOVABLE is not set.
That was what I meant about not covering code paths for removable cards.

This code does not cover cards that are not specified as non-removable, so:

	if (mmc_card_is_removable(host))
		return 0;

> I can't catch the meaning exactly.
> Please let me know.
>
> Thanks.
> Beset regards,
> Seungwon Jeon.
>
>>> +	if (card&&   mmc_card_mmc(card)&&
>>> +			(card->ext_csd.cache_size>   0)) {
>>> +		enable = !!enable;
>>> +
>>> +		if (card->ext_csd.cache_ctrl ^ enable)
>>> +			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>>> +					EXT_CSD_CACHE_CTRL, enable, 0);
>>> +		if (err)
>>> +			pr_err("%s: cache %s error %d\n",
>>> +					mmc_hostname(card->host),
>>> +					enable ? "on" : "off",
>>> +					err);
>>> +		else
>>> +			card->ext_csd.cache_ctrl = enable;
>>> +	}
>>> +
>>> +	return err;
>>> +}
>>> +EXPORT_SYMBOL(mmc_cache_ctrl);
>>> +
>>>    #ifdef CONFIG_PM
>>>
>>>    /**
>>> @@ -2001,6 +2059,9 @@ int mmc_suspend_host(struct mmc_host *host)
>>>    		cancel_delayed_work(&host->disable);
>>>    	cancel_delayed_work(&host->detect);
>>>    	mmc_flush_scheduled_work();
>>> +	err = mmc_cache_ctrl(host, 0);
>>> +	if (err)
>>> +		goto out;
>>>
>>>    	mmc_bus_get(host);
>>>    	if (host->bus_ops&&   !host->bus_dead) {
>>> @@ -2025,6 +2086,7 @@ int mmc_suspend_host(struct mmc_host *host)
>>>    	if (!err&&   !mmc_card_keep_power(host))
>>>    		mmc_power_off(host);
>>>
>>> +out:
>>>    	return err;
>>>    }
>>>
>>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>>> index ea58a0c..035112b 100644
>>> --- a/drivers/mmc/core/mmc.c
>>> +++ b/drivers/mmc/core/mmc.c
>>> @@ -419,6 +419,12 @@ static int mmc_read_ext_csd(struct mmc_card *card,
>> u8 *ext_csd)
>>>    		*/
>>>    		card->ext_csd.generic_cmd6_time = 0;
>>>
>>> +	card->ext_csd.cache_size =
>>> +		ext_csd[EXT_CSD_CACHE_SIZE + 0]<<   0 |
>>> +		ext_csd[EXT_CSD_CACHE_SIZE + 1]<<   8 |
>>> +		ext_csd[EXT_CSD_CACHE_SIZE + 2]<<   16 |
>>> +		ext_csd[EXT_CSD_CACHE_SIZE + 3]<<   24;
>>> +
>>>    out:
>>>    	return err;
>>>    }
>>> @@ -851,6 +857,23 @@ static int mmc_init_card(struct mmc_host *host, u32
>> ocr,
>>>    		}
>>>    	}
>>>
>>> +	/*
>>> +	 * If cache size is higher than 0, this indicates
>>> +	 * the the existence of cache and it can be turned on.
>>> +	 */
>>> +	if ((host->caps&   MMC_CAP_CACHE_CTRL)&&
>>> +			card->ext_csd.cache_size>   0) {
>>> +		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>>> +				EXT_CSD_CACHE_CTRL, 1, 0);
>>> +		if (err&&   err != -EBADMSG)
>>> +			goto free_card;
>>> +
>>> +		/*
>>> +		 * Only if no error, cache is turned on successfully.
>>> +		 */
>>> +		card->ext_csd.cache_ctrl = err ? 0 : 1;
>>> +	}
>>> +
>>>    	if (!oldcard)
>>>    		host->card = card;
>>>
>>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>>> index b713abf..519660b 100644
>>> --- a/include/linux/mmc/card.h
>>> +++ b/include/linux/mmc/card.h
>>> @@ -50,6 +50,7 @@ struct mmc_ext_csd {
>>>    	u8			rel_sectors;
>>>    	u8			rel_param;
>>>    	u8			part_config;
>>> +	u8			cache_ctrl;
>>>    	unsigned int		part_time;		/* Units: ms */
>>>    	unsigned int		sa_timeout;		/* Units: 100ns */
>>>    	unsigned int		generic_cmd6_time;	/* Units: 10ms */
>>> @@ -65,6 +66,7 @@ struct mmc_ext_csd {
>>>    	unsigned long long	enhanced_area_offset;	/* Units: Byte */
>>>    	unsigned int		enhanced_area_size;	/* Units: KB */
>>>    	unsigned int		boot_size;		/* in bytes */
>>> +	unsigned int		cache_size;		/* Units: KB */
>>>    	u8			raw_partition_support;	/* 160 */
>>>    	u8			raw_erased_mem_count;	/* 181 */
>>>    	u8			raw_ext_csd_structure;	/* 194 */
>>> diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
>>> index b8b1b7a..45b4acf 100644
>>> --- a/include/linux/mmc/core.h
>>> +++ b/include/linux/mmc/core.h
>>> @@ -171,6 +171,8 @@ extern void mmc_release_host(struct mmc_host *host);
>>>    extern void mmc_do_release_host(struct mmc_host *host);
>>>    extern int mmc_try_claim_host(struct mmc_host *host);
>>>
>>> +extern int mmc_flush_cache(struct mmc_card *);
>>> +
>>>    /**
>>>     *	mmc_claim_host - exclusively claim a host
>>>     *	@host: mmc host to claim
>>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>>> index 4c4bddf..6d0006d 100644
>>> --- a/include/linux/mmc/host.h
>>> +++ b/include/linux/mmc/host.h
>>> @@ -230,6 +230,7 @@ struct mmc_host {
>>>    #define MMC_CAP_MAX_CURRENT_600	(1<<   28)	/* Host max current
>> limit is 600mA */
>>>    #define MMC_CAP_MAX_CURRENT_800	(1<<   29)	/* Host max current
>> limit is 800mA */
>>>    #define MMC_CAP_CMD23		(1<<   30)	/* CMD23 supported. */
>>> +#define MMC_CAP_CACHE_CTRL		(1<<   31)	/* Allow cache
>> control. */
>>>
>>>    	mmc_pm_flag_t		pm_caps;	/* supported pm features */
>>>
>>> @@ -335,6 +336,8 @@ extern int mmc_power_restore_host(struct mmc_host
>> *host);
>>>    extern void mmc_detect_change(struct mmc_host *, unsigned long delay);
>>>    extern void mmc_request_done(struct mmc_host *, struct mmc_request *);
>>>
>>> +extern int mmc_cache_ctrl(struct mmc_host *, u8);
>>> +
>>>    static inline void mmc_signal_sdio_irq(struct mmc_host *host)
>>>    {
>>>    	host->ops->enable_sdio_irq(host, 0);
>>> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>>> index e869f00..b7fa9f7 100644
>>> --- a/include/linux/mmc/mmc.h
>>> +++ b/include/linux/mmc/mmc.h
>>> @@ -270,6 +270,8 @@ struct _mmc_csd {
>>>     * EXT_CSD fields
>>>     */
>>>
>>> +#define EXT_CSD_FLUSH_CACHE		32	/* W */
>>> +#define EXT_CSD_CACHE_CTRL		33	/* R/W */
>>>    #define EXT_CSD_PARTITION_ATTRIBUTE	156	/* R/W */
>>>    #define EXT_CSD_PARTITION_SUPPORT	160	/* RO */
>>>    #define EXT_CSD_WR_REL_PARAM		166	/* RO */
>>> @@ -294,6 +296,7 @@ struct _mmc_csd {
>>>    #define EXT_CSD_SEC_FEATURE_SUPPORT	231	/* RO */
>>>    #define EXT_CSD_TRIM_MULT		232	/* RO */
>>>    #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
>>> +#define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
>>>
>>>    /*
>>>     * EXT_CSD field definitions
>>> --
>>> 1.7.0.4
>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>>> the body of a message to majordomo@vger.kernel.org
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: [PATCH] mmc: core: Add cache control for eMMC4.5 device
  2011-10-06  5:21     ` Andrei E. Warkentin
@ 2011-10-06  8:22       ` Seungwon Jeon
  2011-10-06 19:38         ` Andrei E. Warkentin
  0 siblings, 1 reply; 8+ messages in thread
From: Seungwon Jeon @ 2011-10-06  8:22 UTC (permalink / raw)
  To: 'Andrei E. Warkentin'
  Cc: 'Adrian Hunter',
	linux-mmc, cjb, linux-samsung-soc, kgene.kim, dh.han

Andrei E. Warkentin wrote:
> Hi Seungwon,
> 
> 2011/10/6 Seungwon Jeon <tgih.jun@samsung.com>:
> > Adrian Hunter wrote:
> >> On 08/09/11 10:29, Seungwon Jeon wrote:
> >> > This patch adds cache feature of eMMC4.5 Spec.
> >> > If device supports cache capability, host can utilize some specific
> >> > operations.
> >> >
> >> > Signed-off-by: Seungwon Jeon<tgih.jun@samsung.com>
> >> > ---
> 
> I don't think eMMC 4.5 is public yet, so could you elaborate on the
> volatile cache? I am
> in particular interested in how the volatile cache affects reliable
> writes (I would assume it doesn't
> affect them at all).
Right, no effect.
Data of reliable write will be written the non-volatile memory not cache forcedly.
> 
> A
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: [PATCH] mmc: core: Add cache control for eMMC4.5 device
  2011-10-06  7:06     ` Adrian Hunter
@ 2011-10-06  8:48       ` Seungwon Jeon
  0 siblings, 0 replies; 8+ messages in thread
From: Seungwon Jeon @ 2011-10-06  8:48 UTC (permalink / raw)
  To: 'Adrian Hunter'
  Cc: linux-mmc, cjb, linux-samsung-soc, kgene.kim, dh.han

Adrian Hunter wrote:
> On 06/10/11 07:38, Seungwon Jeon wrote:
> > Adrian Hunter wrote:
> >> On 08/09/11 10:29, Seungwon Jeon wrote:
> >>> This patch adds cache feature of eMMC4.5 Spec.
> >>> If device supports cache capability, host can utilize some specific
> >>> operations.
> >>>
> >>> Signed-off-by: Seungwon Jeon<tgih.jun@samsung.com>
> >>> ---
> >>> This patch is base on [PATCH v3] mmc: core: Add default timeout value
> >> for CMD6
> >>>
> >>>    drivers/mmc/card/block.c |   14 ++++++----
> >>>    drivers/mmc/core/core.c  |   62
> >> ++++++++++++++++++++++++++++++++++++++++++++++
> >>>    drivers/mmc/core/mmc.c   |   23 +++++++++++++++++
> >>>    include/linux/mmc/card.h |    2 +
> >>>    include/linux/mmc/core.h |    2 +
> >>>    include/linux/mmc/host.h |    3 ++
> >>>    include/linux/mmc/mmc.h  |    3 ++
> >>>    7 files changed, 103 insertions(+), 6 deletions(-)
> >>>
> >>> diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
> >>> index e702c61..84fa4bb 100644
> >>> --- a/drivers/mmc/card/block.c
> >>> +++ b/drivers/mmc/card/block.c
> >>> @@ -779,16 +779,18 @@ out:
> >>>    static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request
> >> *req)
> >>>    {
> >>>    	struct mmc_blk_data *md = mq->data;
> >>> +	struct mmc_card *card = md->queue.card;
> >>> +	int ret = 0;
> >>> +
> >>> +	ret = mmc_flush_cache(card);
> >>> +	if (ret)
> >>> +		ret = -EIO;
> >>>
> >>> -	/*
> >>> -	 * No-op, only service this because we need REQ_FUA for reliable
> >>> -	 * writes.
> >>> -	 */
> >>>    	spin_lock_irq(&md->lock);
> >>> -	__blk_end_request_all(req, 0);
> >>> +	__blk_end_request_all(req, ret);
> >>>    	spin_unlock_irq(&md->lock);
> >>>
> >>> -	return 1;
> >>> +	return ret ? 0 : 1;
> >>>    }
> >>>
> >>>    /*
> >>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> >>> index 557856b..14c2431 100644
> >>> --- a/drivers/mmc/core/core.c
> >>> +++ b/drivers/mmc/core/core.c
> >>> @@ -1987,6 +1987,64 @@ int mmc_card_can_sleep(struct mmc_host *host)
> >>>    }
> >>>    EXPORT_SYMBOL(mmc_card_can_sleep);
> >>>
> >>> +/*
> >>> + * Flush the cache to the non-volatile storage.
> >>> + */
> >>> +int mmc_flush_cache(struct mmc_card *card)
> >>> +{
> >>> +	struct mmc_host *host = card->host;
> >>> +	int err = 0;
> >>> +
> >>> +	if (!(host->caps&   MMC_CAP_CACHE_CTRL))
> >>> +		return err;
> >>> +
> >>> +	if (mmc_card_mmc(card)&&
> >>> +			(card->ext_csd.cache_size>   0)&&
> >>> +			(card->ext_csd.cache_ctrl&   1)) {
> >>> +		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >>> +				EXT_CSD_FLUSH_CACHE, 1, 0);
> >>> +		if (err)
> >>> +			pr_err("%s: cache flush error %d\n",
> >>> +					mmc_hostname(card->host), err);
> >>> +	}
> >>> +
> >>> +	return err;
> >>> +}
> >>> +EXPORT_SYMBOL(mmc_flush_cache);
> >>> +
> >>> +/*
> >>> + * Turn the cache ON/OFF.
> >>> + * Turning the cache OFF shall trigger flushing of the data
> >>> + * to the non-volatile storage.
> >>> + */
> >>> +int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
> >>> +{
> >>> +	struct mmc_card *card = host->card;
> >>> +	int err = 0;
> >>> +
> >>> +	if (!(host->caps&   MMC_CAP_CACHE_CTRL))
> >>> +		return err;
> >>> +
> >>
> >> This patch does not cover code paths for removable cards.
> >> For clarity and in case a platform does not set non-removable
> >> flags for eMMC, a check is needed here e.g.
> >>
> >> 	if (mmc_card_is_removable(host))
> >> 		return 0;
> >>
> > Is it worry about normal MMC card type and?
> > Then, "card->ext_csd.cache_size" is a good condition for deciding cache
> control.
> > Or even though eMMC should be non-removable type, platform does not set
> non-removable for eMMC type mistakenly?
> 
> Yes.  Looking at mmc_pm_notify() and mmc_attach_bus_ops() it seems that an
> eMMC
> will get powered off before suspend if the MMC_CAP_NONREMOVABLE is not set.
> That was what I meant about not covering code paths for removable cards.
> 
> This code does not cover cards that are not specified as non-removable, so:
> 
> 	if (mmc_card_is_removable(host))
> 		return 0;
Yes, I found it.
This case is undesirable but will affect flushing cache.
Thank you for review.
I will resend including this.
> 
> > I can't catch the meaning exactly.
> > Please let me know.
> >
> > Thanks.
> > Beset regards,
> > Seungwon Jeon.
> >
> >>> +	if (card&&   mmc_card_mmc(card)&&
> >>> +			(card->ext_csd.cache_size>   0)) {
> >>> +		enable = !!enable;
> >>> +
> >>> +		if (card->ext_csd.cache_ctrl ^ enable)
> >>> +			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >>> +					EXT_CSD_CACHE_CTRL, enable, 0);
> >>> +		if (err)
> >>> +			pr_err("%s: cache %s error %d\n",
> >>> +					mmc_hostname(card->host),
> >>> +					enable ? "on" : "off",
> >>> +					err);
> >>> +		else
> >>> +			card->ext_csd.cache_ctrl = enable;
> >>> +	}
> >>> +
> >>> +	return err;
> >>> +}
> >>> +EXPORT_SYMBOL(mmc_cache_ctrl);
> >>> +
> >>>    #ifdef CONFIG_PM
> >>>
> >>>    /**
> >>> @@ -2001,6 +2059,9 @@ int mmc_suspend_host(struct mmc_host *host)
> >>>    		cancel_delayed_work(&host->disable);
> >>>    	cancel_delayed_work(&host->detect);
> >>>    	mmc_flush_scheduled_work();
> >>> +	err = mmc_cache_ctrl(host, 0);
> >>> +	if (err)
> >>> +		goto out;
> >>>
> >>>    	mmc_bus_get(host);
> >>>    	if (host->bus_ops&&   !host->bus_dead) {
> >>> @@ -2025,6 +2086,7 @@ int mmc_suspend_host(struct mmc_host *host)
> >>>    	if (!err&&   !mmc_card_keep_power(host))
> >>>    		mmc_power_off(host);
> >>>
> >>> +out:
> >>>    	return err;
> >>>    }
> >>>
> >>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> >>> index ea58a0c..035112b 100644
> >>> --- a/drivers/mmc/core/mmc.c
> >>> +++ b/drivers/mmc/core/mmc.c
> >>> @@ -419,6 +419,12 @@ static int mmc_read_ext_csd(struct mmc_card *card,
> >> u8 *ext_csd)
> >>>    		*/
> >>>    		card->ext_csd.generic_cmd6_time = 0;
> >>>
> >>> +	card->ext_csd.cache_size =
> >>> +		ext_csd[EXT_CSD_CACHE_SIZE + 0]<<   0 |
> >>> +		ext_csd[EXT_CSD_CACHE_SIZE + 1]<<   8 |
> >>> +		ext_csd[EXT_CSD_CACHE_SIZE + 2]<<   16 |
> >>> +		ext_csd[EXT_CSD_CACHE_SIZE + 3]<<   24;
> >>> +
> >>>    out:
> >>>    	return err;
> >>>    }
> >>> @@ -851,6 +857,23 @@ static int mmc_init_card(struct mmc_host *host,
> u32
> >> ocr,
> >>>    		}
> >>>    	}
> >>>
> >>> +	/*
> >>> +	 * If cache size is higher than 0, this indicates
> >>> +	 * the the existence of cache and it can be turned on.
> >>> +	 */
> >>> +	if ((host->caps&   MMC_CAP_CACHE_CTRL)&&
> >>> +			card->ext_csd.cache_size>   0) {
> >>> +		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> >>> +				EXT_CSD_CACHE_CTRL, 1, 0);
> >>> +		if (err&&   err != -EBADMSG)
> >>> +			goto free_card;
> >>> +
> >>> +		/*
> >>> +		 * Only if no error, cache is turned on successfully.
> >>> +		 */
> >>> +		card->ext_csd.cache_ctrl = err ? 0 : 1;
> >>> +	}
> >>> +
> >>>    	if (!oldcard)
> >>>    		host->card = card;
> >>>
> >>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> >>> index b713abf..519660b 100644
> >>> --- a/include/linux/mmc/card.h
> >>> +++ b/include/linux/mmc/card.h
> >>> @@ -50,6 +50,7 @@ struct mmc_ext_csd {
> >>>    	u8			rel_sectors;
> >>>    	u8			rel_param;
> >>>    	u8			part_config;
> >>> +	u8			cache_ctrl;
> >>>    	unsigned int		part_time;		/* Units: ms */
> >>>    	unsigned int		sa_timeout;		/* Units: 100ns */
> >>>    	unsigned int		generic_cmd6_time;	/* Units: 10ms */
> >>> @@ -65,6 +66,7 @@ struct mmc_ext_csd {
> >>>    	unsigned long long	enhanced_area_offset;	/* Units: Byte */
> >>>    	unsigned int		enhanced_area_size;	/* Units: KB */
> >>>    	unsigned int		boot_size;		/* in bytes */
> >>> +	unsigned int		cache_size;		/* Units: KB */
> >>>    	u8			raw_partition_support;	/* 160 */
> >>>    	u8			raw_erased_mem_count;	/* 181 */
> >>>    	u8			raw_ext_csd_structure;	/* 194 */
> >>> diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
> >>> index b8b1b7a..45b4acf 100644
> >>> --- a/include/linux/mmc/core.h
> >>> +++ b/include/linux/mmc/core.h
> >>> @@ -171,6 +171,8 @@ extern void mmc_release_host(struct mmc_host
> *host);
> >>>    extern void mmc_do_release_host(struct mmc_host *host);
> >>>    extern int mmc_try_claim_host(struct mmc_host *host);
> >>>
> >>> +extern int mmc_flush_cache(struct mmc_card *);
> >>> +
> >>>    /**
> >>>     *	mmc_claim_host - exclusively claim a host
> >>>     *	@host: mmc host to claim
> >>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> >>> index 4c4bddf..6d0006d 100644
> >>> --- a/include/linux/mmc/host.h
> >>> +++ b/include/linux/mmc/host.h
> >>> @@ -230,6 +230,7 @@ struct mmc_host {
> >>>    #define MMC_CAP_MAX_CURRENT_600	(1<<   28)	/* Host max current
> >> limit is 600mA */
> >>>    #define MMC_CAP_MAX_CURRENT_800	(1<<   29)	/* Host max current
> >> limit is 800mA */
> >>>    #define MMC_CAP_CMD23		(1<<   30)	/* CMD23 supported.
> */
> >>> +#define MMC_CAP_CACHE_CTRL		(1<<   31)	/* Allow cache
> >> control. */
> >>>
> >>>    	mmc_pm_flag_t		pm_caps;	/* supported pm features */
> >>>
> >>> @@ -335,6 +336,8 @@ extern int mmc_power_restore_host(struct mmc_host
> >> *host);
> >>>    extern void mmc_detect_change(struct mmc_host *, unsigned long
> delay);
> >>>    extern void mmc_request_done(struct mmc_host *, struct mmc_request
> *);
> >>>
> >>> +extern int mmc_cache_ctrl(struct mmc_host *, u8);
> >>> +
> >>>    static inline void mmc_signal_sdio_irq(struct mmc_host *host)
> >>>    {
> >>>    	host->ops->enable_sdio_irq(host, 0);
> >>> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> >>> index e869f00..b7fa9f7 100644
> >>> --- a/include/linux/mmc/mmc.h
> >>> +++ b/include/linux/mmc/mmc.h
> >>> @@ -270,6 +270,8 @@ struct _mmc_csd {
> >>>     * EXT_CSD fields
> >>>     */
> >>>
> >>> +#define EXT_CSD_FLUSH_CACHE		32	/* W */
> >>> +#define EXT_CSD_CACHE_CTRL		33	/* R/W */
> >>>    #define EXT_CSD_PARTITION_ATTRIBUTE	156	/* R/W */
> >>>    #define EXT_CSD_PARTITION_SUPPORT	160	/* RO */
> >>>    #define EXT_CSD_WR_REL_PARAM		166	/* RO */
> >>> @@ -294,6 +296,7 @@ struct _mmc_csd {
> >>>    #define EXT_CSD_SEC_FEATURE_SUPPORT	231	/* RO */
> >>>    #define EXT_CSD_TRIM_MULT		232	/* RO */
> >>>    #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
> >>> +#define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
> >>>
> >>>    /*
> >>>     * EXT_CSD field definitions
> >>> --
> >>> 1.7.0.4
> >>>
> >>> --
> >>> To unsubscribe from this list: send the line "unsubscribe linux-mmc"
> in
> >>> the body of a message to majordomo@vger.kernel.org
> >>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >>
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> >> the body of a message to majordomo@vger.kernel.org
> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
> >

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] mmc: core: Add cache control for eMMC4.5 device
  2011-10-06  8:22       ` Seungwon Jeon
@ 2011-10-06 19:38         ` Andrei E. Warkentin
  0 siblings, 0 replies; 8+ messages in thread
From: Andrei E. Warkentin @ 2011-10-06 19:38 UTC (permalink / raw)
  To: Seungwon Jeon
  Cc: Adrian Hunter, linux-mmc, cjb, linux-samsung-soc, kgene.kim, dh.han

2011/10/6 Seungwon Jeon <tgih.jun@samsung.com>:
> Andrei E. Warkentin wrote:
>> Hi Seungwon,
>>
>> 2011/10/6 Seungwon Jeon <tgih.jun@samsung.com>:
>> > Adrian Hunter wrote:
>> >> On 08/09/11 10:29, Seungwon Jeon wrote:
>> >> > This patch adds cache feature of eMMC4.5 Spec.
>> >> > If device supports cache capability, host can utilize some specific
>> >> > operations.
>> >> >
>> >> > Signed-off-by: Seungwon Jeon<tgih.jun@samsung.com>
>> >> > ---
>>
>> I don't think eMMC 4.5 is public yet, so could you elaborate on the
>> volatile cache? I am
>> in particular interested in how the volatile cache affects reliable
>> writes (I would assume it doesn't
>> affect them at all).
> Right, no effect.
> Data of reliable write will be written the non-volatile memory not cache forcedly.
>>

Good, sounds like REQ_FUA path needs no changes, then.

A

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2011-10-06 19:38 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-09-08  7:29 [PATCH] mmc: core: Add cache control for eMMC4.5 device Seungwon Jeon
2011-10-05 11:47 ` Adrian Hunter
2011-10-06  4:38   ` Seungwon Jeon
2011-10-06  5:21     ` Andrei E. Warkentin
2011-10-06  8:22       ` Seungwon Jeon
2011-10-06 19:38         ` Andrei E. Warkentin
2011-10-06  7:06     ` Adrian Hunter
2011-10-06  8:48       ` Seungwon Jeon

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.