mmc: propagate error codes back from bus drivers' suspend/resume methods
Especially for SDIO drivers which may have special conditions/errors to report, it is a good thing to relay the returned error code back to upper layers. This also allows for the rationalization of the resume path where code to "remove" a no-longer-existing or replaced card was duplicated into the MMC, SD and SDIO bus drivers. In the SDIO case, if a function suspend method returns an error, then all previously suspended functions are resumed and the error returned. An exception is made for -ENOSYS which the core interprets as "we don't support suspend so just kick the card out for suspend and return success". When resuming SDIO cards, the core code only validates the manufacturer and product IDs to make sure the same kind of card is still present before invoking functions resume methods. It's the function driver's responsibility to perform further tests to confirm that the actual same card is present (same MAC address, etc.) and return an error otherwise. Signed-off-by: Nicolas Pitre <nico@marvell.com> Cc: <linux-mmc@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
committed by
Linus Torvalds
parent
17d33e14f7
commit
95cdfb72b9
@@ -1236,6 +1236,8 @@ EXPORT_SYMBOL(mmc_card_can_sleep);
|
||||
*/
|
||||
int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (host->caps & MMC_CAP_DISABLE)
|
||||
cancel_delayed_work(&host->disable);
|
||||
cancel_delayed_work(&host->detect);
|
||||
@@ -1244,21 +1246,26 @@ int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
|
||||
mmc_bus_get(host);
|
||||
if (host->bus_ops && !host->bus_dead) {
|
||||
if (host->bus_ops->suspend)
|
||||
host->bus_ops->suspend(host);
|
||||
if (!host->bus_ops->resume) {
|
||||
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.
|
||||
*/
|
||||
if (host->bus_ops->remove)
|
||||
host->bus_ops->remove(host);
|
||||
|
||||
mmc_claim_host(host);
|
||||
mmc_detach_bus(host);
|
||||
mmc_release_host(host);
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
mmc_bus_put(host);
|
||||
|
||||
mmc_power_off(host);
|
||||
if (!err)
|
||||
mmc_power_off(host);
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(mmc_suspend_host);
|
||||
@@ -1269,12 +1276,26 @@ EXPORT_SYMBOL(mmc_suspend_host);
|
||||
*/
|
||||
int mmc_resume_host(struct mmc_host *host)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
mmc_bus_get(host);
|
||||
if (host->bus_ops && !host->bus_dead) {
|
||||
mmc_power_up(host);
|
||||
mmc_select_voltage(host, host->ocr);
|
||||
BUG_ON(!host->bus_ops->resume);
|
||||
host->bus_ops->resume(host);
|
||||
err = host->bus_ops->resume(host);
|
||||
if (err) {
|
||||
printk(KERN_WARNING "%s: error %d during resume "
|
||||
"(card was removed?)\n",
|
||||
mmc_hostname(host), err);
|
||||
if (host->bus_ops->remove)
|
||||
host->bus_ops->remove(host);
|
||||
mmc_claim_host(host);
|
||||
mmc_detach_bus(host);
|
||||
mmc_release_host(host);
|
||||
/* no need to bother upper layers */
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
mmc_bus_put(host);
|
||||
|
||||
@@ -1284,7 +1305,7 @@ int mmc_resume_host(struct mmc_host *host)
|
||||
*/
|
||||
mmc_detect_change(host, 1);
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(mmc_resume_host);
|
||||
|
Reference in New Issue
Block a user