Skip to content

Commit

Permalink
mmc: mmc: Improve reliability of mmc_select_hs200()
Browse files Browse the repository at this point in the history
Currently mmc_select_hs200() uses __mmc_switch() which checks the
success of the switch to HS200 mode using CMD13 (SEND_STATUS).
The problem is that it does that using the timing settings of legacy
mode.  That is prone to error, not least because the timing parameters
for legacy mode are tighter than the timing parameters for HS200 mode.

In the case when CMD13 polling is used (i.e. not MMC_CAP_WAIT_WHILE_BUSY)
with the switch command, it must be assumed that using different modes on
the card and host must work.

However in the case when CMD13 polling is not used
(i.e. MMC_CAP_WAIT_WHILE_BUSY) mmc_select_hs200() can be made more
reliable by setting the host to the correct timing before sending CMD13.

This patch does that.

A complication is that the caller, mmc_select_timing(), will ignore a
switch error (indicated by -EBADMSG), assume the old mode is valid
and continue, so the old timing must be restored in that case.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: <stable@vger.kernel.org> # 4.2+
Tested-by: Alim Akhtar <alim.akhtar@samsung.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
  • Loading branch information
Adrian Hunter authored and Ulf Hansson committed Nov 9, 2015
1 parent 26d49fe commit 1815e61
Showing 1 changed file with 22 additions and 3 deletions.
25 changes: 22 additions & 3 deletions drivers/mmc/core/mmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1219,6 +1219,8 @@ static void mmc_select_driver_type(struct mmc_card *card)
static int mmc_select_hs200(struct mmc_card *card)
{
struct mmc_host *host = card->host;
bool send_status = true;
unsigned int old_timing;
int err = -EINVAL;
u8 val;

Expand All @@ -1234,6 +1236,9 @@ static int mmc_select_hs200(struct mmc_card *card)

mmc_select_driver_type(card);

if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
send_status = false;

/*
* Set the bus width(4 or 8) with host's support and
* switch to HS200 mode if bus width is set successfully.
Expand All @@ -1245,11 +1250,25 @@ static int mmc_select_hs200(struct mmc_card *card)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time,
true, true, true);
if (!err)
mmc_set_timing(host, MMC_TIMING_MMC_HS200);
true, send_status, true);
if (err)
goto err;
old_timing = host->ios.timing;
mmc_set_timing(host, MMC_TIMING_MMC_HS200);
if (!send_status) {
err = mmc_switch_status(card);
/*
* mmc_select_timing() assumes timing has not changed if
* it is a switch error.
*/
if (err == -EBADMSG)
mmc_set_timing(host, old_timing);
}
}
err:
if (err)
pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
__func__, err);
return err;
}

Expand Down

0 comments on commit 1815e61

Please sign in to comment.