mmc: core: Respect host's max_busy_timeout when sending sleep cmd

When sending the sleep command for host drivers supporting
MMC_CAP_WAIT_WHILE_BUSY, we need to confirm that max_busy_timeout is
big enough comparing to the sleep timeout specified from card's
EXT_CSD. If this isn't case, we use a R1 response instead of R1B and
fallback to use a delay instead.

Do note that a max_busy_timeout set to zero by the host, is interpreted
as it can cope with whatever timeout the mmc core provides it with.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Chris Ball <chris@printf.net>
This commit is contained in:
Ulf Hansson 2014-01-14 23:17:36 +01:00 committed by Chris Ball
parent 57de31f635
commit cb962e04b0

View file

@ -1358,6 +1358,7 @@ static int mmc_sleep(struct mmc_host *host)
{ {
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
struct mmc_card *card = host->card; struct mmc_card *card = host->card;
unsigned int timeout_ms = DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000);
int err; int err;
err = mmc_deselect_cards(host); err = mmc_deselect_cards(host);
@ -1368,7 +1369,19 @@ static int mmc_sleep(struct mmc_host *host)
cmd.arg = card->rca << 16; cmd.arg = card->rca << 16;
cmd.arg |= 1 << 15; cmd.arg |= 1 << 15;
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; /*
* If the max_busy_timeout of the host is specified, validate it against
* the sleep cmd timeout. A failure means we need to prevent the host
* from doing hw busy detection, which is done by converting to a R1
* response instead of a R1B.
*/
if (host->max_busy_timeout && (timeout_ms > host->max_busy_timeout)) {
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
} else {
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
cmd.busy_timeout = timeout_ms;
}
err = mmc_wait_for_cmd(host, &cmd, 0); err = mmc_wait_for_cmd(host, &cmd, 0);
if (err) if (err)
return err; return err;
@ -1379,8 +1392,8 @@ static int mmc_sleep(struct mmc_host *host)
* SEND_STATUS command to poll the status because that command (and most * SEND_STATUS command to poll the status because that command (and most
* others) is invalid while the card sleeps. * others) is invalid while the card sleeps.
*/ */
if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY)) if (!cmd.busy_timeout || !(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000)); mmc_delay(timeout_ms);
return err; return err;
} }