mmc: core: Avoid hogging the CPU while polling for busy after I/O writes
authorUlf Hansson <ulf.hansson@linaro.org>
Fri, 2 Jul 2021 13:42:29 +0000 (15:42 +0200)
committerUlf Hansson <ulf.hansson@linaro.org>
Tue, 24 Aug 2021 08:15:32 +0000 (10:15 +0200)
When mmc_blk_card_busy() calls card_busy_detect() to poll for the card's
state with CMD13, this is done without any delays in between the commands
being sent.

Rather than fixing card_busy_detect() in this regards, let's instead
convert into using the common __mmc_poll_for_busy(), which also helps us to
avoid open-coding.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
Link: https://lore.kernel.org/r/20210702134229.357717-4-ulf.hansson@linaro.org
drivers/mmc/core/block.c
drivers/mmc/core/mmc_ops.c

index c30d0ab..a9ad9f5 100644 (file)
@@ -98,6 +98,11 @@ static int max_devices;
 static DEFINE_IDA(mmc_blk_ida);
 static DEFINE_IDA(mmc_rpmb_ida);
 
+struct mmc_blk_busy_data {
+       struct mmc_card *card;
+       u32 status;
+};
+
 /*
  * There is one mmc_blk_data per slot.
  */
@@ -417,42 +422,6 @@ static int mmc_blk_ioctl_copy_to_user(struct mmc_ioc_cmd __user *ic_ptr,
        return 0;
 }
 
-static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms,
-                           u32 *resp_errs)
-{
-       unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
-       int err = 0;
-       u32 status;
-
-       do {
-               bool done = time_after(jiffies, timeout);
-
-               err = __mmc_send_status(card, &status, 5);
-               if (err) {
-                       dev_err(mmc_dev(card->host),
-                               "error %d requesting status\n", err);
-                       return err;
-               }
-
-               /* Accumulate any response error bits seen */
-               if (resp_errs)
-                       *resp_errs |= status;
-
-               /*
-                * Timeout if the device never becomes ready for data and never
-                * leaves the program state.
-                */
-               if (done) {
-                       dev_err(mmc_dev(card->host),
-                               "Card stuck in wrong state! %s status: %#x\n",
-                                __func__, status);
-                       return -ETIMEDOUT;
-               }
-       } while (!mmc_ready_for_data(status));
-
-       return err;
-}
-
 static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
                               struct mmc_blk_ioc_data *idata)
 {
@@ -1852,28 +1821,48 @@ static inline bool mmc_blk_rq_error(struct mmc_blk_request *brq)
               brq->data.error || brq->cmd.resp[0] & CMD_ERRORS;
 }
 
+static int mmc_blk_busy_cb(void *cb_data, bool *busy)
+{
+       struct mmc_blk_busy_data *data = cb_data;
+       u32 status = 0;
+       int err;
+
+       err = mmc_send_status(data->card, &status);
+       if (err)
+               return err;
+
+       /* Accumulate response error bits. */
+       data->status |= status;
+
+       *busy = !mmc_ready_for_data(status);
+       return 0;
+}
+
 static int mmc_blk_card_busy(struct mmc_card *card, struct request *req)
 {
        struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
-       u32 status = 0;
+       struct mmc_blk_busy_data cb_data;
        int err;
 
        if (mmc_host_is_spi(card->host) || rq_data_dir(req) == READ)
                return 0;
 
-       err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, &status);
+       cb_data.card = card;
+       cb_data.status = 0;
+       err = __mmc_poll_for_busy(card, MMC_BLK_TIMEOUT_MS, &mmc_blk_busy_cb,
+                                 &cb_data);
 
        /*
         * Do not assume data transferred correctly if there are any error bits
         * set.
         */
-       if (status & mmc_blk_stop_err_bits(&mqrq->brq)) {
+       if (cb_data.status & mmc_blk_stop_err_bits(&mqrq->brq)) {
                mqrq->brq.data.bytes_xfered = 0;
                err = err ? err : -EIO;
        }
 
        /* Copy the exception bit so it will be seen later on */
-       if (mmc_card_mmc(card) && status & R1_EXCEPTION_EVENT)
+       if (mmc_card_mmc(card) && cb_data.status & R1_EXCEPTION_EVENT)
                mqrq->brq.cmd.resp[0] |= R1_EXCEPTION_EVENT;
 
        return err;
index e2c431c..90d213a 100644 (file)
@@ -510,6 +510,7 @@ int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(__mmc_poll_for_busy);
 
 int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
                      bool retry_crc_err, enum mmc_busy_cmd busy_cmd)