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@xxxxxxxxxxx> > > --- > > 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@xxxxxxxxxxxxxxx > > 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@xxxxxxxxxxxxxxx > 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@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html