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

Commit d9fc89ee authored by Ram Prakash Gupta's avatar Ram Prakash Gupta
Browse files

mmc: Add deferred resume support on 4.19



Add deferred resume support on 4.19 kernel.

This change is squash of following deferred resume patches:
----------------------------------------------------------

7eac9a6d : mmc: core: Add deferred bus resume policy
f88fc3ea : mmc: Fix pm_notifier obeying deferred resume
21de67ad : mmc: core: Add deferred resume support to CQ
15c8f04a : mmc: block: Fix issue with deferred resume when CQ is
enabled
3059e03a : mmc: core: add deferred resume support
14093fed : ARM: config: Enable DEFERRED RESUME flag on SDM660
8706e3a  : mmc: card: blk: Add support for deferred SD bus resume
cdf0d57  : mmc: core: Ignore bus resume flags when card removal event
is detected
3498a2f  : mmc: core: Send SD card initialization sequence in deferred
resume path
5ebdb44  : mmc: core: detect change in resume if a new card is found
46a34ac  : mmc: core: rescan for card if deferred resume fails
6794d0e2 : mmc: core: Fix deadlock in suspend & rescan path

This change also includes fix for deadlock issue coming due to
claiming host from two different context, hardware queue context
and task context.

Change-Id: I926bb3783e62892ce842e5d4da44a3c24c8f244d
Signed-off-by: default avatarRitesh Harjani <riteshh@codeaurora.org>
Signed-off-by: default avatarRam Prakash Gupta <rampraka@codeaurora.org>
parent 7ba53b8e
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -61,6 +61,17 @@ config MMC_BLOCK_MINORS

	  If unsure, say 8 here.

config MMC_BLOCK_DEFERRED_RESUME
	bool "Defer MMC layer resume until I/O is requested"
	depends on MMC_BLOCK
	default n
	help
	  Say Y here to enable deferred MMC resume until I/O
	  is requested.

	  This will reduce overall resume latency and
	  save power when there is an SD card inserted but not being used.

config SDIO_UART
	tristate "SDIO UART/GPS class support"
	depends on TTY
+6 −0
Original line number Diff line number Diff line
@@ -2985,6 +2985,9 @@ static int mmc_blk_probe(struct mmc_card *card)

	dev_set_drvdata(&card->dev, md);

#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
	mmc_set_bus_resume_policy(card->host, 1);
#endif
	if (mmc_add_disk(md))
		goto out;

@@ -3033,6 +3036,9 @@ static void mmc_blk_remove(struct mmc_card *card)
	pm_runtime_put_noidle(&card->dev);
	mmc_blk_remove_req(md);
	dev_set_drvdata(&card->dev, NULL);
#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
	mmc_set_bus_resume_policy(card->host, 0);
#endif
	destroy_workqueue(card->complete_wq);
}

+14 −0
Original line number Diff line number Diff line
@@ -166,6 +166,8 @@ static int mmc_bus_suspend(struct device *dev)
	if (ret)
		return ret;

	if (mmc_bus_needs_resume(host))
		return 0;
	ret = host->bus_ops->suspend(host);
	if (ret)
		pm_generic_resume(dev);
@@ -179,11 +181,17 @@ static int mmc_bus_resume(struct device *dev)
	struct mmc_host *host = card->host;
	int ret;

	if (mmc_bus_manual_resume(host)) {
		host->bus_resume_flags |= MMC_BUSRESUME_NEEDS_RESUME;
		goto skip_full_resume;
	}

	ret = host->bus_ops->resume(host);
	if (ret)
		pr_warn("%s: error %d during resume (card was removed?)\n",
			mmc_hostname(host), ret);

skip_full_resume:
	ret = pm_generic_resume(dev);
	return ret;
}
@@ -195,6 +203,9 @@ static int mmc_runtime_suspend(struct device *dev)
	struct mmc_card *card = mmc_dev_to_card(dev);
	struct mmc_host *host = card->host;

	if (mmc_bus_needs_resume(host))
		return 0;

	return host->bus_ops->runtime_suspend(host);
}

@@ -203,6 +214,9 @@ static int mmc_runtime_resume(struct device *dev)
	struct mmc_card *card = mmc_dev_to_card(dev);
	struct mmc_host *host = card->host;

	if (mmc_bus_needs_resume(host))
		host->bus_resume_flags &= ~MMC_BUSRESUME_NEEDS_RESUME;

	return host->bus_ops->runtime_resume(host);
}
#endif /* !CONFIG_PM */
+82 −1
Original line number Diff line number Diff line
@@ -1496,6 +1496,10 @@ EXPORT_SYMBOL(mmc_is_req_done);
 */
