* [PATCH] power/amd_pstate: fix frequency matching for continuous scaling
@ 2026-03-28 19:34 Stephen Hemminger
2026-04-03 4:09 ` Tummala, Sivaprasad
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Stephen Hemminger @ 2026-03-28 19:34 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, stable, Anatoly Burakov, Sivaprasad Tummala
The power_init_for_setting_freq() function fails on systems using the
amd-pstate-epp driver because the current CPU frequency read from
scaling_setspeed does not exactly match any of the synthesized
frequency buckets. Unlike acpi_cpufreq which provides a discrete list
of frequencies, amd-pstate operates with continuously variable
frequencies, so an exact match will rarely succeed.
For example, on a Ryzen 9 7945HX the sysfs file reports 2797172
which rounds to 2797000, but this value does not appear in the
generated frequency table.
Replace the exact match lookup with a nearest-frequency search.
Also fix several issues in the same function:
- strtoul() was called with NULL endptr, making parse failures
undetectable
- errno was not checked, so stale errors could cause false positives
- freq was declared as uint32_t, truncating the unsigned long
return value of strtoul() on LP64 platforms
- no error was logged when frequency matching failed
Bugzilla ID: 1915
Fixes: 1ed04d33cf19 ("power: support amd-pstate cpufreq driver")
Cc: stable@dpdk.org
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/power/amd_pstate/amd_pstate_cpufreq.c | 56 ++++++++++++++-----
1 file changed, 41 insertions(+), 15 deletions(-)
diff --git a/drivers/power/amd_pstate/amd_pstate_cpufreq.c b/drivers/power/amd_pstate/amd_pstate_cpufreq.c
index 95495bff7d..14625ffd73 100644
--- a/drivers/power/amd_pstate/amd_pstate_cpufreq.c
+++ b/drivers/power/amd_pstate/amd_pstate_cpufreq.c
@@ -5,6 +5,7 @@
*/
#include <stdlib.h>
+#include <errno.h>
#include <rte_memcpy.h>
#include <rte_stdatomic.h>
@@ -291,15 +292,21 @@ power_get_available_freqs(struct amd_pstate_power_info *pi)
return ret;
}
-/**
- * It is to fopen the sys file for the future setting the lcore frequency.
- */
+static inline unsigned long
+abs_diff(unsigned long a, unsigned long b)
+{
+ return (a > b) ? a - b : b - a;
+}
+
static int
power_init_for_setting_freq(struct amd_pstate_power_info *pi)
{
- FILE *f = NULL;
+ FILE *f;
char buf[BUFSIZ];
- uint32_t i, freq;
+ char *endptr;
+ unsigned long freq, freq_conv;
+ unsigned long best_diff, diff;
+ uint32_t i, best_idx;
int ret;
open_core_sysfs_file(&f, "rw+", POWER_SYSFILE_SETSPEED, pi->lcore_id);
@@ -308,7 +315,6 @@ power_init_for_setting_freq(struct amd_pstate_power_info *pi)
POWER_SYSFILE_SETSPEED);
goto err;
}
-
ret = read_core_sysfs_s(f, buf, sizeof(buf));
if (ret < 0) {
POWER_LOG(ERR, "Failed to read %s",
@@ -316,25 +322,45 @@ power_init_for_setting_freq(struct amd_pstate_power_info *pi)
goto err;
}
- freq = strtoul(buf, NULL, POWER_CONVERT_TO_DECIMAL);
+ errno = 0;
+ freq = strtoul(buf, &endptr, POWER_CONVERT_TO_DECIMAL);
+ if (errno != 0 || endptr == buf || freq == 0) {
+ POWER_LOG(ERR, "Failed to parse frequency '%s' for lcore %u",
+ buf, pi->lcore_id);
+ goto err;
+ }
/* convert the frequency to nearest 1000 value
* Ex: if freq=1396789 then freq_conv=1397000
* Ex: if freq=800030 then freq_conv=800000
*/
- unsigned int freq_conv = 0;
- freq_conv = (freq + FREQ_ROUNDING_DELTA)
- / ROUND_FREQ_TO_N_1000;
+ freq_conv = (freq + FREQ_ROUNDING_DELTA) / ROUND_FREQ_TO_N_1000;
freq_conv = freq_conv * ROUND_FREQ_TO_N_1000;
- for (i = 0; i < pi->nb_freqs; i++) {
- if (freq_conv == pi->freqs[i]) {
- pi->curr_idx = i;
- pi->f = f;
- return 0;
+ /* Find the nearest frequency in the table.
+ * With amd-pstate the CPU runs at continuously variable
+ * frequencies so the current frequency will not exactly
+ * match one of the synthesized frequency buckets.
+ */
+ best_idx = 0;
+ best_diff = abs_diff(freq_conv, pi->freqs[0]);
+
+ for (i = 1; i < pi->nb_freqs; i++) {
+ diff = abs_diff(freq_conv, pi->freqs[i]);
+ if (diff < best_diff) {
+ best_diff = diff;
+ best_idx = i;
}
}
+ POWER_DEBUG_LOG("Freq %lu rounded to %lu matched bucket [%u] = %u "
+ "for lcore %u", freq, freq_conv, best_idx,
+ pi->freqs[best_idx], pi->lcore_id);
+
+ pi->curr_idx = best_idx;
+ pi->f = f;
+ return 0;
+
err:
if (f != NULL)
fclose(f);
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* RE: [PATCH] power/amd_pstate: fix frequency matching for continuous scaling
2026-03-28 19:34 [PATCH] power/amd_pstate: fix frequency matching for continuous scaling Stephen Hemminger
@ 2026-04-03 4:09 ` Tummala, Sivaprasad
2026-06-10 22:25 ` Thomas Monjalon
2026-09-08 16:52 ` [PATCH v2 0/3] power: fixes for amd-pstate frequency scaling Stephen Hemminger
2 siblings, 0 replies; 7+ messages in thread
From: Tummala, Sivaprasad @ 2026-04-03 4:09 UTC (permalink / raw)
To: Stephen Hemminger, dev@dpdk.org; +Cc: stable@dpdk.org, Anatoly Burakov
[AMD Official Use Only - AMD Internal Distribution Only]
> -----Original Message-----
> From: Stephen Hemminger <stephen@networkplumber.org>
> Sent: Sunday, March 29, 2026 1:04 AM
> To: dev@dpdk.org
> Cc: Stephen Hemminger <stephen@networkplumber.org>; stable@dpdk.org;
> Anatoly Burakov <anatoly.burakov@intel.com>; Tummala, Sivaprasad
> <Sivaprasad.Tummala@amd.com>
> Subject: [PATCH] power/amd_pstate: fix frequency matching for continuous scaling
>
> Caution: This message originated from an External Source. Use proper caution
> when opening attachments, clicking links, or responding.
>
>
> The power_init_for_setting_freq() function fails on systems using the amd-pstate-
> epp driver because the current CPU frequency read from scaling_setspeed does
> not exactly match any of the synthesized frequency buckets. Unlike acpi_cpufreq
> which provides a discrete list of frequencies, amd-pstate operates with continuously
> variable frequencies, so an exact match will rarely succeed.
>
> For example, on a Ryzen 9 7945HX the sysfs file reports 2797172 which rounds to
> 2797000, but this value does not appear in the generated frequency table.
>
> Replace the exact match lookup with a nearest-frequency search.
>
> Also fix several issues in the same function:
> - strtoul() was called with NULL endptr, making parse failures
> undetectable
> - errno was not checked, so stale errors could cause false positives
> - freq was declared as uint32_t, truncating the unsigned long
> return value of strtoul() on LP64 platforms
> - no error was logged when frequency matching failed
>
> Bugzilla ID: 1915
> Fixes: 1ed04d33cf19 ("power: support amd-pstate cpufreq driver")
> Cc: stable@dpdk.org
>
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
> drivers/power/amd_pstate/amd_pstate_cpufreq.c | 56 ++++++++++++++-----
> 1 file changed, 41 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/power/amd_pstate/amd_pstate_cpufreq.c
> b/drivers/power/amd_pstate/amd_pstate_cpufreq.c
> index 95495bff7d..14625ffd73 100644
> --- a/drivers/power/amd_pstate/amd_pstate_cpufreq.c
> +++ b/drivers/power/amd_pstate/amd_pstate_cpufreq.c
> @@ -5,6 +5,7 @@
> */
>
> #include <stdlib.h>
> +#include <errno.h>
>
> #include <rte_memcpy.h>
> #include <rte_stdatomic.h>
> @@ -291,15 +292,21 @@ power_get_available_freqs(struct
> amd_pstate_power_info *pi)
> return ret;
> }
>
> -/**
> - * It is to fopen the sys file for the future setting the lcore frequency.
> - */
> +static inline unsigned long
> +abs_diff(unsigned long a, unsigned long b) {
> + return (a > b) ? a - b : b - a;
> +}
> +
> static int
> power_init_for_setting_freq(struct amd_pstate_power_info *pi) {
> - FILE *f = NULL;
> + FILE *f;
> char buf[BUFSIZ];
> - uint32_t i, freq;
> + char *endptr;
> + unsigned long freq, freq_conv;
> + unsigned long best_diff, diff;
> + uint32_t i, best_idx;
> int ret;
>
> open_core_sysfs_file(&f, "rw+", POWER_SYSFILE_SETSPEED, pi-
> >lcore_id); @@ -308,7 +315,6 @@ power_init_for_setting_freq(struct
> amd_pstate_power_info *pi)
> POWER_SYSFILE_SETSPEED);
> goto err;
> }
> -
> ret = read_core_sysfs_s(f, buf, sizeof(buf));
> if (ret < 0) {
> POWER_LOG(ERR, "Failed to read %s", @@ -316,25 +322,45 @@
> power_init_for_setting_freq(struct amd_pstate_power_info *pi)
> goto err;
> }
>
> - freq = strtoul(buf, NULL, POWER_CONVERT_TO_DECIMAL);
> + errno = 0;
> + freq = strtoul(buf, &endptr, POWER_CONVERT_TO_DECIMAL);
> + if (errno != 0 || endptr == buf || freq == 0) {
> + POWER_LOG(ERR, "Failed to parse frequency '%s' for lcore %u",
> + buf, pi->lcore_id);
> + goto err;
> + }
>
> /* convert the frequency to nearest 1000 value
> * Ex: if freq=1396789 then freq_conv=1397000
> * Ex: if freq=800030 then freq_conv=800000
> */
> - unsigned int freq_conv = 0;
> - freq_conv = (freq + FREQ_ROUNDING_DELTA)
> - / ROUND_FREQ_TO_N_1000;
> + freq_conv = (freq + FREQ_ROUNDING_DELTA) /
> ROUND_FREQ_TO_N_1000;
> freq_conv = freq_conv * ROUND_FREQ_TO_N_1000;
>
> - for (i = 0; i < pi->nb_freqs; i++) {
> - if (freq_conv == pi->freqs[i]) {
> - pi->curr_idx = i;
> - pi->f = f;
> - return 0;
> + /* Find the nearest frequency in the table.
> + * With amd-pstate the CPU runs at continuously variable
> + * frequencies so the current frequency will not exactly
> + * match one of the synthesized frequency buckets.
> + */
> + best_idx = 0;
> + best_diff = abs_diff(freq_conv, pi->freqs[0]);
> +
> + for (i = 1; i < pi->nb_freqs; i++) {
> + diff = abs_diff(freq_conv, pi->freqs[i]);
> + if (diff < best_diff) {
> + best_diff = diff;
> + best_idx = i;
> }
> }
>
> + POWER_DEBUG_LOG("Freq %lu rounded to %lu matched bucket [%u] =
> %u "
> + "for lcore %u", freq, freq_conv, best_idx,
> + pi->freqs[best_idx], pi->lcore_id);
> +
> + pi->curr_idx = best_idx;
> + pi->f = f;
> + return 0;
> +
> err:
> if (f != NULL)
> fclose(f);
> --
> 2.53.0
LGTM
Acked-by: Sivaprasad Tummala <sivaprasad.tummala@amd.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] power/amd_pstate: fix frequency matching for continuous scaling
2026-03-28 19:34 [PATCH] power/amd_pstate: fix frequency matching for continuous scaling Stephen Hemminger
2026-04-03 4:09 ` Tummala, Sivaprasad
@ 2026-06-10 22:25 ` Thomas Monjalon
2026-09-08 16:52 ` [PATCH v2 0/3] power: fixes for amd-pstate frequency scaling Stephen Hemminger
2 siblings, 0 replies; 7+ messages in thread
From: Thomas Monjalon @ 2026-06-10 22:25 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: dev, stable, Anatoly Burakov, Sivaprasad Tummala
28/03/2026 20:34, Stephen Hemminger:
> The power_init_for_setting_freq() function fails on systems using the
> amd-pstate-epp driver because the current CPU frequency read from
> scaling_setspeed does not exactly match any of the synthesized
> frequency buckets. Unlike acpi_cpufreq which provides a discrete list
> of frequencies, amd-pstate operates with continuously variable
> frequencies, so an exact match will rarely succeed.
>
> For example, on a Ryzen 9 7945HX the sysfs file reports 2797172
> which rounds to 2797000, but this value does not appear in the
> generated frequency table.
>
> Replace the exact match lookup with a nearest-frequency search.
>
[...]
> - freq = strtoul(buf, NULL, POWER_CONVERT_TO_DECIMAL);
> + errno = 0;
> + freq = strtoul(buf, &endptr, POWER_CONVERT_TO_DECIMAL);
> + if (errno != 0 || endptr == buf || freq == 0) {
> + POWER_LOG(ERR, "Failed to parse frequency '%s' for lcore %u",
> + buf, pi->lcore_id);
> + goto err;
> + }
>
> /* convert the frequency to nearest 1000 value
> * Ex: if freq=1396789 then freq_conv=1397000
> * Ex: if freq=800030 then freq_conv=800000
> */
> - unsigned int freq_conv = 0;
> - freq_conv = (freq + FREQ_ROUNDING_DELTA)
> - / ROUND_FREQ_TO_N_1000;
> + freq_conv = (freq + FREQ_ROUNDING_DELTA) / ROUND_FREQ_TO_N_1000;
> freq_conv = freq_conv * ROUND_FREQ_TO_N_1000;
>
> - for (i = 0; i < pi->nb_freqs; i++) {
> - if (freq_conv == pi->freqs[i]) {
> - pi->curr_idx = i;
> - pi->f = f;
> - return 0;
> + /* Find the nearest frequency in the table.
> + * With amd-pstate the CPU runs at continuously variable
> + * frequencies so the current frequency will not exactly
> + * match one of the synthesized frequency buckets.
> + */
> + best_idx = 0;
> + best_diff = abs_diff(freq_conv, pi->freqs[0]);
> +
> + for (i = 1; i < pi->nb_freqs; i++) {
> + diff = abs_diff(freq_conv, pi->freqs[i]);
> + if (diff < best_diff) {
> + best_diff = diff;
> + best_idx = i;
> }
> }
GPT found this problem:
power_init_for_setting_freq() now assigns pi->curr_idx = best_idx
after finding the nearest synthesized frequency bucket.
However, set_freq_internal() skips the sysfs write
whenever idx == pi->curr_idx.
This means that if the current scaling_setspeed value is merely close
to a bucket but not equal to it, a later request to set that bucket
will return success without actually writing the requested frequency.
This can happen during init too: power_amd_pstate_cpufreq_init()
calls freq_max() after initialization, but if the current frequency
is nearest to the max bucket, freq_max() will be skipped even when
the actual sysfs value is not the synthesized max.
The nearest-bucket match should not be treated as an exact programmed
frequency, or the next explicit set to that bucket should be forced.
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 0/3] power: fixes for amd-pstate frequency scaling
2026-03-28 19:34 [PATCH] power/amd_pstate: fix frequency matching for continuous scaling Stephen Hemminger
2026-04-03 4:09 ` Tummala, Sivaprasad
2026-06-10 22:25 ` Thomas Monjalon
@ 2026-09-08 16:52 ` Stephen Hemminger
2026-09-08 16:52 ` [PATCH v2 1/3] power/amd_pstate: fix frequency matching for continuous scaling Stephen Hemminger
` (2 more replies)
2 siblings, 3 replies; 7+ messages in thread
From: Stephen Hemminger @ 2026-09-08 16:52 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger
The power library does not work with the amd-pstate driver in passive
mode. Initialization fails because the current frequency read from
scaling_setspeed never matches one of the synthesized frequency buckets
exactly, since amd-pstate scales continuously.
The first patch fixes the matching. The second fixes an unrelated bug
found while testing: the sysfs file is buffered, so a frequency the
kernel rejected was reported as success. The third fixes the unit test,
which assumed the nominal frequency sits at a fixed index in the table.
Tested on a Ryzen 9 7945HX booted with amd_pstate=passive and the
cpufreq_userspace governor loaded. power_cpufreq_autotest now passes,
with and without turbo.
v2 - fixed review comment from GPT
- fixed two other bugs found during review/testing.
Stephen Hemminger (3):
power/amd_pstate: fix frequency matching for continuous scaling
power: check for errors when writing frequency
test/power: fix nominal frequency check with amd-pstate
app/test/test_power_cpufreq.c | 5 +-
drivers/power/acpi/acpi_cpufreq.c | 12 ++-
drivers/power/amd_pstate/amd_pstate_cpufreq.c | 89 +++++++++++++------
drivers/power/cppc/cppc_cpufreq.c | 12 ++-
4 files changed, 74 insertions(+), 44 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 1/3] power/amd_pstate: fix frequency matching for continuous scaling
2026-09-08 16:52 ` [PATCH v2 0/3] power: fixes for amd-pstate frequency scaling Stephen Hemminger
@ 2026-09-08 16:52 ` Stephen Hemminger
2026-09-08 16:52 ` [PATCH v2 2/3] power: check for errors when writing frequency Stephen Hemminger
2026-09-08 16:52 ` [PATCH v2 3/3] test/power: fix nominal frequency check with amd-pstate Stephen Hemminger
2 siblings, 0 replies; 7+ messages in thread
From: Stephen Hemminger @ 2026-09-08 16:52 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, stable, Sivaprasad Tummala, Anatoly Burakov
power_init_for_setting_freq() fails with the amd-pstate driver because
the frequency read from scaling_setspeed does not exactly match any of
the synthesized frequency buckets. Unlike acpi_cpufreq, which provides a
discrete list, amd-pstate scales continuously, so an exact match rarely
succeeds. On a Ryzen 9 7945HX the sysfs file reports 2492000 while the
buckets are spaced by (scaling_max - scaling_min) / 63.
Use the nearest frequency instead of an exact match.
Since the match is only the nearest bucket, curr_idx would no longer
match what was last written to scaling_setspeed. set_freq_internal()
returns early when the requested index is already current, so setting
that bucket would report success without doing anything. Split the
sysfs write out into write_freq() and program the bucket during init.
Also in the same function:
- strtoul() was called with NULL endptr, so parse failures went
undetected
- errno was not checked
- freq was uint32_t, truncating the strtoul() result on LP64
- no error was logged when matching failed
Bugzilla ID: 1915
Fixes: 1ed04d33cf19 ("power: support amd-pstate cpufreq driver")
Cc: stable@dpdk.org
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Sivaprasad Tummala <sivaprasad.tummala@amd.com>
---
drivers/power/amd_pstate/amd_pstate_cpufreq.c | 91 +++++++++++++------
1 file changed, 63 insertions(+), 28 deletions(-)
diff --git a/drivers/power/amd_pstate/amd_pstate_cpufreq.c b/drivers/power/amd_pstate/amd_pstate_cpufreq.c
index af9c1309f3..13ffcefc84 100644
--- a/drivers/power/amd_pstate/amd_pstate_cpufreq.c
+++ b/drivers/power/amd_pstate/amd_pstate_cpufreq.c
@@ -5,6 +5,7 @@
*/
#include <stdlib.h>
+#include <errno.h>
#include <rte_memcpy.h>
#include <rte_stdatomic.h>
@@ -53,6 +54,25 @@ struct __rte_cache_aligned amd_pstate_power_info {
static struct amd_pstate_power_info lcore_power_info[RTE_MAX_LCORE];
+static int
+write_freq(struct amd_pstate_power_info *pi, uint32_t idx)
+{
+ if (fseek(pi->f, 0, SEEK_SET) < 0) {
+ POWER_LOG(ERR, "Fail to set file position indicator to 0 "
+ "for setting frequency for lcore %u", pi->lcore_id);
+ return -1;
+ }
+ if (fprintf(pi->f, "%u", pi->freqs[idx]) < 0) {
+ POWER_LOG(ERR, "Fail to write new frequency for "
+ "lcore %u", pi->lcore_id);
+ return -1;
+ }
+ fflush(pi->f);
+ pi->curr_idx = idx;
+
+ return 1;
+}
+
/**
* It is to set specific freq for specific logical core, according to the index
* of supported frequencies.
@@ -72,20 +92,8 @@ set_freq_internal(struct amd_pstate_power_info *pi, uint32_t idx)
POWER_DEBUG_LOG("Frequency[%u] %u to be set for lcore %u",
idx, pi->freqs[idx], pi->lcore_id);
- if (fseek(pi->f, 0, SEEK_SET) < 0) {
- POWER_LOG(ERR, "Fail to set file position indicator to 0 "
- "for setting frequency for lcore %u", pi->lcore_id);
- return -1;
- }
- if (fprintf(pi->f, "%u", pi->freqs[idx]) < 0) {
- POWER_LOG(ERR, "Fail to write new frequency for "
- "lcore %u", pi->lcore_id);
- return -1;
- }
- fflush(pi->f);
- pi->curr_idx = idx;
- return 1;
+ return write_freq(pi, idx);
}
/**
@@ -282,15 +290,21 @@ power_get_available_freqs(struct amd_pstate_power_info *pi)
return ret;
}
-/**
- * It is to fopen the sys file for the future setting the lcore frequency.
- */
+static inline unsigned long
+abs_diff(unsigned long a, unsigned long b)
+{
+ return (a > b) ? a - b : b - a;
+}
+
static int
power_init_for_setting_freq(struct amd_pstate_power_info *pi)
{
- FILE *f = NULL;
+ FILE *f;
char buf[BUFSIZ];
- uint32_t i, freq;
+ char *endptr;
+ unsigned long freq, freq_conv;
+ unsigned long best_diff, diff;
+ uint32_t i, best_idx;
int ret;
open_core_sysfs_file(&f, "rw+", POWER_SYSFILE_SETSPEED, pi->lcore_id);
@@ -299,7 +313,6 @@ power_init_for_setting_freq(struct amd_pstate_power_info *pi)
POWER_SYSFILE_SETSPEED);
goto err;
}
-
ret = read_core_sysfs_s(f, buf, sizeof(buf));
if (ret < 0) {
POWER_LOG(ERR, "Failed to read %s",
@@ -307,28 +320,50 @@ power_init_for_setting_freq(struct amd_pstate_power_info *pi)
goto err;
}
- freq = strtoul(buf, NULL, POWER_CONVERT_TO_DECIMAL);
+ errno = 0;
+ freq = strtoul(buf, &endptr, POWER_CONVERT_TO_DECIMAL);
+ if (errno != 0 || endptr == buf || freq == 0) {
+ POWER_LOG(ERR, "Failed to parse frequency '%s' for lcore %u",
+ buf, pi->lcore_id);
+ goto err;
+ }
/* convert the frequency to nearest 1000 value
* Ex: if freq=1396789 then freq_conv=1397000
* Ex: if freq=800030 then freq_conv=800000
*/
- unsigned int freq_conv = 0;
- freq_conv = (freq + FREQ_ROUNDING_DELTA)
- / ROUND_FREQ_TO_N_1000;
+ freq_conv = (freq + FREQ_ROUNDING_DELTA) / ROUND_FREQ_TO_N_1000;
freq_conv = freq_conv * ROUND_FREQ_TO_N_1000;
- for (i = 0; i < pi->nb_freqs; i++) {
- if (freq_conv == pi->freqs[i]) {
- pi->curr_idx = i;
- pi->f = f;
- return 0;
+ /* amd-pstate scales continuously, so the current frequency will
+ * rarely match a bucket exactly. Use the nearest one.
+ */
+ best_idx = 0;
+ best_diff = abs_diff(freq_conv, pi->freqs[0]);
+
+ for (i = 1; i < pi->nb_freqs; i++) {
+ diff = abs_diff(freq_conv, pi->freqs[i]);
+ if (diff < best_diff) {
+ best_diff = diff;
+ best_idx = i;
}
}
+ POWER_DEBUG_LOG("Freq %lu rounded to %lu matched bucket [%u] = %u "
+ "for lcore %u", freq, freq_conv, best_idx,
+ pi->freqs[best_idx], pi->lcore_id);
+
+ /* Program the bucket so curr_idx matches the actual frequency. */
+ pi->f = f;
+ if (write_freq(pi, best_idx) < 0)
+ goto err;
+
+ return 0;
+
err:
if (f != NULL)
fclose(f);
+ pi->f = NULL;
return -1;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 2/3] power: check for errors when writing frequency
2026-09-08 16:52 ` [PATCH v2 0/3] power: fixes for amd-pstate frequency scaling Stephen Hemminger
2026-09-08 16:52 ` [PATCH v2 1/3] power/amd_pstate: fix frequency matching for continuous scaling Stephen Hemminger
@ 2026-09-08 16:52 ` Stephen Hemminger
2026-09-08 16:52 ` [PATCH v2 3/3] test/power: fix nominal frequency check with amd-pstate Stephen Hemminger
2 siblings, 0 replies; 7+ messages in thread
From: Stephen Hemminger @ 2026-09-08 16:52 UTC (permalink / raw)
To: dev
Cc: Stephen Hemminger, stable, Anatoly Burakov, Sivaprasad Tummala,
Pablo de Lara, Alan Carew, Richael Zhuang, David Hunt
The sysfs file is buffered, so fprintf() returns success even when the
kernel rejects the value. The error only shows up when the buffer is
flushed, and the fflush() return was never checked. A failed frequency
change was therefore reported as success.
Use write_core_sysfs_s() which already does the fseek, write and a
checked fflush.
Fixes: 445c6528b55f ("power: common interface for guest and host")
Fixes: ef1cc88f1837 ("power: support cppc_cpufreq driver")
Fixes: 1ed04d33cf19 ("power: support amd-pstate cpufreq driver")
Cc: stable@dpdk.org
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
drivers/power/acpi/acpi_cpufreq.c | 12 +++++-------
drivers/power/amd_pstate/amd_pstate_cpufreq.c | 16 +++++++---------
drivers/power/cppc/cppc_cpufreq.c | 12 +++++-------
3 files changed, 17 insertions(+), 23 deletions(-)
diff --git a/drivers/power/acpi/acpi_cpufreq.c b/drivers/power/acpi/acpi_cpufreq.c
index af85a8cdec..4ee3d5bd26 100644
--- a/drivers/power/acpi/acpi_cpufreq.c
+++ b/drivers/power/acpi/acpi_cpufreq.c
@@ -54,6 +54,8 @@ static struct acpi_power_info lcore_power_info[RTE_MAX_LCORE];
static int
set_freq_internal(struct acpi_power_info *pi, uint32_t idx)
{
+ char buf[16];
+
if (idx >= RTE_MAX_LCORE_FREQS || idx >= pi->nb_freqs) {
POWER_LOG(ERR, "Invalid frequency index %u, which "
"should be less than %u", idx, pi->nb_freqs);
@@ -66,17 +68,13 @@ set_freq_internal(struct acpi_power_info *pi, uint32_t idx)
POWER_DEBUG_LOG("Frequency[%u] %u to be set for lcore %u",
idx, pi->freqs[idx], pi->lcore_id);
- if (fseek(pi->f, 0, SEEK_SET) < 0) {
- POWER_LOG(ERR, "Fail to set file position indicator to 0 "
- "for setting frequency for lcore %u", pi->lcore_id);
- return -1;
- }
- if (fprintf(pi->f, "%u", pi->freqs[idx]) < 0) {
+
+ snprintf(buf, sizeof(buf), "%u", pi->freqs[idx]);
+ if (write_core_sysfs_s(pi->f, buf) != 0) {
POWER_LOG(ERR, "Fail to write new frequency for "
"lcore %u", pi->lcore_id);
return -1;
}
- fflush(pi->f);
pi->curr_idx = idx;
return 1;
diff --git a/drivers/power/amd_pstate/amd_pstate_cpufreq.c b/drivers/power/amd_pstate/amd_pstate_cpufreq.c
index 13ffcefc84..f7e32fe0ac 100644
--- a/drivers/power/amd_pstate/amd_pstate_cpufreq.c
+++ b/drivers/power/amd_pstate/amd_pstate_cpufreq.c
@@ -57,17 +57,15 @@ static struct amd_pstate_power_info lcore_power_info[RTE_MAX_LCORE];
static int
write_freq(struct amd_pstate_power_info *pi, uint32_t idx)
{
- if (fseek(pi->f, 0, SEEK_SET) < 0) {
- POWER_LOG(ERR, "Fail to set file position indicator to 0 "
- "for setting frequency for lcore %u", pi->lcore_id);
- return -1;
- }
- if (fprintf(pi->f, "%u", pi->freqs[idx]) < 0) {
- POWER_LOG(ERR, "Fail to write new frequency for "
- "lcore %u", pi->lcore_id);
+ char buf[16];
+
+ snprintf(buf, sizeof(buf), "%u", pi->freqs[idx]);
+
+ if (write_core_sysfs_s(pi->f, buf) != 0) {
+ POWER_LOG(ERR, "Fail to write new frequency for lcore %u",
+ pi->lcore_id);
return -1;
}
- fflush(pi->f);
pi->curr_idx = idx;
return 1;
diff --git a/drivers/power/cppc/cppc_cpufreq.c b/drivers/power/cppc/cppc_cpufreq.c
index aed44c1212..3bcd4dec41 100644
--- a/drivers/power/cppc/cppc_cpufreq.c
+++ b/drivers/power/cppc/cppc_cpufreq.c
@@ -63,6 +63,8 @@ static struct cppc_power_info lcore_power_info[RTE_MAX_LCORE];
static int
set_freq_internal(struct cppc_power_info *pi, uint32_t idx)
{
+ char buf[16];
+
if (idx >= RTE_MAX_LCORE_FREQS || idx >= pi->nb_freqs) {
POWER_LOG(ERR, "Invalid frequency index %u, which "
"should be less than %u", idx, pi->nb_freqs);
@@ -75,17 +77,13 @@ set_freq_internal(struct cppc_power_info *pi, uint32_t idx)
POWER_DEBUG_LOG("Frequency[%u] %u to be set for lcore %u",
idx, pi->freqs[idx], pi->lcore_id);
- if (fseek(pi->f, 0, SEEK_SET) < 0) {
- POWER_LOG(ERR, "Fail to set file position indicator to 0 "
- "for setting frequency for lcore %u", pi->lcore_id);
- return -1;
- }
- if (fprintf(pi->f, "%u", pi->freqs[idx]) < 0) {
+
+ snprintf(buf, sizeof(buf), "%u", pi->freqs[idx]);
+ if (write_core_sysfs_s(pi->f, buf) != 0) {
POWER_LOG(ERR, "Fail to write new frequency for "
"lcore %u", pi->lcore_id);
return -1;
}
- fflush(pi->f);
pi->curr_idx = idx;
return 1;
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 3/3] test/power: fix nominal frequency check with amd-pstate
2026-09-08 16:52 ` [PATCH v2 0/3] power: fixes for amd-pstate frequency scaling Stephen Hemminger
2026-09-08 16:52 ` [PATCH v2 1/3] power/amd_pstate: fix frequency matching for continuous scaling Stephen Hemminger
2026-09-08 16:52 ` [PATCH v2 2/3] power: check for errors when writing frequency Stephen Hemminger
@ 2026-09-08 16:52 ` Stephen Hemminger
2 siblings, 0 replies; 7+ messages in thread
From: Stephen Hemminger @ 2026-09-08 16:52 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, stable, Anatoly Burakov, Sivaprasad Tummala
The turbo test checks that the core runs at frequency index 1 after
scaling up with turbo disabled. That index is only nominal for
acpi-cpufreq; amd-pstate spreads its buckets between scaling_min_freq
and scaling_max_freq, putting nominal at index 47 on a Ryzen 9 7945HX.
Use the index reported by rte_power_get_freq() instead.
Fixes: 1ed04d33cf19 ("power: support amd-pstate cpufreq driver")
Cc: stable@dpdk.org
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
app/test/test_power_cpufreq.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/app/test/test_power_cpufreq.c b/app/test/test_power_cpufreq.c
index 08bce4c0d1..1f79b80e6f 100644
--- a/app/test/test_power_cpufreq.c
+++ b/app/test/test_power_cpufreq.c
@@ -486,8 +486,9 @@ check_power_turbo(void)
return -1;
}
- /* Check the current frequency */
- ret = check_cur_freq(TEST_POWER_LCORE_ID, 1, false);
+ /* Nominal frequency is not at a fixed index in the table. */
+ ret = check_cur_freq(TEST_POWER_LCORE_ID,
+ rte_power_get_freq(TEST_POWER_LCORE_ID), false);
if (ret < 0)
return -1;
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-09-08 16:55 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-28 19:34 [PATCH] power/amd_pstate: fix frequency matching for continuous scaling Stephen Hemminger
2026-04-03 4:09 ` Tummala, Sivaprasad
2026-06-10 22:25 ` Thomas Monjalon
2026-09-08 16:52 ` [PATCH v2 0/3] power: fixes for amd-pstate frequency scaling Stephen Hemminger
2026-09-08 16:52 ` [PATCH v2 1/3] power/amd_pstate: fix frequency matching for continuous scaling Stephen Hemminger
2026-09-08 16:52 ` [PATCH v2 2/3] power: check for errors when writing frequency Stephen Hemminger
2026-09-08 16:52 ` [PATCH v2 3/3] test/power: fix nominal frequency check with amd-pstate Stephen Hemminger
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox