mmc: Retry some MMC cmds on failure
With certain SD cards like Kingston 8GB/16GB UHS card, it is seen that
MMC_CMD_ALL_SEND_CID cmd fails on first attempt, but succeeds
subsequently. Therefore, retry MMC_CMD_ALL_SEND_CID cmd a few time
as done in Linux kernel.
Similarly, it is seen that MMC_CMD_SET_BLOCKLEN may fail on first
attempt, therefore retry this cmd a few times as done in kernel.
To make it clear that those are optionnal workarounds, a new Kconfig
option 'MMC_QUIRKS' is added (enabled by default).
Signed-off-by: Vignesh R <vigneshr@ti.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 6278d1f..26589b8 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -279,6 +279,7 @@
int mmc_set_blocklen(struct mmc *mmc, int len)
{
struct mmc_cmd cmd;
+ int err;
if (mmc->ddr_mode)
return 0;
@@ -287,7 +288,24 @@
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = len;
- return mmc_send_cmd(mmc, &cmd, NULL);
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+
+#ifdef CONFIG_MMC_QUIRKS
+ if (err && (mmc->quirks & MMC_QUIRK_RETRY_SET_BLOCKLEN)) {
+ int retries = 4;
+ /*
+ * It has been seen that SET_BLOCKLEN may fail on the first
+ * attempt, let's try a few more time
+ */
+ do {
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (!err)
+ break;
+ } while (retries--);
+ }
+#endif
+
+ return err;
}
static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
@@ -1881,7 +1899,6 @@
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = 1;
err = mmc_send_cmd(mmc, &cmd, NULL);
-
if (err)
return err;
}
@@ -1895,6 +1912,21 @@
err = mmc_send_cmd(mmc, &cmd, NULL);
+#ifdef CONFIG_MMC_QUIRKS
+ if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) {
+ int retries = 4;
+ /*
+ * It has been seen that SEND_CID may fail on the first
+ * attempt, let's try a few more time
+ */
+ do {
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (!err)
+ break;
+ } while (retries--);
+ }
+#endif
+
if (err)
return err;
@@ -2239,6 +2271,11 @@
if (err)
return err;
+#ifdef CONFIG_MMC_QUIRKS
+ mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN |
+ MMC_QUIRK_RETRY_SEND_CID;
+#endif
+
err = mmc_power_cycle(mmc);
if (err) {
/*