aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Hansson <ulf.hansson@linaro.org>2023-02-09 17:27:15 +0100
committerUlf Hansson <ulf.hansson@linaro.org>2023-02-09 17:35:13 +0100
commitf1c4b1833319282efa5080eb09fd481fa8b9375b (patch)
tree7a8c15729c54834aa9da528eea6863469567f7e2
parent56f34e8ddc40d8eca29fb16ada409ac74c180b1f (diff)
mmc: core: Use common busy detection for the block recovery pathwip_blk_align_busy
When polling for busy for other commands than CMD12, we are using the optional HW busy detection support (MMC_CAP_WAIT_WHILE_BUSY). Let's do that for the block recovery path too, to strive towards a more consistent behaviour from the core. While at it, let's move away from using the data timeout (which isn't really for these kinds of things).... And don't use retries of 5, as it doesn't make sense for R1B.. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
-rw-r--r--drivers/mmc/core/block.c69
-rw-r--r--drivers/mmc/core/mmc_ops.c1
2 files changed, 23 insertions, 47 deletions
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index 20da7ed43e6d..2fab95b9c668 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -947,34 +947,6 @@ static int mmc_sd_num_wr_blocks(struct mmc_card *card, u32 *written_blocks)
return 0;
}
-static unsigned int mmc_blk_clock_khz(struct mmc_host *host)
-{
- if (host->actual_clock)
- return host->actual_clock / 1000;
-
- /* Clock may be subject to a divisor, fudge it by a factor of 2. */
- if (host->ios.clock)
- return host->ios.clock / 2000;
-
- /* How can there be no clock */
- WARN_ON_ONCE(1);
- return 100; /* 100 kHz is minimum possible value */
-}
-
-static unsigned int mmc_blk_data_timeout_ms(struct mmc_host *host,
- struct mmc_data *data)
-{
- unsigned int ms = DIV_ROUND_UP(data->timeout_ns, 1000000);
- unsigned int khz;
-
- if (data->timeout_clks) {
- khz = mmc_blk_clock_khz(host);
- ms += DIV_ROUND_UP(data->timeout_clks, khz);
- }
-
- return ms;
-}
-
/*
* Attempts to reset the card and get back to the requested partition.
* Therefore any error here must result in cancelling the block layer
@@ -1656,31 +1628,34 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
#define MMC_DATA_RETRIES 2
#define MMC_NO_RETRIES (MMC_MAX_RETRIES + 1)
-static int mmc_blk_send_stop(struct mmc_card *card, unsigned int timeout)
+static int mmc_blk_send_stop(struct mmc_card *card)
{
- struct mmc_command cmd = {
- .opcode = MMC_STOP_TRANSMISSION,
- .flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC,
- /* Some hosts wait for busy anyway, so provide a busy timeout */
- .busy_timeout = timeout,
- };
+ unsigned int timeout_ms = MMC_BLK_TIMEOUT_MS;
+ struct mmc_host *host = card->host;
+ struct mmc_command cmd = {};
+ bool use_r1b_resp;
+ int err;
+
+ cmd.opcode = MMC_STOP_TRANSMISSION;
+ use_r1b_resp = mmc_prepare_busy_cmd(host, &cmd, timeout_ms);
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err)
+ return err;
+
+ /* No need to poll when using HW busy detection. */
+ if (host->caps & MMC_CAP_WAIT_WHILE_BUSY && use_r1b_resp)
+ return 0;
- return mmc_wait_for_cmd(card->host, &cmd, 5);
+ return mmc_poll_for_busy(card, timeout_ms, false, MMC_BUSY_IO);
}
-static int mmc_blk_fix_state(struct mmc_card *card, struct request *req)
+static int mmc_blk_fix_state(struct mmc_card *card)
{
- struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
- struct mmc_blk_request *brq = &mqrq->brq;
- unsigned int timeout = mmc_blk_data_timeout_ms(card->host, &brq->data);
int err;
mmc_retune_hold_now(card->host);
-
- mmc_blk_send_stop(card, timeout);
-
- err = mmc_poll_for_busy(card, timeout, false, MMC_BUSY_IO);
-
+ err = mmc_blk_send_stop(card);
mmc_retune_release(card->host);
return err;
@@ -1714,7 +1689,7 @@ static void mmc_blk_read_single(struct mmc_queue *mq, struct request *req)
if (!mmc_host_is_spi(host) &&
!mmc_ready_for_data(status)) {
- err = mmc_blk_fix_state(card, req);
+ err = mmc_blk_fix_state(card);
if (err)
goto error_exit;
}
@@ -1835,7 +1810,7 @@ static void mmc_blk_mq_rw_recovery(struct mmc_queue *mq, struct request *req)
/* Try to get back to "tran" state */
if (!mmc_host_is_spi(mq->card->host) &&
(err || !mmc_ready_for_data(status)))
- err = mmc_blk_fix_state(mq->card, req);
+ err = mmc_blk_fix_state(mq->card);
/*
* Special case for SD cards where the card might record the number of
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 81c55bfd6e0c..3b3adbddf664 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -575,6 +575,7 @@ bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
cmd->busy_timeout = timeout_ms;
return true;
}
+EXPORT_SYMBOL_GPL(mmc_prepare_busy_cmd);
/**
* __mmc_switch - modify EXT_CSD register