Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/power/x86/intel-speed-select/isst-config.c
52064 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Intel Speed Select -- Enumerate and control features
4
* Copyright (c) 2019 Intel Corporation.
5
*/
6
7
#include <ctype.h>
8
#include <linux/isst_if.h>
9
10
#include "isst.h"
11
12
struct process_cmd_struct {
13
char *feature;
14
char *command;
15
void (*process_fn)(int arg);
16
int arg;
17
};
18
19
static const char *version_str = "v1.25";
20
21
static const int supported_api_ver = 3;
22
static struct isst_if_platform_info isst_platform_info;
23
static char *progname;
24
static int debug_flag;
25
static FILE *outf;
26
27
static int cpu_model;
28
static int cpu_stepping;
29
static int extended_family;
30
31
#define MAX_CPUS_IN_ONE_REQ 512
32
static short max_target_cpus;
33
static unsigned short target_cpus[MAX_CPUS_IN_ONE_REQ];
34
35
static int topo_max_cpus;
36
static size_t present_cpumask_size;
37
static cpu_set_t *present_cpumask;
38
static size_t target_cpumask_size;
39
static cpu_set_t *target_cpumask;
40
static int tdp_level = 0xFF;
41
static int fact_bucket = 0xFF;
42
static int fact_avx = 0xFF;
43
static unsigned long long fact_trl;
44
static int out_format_json;
45
static int cmd_help;
46
static int force_online_offline;
47
static int auto_mode;
48
static int fact_enable_fail;
49
static int cgroupv2;
50
static int max_pkg_id;
51
static int max_die_id;
52
static int max_die_id_package_0;
53
54
/* clos related */
55
static int current_clos = -1;
56
static int clos_epp = -1;
57
static int clos_prop_prio = -1;
58
static int clos_min = -1;
59
static int clos_max = -1;
60
static int clos_desired = -1;
61
static int clos_priority_type;
62
static int cpu_0_cgroupv2;
63
static int cpu_0_workaround(int isolate);
64
65
struct _cpu_map {
66
unsigned short core_id;
67
unsigned short pkg_id;
68
unsigned short die_id;
69
unsigned short punit_id;
70
unsigned short punit_cpu;
71
unsigned short punit_cpu_core;
72
unsigned short initialized;
73
};
74
struct _cpu_map *cpu_map;
75
76
struct cpu_topology {
77
short cpu;
78
short core_id;
79
short pkg_id;
80
short die_id;
81
};
82
83
static int read_only;
84
85
static void check_privilege(void)
86
{
87
if (!read_only)
88
return;
89
90
isst_display_error_info_message(1, "Insufficient privileges", 0, 0);
91
isst_ctdp_display_information_end(outf);
92
exit(1);
93
}
94
95
FILE *get_output_file(void)
96
{
97
return outf;
98
}
99
100
int is_debug_enabled(void)
101
{
102
return debug_flag;
103
}
104
105
void debug_printf(const char *format, ...)
106
{
107
va_list args;
108
109
va_start(args, format);
110
111
if (debug_flag)
112
vprintf(format, args);
113
114
va_end(args);
115
}
116
117
118
int is_clx_n_platform(void)
119
{
120
if (cpu_model == 0x55)
121
if (cpu_stepping == 0x6 || cpu_stepping == 0x7)
122
return 1;
123
return 0;
124
}
125
126
int is_skx_based_platform(void)
127
{
128
if (cpu_model == 0x55)
129
return 1;
130
131
return 0;
132
}
133
134
int is_spr_platform(void)
135
{
136
if (cpu_model == 0x8F)
137
return 1;
138
139
return 0;
140
}
141
142
int is_emr_platform(void)
143
{
144
if (cpu_model == 0xCF)
145
return 1;
146
147
return 0;
148
}
149
150
151
int is_icx_platform(void)
152
{
153
if (cpu_model == 0x6A || cpu_model == 0x6C)
154
return 1;
155
156
return 0;
157
}
158
159
static int is_dmr_plus_platform(void)
160
{
161
if (extended_family == 0x04)
162
return 1;
163
164
return 0;
165
}
166
167
static int update_cpu_model(void)
168
{
169
unsigned int ebx, ecx, edx;
170
unsigned int fms, family;
171
172
__cpuid(1, fms, ebx, ecx, edx);
173
family = (fms >> 8) & 0xf;
174
extended_family = (fms >> 20) & 0x0f;
175
cpu_model = (fms >> 4) & 0xf;
176
if (family == 6 || family == 0xf)
177
cpu_model += ((fms >> 16) & 0xf) << 4;
178
179
cpu_stepping = fms & 0xf;
180
/* only three CascadeLake-N models are supported */
181
if (is_clx_n_platform()) {
182
FILE *fp;
183
size_t n = 0;
184
char *line = NULL;
185
int ret = 1;
186
187
fp = fopen("/proc/cpuinfo", "r");
188
if (!fp)
189
err(-1, "cannot open /proc/cpuinfo\n");
190
191
while (getline(&line, &n, fp) > 0) {
192
if (strstr(line, "model name")) {
193
if (strstr(line, "6252N") ||
194
strstr(line, "6230N") ||
195
strstr(line, "5218N"))
196
ret = 0;
197
break;
198
}
199
}
200
free(line);
201
fclose(fp);
202
return ret;
203
}
204
return 0;
205
}
206
207
int api_version(void)
208
{
209
return isst_platform_info.api_version;
210
}
211
212
/* Open a file, and exit on failure */
213
static FILE *fopen_or_exit(const char *path, const char *mode)
214
{
215
FILE *filep = fopen(path, mode);
216
217
if (!filep)
218
err(1, "%s: open failed", path);
219
220
return filep;
221
}
222
223
/* Parse a file containing a single int */
224
static int parse_int_file(int fatal, const char *fmt, ...)
225
{
226
va_list args;
227
char path[PATH_MAX];
228
FILE *filep;
229
int value;
230
231
va_start(args, fmt);
232
vsnprintf(path, sizeof(path), fmt, args);
233
va_end(args);
234
if (fatal) {
235
filep = fopen_or_exit(path, "r");
236
} else {
237
filep = fopen(path, "r");
238
if (!filep)
239
return -1;
240
}
241
if (fscanf(filep, "%d", &value) != 1)
242
err(1, "%s: failed to parse number from file", path);
243
fclose(filep);
244
245
return value;
246
}
247
248
int cpufreq_sysfs_present(void)
249
{
250
DIR *dir;
251
252
dir = opendir("/sys/devices/system/cpu/cpu0/cpufreq");
253
if (dir) {
254
closedir(dir);
255
return 1;
256
}
257
258
return 0;
259
}
260
261
int out_format_is_json(void)
262
{
263
return out_format_json;
264
}
265
266
static int get_stored_topology_info(int cpu, int *core_id, int *pkg_id, int *die_id)
267
{
268
const char *pathname = "/var/run/isst_cpu_topology.dat";
269
struct cpu_topology cpu_top;
270
FILE *fp;
271
int ret;
272
273
fp = fopen(pathname, "rb");
274
if (!fp)
275
return -1;
276
277
ret = fseek(fp, cpu * sizeof(cpu_top), SEEK_SET);
278
if (ret)
279
goto err_ret;
280
281
ret = fread(&cpu_top, sizeof(cpu_top), 1, fp);
282
if (ret != 1) {
283
ret = -1;
284
goto err_ret;
285
}
286
287
*pkg_id = cpu_top.pkg_id;
288
*core_id = cpu_top.core_id;
289
*die_id = cpu_top.die_id;
290
ret = 0;
291
292
err_ret:
293
fclose(fp);
294
295
return ret;
296
}
297
298
static void store_cpu_topology(void)
299
{
300
const char *pathname = "/var/run/isst_cpu_topology.dat";
301
FILE *fp;
302
int i;
303
304
fp = fopen(pathname, "rb");
305
if (fp) {
306
/* Mapping already exists */
307
fclose(fp);
308
return;
309
}
310
311
fp = fopen(pathname, "wb");
312
if (!fp) {
313
fprintf(stderr, "Can't create file:%s\n", pathname);
314
return;
315
}
316
317
fprintf(stderr, "Caching topology information\n");
318
319
for (i = 0; i < topo_max_cpus; ++i) {
320
struct cpu_topology cpu_top;
321
322
cpu_top.core_id = parse_int_file(0,
323
"/sys/devices/system/cpu/cpu%d/topology/core_id", i);
324
if (cpu_top.core_id < 0)
325
cpu_top.core_id = -1;
326
327
cpu_top.pkg_id = parse_int_file(0,
328
"/sys/devices/system/cpu/cpu%d/topology/physical_package_id", i);
329
if (cpu_top.pkg_id < 0)
330
cpu_top.pkg_id = -1;
331
332
cpu_top.die_id = parse_int_file(0,
333
"/sys/devices/system/cpu/cpu%d/topology/die_id", i);
334
if (cpu_top.die_id < 0)
335
cpu_top.die_id = -1;
336
337
cpu_top.cpu = i;
338
339
if (fwrite(&cpu_top, sizeof(cpu_top), 1, fp) != 1) {
340
fprintf(stderr, "Can't write to:%s\n", pathname);
341
break;
342
}
343
}
344
345
fclose(fp);
346
}
347
348
static int get_physical_package_id(int cpu)
349
{
350
int ret;
351
352
if (cpu < 0)
353
return -1;
354
355
if (cpu_map && cpu_map[cpu].initialized)
356
return cpu_map[cpu].pkg_id;
357
358
ret = parse_int_file(0,
359
"/sys/devices/system/cpu/cpu%d/topology/physical_package_id",
360
cpu);
361
if (ret < 0) {
362
int core_id, pkg_id, die_id;
363
364
ret = get_stored_topology_info(cpu, &core_id, &pkg_id, &die_id);
365
if (!ret)
366
return pkg_id;
367
}
368
369
return ret;
370
}
371
372
static int get_physical_core_id(int cpu)
373
{
374
int ret;
375
376
if (cpu < 0)
377
return -1;
378
379
if (cpu_map && cpu_map[cpu].initialized)
380
return cpu_map[cpu].core_id;
381
382
ret = parse_int_file(0,
383
"/sys/devices/system/cpu/cpu%d/topology/core_id",
384
cpu);
385
if (ret < 0) {
386
int core_id, pkg_id, die_id;
387
388
ret = get_stored_topology_info(cpu, &core_id, &pkg_id, &die_id);
389
if (!ret)
390
return core_id;
391
}
392
393
return ret;
394
}
395
396
static int get_physical_die_id(int cpu)
397
{
398
int ret;
399
400
if (cpu < 0)
401
return -1;
402
403
if (cpu_map && cpu_map[cpu].initialized)
404
return cpu_map[cpu].die_id;
405
406
ret = parse_int_file(0,
407
"/sys/devices/system/cpu/cpu%d/topology/die_id",
408
cpu);
409
if (ret < 0) {
410
int core_id, pkg_id, die_id;
411
412
ret = get_stored_topology_info(cpu, &core_id, &pkg_id, &die_id);
413
if (!ret) {
414
if (die_id < 0)
415
die_id = 0;
416
417
return die_id;
418
}
419
}
420
421
if (ret < 0)
422
ret = 0;
423
424
return ret;
425
}
426
427
static int get_physical_punit_id(int cpu)
428
{
429
if (cpu < 0)
430
return -1;
431
432
if (cpu_map && cpu_map[cpu].initialized)
433
return cpu_map[cpu].punit_id;
434
435
return -1;
436
}
437
438
void set_isst_id(struct isst_id *id, int cpu)
439
{
440
id->cpu = cpu;
441
442
id->pkg = get_physical_package_id(cpu);
443
if (id->pkg >= MAX_PACKAGE_COUNT)
444
id->pkg = -1;
445
446
id->die = get_physical_die_id(cpu);
447
if (id->die >= MAX_DIE_PER_PACKAGE)
448
id->die = -1;
449
450
id->punit = get_physical_punit_id(cpu);
451
if (id->punit >= MAX_PUNIT_PER_DIE)
452
id->punit = -1;
453
}
454
455
int is_cpu_in_power_domain(int cpu, struct isst_id *id)
456
{
457
struct isst_id tid;
458
459
set_isst_id(&tid, cpu);
460
461
if (id->pkg == tid.pkg && id->die == tid.die && id->punit == tid.punit)
462
return 1;
463
464
return 0;
465
}
466
467
int get_cpufreq_base_freq(int cpu)
468
{
469
return parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/base_frequency", cpu);
470
}
471
472
int get_topo_max_cpus(void)
473
{
474
return topo_max_cpus;
475
}
476
477
static unsigned int is_cpu_online(int cpu)
478
{
479
char buffer[128];
480
int fd, ret;
481
unsigned char online;
482
483
snprintf(buffer, sizeof(buffer),
484
"/sys/devices/system/cpu/cpu%d/online", cpu);
485
486
fd = open(buffer, O_RDONLY);
487
if (fd < 0)
488
return fd;
489
490
ret = read(fd, &online, sizeof(online));
491
close(fd);
492
493
if (ret == -1)
494
return ret;
495
496
if (online == '1')
497
online = 1;
498
else
499
online = 0;
500
501
return online;
502
}
503
504
void set_cpu_online_offline(int cpu, int state)
505
{
506
char buffer[128];
507
int fd, ret;
508
509
if (cpu_0_cgroupv2 && !cpu) {
510
fprintf(stderr, "Will use cgroup v2 for CPU 0\n");
511
cpu_0_workaround(!state);
512
return;
513
}
514
515
snprintf(buffer, sizeof(buffer),
516
"/sys/devices/system/cpu/cpu%d/online", cpu);
517
518
fd = open(buffer, O_WRONLY);
519
if (fd < 0) {
520
if (!cpu) {
521
fprintf(stderr, "This system is not configured for CPU 0 online/offline\n");
522
fprintf(stderr, "Will use cgroup v2\n");
523
cpu_0_workaround(!state);
524
return;
525
}
526
err(-1, "%s open failed", buffer);
527
}
528
529
if (state)
530
ret = write(fd, "1\n", 2);
531
else
532
ret = write(fd, "0\n", 2);
533
534
if (ret == -1)
535
perror("Online/Offline: Operation failed\n");
536
537
close(fd);
538
}
539
540
static void force_all_cpus_online(void)
541
{
542
int i;
543
544
fprintf(stderr, "Forcing all CPUs online\n");
545
546
for (i = 0; i < topo_max_cpus; ++i)
547
set_cpu_online_offline(i, 1);
548
549
unlink("/var/run/isst_cpu_topology.dat");
550
}
551
552
void for_each_online_power_domain_in_set(void (*callback)(struct isst_id *, void *, void *,
553
void *, void *),
554
void *arg1, void *arg2, void *arg3,
555
void *arg4)
556
{
557
struct isst_id id;
558
int cpus[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE][MAX_PUNIT_PER_DIE];
559
int valid_mask[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE] = {0};
560
int i, j, k;
561
562
memset(cpus, -1, sizeof(cpus));
563
564
for (i = 0; i < topo_max_cpus; ++i) {
565
int online;
566
567
if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
568
continue;
569
570
online = parse_int_file(
571
i != 0, "/sys/devices/system/cpu/cpu%d/online", i);
572
if (online < 0)
573
online = 1; /* online entry for CPU 0 needs some special configs */
574
575
if (!online)
576
continue;
577
578
set_isst_id(&id, i);
579
580
if (id.pkg < 0 || id.die < 0 || id.punit < 0)
581
continue;
582
583
id.die = id.die % (max_die_id_package_0 + 1);
584
585
valid_mask[id.pkg][id.die] = 1;
586
587
if (cpus[id.pkg][id.die][id.punit] == -1)
588
cpus[id.pkg][id.die][id.punit] = i;
589
}
590
591
for (i = 0; i < MAX_PACKAGE_COUNT; i++) {
592
if (max_die_id > max_pkg_id) {
593
for (k = 0; k < MAX_PUNIT_PER_DIE && k < MAX_DIE_PER_PACKAGE; k++) {
594
id.cpu = cpus[i][k][k];
595
id.pkg = i;
596
id.die = get_physical_die_id(id.cpu);
597
id.punit = k;
598
if (isst_is_punit_valid(&id))
599
callback(&id, arg1, arg2, arg3, arg4);
600
}
601
continue;
602
}
603
604
for (j = 0; j < MAX_DIE_PER_PACKAGE; j++) {
605
/*
606
* Fix me:
607
* How to check a non-cpu die for a package/die with all cpu offlined?
608
*/
609
if (!valid_mask[i][j])
610
continue;
611
for (k = 0; k < MAX_PUNIT_PER_DIE; k++) {
612
id.cpu = cpus[i][j][k];
613
id.pkg = i;
614
if (id.cpu >= 0)
615
id.die = get_physical_die_id(id.cpu);
616
else
617
id.die = id.pkg;
618
id.punit = k;
619
if (isst_is_punit_valid(&id))
620
callback(&id, arg1, arg2, arg3, arg4);
621
}
622
}
623
}
624
}
625
626
static void for_each_online_target_cpu_in_set(
627
void (*callback)(struct isst_id *, void *, void *, void *, void *), void *arg1,
628
void *arg2, void *arg3, void *arg4)
629
{
630
int i, found = 0;
631
struct isst_id id;
632
633
for (i = 0; i < topo_max_cpus; ++i) {
634
int online;
635
636
if (!CPU_ISSET_S(i, target_cpumask_size, target_cpumask))
637
continue;
638
if (i)
639
online = parse_int_file(
640
1, "/sys/devices/system/cpu/cpu%d/online", i);
641
else
642
online =
643
1; /* online entry for CPU 0 needs some special configs */
644
645
set_isst_id(&id, i);
646
if (online && callback) {
647
callback(&id, arg1, arg2, arg3, arg4);
648
found = 1;
649
}
650
}
651
652
if (!found)
653
fprintf(stderr, "No valid CPU in the list\n");
654
}
655
656
#define BITMASK_SIZE 32
657
static void set_max_cpu_num(void)
658
{
659
FILE *filep;
660
unsigned long dummy;
661
int i;
662
663
topo_max_cpus = 0;
664
for (i = 0; i < 256; ++i) {
665
char path[256];
666
667
snprintf(path, sizeof(path),
668
"/sys/devices/system/cpu/cpu%d/topology/thread_siblings", i);
669
filep = fopen(path, "r");
670
if (filep)
671
break;
672
}
673
674
if (!filep) {
675
fprintf(stderr, "Can't get max cpu number\n");
676
exit(0);
677
}
678
679
while (fscanf(filep, "%lx,", &dummy) == 1)
680
topo_max_cpus += BITMASK_SIZE;
681
fclose(filep);
682
683
debug_printf("max cpus %d\n", topo_max_cpus);
684
}
685
686
size_t alloc_cpu_set(cpu_set_t **cpu_set)
687
{
688
cpu_set_t *_cpu_set;
689
size_t size;
690
691
_cpu_set = CPU_ALLOC((topo_max_cpus + 1));
692
if (_cpu_set == NULL)
693
err(3, "CPU_ALLOC");
694
size = CPU_ALLOC_SIZE((topo_max_cpus + 1));
695
CPU_ZERO_S(size, _cpu_set);
696
697
*cpu_set = _cpu_set;
698
return size;
699
}
700
701
void free_cpu_set(cpu_set_t *cpu_set)
702
{
703
CPU_FREE(cpu_set);
704
}
705
706
static int cpu_cnt[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE][MAX_PUNIT_PER_DIE];
707
708
int get_max_punit_core_id(struct isst_id *id)
709
{
710
int max_id = 0;
711
int i;
712
713
for (i = 0; i < topo_max_cpus; ++i)
714
{
715
if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
716
continue;
717
718
if (is_cpu_in_power_domain(i, id) &&
719
cpu_map[i].punit_cpu_core > max_id)
720
max_id = cpu_map[i].punit_cpu_core;
721
}
722
723
return max_id;
724
}
725
726
int get_cpu_count(struct isst_id *id)
727
{
728
if (id->pkg < 0 || id->die < 0 || id->punit < 0)
729
return 0;
730
731
return cpu_cnt[id->pkg][id->die][id->punit];
732
}
733
734
static void update_punit_cpu_info(__u32 physical_cpu, struct _cpu_map *cpu_map)
735
{
736
if (api_version() > 1) {
737
/*
738
* MSR 0x54 format
739
* [15:11] PM_DOMAIN_ID
740
* [10:3] MODULE_ID (aka IDI_AGENT_ID)
741
* [2:0] LP_ID (We don't care about these bits we only
742
* care die and core id
743
* For Atom:
744
* [2] Always 0
745
* [1:0] core ID within module
746
* For Core
747
* [2:1] Always 0
748
* [0] thread ID
749
*/
750
cpu_map->punit_id = (physical_cpu >> 11) & 0x1f;
751
cpu_map->punit_cpu_core = (physical_cpu >> 3) & 0xff;
752
cpu_map->punit_cpu = physical_cpu & 0x7ff;
753
} else {
754
int punit_id;
755
756
/*
757
* MSR 0x53 format
758
* Format
759
* Bit 0 – thread ID
760
* Bit 8:1 – core ID
761
* Bit 13:9 – punit ID
762
*/
763
cpu_map->punit_cpu = physical_cpu & 0x1ff;
764
cpu_map->punit_cpu_core = (cpu_map->punit_cpu >> 1); // shift to get core id
765
punit_id = (physical_cpu >> 9) & 0x1f;
766
767
if (punit_id >= MAX_PUNIT_PER_DIE)
768
punit_id = 0;
769
770
cpu_map->punit_id = punit_id;
771
}
772
}
773
774
static void create_cpu_map(void)
775
{
776
const char *pathname = "/dev/isst_interface";
777
size_t size;
778
DIR *dir;
779
int i, fd = 0;
780
struct isst_if_cpu_maps map;
781
782
/* Use calloc to make sure the memory is initialized to Zero */
783
cpu_map = calloc(topo_max_cpus, sizeof(*cpu_map));
784
if (!cpu_map)
785
err(3, "cpumap");
786
787
fd = open(pathname, O_RDWR);
788
if (fd < 0 && !is_clx_n_platform())
789
err(-1, "%s open failed", pathname);
790
791
size = alloc_cpu_set(&present_cpumask);
792
present_cpumask_size = size;
793
794
for (i = 0; i < topo_max_cpus; ++i) {
795
char buffer[256];
796
int pkg_id, die_id, core_id, punit_id;
797
798
/* check if CPU is online */
799
snprintf(buffer, sizeof(buffer),
800
"/sys/devices/system/cpu/cpu%d", i);
801
dir = opendir(buffer);
802
if (!dir)
803
continue;
804
closedir(dir);
805
806
CPU_SET_S(i, size, present_cpumask);
807
808
pkg_id = get_physical_package_id(i);
809
die_id = get_physical_die_id(i);
810
core_id = get_physical_core_id(i);
811
812
if (pkg_id < 0 || die_id < 0 || core_id < 0)
813
continue;
814
815
cpu_map[i].pkg_id = pkg_id;
816
cpu_map[i].die_id = die_id;
817
cpu_map[i].core_id = core_id;
818
819
if (max_pkg_id < pkg_id)
820
max_pkg_id = pkg_id;
821
822
punit_id = 0;
823
824
if (fd >= 0) {
825
map.cmd_count = 1;
826
map.cpu_map[0].logical_cpu = i;
827
debug_printf(" map logical_cpu:%d\n",
828
map.cpu_map[0].logical_cpu);
829
if (ioctl(fd, ISST_IF_GET_PHY_ID, &map) == -1) {
830
perror("ISST_IF_GET_PHY_ID");
831
fprintf(outf, "Error: map logical_cpu:%d\n",
832
map.cpu_map[0].logical_cpu);
833
} else {
834
update_punit_cpu_info(map.cpu_map[0].physical_cpu, &cpu_map[i]);
835
punit_id = cpu_map[i].punit_id;
836
}
837
}
838
cpu_map[i].initialized = 1;
839
840
cpu_cnt[pkg_id][die_id][punit_id]++;
841
842
if (max_die_id < die_id)
843
max_die_id = die_id;
844
845
if (!pkg_id && max_die_id_package_0 < die_id)
846
max_die_id_package_0 = die_id;
847
848
debug_printf(
849
"map logical_cpu:%d core: %d die:%d pkg:%d punit:%d punit_cpu:%d punit_core:%d\n",
850
i, cpu_map[i].core_id, cpu_map[i].die_id,
851
cpu_map[i].pkg_id, cpu_map[i].punit_id,
852
cpu_map[i].punit_cpu, cpu_map[i].punit_cpu_core);
853
}
854
if (fd >= 0)
855
close(fd);
856
857
size = alloc_cpu_set(&target_cpumask);
858
target_cpumask_size = size;
859
for (i = 0; i < max_target_cpus; ++i) {
860
if (!CPU_ISSET_S(target_cpus[i], present_cpumask_size,
861
present_cpumask))
862
continue;
863
864
CPU_SET_S(target_cpus[i], size, target_cpumask);
865
}
866
}
867
868
void set_cpu_mask_from_punit_coremask(struct isst_id *id, unsigned long long core_mask,
869
size_t core_cpumask_size,
870
cpu_set_t *core_cpumask, int *cpu_cnt)
871
{
872
int i, cnt = 0;
873
874
if (id->cpu < 0)
875
return;
876
877
*cpu_cnt = 0;
878
879
for (i = 0; i < 64; ++i) {
880
if (core_mask & BIT_ULL(i)) {
881
int j;
882
883
for (j = 0; j < topo_max_cpus; ++j) {
884
if (!CPU_ISSET_S(j, present_cpumask_size, present_cpumask))
885
continue;
886
887
if (is_cpu_in_power_domain(j, id) &&
888
cpu_map[j].punit_cpu_core == i) {
889
CPU_SET_S(j, core_cpumask_size,
890
core_cpumask);
891
++cnt;
892
}
893
}
894
}
895
}
896
897
*cpu_cnt = cnt;
898
}
899
900
int find_phy_core_num(int logical_cpu)
901
{
902
if (logical_cpu < topo_max_cpus)
903
return cpu_map[logical_cpu].punit_cpu_core;
904
905
return -EINVAL;
906
}
907
908
int use_cgroupv2(void)
909
{
910
return cgroupv2;
911
}
912
913
int enable_cpuset_controller(void)
914
{
915
int fd, ret;
916
917
fd = open("/sys/fs/cgroup/cgroup.subtree_control", O_RDWR, 0);
918
if (fd < 0) {
919
debug_printf("Can't activate cpuset controller\n");
920
debug_printf("Either you are not root user or CGroup v2 is not supported\n");
921
return fd;
922
}
923
924
ret = write(fd, " +cpuset", strlen(" +cpuset"));
925
close(fd);
926
927
if (ret == -1) {
928
debug_printf("Can't activate cpuset controller: Write failed\n");
929
return ret;
930
}
931
932
return 0;
933
}
934
935
int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int level, int cpu_0_only)
936
{
937
int i, first, curr_index, index, ret, fd;
938
static char str[512], dir_name[64];
939
static char cpuset_cpus[128];
940
int str_len = sizeof(str);
941
DIR *dir;
942
943
snprintf(dir_name, sizeof(dir_name), "/sys/fs/cgroup/%d-%d-%d", id->pkg, id->die, id->punit);
944
dir = opendir(dir_name);
945
if (!dir) {
946
ret = mkdir(dir_name, 0744);
947
if (ret) {
948
debug_printf("Can't create dir:%s errno:%d\n", dir_name, errno);
949
return ret;
950
}
951
}
952
closedir(dir);
953
954
if (!level) {
955
sprintf(cpuset_cpus, "%s/cpuset.cpus.partition", dir_name);
956
957
fd = open(cpuset_cpus, O_RDWR, 0);
958
if (fd < 0) {
959
return fd;
960
}
961
962
ret = write(fd, "member", strlen("member"));
963
if (ret == -1) {
964
printf("Can't update to member\n");
965
close(fd);
966
return ret;
967
}
968
969
close(fd);
970
return 0;
971
}
972
973
if (!CPU_COUNT_S(mask_size, cpu_mask)) {
974
return -1;
975
}
976
977
curr_index = 0;
978
first = 1;
979
str[0] = '\0';
980
981
if (cpu_0_only) {
982
snprintf(str, str_len, "0");
983
goto create_partition;
984
}
985
986
for (i = 0; i < get_topo_max_cpus(); ++i) {
987
if (!is_cpu_in_power_domain(i, id))
988
continue;
989
990
if (CPU_ISSET_S(i, mask_size, cpu_mask))
991
continue;
992
993
if (!first) {
994
index = snprintf(&str[curr_index],
995
str_len - curr_index, ",");
996
curr_index += index;
997
if (curr_index >= str_len)
998
break;
999
}
1000
index = snprintf(&str[curr_index], str_len - curr_index, "%d",
1001
i);
1002
curr_index += index;
1003
if (curr_index >= str_len)
1004
break;
1005
first = 0;
1006
}
1007
1008
create_partition:
1009
debug_printf("isolated CPUs list: package:%d curr_index:%d [%s]\n", id->pkg, curr_index ,str);
1010
1011
snprintf(cpuset_cpus, sizeof(cpuset_cpus), "%s/cpuset.cpus", dir_name);
1012
1013
fd = open(cpuset_cpus, O_RDWR, 0);
1014
if (fd < 0) {
1015
return fd;
1016
}
1017
1018
ret = write(fd, str, strlen(str));
1019
close(fd);
1020
1021
if (ret == -1) {
1022
debug_printf("Can't activate cpuset controller: Write failed\n");
1023
return ret;
1024
}
1025
1026
snprintf(cpuset_cpus, sizeof(cpuset_cpus), "%s/cpuset.cpus.partition", dir_name);
1027
1028
fd = open(cpuset_cpus, O_RDWR, 0);
1029
if (fd < 0) {
1030
return fd;
1031
}
1032
1033
ret = write(fd, "isolated", strlen("isolated"));
1034
if (ret == -1) {
1035
debug_printf("Can't update to isolated\n");
1036
ret = write(fd, "root", strlen("root"));
1037
if (ret == -1)
1038
debug_printf("Can't update to root\n");
1039
}
1040
1041
close(fd);
1042
1043
if (ret < 0)
1044
return ret;
1045
1046
return 0;
1047
}
1048
1049
static int cpu_0_workaround(int isolate)
1050
{
1051
int fd, fd1, len, ret;
1052
cpu_set_t cpu_mask;
1053
struct isst_id id;
1054
char str[2];
1055
1056
debug_printf("isolate CPU 0 state: %d\n", isolate);
1057
1058
if (isolate)
1059
goto isolate;
1060
1061
/* First check if CPU 0 was isolated to remove isolation. */
1062
1063
/* If the cpuset.cpus doesn't exist, that means that none of the CPUs are isolated*/
1064
fd = open("/sys/fs/cgroup/0-0-0/cpuset.cpus", O_RDONLY, 0);
1065
if (fd < 0)
1066
return 0;
1067
1068
len = read(fd, str, sizeof(str));
1069
/* Error check, but unlikely to fail. If fails that means that not isolated */
1070
if (len == -1)
1071
return 0;
1072
1073
1074
/* Is CPU 0 is in isolate list, the display is sorted so first element will be CPU 0*/
1075
if (str[0] != '0') {
1076
close(fd);
1077
return 0;
1078
}
1079
1080
fd1 = open("/sys/fs/cgroup/0-0-0/cpuset.cpus.partition", O_RDONLY, 0);
1081
/* Unlikely that, this attribute is not present, but handle error */
1082
if (fd1 < 0) {
1083
close(fd);
1084
return 0;
1085
}
1086
1087
/* Is CPU 0 already changed partition to "member" */
1088
len = read(fd1, str, sizeof(str));
1089
if (len != -1 && str[0] == 'm') {
1090
close(fd1);
1091
close(fd);
1092
return 0;
1093
}
1094
1095
close(fd1);
1096
close(fd);
1097
1098
debug_printf("CPU 0 was isolated before, so remove isolation\n");
1099
1100
isolate:
1101
ret = enable_cpuset_controller();
1102
if (ret)
1103
goto isolate_fail;
1104
1105
CPU_ZERO(&cpu_mask);
1106
memset(&id, 0, sizeof(struct isst_id));
1107
CPU_SET(0, &cpu_mask);
1108
1109
ret = isolate_cpus(&id, sizeof(cpu_mask), &cpu_mask, isolate, 1);
1110
isolate_fail:
1111
if (ret)
1112
fprintf(stderr, "Can't isolate CPU 0\n");
1113
1114
return ret;
1115
}
1116
1117
static int isst_fill_platform_info(void)
1118
{
1119
const char *pathname = "/dev/isst_interface";
1120
int fd;
1121
1122
if (is_clx_n_platform()) {
1123
isst_platform_info.api_version = 1;
1124
goto set_platform_ops;
1125
}
1126
1127
fd = open(pathname, O_RDWR);
1128
if (fd < 0)
1129
err(-1, "%s open failed", pathname);
1130
1131
if (ioctl(fd, ISST_IF_GET_PLATFORM_INFO, &isst_platform_info) == -1) {
1132
perror("ISST_IF_GET_PLATFORM_INFO");
1133
close(fd);
1134
return -1;
1135
}
1136
1137
close(fd);
1138
1139
if (isst_platform_info.api_version > supported_api_ver) {
1140
printf("Incompatible API versions; Upgrade of tool is required\n");
1141
return -1;
1142
}
1143
1144
set_platform_ops:
1145
if (isst_set_platform_ops(isst_platform_info.api_version)) {
1146
fprintf(stderr, "Failed to set platform callbacks\n");
1147
exit(0);
1148
}
1149
return 0;
1150
}
1151
1152
void get_isst_status(struct isst_id *id, void *arg1, void *arg2, void *arg3, void *arg4)
1153
{
1154
struct isst_pkg_ctdp pkg_dev;
1155
struct isst_id *tid = (struct isst_id *)arg2;
1156
int *mask = (int *)arg3;
1157
int *max_level = (int *)arg4;
1158
int j, ret;
1159
1160
/* Only check the first cpu power domain */
1161
if (id->cpu < 0 || tid->cpu >= 0)
1162
return;
1163
1164
ret = isst_get_ctdp_levels(id, &pkg_dev);
1165
if (ret)
1166
return;
1167
1168
if (pkg_dev.enabled)
1169
*mask |= BIT(0);
1170
1171
if (pkg_dev.locked)
1172
*mask |= BIT(1);
1173
1174
if (*max_level < pkg_dev.levels)
1175
*max_level = pkg_dev.levels;
1176
1177
for (j = 0; j <= pkg_dev.levels; ++j) {
1178
struct isst_pkg_ctdp_level_info ctdp_level;
1179
1180
ret = isst_get_ctdp_control(id, j, &ctdp_level);
1181
if (ret)
1182
continue;
1183
1184
if (ctdp_level.fact_support)
1185
*mask |= BIT(2);
1186
1187
if (ctdp_level.pbf_support)
1188
*mask |= BIT(3);
1189
}
1190
1191
tid->cpu = id->cpu;
1192
tid->pkg = id->pkg;
1193
tid->die = id->die;
1194
tid->punit = id->punit;
1195
}
1196
1197
static void isst_print_extended_platform_info(void)
1198
{
1199
int cp_state, cp_cap;
1200
struct isst_id id;
1201
int mask = 0, max_level = 0;
1202
1203
id.cpu = -1;
1204
for_each_online_power_domain_in_set(get_isst_status, NULL, &id, &mask, &max_level);
1205
1206
if (mask & BIT(0)) {
1207
fprintf(outf, "Intel(R) SST-PP (feature perf-profile) is supported\n");
1208
} else {
1209
fprintf(outf, "Intel(R) SST-PP (feature perf-profile) is not supported\n");
1210
fprintf(outf, "Only performance level 0 (base level) is present\n");
1211
}
1212
1213
if (mask & BIT(1))
1214
fprintf(outf, "TDP level change control is locked\n");
1215
else
1216
fprintf(outf, "TDP level change control is unlocked, max level: %d\n", max_level);
1217
1218
if (mask & BIT(2))
1219
fprintf(outf, "Intel(R) SST-TF (feature turbo-freq) is supported\n");
1220
else
1221
fprintf(outf, "Intel(R) SST-TF (feature turbo-freq) is not supported\n");
1222
1223
if (mask & BIT(3))
1224
fprintf(outf, "Intel(R) SST-BF (feature base-freq) is supported\n");
1225
else
1226
fprintf(outf, "Intel(R) SST-BF (feature base-freq) is not supported\n");
1227
1228
if (isst_read_pm_config(&id, &cp_state, &cp_cap)) {
1229
fprintf(outf, "Intel(R) SST-CP (feature core-power) status is unknown\n");
1230
return;
1231
}
1232
1233
if (cp_cap)
1234
fprintf(outf, "Intel(R) SST-CP (feature core-power) is supported\n");
1235
else
1236
fprintf(outf, "Intel(R) SST-CP (feature core-power) is not supported\n");
1237
}
1238
1239
static void isst_print_platform_information(void)
1240
{
1241
if (is_clx_n_platform()) {
1242
fprintf(stderr, "\nThis option in not supported on this platform\n");
1243
exit(0);
1244
}
1245
1246
/* Early initialization to create working cpu_map */
1247
set_max_cpu_num();
1248
create_cpu_map();
1249
1250
fprintf(outf, "Platform: API version : %d\n",
1251
isst_platform_info.api_version);
1252
fprintf(outf, "Platform: Driver version : %d\n",
1253
isst_platform_info.driver_version);
1254
fprintf(outf, "Platform: mbox supported : %d\n",
1255
isst_platform_info.mbox_supported);
1256
fprintf(outf, "Platform: mmio supported : %d\n",
1257
isst_platform_info.mmio_supported);
1258
isst_print_extended_platform_info();
1259
1260
exit(0);
1261
}
1262
1263
static char *local_str0, *local_str1;
1264
static void exec_on_get_ctdp_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
1265
void *arg4)
1266
{
1267
int (*fn_ptr)(struct isst_id *id, void *arg);
1268
int ret;
1269
1270
fn_ptr = arg1;
1271
ret = fn_ptr(id, arg2);
1272
if (ret)
1273
isst_display_error_info_message(1, "get_tdp_* failed", 0, 0);
1274
else
1275
isst_ctdp_display_core_info(id, outf, arg3,
1276
*(unsigned int *)arg4,
1277
local_str0, local_str1);
1278
}
1279
1280
#define _get_tdp_level(desc, suffix, object, help, str0, str1) \
1281
static void get_tdp_##object(int arg) \
1282
{ \
1283
struct isst_pkg_ctdp ctdp; \
1284
\
1285
if (cmd_help) { \
1286
fprintf(stderr, \
1287
"Print %s [No command arguments are required]\n", \
1288
help); \
1289
exit(0); \
1290
} \
1291
local_str0 = str0; \
1292
local_str1 = str1; \
1293
isst_ctdp_display_information_start(outf); \
1294
if (max_target_cpus) \
1295
for_each_online_target_cpu_in_set( \
1296
exec_on_get_ctdp_cpu, isst_get_ctdp_##suffix, \
1297
&ctdp, desc, &ctdp.object); \
1298
else \
1299
for_each_online_power_domain_in_set(exec_on_get_ctdp_cpu, \
1300
isst_get_ctdp_##suffix, \
1301
&ctdp, desc, \
1302
&ctdp.object); \
1303
isst_ctdp_display_information_end(outf); \
1304
}
1305
1306
_get_tdp_level("get-config-levels", levels, levels, "Max TDP level", NULL, NULL);
1307
_get_tdp_level("get-config-version", levels, version, "TDP version", NULL, NULL);
1308
_get_tdp_level("get-config-enabled", levels, enabled, "perf-profile enable status", "disabled", "enabled");
1309
_get_tdp_level("get-config-current_level", levels, current_level,
1310
"Current TDP Level", NULL, NULL);
1311
_get_tdp_level("get-lock-status", levels, locked, "TDP lock status", "unlocked", "locked");
1312
1313
struct isst_pkg_ctdp clx_n_pkg_dev;
1314
1315
static int clx_n_get_base_ratio(void)
1316
{
1317
FILE *fp;
1318
char *begin, *end, *line = NULL;
1319
char number[5];
1320
float value = 0;
1321
size_t n = 0;
1322
1323
fp = fopen("/proc/cpuinfo", "r");
1324
if (!fp)
1325
err(-1, "cannot open /proc/cpuinfo\n");
1326
1327
while (getline(&line, &n, fp) > 0) {
1328
if (strstr(line, "model name")) {
1329
/* this is true for CascadeLake-N */
1330
begin = strstr(line, "@ ") + 2;
1331
end = strstr(line, "GHz");
1332
strncpy(number, begin, end - begin);
1333
value = atof(number) * 10;
1334
break;
1335
}
1336
}
1337
free(line);
1338
fclose(fp);
1339
1340
return (int)(value);
1341
}
1342
1343
static int clx_n_config(struct isst_id *id)
1344
{
1345
int i, ret;
1346
unsigned long cpu_bf;
1347
struct isst_pkg_ctdp_level_info *ctdp_level;
1348
struct isst_pbf_info *pbf_info;
1349
1350
ctdp_level = &clx_n_pkg_dev.ctdp_level[0];
1351
pbf_info = &ctdp_level->pbf_info;
1352
ctdp_level->core_cpumask_size =
1353
alloc_cpu_set(&ctdp_level->core_cpumask);
1354
1355
/* find the frequency base ratio */
1356
ctdp_level->tdp_ratio = clx_n_get_base_ratio();
1357
if (ctdp_level->tdp_ratio == 0) {
1358
debug_printf("CLX: cn base ratio is zero\n");
1359
ret = -1;
1360
goto error_ret;
1361
}
1362
1363
/* find the high and low priority frequencies */
1364
pbf_info->p1_high = 0;
1365
pbf_info->p1_low = ~0;
1366
1367
for (i = 0; i < topo_max_cpus; i++) {
1368
if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
1369
continue;
1370
1371
if (!is_cpu_in_power_domain(i, id))
1372
continue;
1373
1374
CPU_SET_S(i, ctdp_level->core_cpumask_size,
1375
ctdp_level->core_cpumask);
1376
1377
cpu_bf = parse_int_file(1,
1378
"/sys/devices/system/cpu/cpu%d/cpufreq/base_frequency",
1379
i);
1380
if (cpu_bf > pbf_info->p1_high)
1381
pbf_info->p1_high = cpu_bf;
1382
if (cpu_bf < pbf_info->p1_low)
1383
pbf_info->p1_low = cpu_bf;
1384
}
1385
1386
if (pbf_info->p1_high == ~0UL) {
1387
debug_printf("CLX: maximum base frequency not set\n");
1388
ret = -1;
1389
goto error_ret;
1390
}
1391
1392
if (pbf_info->p1_low == 0) {
1393
debug_printf("CLX: minimum base frequency not set\n");
1394
ret = -1;
1395
goto error_ret;
1396
}
1397
1398
/* convert frequencies back to ratios */
1399
pbf_info->p1_high = pbf_info->p1_high / 100000;
1400
pbf_info->p1_low = pbf_info->p1_low / 100000;
1401
1402
/* create high priority cpu mask */
1403
pbf_info->core_cpumask_size = alloc_cpu_set(&pbf_info->core_cpumask);
1404
for (i = 0; i < topo_max_cpus; i++) {
1405
if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
1406
continue;
1407
1408
if (!is_cpu_in_power_domain(i, id))
1409
continue;
1410
1411
cpu_bf = parse_int_file(1,
1412
"/sys/devices/system/cpu/cpu%d/cpufreq/base_frequency",
1413
i);
1414
cpu_bf = cpu_bf / 100000;
1415
if (cpu_bf == pbf_info->p1_high)
1416
CPU_SET_S(i, pbf_info->core_cpumask_size,
1417
pbf_info->core_cpumask);
1418
}
1419
1420
/* extra ctdp & pbf struct parameters */
1421
ctdp_level->processed = 1;
1422
ctdp_level->pbf_support = 1; /* PBF is always supported and enabled */
1423
ctdp_level->pbf_enabled = 1;
1424
ctdp_level->fact_support = 0; /* FACT is never supported */
1425
ctdp_level->fact_enabled = 0;
1426
1427
return 0;
1428
1429
error_ret:
1430
free_cpu_set(ctdp_level->core_cpumask);
1431
return ret;
1432
}
1433
1434
static void dump_clx_n_config_for_cpu(struct isst_id *id, void *arg1, void *arg2,
1435
void *arg3, void *arg4)
1436
{
1437
int ret;
1438
1439
if (tdp_level != 0xff && tdp_level != 0) {
1440
isst_display_error_info_message(1, "Invalid level", 1, tdp_level);
1441
exit(0);
1442
}
1443
1444
ret = clx_n_config(id);
1445
if (ret) {
1446
debug_printf("clx_n_config failed");
1447
} else {
1448
struct isst_pkg_ctdp_level_info *ctdp_level;
1449
struct isst_pbf_info *pbf_info;
1450
1451
ctdp_level = &clx_n_pkg_dev.ctdp_level[0];
1452
pbf_info = &ctdp_level->pbf_info;
1453
clx_n_pkg_dev.processed = 1;
1454
isst_ctdp_display_information(id, outf, tdp_level, &clx_n_pkg_dev);
1455
free_cpu_set(ctdp_level->core_cpumask);
1456
free_cpu_set(pbf_info->core_cpumask);
1457
}
1458
}
1459
1460
static void dump_isst_config_for_cpu(struct isst_id *id, void *arg1, void *arg2,
1461
void *arg3, void *arg4)
1462
{
1463
struct isst_pkg_ctdp pkg_dev;
1464
int ret;
1465
1466
memset(&pkg_dev, 0, sizeof(pkg_dev));
1467
ret = isst_get_process_ctdp(id, tdp_level, &pkg_dev);
1468
if (ret) {
1469
isst_display_error_info_message(1, "Failed to get perf-profile info on cpu", 1, id->cpu);
1470
isst_ctdp_display_information_end(outf);
1471
exit(1);
1472
} else {
1473
isst_ctdp_display_information(id, outf, tdp_level, &pkg_dev);
1474
isst_get_process_ctdp_complete(id, &pkg_dev);
1475
}
1476
}
1477
1478
static void dump_isst_config(int arg)
1479
{
1480
void *fn;
1481
1482
if (cmd_help) {
1483
fprintf(stderr,
1484
"Print Intel(R) Speed Select Technology Performance profile configuration\n");
1485
fprintf(stderr,
1486
"including base frequency and turbo frequency configurations\n");
1487
fprintf(stderr, "Optional: -l|--level : Specify tdp level\n");
1488
fprintf(stderr,
1489
"\tIf no arguments, dump information for all TDP levels\n");
1490
exit(0);
1491
}
1492
1493
if (!is_clx_n_platform())
1494
fn = dump_isst_config_for_cpu;
1495
else
1496
fn = dump_clx_n_config_for_cpu;
1497
1498
isst_ctdp_display_information_start(outf);
1499
1500
if (max_target_cpus)
1501
for_each_online_target_cpu_in_set(fn, NULL, NULL, NULL, NULL);
1502
else
1503
for_each_online_power_domain_in_set(fn, NULL, NULL, NULL, NULL);
1504
1505
isst_ctdp_display_information_end(outf);
1506
}
1507
1508
static void adjust_scaling_max_from_base_freq(int cpu);
1509
1510
static void set_tdp_level_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
1511
void *arg4)
1512
{
1513
struct isst_pkg_ctdp pkg_dev;
1514
int ret;
1515
1516
ret = isst_get_ctdp_levels(id, &pkg_dev);
1517
if (ret) {
1518
isst_display_error_info_message(1, "Get TDP level failed", 0, 0);
1519
isst_ctdp_display_information_end(outf);
1520
exit(1);
1521
}
1522
1523
if (pkg_dev.current_level == tdp_level) {
1524
debug_printf("TDP level already set. Skipped\n");
1525
goto display_result;
1526
}
1527
1528
ret = isst_set_tdp_level(id, tdp_level);
1529
if (ret) {
1530
isst_display_error_info_message(1, "Set TDP level failed", 0, 0);
1531
isst_ctdp_display_information_end(outf);
1532
exit(1);
1533
}
1534
1535
display_result:
1536
isst_display_result(id, outf, "perf-profile", "set_tdp_level", ret);
1537
if (force_online_offline && id->cpu >= 0) {
1538
struct isst_pkg_ctdp_level_info ctdp_level;
1539
1540
/* Wait for updated base frequencies */
1541
usleep(2000);
1542
1543
/* Adjusting uncore freq */
1544
if (!is_dmr_plus_platform())
1545
isst_adjust_uncore_freq(id, tdp_level, &ctdp_level);
1546
1547
fprintf(stderr, "Option is set to online/offline\n");
1548
ctdp_level.core_cpumask_size =
1549
alloc_cpu_set(&ctdp_level.core_cpumask);
1550
ret = isst_get_coremask_info(id, tdp_level, &ctdp_level);
1551
if (ret) {
1552
isst_display_error_info_message(1, "Can't get coremask, online/offline option is ignored", 0, 0);
1553
goto free_mask;
1554
}
1555
1556
if (use_cgroupv2()) {
1557
int ret;
1558
1559
fprintf(stderr, "Using cgroup v2 in lieu of online/offline\n");
1560
ret = enable_cpuset_controller();
1561
if (ret)
1562
goto use_offline;
1563
1564
ret = isolate_cpus(id, ctdp_level.core_cpumask_size,
1565
ctdp_level.core_cpumask, tdp_level, 0);
1566
if (ret)
1567
goto use_offline;
1568
1569
goto free_mask;
1570
}
1571
1572
use_offline:
1573
if (ctdp_level.cpu_count) {
1574
int i, max_cpus = get_topo_max_cpus();
1575
for (i = 0; i < max_cpus; ++i) {
1576
if (!is_cpu_in_power_domain(i, id))
1577
continue;
1578
if (CPU_ISSET_S(i, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask)) {
1579
fprintf(stderr, "online cpu %d\n", i);
1580
set_cpu_online_offline(i, 1);
1581
adjust_scaling_max_from_base_freq(i);
1582
} else {
1583
fprintf(stderr, "offline cpu %d\n", i);
1584
set_cpu_online_offline(i, 0);
1585
}
1586
}
1587
}
1588
free_mask:
1589
free_cpu_set(ctdp_level.core_cpumask);
1590
}
1591
}
1592
1593
static void set_tdp_level(int arg)
1594
{
1595
check_privilege();
1596
1597
if (cmd_help) {
1598
fprintf(stderr, "Set Config TDP level\n");
1599
fprintf(stderr,
1600
"\t Arguments: -l|--level : Specify tdp level\n");
1601
fprintf(stderr,
1602
"\t Optional Arguments: -o | online : online/offline for the tdp level\n");
1603
fprintf(stderr,
1604
"\t online/offline operation has limitations, refer to Linux hotplug documentation\n");
1605
exit(0);
1606
}
1607
1608
if (tdp_level == 0xff) {
1609
isst_display_error_info_message(1, "Invalid command: specify tdp_level", 0, 0);
1610
exit(1);
1611
}
1612
isst_ctdp_display_information_start(outf);
1613
if (max_target_cpus)
1614
for_each_online_target_cpu_in_set(set_tdp_level_for_cpu, NULL,
1615
NULL, NULL, NULL);
1616
else
1617
for_each_online_power_domain_in_set(set_tdp_level_for_cpu, NULL,
1618
NULL, NULL, NULL);
1619
isst_ctdp_display_information_end(outf);
1620
}
1621
1622
static void clx_n_dump_pbf_config_for_cpu(struct isst_id *id, void *arg1, void *arg2,
1623
void *arg3, void *arg4)
1624
{
1625
int ret;
1626
1627
ret = clx_n_config(id);
1628
if (ret) {
1629
isst_display_error_info_message(1, "clx_n_config failed", 0, 0);
1630
} else {
1631
struct isst_pkg_ctdp_level_info *ctdp_level;
1632
struct isst_pbf_info *pbf_info;
1633
1634
ctdp_level = &clx_n_pkg_dev.ctdp_level[0];
1635
pbf_info = &ctdp_level->pbf_info;
1636
isst_pbf_display_information(id, outf, tdp_level, pbf_info);
1637
free_cpu_set(ctdp_level->core_cpumask);
1638
free_cpu_set(pbf_info->core_cpumask);
1639
}
1640
}
1641
1642
static void dump_pbf_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
1643
void *arg4)
1644
{
1645
struct isst_pbf_info pbf_info;
1646
int ret;
1647
1648
ret = isst_get_pbf_info(id, tdp_level, &pbf_info);
1649
if (ret) {
1650
isst_display_error_info_message(1, "Failed to get base-freq info at this level", 1, tdp_level);
1651
isst_ctdp_display_information_end(outf);
1652
exit(1);
1653
} else {
1654
isst_pbf_display_information(id, outf, tdp_level, &pbf_info);
1655
free_cpu_set(pbf_info.core_cpumask);
1656
}
1657
}
1658
1659
static void dump_pbf_config(int arg)
1660
{
1661
void *fn;
1662
1663
if (cmd_help) {
1664
fprintf(stderr,
1665
"Print Intel(R) Speed Select Technology base frequency configuration for a TDP level\n");
1666
fprintf(stderr,
1667
"\tArguments: -l|--level : Specify tdp level\n");
1668
exit(0);
1669
}
1670
1671
if (tdp_level == 0xff) {
1672
isst_display_error_info_message(1, "Invalid command: specify tdp_level", 0, 0);
1673
exit(1);
1674
}
1675
1676
if (!is_clx_n_platform())
1677
fn = dump_pbf_config_for_cpu;
1678
else
1679
fn = clx_n_dump_pbf_config_for_cpu;
1680
1681
isst_ctdp_display_information_start(outf);
1682
1683
if (max_target_cpus)
1684
for_each_online_target_cpu_in_set(fn, NULL, NULL, NULL, NULL);
1685
else
1686
for_each_online_power_domain_in_set(fn, NULL, NULL, NULL, NULL);
1687
1688
isst_ctdp_display_information_end(outf);
1689
}
1690
1691
static int set_clos_param(struct isst_id *id, int clos, int epp, int wt, int min, int max)
1692
{
1693
struct isst_clos_config clos_config;
1694
int ret;
1695
1696
ret = isst_pm_get_clos(id, clos, &clos_config);
1697
if (ret) {
1698
isst_display_error_info_message(1, "isst_pm_get_clos failed", 0, 0);
1699
return ret;
1700
}
1701
clos_config.clos_min = min;
1702
clos_config.clos_max = max;
1703
clos_config.epp = epp;
1704
clos_config.clos_prop_prio = wt;
1705
ret = isst_set_clos(id, clos, &clos_config);
1706
if (ret) {
1707
isst_display_error_info_message(1, "isst_set_clos failed", 0, 0);
1708
return ret;
1709
}
1710
1711
return 0;
1712
}
1713
1714
static int set_cpufreq_scaling_min_max(int cpu, int max, int freq)
1715
{
1716
char buffer[128], freq_str[16];
1717
int fd, ret, len;
1718
1719
if (max)
1720
snprintf(buffer, sizeof(buffer),
1721
"/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
1722
else
1723
snprintf(buffer, sizeof(buffer),
1724
"/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu);
1725
1726
fd = open(buffer, O_WRONLY);
1727
if (fd < 0)
1728
return fd;
1729
1730
snprintf(freq_str, sizeof(freq_str), "%d", freq);
1731
len = strlen(freq_str);
1732
ret = write(fd, freq_str, len);
1733
if (ret == -1) {
1734
close(fd);
1735
return ret;
1736
}
1737
close(fd);
1738
1739
return 0;
1740
}
1741
1742
static int no_turbo(void)
1743
{
1744
return parse_int_file(0, "/sys/devices/system/cpu/intel_pstate/no_turbo");
1745
}
1746
1747
static void adjust_scaling_max_from_base_freq(int cpu)
1748
{
1749
int base_freq, scaling_max_freq;
1750
1751
scaling_max_freq = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
1752
base_freq = get_cpufreq_base_freq(cpu);
1753
if (scaling_max_freq < base_freq || no_turbo())
1754
set_cpufreq_scaling_min_max(cpu, 1, base_freq);
1755
}
1756
1757
static void adjust_scaling_min_from_base_freq(int cpu)
1758
{
1759
int base_freq, scaling_min_freq;
1760
1761
scaling_min_freq = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu);
1762
base_freq = get_cpufreq_base_freq(cpu);
1763
if (scaling_min_freq < base_freq)
1764
set_cpufreq_scaling_min_max(cpu, 0, base_freq);
1765
}
1766
1767
static int set_clx_pbf_cpufreq_scaling_min_max(struct isst_id *id)
1768
{
1769
struct isst_pkg_ctdp_level_info *ctdp_level;
1770
struct isst_pbf_info *pbf_info;
1771
int i, freq, freq_high, freq_low;
1772
int ret;
1773
1774
ret = clx_n_config(id);
1775
if (ret) {
1776
debug_printf("cpufreq_scaling_min_max failed for CLX");
1777
return ret;
1778
}
1779
1780
ctdp_level = &clx_n_pkg_dev.ctdp_level[0];
1781
pbf_info = &ctdp_level->pbf_info;
1782
freq_high = pbf_info->p1_high * 100000;
1783
freq_low = pbf_info->p1_low * 100000;
1784
1785
for (i = 0; i < get_topo_max_cpus(); ++i) {
1786
if (!is_cpu_in_power_domain(i, id))
1787
continue;
1788
1789
if (CPU_ISSET_S(i, pbf_info->core_cpumask_size,
1790
pbf_info->core_cpumask))
1791
freq = freq_high;
1792
else
1793
freq = freq_low;
1794
1795
set_cpufreq_scaling_min_max(i, 1, freq);
1796
set_cpufreq_scaling_min_max(i, 0, freq);
1797
}
1798
1799
return 0;
1800
}
1801
1802
static int set_cpufreq_scaling_min_max_from_cpuinfo(int cpu, int cpuinfo_max, int scaling_max)
1803
{
1804
char buffer[128], min_freq[16];
1805
int fd, ret, len;
1806
1807
if (!CPU_ISSET_S(cpu, present_cpumask_size, present_cpumask))
1808
return -1;
1809
1810
if (cpuinfo_max)
1811
snprintf(buffer, sizeof(buffer),
1812
"/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", cpu);
1813
else
1814
snprintf(buffer, sizeof(buffer),
1815
"/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_min_freq", cpu);
1816
1817
fd = open(buffer, O_RDONLY);
1818
if (fd < 0)
1819
return fd;
1820
1821
len = read(fd, min_freq, sizeof(min_freq));
1822
close(fd);
1823
1824
if (len < 0)
1825
return len;
1826
1827
if (scaling_max)
1828
snprintf(buffer, sizeof(buffer),
1829
"/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
1830
else
1831
snprintf(buffer, sizeof(buffer),
1832
"/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu);
1833
1834
fd = open(buffer, O_WRONLY);
1835
if (fd < 0)
1836
return fd;
1837
1838
min_freq[15] = '\0';
1839
len = strlen(min_freq);
1840
ret = write(fd, min_freq, len);
1841
if (ret == -1) {
1842
close(fd);
1843
return ret;
1844
}
1845
close(fd);
1846
1847
return 0;
1848
}
1849
1850
static void set_scaling_min_to_cpuinfo_max(struct isst_id *id)
1851
{
1852
int i;
1853
1854
if (id->cpu < 0)
1855
return;
1856
1857
for (i = 0; i < get_topo_max_cpus(); ++i) {
1858
if (!is_cpu_in_power_domain(i, id))
1859
continue;
1860
1861
if (is_cpu_online(i) != 1)
1862
continue;
1863
1864
adjust_scaling_max_from_base_freq(i);
1865
set_cpufreq_scaling_min_max_from_cpuinfo(i, 1, 0);
1866
adjust_scaling_min_from_base_freq(i);
1867
}
1868
}
1869
1870
static void set_scaling_min_to_cpuinfo_min(struct isst_id *id)
1871
{
1872
int i;
1873
1874
if (id->cpu < 0)
1875
return;
1876
1877
for (i = 0; i < get_topo_max_cpus(); ++i) {
1878
if (!is_cpu_in_power_domain(i, id))
1879
continue;
1880
1881
if (is_cpu_online(i) != 1)
1882
continue;
1883
1884
adjust_scaling_max_from_base_freq(i);
1885
set_cpufreq_scaling_min_max_from_cpuinfo(i, 0, 0);
1886
}
1887
}
1888
1889
static void set_scaling_max_to_cpuinfo_max(struct isst_id *id)
1890
{
1891
int i;
1892
1893
for (i = 0; i < get_topo_max_cpus(); ++i) {
1894
if (!is_cpu_in_power_domain(i, id))
1895
continue;
1896
1897
set_cpufreq_scaling_min_max_from_cpuinfo(i, 1, 1);
1898
}
1899
}
1900
1901
static int set_core_priority_and_min(struct isst_id *id, int mask_size,
1902
cpu_set_t *cpu_mask, int min_high,
1903
int min_low)
1904
{
1905
int ret, i;
1906
1907
if (!CPU_COUNT_S(mask_size, cpu_mask))
1908
return -1;
1909
1910
ret = set_clos_param(id, 0, 0, 0, min_high, 0xff);
1911
if (ret)
1912
return ret;
1913
1914
ret = set_clos_param(id, 1, 15, 15, min_low, 0xff);
1915
if (ret)
1916
return ret;
1917
1918
ret = set_clos_param(id, 2, 15, 15, min_low, 0xff);
1919
if (ret)
1920
return ret;
1921
1922
ret = set_clos_param(id, 3, 15, 15, min_low, 0xff);
1923
if (ret)
1924
return ret;
1925
1926
for (i = 0; i < get_topo_max_cpus(); ++i) {
1927
int clos;
1928
struct isst_id tid;
1929
1930
if (!is_cpu_in_power_domain(i, id))
1931
continue;
1932
1933
if (CPU_ISSET_S(i, mask_size, cpu_mask))
1934
clos = 0;
1935
else
1936
clos = 3;
1937
1938
debug_printf("Associate cpu: %d clos: %d\n", i, clos);
1939
set_isst_id(&tid, i);
1940
ret = isst_clos_associate(&tid, clos);
1941
if (ret) {
1942
isst_display_error_info_message(1, "isst_clos_associate failed", 0, 0);
1943
return ret;
1944
}
1945
}
1946
1947
return 0;
1948
}
1949
1950
static int set_pbf_core_power(struct isst_id *id)
1951
{
1952
struct isst_pbf_info pbf_info;
1953
struct isst_pkg_ctdp pkg_dev;
1954
int ret;
1955
1956
if (id->cpu < 0)
1957
return 0;
1958
1959
ret = isst_get_ctdp_levels(id, &pkg_dev);
1960
if (ret) {
1961
debug_printf("isst_get_ctdp_levels failed");
1962
return ret;
1963
}
1964
debug_printf("Current_level: %d\n", pkg_dev.current_level);
1965
1966
ret = isst_get_pbf_info(id, pkg_dev.current_level, &pbf_info);
1967
if (ret) {
1968
debug_printf("isst_get_pbf_info failed");
1969
return ret;
1970
}
1971
debug_printf("p1_high: %d p1_low: %d\n", pbf_info.p1_high,
1972
pbf_info.p1_low);
1973
1974
ret = set_core_priority_and_min(id, pbf_info.core_cpumask_size,
1975
pbf_info.core_cpumask,
1976
pbf_info.p1_high, pbf_info.p1_low);
1977
if (ret) {
1978
debug_printf("set_core_priority_and_min failed");
1979
return ret;
1980
}
1981
1982
ret = isst_pm_qos_config(id, 1, 1);
1983
if (ret) {
1984
debug_printf("isst_pm_qos_config failed");
1985
return ret;
1986
}
1987
1988
return 0;
1989
}
1990
1991
static void set_pbf_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
1992
void *arg4)
1993
{
1994
struct isst_pkg_ctdp_level_info ctdp_level;
1995
struct isst_pkg_ctdp pkg_dev;
1996
int ret;
1997
int status = *(int *)arg4;
1998
1999
if (is_clx_n_platform()) {
2000
ret = 0;
2001
if (status) {
2002
set_clx_pbf_cpufreq_scaling_min_max(id);
2003
2004
} else {
2005
set_scaling_max_to_cpuinfo_max(id);
2006
set_scaling_min_to_cpuinfo_min(id);
2007
}
2008
goto disp_result;
2009
}
2010
2011
ret = isst_get_ctdp_levels(id, &pkg_dev);
2012
if (ret) {
2013
isst_display_error_info_message(1, "Failed to get number of levels", 0, 0);
2014
goto disp_result;
2015
}
2016
2017
ret = isst_get_ctdp_control(id, pkg_dev.current_level, &ctdp_level);
2018
if (ret) {
2019
isst_display_error_info_message(1, "Failed to get current level", 0, 0);
2020
goto disp_result;
2021
}
2022
2023
if (!ctdp_level.pbf_support) {
2024
isst_display_error_info_message(1, "base-freq feature is not present at this level", 1, pkg_dev.current_level);
2025
ret = -1;
2026
goto disp_result;
2027
}
2028
2029
if (auto_mode && status) {
2030
ret = set_pbf_core_power(id);
2031
if (ret)
2032
goto disp_result;
2033
}
2034
2035
ret = isst_set_pbf_fact_status(id, 1, status);
2036
if (ret) {
2037
debug_printf("isst_set_pbf_fact_status failed");
2038
if (auto_mode)
2039
isst_pm_qos_config(id, 0, 0);
2040
} else {
2041
if (auto_mode) {
2042
if (status)
2043
set_scaling_min_to_cpuinfo_max(id);
2044
else
2045
set_scaling_min_to_cpuinfo_min(id);
2046
}
2047
}
2048
2049
if (auto_mode && !status)
2050
isst_pm_qos_config(id, 0, 1);
2051
2052
disp_result:
2053
if (status)
2054
isst_display_result(id, outf, "base-freq", "enable",
2055
ret);
2056
else
2057
isst_display_result(id, outf, "base-freq", "disable",
2058
ret);
2059
}
2060
2061
static void set_pbf_enable(int arg)
2062
{
2063
int enable = arg;
2064
2065
check_privilege();
2066
2067
if (cmd_help) {
2068
if (enable) {
2069
fprintf(stderr,
2070
"Enable Intel Speed Select Technology base frequency feature\n");
2071
if (is_clx_n_platform()) {
2072
fprintf(stderr,
2073
"\tOn this platform this command doesn't enable feature in the hardware.\n");
2074
fprintf(stderr,
2075
"\tIt updates the cpufreq scaling_min_freq to match cpufreq base_frequency.\n");
2076
exit(0);
2077
2078
}
2079
fprintf(stderr,
2080
"\tOptional Arguments: -a|--auto : Use priority of cores to set core-power associations\n");
2081
} else {
2082
2083
if (is_clx_n_platform()) {
2084
fprintf(stderr,
2085
"\tOn this platform this command doesn't disable feature in the hardware.\n");
2086
fprintf(stderr,
2087
"\tIt updates the cpufreq scaling_min_freq to match cpuinfo_min_freq\n");
2088
exit(0);
2089
}
2090
fprintf(stderr,
2091
"Disable Intel Speed Select Technology base frequency feature\n");
2092
fprintf(stderr,
2093
"\tOptional Arguments: -a|--auto : Also disable core-power associations\n");
2094
}
2095
exit(0);
2096
}
2097
2098
isst_ctdp_display_information_start(outf);
2099
if (max_target_cpus)
2100
for_each_online_target_cpu_in_set(set_pbf_for_cpu, NULL, NULL,
2101
NULL, &enable);
2102
else
2103
for_each_online_power_domain_in_set(set_pbf_for_cpu, NULL, NULL,
2104
NULL, &enable);
2105
isst_ctdp_display_information_end(outf);
2106
}
2107
2108
static void dump_fact_config_for_cpu(struct isst_id *id, void *arg1, void *arg2,
2109
void *arg3, void *arg4)
2110
{
2111
struct isst_fact_info fact_info;
2112
int ret;
2113
2114
memset(&fact_info, 0, sizeof(fact_info));
2115
ret = isst_get_fact_info(id, tdp_level, fact_bucket, &fact_info);
2116
if (ret) {
2117
isst_display_error_info_message(1, "Failed to get turbo-freq info at this level", 1, tdp_level);
2118
isst_ctdp_display_information_end(outf);
2119
exit(1);
2120
} else {
2121
isst_fact_display_information(id, outf, tdp_level, fact_bucket,
2122
fact_avx, &fact_info);
2123
}
2124
}
2125
2126
static void dump_fact_config(int arg)
2127
{
2128
if (cmd_help) {
2129
fprintf(stderr,
2130
"Print complete Intel Speed Select Technology turbo frequency configuration for a TDP level. Other arguments are optional.\n");
2131
fprintf(stderr,
2132
"\tArguments: -l|--level : Specify tdp level\n");
2133
fprintf(stderr,
2134
"\tArguments: -b|--bucket : Bucket index to dump\n");
2135
fprintf(stderr,
2136
"\tArguments: -r|--trl-type : Specify trl type: sse|avx2|avx512\n");
2137
exit(0);
2138
}
2139
2140
if (tdp_level == 0xff) {
2141
isst_display_error_info_message(1, "Invalid command: specify tdp_level\n", 0, 0);
2142
exit(1);
2143
}
2144
2145
isst_ctdp_display_information_start(outf);
2146
if (max_target_cpus)
2147
for_each_online_target_cpu_in_set(dump_fact_config_for_cpu,
2148
NULL, NULL, NULL, NULL);
2149
else
2150
for_each_online_power_domain_in_set(dump_fact_config_for_cpu, NULL,
2151
NULL, NULL, NULL);
2152
isst_ctdp_display_information_end(outf);
2153
}
2154
2155
static void set_fact_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
2156
void *arg4)
2157
{
2158
struct isst_pkg_ctdp_level_info ctdp_level;
2159
struct isst_pkg_ctdp pkg_dev;
2160
int ret;
2161
int status = *(int *)arg4;
2162
2163
if (status && no_turbo()) {
2164
isst_display_error_info_message(1, "Turbo mode is disabled", 0, 0);
2165
ret = -1;
2166
goto disp_results;
2167
}
2168
2169
ret = isst_get_ctdp_levels(id, &pkg_dev);
2170
if (ret) {
2171
isst_display_error_info_message(1, "Failed to get number of levels", 0, 0);
2172
goto disp_results;
2173
}
2174
2175
ret = isst_get_ctdp_control(id, pkg_dev.current_level, &ctdp_level);
2176
if (ret) {
2177
isst_display_error_info_message(1, "Failed to get current level", 0, 0);
2178
goto disp_results;
2179
}
2180
2181
if (!ctdp_level.fact_support) {
2182
isst_display_error_info_message(1, "turbo-freq feature is not present at this level", 1, pkg_dev.current_level);
2183
ret = -1;
2184
goto disp_results;
2185
}
2186
2187
if (status) {
2188
ret = isst_pm_qos_config(id, 1, 1);
2189
if (ret)
2190
goto disp_results;
2191
}
2192
2193
ret = isst_set_pbf_fact_status(id, 0, status);
2194
if (ret) {
2195
debug_printf("isst_set_pbf_fact_status failed");
2196
if (auto_mode)
2197
isst_pm_qos_config(id, 0, 0);
2198
2199
goto disp_results;
2200
}
2201
2202
/* Set TRL */
2203
if (status) {
2204
struct isst_pkg_ctdp pkg_dev;
2205
2206
ret = isst_get_ctdp_levels(id, &pkg_dev);
2207
if (!ret && id->cpu >= 0)
2208
ret = isst_set_trl(id, fact_trl);
2209
if (ret && auto_mode)
2210
isst_pm_qos_config(id, 0, 0);
2211
} else {
2212
if (auto_mode)
2213
isst_pm_qos_config(id, 0, 0);
2214
}
2215
2216
disp_results:
2217
if (status) {
2218
isst_display_result(id, outf, "turbo-freq", "enable", ret);
2219
if (ret)
2220
fact_enable_fail = ret;
2221
} else {
2222
/* Since we modified TRL during Fact enable, restore it */
2223
isst_set_trl_from_current_tdp(id, fact_trl);
2224
isst_display_result(id, outf, "turbo-freq", "disable", ret);
2225
}
2226
}
2227
2228
static void set_fact_enable(int arg)
2229
{
2230
int i, ret, enable = arg;
2231
struct isst_id id;
2232
2233
check_privilege();
2234
2235
if (cmd_help) {
2236
if (enable) {
2237
fprintf(stderr,
2238
"Enable Intel Speed Select Technology Turbo frequency feature\n");
2239
fprintf(stderr,
2240
"Optional: -t|--trl : Specify turbo ratio limit in hex starting with 0x\n");
2241
fprintf(stderr,
2242
"\tOptional Arguments: -a|--auto : Designate specified target CPUs with");
2243
fprintf(stderr,
2244
"-C|--cpu option as as high priority using core-power feature\n");
2245
} else {
2246
fprintf(stderr,
2247
"Disable Intel Speed Select Technology turbo frequency feature\n");
2248
fprintf(stderr,
2249
"Optional: -t|--trl : Specify turbo ratio limit in hex starting with 0x\n");
2250
fprintf(stderr,
2251
"\tOptional Arguments: -a|--auto : Also disable core-power associations\n");
2252
}
2253
exit(0);
2254
}
2255
2256
isst_ctdp_display_information_start(outf);
2257
if (max_target_cpus)
2258
for_each_online_target_cpu_in_set(set_fact_for_cpu, NULL, NULL,
2259
NULL, &enable);
2260
else
2261
for_each_online_power_domain_in_set(set_fact_for_cpu, NULL, NULL,
2262
NULL, &enable);
2263
2264
if (!fact_enable_fail && enable && auto_mode) {
2265
/*
2266
* When we adjust CLOS param, we have to set for siblings also.
2267
* So for the each user specified CPU, also add the sibling
2268
* in the present_cpu_mask.
2269
*/
2270
for (i = 0; i < get_topo_max_cpus(); ++i) {
2271
char buffer[128], sibling_list[128], *cpu_str;
2272
int fd, len;
2273
2274
if (!CPU_ISSET_S(i, target_cpumask_size, target_cpumask))
2275
continue;
2276
2277
snprintf(buffer, sizeof(buffer),
2278
"/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", i);
2279
2280
fd = open(buffer, O_RDONLY);
2281
if (fd < 0)
2282
continue;
2283
2284
len = read(fd, sibling_list, sizeof(sibling_list));
2285
close(fd);
2286
2287
if (len < 0)
2288
continue;
2289
2290
sibling_list[127] = '\0';
2291
cpu_str = strtok(sibling_list, ",");
2292
while (cpu_str != NULL) {
2293
int cpu;
2294
2295
sscanf(cpu_str, "%d", &cpu);
2296
CPU_SET_S(cpu, target_cpumask_size, target_cpumask);
2297
cpu_str = strtok(NULL, ",");
2298
}
2299
}
2300
2301
for (i = 0; i < get_topo_max_cpus(); ++i) {
2302
int clos;
2303
2304
if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
2305
continue;
2306
2307
if (is_cpu_online(i) != 1)
2308
continue;
2309
2310
set_isst_id(&id, i);
2311
ret = set_clos_param(&id, 0, 0, 0, 0, 0xff);
2312
if (ret)
2313
goto error_disp;
2314
2315
ret = set_clos_param(&id, 1, 15, 15, 0, 0xff);
2316
if (ret)
2317
goto error_disp;
2318
2319
ret = set_clos_param(&id, 2, 15, 15, 0, 0xff);
2320
if (ret)
2321
goto error_disp;
2322
2323
ret = set_clos_param(&id, 3, 15, 15, 0, 0xff);
2324
if (ret)
2325
goto error_disp;
2326
2327
if (CPU_ISSET_S(i, target_cpumask_size, target_cpumask))
2328
clos = 0;
2329
else
2330
clos = 3;
2331
2332
debug_printf("Associate cpu: %d clos: %d\n", i, clos);
2333
ret = isst_clos_associate(&id, clos);
2334
if (ret)
2335
goto error_disp;
2336
}
2337
set_isst_id(&id, -1);
2338
isst_display_result(&id, outf, "turbo-freq --auto", "enable", 0);
2339
}
2340
2341
isst_ctdp_display_information_end(outf);
2342
2343
return;
2344
2345
error_disp:
2346
isst_display_result(&id, outf, "turbo-freq --auto", "enable", ret);
2347
isst_ctdp_display_information_end(outf);
2348
2349
}
2350
2351
static void enable_clos_qos_config(struct isst_id *id, void *arg1, void *arg2, void *arg3,
2352
void *arg4)
2353
{
2354
int ret;
2355
int status = *(int *)arg4;
2356
int cp_state, cp_cap;
2357
2358
if (!isst_read_pm_config(id, &cp_state, &cp_cap)) {
2359
if (!cp_cap) {
2360
isst_display_error_info_message(1, "core-power not supported", 0, 0);
2361
return;
2362
}
2363
}
2364
2365
if (is_skx_based_platform())
2366
clos_priority_type = 1;
2367
2368
ret = isst_pm_qos_config(id, status, clos_priority_type);
2369
if (ret)
2370
isst_display_error_info_message(1, "isst_pm_qos_config failed", 0, 0);
2371
2372
if (status)
2373
isst_display_result(id, outf, "core-power", "enable",
2374
ret);
2375
else
2376
isst_display_result(id, outf, "core-power", "disable",
2377
ret);
2378
}
2379
2380
static void set_clos_enable(int arg)
2381
{
2382
int enable = arg;
2383
2384
check_privilege();
2385
2386
if (cmd_help) {
2387
if (enable) {
2388
fprintf(stderr,
2389
"Enable core-power for a package/die\n");
2390
if (!is_skx_based_platform()) {
2391
fprintf(stderr,
2392
"\tClos Enable: Specify priority type with [--priority|-p]\n");
2393
fprintf(stderr, "\t\t 0: Proportional, 1: Ordered\n");
2394
}
2395
} else {
2396
fprintf(stderr,
2397
"Disable core-power: [No command arguments are required]\n");
2398
}
2399
exit(0);
2400
}
2401
2402
if (enable && cpufreq_sysfs_present()) {
2403
fprintf(stderr,
2404
"cpufreq subsystem and core-power enable will interfere with each other!\n");
2405
}
2406
2407
isst_ctdp_display_information_start(outf);
2408
if (max_target_cpus)
2409
for_each_online_target_cpu_in_set(enable_clos_qos_config, NULL,
2410
NULL, NULL, &enable);
2411
else
2412
for_each_online_power_domain_in_set(enable_clos_qos_config, NULL,
2413
NULL, NULL, &enable);
2414
isst_ctdp_display_information_end(outf);
2415
}
2416
2417
static void dump_clos_config_for_cpu(struct isst_id *id, void *arg1, void *arg2,
2418
void *arg3, void *arg4)
2419
{
2420
struct isst_clos_config clos_config;
2421
int ret;
2422
2423
ret = isst_pm_get_clos(id, current_clos, &clos_config);
2424
if (ret)
2425
isst_display_error_info_message(1, "isst_pm_get_clos failed", 0, 0);
2426
else
2427
isst_clos_display_information(id, outf, current_clos,
2428
&clos_config);
2429
}
2430
2431
static void dump_clos_config(int arg)
2432
{
2433
if (cmd_help) {
2434
fprintf(stderr,
2435
"Print Intel Speed Select Technology core power configuration\n");
2436
fprintf(stderr,
2437
"\tArguments: [-c | --clos]: Specify clos id\n");
2438
exit(0);
2439
}
2440
if (current_clos < 0 || current_clos > 3) {
2441
isst_display_error_info_message(1, "Invalid clos id\n", 0, 0);
2442
isst_ctdp_display_information_end(outf);
2443
exit(0);
2444
}
2445
2446
isst_ctdp_display_information_start(outf);
2447
if (max_target_cpus)
2448
for_each_online_target_cpu_in_set(dump_clos_config_for_cpu,
2449
NULL, NULL, NULL, NULL);
2450
else
2451
for_each_online_power_domain_in_set(dump_clos_config_for_cpu, NULL,
2452
NULL, NULL, NULL);
2453
isst_ctdp_display_information_end(outf);
2454
}
2455
2456
static void get_clos_info_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
2457
void *arg4)
2458
{
2459
int enable, ret, prio_type;
2460
2461
ret = isst_clos_get_clos_information(id, &enable, &prio_type);
2462
if (ret)
2463
isst_display_error_info_message(1, "isst_clos_get_info failed", 0, 0);
2464
else {
2465
int cp_state, cp_cap;
2466
2467
isst_read_pm_config(id, &cp_state, &cp_cap);
2468
isst_clos_display_clos_information(id, outf, enable, prio_type,
2469
cp_state, cp_cap);
2470
}
2471
}
2472
2473
static void dump_clos_info(int arg)
2474
{
2475
if (cmd_help) {
2476
fprintf(stderr,
2477
"Print Intel Speed Select Technology core power information\n");
2478
fprintf(stderr, "\t Optionally specify targeted cpu id with [--cpu|-c]\n");
2479
exit(0);
2480
}
2481
2482
isst_ctdp_display_information_start(outf);
2483
if (max_target_cpus)
2484
for_each_online_target_cpu_in_set(get_clos_info_for_cpu, NULL,
2485
NULL, NULL, NULL);
2486
else
2487
for_each_online_power_domain_in_set(get_clos_info_for_cpu, NULL,
2488
NULL, NULL, NULL);
2489
isst_ctdp_display_information_end(outf);
2490
2491
}
2492
2493
static void set_clos_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
2494
void *arg4)
2495
{
2496
struct isst_clos_config clos_config;
2497
int ret;
2498
2499
if (id->cpu < 0)
2500
return;
2501
2502
clos_config.epp = clos_epp;
2503
clos_config.clos_prop_prio = clos_prop_prio;
2504
clos_config.clos_min = clos_min;
2505
clos_config.clos_max = clos_max;
2506
clos_config.clos_desired = clos_desired;
2507
ret = isst_set_clos(id, current_clos, &clos_config);
2508
if (ret)
2509
isst_display_error_info_message(1, "isst_set_clos failed", 0, 0);
2510
else
2511
isst_display_result(id, outf, "core-power", "config", ret);
2512
}
2513
2514
static void set_clos_config(int arg)
2515
{
2516
check_privilege();
2517
2518
if (cmd_help) {
2519
fprintf(stderr,
2520
"Set core-power configuration for one of the four clos ids\n");
2521
fprintf(stderr,
2522
"\tSpecify targeted clos id with [--clos|-c]\n");
2523
if (!is_skx_based_platform()) {
2524
fprintf(stderr, "\tSpecify clos EPP with [--epp|-e]\n");
2525
fprintf(stderr,
2526
"\tSpecify clos Proportional Priority [--weight|-w]\n");
2527
}
2528
fprintf(stderr, "\tSpecify clos min in MHz with [--min|-n]\n");
2529
fprintf(stderr, "\tSpecify clos max in MHz with [--max|-m]\n");
2530
exit(0);
2531
}
2532
2533
if (current_clos < 0 || current_clos > 3) {
2534
isst_display_error_info_message(1, "Invalid clos id\n", 0, 0);
2535
exit(0);
2536
}
2537
if (!is_skx_based_platform() && (clos_epp < 0 || clos_epp > 0x0F)) {
2538
fprintf(stderr, "clos epp is not specified or invalid, default: 0\n");
2539
clos_epp = 0;
2540
}
2541
if (!is_skx_based_platform() && (clos_prop_prio < 0 || clos_prop_prio > 0x0F)) {
2542
fprintf(stderr,
2543
"clos frequency weight is not specified or invalid, default: 0\n");
2544
clos_prop_prio = 0;
2545
}
2546
if (clos_min < 0) {
2547
fprintf(stderr, "clos min is not specified, default: 0\n");
2548
clos_min = 0;
2549
}
2550
if (clos_max < 0) {
2551
fprintf(stderr, "clos max is not specified, default: Max frequency (ratio 0xff)\n");
2552
clos_max = 0xff;
2553
}
2554
if (clos_desired) {
2555
fprintf(stderr, "clos desired is not supported on this platform\n");
2556
clos_desired = 0x00;
2557
}
2558
2559
isst_ctdp_display_information_start(outf);
2560
if (max_target_cpus)
2561
for_each_online_target_cpu_in_set(set_clos_config_for_cpu, NULL,
2562
NULL, NULL, NULL);
2563
else
2564
for_each_online_power_domain_in_set(set_clos_config_for_cpu, NULL,
2565
NULL, NULL, NULL);
2566
isst_ctdp_display_information_end(outf);
2567
}
2568
2569
static void set_clos_assoc_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
2570
void *arg4)
2571
{
2572
int ret;
2573
2574
ret = isst_clos_associate(id, current_clos);
2575
if (ret)
2576
debug_printf("isst_clos_associate failed");
2577
else
2578
isst_display_result(id, outf, "core-power", "assoc", ret);
2579
}
2580
2581
static void set_clos_assoc(int arg)
2582
{
2583
check_privilege();
2584
2585
if (cmd_help) {
2586
fprintf(stderr, "Associate a clos id to a CPU\n");
2587
fprintf(stderr,
2588
"\tSpecify targeted clos id with [--clos|-c]\n");
2589
fprintf(stderr,
2590
"\tFor example to associate clos 1 to CPU 0: issue\n");
2591
fprintf(stderr,
2592
"\tintel-speed-select --cpu 0 core-power assoc --clos 1\n");
2593
exit(0);
2594
}
2595
2596
if (current_clos < 0 || current_clos > 3) {
2597
isst_display_error_info_message(1, "Invalid clos id\n", 0, 0);
2598
exit(0);
2599
}
2600
2601
isst_ctdp_display_information_start(outf);
2602
2603
if (max_target_cpus)
2604
for_each_online_target_cpu_in_set(set_clos_assoc_for_cpu, NULL,
2605
NULL, NULL, NULL);
2606
else {
2607
isst_display_error_info_message(1, "Invalid target cpu. Specify with [-c|--cpu]", 0, 0);
2608
}
2609
isst_ctdp_display_information_end(outf);
2610
}
2611
2612
static void get_clos_assoc_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
2613
void *arg4)
2614
{
2615
int clos, ret;
2616
2617
ret = isst_clos_get_assoc_status(id, &clos);
2618
if (ret)
2619
isst_display_error_info_message(1, "isst_clos_get_assoc_status failed", 0, 0);
2620
else
2621
isst_clos_display_assoc_information(id, outf, clos);
2622
}
2623
2624
static void get_clos_assoc(int arg)
2625
{
2626
if (cmd_help) {
2627
fprintf(stderr, "Get associate clos id to a CPU\n");
2628
fprintf(stderr, "\tSpecify targeted cpu id with [--cpu|-c]\n");
2629
exit(0);
2630
}
2631
2632
if (!max_target_cpus) {
2633
isst_display_error_info_message(1, "Invalid target cpu. Specify with [-c|--cpu]", 0, 0);
2634
exit(0);
2635
}
2636
2637
isst_ctdp_display_information_start(outf);
2638
for_each_online_target_cpu_in_set(get_clos_assoc_for_cpu, NULL,
2639
NULL, NULL, NULL);
2640
isst_ctdp_display_information_end(outf);
2641
}
2642
2643
static void set_turbo_mode_for_cpu(struct isst_id *id, int status)
2644
{
2645
int base_freq;
2646
2647
if (status) {
2648
base_freq = get_cpufreq_base_freq(id->cpu);
2649
set_cpufreq_scaling_min_max(id->cpu, 1, base_freq);
2650
} else {
2651
set_scaling_max_to_cpuinfo_max(id);
2652
}
2653
2654
if (status) {
2655
isst_display_result(id, outf, "turbo-mode", "disable", 0);
2656
} else {
2657
isst_display_result(id, outf, "turbo-mode", "enable", 0);
2658
}
2659
}
2660
2661
static void set_turbo_mode(int arg)
2662
{
2663
int i, disable = arg;
2664
struct isst_id id;
2665
2666
check_privilege();
2667
2668
if (cmd_help) {
2669
if (disable)
2670
fprintf(stderr, "Set turbo mode disable\n");
2671
else
2672
fprintf(stderr, "Set turbo mode enable\n");
2673
exit(0);
2674
}
2675
2676
isst_ctdp_display_information_start(outf);
2677
2678
for (i = 0; i < topo_max_cpus; ++i) {
2679
int online;
2680
2681
if (i)
2682
online = parse_int_file(
2683
1, "/sys/devices/system/cpu/cpu%d/online", i);
2684
else
2685
online =
2686
1; /* online entry for CPU 0 needs some special configs */
2687
2688
if (online) {
2689
set_isst_id(&id, i);
2690
set_turbo_mode_for_cpu(&id, disable);
2691
}
2692
2693
}
2694
isst_ctdp_display_information_end(outf);
2695
}
2696
2697
static void get_set_trl(struct isst_id *id, void *arg1, void *arg2, void *arg3,
2698
void *arg4)
2699
{
2700
unsigned long long trl;
2701
int set = *(int *)arg4;
2702
int ret;
2703
2704
if (id->cpu < 0)
2705
return;
2706
2707
if (set && !fact_trl) {
2708
isst_display_error_info_message(1, "Invalid TRL. Specify with [-t|--trl]", 0, 0);
2709
exit(0);
2710
}
2711
2712
if (set) {
2713
check_privilege();
2714
ret = isst_set_trl(id, fact_trl);
2715
isst_display_result(id, outf, "turbo-mode", "set-trl", ret);
2716
return;
2717
}
2718
2719
ret = isst_get_trl(id, &trl);
2720
if (ret)
2721
isst_display_result(id, outf, "turbo-mode", "get-trl", ret);
2722
else
2723
isst_trl_display_information(id, outf, trl);
2724
}
2725
2726
static void process_trl(int arg)
2727
{
2728
if (cmd_help) {
2729
if (arg) {
2730
fprintf(stderr, "Set TRL (turbo ratio limits)\n");
2731
fprintf(stderr, "\t t|--trl: Specify turbo ratio limit for setting TRL in hex starting with 0x\n");
2732
} else {
2733
fprintf(stderr, "Get TRL (turbo ratio limits)\n");
2734
}
2735
exit(0);
2736
}
2737
2738
isst_ctdp_display_information_start(outf);
2739
if (max_target_cpus)
2740
for_each_online_target_cpu_in_set(get_set_trl, NULL,
2741
NULL, NULL, &arg);
2742
else
2743
for_each_online_power_domain_in_set(get_set_trl, NULL,
2744
NULL, NULL, &arg);
2745
isst_ctdp_display_information_end(outf);
2746
}
2747
2748
static struct process_cmd_struct clx_n_cmds[] = {
2749
{ "perf-profile", "info", dump_isst_config, 0 },
2750
{ "base-freq", "info", dump_pbf_config, 0 },
2751
{ "base-freq", "enable", set_pbf_enable, 1 },
2752
{ "base-freq", "disable", set_pbf_enable, 0 },
2753
{ NULL, NULL, NULL, 0 }
2754
};
2755
2756
static struct process_cmd_struct isst_cmds[] = {
2757
{ "perf-profile", "get-lock-status", get_tdp_locked, 0 },
2758
{ "perf-profile", "get-config-levels", get_tdp_levels, 0 },
2759
{ "perf-profile", "get-config-version", get_tdp_version, 0 },
2760
{ "perf-profile", "get-config-enabled", get_tdp_enabled, 0 },
2761
{ "perf-profile", "get-config-current-level", get_tdp_current_level,
2762
0 },
2763
{ "perf-profile", "set-config-level", set_tdp_level, 0 },
2764
{ "perf-profile", "info", dump_isst_config, 0 },
2765
{ "base-freq", "info", dump_pbf_config, 0 },
2766
{ "base-freq", "enable", set_pbf_enable, 1 },
2767
{ "base-freq", "disable", set_pbf_enable, 0 },
2768
{ "turbo-freq", "info", dump_fact_config, 0 },
2769
{ "turbo-freq", "enable", set_fact_enable, 1 },
2770
{ "turbo-freq", "disable", set_fact_enable, 0 },
2771
{ "core-power", "info", dump_clos_info, 0 },
2772
{ "core-power", "enable", set_clos_enable, 1 },
2773
{ "core-power", "disable", set_clos_enable, 0 },
2774
{ "core-power", "config", set_clos_config, 0 },
2775
{ "core-power", "get-config", dump_clos_config, 0 },
2776
{ "core-power", "assoc", set_clos_assoc, 0 },
2777
{ "core-power", "get-assoc", get_clos_assoc, 0 },
2778
{ "turbo-mode", "enable", set_turbo_mode, 0 },
2779
{ "turbo-mode", "disable", set_turbo_mode, 1 },
2780
{ "turbo-mode", "get-trl", process_trl, 0 },
2781
{ "turbo-mode", "set-trl", process_trl, 1 },
2782
{ NULL, NULL, NULL }
2783
};
2784
2785
/*
2786
* parse cpuset with following syntax
2787
* 1,2,4..6,8-10 and set bits in cpu_subset
2788
*/
2789
void parse_cpu_command(char *optarg)
2790
{
2791
unsigned int start, end, invalid_count;
2792
char *next;
2793
2794
next = optarg;
2795
invalid_count = 0;
2796
2797
while (next && *next) {
2798
if (*next == '-') /* no negative cpu numbers */
2799
goto error;
2800
2801
start = strtoul(next, &next, 10);
2802
2803
if (max_target_cpus < MAX_CPUS_IN_ONE_REQ)
2804
target_cpus[max_target_cpus++] = start;
2805
else
2806
invalid_count = 1;
2807
2808
if (*next == '\0')
2809
break;
2810
2811
if (*next == ',') {
2812
next += 1;
2813
continue;
2814
}
2815
2816
if (*next == '-') {
2817
next += 1; /* start range */
2818
} else if (*next == '.') {
2819
next += 1;
2820
if (*next == '.')
2821
next += 1; /* start range */
2822
else
2823
goto error;
2824
}
2825
2826
end = strtoul(next, &next, 10);
2827
if (end <= start)
2828
goto error;
2829
2830
while (++start <= end) {
2831
if (max_target_cpus < MAX_CPUS_IN_ONE_REQ)
2832
target_cpus[max_target_cpus++] = start;
2833
else
2834
invalid_count = 1;
2835
}
2836
2837
if (*next == ',')
2838
next += 1;
2839
else if (*next != '\0')
2840
goto error;
2841
}
2842
2843
if (invalid_count) {
2844
isst_ctdp_display_information_start(outf);
2845
isst_display_error_info_message(1, "Too many CPUs in one request: max is", 1, MAX_CPUS_IN_ONE_REQ - 1);
2846
isst_ctdp_display_information_end(outf);
2847
exit(-1);
2848
}
2849
2850
#ifdef DEBUG
2851
{
2852
int i;
2853
2854
for (i = 0; i < max_target_cpus; ++i)
2855
printf("cpu [%d] in arg\n", target_cpus[i]);
2856
}
2857
#endif
2858
return;
2859
2860
error:
2861
fprintf(stderr, "\"--cpu %s\" malformed\n", optarg);
2862
exit(-1);
2863
}
2864
2865
static void check_optarg(char *option, int hex)
2866
{
2867
if (optarg) {
2868
char *start = optarg;
2869
int i;
2870
2871
if (hex && strlen(optarg) < 3) {
2872
/* At least 0x plus one character must be present */
2873
fprintf(stderr, "malformed arguments for:%s [%s]\n", option, optarg);
2874
exit(0);
2875
}
2876
2877
if (hex) {
2878
if (optarg[0] != '0' || tolower(optarg[1]) != 'x') {
2879
fprintf(stderr, "malformed arguments for:%s [%s]\n",
2880
option, optarg);
2881
exit(0);
2882
}
2883
start = &optarg[2];
2884
}
2885
2886
for (i = 0; i < strlen(start); ++i) {
2887
if (hex) {
2888
if (!isxdigit(start[i])) {
2889
fprintf(stderr, "malformed arguments for:%s [%s]\n",
2890
option, optarg);
2891
exit(0);
2892
}
2893
} else if (!isdigit(start[i])) {
2894
fprintf(stderr, "malformed arguments for:%s [%s]\n",
2895
option, optarg);
2896
exit(0);
2897
}
2898
}
2899
}
2900
}
2901
2902
static void parse_cmd_args(int argc, int start, char **argv)
2903
{
2904
int opt;
2905
int option_index;
2906
2907
static struct option long_options[] = {
2908
{ "bucket", required_argument, 0, 'b' },
2909
{ "level", required_argument, 0, 'l' },
2910
{ "online", required_argument, 0, 'o' },
2911
{ "trl-type", required_argument, 0, 'r' },
2912
{ "trl", required_argument, 0, 't' },
2913
{ "help", no_argument, 0, 'h' },
2914
{ "clos", required_argument, 0, 'c' },
2915
{ "desired", required_argument, 0, 'd' },
2916
{ "epp", required_argument, 0, 'e' },
2917
{ "min", required_argument, 0, 'n' },
2918
{ "max", required_argument, 0, 'm' },
2919
{ "priority", required_argument, 0, 'p' },
2920
{ "weight", required_argument, 0, 'w' },
2921
{ "auto", no_argument, 0, 'a' },
2922
{ 0, 0, 0, 0 }
2923
};
2924
2925
option_index = start;
2926
2927
optind = start + 1;
2928
while ((opt = getopt_long(argc, argv, "b:l:t:c:d:e:n:m:p:w:r:hoa",
2929
long_options, &option_index)) != -1) {
2930
switch (opt) {
2931
case 'a':
2932
auto_mode = 1;
2933
break;
2934
case 'b':
2935
check_optarg("bucket", 0);
2936
fact_bucket = atoi(optarg);
2937
break;
2938
case 'h':
2939
cmd_help = 1;
2940
break;
2941
case 'l':
2942
check_optarg("level", 0);
2943
tdp_level = atoi(optarg);
2944
break;
2945
case 'o':
2946
force_online_offline = 1;
2947
break;
2948
case 't':
2949
check_optarg("trl", 1);
2950
sscanf(optarg, "0x%llx", &fact_trl);
2951
break;
2952
case 'r':
2953
if (!strncmp(optarg, "sse", 3)) {
2954
fact_avx = 0x01;
2955
} else if (!strncmp(optarg, "avx2", 4)) {
2956
fact_avx = 0x02;
2957
} else if (!strncmp(optarg, "avx512", 6)) {
2958
fact_avx = 0x04;
2959
} else {
2960
fprintf(outf, "Invalid sse,avx options\n");
2961
exit(1);
2962
}
2963
break;
2964
/* CLOS related */
2965
case 'c':
2966
check_optarg("clos", 0);
2967
current_clos = atoi(optarg);
2968
break;
2969
case 'd':
2970
check_optarg("desired", 0);
2971
clos_desired = atoi(optarg);
2972
clos_desired /= isst_get_disp_freq_multiplier();
2973
break;
2974
case 'e':
2975
check_optarg("epp", 0);
2976
clos_epp = atoi(optarg);
2977
if (is_skx_based_platform()) {
2978
isst_display_error_info_message(1, "epp can't be specified on this platform", 0, 0);
2979
exit(0);
2980
}
2981
break;
2982
case 'n':
2983
check_optarg("min", 0);
2984
clos_min = atoi(optarg);
2985
clos_min /= isst_get_disp_freq_multiplier();
2986
break;
2987
case 'm':
2988
check_optarg("max", 0);
2989
clos_max = atoi(optarg);
2990
clos_max /= isst_get_disp_freq_multiplier();
2991
break;
2992
case 'p':
2993
check_optarg("priority", 0);
2994
clos_priority_type = atoi(optarg);
2995
if (is_skx_based_platform() && !clos_priority_type) {
2996
isst_display_error_info_message(1, "Invalid clos priority type: proportional for this platform", 0, 0);
2997
exit(0);
2998
}
2999
break;
3000
case 'w':
3001
check_optarg("weight", 0);
3002
clos_prop_prio = atoi(optarg);
3003
if (is_skx_based_platform()) {
3004
isst_display_error_info_message(1, "weight can't be specified on this platform", 0, 0);
3005
exit(0);
3006
}
3007
break;
3008
default:
3009
printf("Unknown option: ignore\n");
3010
}
3011
}
3012
3013
if (argv[optind])
3014
printf("Garbage at the end of command: ignore\n");
3015
}
3016
3017
static void isst_help(void)
3018
{
3019
printf("perf-profile:\tAn architectural mechanism that allows multiple optimized \n\
3020
performance profiles per system via static and/or dynamic\n\
3021
adjustment of core count, workload, Tjmax, and\n\
3022
TDP, etc.\n");
3023
printf("\nCommands : For feature=perf-profile\n");
3024
printf("\tinfo\n");
3025
3026
if (!is_clx_n_platform()) {
3027
printf("\tget-lock-status\n");
3028
printf("\tget-config-levels\n");
3029
printf("\tget-config-version\n");
3030
printf("\tget-config-enabled\n");
3031
printf("\tget-config-current-level\n");
3032
printf("\tset-config-level\n");
3033
}
3034
}
3035
3036
static void pbf_help(void)
3037
{
3038
printf("base-freq:\tEnables users to increase guaranteed base frequency\n\
3039
on certain cores (high priority cores) in exchange for lower\n\
3040
base frequency on remaining cores (low priority cores).\n");
3041
printf("\tcommand : info\n");
3042
printf("\tcommand : enable\n");
3043
printf("\tcommand : disable\n");
3044
}
3045
3046
static void fact_help(void)
3047
{
3048
printf("turbo-freq:\tEnables the ability to set different turbo ratio\n\
3049
limits to cores based on priority.\n");
3050
printf("\nCommand: For feature=turbo-freq\n");
3051
printf("\tcommand : info\n");
3052
printf("\tcommand : enable\n");
3053
printf("\tcommand : disable\n");
3054
}
3055
3056
static void turbo_mode_help(void)
3057
{
3058
printf("turbo-mode:\tEnables users to enable/disable turbo mode by adjusting frequency settings. Also allows to get and set turbo ratio limits (TRL).\n");
3059
printf("\tcommand : enable\n");
3060
printf("\tcommand : disable\n");
3061
printf("\tcommand : get-trl\n");
3062
printf("\tcommand : set-trl\n");
3063
}
3064
3065
3066
static void core_power_help(void)
3067
{
3068
printf("core-power:\tInterface that allows user to define per core/tile\n\
3069
priority.\n");
3070
printf("\nCommands : For feature=core-power\n");
3071
printf("\tinfo\n");
3072
printf("\tenable\n");
3073
printf("\tdisable\n");
3074
printf("\tconfig\n");
3075
printf("\tget-config\n");
3076
printf("\tassoc\n");
3077
printf("\tget-assoc\n");
3078
}
3079
3080
struct process_cmd_help_struct {
3081
char *feature;
3082
void (*process_fn)(void);
3083
};
3084
3085
static struct process_cmd_help_struct isst_help_cmds[] = {
3086
{ "perf-profile", isst_help },
3087
{ "base-freq", pbf_help },
3088
{ "turbo-freq", fact_help },
3089
{ "core-power", core_power_help },
3090
{ "turbo-mode", turbo_mode_help },
3091
{ NULL, NULL }
3092
};
3093
3094
static struct process_cmd_help_struct clx_n_help_cmds[] = {
3095
{ "perf-profile", isst_help },
3096
{ "base-freq", pbf_help },
3097
{ NULL, NULL }
3098
};
3099
3100
void process_command(int argc, char **argv,
3101
struct process_cmd_help_struct *help_cmds,
3102
struct process_cmd_struct *cmds)
3103
{
3104
int i = 0, matched = 0;
3105
char *feature = argv[optind];
3106
char *cmd = argv[optind + 1];
3107
3108
if (!feature || !cmd)
3109
return;
3110
3111
debug_printf("feature name [%s] command [%s]\n", feature, cmd);
3112
if (!strcmp(cmd, "-h") || !strcmp(cmd, "--help")) {
3113
while (help_cmds[i].feature) {
3114
if (!strcmp(help_cmds[i].feature, feature)) {
3115
help_cmds[i].process_fn();
3116
exit(0);
3117
}
3118
++i;
3119
}
3120
}
3121
3122
i = 0;
3123
while (cmds[i].feature) {
3124
if (!strcmp(cmds[i].feature, feature) &&
3125
!strcmp(cmds[i].command, cmd)) {
3126
parse_cmd_args(argc, optind + 1, argv);
3127
cmds[i].process_fn(cmds[i].arg);
3128
matched = 1;
3129
break;
3130
}
3131
++i;
3132
}
3133
3134
if (!matched)
3135
fprintf(stderr, "Invalid command\n");
3136
}
3137
3138
static void usage(void)
3139
{
3140
if (is_clx_n_platform()) {
3141
fprintf(stderr, "\nThere is limited support of Intel Speed Select features on this platform.\n");
3142
fprintf(stderr, "Everything is pre-configured using BIOS options, this tool can't enable any feature in the hardware.\n\n");
3143
}
3144
3145
printf("\nUsage:\n");
3146
printf("intel-speed-select [OPTIONS] FEATURE COMMAND COMMAND_ARGUMENTS\n");
3147
printf("\nUse this tool to enumerate and control the Intel Speed Select Technology features:\n");
3148
if (is_clx_n_platform())
3149
printf("\nFEATURE : [perf-profile|base-freq]\n");
3150
else
3151
printf("\nFEATURE : [perf-profile|base-freq|turbo-freq|core-power|turbo-mode]\n");
3152
printf("\nFor help on each feature, use -h|--help\n");
3153
printf("\tFor example: intel-speed-select perf-profile -h\n");
3154
3155
printf("\nFor additional help on each command for a feature, use --h|--help\n");
3156
printf("\tFor example: intel-speed-select perf-profile get-lock-status -h\n");
3157
printf("\t\t This will print help for the command \"get-lock-status\" for the feature \"perf-profile\"\n");
3158
3159
printf("\nOPTIONS\n");
3160
printf("\t[-c|--cpu] : logical cpu number\n");
3161
printf("\t\tDefault: Die scoped for all dies in the system with multiple dies/package\n");
3162
printf("\t\t\t Or Package scoped for all Packages when each package contains one die\n");
3163
printf("\t[-d|--debug] : Debug mode\n");
3164
printf("\t[-f|--format] : output format [json|text]. Default: text\n");
3165
printf("\t[-h|--help] : Print help\n");
3166
printf("\t[-i|--info] : Print platform information\n");
3167
printf("\t[-a|--all-cpus-online] : Force online every CPU in the system\n");
3168
printf("\t[-o|--out] : Output file\n");
3169
printf("\t\t\tDefault : stderr\n");
3170
printf("\t[-p|--pause] : Delay between two mail box commands in milliseconds\n");
3171
printf("\t[-r|--retry] : Retry count for mail box commands on failure, default 3\n");
3172
printf("\t[-v|--version] : Print version\n");
3173
printf("\t[-b|--oob : Start a daemon to process HFI events for perf profile change from Out of Band agent.\n");
3174
printf("\t[-n|--no-daemon : Don't run as daemon. By default --oob will turn on daemon mode\n");
3175
printf("\t[-w|--delay : Delay for reading config level state change in OOB poll mode.\n");
3176
printf("\t[-g|--cgroupv2 : Try to use cgroup v2 CPU isolation instead of CPU online/offline.\n");
3177
printf("\t[-u|--cpu0-workaround : Don't try to online/offline CPU0 instead use cgroup v2.\n");
3178
printf("\nResult format\n");
3179
printf("\tResult display uses a common format for each command:\n");
3180
printf("\tResults are formatted in text/JSON with\n");
3181
printf("\t\tPackage, Die, CPU, and command specific results.\n");
3182
3183
printf("\nExamples\n");
3184
printf("\tTo get platform information:\n");
3185
printf("\t\tintel-speed-select --info\n");
3186
printf("\tTo get full perf-profile information dump:\n");
3187
printf("\t\tintel-speed-select perf-profile info\n");
3188
printf("\tTo get full base-freq information dump:\n");
3189
printf("\t\tintel-speed-select base-freq info -l 0\n");
3190
if (!is_clx_n_platform()) {
3191
printf("\tTo get full turbo-freq information dump:\n");
3192
printf("\t\tintel-speed-select turbo-freq info -l 0\n");
3193
}
3194
exit(1);
3195
}
3196
3197
static void print_version(void)
3198
{
3199
fprintf(outf, "Version %s\n", version_str);
3200
exit(0);
3201
}
3202
3203
static void cmdline(int argc, char **argv)
3204
{
3205
const char *pathname = "/dev/isst_interface";
3206
char *ptr;
3207
FILE *fp;
3208
int opt, force_cpus_online = 0;
3209
int option_index = 0;
3210
int ret;
3211
int oob_mode = 0;
3212
int poll_interval = -1;
3213
int no_daemon = 0;
3214
int mbox_delay = 0, mbox_retries = 3;
3215
3216
static struct option long_options[] = {
3217
{ "all-cpus-online", no_argument, 0, 'a' },
3218
{ "cpu", required_argument, 0, 'c' },
3219
{ "debug", no_argument, 0, 'd' },
3220
{ "format", required_argument, 0, 'f' },
3221
{ "help", no_argument, 0, 'h' },
3222
{ "info", no_argument, 0, 'i' },
3223
{ "pause", required_argument, 0, 'p' },
3224
{ "out", required_argument, 0, 'o' },
3225
{ "retry", required_argument, 0, 'r' },
3226
{ "version", no_argument, 0, 'v' },
3227
{ "oob", no_argument, 0, 'b' },
3228
{ "no-daemon", no_argument, 0, 'n' },
3229
{ "poll-interval", required_argument, 0, 'w' },
3230
{ "cgroupv2", required_argument, 0, 'g' },
3231
{ "cpu0-workaround", required_argument, 0, 'u' },
3232
{ 0, 0, 0, 0 }
3233
};
3234
3235
if (geteuid() != 0) {
3236
int fd;
3237
3238
fd = open(pathname, O_RDWR);
3239
if (fd < 0) {
3240
fprintf(stderr, "Must run as root\n");
3241
exit(0);
3242
}
3243
fprintf(stderr, "\nNot running as root, Only read only operations are supported\n");
3244
close(fd);
3245
read_only = 1;
3246
}
3247
3248
ret = update_cpu_model();
3249
if (ret)
3250
err(-1, "Invalid CPU model (%d)\n", cpu_model);
3251
printf("Intel(R) Speed Select Technology\n");
3252
printf("Executing on CPU model:%d[0x%x]\n", cpu_model, cpu_model);
3253
3254
if (!is_clx_n_platform()) {
3255
fp = fopen(pathname, "rb");
3256
if (!fp) {
3257
fprintf(stderr, "Intel speed select drivers are not loaded on this system.\n");
3258
fprintf(stderr, "Verify that kernel config includes CONFIG_INTEL_SPEED_SELECT_INTERFACE.\n");
3259
fprintf(stderr, "If the config is included then this is not a supported platform.\n");
3260
exit(0);
3261
}
3262
fclose(fp);
3263
}
3264
3265
ret = isst_fill_platform_info();
3266
if (ret)
3267
goto out;
3268
3269
progname = argv[0];
3270
while ((opt = getopt_long_only(argc, argv, "+c:df:hio:vabw:ngu", long_options,
3271
&option_index)) != -1) {
3272
switch (opt) {
3273
case 'a':
3274
force_cpus_online = 1;
3275
break;
3276
case 'c':
3277
parse_cpu_command(optarg);
3278
break;
3279
case 'd':
3280
debug_flag = 1;
3281
printf("Debug Mode ON\n");
3282
break;
3283
case 'f':
3284
if (!strncmp(optarg, "json", 4))
3285
out_format_json = 1;
3286
break;
3287
case 'h':
3288
usage();
3289
break;
3290
case 'i':
3291
isst_print_platform_information();
3292
break;
3293
case 'o':
3294
if (outf)
3295
fclose(outf);
3296
outf = fopen_or_exit(optarg, "w");
3297
break;
3298
case 'p':
3299
ret = strtol(optarg, &ptr, 10);
3300
if (!ret)
3301
fprintf(stderr, "Invalid pause interval, ignore\n");
3302
else
3303
mbox_delay = ret;
3304
break;
3305
case 'r':
3306
ret = strtol(optarg, &ptr, 10);
3307
if (!ret)
3308
fprintf(stderr, "Invalid retry count, ignore\n");
3309
else
3310
mbox_retries = ret;
3311
break;
3312
case 'v':
3313
print_version();
3314
break;
3315
case 'b':
3316
oob_mode = 1;
3317
break;
3318
case 'n':
3319
no_daemon = 1;
3320
break;
3321
case 'w':
3322
ret = strtol(optarg, &ptr, 10);
3323
if (!ret) {
3324
fprintf(stderr, "Invalid poll interval count\n");
3325
exit(0);
3326
}
3327
poll_interval = ret;
3328
break;
3329
case 'g':
3330
cgroupv2 = 1;
3331
break;
3332
case 'u':
3333
cpu_0_cgroupv2 = 1;
3334
break;
3335
default:
3336
usage();
3337
}
3338
}
3339
3340
if (optind > (argc - 2) && !oob_mode) {
3341
usage();
3342
exit(0);
3343
}
3344
3345
isst_update_platform_param(ISST_PARAM_MBOX_DELAY, mbox_delay);
3346
isst_update_platform_param(ISST_PARAM_MBOX_RETRIES, mbox_retries);
3347
3348
set_max_cpu_num();
3349
if (force_cpus_online)
3350
force_all_cpus_online();
3351
store_cpu_topology();
3352
create_cpu_map();
3353
3354
if (oob_mode) {
3355
if (debug_flag)
3356
fprintf(stderr, "OOB mode is enabled in debug mode\n");
3357
3358
ret = isst_daemon(debug_flag, poll_interval, no_daemon);
3359
if (ret)
3360
fprintf(stderr, "OOB mode enable failed\n");
3361
goto out;
3362
}
3363
3364
if (!is_clx_n_platform()) {
3365
process_command(argc, argv, isst_help_cmds, isst_cmds);
3366
} else {
3367
process_command(argc, argv, clx_n_help_cmds, clx_n_cmds);
3368
}
3369
out:
3370
free_cpu_set(present_cpumask);
3371
free_cpu_set(target_cpumask);
3372
}
3373
3374
int main(int argc, char **argv)
3375
{
3376
outf = stderr;
3377
cmdline(argc, argv);
3378
return 0;
3379
}
3380
3381