summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-07-04 21:22:50 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2023-07-04 21:22:50 +0300
commitccf46d85318327e5aebaae53f1fe33cc31ed1fd1 (patch)
treef4b1354fb2f9d65020ef20e5d099e1efdb9b582f /drivers
parentb869e9f49964aace737a5a3fadd958ea94e96288 (diff)
parent40c565a429d706951f18fe07ccd9f6fded23a4dc (diff)
downloadlinux-ccf46d85318327e5aebaae53f1fe33cc31ed1fd1.tar.xz
Merge tag 'pm-6.5-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull more power management updates from Rafael Wysocki: "These add support for new hardware (ap807 and AM62A7), fix several issues in cpufreq drivers and in the operating performance points (OPP) framework, fix up intel_idle after recent changes and add documentation. Specifics: - Add missing __init annotation to one function in the intel_idle drvier (Rafael Wysocki) - Make intel_pstate use a correct scaling factor when mapping HWP performance levels to frequency values on hybrid-capable systems with disabled E-cores (Srinivas Pandruvada) - Fix Kconfig dependencies of the cpufreq-dt-platform driver (Viresh Kumar) - Add support to build cpufreq-dt-platdev as a module (Zhipeng Wang) - Don't allocate Sparc's cpufreq_driver dynamically (Viresh Kumar) - Add support for TI's AM62A7 platform (Vibhore Vardhan) - Add support for Armada's ap807 platform (Russell King (Oracle)) - Add support for StarFive JH7110 SoC (Mason Huo) - Fix voltage selection for Mediatek Socs (Daniel Golle) - Fix error handling in Tegra's cpufreq driver (Christophe JAILLET) - Document Qualcomm's IPQ8074 in DT bindings (Robert Marko) - Don't warn for disabling a non-existing frequency for imx6q cpufreq driver (Christoph Niedermaier) - Use dev_err_probe() in Qualcomm's cpufreq driver (Andrew Halaney) - Simplify performance state related logic in the OPP core (Viresh Kumar) - Fix use-after-free and improve locking around lazy_opp_tables (Viresh Kumar, Stephan Gerhold) - Minor cleanups - using dev_err_probe() and rate-limiting debug messages (Andrew Halaney, Adrián Larumbe)" * tag 'pm-6.5-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (23 commits) cpufreq: intel_pstate: Fix scaling for hybrid-capable systems with disabled E-cores cpufreq: Make CONFIG_CPUFREQ_DT_PLATDEV depend on OF intel_idle: Add __init annotation to matchup_vm_state_with_baremetal() OPP: Properly propagate error along when failing to get icc_path OPP: Use dev_err_probe() when failing to get icc_path cpufreq: qcom-cpufreq-hw: Use dev_err_probe() when failing to get icc paths cpufreq: mediatek: correct voltages for MT7622 and MT7623 cpufreq: armada-8k: add ap807 support OPP: Simplify the over-designed pstate <-> level dance OPP: pstate is only valid for genpd OPP tables OPP: don't drop performance constraint on OPP table removal OPP: Protect `lazy_opp_tables` list with `opp_table_lock` OPP: Staticize `lazy_opp_tables` in of.c cpufreq: dt-platdev: Support building as module opp: Fix use-after-free in lazy_opp_tables after probe deferral dt-bindings: cpufreq: qcom-cpufreq-nvmem: document IPQ8074 cpufreq: dt-platdev: Blacklist ti,am62a7 SoC cpufreq: ti-cpufreq: Add support for AM62A7 OPP: rate-limit debug messages when no change in OPP is required cpufreq: imx6q: don't warn for disabling a non-existing frequency ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/cpufreq/Kconfig3
-rw-r--r--drivers/cpufreq/armada-8k-cpufreq.c16
-rw-r--r--drivers/cpufreq/cpufreq-dt-platdev.c5
-rw-r--r--drivers/cpufreq/imx6q-cpufreq.c30
-rw-r--r--drivers/cpufreq/intel_pstate.c58
-rw-r--r--drivers/cpufreq/mediatek-cpufreq.c13
-rw-r--r--drivers/cpufreq/qcom-cpufreq-hw.c2
-rw-r--r--drivers/cpufreq/sparc-us2e-cpufreq.c58
-rw-r--r--drivers/cpufreq/sparc-us3-cpufreq.c58
-rw-r--r--drivers/cpufreq/tegra194-cpufreq.c6
-rw-r--r--drivers/cpufreq/ti-cpufreq.c1
-rw-r--r--drivers/idle/intel_idle.c2
-rw-r--r--drivers/opp/core.c44
-rw-r--r--drivers/opp/debugfs.c1
-rw-r--r--drivers/opp/of.c40
-rw-r--r--drivers/opp/opp.h6
16 files changed, 179 insertions, 164 deletions
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index a1c51abddbc5..f429b9b37b76 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -218,7 +218,8 @@ config CPUFREQ_DT
If in doubt, say N.
config CPUFREQ_DT_PLATDEV
- bool
+ tristate "Generic DT based cpufreq platdev driver"
+ depends on OF
help
This adds a generic DT based cpufreq platdev driver for frequency
management. This creates a 'cpufreq-dt' platform device, on the
diff --git a/drivers/cpufreq/armada-8k-cpufreq.c b/drivers/cpufreq/armada-8k-cpufreq.c
index b0fc5e84f857..8afefdea4d80 100644
--- a/drivers/cpufreq/armada-8k-cpufreq.c
+++ b/drivers/cpufreq/armada-8k-cpufreq.c
@@ -21,6 +21,13 @@
#include <linux/pm_opp.h>
#include <linux/slab.h>
+static const struct of_device_id __maybe_unused armada_8k_cpufreq_of_match[] = {
+ { .compatible = "marvell,ap806-cpu-clock" },
+ { .compatible = "marvell,ap807-cpu-clock" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, armada_8k_cpufreq_of_match);
+
/*
* Setup the opps list with the divider for the max frequency, that
* will be filled at runtime.
@@ -127,7 +134,8 @@ static int __init armada_8k_cpufreq_init(void)
struct device_node *node;
struct cpumask cpus;
- node = of_find_compatible_node(NULL, NULL, "marvell,ap806-cpu-clock");
+ node = of_find_matching_node_and_match(NULL, armada_8k_cpufreq_of_match,
+ NULL);
if (!node || !of_device_is_available(node)) {
of_node_put(node);
return -ENODEV;
@@ -204,12 +212,6 @@ static void __exit armada_8k_cpufreq_exit(void)
}
module_exit(armada_8k_cpufreq_exit);
-static const struct of_device_id __maybe_unused armada_8k_cpufreq_of_match[] = {
- { .compatible = "marvell,ap806-cpu-clock" },
- { },
-};
-MODULE_DEVICE_TABLE(of, armada_8k_cpufreq_of_match);
-
MODULE_AUTHOR("Gregory Clement <gregory.clement@bootlin.com>");
MODULE_DESCRIPTION("Armada 8K cpufreq driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
index 338cf6cc6596..e2b20080de3a 100644
--- a/drivers/cpufreq/cpufreq-dt-platdev.c
+++ b/drivers/cpufreq/cpufreq-dt-platdev.c
@@ -5,6 +5,7 @@
*/
#include <linux/err.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -85,6 +86,8 @@ static const struct of_device_id allowlist[] __initconst = {
{ .compatible = "st-ericsson,u9500", },
{ .compatible = "st-ericsson,u9540", },
+ { .compatible = "starfive,jh7110", },
+
{ .compatible = "ti,omap2", },
{ .compatible = "ti,omap4", },
{ .compatible = "ti,omap5", },
@@ -165,6 +168,7 @@ static const struct of_device_id blocklist[] __initconst = {
{ .compatible = "ti,dra7", },
{ .compatible = "ti,omap3", },
{ .compatible = "ti,am625", },
+ { .compatible = "ti,am62a7", },
{ .compatible = "qcom,ipq8064", },
{ .compatible = "qcom,apq8064", },
@@ -214,3 +218,4 @@ create_pdev:
sizeof(struct cpufreq_dt_platform_data)));
}
core_initcall(cpufreq_dt_platdev_init);
+MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
index 48e1772e98fd..9fb1501033bb 100644
--- a/drivers/cpufreq/imx6q-cpufreq.c
+++ b/drivers/cpufreq/imx6q-cpufreq.c
@@ -209,6 +209,14 @@ static struct cpufreq_driver imx6q_cpufreq_driver = {
.suspend = cpufreq_generic_suspend,
};
+static void imx6x_disable_freq_in_opp(struct device *dev, unsigned long freq)
+{
+ int ret = dev_pm_opp_disable(dev, freq);
+
+ if (ret < 0 && ret != -ENODEV)
+ dev_warn(dev, "failed to disable %ldMHz OPP\n", freq / 1000000);
+}
+
#define OCOTP_CFG3 0x440
#define OCOTP_CFG3_SPEED_SHIFT 16
#define OCOTP_CFG3_SPEED_1P2GHZ 0x3
@@ -254,17 +262,15 @@ static int imx6q_opp_check_speed_grading(struct device *dev)
val &= 0x3;
if (val < OCOTP_CFG3_SPEED_996MHZ)
- if (dev_pm_opp_disable(dev, 996000000))
- dev_warn(dev, "failed to disable 996MHz OPP\n");
+ imx6x_disable_freq_in_opp(dev, 996000000);
if (of_machine_is_compatible("fsl,imx6q") ||
of_machine_is_compatible("fsl,imx6qp")) {
if (val != OCOTP_CFG3_SPEED_852MHZ)
- if (dev_pm_opp_disable(dev, 852000000))
- dev_warn(dev, "failed to disable 852MHz OPP\n");
+ imx6x_disable_freq_in_opp(dev, 852000000);
+
if (val != OCOTP_CFG3_SPEED_1P2GHZ)
- if (dev_pm_opp_disable(dev, 1200000000))
- dev_warn(dev, "failed to disable 1.2GHz OPP\n");
+ imx6x_disable_freq_in_opp(dev, 1200000000);
}
return 0;
@@ -316,20 +322,16 @@ static int imx6ul_opp_check_speed_grading(struct device *dev)
val >>= OCOTP_CFG3_SPEED_SHIFT;
val &= 0x3;
- if (of_machine_is_compatible("fsl,imx6ul")) {
+ if (of_machine_is_compatible("fsl,imx6ul"))
if (val != OCOTP_CFG3_6UL_SPEED_696MHZ)
- if (dev_pm_opp_disable(dev, 696000000))
- dev_warn(dev, "failed to disable 696MHz OPP\n");
- }
+ imx6x_disable_freq_in_opp(dev, 696000000);
if (of_machine_is_compatible("fsl,imx6ull")) {
if (val != OCOTP_CFG3_6ULL_SPEED_792MHZ)
- if (dev_pm_opp_disable(dev, 792000000))
- dev_warn(dev, "failed to disable 792MHz OPP\n");
+ imx6x_disable_freq_in_opp(dev, 792000000);
if (val != OCOTP_CFG3_6ULL_SPEED_900MHZ)
- if (dev_pm_opp_disable(dev, 900000000))
- dev_warn(dev, "failed to disable 900MHz OPP\n");
+ imx6x_disable_freq_in_opp(dev, 900000000);
}
return ret;
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index f29182512b98..8ca2bce4341a 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -302,6 +302,13 @@ static bool hwp_forced __read_mostly;
static struct cpufreq_driver *intel_pstate_driver __read_mostly;
+#define HYBRID_SCALING_FACTOR 78741
+
+static inline int core_get_scaling(void)
+{
+ return 100000;
+}
+
#ifdef CONFIG_ACPI
static bool acpi_ppc;
#endif
@@ -400,6 +407,26 @@ static int intel_pstate_get_cppc_guaranteed(int cpu)
return cppc_perf.nominal_perf;
}
+
+static int intel_pstate_cppc_get_scaling(int cpu)
+{
+ struct cppc_perf_caps cppc_perf;
+ int ret;
+
+ ret = cppc_get_perf_caps(cpu, &cppc_perf);
+
+ /*
+ * If the nominal frequency and the nominal performance are not
+ * zero and the ratio between them is not 100, return the hybrid
+ * scaling factor.
+ */
+ if (!ret && cppc_perf.nominal_perf && cppc_perf.nominal_freq &&
+ cppc_perf.nominal_perf * 100 != cppc_perf.nominal_freq)
+ return HYBRID_SCALING_FACTOR;
+
+ return core_get_scaling();
+}
+
#else /* CONFIG_ACPI_CPPC_LIB */
static inline void intel_pstate_set_itmt_prio(int cpu)
{
@@ -492,6 +519,11 @@ static inline int intel_pstate_get_cppc_guaranteed(int cpu)
{
return -ENOTSUPP;
}
+
+static int intel_pstate_cppc_get_scaling(int cpu)
+{
+ return core_get_scaling();
+}
#endif /* CONFIG_ACPI_CPPC_LIB */
/**
@@ -1897,11 +1929,6 @@ static int core_get_turbo_pstate(int cpu)
return ret;
}
-static inline int core_get_scaling(void)
-{
- return 100000;
-}
-
static u64 core_get_val(struct cpudata *cpudata, int pstate)
{
u64 val;
@@ -1938,16 +1965,28 @@ static void hybrid_get_type(void *data)
*cpu_type = get_this_hybrid_cpu_type();
}
-static int hybrid_get_cpu_scaling(int cpu)
+static int hwp_get_cpu_scaling(int cpu)
{
u8 cpu_type = 0;
smp_call_function_single(cpu, hybrid_get_type, &cpu_type, 1);
/* P-cores have a smaller perf level-to-freqency scaling factor. */
if (cpu_type == 0x40)
- return 78741;
+ return HYBRID_SCALING_FACTOR;
- return core_get_scaling();
+ /* Use default core scaling for E-cores */
+ if (cpu_type == 0x20)
+ return core_get_scaling();
+
+ /*
+ * If reached here, this system is either non-hybrid (like Tiger
+ * Lake) or hybrid-capable (like Alder Lake or Raptor Lake) with
+ * no E cores (in which case CPUID for hybrid support is 0).
+ *
+ * The CPPC nominal_frequency field is 0 for non-hybrid systems,
+ * so the default core scaling will be used for them.
+ */
+ return intel_pstate_cppc_get_scaling(cpu);
}
static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
@@ -3395,8 +3434,7 @@ static int __init intel_pstate_init(void)
if (!default_driver)
default_driver = &intel_pstate;
- if (boot_cpu_has(X86_FEATURE_HYBRID_CPU))
- pstate_funcs.get_cpu_scaling = hybrid_get_cpu_scaling;
+ pstate_funcs.get_cpu_scaling = hwp_get_cpu_scaling;
goto hwp_cpu_matched;
}
diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c
index 9a39a7ccfae9..fef68cb2b38f 100644
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -696,9 +696,16 @@ static const struct mtk_cpufreq_platform_data mt2701_platform_data = {
static const struct mtk_cpufreq_platform_data mt7622_platform_data = {
.min_volt_shift = 100000,
.max_volt_shift = 200000,
- .proc_max_volt = 1360000,
+ .proc_max_volt = 1350000,
.sram_min_volt = 0,
- .sram_max_volt = 1360000,
+ .sram_max_volt = 1350000,
+ .ccifreq_supported = false,
+};
+
+static const struct mtk_cpufreq_platform_data mt7623_platform_data = {
+ .min_volt_shift = 100000,
+ .max_volt_shift = 200000,
+ .proc_max_volt = 1300000,
.ccifreq_supported = false,
};
@@ -734,7 +741,7 @@ static const struct of_device_id mtk_cpufreq_machines[] __initconst = {
{ .compatible = "mediatek,mt2701", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt2712", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt7622", .data = &mt7622_platform_data },
- { .compatible = "mediatek,mt7623", .data = &mt7622_platform_data },
+ { .compatible = "mediatek,mt7623", .data = &mt7623_platform_data },
{ .compatible = "mediatek,mt8167", .data = &mt8516_platform_data },
{ .compatible = "mediatek,mt817x", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt8173", .data = &mt2701_platform_data },
diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c
index a78d7a27b4b5..f2830371d25f 100644
--- a/drivers/cpufreq/qcom-cpufreq-hw.c
+++ b/drivers/cpufreq/qcom-cpufreq-hw.c
@@ -661,7 +661,7 @@ static int qcom_cpufreq_hw_driver_probe(struct platform_device *pdev)
ret = dev_pm_opp_of_find_icc_paths(cpu_dev, NULL);
if (ret)
- return ret;
+ return dev_err_probe(dev, ret, "Failed to find icc paths\n");
for (num_domains = 0; num_domains < MAX_FREQ_DOMAINS; num_domains++)
if (!platform_get_resource(pdev, IORESOURCE_MEM, num_domains))
diff --git a/drivers/cpufreq/sparc-us2e-cpufreq.c b/drivers/cpufreq/sparc-us2e-cpufreq.c
index 92acbb25abb3..d3510cfdb3eb 100644
--- a/drivers/cpufreq/sparc-us2e-cpufreq.c
+++ b/drivers/cpufreq/sparc-us2e-cpufreq.c
@@ -20,8 +20,6 @@
#include <asm/asi.h>
#include <asm/timer.h>
-static struct cpufreq_driver *cpufreq_us2e_driver;
-
struct us2e_freq_percpu_info {
struct cpufreq_frequency_table table[6];
};
@@ -300,12 +298,19 @@ static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy)
static int us2e_freq_cpu_exit(struct cpufreq_policy *policy)
{
- if (cpufreq_us2e_driver)
- us2e_freq_target(policy, 0);
-
+ us2e_freq_target(policy, 0);
return 0;
}
+static struct cpufreq_driver cpufreq_us2e_driver = {
+ .name = "UltraSPARC-IIe",
+ .init = us2e_freq_cpu_init,
+ .verify = cpufreq_generic_frequency_table_verify,
+ .target_index = us2e_freq_target,
+ .get = us2e_freq_get,
+ .exit = us2e_freq_cpu_exit,
+};
+
static int __init us2e_freq_init(void)
{
unsigned long manuf, impl, ver;
@@ -319,39 +324,15 @@ static int __init us2e_freq_init(void)
impl = ((ver >> 32) & 0xffff);
if (manuf == 0x17 && impl == 0x13) {
- struct cpufreq_driver *driver;
-
- ret = -ENOMEM;
- driver = kzalloc(sizeof(*driver), GFP_KERNEL);
- if (!driver)
- goto err_out;
-
- us2e_freq_table = kzalloc((NR_CPUS * sizeof(*us2e_freq_table)),
- GFP_KERNEL);
+ us2e_freq_table = kzalloc(NR_CPUS * sizeof(*us2e_freq_table),
+ GFP_KERNEL);
if (!us2e_freq_table)
- goto err_out;
-
- driver->init = us2e_freq_cpu_init;
- driver->verify = cpufreq_generic_frequency_table_verify;
- driver->target_index = us2e_freq_target;
- driver->get = us2e_freq_get;
- driver->exit = us2e_freq_cpu_exit;
- strcpy(driver->name, "UltraSPARC-IIe");
+ return -ENOMEM;
- cpufreq_us2e_driver = driver;
- ret = cpufreq_register_driver(driver);
+ ret = cpufreq_register_driver(&cpufreq_us2e_driver);
if (ret)
- goto err_out;
+ kfree(us2e_freq_table);
- return 0;
-
-err_out:
- if (driver) {
- kfree(driver);
- cpufreq_us2e_driver = NULL;
- }
- kfree(us2e_freq_table);
- us2e_freq_table = NULL;
return ret;
}
@@ -360,13 +341,8 @@ err_out:
static void __exit us2e_freq_exit(void)
{
- if (cpufreq_us2e_driver) {
- cpufreq_unregister_driver(cpufreq_us2e_driver);
- kfree(cpufreq_us2e_driver);
- cpufreq_us2e_driver = NULL;
- kfree(us2e_freq_table);
- us2e_freq_table = NULL;
- }
+ cpufreq_unregister_driver(&cpufreq_us2e_driver);
+ kfree(us2e_freq_table);
}
MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
diff --git a/drivers/cpufreq/sparc-us3-cpufreq.c b/drivers/cpufreq/sparc-us3-cpufreq.c
index e41b35b16afd..91d1ed558136 100644
--- a/drivers/cpufreq/sparc-us3-cpufreq.c
+++ b/drivers/cpufreq/sparc-us3-cpufreq.c
@@ -19,8 +19,6 @@
#include <asm/head.h>
#include <asm/timer.h>
-static struct cpufreq_driver *cpufreq_us3_driver;
-
struct us3_freq_percpu_info {
struct cpufreq_frequency_table table[4];
};
@@ -144,12 +142,19 @@ static int __init us3_freq_cpu_init(struct cpufreq_policy *policy)
static int us3_freq_cpu_exit(struct cpufreq_policy *policy)
{
- if (cpufreq_us3_driver)
- us3_freq_target(policy, 0);
-
+ us3_freq_target(policy, 0);
return 0;
}
+static struct cpufreq_driver cpufreq_us3_driver = {
+ .name = "UltraSPARC-III",
+ .init = us3_freq_cpu_init,
+ .verify = cpufreq_generic_frequency_table_verify,
+ .target_index = us3_freq_target,
+ .get = us3_freq_get,
+ .exit = us3_freq_cpu_exit,
+};
+
static int __init us3_freq_init(void)
{
unsigned long manuf, impl, ver;
@@ -167,39 +172,15 @@ static int __init us3_freq_init(void)
impl == CHEETAH_PLUS_IMPL ||
impl == JAGUAR_IMPL ||
impl == PANTHER_IMPL)) {
- struct cpufreq_driver *driver;
-
- ret = -ENOMEM;
- driver = kzalloc(sizeof(*driver), GFP_KERNEL);
- if (!driver)
- goto err_out;
-
- us3_freq_table = kzalloc((NR_CPUS * sizeof(*us3_freq_table)),
- GFP_KERNEL);
+ us3_freq_table = kzalloc(NR_CPUS * sizeof(*us3_freq_table),
+ GFP_KERNEL);
if (!us3_freq_table)
- goto err_out;
-
- driver->init = us3_freq_cpu_init;
- driver->verify = cpufreq_generic_frequency_table_verify;
- driver->target_index = us3_freq_target;
- driver->get = us3_freq_get;
- driver->exit = us3_freq_cpu_exit;
- strcpy(driver->name, "UltraSPARC-III");
+ return -ENOMEM;
- cpufreq_us3_driver = driver;
- ret = cpufreq_register_driver(driver);
+ ret = cpufreq_register_driver(&cpufreq_us3_driver);
if (ret)
- goto err_out;
+ kfree(us3_freq_table);
- return 0;
-
-err_out:
- if (driver) {
- kfree(driver);
- cpufreq_us3_driver = NULL;
- }
- kfree(us3_freq_table);
- us3_freq_table = NULL;
return ret;
}
@@ -208,13 +189,8 @@ err_out:
static void __exit us3_freq_exit(void)
{
- if (cpufreq_us3_driver) {
- cpufreq_unregister_driver(cpufreq_us3_driver);
- kfree(cpufreq_us3_driver);
- cpufreq_us3_driver = NULL;
- kfree(us3_freq_table);
- us3_freq_table = NULL;
- }
+ cpufreq_unregister_driver(&cpufreq_us3_driver);
+ kfree(us3_freq_table);
}
MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
diff --git a/drivers/cpufreq/tegra194-cpufreq.c b/drivers/cpufreq/tegra194-cpufreq.c
index c8d03346068a..36dad5ea5947 100644
--- a/drivers/cpufreq/tegra194-cpufreq.c
+++ b/drivers/cpufreq/tegra194-cpufreq.c
@@ -686,8 +686,10 @@ static int tegra194_cpufreq_probe(struct platform_device *pdev)
/* Check for optional OPPv2 and interconnect paths on CPU0 to enable ICC scaling */
cpu_dev = get_cpu_device(0);
- if (!cpu_dev)
- return -EPROBE_DEFER;
+ if (!cpu_dev) {
+ err = -EPROBE_DEFER;
+ goto err_free_res;
+ }
if (dev_pm_opp_of_get_opp_desc_node(cpu_dev)) {
err = dev_pm_opp_of_find_icc_paths(cpu_dev, NULL);
diff --git a/drivers/cpufreq/ti-cpufreq.c b/drivers/cpufreq/ti-cpufreq.c
index be4209d97cb3..d5cd2fd25cad 100644
--- a/drivers/cpufreq/ti-cpufreq.c
+++ b/drivers/cpufreq/ti-cpufreq.c
@@ -337,6 +337,7 @@ static const struct of_device_id ti_cpufreq_of_match[] = {
{ .compatible = "ti,omap34xx", .data = &omap34xx_soc_data, },
{ .compatible = "ti,omap36xx", .data = &omap36xx_soc_data, },
{ .compatible = "ti,am625", .data = &am625_soc_data, },
+ { .compatible = "ti,am62a7", .data = &am625_soc_data, },
/* legacy */
{ .compatible = "ti,omap3430", .data = &omap34xx_soc_data, },
{ .compatible = "ti,omap3630", .data = &omap36xx_soc_data, },
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 34201d7ef33e..b930036edbbe 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -2147,7 +2147,7 @@ static void __init intel_idle_cpuidle_devices_uninit(void)
* All our short idle states are dominated by vmexit/vmenter latencies,
* not the underlying hardware latencies so we keep our values for these.
*/
-static void matchup_vm_state_with_baremetal(void)
+static void __init matchup_vm_state_with_baremetal(void)
{
int cstate;
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index 954c94865cf5..3f46e499d615 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -29,9 +29,6 @@
*/
LIST_HEAD(opp_tables);
-/* OPP tables with uninitialized required OPPs */
-LIST_HEAD(lazy_opp_tables);
-
/* Lock to allow exclusive modification to the device and opp lists */
DEFINE_MUTEX(opp_table_lock);
/* Flag indicating that opp_tables list is being updated at the moment */
@@ -230,17 +227,25 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_level);
unsigned int dev_pm_opp_get_required_pstate(struct dev_pm_opp *opp,
unsigned int index)
{
+ struct opp_table *opp_table = opp->opp_table;
+
if (IS_ERR_OR_NULL(opp) || !opp->available ||
- index >= opp->opp_table->required_opp_count) {
+ index >= opp_table->required_opp_count) {
pr_err("%s: Invalid parameters\n", __func__);
return 0;
}
/* required-opps not fully initialized yet */
- if (lazy_linking_pending(opp->opp_table))
+ if (lazy_linking_pending(opp_table))
return 0;
- return opp->required_opps[index]->pstate;
+ /* The required OPP table must belong to a genpd */
+ if (unlikely(!opp_table->required_opp_tables[index]->is_genpd)) {
+ pr_err("%s: Performance state is only valid for genpds.\n", __func__);
+ return 0;
+ }
+
+ return opp->required_opps[index]->level;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_get_required_pstate);
@@ -938,7 +943,7 @@ static int _set_opp_bw(const struct opp_table *opp_table,
static int _set_performance_state(struct device *dev, struct device *pd_dev,
struct dev_pm_opp *opp, int i)
{
- unsigned int pstate = likely(opp) ? opp->required_opps[i]->pstate : 0;
+ unsigned int pstate = likely(opp) ? opp->required_opps[i]->level: 0;
int ret;
if (!pd_dev)
@@ -1091,7 +1096,7 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table,
/* Return early if nothing to do */
if (!forced && old_opp == opp && opp_table->enabled) {
- dev_dbg(dev, "%s: OPPs are same, nothing to do\n", __func__);
+ dev_dbg_ratelimited(dev, "%s: OPPs are same, nothing to do\n", __func__);
return 0;
}
@@ -1358,7 +1363,10 @@ static struct opp_table *_allocate_opp_table(struct device *dev, int index)
return opp_table;
remove_opp_dev:
+ _of_clear_opp_table(opp_table);
_remove_opp_dev(opp_dev, opp_table);
+ mutex_destroy(&opp_table->genpd_virt_dev_lock);
+ mutex_destroy(&opp_table->lock);
err:
kfree(opp_table);
return ERR_PTR(ret);
@@ -1522,16 +1530,8 @@ static void _opp_table_kref_release(struct kref *kref)
WARN_ON(!list_empty(&opp_table->opp_list));
- list_for_each_entry_safe(opp_dev, temp, &opp_table->dev_list, node) {
- /*
- * The OPP table is getting removed, drop the performance state
- * constraints.
- */
- if (opp_table->genpd_performance_state)
- dev_pm_genpd_set_performance_state((struct device *)(opp_dev->dev), 0);
-
+ list_for_each_entry_safe(opp_dev, temp, &opp_table->dev_list, node)
_remove_opp_dev(opp_dev, opp_table);
- }
mutex_destroy(&opp_table->genpd_virt_dev_lock);
mutex_destroy(&opp_table->lock);
@@ -2704,6 +2704,12 @@ int dev_pm_opp_xlate_performance_state(struct opp_table *src_table,
if (!src_table || !src_table->required_opp_count)
return pstate;
+ /* Both OPP tables must belong to genpds */
+ if (unlikely(!src_table->is_genpd || !dst_table->is_genpd)) {
+ pr_err("%s: Performance state is only valid for genpds.\n", __func__);
+ return -EINVAL;
+ }
+
/* required-opps not fully initialized yet */
if (lazy_linking_pending(src_table))
return -EBUSY;
@@ -2722,8 +2728,8 @@ int dev_pm_opp_xlate_performance_state(struct opp_table *src_table,
mutex_lock(&src_table->lock);
list_for_each_entry(opp, &src_table->opp_list, node) {
- if (opp->pstate == pstate) {
- dest_pstate = opp->required_opps[i]->pstate;
+ if (opp->level == pstate) {
+ dest_pstate = opp->required_opps[i]->level;
goto unlock;
}
}
diff --git a/drivers/opp/debugfs.c b/drivers/opp/debugfs.c
index 2c7fb683441e..17543c0aa5b6 100644
--- a/drivers/opp/debugfs.c
+++ b/drivers/opp/debugfs.c
@@ -152,7 +152,6 @@ void opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
debugfs_create_bool("dynamic", S_IRUGO, d, &opp->dynamic);
debugfs_create_bool("turbo", S_IRUGO, d, &opp->turbo);
debugfs_create_bool("suspend", S_IRUGO, d, &opp->suspend);
- debugfs_create_u32("performance_state", S_IRUGO, d, &opp->pstate);
debugfs_create_u32("level", S_IRUGO, d, &opp->level);
debugfs_create_ulong("clock_latency_ns", S_IRUGO, d,
&opp->clock_latency_ns);
diff --git a/drivers/opp/of.c b/drivers/opp/of.c
index 8246e9b7afe7..ada4963c7cfa 100644
--- a/drivers/opp/of.c
+++ b/drivers/opp/of.c
@@ -21,6 +21,9 @@
#include "opp.h"
+/* OPP tables with uninitialized required OPPs, protected by opp_table_lock */
+static LIST_HEAD(lazy_opp_tables);
+
/*
* Returns opp descriptor node for a device node, caller must
* do of_node_put().
@@ -145,7 +148,10 @@ static void _opp_table_free_required_tables(struct opp_table *opp_table)
opp_table->required_opp_count = 0;
opp_table->required_opp_tables = NULL;
+
+ mutex_lock(&opp_table_lock);
list_del(&opp_table->lazy);
+ mutex_unlock(&opp_table_lock);
}
/*
@@ -194,8 +200,15 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
}
/* Let's do the linking later on */
- if (lazy)
+ if (lazy) {
+ /*
+ * The OPP table is not held while allocating the table, take it
+ * now to avoid corruption to the lazy_opp_tables list.
+ */
+ mutex_lock(&opp_table_lock);
list_add(&opp_table->lazy, &lazy_opp_tables);
+ mutex_unlock(&opp_table_lock);
+ }
else
_update_set_required_opps(opp_table);
@@ -500,11 +513,7 @@ int dev_pm_opp_of_find_icc_paths(struct device *dev,
for (i = 0; i < num_paths; i++) {
paths[i] = of_icc_get_by_index(dev, i);
if (IS_ERR(paths[i])) {
- ret = PTR_ERR(paths[i]);
- if (ret != -EPROBE_DEFER) {
- dev_err(dev, "%s: Unable to get path%d: %d\n",
- __func__, i, ret);
- }
+ ret = dev_err_probe(dev, PTR_ERR(paths[i]), "%s: Unable to get path%d\n", __func__, i);
goto err;
}
}
@@ -932,9 +941,6 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
if (ret)
goto free_required_opps;
- if (opp_table->is_genpd)
- new_opp->pstate = pm_genpd_opp_to_performance_state(dev, new_opp);
-
ret = _opp_add(dev, new_opp, opp_table);
if (ret) {
/* Don't return error for duplicate OPPs */
@@ -1021,14 +1027,6 @@ static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table)
goto remove_static_opp;
}
- list_for_each_entry(opp, &opp_table->opp_list, node) {
- /* Any non-zero performance state would enable the feature */
- if (opp->pstate) {
- opp_table->genpd_performance_state = true;
- break;
- }
- }
-
lazy_link_required_opp_table(opp_table);
return 0;
@@ -1387,9 +1385,15 @@ int of_get_required_opp_performance_state(struct device_node *np, int index)
goto put_required_np;
}
+ /* The OPP tables must belong to a genpd */
+ if (unlikely(!opp_table->is_genpd)) {
+ pr_err("%s: Performance state is only valid for genpds.\n", __func__);
+ goto put_required_np;
+ }
+
opp = _find_opp_of_np(opp_table, required_np);
if (opp) {
- pstate = opp->pstate;
+ pstate = opp->level;
dev_pm_opp_put(opp);
}
diff --git a/drivers/opp/opp.h b/drivers/opp/opp.h
index 2a057c42ddf4..8a5ea38f3a3d 100644
--- a/drivers/opp/opp.h
+++ b/drivers/opp/opp.h
@@ -26,7 +26,7 @@ struct regulator;
/* Lock to allow exclusive modification to the device and opp lists */
extern struct mutex opp_table_lock;
-extern struct list_head opp_tables, lazy_opp_tables;
+extern struct list_head opp_tables;
/* OPP Config flags */
#define OPP_CONFIG_CLK BIT(0)
@@ -78,7 +78,6 @@ struct opp_config_data {
* @turbo: true if turbo (boost) OPP
* @suspend: true if suspend OPP
* @removed: flag indicating that OPP's reference is dropped by OPP core.
- * @pstate: Device's power domain's performance state.
* @rates: Frequencies in hertz
* @level: Performance level
* @supplies: Power supplies voltage/current values
@@ -101,7 +100,6 @@ struct dev_pm_opp {
bool turbo;
bool suspend;
bool removed;
- unsigned int pstate;
unsigned long *rates;
unsigned int level;
@@ -182,7 +180,6 @@ enum opp_table_access {
* @paths: Interconnect path handles
* @path_count: Number of interconnect paths
* @enabled: Set to true if the device's resources are enabled/configured.
- * @genpd_performance_state: Device's power domain support performance state.
* @is_genpd: Marks if the OPP table belongs to a genpd.
* @set_required_opps: Helper responsible to set required OPPs.
* @dentry: debugfs dentry pointer of the real device directory (not links).
@@ -233,7 +230,6 @@ struct opp_table {
struct icc_path **paths;
unsigned int path_count;
bool enabled;
- bool genpd_performance_state;
bool is_genpd;
int (*set_required_opps)(struct device *dev,
struct opp_table *opp_table, struct dev_pm_opp *opp, bool scaling_down);