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