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

Commit fc0f0693 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

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

parents 9c89853b fbc0b6c1
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;