Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 810caddb authored by Ulf Hansson's avatar Ulf Hansson Committed by Chris Ball
Browse files

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: default avatarUlf Hansson <ulf.hansson@linaro.org>
Tested-by: default avatarJaehoon Chung <jh80.chung@samsung.com>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent 58a8a4a1
Loading
Loading
Loading
Loading
+8 −17
Original line number Diff line number Diff line
@@ -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 */
+1 −0
Original line number Diff line number Diff line
@@ -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 *);
+23 −4
Original line number Diff line number Diff line
@@ -910,11 +910,11 @@ static void mmc_sdio_detect(struct mmc_host *host)
}

/*
 * 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,7 +925,25 @@ 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
				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,