mmc: core: Avoid hogging the CPU while polling for busy after I/O writes
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
This commit is contained in:
+29
-40
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user