* [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.