Commit 6966e609 authored by Ulf Hansson's avatar Ulf Hansson
Browse files

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: default avatarUlf Hansson <ulf.hansson@linaro.org>
Reviewed-by: default avatarShawn Lin <shawn.lin@rock-chips.com>
Link: https://lore.kernel.org/r/20210702134229.357717-4-ulf.hansson@linaro.org
parent 46810815
Loading
Loading
Loading
Loading
+29 −40
Original line number Diff line number Diff line
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -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)