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