aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAustin Shafer <ashafer@badland.io>2021-06-03 01:46:23 +0000
committerWarner Losh <imp@FreeBSD.org>2021-06-03 01:46:23 +0000
commite7dc08415a324d1000cd067fbc12b1ec79e0b2ac (patch)
tree3df3199c246e9dd6a30dc18681ca4efcc0672038
parent9a0f82285322a338548d13fcda07e1d574301190 (diff)
downloadsrc-e7dc08415a324d1000cd067fbc12b1ec79e0b2ac.tar.gz
src-e7dc08415a324d1000cd067fbc12b1ec79e0b2ac.zip
mmc: ignore CRC errors from CMD13 (status) when changing rates
Update mmc_switch_status to ignore a few CRC errrors when asking for the card status after setting the new rate with CMD6. Since the card may take a little while to make the switch, it's possible we'll get a communications error if we sent the command at the wrong time. Several low end laptops needs this workaround as they have a window that seems longer than other systems. This is known to fix at least the Acer Aspire A114-32-P7E5. Reviewed by: imp@, manu@ Differential Revision: https://reviews.freebsd.org/D24740
-rw-r--r--sys/dev/mmc/mmc_subr.c16
1 files changed, 14 insertions, 2 deletions
diff --git a/sys/dev/mmc/mmc_subr.c b/sys/dev/mmc/mmc_subr.c
index 53c9009c6e64..b43a233820bb 100644
--- a/sys/dev/mmc/mmc_subr.c
+++ b/sys/dev/mmc/mmc_subr.c
@@ -193,7 +193,7 @@ int
mmc_switch_status(device_t busdev, device_t dev, uint16_t rca, u_int timeout)
{
struct timeval cur, end;
- int err;
+ int err, crc_timeout;
uint32_t status;
KASSERT(timeout != 0, ("%s: no timeout", __func__));
@@ -205,7 +205,19 @@ mmc_switch_status(device_t busdev, device_t dev, uint16_t rca, u_int timeout)
*/
end.tv_sec = end.tv_usec = 0;
for (;;) {
- err = mmc_send_status(busdev, dev, rca, &status);
+ crc_timeout=0;
+ do {
+ /*
+ * CRC errors indicate that the command wasn't accepted
+ * and executed due to a communications error. Retry
+ * CRC errors a couple of times to cope with transient
+ * failures.
+ *
+ * This is required for some cheap laptops to boot.
+ */
+ err = mmc_send_status(busdev, dev, rca, &status);
+ crc_timeout++;
+ } while (err == MMC_ERR_BADCRC && crc_timeout < 10);
if (err != MMC_ERR_NONE)
break;
if (R1_CURRENT_STATE(status) == R1_STATE_TRAN)