diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-07-04 20:22:50 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-07-04 20:22:50 +0200 |
commit | ccf46d85318327e5aebaae53f1fe33cc31ed1fd1 (patch) | |
tree | f4b1354fb2f9d65020ef20e5d099e1efdb9b582f | |
parent | Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cl... (diff) | |
parent | Merge branches 'pm-cpufreq' and 'pm-cpuidle' (diff) | |
download | linux-ccf46d85318327e5aebaae53f1fe33cc31ed1fd1.tar.xz linux-ccf46d85318327e5aebaae53f1fe33cc31ed1fd1.zip |
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
...
-rw-r--r-- | Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-nvmem.yaml | 1 | ||||
-rw-r--r-- | drivers/cpufreq/Kconfig | 3 | ||||
-rw-r--r-- | drivers/cpufreq/armada-8k-cpufreq.c | 16 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq-dt-platdev.c | 5 | ||||
-rw-r--r-- | drivers/cpufreq/imx6q-cpufreq.c | 30 | ||||
-rw-r--r-- | drivers/cpufreq/intel_pstate.c | 58 | ||||
-rw-r--r-- | drivers/cpufreq/mediatek-cpufreq.c | 13 | ||||
-rw-r--r-- | drivers/cpufreq/qcom-cpufreq-hw.c | 2 | ||||
-rw-r--r-- | drivers/cpufreq/sparc-us2e-cpufreq.c | 58 | ||||
-rw-r--r-- | drivers/cpufreq/sparc-us3-cpufreq.c | 58 | ||||
-rw-r--r-- | drivers/cpufreq/tegra194-cpufreq.c | 6 | ||||
-rw-r--r-- | drivers/cpufreq/ti-cpufreq.c | 1 | ||||
-rw-r--r-- | drivers/idle/intel_idle.c | 2 | ||||
-rw-r--r-- | drivers/opp/core.c | 44 | ||||
-rw-r--r-- | drivers/opp/debugfs.c | 1 | ||||
-rw-r--r-- | drivers/opp/of.c | 40 | ||||
-rw-r--r-- | drivers/opp/opp.h | 6 |
17 files changed, 180 insertions, 164 deletions
diff --git a/Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-nvmem.yaml b/Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-nvmem.yaml index 6f5e7904181f..7e1bb992ce90 100644 --- a/Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-nvmem.yaml +++ b/Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-nvmem.yaml @@ -28,6 +28,7 @@ select: - qcom,apq8064 - qcom,apq8096 - qcom,ipq8064 + - qcom,ipq8074 - qcom,msm8939 - qcom,msm8960 - qcom,msm8974 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); |