xref: /linux/tools/power/x86/intel-speed-select/isst-config.c (revision 1193e205dbb6feca917dc8e1862ffcdf2194234b)
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 
get_output_file(void)83 FILE *get_output_file(void)
84 {
85 	return outf;
86 }
87 
is_debug_enabled(void)88 int is_debug_enabled(void)
89 {
90 	return debug_flag;
91 }
92 
debug_printf(const char * format,...)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 
is_clx_n_platform(void)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 
is_skx_based_platform(void)114 int is_skx_based_platform(void)
115 {
116 	if (cpu_model == 0x55)
117 		return 1;
118 
119 	return 0;
120 }
121 
is_spr_platform(void)122 int is_spr_platform(void)
123 {
124 	if (cpu_model == 0x8F)
125 		return 1;
126 
127 	return 0;
128 }
129 
is_emr_platform(void)130 int is_emr_platform(void)
131 {
132 	if (cpu_model == 0xCF)
133 		return 1;
134 
135 	return 0;
136 }
137 
138 
is_icx_platform(void)139 int is_icx_platform(void)
140 {
141 	if (cpu_model == 0x6A || cpu_model == 0x6C)
142 		return 1;
143 
144 	return 0;
145 }
146 
is_dmr_plus_platform(void)147 static int is_dmr_plus_platform(void)
148 {
149 	if (extended_family == 0x04)
150 		return 1;
151 
152 	return 0;
153 }
154 
update_cpu_model(void)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 
api_version(void)195 int api_version(void)
196 {
197         return isst_platform_info.api_version;
198 }
199 
200 /* Open a file, and exit on failure */
fopen_or_exit(const char * path,const char * mode)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 */
parse_int_file(int fatal,const char * fmt,...)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 
cpufreq_sysfs_present(void)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 
out_format_is_json(void)249 int out_format_is_json(void)
250 {
251 	return out_format_json;
252 }
253 
get_stored_topology_info(int cpu,int * core_id,int * pkg_id,int * die_id)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 
store_cpu_topology(void)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 
get_physical_package_id(int cpu)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 
get_physical_core_id(int cpu)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 
get_physical_die_id(int cpu)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 
get_physical_punit_id(int cpu)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 
set_isst_id(struct isst_id * id,int cpu)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 
is_cpu_in_power_domain(int cpu,struct isst_id * id)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 
get_cpufreq_base_freq(int cpu)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 
get_topo_max_cpus(void)460 int get_topo_max_cpus(void)
461 {
462 	return topo_max_cpus;
463 }
464 
is_cpu_online(int cpu)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 
set_cpu_online_offline(int cpu,int state)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 
force_all_cpus_online(void)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 
for_each_online_power_domain_in_set(void (* callback)(struct isst_id *,void *,void *,void *,void *),void * arg1,void * arg2,void * arg3,void * arg4)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 
for_each_online_target_cpu_in_set(void (* callback)(struct isst_id *,void *,void *,void *,void *),void * arg1,void * arg2,void * arg3,void * arg4)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
set_max_cpu_num(void)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 
alloc_cpu_set(cpu_set_t ** cpu_set)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 
free_cpu_set(cpu_set_t * cpu_set)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 
get_max_punit_core_id(struct isst_id * id)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 
get_cpu_count(struct isst_id * id)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 
update_punit_cpu_info(__u32 physical_cpu,struct _cpu_map * cpu_map)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 
create_cpu_map(void)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 
set_cpu_mask_from_punit_coremask(struct isst_id * id,unsigned long long core_mask,size_t core_cpumask_size,cpu_set_t * core_cpumask,int * cpu_cnt)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 
find_phy_core_num(int logical_cpu)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 
use_cgroupv2(void)896 int use_cgroupv2(void)
897 {
898 	return cgroupv2;
899 }
900 
enable_cpuset_controller(void)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 
isolate_cpus(struct isst_id * id,int mask_size,cpu_set_t * cpu_mask,int level,int cpu_0_only)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 
cpu_0_workaround(int isolate)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 
isst_fill_platform_info(void)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 
get_isst_status(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)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 
isst_print_extended_platform_info(void)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 
isst_print_platform_information(void)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;
exec_on_get_ctdp_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)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 
clx_n_get_base_ratio(void)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 
clx_n_config(struct isst_id * id)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 
dump_clx_n_config_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)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 
dump_isst_config_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)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 
dump_isst_config(int arg)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 
set_tdp_level_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)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 
set_tdp_level(int arg)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 
clx_n_dump_pbf_config_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)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 
dump_pbf_config_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)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 
dump_pbf_config(int arg)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 
set_clos_param(struct isst_id * id,int clos,int epp,int wt,int min,int max)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 
set_cpufreq_scaling_min_max(int cpu,int max,int freq)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 
no_turbo(void)1726 static int no_turbo(void)
1727 {
1728 	return parse_int_file(0, "/sys/devices/system/cpu/intel_pstate/no_turbo");
1729 }
1730 
adjust_scaling_max_from_base_freq(int cpu)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 
adjust_scaling_min_from_base_freq(int cpu)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 
set_clx_pbf_cpufreq_scaling_min_max(struct isst_id * id)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 
set_cpufreq_scaling_min_max_from_cpuinfo(int cpu,int cpuinfo_max,int scaling_max)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 
set_scaling_min_to_cpuinfo_max(struct isst_id * id)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 
set_scaling_min_to_cpuinfo_min(struct isst_id * id)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 
set_scaling_max_to_cpuinfo_max(struct isst_id * id)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 
set_core_priority_and_min(struct isst_id * id,int mask_size,cpu_set_t * cpu_mask,int min_high,int min_low)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 
set_pbf_core_power(struct isst_id * id)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 
set_pbf_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)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 
set_pbf_enable(int arg)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 
dump_fact_config_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)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 
dump_fact_config(int arg)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 
set_fact_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)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 
set_fact_enable(int arg)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 
enable_clos_qos_config(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)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 
set_clos_enable(int arg)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 
dump_clos_config_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)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 
dump_clos_config(int arg)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 
get_clos_info_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)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 
dump_clos_info(int arg)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 
set_clos_config_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)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 
set_clos_config(int arg)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 
set_clos_assoc_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)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 
set_clos_assoc(int arg)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 
get_clos_assoc_for_cpu(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)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 
get_clos_assoc(int arg)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 
set_turbo_mode_for_cpu(struct isst_id * id,int status)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 
set_turbo_mode(int arg)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 
get_set_trl(struct isst_id * id,void * arg1,void * arg2,void * arg3,void * arg4)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 
process_trl(int arg)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  */
parse_cpu_command(char * optarg)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 
check_optarg(char * option,int hex)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 
parse_cmd_args(int argc,int start,char ** argv)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 
isst_help(void)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 
pbf_help(void)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 
fact_help(void)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 
turbo_mode_help(void)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 
core_power_help(void)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 
process_command(int argc,char ** argv,struct process_cmd_help_struct * help_cmds,struct process_cmd_struct * cmds)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 
usage(void)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 
print_version(void)3168 static void print_version(void)
3169 {
3170 	fprintf(outf, "Version %s\n", version_str);
3171 	exit(0);
3172 }
3173 
cmdline(int argc,char ** argv)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 
main(int argc,char ** argv)3337 int main(int argc, char **argv)
3338 {
3339 	outf = stderr;
3340 	cmdline(argc, argv);
3341 	return 0;
3342 }
3343