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