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