forked from Minki/linux
mmc: core: Validate suspend prerequisites for SDIO at SUSPEND_PREPARE
This patch moves the validation for all the suspend prerequisites to be done at SUSPEND_PREPARE notification. Previously in the SDIO case parts of the validation was done from mmc_suspend_host. This patch invents a new pre_suspend bus_ops callback and implements it for SDIO. Returning an error code from it, will mean at SUSPEND_PREPARE notification, the card will be removed before proceeding with the suspend sequence. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Tested-by: Jaehoon Chung <jh80.chung@samsung.com> Signed-off-by: Chris Ball <cjb@laptop.org>
This commit is contained in:
parent
58a8a4a1a5
commit
810caddba4
@ -2628,22 +2628,6 @@ int mmc_suspend_host(struct mmc_host *host)
|
||||
if (host->bus_ops && !host->bus_dead) {
|
||||
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.)
|
||||
*/
|
||||
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);
|
||||
|
||||
@ -2706,6 +2690,7 @@ int mmc_pm_notify(struct notifier_block *notify_block,
|
||||
struct mmc_host *host = container_of(
|
||||
notify_block, struct mmc_host, pm_notify);
|
||||
unsigned long flags;
|
||||
int err = 0;
|
||||
|
||||
switch (mode) {
|
||||
case PM_HIBERNATION_PREPARE:
|
||||
@ -2715,7 +2700,13 @@ int mmc_pm_notify(struct notifier_block *notify_block,
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
cancel_delayed_work_sync(&host->detect);
|
||||
|
||||
if (!host->bus_ops || host->bus_ops->suspend)
|
||||
if (!host->bus_ops)
|
||||
break;
|
||||
|
||||
/* Validate prerequisites for suspend */
|
||||
if (host->bus_ops->pre_suspend)
|
||||
err = host->bus_ops->pre_suspend(host);
|
||||
if (!err && host->bus_ops->suspend)
|
||||
break;
|
||||
|
||||
/* Calling bus_ops->remove() with a claimed host can deadlock */
|
||||
|
@ -18,6 +18,7 @@
|
||||
struct mmc_bus_ops {
|
||||
void (*remove)(struct mmc_host *);
|
||||
void (*detect)(struct mmc_host *);
|
||||
int (*pre_suspend)(struct mmc_host *);
|
||||
int (*suspend)(struct mmc_host *);
|
||||
int (*resume)(struct mmc_host *);
|
||||
int (*runtime_suspend)(struct mmc_host *);
|
||||
|
@ -910,11 +910,11 @@ out:
|
||||
}
|
||||
|
||||
/*
|
||||
* SDIO suspend. We need to suspend all functions separately.
|
||||
* SDIO pre_suspend. We need to suspend all functions separately.
|
||||
* Therefore all registered functions must have drivers with suspend
|
||||
* and resume methods. Failing that we simply remove the whole card.
|
||||
*/
|
||||
static int mmc_sdio_suspend(struct mmc_host *host)
|
||||
static int mmc_sdio_pre_suspend(struct mmc_host *host)
|
||||
{
|
||||
int i, err = 0;
|
||||
|
||||
@ -925,8 +925,26 @@ static int mmc_sdio_suspend(struct mmc_host *host)
|
||||
if (!pmops || !pmops->suspend || !pmops->resume) {
|
||||
/* force removal of entire card in that case */
|
||||
err = -ENOSYS;
|
||||
} else
|
||||
err = pmops->suspend(&func->dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* SDIO suspend. Suspend all functions separately.
|
||||
*/
|
||||
static int mmc_sdio_suspend(struct mmc_host *host)
|
||||
{
|
||||
int i, err = 0;
|
||||
|
||||
for (i = 0; i < host->card->sdio_funcs; i++) {
|
||||
struct sdio_func *func = host->card->sdio_func[i];
|
||||
if (func && sdio_func_present(func) && func->dev.driver) {
|
||||
const struct dev_pm_ops *pmops = func->dev.driver->pm;
|
||||
err = pmops->suspend(&func->dev);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
@ -1076,6 +1094,7 @@ static int mmc_sdio_runtime_resume(struct mmc_host *host)
|
||||
static const struct mmc_bus_ops mmc_sdio_ops = {
|
||||
.remove = mmc_sdio_remove,
|
||||
.detect = mmc_sdio_detect,
|
||||
.pre_suspend = mmc_sdio_pre_suspend,
|
||||
.suspend = mmc_sdio_suspend,
|
||||
.resume = mmc_sdio_resume,
|
||||
.runtime_suspend = mmc_sdio_runtime_suspend,
|
||||
|
Loading…
Reference in New Issue
Block a user