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