void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
{
#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
	if (mmc_bus_needs_resume(host))
		mmc_resume_bus(host);
#endif
	__mmc_start_req(host, mrq);

	if (!mrq->cap_cmd_during_tfr)
@@ -1780,7 +1784,12 @@ void mmc_get_card(struct mmc_card *card, struct mmc_ctx *ctx)
{
	pm_runtime_get_sync(&card->dev);
	__mmc_claim_host(card->host, ctx, NULL);
#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
	if (mmc_bus_needs_resume(card->host))
		mmc_resume_bus(card->host);
#endif
}

EXPORT_SYMBOL(mmc_get_card);

/*
@@ -2640,6 +2649,56 @@ static inline void mmc_bus_put(struct mmc_host *host)
	spin_unlock_irqrestore(&host->lock, flags);
}

int mmc_resume_bus(struct mmc_host *host)
{
	unsigned long flags;
	int err = 0;

	if (!mmc_bus_needs_resume(host))
		return -EINVAL;

	pr_debug("%s: Starting deferred resume\n", mmc_hostname(host));
	spin_lock_irqsave(&host->lock, flags);
	host->bus_resume_flags &= ~MMC_BUSRESUME_NEEDS_RESUME;
	spin_unlock_irqrestore(&host->lock, flags);

	mmc_bus_get(host);
	if (host->bus_ops && !host->bus_dead && host->card) {
		mmc_power_up(host, host->card->ocr);
		BUG_ON(!host->bus_ops->deferred_resume);
		err = host->bus_ops->deferred_resume(host);
		if (err) {
			pr_err("%s: %s: resume failed: %d\n",
				       mmc_hostname(host), __func__, err);
			/*
			 * If we have cd-gpio based detection mechanism and
			 * deferred resume is supported, we will not detect
			 * card removal event when system is suspended. So if
			 * resume fails after a system suspend/resume,
			 * schedule the work to detect card presence.
			 */
			if (mmc_card_is_removable(host) &&
					!(host->caps & MMC_CAP_NEEDS_POLL)) {
				mmc_detect_change(host, 0);
			}
		}
		if (host->card->ext_csd.cmdq_en && !host->cqe_enabled) {
			err = host->cqe_ops->cqe_enable(host, host->card);
			host->cqe_enabled = true;
			if (err)
				pr_err("%s: %s: cqe enable failed: %d\n",
				       mmc_hostname(host), __func__, err);
			else
				mmc_card_clr_suspended(host->card);
		}
	}

	mmc_bus_put(host);
	pr_debug("%s: Deferred resume completed\n", mmc_hostname(host));
	return 0;
}
EXPORT_SYMBOL(mmc_resume_bus);

/*
 * Assign a mmc bus handler to a host. Only one bus handler may control a
 * host at any given time.
@@ -2693,6 +2752,16 @@ static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
		pm_wakeup_event(mmc_dev(host), 5000);

	host->detect_change = 1;
	/*
	 * Change in cd_gpio state, so make sure detection part is
	 * not overided because of manual resume.
	 */
	if (cd_irq && mmc_bus_manual_resume(host))
		host->ignore_bus_resume_flags = true;

	if (delayed_work_pending(&host->detect))
		cancel_delayed_work(&host->detect);

	mmc_schedule_delayed_work(&host->detect, delay);
}

@@ -3512,11 +3581,16 @@ EXPORT_SYMBOL(mmc_flush_detect_work);

void mmc_rescan(struct work_struct *work)
{
	unsigned long flags;
	struct mmc_host *host =
		container_of(work, struct mmc_host, detect.work);

	if (host->rescan_disable)
	spin_lock_irqsave(&host->lock, flags);
	if (host->rescan_disable) {
		spin_unlock_irqrestore(&host->lock, flags);
		return;
	}
	spin_unlock_irqrestore(&host->lock, flags);

	/* If there is a non-removable card registered, only scan once */
	if (!mmc_card_is_removable(host) && host->rescan_entered)
@@ -3540,6 +3614,8 @@ void mmc_rescan(struct work_struct *work)
		host->bus_ops->detect(host);

	host->detect_change = 0;
	if (host->ignore_bus_resume_flags)
		host->ignore_bus_resume_flags = false;

	/*
	 * Let mmc_bus_put() free the bus/bus_ops if we've found that
@@ -3679,6 +3755,11 @@ static int mmc_pm_notify(struct notifier_block *notify_block,

		spin_lock_irqsave(&host->lock, flags);
		host->rescan_disable = 0;
		if (mmc_bus_manual_resume(host) &&
				!host->ignore_bus_resume_flags) {
			spin_unlock_irqrestore(&host->lock, flags);
			break;
		}
		spin_unlock_irqrestore(&host->lock, flags);
		_mmc_detect_change(host, 0, false);

+1 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ struct mmc_bus_ops {
	int (*pre_suspend)(struct mmc_host *);
	int (*suspend)(struct mmc_host *);
	int (*resume)(struct mmc_host *);
	int (*deferred_resume)(struct mmc_host *host);
	int (*runtime_suspend)(struct mmc_host *);
	int (*runtime_resume)(struct mmc_host *);
	int (*alive)(struct mmc_host *);
Loading