Skip to content

Commit 4a49db7

Browse files
committed
Merge tag 'linux-cpupower-5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux
Pull cpupower utility updates for 5.18-rc1 from Shuah Khan: "This cpupower update for Linux 5.18-rc1 adds AMD P-State Support to cpupower tool. AMD P-State kernel support went into 5.17-rc1." * tag 'linux-cpupower-5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux: cpupower: Add "perf" option to print AMD P-State information cpupower: Add function to print AMD P-State performance capabilities cpupower: Move print_speed function into misc helper cpupower: Enable boost state support for AMD P-State module cpupower: Add AMD P-State sysfs definition and access helper cpupower: Introduce ACPI CPPC library cpupower: Add the function to get the sysfs value from specific table cpupower: Initial AMD P-State capability cpupower: Add the function to check AMD P-State enabled cpupower: Add AMD P-State capability flag
2 parents caa2824 + 8382dce commit 4a49db7

11 files changed

Lines changed: 321 additions & 62 deletions

File tree

tools/power/cpupower/Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,9 @@ UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \
143143
utils/helpers/bitmask.h \
144144
utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def
145145

146-
LIB_HEADERS = lib/cpufreq.h lib/cpupower.h lib/cpuidle.h
147-
LIB_SRC = lib/cpufreq.c lib/cpupower.c lib/cpuidle.c
148-
LIB_OBJS = lib/cpufreq.o lib/cpupower.o lib/cpuidle.o
146+
LIB_HEADERS = lib/cpufreq.h lib/cpupower.h lib/cpuidle.h lib/acpi_cppc.h
147+
LIB_SRC = lib/cpufreq.c lib/cpupower.c lib/cpuidle.c lib/acpi_cppc.c
148+
LIB_OBJS = lib/cpufreq.o lib/cpupower.o lib/cpuidle.o lib/acpi_cppc.o
149149
LIB_OBJS := $(addprefix $(OUTPUT),$(LIB_OBJS))
150150

151151
override CFLAGS += -pipe
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
3+
#include <stdio.h>
4+
#include <errno.h>
5+
#include <stdlib.h>
6+
#include <string.h>
7+
#include <sys/types.h>
8+
#include <sys/stat.h>
9+
#include <fcntl.h>
10+
#include <unistd.h>
11+
12+
#include "cpupower_intern.h"
13+
#include "acpi_cppc.h"
14+
15+
/* ACPI CPPC sysfs access ***********************************************/
16+
17+
static int acpi_cppc_read_file(unsigned int cpu, const char *fname,
18+
char *buf, size_t buflen)
19+
{
20+
char path[SYSFS_PATH_MAX];
21+
22+
snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/acpi_cppc/%s",
23+
cpu, fname);
24+
return cpupower_read_sysfs(path, buf, buflen);
25+
}
26+
27+
static const char * const acpi_cppc_value_files[] = {
28+
[HIGHEST_PERF] = "highest_perf",
29+
[LOWEST_PERF] = "lowest_perf",
30+
[NOMINAL_PERF] = "nominal_perf",
31+
[LOWEST_NONLINEAR_PERF] = "lowest_nonlinear_perf",
32+
[LOWEST_FREQ] = "lowest_freq",
33+
[NOMINAL_FREQ] = "nominal_freq",
34+
[REFERENCE_PERF] = "reference_perf",
35+
[WRAPAROUND_TIME] = "wraparound_time"
36+
};
37+
38+
unsigned long acpi_cppc_get_data(unsigned int cpu, enum acpi_cppc_value which)
39+
{
40+
unsigned long long value;
41+
unsigned int len;
42+
char linebuf[MAX_LINE_LEN];
43+
char *endp;
44+
45+
if (which >= MAX_CPPC_VALUE_FILES)
46+
return 0;
47+
48+
len = acpi_cppc_read_file(cpu, acpi_cppc_value_files[which],
49+
linebuf, sizeof(linebuf));
50+
if (len == 0)
51+
return 0;
52+
53+
value = strtoull(linebuf, &endp, 0);
54+
55+
if (endp == linebuf || errno == ERANGE)
56+
return 0;
57+
58+
return value;
59+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
3+
#ifndef __ACPI_CPPC_H__
4+
#define __ACPI_CPPC_H__
5+
6+
enum acpi_cppc_value {
7+
HIGHEST_PERF,
8+
LOWEST_PERF,
9+
NOMINAL_PERF,
10+
LOWEST_NONLINEAR_PERF,
11+
LOWEST_FREQ,
12+
NOMINAL_FREQ,
13+
REFERENCE_PERF,
14+
WRAPAROUND_TIME,
15+
MAX_CPPC_VALUE_FILES
16+
};
17+
18+
unsigned long acpi_cppc_get_data(unsigned int cpu,
19+
enum acpi_cppc_value which);
20+
21+
#endif /* _ACPI_CPPC_H */

tools/power/cpupower/lib/cpufreq.c

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,20 +83,21 @@ static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = {
8383
[STATS_NUM_TRANSITIONS] = "stats/total_trans"
8484
};
8585

86-
87-
static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
88-
enum cpufreq_value which)
86+
unsigned long cpufreq_get_sysfs_value_from_table(unsigned int cpu,
87+
const char **table,
88+
unsigned int index,
89+
unsigned int size)
8990
{
9091
unsigned long value;
9192
unsigned int len;
9293
char linebuf[MAX_LINE_LEN];
9394
char *endp;
9495

95-
if (which >= MAX_CPUFREQ_VALUE_READ_FILES)
96+
if (!table || index >= size || !table[index])
9697
return 0;
9798

98-
len = sysfs_cpufreq_read_file(cpu, cpufreq_value_files[which],
99-
linebuf, sizeof(linebuf));
99+
len = sysfs_cpufreq_read_file(cpu, table[index], linebuf,
100+
sizeof(linebuf));
100101

101102
if (len == 0)
102103
return 0;
@@ -109,6 +110,14 @@ static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
109110
return value;
110111
}
111112

