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