| From 5d435933376962b107bd76970912e7e80247dcc7 Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?Christian=20L=C3=B6hle?= <CLoehle@hyperstone.com> |
| Date: Thu, 24 Mar 2022 14:18:41 +0000 |
| Subject: mmc: block: Check for errors after write on SPI |
| |
| From: Christian Lรถhle <CLoehle@hyperstone.com> |
| |
| commit 5d435933376962b107bd76970912e7e80247dcc7 upstream. |
| |
| Introduce a SEND_STATUS check for writes through SPI to not mark |
| an unsuccessful write as successful. |
| |
| Since SPI SD/MMC does not have states, after a write, the card will |
| just hold the line LOW until it is ready again. The driver marks the |
| write therefore as completed as soon as it reads something other than |
| all zeroes. |
| The driver does not distinguish from a card no longer signalling busy |
| and it being disconnected (and the line being pulled-up by the host). |
| This lead to writes being marked as successful when disconnecting |
| a busy card. |
| Now the card is ensured to be still connected by an additional CMD13, |
| just like non-SPI is ensured to go back to TRAN state. |
| |
| While at it and since we already poll for the post-write status anyway, |
| we might as well check for SPIs error bits (any of them). |
| |
| The disconnecting card problem is reproducable for me after continuous |
| write activity and randomly disconnecting, around every 20-50 tries |
| on SPI DS for some card. |
| |
| Fixes: 7213d175e3b6f ("MMC/SD card driver learns SPI") |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Christian Loehle <cloehle@hyperstone.com> |
| Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> |
| Link: https://lore.kernel.org/r/76f6f5d2b35543bab3dfe438f268609c@hyperstone.com |
| Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/mmc/core/block.c | 34 +++++++++++++++++++++++++++++++++- |
| 1 file changed, 33 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/mmc/core/block.c |
| +++ b/drivers/mmc/core/block.c |
| @@ -1880,6 +1880,31 @@ static inline bool mmc_blk_rq_error(stru |
| brq->data.error || brq->cmd.resp[0] & CMD_ERRORS; |
| } |
| |
| +static int mmc_spi_err_check(struct mmc_card *card) |
| +{ |
| + u32 status = 0; |
| + int err; |
| + |
| + /* |
| + * SPI does not have a TRAN state we have to wait on, instead the |
| + * card is ready again when it no longer holds the line LOW. |
| + * We still have to ensure two things here before we know the write |
| + * was successful: |
| + * 1. The card has not disconnected during busy and we actually read our |
| + * own pull-up, thinking it was still connected, so ensure it |
| + * still responds. |
| + * 2. Check for any error bits, in particular R1_SPI_IDLE to catch a |
| + * just reconnected card after being disconnected during busy. |
| + */ |
| + err = __mmc_send_status(card, &status, 0); |
| + if (err) |
| + return err; |
| + /* All R1 and R2 bits of SPI are errors in our case */ |
| + if (status) |
| + return -EIO; |
| + return 0; |
| +} |
| + |
| static int mmc_blk_busy_cb(void *cb_data, bool *busy) |
| { |
| struct mmc_blk_busy_data *data = cb_data; |
| @@ -1903,9 +1928,16 @@ static int mmc_blk_card_busy(struct mmc_ |
| struct mmc_blk_busy_data cb_data; |
| int err; |
| |
| - if (mmc_host_is_spi(card->host) || rq_data_dir(req) == READ) |
| + if (rq_data_dir(req) == READ) |
| return 0; |
| |
| + if (mmc_host_is_spi(card->host)) { |
| + err = mmc_spi_err_check(card); |
| + if (err) |
| + mqrq->brq.data.bytes_xfered = 0; |
| + return err; |
| + } |
| + |
| cb_data.card = card; |
| cb_data.status = 0; |
| err = __mmc_poll_for_busy(card, MMC_BLK_TIMEOUT_MS, &mmc_blk_busy_cb, |