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