From 28a1fd8e94f860a3bbf135779fa399621e9355ad Mon Sep 17 00:00:00 2001 From: Pierre Gondois Date: Thu, 21 May 2026 14:53:46 +0200 Subject: [PATCH] ACPI: CPPC: Add ospm_nominal_perf support additional changes Complementary modifications to: - "ACPI: CPPC: Add ospm_nominal_perf support" Signed-off-by: Pierre Gondois --- .../ABI/testing/sysfs-devices-system-cpu | 4 +- drivers/acpi/cppc_acpi.c | 13 ++ drivers/cpufreq/cppc_cpufreq.c | 144 +++++++++++++++++- include/acpi/cppc_acpi.h | 5 + 4 files changed, 155 insertions(+), 11 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu index ac1bf1b89ac4d..f3d357917242a 100644 --- a/Documentation/ABI/testing/sysfs-devices-system-cpu +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu @@ -356,9 +356,7 @@ Description: OSPM Nominal Performance (kHz) platform treats performance above this level as boost and below as throttle for power and thermal decisions. - Read returns the last written value in kHz, or 0 if no - value has been written. Write a kHz value in the range - [lowest_freq, nominal_freq]. + Values are in kHz and in the range [lowest_freq, nominal_freq]. This file is only present if the cppc-cpufreq driver is in use. diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 97218c4ac162b..01542184e69b2 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -1717,6 +1717,19 @@ int cppc_set_ospm_nominal_perf(int cpu, u64 ospm_nominal_perf) } EXPORT_SYMBOL_GPL(cppc_set_ospm_nominal_perf); +/** + * cppc_get_ospm_nominal_perf() - Read OSPM Nominal Performance register. + * @cpu: CPU from which to read register. + * @ospm_nominal_perf: Pointer to store the OSPM Nominal Performance value. + * + * Return: 0 on success or negative error code. + */ +int cppc_get_ospm_nominal_perf(int cpu, u64 *ospm_nominal_perf) +{ + return cppc_get_reg_val(cpu, OSPM_NOMINAL_PERF, ospm_nominal_perf); +} +EXPORT_SYMBOL_GPL(cppc_get_ospm_nominal_perf); + /** * cppc_get_auto_act_window() - Read autonomous activity window register. * @cpu: CPU from which to read register. diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index 6379b7ceee347..1a51017a81630 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -28,6 +28,9 @@ static struct cpufreq_driver cppc_cpufreq_driver; +/* Values at driver init. */ +static u64 scratch_ospm_nominal_perf[NR_CPUS]; + #ifdef CONFIG_ACPI_CPPC_CPUFREQ_FIE static enum { FIE_UNSET = -1, @@ -642,7 +645,7 @@ static void cppc_cpufreq_put_cpu_data(struct cpufreq_policy *policy) static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) { - unsigned int cpu = policy->cpu; + unsigned int sib, cpu = policy->cpu; struct cppc_cpudata *cpu_data; struct cppc_perf_caps *caps; int ret; @@ -704,6 +707,34 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) if (caps->highest_perf > caps->nominal_perf) policy->boost_supported = true; + /* + * CPUs are expected to have: + * ospm_nominal_perf = nominal_perf + * at policy init. + */ + cpu_data->ospm_nominal_perf = caps->nominal_perf; + + for_each_cpu(sib, policy->cpus) { + u64 ospm_nominal_perf; + + ret = cppc_get_ospm_nominal_perf(sib, &ospm_nominal_perf); + if (ret == -EOPNOTSUPP) { + continue; + } else if (ret) { + pr_err("CPU%d: Could not read ospm_nominal_perf value\n", + sib); + goto out; + } + + if (ospm_nominal_perf != caps->nominal_perf) { + pr_err("Incoherent ospm_nominal_perf values: " + "scratch_value=%llu expected_value=%u\n", + scratch_ospm_nominal_perf[sib], + caps->nominal_perf); + goto out; + } + } + /* Set policy->cur to max now. The governors will adjust later. */ policy->cur = cppc_perf_to_khz(caps, caps->highest_perf); cpu_data->perf_ctrls.desired_perf = caps->highest_perf; @@ -727,9 +758,17 @@ static void cppc_cpufreq_cpu_exit(struct cpufreq_policy *policy) { struct cppc_cpudata *cpu_data = policy->driver_data; struct cppc_perf_caps *caps = &cpu_data->perf_caps; - unsigned int cpu = policy->cpu; + unsigned int sib, cpu = policy->cpu; int ret; + /* + * CPUs are expected to have: + * ospm_nominal_perf = nominal_perf + * at policy init, so come back to that state. + */ + for_each_cpu(sib, policy->cpus) + cppc_set_ospm_nominal_perf(sib, caps->nominal_perf); + cppc_cpufreq_cpu_fie_exit(policy); cpu_data->perf_ctrls.desired_perf = caps->lowest_perf; @@ -989,9 +1028,20 @@ static ssize_t show_ospm_nominal_freq(struct cpufreq_policy *policy, char *buf) { struct cppc_cpudata *cpu_data = policy->driver_data; unsigned int freq_khz; + u64 perf; + int ret; + + ret = cppc_get_ospm_nominal_perf(policy->cpu, &perf); + if (ret == -EOPNOTSUPP) + return sysfs_emit(buf, "\n"); + if (ret) + return ret; - if (!cpu_data->ospm_nominal_perf) - return sysfs_emit(buf, "0\n"); + if (perf != cpu_data->ospm_nominal_perf) { + pr_warn("ospm_nominal_freq value is not coherent: " + "register=%llu scratch_value=%u\n", + perf, cpu_data->ospm_nominal_perf); + } freq_khz = cppc_perf_to_khz(&cpu_data->perf_caps, cpu_data->ospm_nominal_perf); @@ -1002,7 +1052,7 @@ static ssize_t store_ospm_nominal_freq(struct cpufreq_policy *policy, const char *buf, size_t count) { struct cppc_cpudata *cpu_data = policy->driver_data; - unsigned int sib; + unsigned int sib, failing_cpu; u64 freq_khz; u32 perf; int ret; @@ -1015,12 +1065,23 @@ static ssize_t store_ospm_nominal_freq(struct cpufreq_policy *policy, for_each_cpu(sib, policy->cpus) { ret = cppc_set_ospm_nominal_perf(sib, perf); - if (ret) - return ret; + if (ret) { + failing_cpu = sib; + goto error; + } } cpu_data->ospm_nominal_perf = perf; return count; + +error: + for_each_cpu(sib, policy->cpus) { + if (sib == failing_cpu) + break; + cppc_set_ospm_nominal_perf(sib, cpu_data->ospm_nominal_perf); + } + + return ret; } cpufreq_freq_attr_ro(freqdomain_cpus); @@ -1053,6 +1114,64 @@ static struct cpufreq_driver cppc_cpufreq_driver = { .name = "cppc_cpufreq", }; +static void __exit cppc_cpufreq_ospm_nominal_perf_exit(void) +{ + int cpu; + + for_each_present_cpu(cpu) { + if (scratch_ospm_nominal_perf[cpu] == U64_MAX) + continue; + + /* Reset ospm_nominal_perf to the value present at init. */ + cppc_set_ospm_nominal_perf(cpu, scratch_ospm_nominal_perf[cpu]); + } +} + +static int __init cppc_cpufreq_ospm_nominal_perf_init(void) +{ + int ret, cpu; + + ret = 0; + + for_each_present_cpu(cpu) { + u64 nominal_perf; + + /* + * If one CPU failed, scratch_ospm_nominal_perf still needs + * to be initialized. + */ + if (ret) { + scratch_ospm_nominal_perf[cpu] = U64_MAX; + continue; + } + + ret = cppc_get_ospm_nominal_perf(cpu, &scratch_ospm_nominal_perf[cpu]); + if (ret) { + if (ret == -EOPNOTSUPP) { + /* Valid reason to fail. Continue to iterate. */ + ret = 0; + } + + scratch_ospm_nominal_perf[cpu] = U64_MAX; + continue; + } + + /* Set ospm_nominal_perf to nominal_perf before policy init. */ + ret = cppc_get_nominal_perf(cpu, &nominal_perf); + if (ret) + continue; + + ret = cppc_set_ospm_nominal_perf(cpu, nominal_perf); + if (ret) + continue; + } + + if (ret) + cppc_cpufreq_ospm_nominal_perf_exit(); + + return ret; +} + static int __init cppc_cpufreq_init(void) { int ret; @@ -1063,9 +1182,17 @@ static int __init cppc_cpufreq_init(void) cppc_freq_invariance_init(); populate_efficiency_class(); + ret = cppc_cpufreq_ospm_nominal_perf_init(); + if (ret) { + cppc_freq_invariance_exit(); + return ret; + } + ret = cpufreq_register_driver(&cppc_cpufreq_driver); - if (ret) + if (ret) { + cppc_cpufreq_ospm_nominal_perf_exit(); cppc_freq_invariance_exit(); + } return ret; } @@ -1074,6 +1201,7 @@ static void __exit cppc_cpufreq_exit(void) { cpufreq_unregister_driver(&cppc_cpufreq_driver); cppc_freq_invariance_exit(); + cppc_cpufreq_ospm_nominal_perf_exit(); } module_exit(cppc_cpufreq_exit); diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h index 0b1dcdbea10a2..07e6598fa837a 100644 --- a/include/acpi/cppc_acpi.h +++ b/include/acpi/cppc_acpi.h @@ -183,6 +183,7 @@ extern int cppc_get_epp_perf(int cpunum, u64 *epp_perf); extern int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable); extern int cppc_set_epp(int cpu, u64 epp_val); extern int cppc_set_ospm_nominal_perf(int cpu, u64 ospm_nominal_perf); +extern int cppc_get_ospm_nominal_perf(int cpu, u64 *ospm_nominal_perf); extern int cppc_get_auto_act_window(int cpu, u64 *auto_act_window); extern int cppc_set_auto_act_window(int cpu, u64 auto_act_window); extern int cppc_get_auto_sel(int cpu, bool *enable); @@ -273,6 +274,10 @@ static inline int cppc_set_ospm_nominal_perf(int cpu, u64 ospm_nominal_perf) { return -EOPNOTSUPP; } +static inline int cppc_get_ospm_nominal_perf(int cpu, u64 *ospm_nominal_perf) +{ + return -EOPNOTSUPP; +} static inline int cppc_get_auto_act_window(int cpu, u64 *auto_act_window) { return -EOPNOTSUPP; -- 2.43.0