mmc: Add quirk MMC_QUIRK_BROKEN_CACHE_FLUSH for Micron eMMC Q2J54A
authorBean Huo <beanhuo@micron.com>
Mon, 30 Oct 2023 22:48:09 +0000 (23:48 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 28 Nov 2023 17:20:01 +0000 (17:20 +0000)
commit ed9009ad300c0f15a3ecfe9613547b1962bde02c upstream.

Micron MTFC4GACAJCN eMMC supports cache but requires that flush cache
operation be allowed only after a write has occurred. Otherwise, the
cache flush command or subsequent commands will time out.

Signed-off-by: Bean Huo <beanhuo@micron.com>
Signed-off-by: Rafael Beims <rafael.beims@toradex.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20231030224809.59245-1-beanhuo@iokpp.de
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/mmc/core/block.c
drivers/mmc/core/card.h
drivers/mmc/core/mmc.c
drivers/mmc/core/quirks.h
include/linux/mmc/card.h

index 3a8f27c..152dfe5 100644 (file)
@@ -2381,8 +2381,10 @@ enum mmc_issued mmc_blk_mq_issue_rq(struct mmc_queue *mq, struct request *req)
                        }
                        ret = mmc_blk_cqe_issue_flush(mq, req);
                        break;
-               case REQ_OP_READ:
                case REQ_OP_WRITE:
+                       card->written_flag = true;
+                       fallthrough;
+               case REQ_OP_READ:
                        if (host->cqe_enabled)
                                ret = mmc_blk_cqe_issue_rw_rq(mq, req);
                        else
index 4edf905..b7754a1 100644 (file)
@@ -280,4 +280,8 @@ static inline int mmc_card_broken_sd_cache(const struct mmc_card *c)
        return c->quirks & MMC_QUIRK_BROKEN_SD_CACHE;
 }
 
+static inline int mmc_card_broken_cache_flush(const struct mmc_card *c)
+{
+       return c->quirks & MMC_QUIRK_BROKEN_CACHE_FLUSH;
+}
 #endif
index 89cd48f..a46ce08 100644 (file)
@@ -2081,13 +2081,17 @@ static int _mmc_flush_cache(struct mmc_host *host)
 {
        int err = 0;
 
+       if (mmc_card_broken_cache_flush(host->card) && !host->card->written_flag)
+               return 0;
+
        if (_mmc_cache_enabled(host)) {
                err = mmc_switch(host->card, EXT_CSD_CMD_SET_NORMAL,
                                 EXT_CSD_FLUSH_CACHE, 1,
                                 CACHE_FLUSH_TIMEOUT_MS);
                if (err)
-                       pr_err("%s: cache flush error %d\n",
-                              mmc_hostname(host), err);
+                       pr_err("%s: cache flush error %d\n", mmc_hostname(host), err);
+               else
+                       host->card->written_flag = false;
        }
 
        return err;
index 32b64b5..cca7186 100644 (file)
@@ -110,11 +110,12 @@ static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = {
                  MMC_QUIRK_TRIM_BROKEN),
 
        /*
-        * Micron MTFC4GACAJCN-1M advertises TRIM but it does not seems to
-        * support being used to offload WRITE_ZEROES.
+        * Micron MTFC4GACAJCN-1M supports TRIM but does not appear to support
+        * WRITE_ZEROES offloading. It also supports caching, but the cache can
+        * only be flushed after a write has occurred.
         */
        MMC_FIXUP("Q2J54A", CID_MANFID_MICRON, 0x014e, add_quirk_mmc,
-                 MMC_QUIRK_TRIM_BROKEN),
+                 MMC_QUIRK_TRIM_BROKEN | MMC_QUIRK_BROKEN_CACHE_FLUSH),
 
        /*
         * Kingston EMMC04G-M627 advertises TRIM but it does not seems to
index daa2f40..7b12eeb 100644 (file)
@@ -295,7 +295,9 @@ struct mmc_card {
 #define MMC_QUIRK_BROKEN_HPI   (1<<13)         /* Disable broken HPI support */
 #define MMC_QUIRK_BROKEN_SD_DISCARD    (1<<14) /* Disable broken SD discard support */
 #define MMC_QUIRK_BROKEN_SD_CACHE      (1<<15) /* Disable broken SD cache support */
+#define MMC_QUIRK_BROKEN_CACHE_FLUSH   (1<<16) /* Don't flush cache until the write has occurred */
 
+       bool                    written_flag;   /* Indicates eMMC has been written since power on */
        bool                    reenable_cmdq;  /* Re-enable Command Queue */
 
        unsigned int            erase_size;     /* erase size in sectors */