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

Commit 4a561635 authored by Sujit Reddy Thumma's avatar Sujit Reddy Thumma Committed by Stephen Boyd
Browse files

mmc: sdhci: Defer release of CPU DMA PM QoS vote in high load cases



PM QoS vote of default value mean that the CPU is allowed to move
into deepest low power mode whenever possible. Currently, if there
are back-to-back MMC requests, with a short delay, the PM QoS vote
to default value is done immediately which cause the immediate
request to have high latency as the CPU might have idle'd and moved
to deepest low power mode. To avoid this defer the PM QoS vote till
a defined timeout (pm_qos_timeout_us), so that back-to-back requests
may not suffer from additional latencies.

In addition, if the load on MMC is low, the additional latency may be
sustainable. Hence, aggressively release the vote in order to achieve
additional power savings.

CRs-Fixed: 501712
Change-Id: I82166b0ce9416eb0d519f7da26e5a96956093cb2
Signed-off-by: default avatarSujit Reddy Thumma <sthumma@codeaurora.org>
parent b408c40b
Loading
Loading
Loading
Loading
+46 −3
Original line number Diff line number Diff line
@@ -1430,15 +1430,55 @@ static int sdhci_disable(struct mmc_host *mmc)
{
	struct sdhci_host *host = mmc_priv(mmc);

	if (host->cpu_dma_latency_us)
	if (host->cpu_dma_latency_us) {
		/*
		 * In performance mode, release QoS vote after a timeout to
		 * make sure back-to-back requests don't suffer from latencies
		 * that are involved to wake CPU from low power modes in cases
		 * where the CPU goes into low power mode as soon as QoS vote is
		 * released.
		 */
		if (host->power_policy == SDHCI_PERFORMANCE_MODE)
			pm_qos_update_request_timeout(&host->pm_qos_req_dma,
					host->cpu_dma_latency_us,
					host->pm_qos_timeout_us);
		else
			pm_qos_update_request(&host->pm_qos_req_dma,
					PM_QOS_DEFAULT_VALUE);
	}

	if (host->ops->platform_bus_voting)
		host->ops->platform_bus_voting(host, 0);

	return 0;
}

static inline void sdhci_update_power_policy(struct sdhci_host *host,
		enum sdhci_power_policy policy)
{
	host->power_policy = policy;
}

static int sdhci_notify_load(struct mmc_host *mmc, enum mmc_load state)
{
	int err = 0;
	struct sdhci_host *host = mmc_priv(mmc);

	switch (state) {
	case MMC_LOAD_HIGH:
		sdhci_update_power_policy(host, SDHCI_PERFORMANCE_MODE);
		break;
	case MMC_LOAD_LOW:
		sdhci_update_power_policy(host, SDHCI_POWER_SAVE_MODE);
		break;
	default:
		err = -EINVAL;
		break;
	}

	return err;
}

static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
			  bool is_first_req)
{
@@ -2339,6 +2379,7 @@ static const struct mmc_host_ops sdhci_ops = {
	.disable	= sdhci_disable,
	.stop_request = sdhci_stop_request,
	.get_xfer_remain = sdhci_get_xfer_remain,
	.notify_load	= sdhci_notify_load,
};

/*****************************************************************************\
@@ -3547,9 +3588,11 @@ int sdhci_add_host(struct sdhci_host *host)

	mmiowb();

	if (host->cpu_dma_latency_us)
	if (host->cpu_dma_latency_us) {
		host->pm_qos_timeout_us = 10000; /* default value */
		pm_qos_add_request(&host->pm_qos_req_dma,
				PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
	}
	mmc_add_host(mmc);

	pr_info("%s: SDHCI controller on %s [%s] using %s\n",
+7 −0
Original line number Diff line number Diff line
@@ -23,6 +23,11 @@ struct sdhci_next {
	s32 cookie;
};

enum sdhci_power_policy {
	SDHCI_PERFORMANCE_MODE,
	SDHCI_POWER_SAVE_MODE,
};

struct sdhci_host {
	/* Data set by hardware interface driver */
	const char *hw_name;	/* Hardware bus name */
@@ -245,10 +250,12 @@ struct sdhci_host {

	unsigned int cpu_dma_latency_us;
	struct pm_qos_request pm_qos_req_dma;
	unsigned int pm_qos_timeout_us;         /* timeout for PM QoS request */

	struct sdhci_next next_data;
	ktime_t data_start_time;
	struct mutex ios_mutex;
	enum sdhci_power_policy power_policy;

	unsigned long private[0] ____cacheline_aligned;
};