113+
static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
114+
enum cpufreq_value which)
115+
{
116+
return cpufreq_get_sysfs_value_from_table(cpu, cpufreq_value_files,
117+
which,
118+
MAX_CPUFREQ_VALUE_READ_FILES);
119+
}
120+
112121
/* read access to files which contain one string */
113122

114123
enum cpufreq_string {
@@ -124,7 +133,7 @@ static const char *cpufreq_string_files[MAX_CPUFREQ_STRING_FILES] = {
124133

125134

126135
static char *sysfs_cpufreq_get_one_string(unsigned int cpu,
127-
enum cpufreq_string which)
136+
enum cpufreq_string which)
128137
{
129138
char linebuf[MAX_LINE_LEN];
130139
char *result;

tools/power/cpupower/lib/cpufreq.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,18 @@ int cpufreq_modify_policy_governor(unsigned int cpu, char *governor);
203203
int cpufreq_set_frequency(unsigned int cpu,
204204
unsigned long target_frequency);
205205

206+
/*
207+
* get the sysfs value from specific table
208+
*
209+
* Read the value with the sysfs file name from specific table. Does
210+
* only work if the cpufreq driver has the specific sysfs interfaces.
211+
*/
212+
213+
unsigned long cpufreq_get_sysfs_value_from_table(unsigned int cpu,
214+
const char **table,
215+
unsigned int index,
216+
unsigned int size);
217+
206218
#ifdef __cplusplus
207219
}
208220
#endif

tools/power/cpupower/man/cpupower-frequency-info.1

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ human\-readable output for the \-f, \-w, \-s and \-y parameters.
5353
\fB\-n\fR \fB\-\-no-rounding\fR
5454
Output frequencies and latencies without rounding off values.
5555
.TP
56+
\fB\-c\fR \fB\-\-perf\fR
57+
Get performances and frequencies capabilities of CPPC, by reading it from hardware (only available on the hardware with CPPC).
58+
.TP
5659
.SH "REMARKS"
5760
.LP
5861
By default only values of core zero are displayed. How to display settings of

tools/power/cpupower/utils/cpufreq-info.c

Lines changed: 35 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -84,43 +84,6 @@ static void proc_cpufreq_output(void)
8484
}
8585

