aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2015-10-28 08:25:40 -0400
committerUlf Hansson <ulf.hansson@linaro.org>2015-11-09 07:12:08 -0500
commit1815e61b1a7efe81017a883e817292daf7d2f922 (patch)
tree71bdab46ad5549d57472af8f5259100d4ebfb4b8 /drivers/mmc
parent26d49fe7195385f2f1e406feddb01c16b53e77b6 (diff)
mmc: mmc: Improve reliability of mmc_select_hs200()
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>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/core/mmc.c25
1 files changed, 22 insertions, 3 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index c793fda27321..2cef40ce9851 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1219,6 +1219,8 @@ static void mmc_select_driver_type(struct mmc_card *card)
1219static int mmc_select_hs200(struct mmc_card *card) 1219static int mmc_select_hs200(struct mmc_card *card)
1220{ 1220{
1221 struct mmc_host *host = card->host; 1221 struct mmc_host *host = card->host;
1222 bool send_status = true;
1223 unsigned int old_timing;
1222 int err = -EINVAL; 1224 int err = -EINVAL;
1223 u8 val; 1225 u8 val;
1224 1226
@@ -1234,6 +1236,9 @@ static int mmc_select_hs200(struct mmc_card *card)
1234 1236
1235 mmc_select_driver_type(card); 1237 mmc_select_driver_type(card);
1236 1238
1239 if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
1240 send_status = false;
1241
1237 /* 1242 /*
1238 * Set the bus width(4 or 8) with host's support and 1243 * Set the bus width(4 or 8) with host's support and
1239 * switch to HS200 mode if bus width is set successfully. 1244 * switch to HS200 mode if bus width is set successfully.
@@ -1245,11 +1250,25 @@ static int mmc_select_hs200(struct mmc_card *card)
1245 err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, 1250 err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
1246 EXT_CSD_HS_TIMING, val, 1251 EXT_CSD_HS_TIMING, val,
1247 card->ext_csd.generic_cmd6_time, 1252 card->ext_csd.generic_cmd6_time,
1248 true, true, true); 1253 true, send_status, true);
1249 if (!err) 1254 if (err)
1250 mmc_set_timing(host, MMC_TIMING_MMC_HS200); 1255 goto err;
1256 old_timing = host->ios.timing;
1257 mmc_set_timing(host, MMC_TIMING_MMC_HS200);
1258 if (!send_status) {
1259 err = mmc_switch_status(card);
1260 /*
1261 * mmc_select_timing() assumes timing has not changed if
1262 * it is a switch error.
1263 */
1264 if (err == -EBADMSG)
1265 mmc_set_timing(host, old_timing);
1266 }
1251 } 1267 }
1252err: 1268err:
1269 if (err)
1270 pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
1271 __func__, err);
1253 return err; 1272 return err;
1254} 1273}
1255 1274