| From fa146cf7974738fb377de1d7bfe57096cc3bf829 Mon Sep 17 00:00:00 2001 |
| From: Chaotian Jing <chaotian.jing@mediatek.com> |
| Date: Thu, 5 Sep 2019 15:53:18 +0800 |
| Subject: [PATCH] mmc: block: Add CMD13 polling for MMC IOCTLS with R1B |
| response |
| |
| commit a0d4c7eb71dd08a89ad631177bb0cbbabd598f84 upstream. |
| |
| MMC IOCTLS with R1B responses may cause the card to enter the busy state, |
| which means it's not ready to receive a new request. To prevent new |
| requests from being sent to the card, use a CMD13 polling loop to verify |
| that the card returns to the transfer state, before completing the request. |
| |
| Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com> |
| Reviewed-by: Avri Altman <avri.altman@wdc.com> |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c |
| index aa7c19f7e298..95b41c0891d0 100644 |
| --- a/drivers/mmc/core/block.c |
| +++ b/drivers/mmc/core/block.c |
| @@ -408,38 +408,6 @@ static int mmc_blk_ioctl_copy_to_user(struct mmc_ioc_cmd __user *ic_ptr, |
| return 0; |
| } |
| |
| -static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status, |
| - u32 retries_max) |
| -{ |
| - int err; |
| - u32 retry_count = 0; |
| - |
| - if (!status || !retries_max) |
| - return -EINVAL; |
| - |
| - do { |
| - err = __mmc_send_status(card, status, 5); |
| - if (err) |
| - break; |
| - |
| - if (!R1_STATUS(*status) && |
| - (R1_CURRENT_STATE(*status) != R1_STATE_PRG)) |
| - break; /* RPMB programming operation complete */ |
| - |
| - /* |
| - * Rechedule to give the MMC device a chance to continue |
| - * processing the previous command without being polled too |
| - * frequently. |
| - */ |
| - usleep_range(1000, 5000); |
| - } while (++retry_count < retries_max); |
| - |
| - if (retry_count == retries_max) |
| - err = -EPERM; |
| - |
| - return err; |
| -} |
| - |
| static int ioctl_do_sanitize(struct mmc_card *card) |
| { |
| int err; |
| @@ -468,6 +436,58 @@ static int ioctl_do_sanitize(struct mmc_card *card) |
| return err; |
| } |
| |
| +static inline bool mmc_blk_in_tran_state(u32 status) |
| +{ |
| + /* |
| + * Some cards mishandle the status bits, so make sure to check both the |
| + * busy indication and the card state. |
| + */ |
| + return status & R1_READY_FOR_DATA && |
| + (R1_CURRENT_STATE(status) == R1_STATE_TRAN); |
| +} |
| + |
| +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; |
| + } |
| + |
| + /* |
| + * Some cards mishandle the status bits, |
| + * so make sure to check both the busy |
| + * indication and the card state. |
| + */ |
| + } while (!mmc_blk_in_tran_state(status)); |
| + |
| + return err; |
| +} |
| + |
| static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, |
| struct mmc_blk_ioc_data *idata) |
| { |
| @@ -477,7 +497,6 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, |
| struct scatterlist sg; |
| int err; |
| unsigned int target_part; |
| - u32 status = 0; |
| |
| if (!card || !md || !idata) |
| return -EINVAL; |
| @@ -611,16 +630,12 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, |
| |
| memcpy(&(idata->ic.response), cmd.resp, sizeof(cmd.resp)); |
| |
| - if (idata->rpmb) { |
| + if (idata->rpmb || (cmd.flags & MMC_RSP_R1B)) { |
| /* |
| - * Ensure RPMB command has completed by polling CMD13 |
| + * Ensure RPMB/R1B command has completed by polling CMD13 |
| * "Send Status". |
| */ |
| - err = ioctl_rpmb_card_status_poll(card, &status, 5); |
| - if (err) |
| - dev_err(mmc_dev(card->host), |
| - "%s: Card Status=0x%08X, error %d\n", |
| - __func__, status, err); |
| + err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, NULL); |
| } |
| |
| return err; |
| @@ -970,58 +985,6 @@ static unsigned int mmc_blk_data_timeout_ms(struct mmc_host *host, |
| return ms; |
| } |
| |
| -static inline bool mmc_blk_in_tran_state(u32 status) |
| -{ |
| - /* |
| - * Some cards mishandle the status bits, so make sure to check both the |
| - * busy indication and the card state. |
| - */ |
| - return status & R1_READY_FOR_DATA && |
| - (R1_CURRENT_STATE(status) == R1_STATE_TRAN); |
| -} |
| - |
| -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; |
| - } |
| - |
| - /* |
| - * Some cards mishandle the status bits, |
| - * so make sure to check both the busy |
| - * indication and the card state. |
| - */ |
| - } while (!mmc_blk_in_tran_state(status)); |
| - |
| - return err; |
| -} |
| - |
| static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host, |
| int type) |
| { |
| -- |
| 2.7.4 |
| |