Skip to content

Commit

Permalink
mmc: core: Avoid hogging the CPU while polling for busy after I/O writes
Browse files Browse the repository at this point in the history
[ Upstream commit 6966e60 ]

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
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
storulf authored and gregkh committed Sep 18, 2021
1 parent 00d27b4 commit c0598b6
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 40 deletions.
69 changes: 29 additions & 40 deletions drivers/mmc/core/block.c
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions drivers/mmc/core/mmc_ops.c
Expand Up @@ -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)
Expand Down

0 comments on commit c0598b6

Please sign in to comment.