* [PATCH v7 0/3] ACPI / cpufreq: CPPC: Add ospm_nominal_perf support
@ 2026-08-07 21:48 Sumit Gupta
2026-08-07 21:48 ` [PATCH v7 1/3] ACPI: " Sumit Gupta
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Sumit Gupta @ 2026-08-07 21:48 UTC (permalink / raw)
To: rafael, viresh.kumar, pierre.gondois, christian.loehle,
ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre,
mario.limonciello, linux-kernel, linux-pm, linux-acpi,
acpica-devel, linux-tegra
Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu,
sumitg
This series adds support for the OSPM Nominal Performance register
(ACPI 6.6, Section 8.4.6.1.2.6) to the CPPC ACPI and cpufreq drivers.
Unlike the read-only Nominal Performance register, OSPM Nominal
Performance is writable and lets OSPM request a nominal level below
the platform-reported nominal. The platform treats performance above
this level as boost and below as throttle for its power and thermal
decisions.
- Patch 1: adds cppc_set_ospm_nominal_perf() and
cppc_ospm_nominal_perf_supported().
- Patch 2: adds the per-policy ospm_nominal_freq attribute in kHz, and
tracks the register in the OSPM-set save/restore table. The register
cannot be read back, so the attribute is write-only.
- Patch 3: reflects the OSPM nominal in the cpufreq policy, so that
boost and the frequency limits stay consistent with the register.
This series applies on top of the following series, which provides the
save/restore table that patch 2 hooks into:
cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload
https://lore.kernel.org/lkml/20260806200857.601152-1-sumitg@nvidia.com/
v6[6] -> v7:
- Split patch 1 into an ACPI patch and a cpufreq patch.
- Patch 1:
- drop cppc_get_ospm_nominal_perf(), as the register is write-only.
- add cppc_ospm_nominal_perf_supported(), sharing the setter's
writable check via the new cpc_reg_writable() helper.
- Patch 2:
- make ospm_nominal_freq write-only, and track the requested value
in software instead of reading the register back.
- place the register before auto_sel in the save/restore table.
- Patch 3:
- rename *_reflect_nominal() to *_update_nominal_limits().
- do not fail the sysfs write when cppc_cpufreq_update_nominal_limits()
fails to update the QoS limit.
- skip the limit update while boost is enabled.
- make cppc_cpufreq_effective_nominal() take the value from the
software-tracked state, so it returns it directly and cannot fail.
- init() checks cppc_ospm_nominal_perf_supported() directly, instead
of using cppc_cpufreq_effective_nominal().
Sumit Gupta (3):
ACPI: CPPC: Add ospm_nominal_perf support
cpufreq: CPPC: Add ospm_nominal_freq attribute
cpufreq: CPPC: Reflect the OSPM nominal in boost and limits
.../ABI/testing/sysfs-devices-system-cpu | 24 ++++
drivers/acpi/cppc_acpi.c | 48 ++++++-
drivers/cpufreq/cppc_cpufreq.c | 135 +++++++++++++++++-
include/acpi/cppc_acpi.h | 10 ++
4 files changed, 208 insertions(+), 9 deletions(-)
v6: https://lore.kernel.org/lkml/20260717215330.2215058-1-sumitg@nvidia.com/
v5: https://lore.kernel.org/lkml/20260615185934.2383514-1-sumitg@nvidia.com/
v4: https://lore.kernel.org/lkml/20260527194626.185286-1-sumitg@nvidia.com/
v3: https://lore.kernel.org/lkml/20260514194822.1841748-1-sumitg@nvidia.com/
v2: https://lore.kernel.org/lkml/20260430142430.755437-1-sumitg@nvidia.com/
v1: https://lore.kernel.org/lkml/20260427051823.280419-1-sumitg@nvidia.com/
--
2.34.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v7 1/3] ACPI: CPPC: Add ospm_nominal_perf support
2026-08-07 21:48 [PATCH v7 0/3] ACPI / cpufreq: CPPC: Add ospm_nominal_perf support Sumit Gupta
@ 2026-08-07 21:48 ` Sumit Gupta
2026-08-07 21:48 ` [PATCH v7 2/3] cpufreq: CPPC: Add ospm_nominal_freq attribute Sumit Gupta
2026-08-07 21:48 ` [PATCH v7 3/3] cpufreq: CPPC: Reflect the OSPM nominal in boost and limits Sumit Gupta
2 siblings, 0 replies; 4+ messages in thread
From: Sumit Gupta @ 2026-08-07 21:48 UTC (permalink / raw)
To: rafael, viresh.kumar, pierre.gondois, christian.loehle,
ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre,
mario.limonciello, linux-kernel, linux-pm, linux-acpi,
acpica-devel, linux-tegra
Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu,
sumitg
Expose the OSPM Nominal Performance register (ACPI 6.6, Section
8.4.6.1.2.6), which conveys the nominal performance level at which the
platform may run. Unlike the read-only Nominal Performance register, it
is writable, so OSPM can ask for a nominal level below the
platform-reported one, which then becomes the boundary between boosted
and throttled operation for the platform's power and thermal decisions.
Add cppc_set_ospm_nominal_perf() to write the register. Per the spec,
the value must lie in [Lowest Performance, Nominal Performance], which
the caller is responsible for validating.
Add cppc_ospm_nominal_perf_supported() to report whether the platform
implements the register as writable, since a write-only register cannot
be probed by reading it. Factor the writable-register check out of
cppc_set_reg_val() into cpc_reg_writable() and use it for both, so
support is never reported for a register that a write would reject.
Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
---
drivers/acpi/cppc_acpi.c | 48 ++++++++++++++++++++++++++++++++++++++--
include/acpi/cppc_acpi.h | 10 +++++++++
2 files changed, 56 insertions(+), 2 deletions(-)
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 9e882b3911e6..b6bf46cb06cb 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1388,6 +1388,13 @@ static int cppc_set_reg_val_in_pcc(int cpu, struct cpc_register_resource *reg, u
return ret;
}
+/* If a register is writeable, it must be a buffer and not null */
+static bool cpc_reg_writable(const struct cpc_register_resource *reg)
+{
+ return reg->type == ACPI_TYPE_BUFFER &&
+ !IS_NULL_REG(®->cpc_entry.reg);
+}
+
static int cppc_set_reg_val(int cpu, enum cppc_regs reg_idx, u64 val)
{
struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
@@ -1400,8 +1407,7 @@ static int cppc_set_reg_val(int cpu, enum cppc_regs reg_idx, u64 val)
reg = &cpc_desc->cpc_regs[reg_idx];
- /* if a register is writeable, it must be a buffer and not null */
- if ((reg->type != ACPI_TYPE_BUFFER) || IS_NULL_REG(®->cpc_entry.reg)) {
+ if (!cpc_reg_writable(reg)) {
pr_debug("CPC register is not supported\n");
return -EOPNOTSUPP;
}
@@ -1832,6 +1838,44 @@ int cppc_set_epp(int cpu, u64 epp_val)
}
EXPORT_SYMBOL_GPL(cppc_set_epp);
+/**
+ * cppc_set_ospm_nominal_perf() - Write OSPM Nominal Performance register.
+ * @cpu: CPU on which to write register.
+ * @ospm_nominal_perf: Value to write to the OSPM Nominal Performance register.
+ *
+ * OSPM Nominal Performance conveys the desired nominal performance level
+ * at which the platform may run. Per ACPI 6.6, s8.4.6.1.2.6, the value
+ * must lie within [Lowest Performance, Nominal Performance] and may be
+ * set independently of Minimum, Maximum and Desired performance. The
+ * caller is responsible for validating the range.
+ *
+ * Return: 0 on success or negative error code.
+ */
+int cppc_set_ospm_nominal_perf(int cpu, u64 ospm_nominal_perf)
+{
+ return cppc_set_reg_val(cpu, OSPM_NOMINAL_PERF, ospm_nominal_perf);
+}
+EXPORT_SYMBOL_GPL(cppc_set_ospm_nominal_perf);
+
+/**
+ * cppc_ospm_nominal_perf_supported() - Check OSPM Nominal Performance support.
+ * @cpu: CPU to query.
+ *
+ * The OSPM Nominal Performance register is write-only, so its value
+ * cannot be read back. This only reports whether the platform implements
+ * it as a writable register.
+ *
+ * Return: true if the register is supported, false otherwise.
+ */
+bool cppc_ospm_nominal_perf_supported(int cpu)
+{
+ struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
+
+ return cpc_desc &&
+ cpc_reg_writable(&cpc_desc->cpc_regs[OSPM_NOMINAL_PERF]);
+}
+EXPORT_SYMBOL_GPL(cppc_ospm_nominal_perf_supported);
+
/**
* cppc_get_auto_act_window() - Read autonomous activity window register.
* @cpu: CPU from which to read register.
diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
index 3394e1b208be..a078ad5964c2 100644
--- a/include/acpi/cppc_acpi.h
+++ b/include/acpi/cppc_acpi.h
@@ -185,6 +185,8 @@ extern int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val);
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 bool cppc_ospm_nominal_perf_supported(int cpu);
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, u64 *enable);
@@ -277,6 +279,14 @@ static inline int cppc_set_epp(int cpu, u64 epp_val)
{
return -EOPNOTSUPP;
}
+static inline int cppc_set_ospm_nominal_perf(int cpu, u64 ospm_nominal_perf)
+{
+ return -EOPNOTSUPP;
+}
+static inline bool cppc_ospm_nominal_perf_supported(int cpu)
+{
+ return false;
+}
static inline int cppc_get_auto_act_window(int cpu, u64 *auto_act_window)
{
return -EOPNOTSUPP;
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v7 2/3] cpufreq: CPPC: Add ospm_nominal_freq attribute
2026-08-07 21:48 [PATCH v7 0/3] ACPI / cpufreq: CPPC: Add ospm_nominal_perf support Sumit Gupta
2026-08-07 21:48 ` [PATCH v7 1/3] ACPI: " Sumit Gupta
@ 2026-08-07 21:48 ` Sumit Gupta
2026-08-07 21:48 ` [PATCH v7 3/3] cpufreq: CPPC: Reflect the OSPM nominal in boost and limits Sumit Gupta
2 siblings, 0 replies; 4+ messages in thread
From: Sumit Gupta @ 2026-08-07 21:48 UTC (permalink / raw)
To: rafael, viresh.kumar, pierre.gondois, christian.loehle,
ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre,
mario.limonciello, linux-kernel, linux-pm, linux-acpi,
acpica-devel, linux-tegra
Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu,
sumitg
OSPM Nominal Performance (ACPI 6.6, Section 8.4.6.1.2.6) lets the OS
request a nominal performance level below the platform-reported one. The
platform treats performance above that level as boosted and below it as
throttled for its power and thermal decisions. A lower value moves that
boundary down, so sustained work runs at a lower point while the range
above it remains available as boost.
Expose it as a per-policy cpufreq attribute in kHz, matching the unit
convention of the other frequency attributes:
/sys/devices/system/cpu/cpuX/cpufreq/ospm_nominal_freq
The attribute is write-only as the register cannot be read back. Writes
are converted with cppc_khz_to_perf() and rejected unless they fall in
[Lowest Performance, Nominal Performance].
Also track the register in the OSPM-set save/restore table, so a
requested value survives CPU hotplug and suspend/resume. The store
handler records the request rather than init() capturing a firmware
value, and driver unload reverts the register to the platform-reported
Nominal Performance.
Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
---
.../ABI/testing/sysfs-devices-system-cpu | 24 +++++++
drivers/cpufreq/cppc_cpufreq.c | 70 +++++++++++++++++--
2 files changed, 90 insertions(+), 4 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu
index 82d10d556cc8..59aafcb2af97 100644
--- a/Documentation/ABI/testing/sysfs-devices-system-cpu
+++ b/Documentation/ABI/testing/sysfs-devices-system-cpu
@@ -346,6 +346,30 @@ Description: Performance Limited
This file is only present if the cppc-cpufreq driver is in use.
+What: /sys/devices/system/cpu/cpuX/cpufreq/ospm_nominal_freq
+Date: August 2026
+Contact: linux-pm@vger.kernel.org
+Description: OSPM Nominal Performance (kHz), write-only
+
+ OSPM uses this attribute to request a nominal performance level
+ lower than the platform-reported nominal. The platform treats
+ performance above this level as boost and below as throttle for
+ power and thermal decisions.
+
+ Write a value in kHz, between the frequencies corresponding to
+ Lowest Performance and Nominal Performance. The register cannot
+ be read back, so this attribute has no read side.
+
+ Note that tasks may be migrated from one CPU to another by the
+ scheduler's load-balancing algorithm, and if different OSPM
+ Nominal Performance values are set for those CPUs (through
+ different cpufreq policies), that may lead to undesirable
+ outcomes. To avoid such issues it is better to set the same
+ value across all policies, or to pin every task potentially
+ sensitive to it to a specific CPU.
+
+ This file is only present if the cppc-cpufreq driver is in use.
+
What: /sys/devices/system/cpu/cpu*/cache/index3/cache_disable_{0,1}
Date: August 2008
KernelVersion: 2.6.27
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 32f38b0c492b..fe714e71826a 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -33,11 +33,13 @@ static struct cpufreq_driver cppc_cpufreq_driver;
* reapplied from online() across CPU hotplug, and the firmware value is
* restored from offline().
*
- * Autonomous Selection (auto_sel) is kept first, as writes to the registers
- * listed after it only have meaning while autonomous selection is enabled.
+ * Autonomous Selection (auto_sel) splits the list: the registers before it are
+ * independent of it, and those after it have meaning only while autonomous
+ * selection is enabled. Place a new register on the matching side.
*/
enum cppc_saved_reg_id {
- CPPC_SAVED_AUTO_SEL,
+ CPPC_SAVED_OSPM_NOMINAL_PERF,
+ CPPC_SAVED_AUTO_SEL, /* Entries below need auto_sel enabled. */
CPPC_SAVED_EPP,
CPPC_SAVED_AUTO_ACT_WINDOW,
CPPC_NR_SAVED_REGS,
@@ -50,6 +52,11 @@ struct cppc_saved_reg {
};
static const struct cppc_saved_reg cppc_saved_regs[CPPC_NR_SAVED_REGS] = {
+ /* Write-only: the requested value is tracked in software. */
+ [CPPC_SAVED_OSPM_NOMINAL_PERF] = {
+ .name = "ospm_nominal_perf",
+ .set = cppc_set_ospm_nominal_perf,
+ },
[CPPC_SAVED_AUTO_SEL] = {
.name = "auto_sel",
.get = cppc_get_auto_sel,
@@ -79,6 +86,9 @@ enum cppc_saved_type {
* could not be read
* requested_val - value in effect when the policy last went offline,
* reapplied at online(). U64_MAX if none
+ *
+ * A write-only register cannot be read back, so its store handler sets
+ * firmware_val and requested_val instead of init() and offline().
*/
struct cppc_saved_vals {
u64 firmware_val;
@@ -135,7 +145,17 @@ static void cppc_cpufreq_save_regs(struct cpufreq_policy *policy,
st->suspend_regs_handled = false;
for (i = 0; i < CPPC_NR_SAVED_REGS; i++) {
- if (cppc_saved_regs[i].get(cpu, &val))
+ const struct cppc_saved_reg *reg = &cppc_saved_regs[i];
+
+ /*
+ * A write-only register cannot be read back. It has no
+ * firmware value to capture, and its requested value comes
+ * from the store handler, so do not overwrite it here.
+ */
+ if (!reg->get && saved_type == CPPC_SAVED_REQUESTED)
+ continue;
+
+ if (!reg->get || reg->get(cpu, &val))
val = U64_MAX;
if (saved_type == CPPC_SAVED_FIRMWARE) {
@@ -197,6 +217,12 @@ static void cppc_cpufreq_apply_saved_regs(struct cpufreq_policy *policy,
u64 auto_sel, val;
int i;
+ /* Registers before auto_sel do not depend on it. */
+ for (i = 0; i < CPPC_SAVED_AUTO_SEL; i++) {
+ val = cppc_cpufreq_saved_reg_value(st, i, saved_type);
+ cppc_cpufreq_write_saved_reg(cpu, i, val, saved_type);
+ }
+
auto_sel = cppc_cpufreq_saved_reg_value(st, CPPC_SAVED_AUTO_SEL,
saved_type);
@@ -1385,11 +1411,46 @@ static int cppc_get_perf_limited_filtered(int cpu, u64 *perf_limited)
CPPC_CPUFREQ_ATTR_RW_U64(perf_limited, cppc_get_perf_limited_filtered,
cppc_set_perf_limited)
+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;
+ struct cppc_saved_vals *st;
+ unsigned int freq_khz;
+ u32 perf;
+ int ret;
+
+ ret = kstrtouint(buf, 0, &freq_khz);
+ if (ret)
+ return ret;
+
+ perf = cppc_khz_to_perf(&cpu_data->perf_caps, freq_khz);
+ if (perf < cpu_data->perf_caps.lowest_perf ||
+ perf > cpu_data->perf_caps.nominal_perf)
+ return -EINVAL;
+
+ ret = cppc_set_ospm_nominal_perf(policy->cpu, perf);
+ if (ret)
+ return ret;
+
+ /*
+ * Track the request in software: requested_val is reapplied across
+ * hotplug, and firmware_val makes the register revert to the platform
+ * Nominal on driver unload, since the value cannot be read back.
+ */
+ st = &cppc_cpufreq_policy_state(policy)->regs[CPPC_SAVED_OSPM_NOMINAL_PERF];
+ st->requested_val = perf;
+ st->firmware_val = cpu_data->perf_caps.nominal_perf;
+
+ return count;
+}
+
cpufreq_freq_attr_ro(freqdomain_cpus);
cpufreq_freq_attr_rw(auto_select);
cpufreq_freq_attr_rw(auto_act_window);
cpufreq_freq_attr_rw(energy_performance_preference_val);
cpufreq_freq_attr_rw(perf_limited);
+cpufreq_freq_attr_wo(ospm_nominal_freq);
static struct freq_attr *cppc_cpufreq_attr[] = {
&freqdomain_cpus,
@@ -1397,6 +1458,7 @@ static struct freq_attr *cppc_cpufreq_attr[] = {
&auto_act_window,
&energy_performance_preference_val,
&perf_limited,
+ &ospm_nominal_freq,
NULL,
};
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v7 3/3] cpufreq: CPPC: Reflect the OSPM nominal in boost and limits
2026-08-07 21:48 [PATCH v7 0/3] ACPI / cpufreq: CPPC: Add ospm_nominal_perf support Sumit Gupta
2026-08-07 21:48 ` [PATCH v7 1/3] ACPI: " Sumit Gupta
2026-08-07 21:48 ` [PATCH v7 2/3] cpufreq: CPPC: Add ospm_nominal_freq attribute Sumit Gupta
@ 2026-08-07 21:48 ` Sumit Gupta
2 siblings, 0 replies; 4+ messages in thread
From: Sumit Gupta @ 2026-08-07 21:48 UTC (permalink / raw)
To: rafael, viresh.kumar, pierre.gondois, christian.loehle,
ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre,
mario.limonciello, linux-kernel, linux-pm, linux-acpi,
acpica-devel, linux-tegra
Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu,
sumitg
Boost is the performance range above nominal, so lowering the OSPM
Nominal Performance enlarges the boost range and drops the non-boost
ceiling. Keep the policy limits consistent with the register.
Add cppc_cpufreq_effective_nominal(), which returns the OSPM Nominal
Performance when set and the platform nominal otherwise. Use it for the
non-boost ceiling in set_boost(), and to update the policy limits when
ospm_nominal_freq is written.
The cpufreq core caps scaling_max_freq with a per-policy QoS request,
boost_freq_req, that it sets to cpuinfo.max_freq and refreshes only when
boost is toggled. A write to ospm_nominal_freq changes cpuinfo.max_freq
without toggling boost, so cppc_cpufreq_update_nominal_limits() updates
the request itself, rather than leaving scaling_max_freq at the old
nominal.
When boost is enabled the ceiling is highest_perf, not the nominal, so
the update is skipped. set_boost() applies the new nominal when boost is
turned off.
A platform with highest_perf == nominal_perf has no boost range at boot.
Lowering the OSPM nominal from sysfs can create one. The core, however,
adds its boost FREQ_QOS_MAX request only at policy setup, and only if
boost_supported is already set. Set boost_supported in init() when the
OSPM register is supported and highest_perf > lowest_perf. Boost can
then be enabled after the nominal is lowered.
Suggested-by: Pierre Gondois <pierre.gondois@arm.com>
Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
---
drivers/cpufreq/cppc_cpufreq.c | 65 ++++++++++++++++++++++++++++++++--
1 file changed, 62 insertions(+), 3 deletions(-)
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index fe714e71826a..bcac46ad25c3 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -892,6 +892,27 @@ static void cppc_cpufreq_put_cpu_data(struct cpufreq_policy *policy)
policy->driver_data = NULL;
}
+/*
+ * Return the non-boost performance ceiling: the OSPM Nominal Performance the
+ * driver last requested, or the platform-reported Nominal Performance if none
+ * was requested.
+ *
+ * The register is write-only, so the requested value comes from the
+ * software-tracked state rather than from hardware.
+ */
+static u32 cppc_cpufreq_effective_nominal(struct cpufreq_policy *policy)
+{
+ const struct cppc_saved_vals *st = cppc_cpufreq_policy_state(policy)->regs;
+ struct cppc_cpudata *cpu_data = policy->driver_data;
+ u64 ospm_nominal = st[CPPC_SAVED_OSPM_NOMINAL_PERF].requested_val;
+
+ /* U64_MAX means OSPM has not selected a nominal level. */
+ if (ospm_nominal == U64_MAX)
+ return cpu_data->perf_caps.nominal_perf;
+
+ return (u32)ospm_nominal;
+}
+
static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
unsigned int cpu = policy->cpu;
@@ -950,9 +971,14 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
/*
* If 'highest_perf' is greater than 'nominal_perf', we assume CPU Boost
- * is supported.
+ * is supported. A writable OSPM Nominal Performance register can also
+ * open a boost range at runtime by lowering the nominal, so assume
+ * boost is supported in that case too, letting the core register its
+ * QoS request up front.
*/
- if (caps->highest_perf > caps->nominal_perf)
+ if (caps->highest_perf > caps->nominal_perf ||
+ (caps->highest_perf > caps->lowest_perf &&
+ cppc_ospm_nominal_perf_supported(cpu)))
policy->boost_supported = true;
/* Set policy->cur to max now. The governors will adjust later. */
@@ -1233,11 +1259,12 @@ static int cppc_cpufreq_set_boost(struct cpufreq_policy *policy, int state)
{
struct cppc_cpudata *cpu_data = policy->driver_data;
struct cppc_perf_caps *caps = &cpu_data->perf_caps;
+ u32 nominal = cppc_cpufreq_effective_nominal(policy);
if (state)
policy->cpuinfo.max_freq = cppc_perf_to_khz(caps, caps->highest_perf);
else
- policy->cpuinfo.max_freq = cppc_perf_to_khz(caps, caps->nominal_perf);
+ policy->cpuinfo.max_freq = cppc_perf_to_khz(caps, nominal);
return 0;
}
@@ -1411,6 +1438,36 @@ static int cppc_get_perf_limited_filtered(int cpu, u64 *perf_limited)
CPPC_CPUFREQ_ATTR_RW_U64(perf_limited, cppc_get_perf_limited_filtered,
cppc_set_perf_limited)
+/*
+ * While boost is disabled, the nominal is the ceiling. Set cpuinfo.max_freq to
+ * it and update the core's boost_freq_req to match. The core only syncs
+ * boost_freq_req when boost is enabled or disabled, so a plain nominal change
+ * must update it here.
+ */
+static void cppc_cpufreq_update_nominal_limits(struct cpufreq_policy *policy)
+{
+ struct cppc_cpudata *cpu_data = policy->driver_data;
+ u32 nominal;
+ int ret;
+
+ if (policy->boost_enabled)
+ return;
+
+ nominal = cppc_cpufreq_effective_nominal(policy);
+ policy->cpuinfo.max_freq = cppc_perf_to_khz(&cpu_data->perf_caps,
+ nominal);
+
+ if (freq_qos_request_active(&policy->boost_freq_req)) {
+ ret = freq_qos_update_request(&policy->boost_freq_req,
+ policy->cpuinfo.max_freq);
+ if (ret < 0)
+ pr_debug("Failed to update boost limit on CPU%u (%d)\n",
+ policy->cpu, ret);
+ }
+
+ refresh_frequency_limits(policy);
+}
+
static ssize_t store_ospm_nominal_freq(struct cpufreq_policy *policy,
const char *buf, size_t count)
{
@@ -1442,6 +1499,8 @@ static ssize_t store_ospm_nominal_freq(struct cpufreq_policy *policy,
st->requested_val = perf;
st->firmware_val = cpu_data->perf_caps.nominal_perf;
+ cppc_cpufreq_update_nominal_limits(policy);
+
return count;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-08-07 21:49 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-07 21:48 [PATCH v7 0/3] ACPI / cpufreq: CPPC: Add ospm_nominal_perf support Sumit Gupta
2026-08-07 21:48 ` [PATCH v7 1/3] ACPI: " Sumit Gupta
2026-08-07 21:48 ` [PATCH v7 2/3] cpufreq: CPPC: Add ospm_nominal_freq attribute Sumit Gupta
2026-08-07 21:48 ` [PATCH v7 3/3] cpufreq: CPPC: Reflect the OSPM nominal in boost and limits Sumit Gupta
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox