• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Intel Speed Select -- Enumerate and control features
4  * Copyright (c) 2019 Intel Corporation.
5  */
6 
7 #include <linux/isst_if.h>
8 
9 #include "isst.h"
10 
11 struct process_cmd_struct {
12 	char *feature;
13 	char *command;
14 	void (*process_fn)(void);
15 };
16 
17 static const char *version_str = "v1.0";
18 static const int supported_api_ver = 1;
19 static struct isst_if_platform_info isst_platform_info;
20 static char *progname;
21 static int debug_flag;
22 static FILE *outf;
23 
24 static int cpu_model;
25 
26 #define MAX_CPUS_IN_ONE_REQ 64
27 static short max_target_cpus;
28 static unsigned short target_cpus[MAX_CPUS_IN_ONE_REQ];
29 
30 static int topo_max_cpus;
31 static size_t present_cpumask_size;
32 static cpu_set_t *present_cpumask;
33 static size_t target_cpumask_size;
34 static cpu_set_t *target_cpumask;
35 static int tdp_level = 0xFF;
36 static int fact_bucket = 0xFF;
37 static int fact_avx = 0xFF;
38 static unsigned long long fact_trl;
39 static int out_format_json;
40 static int cmd_help;
41 static int force_online_offline;
42 
43 /* clos related */
44 static int current_clos = -1;
45 static int clos_epp = -1;
46 static int clos_prop_prio = -1;
47 static int clos_min = -1;
48 static int clos_max = -1;
49 static int clos_desired = -1;
50 static int clos_priority_type;
51 
52 struct _cpu_map {
53 	unsigned short core_id;
54 	unsigned short pkg_id;
55 	unsigned short die_id;
56 	unsigned short punit_cpu;
57 	unsigned short punit_cpu_core;
58 };
59 struct _cpu_map *cpu_map;
60 
debug_printf(const char * format,...)61 void debug_printf(const char *format, ...)
62 {
63 	va_list args;
64 
65 	va_start(args, format);
66 
67 	if (debug_flag)
68 		vprintf(format, args);
69 
70 	va_end(args);
71 }
72 
update_cpu_model(void)73 static void update_cpu_model(void)
74 {
75 	unsigned int ebx, ecx, edx;
76 	unsigned int fms, family;
77 
78 	__cpuid(1, fms, ebx, ecx, edx);
79 	family = (fms >> 8) & 0xf;
80 	cpu_model = (fms >> 4) & 0xf;
81 	if (family == 6 || family == 0xf)
82 		cpu_model += ((fms >> 16) & 0xf) << 4;
83 }
84 
85 /* Open a file, and exit on failure */
fopen_or_exit(const char * path,const char * mode)86 static FILE *fopen_or_exit(const char *path, const char *mode)
87 {
88 	FILE *filep = fopen(path, mode);
89 
90 	if (!filep)
91 		err(1, "%s: open failed", path);
92 
93 	return filep;
94 }
95 
96 /* Parse a file containing a single int */
parse_int_file(int fatal,const char * fmt,...)97 static int parse_int_file(int fatal, const char *fmt, ...)
98 {
99 	va_list args;
100 	char path[PATH_MAX];
101 	FILE *filep;
102 	int value;
103 
104 	va_start(args, fmt);
105 	vsnprintf(path, sizeof(path), fmt, args);
106 	va_end(args);
107 	if (fatal) {
108 		filep = fopen_or_exit(path, "r");
109 	} else {
110 		filep = fopen(path, "r");
111 		if (!filep)
112 			return -1;
113 	}
114 	if (fscanf(filep, "%d", &value) != 1)
115 		err(1, "%s: failed to parse number from file", path);
116 	fclose(filep);
117 
118 	return value;
119 }
120 
cpufreq_sysfs_present(void)121 int cpufreq_sysfs_present(void)
122 {
123 	DIR *dir;
124 
125 	dir = opendir("/sys/devices/system/cpu/cpu0/cpufreq");
126 	if (dir) {
127 		closedir(dir);
128 		return 1;
129 	}
130 
131 	return 0;
132 }
133 
out_format_is_json(void)134 int out_format_is_json(void)
135 {
136 	return out_format_json;
137 }
138 
get_physical_package_id(int cpu)139 int get_physical_package_id(int cpu)
140 {
141 	return parse_int_file(
142 		0, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id",
143 		cpu);
144 }
145 
get_physical_core_id(int cpu)146 int get_physical_core_id(int cpu)
147 {
148 	return parse_int_file(
149 		0, "/sys/devices/system/cpu/cpu%d/topology/core_id", cpu);
150 }
151 
get_physical_die_id(int cpu)152 int get_physical_die_id(int cpu)
153 {
154 	int ret;
155 
156 	ret = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/topology/die_id",
157 			     cpu);
158 	if (ret < 0)
159 		ret = 0;
160 
161 	return ret;
162 }
163 
get_topo_max_cpus(void)164 int get_topo_max_cpus(void)
165 {
166 	return topo_max_cpus;
167 }
168 
set_cpu_online_offline(int cpu,int state)169 static void set_cpu_online_offline(int cpu, int state)
170 {
171 	char buffer[128];
172 	int fd, ret;
173 
174 	snprintf(buffer, sizeof(buffer),
175 		 "/sys/devices/system/cpu/cpu%d/online", cpu);
176 
177 	fd = open(buffer, O_WRONLY);
178 	if (fd < 0)
179 		err(-1, "%s open failed", buffer);
180 
181 	if (state)
182 		ret = write(fd, "1\n", 2);
183 	else
184 		ret = write(fd, "0\n", 2);
185 
186 	if (ret == -1)
187 		perror("Online/Offline: Operation failed\n");
188 
189 	close(fd);
190 }
191 
192 #define MAX_PACKAGE_COUNT 8
193 #define MAX_DIE_PER_PACKAGE 2
for_each_online_package_in_set(void (* callback)(int,void *,void *,void *,void *),void * arg1,void * arg2,void * arg3,void * arg4)194 static void for_each_online_package_in_set(void (*callback)(int, void *, void *,
195 							    void *, void *),
196 					   void *arg1, void *arg2, void *arg3,
197 					   void *arg4)
198 {
199 	int max_packages[MAX_PACKAGE_COUNT * MAX_PACKAGE_COUNT];
200 	int pkg_index = 0, i;
201 
202 	memset(max_packages, 0xff, sizeof(max_packages));
203 	for (i = 0; i < topo_max_cpus; ++i) {
204 		int j, online, pkg_id, die_id = 0, skip = 0;
205 
206 		if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
207 			continue;
208 		if (i)
209 			online = parse_int_file(
210 				1, "/sys/devices/system/cpu/cpu%d/online", i);
211 		else
212 			online =
213 				1; /* online entry for CPU 0 needs some special configs */
214 
215 		die_id = get_physical_die_id(i);
216 		if (die_id < 0)
217 			die_id = 0;
218 		pkg_id = get_physical_package_id(i);
219 		/* Create an unique id for package, die combination to store */
220 		pkg_id = (MAX_PACKAGE_COUNT * pkg_id + die_id);
221 
222 		for (j = 0; j < pkg_index; ++j) {
223 			if (max_packages[j] == pkg_id) {
224 				skip = 1;
225 				break;
226 			}
227 		}
228 
229 		if (!skip && online && callback) {
230 			callback(i, arg1, arg2, arg3, arg4);
231 			max_packages[pkg_index++] = pkg_id;
232 		}
233 	}
234 }
235 
for_each_online_target_cpu_in_set(void (* callback)(int,void *,void *,void *,void *),void * arg1,void * arg2,void * arg3,void * arg4)236 static void for_each_online_target_cpu_in_set(
237 	void (*callback)(int, void *, void *, void *, void *), void *arg1,
238 	void *arg2, void *arg3, void *arg4)
239 {
240 	int i;
241 
242 	for (i = 0; i < topo_max_cpus; ++i) {
243 		int online;
244 
245 		if (!CPU_ISSET_S(i, target_cpumask_size, target_cpumask))
246 			continue;
247 		if (i)
248 			online = parse_int_file(
249 				1, "/sys/devices/system/cpu/cpu%d/online", i);
250 		else
251 			online =
252 				1; /* online entry for CPU 0 needs some special configs */
253 
254 		if (online && callback)
255 			callback(i, arg1, arg2, arg3, arg4);
256 	}
257 }
258 
259 #define BITMASK_SIZE 32
set_max_cpu_num(void)260 static void set_max_cpu_num(void)
261 {
262 	FILE *filep;
263 	unsigned long dummy;
264 
265 	topo_max_cpus = 0;
266 	filep = fopen_or_exit(
267 		"/sys/devices/system/cpu/cpu0/topology/thread_siblings", "r");
268 	while (fscanf(filep, "%lx,", &dummy) == 1)
269 		topo_max_cpus += BITMASK_SIZE;
270 	fclose(filep);
271 	topo_max_cpus--; /* 0 based */
272 
273 	debug_printf("max cpus %d\n", topo_max_cpus);
274 }
275 
alloc_cpu_set(cpu_set_t ** cpu_set)276 size_t alloc_cpu_set(cpu_set_t **cpu_set)
277 {
278 	cpu_set_t *_cpu_set;
279 	size_t size;
280 
281 	_cpu_set = CPU_ALLOC((topo_max_cpus + 1));
282 	if (_cpu_set == NULL)
283 		err(3, "CPU_ALLOC");
284 	size = CPU_ALLOC_SIZE((topo_max_cpus + 1));
285 	CPU_ZERO_S(size, _cpu_set);
286 
287 	*cpu_set = _cpu_set;
288 	return size;
289 }
290 
free_cpu_set(cpu_set_t * cpu_set)291 void free_cpu_set(cpu_set_t *cpu_set)
292 {
293 	CPU_FREE(cpu_set);
294 }
295 
296 static int cpu_cnt[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE];
set_cpu_present_cpu_mask(void)297 static void set_cpu_present_cpu_mask(void)
298 {
299 	size_t size;
300 	DIR *dir;
301 	int i;
302 
303 	size = alloc_cpu_set(&present_cpumask);
304 	present_cpumask_size = size;
305 	for (i = 0; i < topo_max_cpus; ++i) {
306 		char buffer[256];
307 
308 		snprintf(buffer, sizeof(buffer),
309 			 "/sys/devices/system/cpu/cpu%d", i);
310 		dir = opendir(buffer);
311 		if (dir) {
312 			int pkg_id, die_id;
313 
314 			CPU_SET_S(i, size, present_cpumask);
315 			die_id = get_physical_die_id(i);
316 			if (die_id < 0)
317 				die_id = 0;
318 
319 			pkg_id = get_physical_package_id(i);
320 			if (pkg_id < MAX_PACKAGE_COUNT &&
321 			    die_id < MAX_DIE_PER_PACKAGE)
322 				cpu_cnt[pkg_id][die_id]++;
323 		}
324 		closedir(dir);
325 	}
326 }
327 
get_cpu_count(int pkg_id,int die_id)328 int get_cpu_count(int pkg_id, int die_id)
329 {
330 	if (pkg_id < MAX_PACKAGE_COUNT && die_id < MAX_DIE_PER_PACKAGE)
331 		return cpu_cnt[pkg_id][die_id];
332 
333 	return 0;
334 }
335 
set_cpu_target_cpu_mask(void)336 static void set_cpu_target_cpu_mask(void)
337 {
338 	size_t size;
339 	int i;
340 
341 	size = alloc_cpu_set(&target_cpumask);
342 	target_cpumask_size = size;
343 	for (i = 0; i < max_target_cpus; ++i) {
344 		if (!CPU_ISSET_S(target_cpus[i], present_cpumask_size,
345 				 present_cpumask))
346 			continue;
347 
348 		CPU_SET_S(target_cpus[i], size, target_cpumask);
349 	}
350 }
351 
create_cpu_map(void)352 static void create_cpu_map(void)
353 {
354 	const char *pathname = "/dev/isst_interface";
355 	int i, fd = 0;
356 	struct isst_if_cpu_maps map;
357 
358 	cpu_map = malloc(sizeof(*cpu_map) * topo_max_cpus);
359 	if (!cpu_map)
360 		err(3, "cpumap");
361 
362 	fd = open(pathname, O_RDWR);
363 	if (fd < 0)
364 		err(-1, "%s open failed", pathname);
365 
366 	for (i = 0; i < topo_max_cpus; ++i) {
367 		if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
368 			continue;
369 
370 		map.cmd_count = 1;
371 		map.cpu_map[0].logical_cpu = i;
372 
373 		debug_printf(" map logical_cpu:%d\n",
374 			     map.cpu_map[0].logical_cpu);
375 		if (ioctl(fd, ISST_IF_GET_PHY_ID, &map) == -1) {
376 			perror("ISST_IF_GET_PHY_ID");
377 			fprintf(outf, "Error: map logical_cpu:%d\n",
378 				map.cpu_map[0].logical_cpu);
379 			continue;
380 		}
381 		cpu_map[i].core_id = get_physical_core_id(i);
382 		cpu_map[i].pkg_id = get_physical_package_id(i);
383 		cpu_map[i].die_id = get_physical_die_id(i);
384 		cpu_map[i].punit_cpu = map.cpu_map[0].physical_cpu;
385 		cpu_map[i].punit_cpu_core = (map.cpu_map[0].physical_cpu >>
386 					     1); // shift to get core id
387 
388 		debug_printf(
389 			"map logical_cpu:%d core: %d die:%d pkg:%d punit_cpu:%d punit_core:%d\n",
390 			i, cpu_map[i].core_id, cpu_map[i].die_id,
391 			cpu_map[i].pkg_id, cpu_map[i].punit_cpu,
392 			cpu_map[i].punit_cpu_core);
393 	}
394 
395 	if (fd)
396 		close(fd);
397 }
398 
find_logical_cpu(int pkg_id,int die_id,int punit_core_id)399 int find_logical_cpu(int pkg_id, int die_id, int punit_core_id)
400 {
401 	int i;
402 
403 	for (i = 0; i < topo_max_cpus; ++i) {
404 		if (cpu_map[i].pkg_id == pkg_id &&
405 		    cpu_map[i].die_id == die_id &&
406 		    cpu_map[i].punit_cpu_core == punit_core_id)
407 			return i;
408 	}
409 
410 	return -EINVAL;
411 }
412 
set_cpu_mask_from_punit_coremask(int cpu,unsigned long long core_mask,size_t core_cpumask_size,cpu_set_t * core_cpumask,int * cpu_cnt)413 void set_cpu_mask_from_punit_coremask(int cpu, unsigned long long core_mask,
414 				      size_t core_cpumask_size,
415 				      cpu_set_t *core_cpumask, int *cpu_cnt)
416 {
417 	int i, cnt = 0;
418 	int die_id, pkg_id;
419 
420 	*cpu_cnt = 0;
421 	die_id = get_physical_die_id(cpu);
422 	pkg_id = get_physical_package_id(cpu);
423 
424 	for (i = 0; i < 64; ++i) {
425 		if (core_mask & BIT(i)) {
426 			int j;
427 
428 			for (j = 0; j < topo_max_cpus; ++j) {
429 				if (!CPU_ISSET_S(j, present_cpumask_size, present_cpumask))
430 					continue;
431 
432 				if (cpu_map[j].pkg_id == pkg_id &&
433 				    cpu_map[j].die_id == die_id &&
434 				    cpu_map[j].punit_cpu_core == i) {
435 					CPU_SET_S(j, core_cpumask_size,
436 						  core_cpumask);
437 					++cnt;
438 				}
439 			}
440 		}
441 	}
442 
443 	*cpu_cnt = cnt;
444 }
445 
find_phy_core_num(int logical_cpu)446 int find_phy_core_num(int logical_cpu)
447 {
448 	if (logical_cpu < topo_max_cpus)
449 		return cpu_map[logical_cpu].punit_cpu_core;
450 
451 	return -EINVAL;
452 }
453 
isst_send_mmio_command(unsigned int cpu,unsigned int reg,int write,unsigned int * value)454 static int isst_send_mmio_command(unsigned int cpu, unsigned int reg, int write,
455 				  unsigned int *value)
456 {
457 	struct isst_if_io_regs io_regs;
458 	const char *pathname = "/dev/isst_interface";
459 	int cmd;
460 	int fd;
461 
462 	debug_printf("mmio_cmd cpu:%d reg:%d write:%d\n", cpu, reg, write);
463 
464 	fd = open(pathname, O_RDWR);
465 	if (fd < 0)
466 		err(-1, "%s open failed", pathname);
467 
468 	io_regs.req_count = 1;
469 	io_regs.io_reg[0].logical_cpu = cpu;
470 	io_regs.io_reg[0].reg = reg;
471 	cmd = ISST_IF_IO_CMD;
472 	if (write) {
473 		io_regs.io_reg[0].read_write = 1;
474 		io_regs.io_reg[0].value = *value;
475 	} else {
476 		io_regs.io_reg[0].read_write = 0;
477 	}
478 
479 	if (ioctl(fd, cmd, &io_regs) == -1) {
480 		perror("ISST_IF_IO_CMD");
481 		fprintf(outf, "Error: mmio_cmd cpu:%d reg:%x read_write:%x\n",
482 			cpu, reg, write);
483 	} else {
484 		if (!write)
485 			*value = io_regs.io_reg[0].value;
486 
487 		debug_printf(
488 			"mmio_cmd response: cpu:%d reg:%x rd_write:%x resp:%x\n",
489 			cpu, reg, write, *value);
490 	}
491 
492 	close(fd);
493 
494 	return 0;
495 }
496 
isst_send_mbox_command(unsigned int cpu,unsigned char command,unsigned char sub_command,unsigned int parameter,unsigned int req_data,unsigned int * resp)497 int isst_send_mbox_command(unsigned int cpu, unsigned char command,
498 			   unsigned char sub_command, unsigned int parameter,
499 			   unsigned int req_data, unsigned int *resp)
500 {
501 	const char *pathname = "/dev/isst_interface";
502 	int fd;
503 	struct isst_if_mbox_cmds mbox_cmds = { 0 };
504 
505 	debug_printf(
506 		"mbox_send: cpu:%d command:%x sub_command:%x parameter:%x req_data:%x\n",
507 		cpu, command, sub_command, parameter, req_data);
508 
509 	if (isst_platform_info.mmio_supported && command == CONFIG_CLOS) {
510 		unsigned int value;
511 		int write = 0;
512 		int clos_id, core_id, ret = 0;
513 
514 		debug_printf("CPU %d\n", cpu);
515 
516 		if (parameter & BIT(MBOX_CMD_WRITE_BIT)) {
517 			value = req_data;
518 			write = 1;
519 		}
520 
521 		switch (sub_command) {
522 		case CLOS_PQR_ASSOC:
523 			core_id = parameter & 0xff;
524 			ret = isst_send_mmio_command(
525 				cpu, PQR_ASSOC_OFFSET + core_id * 4, write,
526 				&value);
527 			if (!ret && !write)
528 				*resp = value;
529 			break;
530 		case CLOS_PM_CLOS:
531 			clos_id = parameter & 0x03;
532 			ret = isst_send_mmio_command(
533 				cpu, PM_CLOS_OFFSET + clos_id * 4, write,
534 				&value);
535 			if (!ret && !write)
536 				*resp = value;
537 			break;
538 		case CLOS_PM_QOS_CONFIG:
539 			ret = isst_send_mmio_command(cpu, PM_QOS_CONFIG_OFFSET,
540 						     write, &value);
541 			if (!ret && !write)
542 				*resp = value;
543 			break;
544 		case CLOS_STATUS:
545 			break;
546 		default:
547 			break;
548 		}
549 		return ret;
550 	}
551 
552 	mbox_cmds.cmd_count = 1;
553 	mbox_cmds.mbox_cmd[0].logical_cpu = cpu;
554 	mbox_cmds.mbox_cmd[0].command = command;
555 	mbox_cmds.mbox_cmd[0].sub_command = sub_command;
556 	mbox_cmds.mbox_cmd[0].parameter = parameter;
557 	mbox_cmds.mbox_cmd[0].req_data = req_data;
558 
559 	fd = open(pathname, O_RDWR);
560 	if (fd < 0)
561 		err(-1, "%s open failed", pathname);
562 
563 	if (ioctl(fd, ISST_IF_MBOX_COMMAND, &mbox_cmds) == -1) {
564 		perror("ISST_IF_MBOX_COMMAND");
565 		fprintf(outf,
566 			"Error: mbox_cmd cpu:%d command:%x sub_command:%x parameter:%x req_data:%x\n",
567 			cpu, command, sub_command, parameter, req_data);
568 	} else {
569 		*resp = mbox_cmds.mbox_cmd[0].resp_data;
570 		debug_printf(
571 			"mbox_cmd response: cpu:%d command:%x sub_command:%x parameter:%x req_data:%x resp:%x\n",
572 			cpu, command, sub_command, parameter, req_data, *resp);
573 	}
574 
575 	close(fd);
576 
577 	return 0;
578 }
579 
isst_send_msr_command(unsigned int cpu,unsigned int msr,int write,unsigned long long * req_resp)580 int isst_send_msr_command(unsigned int cpu, unsigned int msr, int write,
581 			  unsigned long long *req_resp)
582 {
583 	struct isst_if_msr_cmds msr_cmds;
584 	const char *pathname = "/dev/isst_interface";
585 	int fd;
586 
587 	fd = open(pathname, O_RDWR);
588 	if (fd < 0)
589 		err(-1, "%s open failed", pathname);
590 
591 	msr_cmds.cmd_count = 1;
592 	msr_cmds.msr_cmd[0].logical_cpu = cpu;
593 	msr_cmds.msr_cmd[0].msr = msr;
594 	msr_cmds.msr_cmd[0].read_write = write;
595 	if (write)
596 		msr_cmds.msr_cmd[0].data = *req_resp;
597 
598 	if (ioctl(fd, ISST_IF_MSR_COMMAND, &msr_cmds) == -1) {
599 		perror("ISST_IF_MSR_COMMAD");
600 		fprintf(outf, "Error: msr_cmd cpu:%d msr:%x read_write:%d\n",
601 			cpu, msr, write);
602 	} else {
603 		if (!write)
604 			*req_resp = msr_cmds.msr_cmd[0].data;
605 
606 		debug_printf(
607 			"msr_cmd response: cpu:%d msr:%x rd_write:%x resp:%llx %llx\n",
608 			cpu, msr, write, *req_resp, msr_cmds.msr_cmd[0].data);
609 	}
610 
611 	close(fd);
612 
613 	return 0;
614 }
615 
isst_fill_platform_info(void)616 static int isst_fill_platform_info(void)
617 {
618 	const char *pathname = "/dev/isst_interface";
619 	int fd;
620 
621 	fd = open(pathname, O_RDWR);
622 	if (fd < 0)
623 		err(-1, "%s open failed", pathname);
624 
625 	if (ioctl(fd, ISST_IF_GET_PLATFORM_INFO, &isst_platform_info) == -1) {
626 		perror("ISST_IF_GET_PLATFORM_INFO");
627 		close(fd);
628 		return -1;
629 	}
630 
631 	close(fd);
632 
633 	if (isst_platform_info.api_version > supported_api_ver) {
634 		printf("Incompatible API versions; Upgrade of tool is required\n");
635 		return -1;
636 	}
637 	return 0;
638 }
639 
isst_print_platform_information(void)640 static void isst_print_platform_information(void)
641 {
642 	struct isst_if_platform_info platform_info;
643 	const char *pathname = "/dev/isst_interface";
644 	int fd;
645 
646 	fd = open(pathname, O_RDWR);
647 	if (fd < 0)
648 		err(-1, "%s open failed", pathname);
649 
650 	if (ioctl(fd, ISST_IF_GET_PLATFORM_INFO, &platform_info) == -1) {
651 		perror("ISST_IF_GET_PLATFORM_INFO");
652 	} else {
653 		fprintf(outf, "Platform: API version : %d\n",
654 			platform_info.api_version);
655 		fprintf(outf, "Platform: Driver version : %d\n",
656 			platform_info.driver_version);
657 		fprintf(outf, "Platform: mbox supported : %d\n",
658 			platform_info.mbox_supported);
659 		fprintf(outf, "Platform: mmio supported : %d\n",
660 			platform_info.mmio_supported);
661 	}
662 
663 	close(fd);
664 
665 	exit(0);
666 }
667 
exec_on_get_ctdp_cpu(int cpu,void * arg1,void * arg2,void * arg3,void * arg4)668 static void exec_on_get_ctdp_cpu(int cpu, void *arg1, void *arg2, void *arg3,
669 				 void *arg4)
670 {
671 	int (*fn_ptr)(int cpu, void *arg);
672 	int ret;
673 
674 	fn_ptr = arg1;
675 	ret = fn_ptr(cpu, arg2);
676 	if (ret)
677 		perror("get_tdp_*");
678 	else
679 		isst_ctdp_display_core_info(cpu, outf, arg3,
680 					    *(unsigned int *)arg4);
681 }
682 
683 #define _get_tdp_level(desc, suffix, object, help)                                \
684 	static void get_tdp_##object(void)                                        \
685 	{                                                                         \
686 		struct isst_pkg_ctdp ctdp;                                        \
687 \
688 		if (cmd_help) {                                                   \
689 			fprintf(stderr,                                           \
690 				"Print %s [No command arguments are required]\n", \
691 				help);                                            \
692 			exit(0);                                                  \
693 		}                                                                 \
694 		isst_ctdp_display_information_start(outf);                        \
695 		if (max_target_cpus)                                              \
696 			for_each_online_target_cpu_in_set(                        \
697 				exec_on_get_ctdp_cpu, isst_get_ctdp_##suffix,     \
698 				&ctdp, desc, &ctdp.object);                       \
699 		else                                                              \
700 			for_each_online_package_in_set(exec_on_get_ctdp_cpu,      \
701 						       isst_get_ctdp_##suffix,    \
702 						       &ctdp, desc,               \
703 						       &ctdp.object);             \
704 		isst_ctdp_display_information_end(outf);                          \
705 	}
706 
707 _get_tdp_level("get-config-levels", levels, levels, "TDP levels");
708 _get_tdp_level("get-config-version", levels, version, "TDP version");
709 _get_tdp_level("get-config-enabled", levels, enabled, "TDP enable status");
710 _get_tdp_level("get-config-current_level", levels, current_level,
711 	       "Current TDP Level");
712 _get_tdp_level("get-lock-status", levels, locked, "TDP lock status");
713 
dump_isst_config_for_cpu(int cpu,void * arg1,void * arg2,void * arg3,void * arg4)714 static void dump_isst_config_for_cpu(int cpu, void *arg1, void *arg2,
715 				     void *arg3, void *arg4)
716 {
717 	struct isst_pkg_ctdp pkg_dev;
718 	int ret;
719 
720 	memset(&pkg_dev, 0, sizeof(pkg_dev));
721 	ret = isst_get_process_ctdp(cpu, tdp_level, &pkg_dev);
722 	if (ret) {
723 		perror("isst_get_process_ctdp");
724 	} else {
725 		isst_ctdp_display_information(cpu, outf, tdp_level, &pkg_dev);
726 		isst_get_process_ctdp_complete(cpu, &pkg_dev);
727 	}
728 }
729 
dump_isst_config(void)730 static void dump_isst_config(void)
731 {
732 	if (cmd_help) {
733 		fprintf(stderr,
734 			"Print Intel(R) Speed Select Technology Performance profile configuration\n");
735 		fprintf(stderr,
736 			"including base frequency and turbo frequency configurations\n");
737 		fprintf(stderr, "Optional: -l|--level : Specify tdp level\n");
738 		fprintf(stderr,
739 			"\tIf no arguments, dump information for all TDP levels\n");
740 		exit(0);
741 	}
742 
743 	isst_ctdp_display_information_start(outf);
744 
745 	if (max_target_cpus)
746 		for_each_online_target_cpu_in_set(dump_isst_config_for_cpu,
747 						  NULL, NULL, NULL, NULL);
748 	else
749 		for_each_online_package_in_set(dump_isst_config_for_cpu, NULL,
750 					       NULL, NULL, NULL);
751 
752 	isst_ctdp_display_information_end(outf);
753 }
754 
set_tdp_level_for_cpu(int cpu,void * arg1,void * arg2,void * arg3,void * arg4)755 static void set_tdp_level_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
756 				  void *arg4)
757 {
758 	int ret;
759 
760 	ret = isst_set_tdp_level(cpu, tdp_level);
761 	if (ret)
762 		perror("set_tdp_level_for_cpu");
763 	else {
764 		isst_display_result(cpu, outf, "perf-profile", "set_tdp_level",
765 				    ret);
766 		if (force_online_offline) {
767 			struct isst_pkg_ctdp_level_info ctdp_level;
768 			int pkg_id = get_physical_package_id(cpu);
769 			int die_id = get_physical_die_id(cpu);
770 
771 			fprintf(stderr, "Option is set to online/offline\n");
772 			ctdp_level.core_cpumask_size =
773 				alloc_cpu_set(&ctdp_level.core_cpumask);
774 			isst_get_coremask_info(cpu, tdp_level, &ctdp_level);
775 			if (ctdp_level.cpu_count) {
776 				int i, max_cpus = get_topo_max_cpus();
777 				for (i = 0; i < max_cpus; ++i) {
778 					if (pkg_id != get_physical_package_id(i) || die_id != get_physical_die_id(i))
779 						continue;
780 					if (CPU_ISSET_S(i, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask)) {
781 						fprintf(stderr, "online cpu %d\n", i);
782 						set_cpu_online_offline(i, 1);
783 					} else {
784 						fprintf(stderr, "offline cpu %d\n", i);
785 						set_cpu_online_offline(i, 0);
786 					}
787 				}
788 			}
789 		}
790 	}
791 }
792 
set_tdp_level(void)793 static void set_tdp_level(void)
794 {
795 	if (cmd_help) {
796 		fprintf(stderr, "Set Config TDP level\n");
797 		fprintf(stderr,
798 			"\t Arguments: -l|--level : Specify tdp level\n");
799 		fprintf(stderr,
800 			"\t Optional Arguments: -o | online : online/offline for the tdp level\n");
801 		exit(0);
802 	}
803 
804 	if (tdp_level == 0xff) {
805 		fprintf(outf, "Invalid command: specify tdp_level\n");
806 		exit(1);
807 	}
808 	isst_ctdp_display_information_start(outf);
809 	if (max_target_cpus)
810 		for_each_online_target_cpu_in_set(set_tdp_level_for_cpu, NULL,
811 						  NULL, NULL, NULL);
812 	else
813 		for_each_online_package_in_set(set_tdp_level_for_cpu, NULL,
814 					       NULL, NULL, NULL);
815 	isst_ctdp_display_information_end(outf);
816 }
817 
dump_pbf_config_for_cpu(int cpu,void * arg1,void * arg2,void * arg3,void * arg4)818 static void dump_pbf_config_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
819 				    void *arg4)
820 {
821 	struct isst_pbf_info pbf_info;
822 	int ret;
823 
824 	ret = isst_get_pbf_info(cpu, tdp_level, &pbf_info);
825 	if (ret) {
826 		perror("isst_get_pbf_info");
827 	} else {
828 		isst_pbf_display_information(cpu, outf, tdp_level, &pbf_info);
829 		isst_get_pbf_info_complete(&pbf_info);
830 	}
831 }
832 
dump_pbf_config(void)833 static void dump_pbf_config(void)
834 {
835 	if (cmd_help) {
836 		fprintf(stderr,
837 			"Print Intel(R) Speed Select Technology base frequency configuration for a TDP level\n");
838 		fprintf(stderr,
839 			"\tArguments: -l|--level : Specify tdp level\n");
840 		exit(0);
841 	}
842 
843 	if (tdp_level == 0xff) {
844 		fprintf(outf, "Invalid command: specify tdp_level\n");
845 		exit(1);
846 	}
847 
848 	isst_ctdp_display_information_start(outf);
849 	if (max_target_cpus)
850 		for_each_online_target_cpu_in_set(dump_pbf_config_for_cpu, NULL,
851 						  NULL, NULL, NULL);
852 	else
853 		for_each_online_package_in_set(dump_pbf_config_for_cpu, NULL,
854 					       NULL, NULL, NULL);
855 	isst_ctdp_display_information_end(outf);
856 }
857 
set_pbf_for_cpu(int cpu,void * arg1,void * arg2,void * arg3,void * arg4)858 static void set_pbf_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
859 			    void *arg4)
860 {
861 	int ret;
862 	int status = *(int *)arg4;
863 
864 	ret = isst_set_pbf_fact_status(cpu, 1, status);
865 	if (ret) {
866 		perror("isst_set_pbf");
867 	} else {
868 		if (status)
869 			isst_display_result(cpu, outf, "base-freq", "enable",
870 					    ret);
871 		else
872 			isst_display_result(cpu, outf, "base-freq", "disable",
873 					    ret);
874 	}
875 }
876 
set_pbf_enable(void)877 static void set_pbf_enable(void)
878 {
879 	int status = 1;
880 
881 	if (cmd_help) {
882 		fprintf(stderr,
883 			"Enable Intel Speed Select Technology base frequency feature [No command arguments are required]\n");
884 		exit(0);
885 	}
886 
887 	isst_ctdp_display_information_start(outf);
888 	if (max_target_cpus)
889 		for_each_online_target_cpu_in_set(set_pbf_for_cpu, NULL, NULL,
890 						  NULL, &status);
891 	else
892 		for_each_online_package_in_set(set_pbf_for_cpu, NULL, NULL,
893 					       NULL, &status);
894 	isst_ctdp_display_information_end(outf);
895 }
896 
set_pbf_disable(void)897 static void set_pbf_disable(void)
898 {
899 	int status = 0;
900 
901 	if (cmd_help) {
902 		fprintf(stderr,
903 			"Disable Intel Speed Select Technology base frequency feature [No command arguments are required]\n");
904 		exit(0);
905 	}
906 
907 	isst_ctdp_display_information_start(outf);
908 	if (max_target_cpus)
909 		for_each_online_target_cpu_in_set(set_pbf_for_cpu, NULL, NULL,
910 						  NULL, &status);
911 	else
912 		for_each_online_package_in_set(set_pbf_for_cpu, NULL, NULL,
913 					       NULL, &status);
914 	isst_ctdp_display_information_end(outf);
915 }
916 
dump_fact_config_for_cpu(int cpu,void * arg1,void * arg2,void * arg3,void * arg4)917 static void dump_fact_config_for_cpu(int cpu, void *arg1, void *arg2,
918 				     void *arg3, void *arg4)
919 {
920 	struct isst_fact_info fact_info;
921 	int ret;
922 
923 	ret = isst_get_fact_info(cpu, tdp_level, &fact_info);
924 	if (ret)
925 		perror("isst_get_fact_bucket_info");
926 	else
927 		isst_fact_display_information(cpu, outf, tdp_level, fact_bucket,
928 					      fact_avx, &fact_info);
929 }
930 
dump_fact_config(void)931 static void dump_fact_config(void)
932 {
933 	if (cmd_help) {
934 		fprintf(stderr,
935 			"Print complete Intel Speed Select Technology turbo frequency configuration for a TDP level. Other arguments are optional.\n");
936 		fprintf(stderr,
937 			"\tArguments: -l|--level : Specify tdp level\n");
938 		fprintf(stderr,
939 			"\tArguments: -b|--bucket : Bucket index to dump\n");
940 		fprintf(stderr,
941 			"\tArguments: -r|--trl-type : Specify trl type: sse|avx2|avx512\n");
942 		exit(0);
943 	}
944 
945 	if (tdp_level == 0xff) {
946 		fprintf(outf, "Invalid command: specify tdp_level\n");
947 		exit(1);
948 	}
949 
950 	isst_ctdp_display_information_start(outf);
951 	if (max_target_cpus)
952 		for_each_online_target_cpu_in_set(dump_fact_config_for_cpu,
953 						  NULL, NULL, NULL, NULL);
954 	else
955 		for_each_online_package_in_set(dump_fact_config_for_cpu, NULL,
956 					       NULL, NULL, NULL);
957 	isst_ctdp_display_information_end(outf);
958 }
959 
set_fact_for_cpu(int cpu,void * arg1,void * arg2,void * arg3,void * arg4)960 static void set_fact_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
961 			     void *arg4)
962 {
963 	int ret;
964 	int status = *(int *)arg4;
965 
966 	ret = isst_set_pbf_fact_status(cpu, 0, status);
967 	if (ret)
968 		perror("isst_set_fact");
969 	else {
970 		if (status) {
971 			struct isst_pkg_ctdp pkg_dev;
972 
973 			ret = isst_get_ctdp_levels(cpu, &pkg_dev);
974 			if (ret) {
975 				isst_display_result(cpu, outf, "turbo-freq",
976 						    "enable", ret);
977 				return;
978 			}
979 			ret = isst_set_trl(cpu, fact_trl);
980 			isst_display_result(cpu, outf, "turbo-freq", "enable",
981 					    ret);
982 		} else {
983 			/* Since we modified TRL during Fact enable, restore it */
984 			isst_set_trl_from_current_tdp(cpu, fact_trl);
985 			isst_display_result(cpu, outf, "turbo-freq", "disable",
986 					    ret);
987 		}
988 	}
989 }
990 
set_fact_enable(void)991 static void set_fact_enable(void)
992 {
993 	int status = 1;
994 
995 	if (cmd_help) {
996 		fprintf(stderr,
997 			"Enable Intel Speed Select Technology Turbo frequency feature\n");
998 		fprintf(stderr,
999 			"Optional: -t|--trl : Specify turbo ratio limit\n");
1000 		exit(0);
1001 	}
1002 
1003 	isst_ctdp_display_information_start(outf);
1004 	if (max_target_cpus)
1005 		for_each_online_target_cpu_in_set(set_fact_for_cpu, NULL, NULL,
1006 						  NULL, &status);
1007 	else
1008 		for_each_online_package_in_set(set_fact_for_cpu, NULL, NULL,
1009 					       NULL, &status);
1010 	isst_ctdp_display_information_end(outf);
1011 }
1012 
set_fact_disable(void)1013 static void set_fact_disable(void)
1014 {
1015 	int status = 0;
1016 
1017 	if (cmd_help) {
1018 		fprintf(stderr,
1019 			"Disable Intel Speed Select Technology turbo frequency feature\n");
1020 		fprintf(stderr,
1021 			"Optional: -t|--trl : Specify turbo ratio limit\n");
1022 		exit(0);
1023 	}
1024 
1025 	isst_ctdp_display_information_start(outf);
1026 	if (max_target_cpus)
1027 		for_each_online_target_cpu_in_set(set_fact_for_cpu, NULL, NULL,
1028 						  NULL, &status);
1029 	else
1030 		for_each_online_package_in_set(set_fact_for_cpu, NULL, NULL,
1031 					       NULL, &status);
1032 	isst_ctdp_display_information_end(outf);
1033 }
1034 
enable_clos_qos_config(int cpu,void * arg1,void * arg2,void * arg3,void * arg4)1035 static void enable_clos_qos_config(int cpu, void *arg1, void *arg2, void *arg3,
1036 				   void *arg4)
1037 {
1038 	int ret;
1039 	int status = *(int *)arg4;
1040 
1041 	ret = isst_pm_qos_config(cpu, status, clos_priority_type);
1042 	if (ret) {
1043 		perror("isst_pm_qos_config");
1044 	} else {
1045 		if (status)
1046 			isst_display_result(cpu, outf, "core-power", "enable",
1047 					    ret);
1048 		else
1049 			isst_display_result(cpu, outf, "core-power", "disable",
1050 					    ret);
1051 	}
1052 }
1053 
set_clos_enable(void)1054 static void set_clos_enable(void)
1055 {
1056 	int status = 1;
1057 
1058 	if (cmd_help) {
1059 		fprintf(stderr, "Enable core-power for a package/die\n");
1060 		fprintf(stderr,
1061 			"\tClos Enable: Specify priority type with [--priority|-p]\n");
1062 		fprintf(stderr, "\t\t 0: Proportional, 1: Ordered\n");
1063 		exit(0);
1064 	}
1065 
1066 	if (cpufreq_sysfs_present()) {
1067 		fprintf(stderr,
1068 			"cpufreq subsystem and core-power enable will interfere with each other!\n");
1069 	}
1070 
1071 	isst_ctdp_display_information_start(outf);
1072 	if (max_target_cpus)
1073 		for_each_online_target_cpu_in_set(enable_clos_qos_config, NULL,
1074 						  NULL, NULL, &status);
1075 	else
1076 		for_each_online_package_in_set(enable_clos_qos_config, NULL,
1077 					       NULL, NULL, &status);
1078 	isst_ctdp_display_information_end(outf);
1079 }
1080 
set_clos_disable(void)1081 static void set_clos_disable(void)
1082 {
1083 	int status = 0;
1084 
1085 	if (cmd_help) {
1086 		fprintf(stderr,
1087 			"Disable core-power: [No command arguments are required]\n");
1088 		exit(0);
1089 	}
1090 
1091 	isst_ctdp_display_information_start(outf);
1092 	if (max_target_cpus)
1093 		for_each_online_target_cpu_in_set(enable_clos_qos_config, NULL,
1094 						  NULL, NULL, &status);
1095 	else
1096 		for_each_online_package_in_set(enable_clos_qos_config, NULL,
1097 					       NULL, NULL, &status);
1098 	isst_ctdp_display_information_end(outf);
1099 }
1100 
dump_clos_config_for_cpu(int cpu,void * arg1,void * arg2,void * arg3,void * arg4)1101 static void dump_clos_config_for_cpu(int cpu, void *arg1, void *arg2,
1102 				     void *arg3, void *arg4)
1103 {
1104 	struct isst_clos_config clos_config;
1105 	int ret;
1106 
1107 	ret = isst_pm_get_clos(cpu, current_clos, &clos_config);
1108 	if (ret)
1109 		perror("isst_pm_get_clos");
1110 	else
1111 		isst_clos_display_information(cpu, outf, current_clos,
1112 					      &clos_config);
1113 }
1114 
dump_clos_config(void)1115 static void dump_clos_config(void)
1116 {
1117 	if (cmd_help) {
1118 		fprintf(stderr,
1119 			"Print Intel Speed Select Technology core power configuration\n");
1120 		fprintf(stderr,
1121 			"\tArguments: [-c | --clos]: Specify clos id\n");
1122 		exit(0);
1123 	}
1124 	if (current_clos < 0 || current_clos > 3) {
1125 		fprintf(stderr, "Invalid clos id\n");
1126 		exit(0);
1127 	}
1128 
1129 	isst_ctdp_display_information_start(outf);
1130 	if (max_target_cpus)
1131 		for_each_online_target_cpu_in_set(dump_clos_config_for_cpu,
1132 						  NULL, NULL, NULL, NULL);
1133 	else
1134 		for_each_online_package_in_set(dump_clos_config_for_cpu, NULL,
1135 					       NULL, NULL, NULL);
1136 	isst_ctdp_display_information_end(outf);
1137 }
1138 
get_clos_info_for_cpu(int cpu,void * arg1,void * arg2,void * arg3,void * arg4)1139 static void get_clos_info_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
1140 				  void *arg4)
1141 {
1142 	int enable, ret, prio_type;
1143 
1144 	ret = isst_clos_get_clos_information(cpu, &enable, &prio_type);
1145 	if (ret)
1146 		perror("isst_clos_get_info");
1147 	else
1148 		isst_clos_display_clos_information(cpu, outf, enable, prio_type);
1149 }
1150 
dump_clos_info(void)1151 static void dump_clos_info(void)
1152 {
1153 	if (cmd_help) {
1154 		fprintf(stderr,
1155 			"Print Intel Speed Select Technology core power information\n");
1156 		fprintf(stderr, "\tSpecify targeted cpu id with [--cpu|-c]\n");
1157 		exit(0);
1158 	}
1159 
1160 	if (!max_target_cpus) {
1161 		fprintf(stderr,
1162 			"Invalid target cpu. Specify with [-c|--cpu]\n");
1163 		exit(0);
1164 	}
1165 
1166 	isst_ctdp_display_information_start(outf);
1167 	for_each_online_target_cpu_in_set(get_clos_info_for_cpu, NULL,
1168 					  NULL, NULL, NULL);
1169 	isst_ctdp_display_information_end(outf);
1170 
1171 }
1172 
set_clos_config_for_cpu(int cpu,void * arg1,void * arg2,void * arg3,void * arg4)1173 static void set_clos_config_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
1174 				    void *arg4)
1175 {
1176 	struct isst_clos_config clos_config;
1177 	int ret;
1178 
1179 	clos_config.pkg_id = get_physical_package_id(cpu);
1180 	clos_config.die_id = get_physical_die_id(cpu);
1181 
1182 	clos_config.epp = clos_epp;
1183 	clos_config.clos_prop_prio = clos_prop_prio;
1184 	clos_config.clos_min = clos_min;
1185 	clos_config.clos_max = clos_max;
1186 	clos_config.clos_desired = clos_desired;
1187 	ret = isst_set_clos(cpu, current_clos, &clos_config);
1188 	if (ret)
1189 		perror("isst_set_clos");
1190 	else
1191 		isst_display_result(cpu, outf, "core-power", "config", ret);
1192 }
1193 
set_clos_config(void)1194 static void set_clos_config(void)
1195 {
1196 	if (cmd_help) {
1197 		fprintf(stderr,
1198 			"Set core-power configuration for one of the four clos ids\n");
1199 		fprintf(stderr,
1200 			"\tSpecify targeted clos id with [--clos|-c]\n");
1201 		fprintf(stderr, "\tSpecify clos EPP with [--epp|-e]\n");
1202 		fprintf(stderr,
1203 			"\tSpecify clos Proportional Priority [--weight|-w]\n");
1204 		fprintf(stderr, "\tSpecify clos min with [--min|-n]\n");
1205 		fprintf(stderr, "\tSpecify clos max with [--max|-m]\n");
1206 		fprintf(stderr, "\tSpecify clos desired with [--desired|-d]\n");
1207 		exit(0);
1208 	}
1209 
1210 	if (current_clos < 0 || current_clos > 3) {
1211 		fprintf(stderr, "Invalid clos id\n");
1212 		exit(0);
1213 	}
1214 	if (clos_epp < 0 || clos_epp > 0x0F) {
1215 		fprintf(stderr, "clos epp is not specified, default: 0\n");
1216 		clos_epp = 0;
1217 	}
1218 	if (clos_prop_prio < 0 || clos_prop_prio > 0x0F) {
1219 		fprintf(stderr,
1220 			"clos frequency weight is not specified, default: 0\n");
1221 		clos_prop_prio = 0;
1222 	}
1223 	if (clos_min < 0) {
1224 		fprintf(stderr, "clos min is not specified, default: 0\n");
1225 		clos_min = 0;
1226 	}
1227 	if (clos_max < 0) {
1228 		fprintf(stderr, "clos max is not specified, default: 0xff\n");
1229 		clos_max = 0xff;
1230 	}
1231 	if (clos_desired < 0) {
1232 		fprintf(stderr, "clos desired is not specified, default: 0\n");
1233 		clos_desired = 0x00;
1234 	}
1235 
1236 	isst_ctdp_display_information_start(outf);
1237 	if (max_target_cpus)
1238 		for_each_online_target_cpu_in_set(set_clos_config_for_cpu, NULL,
1239 						  NULL, NULL, NULL);
1240 	else
1241 		for_each_online_package_in_set(set_clos_config_for_cpu, NULL,
1242 					       NULL, NULL, NULL);
1243 	isst_ctdp_display_information_end(outf);
1244 }
1245 
set_clos_assoc_for_cpu(int cpu,void * arg1,void * arg2,void * arg3,void * arg4)1246 static void set_clos_assoc_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
1247 				   void *arg4)
1248 {
1249 	int ret;
1250 
1251 	ret = isst_clos_associate(cpu, current_clos);
1252 	if (ret)
1253 		perror("isst_clos_associate");
1254 	else
1255 		isst_display_result(cpu, outf, "core-power", "assoc", ret);
1256 }
1257 
set_clos_assoc(void)1258 static void set_clos_assoc(void)
1259 {
1260 	if (cmd_help) {
1261 		fprintf(stderr, "Associate a clos id to a CPU\n");
1262 		fprintf(stderr,
1263 			"\tSpecify targeted clos id with [--clos|-c]\n");
1264 		exit(0);
1265 	}
1266 
1267 	if (current_clos < 0 || current_clos > 3) {
1268 		fprintf(stderr, "Invalid clos id\n");
1269 		exit(0);
1270 	}
1271 	if (max_target_cpus)
1272 		for_each_online_target_cpu_in_set(set_clos_assoc_for_cpu, NULL,
1273 						  NULL, NULL, NULL);
1274 	else {
1275 		fprintf(stderr,
1276 			"Invalid target cpu. Specify with [-c|--cpu]\n");
1277 	}
1278 }
1279 
get_clos_assoc_for_cpu(int cpu,void * arg1,void * arg2,void * arg3,void * arg4)1280 static void get_clos_assoc_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
1281 				   void *arg4)
1282 {
1283 	int clos, ret;
1284 
1285 	ret = isst_clos_get_assoc_status(cpu, &clos);
1286 	if (ret)
1287 		perror("isst_clos_get_assoc_status");
1288 	else
1289 		isst_clos_display_assoc_information(cpu, outf, clos);
1290 }
1291 
get_clos_assoc(void)1292 static void get_clos_assoc(void)
1293 {
1294 	if (cmd_help) {
1295 		fprintf(stderr, "Get associate clos id to a CPU\n");
1296 		fprintf(stderr, "\tSpecify targeted cpu id with [--cpu|-c]\n");
1297 		exit(0);
1298 	}
1299 
1300 	if (!max_target_cpus) {
1301 		fprintf(stderr,
1302 			"Invalid target cpu. Specify with [-c|--cpu]\n");
1303 		exit(0);
1304 	}
1305 
1306 	isst_ctdp_display_information_start(outf);
1307 	for_each_online_target_cpu_in_set(get_clos_assoc_for_cpu, NULL,
1308 					  NULL, NULL, NULL);
1309 	isst_ctdp_display_information_end(outf);
1310 }
1311 
1312 static struct process_cmd_struct isst_cmds[] = {
1313 	{ "perf-profile", "get-lock-status", get_tdp_locked },
1314 	{ "perf-profile", "get-config-levels", get_tdp_levels },
1315 	{ "perf-profile", "get-config-version", get_tdp_version },
1316 	{ "perf-profile", "get-config-enabled", get_tdp_enabled },
1317 	{ "perf-profile", "get-config-current-level", get_tdp_current_level },
1318 	{ "perf-profile", "set-config-level", set_tdp_level },
1319 	{ "perf-profile", "info", dump_isst_config },
1320 	{ "base-freq", "info", dump_pbf_config },
1321 	{ "base-freq", "enable", set_pbf_enable },
1322 	{ "base-freq", "disable", set_pbf_disable },
1323 	{ "turbo-freq", "info", dump_fact_config },
1324 	{ "turbo-freq", "enable", set_fact_enable },
1325 	{ "turbo-freq", "disable", set_fact_disable },
1326 	{ "core-power", "info", dump_clos_info },
1327 	{ "core-power", "enable", set_clos_enable },
1328 	{ "core-power", "disable", set_clos_disable },
1329 	{ "core-power", "config", set_clos_config },
1330 	{ "core-power", "get-config", dump_clos_config },
1331 	{ "core-power", "assoc", set_clos_assoc },
1332 	{ "core-power", "get-assoc", get_clos_assoc },
1333 	{ NULL, NULL, NULL }
1334 };
1335 
1336 /*
1337  * parse cpuset with following syntax
1338  * 1,2,4..6,8-10 and set bits in cpu_subset
1339  */
parse_cpu_command(char * optarg)1340 void parse_cpu_command(char *optarg)
1341 {
1342 	unsigned int start, end;
1343 	char *next;
1344 
1345 	next = optarg;
1346 
1347 	while (next && *next) {
1348 		if (*next == '-') /* no negative cpu numbers */
1349 			goto error;
1350 
1351 		start = strtoul(next, &next, 10);
1352 
1353 		if (max_target_cpus < MAX_CPUS_IN_ONE_REQ)
1354 			target_cpus[max_target_cpus++] = start;
1355 
1356 		if (*next == '\0')
1357 			break;
1358 
1359 		if (*next == ',') {
1360 			next += 1;
1361 			continue;
1362 		}
1363 
1364 		if (*next == '-') {
1365 			next += 1; /* start range */
1366 		} else if (*next == '.') {
1367 			next += 1;
1368 			if (*next == '.')
1369 				next += 1; /* start range */
1370 			else
1371 				goto error;
1372 		}
1373 
1374 		end = strtoul(next, &next, 10);
1375 		if (end <= start)
1376 			goto error;
1377 
1378 		while (++start <= end) {
1379 			if (max_target_cpus < MAX_CPUS_IN_ONE_REQ)
1380 				target_cpus[max_target_cpus++] = start;
1381 		}
1382 
1383 		if (*next == ',')
1384 			next += 1;
1385 		else if (*next != '\0')
1386 			goto error;
1387 	}
1388 
1389 #ifdef DEBUG
1390 	{
1391 		int i;
1392 
1393 		for (i = 0; i < max_target_cpus; ++i)
1394 			printf("cpu [%d] in arg\n", target_cpus[i]);
1395 	}
1396 #endif
1397 	return;
1398 
1399 error:
1400 	fprintf(stderr, "\"--cpu %s\" malformed\n", optarg);
1401 	exit(-1);
1402 }
1403 
parse_cmd_args(int argc,int start,char ** argv)1404 static void parse_cmd_args(int argc, int start, char **argv)
1405 {
1406 	int opt;
1407 	int option_index;
1408 
1409 	static struct option long_options[] = {
1410 		{ "bucket", required_argument, 0, 'b' },
1411 		{ "level", required_argument, 0, 'l' },
1412 		{ "online", required_argument, 0, 'o' },
1413 		{ "trl-type", required_argument, 0, 'r' },
1414 		{ "trl", required_argument, 0, 't' },
1415 		{ "help", no_argument, 0, 'h' },
1416 		{ "clos", required_argument, 0, 'c' },
1417 		{ "desired", required_argument, 0, 'd' },
1418 		{ "epp", required_argument, 0, 'e' },
1419 		{ "min", required_argument, 0, 'n' },
1420 		{ "max", required_argument, 0, 'm' },
1421 		{ "priority", required_argument, 0, 'p' },
1422 		{ "weight", required_argument, 0, 'w' },
1423 		{ 0, 0, 0, 0 }
1424 	};
1425 
1426 	option_index = start;
1427 
1428 	optind = start + 1;
1429 	while ((opt = getopt_long(argc, argv, "b:l:t:c:d:e:n:m:p:w:ho",
1430 				  long_options, &option_index)) != -1) {
1431 		switch (opt) {
1432 		case 'b':
1433 			fact_bucket = atoi(optarg);
1434 			break;
1435 		case 'h':
1436 			cmd_help = 1;
1437 			break;
1438 		case 'l':
1439 			tdp_level = atoi(optarg);
1440 			break;
1441 		case 'o':
1442 			force_online_offline = 1;
1443 			break;
1444 		case 't':
1445 			sscanf(optarg, "0x%llx", &fact_trl);
1446 			break;
1447 		case 'r':
1448 			if (!strncmp(optarg, "sse", 3)) {
1449 				fact_avx = 0x01;
1450 			} else if (!strncmp(optarg, "avx2", 4)) {
1451 				fact_avx = 0x02;
1452 			} else if (!strncmp(optarg, "avx512", 4)) {
1453 				fact_avx = 0x04;
1454 			} else {
1455 				fprintf(outf, "Invalid sse,avx options\n");
1456 				exit(1);
1457 			}
1458 			break;
1459 		/* CLOS related */
1460 		case 'c':
1461 			current_clos = atoi(optarg);
1462 			break;
1463 		case 'd':
1464 			clos_desired = atoi(optarg);
1465 			break;
1466 		case 'e':
1467 			clos_epp = atoi(optarg);
1468 			break;
1469 		case 'n':
1470 			clos_min = atoi(optarg);
1471 			break;
1472 		case 'm':
1473 			clos_max = atoi(optarg);
1474 			break;
1475 		case 'p':
1476 			clos_priority_type = atoi(optarg);
1477 			break;
1478 		case 'w':
1479 			clos_prop_prio = atoi(optarg);
1480 			break;
1481 		default:
1482 			printf("no match\n");
1483 		}
1484 	}
1485 }
1486 
isst_help(void)1487 static void isst_help(void)
1488 {
1489 	printf("perf-profile:\tAn architectural mechanism that allows multiple optimized \n\
1490 		performance profiles per system via static and/or dynamic\n\
1491 		adjustment of core count, workload, Tjmax, and\n\
1492 		TDP, etc.\n");
1493 	printf("\nCommands : For feature=perf-profile\n");
1494 	printf("\tinfo\n");
1495 	printf("\tget-lock-status\n");
1496 	printf("\tget-config-levels\n");
1497 	printf("\tget-config-version\n");
1498 	printf("\tget-config-enabled\n");
1499 	printf("\tget-config-current-level\n");
1500 	printf("\tset-config-level\n");
1501 }
1502 
pbf_help(void)1503 static void pbf_help(void)
1504 {
1505 	printf("base-freq:\tEnables users to increase guaranteed base frequency\n\
1506 		on certain cores (high priority cores) in exchange for lower\n\
1507 		base frequency on remaining cores (low priority cores).\n");
1508 	printf("\tcommand : info\n");
1509 	printf("\tcommand : enable\n");
1510 	printf("\tcommand : disable\n");
1511 }
1512 
fact_help(void)1513 static void fact_help(void)
1514 {
1515 	printf("turbo-freq:\tEnables the ability to set different turbo ratio\n\
1516 		limits to cores based on priority.\n");
1517 	printf("\nCommand: For feature=turbo-freq\n");
1518 	printf("\tcommand : info\n");
1519 	printf("\tcommand : enable\n");
1520 	printf("\tcommand : disable\n");
1521 }
1522 
core_power_help(void)1523 static void core_power_help(void)
1524 {
1525 	printf("core-power:\tInterface that allows user to define per core/tile\n\
1526 		priority.\n");
1527 	printf("\nCommands : For feature=core-power\n");
1528 	printf("\tinfo\n");
1529 	printf("\tenable\n");
1530 	printf("\tdisable\n");
1531 	printf("\tconfig\n");
1532 	printf("\tget-config\n");
1533 	printf("\tassoc\n");
1534 	printf("\tget-assoc\n");
1535 }
1536 
1537 struct process_cmd_help_struct {
1538 	char *feature;
1539 	void (*process_fn)(void);
1540 };
1541 
1542 static struct process_cmd_help_struct isst_help_cmds[] = {
1543 	{ "perf-profile", isst_help },
1544 	{ "base-freq", pbf_help },
1545 	{ "turbo-freq", fact_help },
1546 	{ "core-power", core_power_help },
1547 	{ NULL, NULL }
1548 };
1549 
process_command(int argc,char ** argv)1550 void process_command(int argc, char **argv)
1551 {
1552 	int i = 0, matched = 0;
1553 	char *feature = argv[optind];
1554 	char *cmd = argv[optind + 1];
1555 
1556 	if (!feature || !cmd)
1557 		return;
1558 
1559 	debug_printf("feature name [%s] command [%s]\n", feature, cmd);
1560 	if (!strcmp(cmd, "-h") || !strcmp(cmd, "--help")) {
1561 		while (isst_help_cmds[i].feature) {
1562 			if (!strcmp(isst_help_cmds[i].feature, feature)) {
1563 				isst_help_cmds[i].process_fn();
1564 				exit(0);
1565 			}
1566 			++i;
1567 		}
1568 	}
1569 
1570 	create_cpu_map();
1571 
1572 	i = 0;
1573 	while (isst_cmds[i].feature) {
1574 		if (!strcmp(isst_cmds[i].feature, feature) &&
1575 		    !strcmp(isst_cmds[i].command, cmd)) {
1576 			parse_cmd_args(argc, optind + 1, argv);
1577 			isst_cmds[i].process_fn();
1578 			matched = 1;
1579 			break;
1580 		}
1581 		++i;
1582 	}
1583 
1584 	if (!matched)
1585 		fprintf(stderr, "Invalid command\n");
1586 }
1587 
usage(void)1588 static void usage(void)
1589 {
1590 	printf("Intel(R) Speed Select Technology\n");
1591 	printf("\nUsage:\n");
1592 	printf("intel-speed-select [OPTIONS] FEATURE COMMAND COMMAND_ARGUMENTS\n");
1593 	printf("\nUse this tool to enumerate and control the Intel Speed Select Technology features,\n");
1594 	printf("\nFEATURE : [perf-profile|base-freq|turbo-freq|core-power]\n");
1595 	printf("\nFor help on each feature, use -h|--help\n");
1596 	printf("\tFor example:  intel-speed-select perf-profile -h\n");
1597 
1598 	printf("\nFor additional help on each command for a feature, use --h|--help\n");
1599 	printf("\tFor example:  intel-speed-select perf-profile get-lock-status -h\n");
1600 	printf("\t\t This will print help for the command \"get-lock-status\" for the feature \"perf-profile\"\n");
1601 
1602 	printf("\nOPTIONS\n");
1603 	printf("\t[-c|--cpu] : logical cpu number\n");
1604 	printf("\t\tDefault: Die scoped for all dies in the system with multiple dies/package\n");
1605 	printf("\t\t\t Or Package scoped for all Packages when each package contains one die\n");
1606 	printf("\t[-d|--debug] : Debug mode\n");
1607 	printf("\t[-h|--help] : Print help\n");
1608 	printf("\t[-i|--info] : Print platform information\n");
1609 	printf("\t[-o|--out] : Output file\n");
1610 	printf("\t\t\tDefault : stderr\n");
1611 	printf("\t[-f|--format] : output format [json|text]. Default: text\n");
1612 	printf("\t[-v|--version] : Print version\n");
1613 
1614 	printf("\nResult format\n");
1615 	printf("\tResult display uses a common format for each command:\n");
1616 	printf("\tResults are formatted in text/JSON with\n");
1617 	printf("\t\tPackage, Die, CPU, and command specific results.\n");
1618 	exit(1);
1619 }
1620 
print_version(void)1621 static void print_version(void)
1622 {
1623 	fprintf(outf, "Version %s\n", version_str);
1624 	fprintf(outf, "Build date %s time %s\n", __DATE__, __TIME__);
1625 	exit(0);
1626 }
1627 
cmdline(int argc,char ** argv)1628 static void cmdline(int argc, char **argv)
1629 {
1630 	int opt;
1631 	int option_index = 0;
1632 	int ret;
1633 
1634 	static struct option long_options[] = {
1635 		{ "cpu", required_argument, 0, 'c' },
1636 		{ "debug", no_argument, 0, 'd' },
1637 		{ "format", required_argument, 0, 'f' },
1638 		{ "help", no_argument, 0, 'h' },
1639 		{ "info", no_argument, 0, 'i' },
1640 		{ "out", required_argument, 0, 'o' },
1641 		{ "version", no_argument, 0, 'v' },
1642 		{ 0, 0, 0, 0 }
1643 	};
1644 
1645 	progname = argv[0];
1646 	while ((opt = getopt_long_only(argc, argv, "+c:df:hio:v", long_options,
1647 				       &option_index)) != -1) {
1648 		switch (opt) {
1649 		case 'c':
1650 			parse_cpu_command(optarg);
1651 			break;
1652 		case 'd':
1653 			debug_flag = 1;
1654 			printf("Debug Mode ON\n");
1655 			break;
1656 		case 'f':
1657 			if (!strncmp(optarg, "json", 4))
1658 				out_format_json = 1;
1659 			break;
1660 		case 'h':
1661 			usage();
1662 			break;
1663 		case 'i':
1664 			isst_print_platform_information();
1665 			break;
1666 		case 'o':
1667 			if (outf)
1668 				fclose(outf);
1669 			outf = fopen_or_exit(optarg, "w");
1670 			break;
1671 		case 'v':
1672 			print_version();
1673 			break;
1674 		default:
1675 			usage();
1676 		}
1677 	}
1678 
1679 	if (geteuid() != 0) {
1680 		fprintf(stderr, "Must run as root\n");
1681 		exit(0);
1682 	}
1683 
1684 	if (optind > (argc - 2)) {
1685 		fprintf(stderr, "Feature name and|or command not specified\n");
1686 		exit(0);
1687 	}
1688 	update_cpu_model();
1689 	printf("Intel(R) Speed Select Technology\n");
1690 	printf("Executing on CPU model:%d[0x%x]\n", cpu_model, cpu_model);
1691 	set_max_cpu_num();
1692 	set_cpu_present_cpu_mask();
1693 	set_cpu_target_cpu_mask();
1694 	ret = isst_fill_platform_info();
1695 	if (ret)
1696 		goto out;
1697 
1698 	process_command(argc, argv);
1699 out:
1700 	free_cpu_set(present_cpumask);
1701 	free_cpu_set(target_cpumask);
1702 }
1703 
main(int argc,char ** argv)1704 int main(int argc, char **argv)
1705 {
1706 	outf = stderr;
1707 	cmdline(argc, argv);
1708 	return 0;
1709 }
1710