Loading Documentation/devicetree/bindings/mmc/sdhci-msm.txt +7 −7 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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: Loading drivers/mmc/host/sdhci-msm.c +38 −20 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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) { } Loading Loading @@ -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; Loading Loading @@ -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: Loading Loading @@ -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); Loading drivers/mmc/host/sdhci.c +43 −32 Original line number Diff line number Diff line Loading @@ -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 * Loading @@ -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) Loading @@ -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 Loading @@ -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: Loading Loading @@ -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; Loading Loading @@ -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); Loading include/linux/mmc/sdhci.h +7 −0 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading @@ -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; Loading Loading
Documentation/devicetree/bindings/mmc/sdhci-msm.txt +7 −7 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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: Loading
drivers/mmc/host/sdhci-msm.c +38 −20 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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) { } Loading Loading @@ -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; Loading Loading @@ -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: Loading Loading @@ -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); Loading
drivers/mmc/host/sdhci.c +43 −32 Original line number Diff line number Diff line Loading @@ -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 * Loading @@ -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) Loading @@ -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 Loading @@ -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: Loading Loading @@ -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; Loading Loading @@ -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); Loading
include/linux/mmc/sdhci.h +7 −0 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading @@ -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; Loading