mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-11 15:37:23 +00:00
mmc: Add some helper functions for retrying on error
All of the existing quirks add retries to various calls of mmc_send_cmd. mmc_send_cmd_quirks is a helper function to do this retrying behavior. It checks if quirks mode is enabled, and if a specific quirk is activated it retries on error. This also adds mmc_send_cmd_retry, which retries on error every time (instead of if a quirk is activated). Signed-off-by: Sean Anderson <seanga2@gmail.com> Reviewed-by: Jaehoon Chung <jh80.chung@samsung.com> Reviewed-by: Jaehoon Chung <jh80.chung@samsung.com>
This commit is contained in:
parent
7889951d0f
commit
da12917060
1 changed files with 58 additions and 83 deletions
|
@ -207,26 +207,65 @@ int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
|
|||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* mmc_send_cmd_retry() - send a command to the mmc device, retrying on error
|
||||
*
|
||||
* @dev: device to receive the command
|
||||
* @cmd: command to send
|
||||
* @data: additional data to send/receive
|
||||
* @retries: how many times to retry; mmc_send_cmd is always called at least
|
||||
* once
|
||||
* @return 0 if ok, -ve on error
|
||||
*/
|
||||
static int mmc_send_cmd_retry(struct mmc *mmc, struct mmc_cmd *cmd,
|
||||
struct mmc_data *data, uint retries)
|
||||
{
|
||||
int ret;
|
||||
|
||||
do {
|
||||
ret = mmc_send_cmd(mmc, cmd, data);
|
||||
} while (ret && retries--);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* mmc_send_cmd_quirks() - send a command to the mmc device, retrying if a
|
||||
* specific quirk is enabled
|
||||
*
|
||||
* @dev: device to receive the command
|
||||
* @cmd: command to send
|
||||
* @data: additional data to send/receive
|
||||
* @quirk: retry only if this quirk is enabled
|
||||
* @retries: how many times to retry; mmc_send_cmd is always called at least
|
||||
* once
|
||||
* @return 0 if ok, -ve on error
|
||||
*/
|
||||
static int mmc_send_cmd_quirks(struct mmc *mmc, struct mmc_cmd *cmd,
|
||||
struct mmc_data *data, u32 quirk, uint retries)
|
||||
{
|
||||
if (CONFIG_IS_ENABLED(MMC_QUIRKS) && mmc->quirks & quirk)
|
||||
return mmc_send_cmd_retry(mmc, cmd, data, retries);
|
||||
else
|
||||
return mmc_send_cmd(mmc, cmd, data);
|
||||
}
|
||||
|
||||
int mmc_send_status(struct mmc *mmc, unsigned int *status)
|
||||
{
|
||||
struct mmc_cmd cmd;
|
||||
int err, retries = 5;
|
||||
int ret;
|
||||
|
||||
cmd.cmdidx = MMC_CMD_SEND_STATUS;
|
||||
cmd.resp_type = MMC_RSP_R1;
|
||||
if (!mmc_host_is_spi(mmc))
|
||||
cmd.cmdarg = mmc->rca << 16;
|
||||
|
||||
while (retries--) {
|
||||
err = mmc_send_cmd(mmc, &cmd, NULL);
|
||||
if (!err) {
|
||||
mmc_trace_state(mmc, &cmd);
|
||||
*status = cmd.response[0];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
ret = mmc_send_cmd_retry(mmc, &cmd, NULL, 4);
|
||||
mmc_trace_state(mmc, &cmd);
|
||||
return -ECOMM;
|
||||
if (!ret)
|
||||
*status = cmd.response[0];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mmc_poll_for_busy(struct mmc *mmc, int timeout_ms)
|
||||
|
@ -274,7 +313,6 @@ int mmc_poll_for_busy(struct mmc *mmc, int timeout_ms)
|
|||
int mmc_set_blocklen(struct mmc *mmc, int len)
|
||||
{
|
||||
struct mmc_cmd cmd;
|
||||
int err;
|
||||
|
||||
if (mmc->ddr_mode)
|
||||
return 0;
|
||||
|
@ -283,24 +321,8 @@ int mmc_set_blocklen(struct mmc *mmc, int len)
|
|||
cmd.resp_type = MMC_RSP_R1;
|
||||
cmd.cmdarg = len;
|
||||
|
||||
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;
|
||||
return mmc_send_cmd_quirks(mmc, &cmd, NULL,
|
||||
MMC_QUIRK_RETRY_SET_BLOCKLEN, 4);
|
||||
}
|
||||
|
||||
#ifdef MMC_SUPPORTS_TUNING
|
||||
|
@ -771,7 +793,6 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value,
|
|||
int timeout_ms = DEFAULT_CMD6_TIMEOUT_MS;
|
||||
bool is_part_switch = (set == EXT_CSD_CMD_SET_NORMAL) &&
|
||||
(index == EXT_CSD_PART_CONF);
|
||||
int retries = 3;
|
||||
int ret;
|
||||
|
||||
if (mmc->gen_cmd6_time)
|
||||
|
@ -786,10 +807,7 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value,
|
|||
(index << 16) |
|
||||
(value << 8);
|
||||
|
||||
do {
|
||||
ret = mmc_send_cmd(mmc, &cmd, NULL);
|
||||
} while (ret && retries-- > 0);
|
||||
|
||||
ret = mmc_send_cmd_retry(mmc, &cmd, NULL, 3);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1287,22 +1305,15 @@ static int sd_get_capabilities(struct mmc *mmc)
|
|||
cmd.resp_type = MMC_RSP_R1;
|
||||
cmd.cmdarg = 0;
|
||||
|
||||
timeout = 3;
|
||||
|
||||
retry_scr:
|
||||
data.dest = (char *)scr;
|
||||
data.blocksize = 8;
|
||||
data.blocks = 1;
|
||||
data.flags = MMC_DATA_READ;
|
||||
|
||||
err = mmc_send_cmd(mmc, &cmd, &data);
|
||||
|
||||
if (err) {
|
||||
if (timeout--)
|
||||
goto retry_scr;
|
||||
err = mmc_send_cmd_retry(mmc, &cmd, &data, 3);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
mmc->scr[0] = __be32_to_cpu(scr[0]);
|
||||
mmc->scr[1] = __be32_to_cpu(scr[1]);
|
||||
|
@ -1463,28 +1474,13 @@ static int sd_read_ssr(struct mmc *mmc)
|
|||
struct mmc_cmd cmd;
|
||||
ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
|
||||
struct mmc_data data;
|
||||
int timeout = 3;
|
||||
unsigned int au, eo, et, es;
|
||||
|
||||
cmd.cmdidx = MMC_CMD_APP_CMD;
|
||||
cmd.resp_type = MMC_RSP_R1;
|
||||
cmd.cmdarg = mmc->rca << 16;
|
||||
|
||||
err = mmc_send_cmd(mmc, &cmd, NULL);
|
||||
#ifdef CONFIG_MMC_QUIRKS
|
||||
if (err && (mmc->quirks & MMC_QUIRK_RETRY_APP_CMD)) {
|
||||
int retries = 4;
|
||||
/*
|
||||
* It has been seen that APP_CMD may fail on the first
|
||||
* attempt, let's try a few more times
|
||||
*/
|
||||
do {
|
||||
err = mmc_send_cmd(mmc, &cmd, NULL);
|
||||
if (!err)
|
||||
break;
|
||||
} while (retries--);
|
||||
}
|
||||
#endif
|
||||
err = mmc_send_cmd_quirks(mmc, &cmd, NULL, MMC_QUIRK_RETRY_APP_CMD, 4);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -1492,19 +1488,14 @@ static int sd_read_ssr(struct mmc *mmc)
|
|||
cmd.resp_type = MMC_RSP_R1;
|
||||
cmd.cmdarg = 0;
|
||||
|
||||
retry_ssr:
|
||||
data.dest = (char *)ssr;
|
||||
data.blocksize = 64;
|
||||
data.blocks = 1;
|
||||
data.flags = MMC_DATA_READ;
|
||||
|
||||
err = mmc_send_cmd(mmc, &cmd, &data);
|
||||
if (err) {
|
||||
if (timeout--)
|
||||
goto retry_ssr;
|
||||
|
||||
err = mmc_send_cmd_retry(mmc, &cmd, &data, 3);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
ssr[i] = be32_to_cpu(ssr[i]);
|
||||
|
@ -2441,23 +2432,7 @@ static int mmc_startup(struct mmc *mmc)
|
|||
cmd.resp_type = MMC_RSP_R2;
|
||||
cmd.cmdarg = 0;
|
||||
|
||||
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
|
||||
|
||||
err = mmc_send_cmd_quirks(mmc, &cmd, NULL, MMC_QUIRK_RETRY_SEND_CID, 4);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
Loading…
Reference in a new issue