]> git.baikalelectronics.ru Git - kernel.git/commitdiff
mmc: core: Convert to mmc_poll_for_busy() for erase/trim/discard
authorUlf Hansson <ulf.hansson@linaro.org>
Tue, 4 Feb 2020 08:54:45 +0000 (09:54 +0100)
committerUlf Hansson <ulf.hansson@linaro.org>
Tue, 24 Mar 2020 13:35:40 +0000 (14:35 +0100)
Rather than open coding the polling loop in mmc_do_erase(), let's convert
to use mmc_poll_for_busy().

To allow a slightly different error parsing during polling, compared to the
__mmc_switch() case, a new in-parameter to mmc_poll_for_busy() is needed,
but other than that the conversion is straight forward.

Besides addressing the open coding issue, moving to mmc_poll_for_busy() for
erase/trim/discard improves the behaviour according to below.

- Adds support for polling via the optional ->card_busy() host ops.
- Returns zero to indicate success when the final polling attempt finds the
  card non-busy, even if the timeout expired.
- Exits the polling loop when state moves to R1_STATE_TRAN, rather than
  when leaving R1_STATE_PRG.
- Decreases the starting range for throttling to 32-64us.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Tested-by: Baolin Wang <baolin.wang7@gmail.com>
Tested-by: Ludovic Barre <ludovic.barre@st.com>
Reviewed-by: Ludovic Barre <ludovic.barre@st.com>
Link: https://lore.kernel.org/r/20200204085449.32585-9-ulf.hansson@linaro.org
drivers/mmc/core/core.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/core/mmc_ops.h

index a971c4bcc442b11ab76c5425bbab46c89bf32dfd..3f7a31456eb4fe4135688192fb28f7e5e4c868f7 100644 (file)
@@ -1658,8 +1658,6 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
        struct mmc_command cmd = {};
        unsigned int qty = 0, busy_timeout = 0;
        bool use_r1b_resp = false;
-       unsigned long timeout;
-       int loop_udelay=64, udelay_max=32768;
        int err;
 
        mmc_retune_hold(card->host);
@@ -1763,38 +1761,8 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
        if ((card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
                goto out;
 
-       timeout = jiffies + msecs_to_jiffies(busy_timeout);
-       do {
-               memset(&cmd, 0, sizeof(struct mmc_command));
-               cmd.opcode = MMC_SEND_STATUS;
-               cmd.arg = card->rca << 16;
-               cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-               /* Do not retry else we can't see errors */
-               err = mmc_wait_for_cmd(card->host, &cmd, 0);
-               if (err || R1_STATUS(cmd.resp[0])) {
-                       pr_err("error %d requesting status %#x\n",
-                               err, cmd.resp[0]);
-                       err = -EIO;
-                       goto out;
-               }
-
-               /* Timeout if the device never becomes ready for data and
-                * never leaves the program state.
-                */
-               if (time_after(jiffies, timeout)) {
-                       pr_err("%s: Card stuck in programming state! %s\n",
-                               mmc_hostname(card->host), __func__);
-                       err =  -EIO;
-                       goto out;
-               }
-               if ((cmd.resp[0] & R1_READY_FOR_DATA) &&
-                   R1_CURRENT_STATE(cmd.resp[0]) != R1_STATE_PRG)
-                       break;
-
-               usleep_range(loop_udelay, loop_udelay*2);
-               if (loop_udelay < udelay_max)
-                       loop_udelay *= 2;
-       } while (1);
+       /* Let's poll to find out when the erase operation completes. */
+       err = mmc_poll_for_busy(card, busy_timeout, MMC_BUSY_ERASE);
 
 out:
        mmc_retune_release(card->host);
index 4566f43305d565763456981080ee9c656ec12b8d..3f510348b9163516274cc3aabd9e02b91a4fa40a 100644 (file)
@@ -445,7 +445,7 @@ int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal)
 }
 
 static int mmc_busy_status(struct mmc_card *card, bool retry_crc_err,
-                          bool *busy)
+                          enum mmc_busy_cmd busy_cmd, bool *busy)
 {
        struct mmc_host *host = card->host;
        u32 status = 0;
@@ -464,7 +464,17 @@ static int mmc_busy_status(struct mmc_card *card, bool retry_crc_err,
        if (err)
                return err;
 
-       err = mmc_switch_status_error(card->host, status);
+       switch (busy_cmd) {
+       case MMC_BUSY_CMD6:
+               err = mmc_switch_status_error(card->host, status);
+               break;
+       case MMC_BUSY_ERASE:
+               err = R1_STATUS(status) ? -EIO : 0;
+               break;
+       default:
+               err = -EINVAL;
+       }
+
        if (err)
                return err;
 
@@ -472,8 +482,9 @@ static int mmc_busy_status(struct mmc_card *card, bool retry_crc_err,
        return 0;
 }
 
-static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
-                       bool send_status, bool retry_crc_err)
+static int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
+                              bool send_status, bool retry_crc_err,
+                              enum mmc_busy_cmd busy_cmd)
 {
        struct mmc_host *host = card->host;
        int err;
@@ -500,7 +511,7 @@ static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
                 */
                expired = time_after(jiffies, timeout);
 
-               err = mmc_busy_status(card, retry_crc_err, &busy);
+               err = mmc_busy_status(card, retry_crc_err, busy_cmd, &busy);
                if (err)
                        return err;
 
@@ -522,6 +533,12 @@ static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
        return 0;
 }
 
+int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
+                     enum mmc_busy_cmd busy_cmd)
+{
+       return __mmc_poll_for_busy(card, timeout_ms, true, false, busy_cmd);
+}
+
 /**
  *     __mmc_switch - modify EXT_CSD register
  *     @card: the MMC card associated with the data transfer
@@ -591,7 +608,8 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                goto out_tim;
 
        /* Let's try to poll to find out when the command is completed. */
-       err = mmc_poll_for_busy(card, timeout_ms, send_status, retry_crc_err);
+       err = __mmc_poll_for_busy(card, timeout_ms, send_status, retry_crc_err,
+                                 MMC_BUSY_CMD6);
        if (err)
                goto out;
 
index de0c509a3a38997b216e2cb5c8ea7a6b639c75f2..8cd05fb583da52886dff1fd11a97b6a3e11371de 100644 (file)
 
 #include <linux/types.h>
 
+enum mmc_busy_cmd {
+       MMC_BUSY_CMD6,
+       MMC_BUSY_ERASE,
+};
+
 struct mmc_host;
 struct mmc_card;
 
@@ -30,6 +35,8 @@ int mmc_interrupt_hpi(struct mmc_card *card);
 int mmc_can_ext_csd(struct mmc_card *card);
 int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
 int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal);
+int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
+                     enum mmc_busy_cmd busy_cmd);
 int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                unsigned int timeout_ms, unsigned char timing,
                bool send_status, bool retry_crc_err);