aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2016-11-02 09:49:08 -0400
committerUlf Hansson <ulf.hansson@linaro.org>2016-11-07 07:26:42 -0500
commit6ebebeab5185f50d55c6a24d0abe47e5dac1b191 (patch)
treebd172a01a2f256372da614db6ba91c1dd6f8b606
parent3a667e3ff78ae81afc49343c753864cc1ede2f77 (diff)
mmc: sdhci: Fix CMD line reset interfering with ongoing data transfer
CMD line reset during an ongoing data transfer can cause the data transfer to hang. Fix by delaying the reset until the data transfer is finished. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Cc: stable@vger.kernel.org # v4.8+ Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
-rw-r--r--drivers/mmc/host/sdhci.c23
1 files changed, 16 insertions, 7 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 71654b90227f..fd0f24cddad4 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2286,10 +2286,8 @@ static bool sdhci_request_done(struct sdhci_host *host)
2286 2286
2287 for (i = 0; i < SDHCI_MAX_MRQS; i++) { 2287 for (i = 0; i < SDHCI_MAX_MRQS; i++) {
2288 mrq = host->mrqs_done[i]; 2288 mrq = host->mrqs_done[i];
2289 if (mrq) { 2289 if (mrq)
2290 host->mrqs_done[i] = NULL;
2291 break; 2290 break;
2292 }
2293 } 2291 }
2294 2292
2295 if (!mrq) { 2293 if (!mrq) {
@@ -2320,6 +2318,17 @@ static bool sdhci_request_done(struct sdhci_host *host)
2320 * upon error conditions. 2318 * upon error conditions.
2321 */ 2319 */
2322 if (sdhci_needs_reset(host, mrq)) { 2320 if (sdhci_needs_reset(host, mrq)) {
2321 /*
2322 * Do not finish until command and data lines are available for
2323 * reset. Note there can only be one other mrq, so it cannot
2324 * also be in mrqs_done, otherwise host->cmd and host->data_cmd
2325 * would both be null.
2326 */
2327 if (host->cmd || host->data_cmd) {
2328 spin_unlock_irqrestore(&host->lock, flags);
2329 return true;
2330 }
2331
2323 /* Some controllers need this kick or reset won't work here */ 2332 /* Some controllers need this kick or reset won't work here */
2324 if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) 2333 if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
2325 /* This is to force an update */ 2334 /* This is to force an update */
@@ -2327,10 +2336,8 @@ static bool sdhci_request_done(struct sdhci_host *host)
2327 2336
2328 /* Spec says we should do both at the same time, but Ricoh 2337 /* Spec says we should do both at the same time, but Ricoh
2329 controllers do not like that. */ 2338 controllers do not like that. */
2330 if (!host->cmd) 2339 sdhci_do_reset(host, SDHCI_RESET_CMD);
2331 sdhci_do_reset(host, SDHCI_RESET_CMD); 2340 sdhci_do_reset(host, SDHCI_RESET_DATA);
2332 if (!host->data_cmd)
2333 sdhci_do_reset(host, SDHCI_RESET_DATA);
2334 2341
2335 host->pending_reset = false; 2342 host->pending_reset = false;
2336 } 2343 }
@@ -2338,6 +2345,8 @@ static bool sdhci_request_done(struct sdhci_host *host)
2338 if (!sdhci_has_requests(host)) 2345 if (!sdhci_has_requests(host))
2339 sdhci_led_deactivate(host); 2346 sdhci_led_deactivate(host);
2340 2347
2348 host->mrqs_done[i] = NULL;
2349
2341 mmiowb(); 2350 mmiowb();
2342 spin_unlock_irqrestore(&host->lock, flags); 2351 spin_unlock_irqrestore(&host->lock, flags);
2343 2352