mmc: core: Do not pre-claim host in suspend

Since SDIO drivers may want to do some SDIO operations in their suspend
callback functions, we must not keep the host claimed when calling them.

Daniel Drake reported that libertas_sdio encountered a deadlock in its
suspend function.

Signed-off-by: Ulf Hansson <ulf.hansson@stericsson.com>
Tested-by: Daniel Drake <dsd@laptop.org>
[stable@: please apply to 3.2-stable and 3.3-stable]
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
This commit is contained in:
Ulf Hansson 2012-04-19 11:55:25 +02:00 committed by Chris Ball
parent e1631f989e
commit 7c57091940

View File

@ -2238,6 +2238,7 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
mmc_card_is_removable(host)) mmc_card_is_removable(host))
return err; return err;
mmc_claim_host(host);
if (card && mmc_card_mmc(card) && if (card && mmc_card_mmc(card) &&
(card->ext_csd.cache_size > 0)) { (card->ext_csd.cache_size > 0)) {
enable = !!enable; enable = !!enable;
@ -2255,6 +2256,7 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
card->ext_csd.cache_ctrl = enable; card->ext_csd.cache_ctrl = enable;
} }
} }
mmc_release_host(host);
return err; return err;
} }
@ -2272,49 +2274,32 @@ int mmc_suspend_host(struct mmc_host *host)
cancel_delayed_work(&host->detect); cancel_delayed_work(&host->detect);
mmc_flush_scheduled_work(); mmc_flush_scheduled_work();
if (mmc_try_claim_host(host)) {
err = mmc_cache_ctrl(host, 0);
mmc_release_host(host);
} else {
err = -EBUSY;
}
err = mmc_cache_ctrl(host, 0);
if (err) if (err)
goto out; goto out;
mmc_bus_get(host); mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) { if (host->bus_ops && !host->bus_dead) {
/* if (host->bus_ops->suspend)
* A long response time is not acceptable for device drivers err = host->bus_ops->suspend(host);
* when doing suspend. Prevent mmc_claim_host in the suspend
* sequence, to potentially wait "forever" by trying to
* pre-claim the host.
*/
if (mmc_try_claim_host(host)) {
if (host->bus_ops->suspend) {
err = host->bus_ops->suspend(host);
}
mmc_release_host(host);
if (err == -ENOSYS || !host->bus_ops->resume) { if (err == -ENOSYS || !host->bus_ops->resume) {
/* /*
* We simply "remove" the card in this case. * We simply "remove" the card in this case.
* It will be redetected on resume. (Calling * It will be redetected on resume. (Calling
* bus_ops->remove() with a claimed host can * bus_ops->remove() with a claimed host can
* deadlock.) * deadlock.)
*/ */
if (host->bus_ops->remove) if (host->bus_ops->remove)
host->bus_ops->remove(host); host->bus_ops->remove(host);
mmc_claim_host(host); mmc_claim_host(host);
mmc_detach_bus(host); mmc_detach_bus(host);
mmc_power_off(host); mmc_power_off(host);
mmc_release_host(host); mmc_release_host(host);
host->pm_flags = 0; host->pm_flags = 0;
err = 0; err = 0;
}
} else {
err = -EBUSY;
} }
} }
mmc_bus_put(host); mmc_bus_put(host);