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:
parent
e1631f989e
commit
7c57091940
1 changed files with 20 additions and 35 deletions
|
@ -2238,6 +2238,7 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
|
|||
mmc_card_is_removable(host))
|
||||
return err;
|
||||
|
||||
mmc_claim_host(host);
|
||||
if (card && mmc_card_mmc(card) &&
|
||||
(card->ext_csd.cache_size > 0)) {
|
||||
enable = !!enable;
|
||||
|
@ -2255,6 +2256,7 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
|
|||
card->ext_csd.cache_ctrl = enable;
|
||||
}
|
||||
}
|
||||
mmc_release_host(host);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -2272,49 +2274,32 @@ int mmc_suspend_host(struct mmc_host *host)
|
|||
|
||||
cancel_delayed_work(&host->detect);
|
||||
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)
|
||||
goto out;
|
||||
|
||||
mmc_bus_get(host);
|
||||
if (host->bus_ops && !host->bus_dead) {
|
||||
|
||||
/*
|
||||
* A long response time is not acceptable for device drivers
|
||||
* 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 (host->bus_ops->suspend)
|
||||
err = host->bus_ops->suspend(host);
|
||||
|
||||
if (err == -ENOSYS || !host->bus_ops->resume) {
|
||||
/*
|
||||
* We simply "remove" the card in this case.
|
||||
* It will be redetected on resume. (Calling
|
||||
* bus_ops->remove() with a claimed host can
|
||||
* deadlock.)
|
||||
*/
|
||||
if (host->bus_ops->remove)
|
||||
host->bus_ops->remove(host);
|
||||
mmc_claim_host(host);
|
||||
mmc_detach_bus(host);
|
||||
mmc_power_off(host);
|
||||
mmc_release_host(host);
|
||||
host->pm_flags = 0;
|
||||
err = 0;
|
||||
}
|
||||
} else {
|
||||
err = -EBUSY;
|
||||
if (err == -ENOSYS || !host->bus_ops->resume) {
|
||||
/*
|
||||
* We simply "remove" the card in this case.
|
||||
* It will be redetected on resume. (Calling
|
||||
* bus_ops->remove() with a claimed host can
|
||||
* deadlock.)
|
||||
*/
|
||||
if (host->bus_ops->remove)
|
||||
host->bus_ops->remove(host);
|
||||
mmc_claim_host(host);
|
||||
mmc_detach_bus(host);
|
||||
mmc_power_off(host);
|
||||
mmc_release_host(host);
|
||||
host->pm_flags = 0;
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
mmc_bus_put(host);
|
||||
|
|
Loading…
Reference in a new issue