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

Commit fbc0b6c1 authored by Venkat Gopalakrishnan's avatar Venkat Gopalakrishnan Committed by Maya Erez
Browse files

mmc: host: sdhci: update pm qos votes based on cpu clusters



Performance of the workload largely depends on the pm qos votes.
Dynamically identify the core in which the current task is running
and apply the pm qos votes to the cluster that this core belongs to.
This ensures that the performance of the workload is not impacted and
also improves the power efficiency of the system.

Change-Id: I4d7fc5250e73b945fa2cfef63e2be18602233f53
Signed-off-by: default avatarVenkat Gopalakrishnan <venkatg@codeaurora.org>
parent 7ec2647c
Loading
Loading
Loading
Loading
+7 −7
Original line number Diff line number Diff line
@@ -58,8 +58,8 @@ Optional Properties:
				"HS200_1p2v" - indicates that host can support HS200 at 1.2v.
				"DDR_1p8v" - indicates that host can support DDR mode at 1.8v.
				"DDR_1p2v" - indicates that host can support DDR mode at 1.2v.
	- qcom,cpu-dma-latency-us: specifies acceptable DMA latency in microseconds.
				Default value is 200 ms. If this property specified as 0,
	- qcom,cpu-dma-latency-us: specifies array of acceptable DMA latencies in microseconds.
				Default value is 200 us. If this property specified as 0,
				then SDHC driver will not vote for PM QOS.
        - qcom,dat1-mpm-int:    specifies MPM interrupt number (e.g. sdhc_2 node below)
				corresponding to DAT1 line of SDHC (used only if slot has dedicated
@@ -110,14 +110,14 @@ In the following, <supply> can be vdd (flash core voltage) or vdd-io (I/O voltag
	  "affine_irq" - PM_QOS_REQ_AFFINE_IRQ request type shall update/apply
	  the vote only to that CPU to which this IRQ's affinity is set to.
	  "affine_cores" - PM_QOS_REQ_AFFINE_CORES request type is used for
	  targets that have little cluster and will update/apply the vote to
	  all the cores in the little cluster.
	  targets that have big/little architecture and will update/apply the vote
	  to all the cores in the respective cluster.
	  The default CPU affinity mode is PM_QOS_REQ_AFFINE_IRQ to maintain
	  backward compatibility.

	- qcom,cpu-affinity-mask: this is a bitmap that specifies little cluster CPU
	  cores used for PM QoS voting. This is parsed only for pm QoS request type of
	  PM_QOS_REQ_AFFINE_CORES ("affine_cores").
	- qcom,cpu-affinity-mask: this is an array of bitmap that specifies
	  big/little cluster CPU cores used for PM QoS voting. This is parsed only
	  for pm QoS request type of PM_QOS_REQ_AFFINE_CORES ("affine_cores").

Example:

+38 −20
Original line number Diff line number Diff line
@@ -323,7 +323,8 @@ struct sdhci_msm_pltfm_data {
	int mpm_sdiowakeup_int;
	int sdiowakeup_irq;
	enum pm_qos_req_type cpu_affinity_type;
	cpumask_t cpu_affinity_mask;
	u32 *cpu_affinity_mask;
	unsigned int cpu_affinity_mask_tbl_sz;
};

struct sdhci_msm_bus_vote {
@@ -1502,28 +1503,47 @@ out:
}

#ifdef CONFIG_SMP
static void sdhci_msm_populate_affinity(struct sdhci_msm_pltfm_data *pdata,
static void sdhci_msm_populate_affinity(struct device *dev,
					struct sdhci_msm_pltfm_data *pdata,
					struct device_node *np)
{
	const char *cpu_affinity = NULL;
	u32 cpu_mask;
	u32 prop_val = 0;

	pdata->cpu_affinity_type = PM_QOS_REQ_AFFINE_IRQ;
	if (!of_property_read_string(np, "qcom,cpu-affinity", &cpu_affinity)) {
		if (!strcmp(cpu_affinity, "all_cores"))
		if (!strcmp(cpu_affinity, "all_cores")) {
			pdata->cpu_affinity_type = PM_QOS_REQ_ALL_CORES;
		else if (!strcmp(cpu_affinity, "affine_cores") &&
			 !of_property_read_u32(np, "qcom,cpu-affinity-mask",
						&cpu_mask)) {
				cpumask_bits(&pdata->cpu_affinity_mask)[0] =
					cpu_mask;
				pdata->cpu_affinity_type =
					PM_QOS_REQ_AFFINE_CORES;
		} else if (!strcmp(cpu_affinity, "affine_cores") &&
			   of_get_property(np, "qcom,cpu-affinity-mask",
					   &prop_val)) {
			pdata->cpu_affinity_mask_tbl_sz =
				prop_val/sizeof(*pdata->cpu_affinity_mask);

			pdata->cpu_affinity_mask = devm_kzalloc(dev,
				sizeof(*pdata->cpu_affinity_mask) *
				pdata->cpu_affinity_mask_tbl_sz,
				GFP_KERNEL);

			if (!pdata->cpu_affinity_mask) {
				dev_err(dev, "cpu_affinity_mask alloc fail\n");
				return;
			}
			if (of_property_read_u32_array(np,
				"qcom,cpu-affinity-mask",
				pdata->cpu_affinity_mask,
				pdata->cpu_affinity_mask_tbl_sz)) {
				dev_err(dev, "cpu-affinity-mask parse fail\n");
				return;
			}
			pdata->cpu_affinity_type = PM_QOS_REQ_AFFINE_CORES;
		}
	}

}
#else
static void sdhci_msm_populate_affinity(struct sdhci_msm_pltfm_data *pdata,
static void sdhci_msm_populate_affinity(struct device *dev,
					struct sdhci_msm_pltfm_data *pdata,
					struct device_node *np)
{
}
@@ -1568,8 +1588,8 @@ static struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev)
		pdata->cpu_dma_latency_tbl_sz =
			prop_val/sizeof(*pdata->cpu_dma_latency_us);

		if (!(pdata->cpu_dma_latency_tbl_sz == 1 ||
			pdata->cpu_dma_latency_tbl_sz == 3)) {
		if (!(pdata->cpu_dma_latency_tbl_sz >= 1 &&
			pdata->cpu_dma_latency_tbl_sz <= 3)) {
			dev_warn(dev, "incorrect Qos param passed from DT: %d\n",
				pdata->cpu_dma_latency_tbl_sz);
			skip_qos_from_dt = true;
@@ -1686,7 +1706,7 @@ static struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev)
	else
		pdata->mpm_sdiowakeup_int = -1;

	sdhci_msm_populate_affinity(pdata, np);
	sdhci_msm_populate_affinity(dev, pdata, np);

	return pdata;
out:
@@ -3399,9 +3419,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
	host->cpu_dma_latency_tbl_sz = msm_host->pdata->cpu_dma_latency_tbl_sz;
	host->pm_qos_req_dma.type = msm_host->pdata->cpu_affinity_type;
	if (host->pm_qos_req_dma.type == PM_QOS_REQ_AFFINE_CORES)
		bitmap_copy(cpumask_bits(&host->pm_qos_req_dma.cpus_affine),
			    cpumask_bits(&msm_host->pdata->cpu_affinity_mask),
			    nr_cpumask_bits);
		host->cpu_affinity_mask = msm_host->pdata->cpu_affinity_mask;

	init_completion(&msm_host->pwr_irq_completion);

+43 −32
Original line number Diff line number Diff line
@@ -1502,6 +1502,39 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
	return power;
}

#ifdef CONFIG_SMP
static void sdhci_set_pmqos_req_type(struct sdhci_host *host, bool enable)
{
	/*
	 * The default request type PM_QOS_REQ_ALL_CORES is
	 * applicable to all CPU cores that are online and
	 * this would have a power impact when there are more
	 * number of CPUs. This new PM_QOS_REQ_AFFINE_IRQ request
	 * type shall update/apply the vote only to that CPU to
	 * which this IRQ's affinity is set to.
	 * PM_QOS_REQ_AFFINE_CORES request type is used for targets that have
	 * big/little architecture and will update/apply the vote to all the
	 * cores in the respective cluster.
	 */
	if (host->pm_qos_req_dma.type == PM_QOS_REQ_AFFINE_IRQ) {
		host->pm_qos_req_dma.irq = host->irq;
	} else if (host->pm_qos_req_dma.type == PM_QOS_REQ_AFFINE_CORES) {
		if (enable) {
			if (current_thread_info()->cpu < 4)
				host->pm_qos_index = SDHCI_LITTLE_CLUSTER;
			else
				host->pm_qos_index = SDHCI_BIG_CLUSTER;
		}
		cpumask_bits(&host->pm_qos_req_dma.cpus_affine)[0] =
			host->cpu_affinity_mask[host->pm_qos_index];
	}
}
#else
static void sdhci_set_pmqos_req_type(struct sdhci_host *host, bool enable)
{
}
#endif

/*****************************************************************************\
 *                                                                           *
 * MMC callbacks                                                             *
@@ -1511,16 +1544,16 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
static int sdhci_enable(struct mmc_host *mmc)
{
	struct sdhci_host *host = mmc_priv(mmc);
	u32 pol_index = 0;

	if (unlikely(!host->cpu_dma_latency_us))
		goto platform_bus_vote;

	if (host->cpu_dma_latency_tbl_sz > 1)
		pol_index = host->power_policy;
	if (host->cpu_dma_latency_tbl_sz > 2)
		host->pm_qos_index = host->power_policy;

	sdhci_set_pmqos_req_type(host, true);
	pm_qos_update_request(&host->pm_qos_req_dma,
		host->cpu_dma_latency_us[pol_index]);
		host->cpu_dma_latency_us[host->pm_qos_index]);

platform_bus_vote:
	if (host->ops->platform_bus_voting)
@@ -1532,13 +1565,14 @@ platform_bus_vote:
static int sdhci_disable(struct mmc_host *mmc)
{
	struct sdhci_host *host = mmc_priv(mmc);
	u32 pol_index = 0;

	if (unlikely(!host->cpu_dma_latency_us))
		goto platform_bus_vote;

	if (host->cpu_dma_latency_tbl_sz > 1)
		pol_index = host->power_policy;
	if (host->cpu_dma_latency_tbl_sz > 2)
		host->pm_qos_index = host->power_policy;

	sdhci_set_pmqos_req_type(host, false);
	/*
	 * In performance mode, release QoS vote after a timeout to
	 * make sure back-to-back requests don't suffer from latencies
@@ -1551,7 +1585,7 @@ static int sdhci_disable(struct mmc_host *mmc)
			PM_QOS_DEFAULT_VALUE);
	else
		pm_qos_update_request_timeout(&host->pm_qos_req_dma,
			host->cpu_dma_latency_us[pol_index],
			host->cpu_dma_latency_us[host->pm_qos_index],
			host->pm_qos_timeout_us);

platform_bus_vote:
@@ -3452,29 +3486,6 @@ static int sdhci_is_adma2_64bit(struct sdhci_host *host)
}
#endif

#ifdef CONFIG_SMP
static void sdhci_set_pmqos_req_type(struct sdhci_host *host)
{
	/*
	 * The default request type PM_QOS_REQ_ALL_CORES is
	 * applicable to all CPU cores that are online and
	 * this would have a power impact when there are more
	 * number of CPUs. This new PM_QOS_REQ_AFFINE_IRQ request
	 * type shall update/apply the vote only to that CPU to
	 * which this IRQ's affinity is set to.
	 * PM_QOS_REQ_AFFINE_CORES request type is used for targets that have
	 * little cluster and will update/apply the vote to all the cores in
	 * the little cluster.
	 */
	if (host->pm_qos_req_dma.type == PM_QOS_REQ_AFFINE_IRQ)
		host->pm_qos_req_dma.irq = host->irq;
}
#else
static void sdhci_set_pmqos_req_type(struct sdhci_host *host)
{
}
#endif

int sdhci_add_host(struct sdhci_host *host)
{
	struct mmc_host *mmc;
@@ -4026,7 +4037,7 @@ int sdhci_add_host(struct sdhci_host *host)

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

+7 −0
Original line number Diff line number Diff line
@@ -30,6 +30,11 @@ enum sdhci_power_policy {
	SDHCI_POWER_SAVE_MODE,
};

enum sdhci_cluster_info {
	SDHCI_LITTLE_CLUSTER,
	SDHCI_BIG_CLUSTER,
};

struct sdhci_host {
	/* Data set by hardware interface driver */
	const char *hw_name;	/* Hardware bus name */
@@ -266,6 +271,8 @@ struct sdhci_host {

	unsigned int *cpu_dma_latency_us;
	unsigned int cpu_dma_latency_tbl_sz;
	enum sdhci_cluster_info pm_qos_index;
	unsigned int *cpu_affinity_mask;
	struct pm_qos_request pm_qos_req_dma;
	unsigned int pm_qos_timeout_us;         /* timeout for PM QoS request */
	struct device_attribute pm_qos_tout;