8686
static int no_rounding;
87-
static void print_speed(unsigned long speed)
88-
{
89-
unsigned long tmp;
90-
91-
if (no_rounding) {
92-
if (speed > 1000000)
93-
printf("%u.%06u GHz", ((unsigned int) speed/1000000),
94-
((unsigned int) speed%1000000));
95-
else if (speed > 1000)
96-
printf("%u.%03u MHz", ((unsigned int) speed/1000),
97-
(unsigned int) (speed%1000));
98-
else
99-
printf("%lu kHz", speed);
100-
} else {
101-
if (speed > 1000000) {
102-
tmp = speed%10000;
103-
if (tmp >= 5000)
104-
speed += 10000;
105-
printf("%u.%02u GHz", ((unsigned int) speed/1000000),
106-
((unsigned int) (speed%1000000)/10000));
107-
} else if (speed > 100000) {
108-
tmp = speed%1000;
109-
if (tmp >= 500)
110-
speed += 1000;
111-
printf("%u MHz", ((unsigned int) speed/1000));
112-
} else if (speed > 1000) {
113-
tmp = speed%100;
114-
if (tmp >= 50)
115-
speed += 100;
116-
printf("%u.%01u MHz", ((unsigned int) speed/1000),
117-
((unsigned int) (speed%1000)/100));
118-
}
119-
}
120-
121-
return;
122-
}
123-
12487
static void print_duration(unsigned long duration)
12588
{
12689
unsigned long tmp;
@@ -183,9 +146,12 @@ static int get_boost_mode_x86(unsigned int cpu)
183146
printf(_(" Supported: %s\n"), support ? _("yes") : _("no"));
184147
printf(_(" Active: %s\n"), active ? _("yes") : _("no"));
185148

186-
if ((cpupower_cpu_info.vendor == X86_VENDOR_AMD &&
187-
cpupower_cpu_info.family >= 0x10) ||
188-
cpupower_cpu_info.vendor == X86_VENDOR_HYGON) {
149+
if (cpupower_cpu_info.vendor == X86_VENDOR_AMD &&
150+
cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_PSTATE) {
151+
return 0;
152+
} else if ((cpupower_cpu_info.vendor == X86_VENDOR_AMD &&
153+
cpupower_cpu_info.family >= 0x10) ||
154+
cpupower_cpu_info.vendor == X86_VENDOR_HYGON) {
189155
ret = decode_pstates(cpu, b_states, pstates, &pstate_no);
190156
if (ret)
191157
return ret;
@@ -254,11 +220,11 @@ static int get_boost_mode(unsigned int cpu)
254220
if (freqs) {
255221
printf(_(" boost frequency steps: "));
256222
while (freqs->next) {
257-
print_speed(freqs->frequency);
223+
print_speed(freqs->frequency, no_rounding);
258224
printf(", ");
259225
freqs = freqs->next;
260226
}
261-
print_speed(freqs->frequency);
227+
print_speed(freqs->frequency, no_rounding);
262228
printf("\n");
263229
cpufreq_put_available_frequencies(freqs);
264230
}
@@ -277,7 +243,7 @@ static int get_freq_kernel(unsigned int cpu, unsigned int human)
277243
return -EINVAL;
278244
}
279245
if (human) {
280-
print_speed(freq);
246+
print_speed(freq, no_rounding);
281247
} else
282248
printf("%lu", freq);
283249
printf(_(" (asserted by call to kernel)\n"));
@@ -296,7 +262,7 @@ static int get_freq_hardware(unsigned int cpu, unsigned int human)
296262
return -EINVAL;
297263
}
298264
if (human) {
299-
print_speed(freq);
265+
print_speed(freq, no_rounding);
300266
} else
301267
printf("%lu", freq);
302268
printf(_(" (asserted by call to hardware)\n"));
@@ -316,9 +282,9 @@ static int get_hardware_limits(unsigned int cpu, unsigned int human)
316282

317283
if (human) {
318284
printf(_(" hardware limits: "));
319-
print_speed(min);
285+
print_speed(min, no_rounding);
320286
printf(" - ");
321-
print_speed(max);
287+
print_speed(max, no_rounding);
322288
printf("\n");
323289
} else {
324290
printf("%lu %lu\n", min, max);
@@ -350,9 +316,9 @@ static int get_policy(unsigned int cpu)
350316
return -EINVAL;
351317
}
352318
printf(_(" current policy: frequency should be within "));
353-
print_speed(policy->min);
319+
print_speed(policy->min, no_rounding);
354320
printf(_(" and "));
355-
print_speed(policy->max);
321+
print_speed(policy->max, no_rounding);
356322

357323
printf(".\n ");
358324
printf(_("The governor \"%s\" may decide which speed to use\n"
@@ -436,7 +402,7 @@ static int get_freq_stats(unsigned int cpu, unsigned int human)
436402
struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time);
437403
while (stats) {
438404
if (human) {
439-
print_speed(stats->frequency);
405+
print_speed(stats->frequency, no_rounding);
440406
printf(":%.2f%%",
441407
(100.0 * stats->time_in_state) / total_time);
442408
} else
@@ -472,6 +438,17 @@ static int get_latency(unsigned int cpu, unsigned int human)
472438
return 0;
473439
}
474440

441+
/* --performance / -c */
442+
443+
static int get_perf_cap(unsigned int cpu)
444+
{
445+
if (cpupower_cpu_info.vendor == X86_VENDOR_AMD &&
446+
cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_PSTATE)
447+
amd_pstate_show_perf_and_freq(cpu, no_rounding);
448+
449+
return 0;
450+
}
451+
475452
static void debug_output_one(unsigned int cpu)
476453
{
477454
struct cpufreq_available_frequencies *freqs;
@@ -486,11 +463,11 @@ static void debug_output_one(unsigned int cpu)
486463
if (freqs) {
487464
printf(_(" available frequency steps: "));
488465
while (freqs->next) {
489-
print_speed(freqs->frequency);
466+
print_speed(freqs->frequency, no_rounding);
490467
printf(", ");
491468
freqs = freqs->next;
492469
}
493-
print_speed(freqs->frequency);
470+
print_speed(freqs->frequency, no_rounding);
494471
printf("\n");
495472
cpufreq_put_available_frequencies(freqs);
496473
}
@@ -500,6 +477,7 @@ static void debug_output_one(unsigned int cpu)
500477
if (get_freq_hardware(cpu, 1) < 0)
501478
get_freq_kernel(cpu, 1);
502479
get_boost_mode(cpu);
480+
get_perf_cap(cpu);
503481
}
504482

505483
static struct option info_opts[] = {
@@ -518,6 +496,7 @@ static struct option info_opts[] = {
518496
{"proc", no_argument, NULL, 'o'},
519497
{"human", no_argument, NULL, 'm'},
520498
{"no-rounding", no_argument, NULL, 'n'},
499+
{"performance", no_argument, NULL, 'c'},
521500
{ },
522501
};
523502

@@ -531,7 +510,7 @@ int cmd_freq_info(int argc, char **argv)
531510
int output_param = 0;
532511

533512
do {
534-
ret = getopt_long(argc, argv, "oefwldpgrasmybn", info_opts,
513+
ret = getopt_long(argc, argv, "oefwldpgrasmybnc", info_opts,
535514
NULL);
536515
switch (ret) {
537516
case '?':
@@ -554,6 +533,7 @@ int cmd_freq_info(int argc, char **argv)
554533
case 'e':
555534
case 's':
556535
case 'y':
536+
case 'c':
557537
if (output_param) {
558538
output_param = -1;
559539
cont = 0;
@@ -660,6 +640,9 @@ int cmd_freq_info(int argc, char **argv)
660640
case 'y':
661641
ret = get_latency(cpu, human);
662642
break;
643+
case 'c':
644+
ret = get_perf_cap(cpu);
645+
break;
663646
}
664647
if (ret)
665648
return ret;

0 commit comments

Comments
 (0)