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] + 1;
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 	return 0;
607 }
608 
609 static void isst_print_platform_information(void)
610 {
611 	struct isst_if_platform_info platform_info;
612 	const char *pathname = "/dev/isst_interface";
613 	int fd;
614 
615 	fd = open(pathname, O_RDWR);
616 	if (fd < 0)
617 		err(-1, "%s open failed", pathname);
618 
619 	if (ioctl(fd, ISST_IF_GET_PLATFORM_INFO, &platform_info) == -1) {
620 		perror("ISST_IF_GET_PLATFORM_INFO");
621 	} else {
622 		fprintf(outf, "Platform: API version : %d\n",
623 			platform_info.api_version);
624 		fprintf(outf, "Platform: Driver version : %d\n",
625 			platform_info.driver_version);
626 		fprintf(outf, "Platform: mbox supported : %d\n",
627 			platform_info.mbox_supported);
628 		fprintf(outf, "Platform: mmio supported : %d\n",
629 			platform_info.mmio_supported);
630 	}
631 
632 	close(fd);
633 
634 	exit(0);
635 }
636 
637 static void exec_on_get_ctdp_cpu(int cpu, void *arg1, void *arg2, void *arg3,
638 				 void *arg4)
639 {
640 	int (*fn_ptr)(int cpu, void *arg);
641 	int ret;
642 
643 	fn_ptr = arg1;
644 	ret = fn_ptr(cpu, arg2);
645 	if (ret)
646 		perror("get_tdp_*");
647 	else
648 		isst_display_result(cpu, outf, "perf-profile", (char *)arg3,
649 				    *(unsigned int *)arg4);
650 }
651 
652 #define _get_tdp_level(desc, suffix, object, help)                                \
653 	static void get_tdp_##object(void)                                        \
654 	{                                                                         \
655 		struct isst_pkg_ctdp ctdp;                                        \
656 \
657 		if (cmd_help) {                                                   \
658 			fprintf(stderr,                                           \
659 				"Print %s [No command arguments are required]\n", \
660 				help);                                            \
661 			exit(0);                                                  \
662 		}                                                                 \
663 		isst_ctdp_display_information_start(outf);                        \
664 		if (max_target_cpus)                                              \
665 			for_each_online_target_cpu_in_set(                        \
666 				exec_on_get_ctdp_cpu, isst_get_ctdp_##suffix,     \
667 				&ctdp, desc, &ctdp.object);                       \
668 		else                                                              \
669 			for_each_online_package_in_set(exec_on_get_ctdp_cpu,      \
670 						       isst_get_ctdp_##suffix,    \
671 						       &ctdp, desc,               \
672 						       &ctdp.object);             \
673 		isst_ctdp_display_information_end(outf);                          \
674 	}
675 
676 _get_tdp_level("get-config-levels", levels, levels, "TDP levels");
677 _get_tdp_level("get-config-version", levels, version, "TDP version");
678 _get_tdp_level("get-config-enabled", levels, enabled, "TDP enable status");
679 _get_tdp_level("get-config-current_level", levels, current_level,
680 	       "Current TDP Level");
681 _get_tdp_level("get-lock-status", levels, locked, "TDP lock status");
682 
683 static void dump_isst_config_for_cpu(int cpu, void *arg1, void *arg2,
684 				     void *arg3, void *arg4)
685 {
686 	struct isst_pkg_ctdp pkg_dev;
687 	int ret;
688 
689 	memset(&pkg_dev, 0, sizeof(pkg_dev));
690 	ret = isst_get_process_ctdp(cpu, tdp_level, &pkg_dev);
691 	if (ret) {
692 		perror("isst_get_process_ctdp");
693 	} else {
694 		isst_ctdp_display_information(cpu, outf, tdp_level, &pkg_dev);
695 		isst_get_process_ctdp_complete(cpu, &pkg_dev);
696 	}
697 }
698 
699 static void dump_isst_config(void)
700 {
701 	if (cmd_help) {
702 		fprintf(stderr,
703 			"Print Intel(R) Speed Select Technology Performance profile configuration\n");
704 		fprintf(stderr,
705 			"including base frequency and turbo frequency configurations\n");
706 		fprintf(stderr, "Optional: -l|--level : Specify tdp level\n");
707 		fprintf(stderr,
708 			"\tIf no arguments, dump information for all TDP levels\n");
709 		exit(0);
710 	}
711 
712 	isst_ctdp_display_information_start(outf);
713 
714 	if (max_target_cpus)
715 		for_each_online_target_cpu_in_set(dump_isst_config_for_cpu,
716 						  NULL, NULL, NULL, NULL);
717 	else
718 		for_each_online_package_in_set(dump_isst_config_for_cpu, NULL,
719 					       NULL, NULL, NULL);
720 
721 	isst_ctdp_display_information_end(outf);
722 }
723 
724 static void set_tdp_level_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
725 				  void *arg4)
726 {
727 	int ret;
728 
729 	ret = isst_set_tdp_level(cpu, tdp_level);
730 	if (ret)
731 		perror("set_tdp_level_for_cpu");
732 	else
733 		isst_display_result(cpu, outf, "perf-profile", "set_tdp_level",
734 				    ret);
735 }
736 
737 static void set_tdp_level(void)
738 {
739 	if (cmd_help) {
740 		fprintf(stderr, "Set Config TDP level\n");
741 		fprintf(stderr,
742 			"\t Arguments: -l|--level : Specify tdp level\n");
743 		exit(0);
744 	}
745 
746 	if (tdp_level == 0xff) {
747 		fprintf(outf, "Invalid command: specify tdp_level\n");
748 		exit(1);
749 	}
750 	isst_ctdp_display_information_start(outf);
751 	if (max_target_cpus)
752 		for_each_online_target_cpu_in_set(set_tdp_level_for_cpu, NULL,
753 						  NULL, NULL, NULL);
754 	else
755 		for_each_online_package_in_set(set_tdp_level_for_cpu, NULL,
756 					       NULL, NULL, NULL);
757 	isst_ctdp_display_information_end(outf);
758 }
759 
760 static void dump_pbf_config_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
761 				    void *arg4)
762 {
763 	struct isst_pbf_info pbf_info;
764 	int ret;
765 
766 	ret = isst_get_pbf_info(cpu, tdp_level, &pbf_info);
767 	if (ret) {
768 		perror("isst_get_pbf_info");
769 	} else {
770 		isst_pbf_display_information(cpu, outf, tdp_level, &pbf_info);
771 		isst_get_pbf_info_complete(&pbf_info);
772 	}
773 }
774 
775 static void dump_pbf_config(void)
776 {
777 	if (cmd_help) {
778 		fprintf(stderr,
779 			"Print Intel(R) Speed Select Technology base frequency configuration for a TDP level\n");
780 		fprintf(stderr,
781 			"\tArguments: -l|--level : Specify tdp level\n");
782 		exit(0);
783 	}
784 
785 	if (tdp_level == 0xff) {
786 		fprintf(outf, "Invalid command: specify tdp_level\n");
787 		exit(1);
788 	}
789 
790 	isst_ctdp_display_information_start(outf);
791 	if (max_target_cpus)
792 		for_each_online_target_cpu_in_set(dump_pbf_config_for_cpu, NULL,
793 						  NULL, NULL, NULL);
794 	else
795 		for_each_online_package_in_set(dump_pbf_config_for_cpu, NULL,
796 					       NULL, NULL, NULL);
797 	isst_ctdp_display_information_end(outf);
798 }
799 
800 static void set_pbf_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
801 			    void *arg4)
802 {
803 	int ret;
804 	int status = *(int *)arg4;
805 
806 	ret = isst_set_pbf_fact_status(cpu, 1, status);
807 	if (ret) {
808 		perror("isst_set_pbf");
809 	} else {
810 		if (status)
811 			isst_display_result(cpu, outf, "base-freq", "enable",
812 					    ret);
813 		else
814 			isst_display_result(cpu, outf, "base-freq", "disable",
815 					    ret);
816 	}
817 }
818 
819 static void set_pbf_enable(void)
820 {
821 	int status = 1;
822 
823 	if (cmd_help) {
824 		fprintf(stderr,
825 			"Enable Intel Speed Select Technology base frequency feature [No command arguments are required]\n");
826 		exit(0);
827 	}
828 
829 	isst_ctdp_display_information_start(outf);
830 	if (max_target_cpus)
831 		for_each_online_target_cpu_in_set(set_pbf_for_cpu, NULL, NULL,
832 						  NULL, &status);
833 	else
834 		for_each_online_package_in_set(set_pbf_for_cpu, NULL, NULL,
835 					       NULL, &status);
836 	isst_ctdp_display_information_end(outf);
837 }
838 
839 static void set_pbf_disable(void)
840 {
841 	int status = 0;
842 
843 	if (cmd_help) {
844 		fprintf(stderr,
845 			"Disable Intel Speed Select Technology base frequency feature [No command arguments are required]\n");
846 		exit(0);
847 	}
848 
849 	isst_ctdp_display_information_start(outf);
850 	if (max_target_cpus)
851 		for_each_online_target_cpu_in_set(set_pbf_for_cpu, NULL, NULL,
852 						  NULL, &status);
853 	else
854 		for_each_online_package_in_set(set_pbf_for_cpu, NULL, NULL,
855 					       NULL, &status);
856 	isst_ctdp_display_information_end(outf);
857 }
858 
859 static void dump_fact_config_for_cpu(int cpu, void *arg1, void *arg2,
860 				     void *arg3, void *arg4)
861 {
862 	struct isst_fact_info fact_info;
863 	int ret;
864 
865 	ret = isst_get_fact_info(cpu, tdp_level, &fact_info);
866 	if (ret)
867 		perror("isst_get_fact_bucket_info");
868 	else
869 		isst_fact_display_information(cpu, outf, tdp_level, fact_bucket,
870 					      fact_avx, &fact_info);
871 }
872 
873 static void dump_fact_config(void)
874 {
875 	if (cmd_help) {
876 		fprintf(stderr,
877 			"Print complete Intel Speed Select Technology turbo frequency configuration for a TDP level. Other arguments are optional.\n");
878 		fprintf(stderr,
879 			"\tArguments: -l|--level : Specify tdp level\n");
880 		fprintf(stderr,
881 			"\tArguments: -b|--bucket : Bucket index to dump\n");
882 		fprintf(stderr,
883 			"\tArguments: -r|--trl-type : Specify trl type: sse|avx2|avx512\n");
884 		exit(0);
885 	}
886 
887 	if (tdp_level == 0xff) {
888 		fprintf(outf, "Invalid command: specify tdp_level\n");
889 		exit(1);
890 	}
891 
892 	isst_ctdp_display_information_start(outf);
893 	if (max_target_cpus)
894 		for_each_online_target_cpu_in_set(dump_fact_config_for_cpu,
895 						  NULL, NULL, NULL, NULL);
896 	else
897 		for_each_online_package_in_set(dump_fact_config_for_cpu, NULL,
898 					       NULL, NULL, NULL);
899 	isst_ctdp_display_information_end(outf);
900 }
901 
902 static void set_fact_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
903 			     void *arg4)
904 {
905 	int ret;
906 	int status = *(int *)arg4;
907 
908 	ret = isst_set_pbf_fact_status(cpu, 0, status);
909 	if (ret)
910 		perror("isst_set_fact");
911 	else {
912 		if (status) {
913 			struct isst_pkg_ctdp pkg_dev;
914 
915 			ret = isst_get_ctdp_levels(cpu, &pkg_dev);
916 			if (ret) {
917 				isst_display_result(cpu, outf, "turbo-freq",
918 						    "enable", ret);
919 				return;
920 			}
921 			ret = isst_set_trl(cpu, fact_trl);
922 			isst_display_result(cpu, outf, "turbo-freq", "enable",
923 					    ret);
924 		} else {
925 			/* Since we modified TRL during Fact enable, restore it */
926 			isst_set_trl_from_current_tdp(cpu, fact_trl);
927 			isst_display_result(cpu, outf, "turbo-freq", "disable",
928 					    ret);
929 		}
930 	}
931 }
932 
933 static void set_fact_enable(void)
934 {
935 	int status = 1;
936 
937 	if (cmd_help) {
938 		fprintf(stderr,
939 			"Enable Intel Speed Select Technology Turbo frequency feature\n");
940 		fprintf(stderr,
941 			"Optional: -t|--trl : Specify turbo ratio limit\n");
942 		exit(0);
943 	}
944 
945 	isst_ctdp_display_information_start(outf);
946 	if (max_target_cpus)
947 		for_each_online_target_cpu_in_set(set_fact_for_cpu, NULL, NULL,
948 						  NULL, &status);
949 	else
950 		for_each_online_package_in_set(set_fact_for_cpu, NULL, NULL,
951 					       NULL, &status);
952 	isst_ctdp_display_information_end(outf);
953 }
954 
955 static void set_fact_disable(void)
956 {
957 	int status = 0;
958 
959 	if (cmd_help) {
960 		fprintf(stderr,
961 			"Disable Intel Speed Select Technology turbo frequency feature\n");
962 		fprintf(stderr,
963 			"Optional: -t|--trl : Specify turbo ratio limit\n");
964 		exit(0);
965 	}
966 
967 	isst_ctdp_display_information_start(outf);
968 	if (max_target_cpus)
969 		for_each_online_target_cpu_in_set(set_fact_for_cpu, NULL, NULL,
970 						  NULL, &status);
971 	else
972 		for_each_online_package_in_set(set_fact_for_cpu, NULL, NULL,
973 					       NULL, &status);
974 	isst_ctdp_display_information_end(outf);
975 }
976 
977 static void enable_clos_qos_config(int cpu, void *arg1, void *arg2, void *arg3,
978 				   void *arg4)
979 {
980 	int ret;
981 	int status = *(int *)arg4;
982 
983 	ret = isst_pm_qos_config(cpu, status, clos_priority_type);
984 	if (ret) {
985 		perror("isst_pm_qos_config");
986 	} else {
987 		if (status)
988 			isst_display_result(cpu, outf, "core-power", "enable",
989 					    ret);
990 		else
991 			isst_display_result(cpu, outf, "core-power", "disable",
992 					    ret);
993 	}
994 }
995 
996 static void set_clos_enable(void)
997 {
998 	int status = 1;
999 
1000 	if (cmd_help) {
1001 		fprintf(stderr, "Enable core-power for a package/die\n");
1002 		fprintf(stderr,
1003 			"\tClos Enable: Specify priority type with [--priority|-p]\n");
1004 		fprintf(stderr, "\t\t 0: Proportional, 1: Ordered\n");
1005 		exit(0);
1006 	}
1007 
1008 	if (cpufreq_sysfs_present()) {
1009 		fprintf(stderr,
1010 			"cpufreq subsystem and core-power enable will interfere with each other!\n");
1011 	}
1012 
1013 	isst_ctdp_display_information_start(outf);
1014 	if (max_target_cpus)
1015 		for_each_online_target_cpu_in_set(enable_clos_qos_config, NULL,
1016 						  NULL, NULL, &status);
1017 	else
1018 		for_each_online_package_in_set(enable_clos_qos_config, NULL,
1019 					       NULL, NULL, &status);
1020 	isst_ctdp_display_information_end(outf);
1021 }
1022 
1023 static void set_clos_disable(void)
1024 {
1025 	int status = 0;
1026 
1027 	if (cmd_help) {
1028 		fprintf(stderr,
1029 			"Disable core-power: [No command arguments are required]\n");
1030 		exit(0);
1031 	}
1032 
1033 	isst_ctdp_display_information_start(outf);
1034 	if (max_target_cpus)
1035 		for_each_online_target_cpu_in_set(enable_clos_qos_config, NULL,
1036 						  NULL, NULL, &status);
1037 	else
1038 		for_each_online_package_in_set(enable_clos_qos_config, NULL,
1039 					       NULL, NULL, &status);
1040 	isst_ctdp_display_information_end(outf);
1041 }
1042 
1043 static void dump_clos_config_for_cpu(int cpu, void *arg1, void *arg2,
1044 				     void *arg3, void *arg4)
1045 {
1046 	struct isst_clos_config clos_config;
1047 	int ret;
1048 
1049 	ret = isst_pm_get_clos(cpu, current_clos, &clos_config);
1050 	if (ret)
1051 		perror("isst_pm_get_clos");
1052 	else
1053 		isst_clos_display_information(cpu, outf, current_clos,
1054 					      &clos_config);
1055 }
1056 
1057 static void dump_clos_config(void)
1058 {
1059 	if (cmd_help) {
1060 		fprintf(stderr,
1061 			"Print Intel Speed Select Technology core power configuration\n");
1062 		fprintf(stderr,
1063 			"\tArguments: [-c | --clos]: Specify clos id\n");
1064 		exit(0);
1065 	}
1066 	if (current_clos < 0 || current_clos > 3) {
1067 		fprintf(stderr, "Invalid clos id\n");
1068 		exit(0);
1069 	}
1070 
1071 	isst_ctdp_display_information_start(outf);
1072 	if (max_target_cpus)
1073 		for_each_online_target_cpu_in_set(dump_clos_config_for_cpu,
1074 						  NULL, NULL, NULL, NULL);
1075 	else
1076 		for_each_online_package_in_set(dump_clos_config_for_cpu, NULL,
1077 					       NULL, NULL, NULL);
1078 	isst_ctdp_display_information_end(outf);
1079 }
1080 
1081 static void set_clos_config_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
1082 				    void *arg4)
1083 {
1084 	struct isst_clos_config clos_config;
1085 	int ret;
1086 
1087 	clos_config.pkg_id = get_physical_package_id(cpu);
1088 	clos_config.die_id = get_physical_die_id(cpu);
1089 
1090 	clos_config.epp = clos_epp;
1091 	clos_config.clos_prop_prio = clos_prop_prio;
1092 	clos_config.clos_min = clos_min;
1093 	clos_config.clos_max = clos_max;
1094 	clos_config.clos_desired = clos_desired;
1095 	ret = isst_set_clos(cpu, current_clos, &clos_config);
1096 	if (ret)
1097 		perror("isst_set_clos");
1098 	else
1099 		isst_display_result(cpu, outf, "core-power", "config", ret);
1100 }
1101 
1102 static void set_clos_config(void)
1103 {
1104 	if (cmd_help) {
1105 		fprintf(stderr,
1106 			"Set core-power configuration for one of the four clos ids\n");
1107 		fprintf(stderr,
1108 			"\tSpecify targeted clos id with [--clos|-c]\n");
1109 		fprintf(stderr, "\tSpecify clos EPP with [--epp|-e]\n");
1110 		fprintf(stderr,
1111 			"\tSpecify clos Proportional Priority [--weight|-w]\n");
1112 		fprintf(stderr, "\tSpecify clos min with [--min|-n]\n");
1113 		fprintf(stderr, "\tSpecify clos max with [--max|-m]\n");
1114 		fprintf(stderr, "\tSpecify clos desired with [--desired|-d]\n");
1115 		exit(0);
1116 	}
1117 
1118 	if (current_clos < 0 || current_clos > 3) {
1119 		fprintf(stderr, "Invalid clos id\n");
1120 		exit(0);
1121 	}
1122 	if (clos_epp < 0 || clos_epp > 0x0F) {
1123 		fprintf(stderr, "clos epp is not specified, default: 0\n");
1124 		clos_epp = 0;
1125 	}
1126 	if (clos_prop_prio < 0 || clos_prop_prio > 0x0F) {
1127 		fprintf(stderr,
1128 			"clos frequency weight is not specified, default: 0\n");
1129 		clos_prop_prio = 0;
1130 	}
1131 	if (clos_min < 0) {
1132 		fprintf(stderr, "clos min is not specified, default: 0\n");
1133 		clos_min = 0;
1134 	}
1135 	if (clos_max < 0) {
1136 		fprintf(stderr, "clos max is not specified, default: 0xff\n");
1137 		clos_max = 0xff;
1138 	}
1139 	if (clos_desired < 0) {
1140 		fprintf(stderr, "clos desired is not specified, default: 0\n");
1141 		clos_desired = 0x00;
1142 	}
1143 
1144 	isst_ctdp_display_information_start(outf);
1145 	if (max_target_cpus)
1146 		for_each_online_target_cpu_in_set(set_clos_config_for_cpu, NULL,
1147 						  NULL, NULL, NULL);
1148 	else
1149 		for_each_online_package_in_set(set_clos_config_for_cpu, NULL,
1150 					       NULL, NULL, NULL);
1151 	isst_ctdp_display_information_end(outf);
1152 }
1153 
1154 static void set_clos_assoc_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
1155 				   void *arg4)
1156 {
1157 	int ret;
1158 
1159 	ret = isst_clos_associate(cpu, current_clos);
1160 	if (ret)
1161 		perror("isst_clos_associate");
1162 	else
1163 		isst_display_result(cpu, outf, "core-power", "assoc", ret);
1164 }
1165 
1166 static void set_clos_assoc(void)
1167 {
1168 	if (cmd_help) {
1169 		fprintf(stderr, "Associate a clos id to a CPU\n");
1170 		fprintf(stderr,
1171 			"\tSpecify targeted clos id with [--clos|-c]\n");
1172 		exit(0);
1173 	}
1174 
1175 	if (current_clos < 0 || current_clos > 3) {
1176 		fprintf(stderr, "Invalid clos id\n");
1177 		exit(0);
1178 	}
1179 	if (max_target_cpus)
1180 		for_each_online_target_cpu_in_set(set_clos_assoc_for_cpu, NULL,
1181 						  NULL, NULL, NULL);
1182 	else {
1183 		fprintf(stderr,
1184 			"Invalid target cpu. Specify with [-c|--cpu]\n");
1185 	}
1186 }
1187 
1188 static void get_clos_assoc_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
1189 				   void *arg4)
1190 {
1191 	int clos, ret;
1192 
1193 	ret = isst_clos_get_assoc_status(cpu, &clos);
1194 	if (ret)
1195 		perror("isst_clos_get_assoc_status");
1196 	else
1197 		isst_display_result(cpu, outf, "core-power", "get-assoc", clos);
1198 }
1199 
1200 static void get_clos_assoc(void)
1201 {
1202 	if (cmd_help) {
1203 		fprintf(stderr, "Get associate clos id to a CPU\n");
1204 		fprintf(stderr, "\tSpecify targeted cpu id with [--cpu|-c]\n");
1205 		exit(0);
1206 	}
1207 	if (max_target_cpus)
1208 		for_each_online_target_cpu_in_set(get_clos_assoc_for_cpu, NULL,
1209 						  NULL, NULL, NULL);
1210 	else {
1211 		fprintf(stderr,
1212 			"Invalid target cpu. Specify with [-c|--cpu]\n");
1213 	}
1214 }
1215 
1216 static struct process_cmd_struct isst_cmds[] = {
1217 	{ "perf-profile", "get-lock-status", get_tdp_locked },
1218 	{ "perf-profile", "get-config-levels", get_tdp_levels },
1219 	{ "perf-profile", "get-config-version", get_tdp_version },
1220 	{ "perf-profile", "get-config-enabled", get_tdp_enabled },
1221 	{ "perf-profile", "get-config-current-level", get_tdp_current_level },
1222 	{ "perf-profile", "set-config-level", set_tdp_level },
1223 	{ "perf-profile", "info", dump_isst_config },
1224 	{ "base-freq", "info", dump_pbf_config },
1225 	{ "base-freq", "enable", set_pbf_enable },
1226 	{ "base-freq", "disable", set_pbf_disable },
1227 	{ "turbo-freq", "info", dump_fact_config },
1228 	{ "turbo-freq", "enable", set_fact_enable },
1229 	{ "turbo-freq", "disable", set_fact_disable },
1230 	{ "core-power", "info", dump_clos_config },
1231 	{ "core-power", "enable", set_clos_enable },
1232 	{ "core-power", "disable", set_clos_disable },
1233 	{ "core-power", "config", set_clos_config },
1234 	{ "core-power", "assoc", set_clos_assoc },
1235 	{ "core-power", "get-assoc", get_clos_assoc },
1236 	{ NULL, NULL, NULL }
1237 };
1238 
1239 /*
1240  * parse cpuset with following syntax
1241  * 1,2,4..6,8-10 and set bits in cpu_subset
1242  */
1243 void parse_cpu_command(char *optarg)
1244 {
1245 	unsigned int start, end;
1246 	char *next;
1247 
1248 	next = optarg;
1249 
1250 	while (next && *next) {
1251 		if (*next == '-') /* no negative cpu numbers */
1252 			goto error;
1253 
1254 		start = strtoul(next, &next, 10);
1255 
1256 		if (max_target_cpus < MAX_CPUS_IN_ONE_REQ)
1257 			target_cpus[max_target_cpus++] = start;
1258 
1259 		if (*next == '\0')
1260 			break;
1261 
1262 		if (*next == ',') {
1263 			next += 1;
1264 			continue;
1265 		}
1266 
1267 		if (*next == '-') {
1268 			next += 1; /* start range */
1269 		} else if (*next == '.') {
1270 			next += 1;
1271 			if (*next == '.')
1272 				next += 1; /* start range */
1273 			else
1274 				goto error;
1275 		}
1276 
1277 		end = strtoul(next, &next, 10);
1278 		if (end <= start)
1279 			goto error;
1280 
1281 		while (++start <= end) {
1282 			if (max_target_cpus < MAX_CPUS_IN_ONE_REQ)
1283 				target_cpus[max_target_cpus++] = start;
1284 		}
1285 
1286 		if (*next == ',')
1287 			next += 1;
1288 		else if (*next != '\0')
1289 			goto error;
1290 	}
1291 
1292 #ifdef DEBUG
1293 	{
1294 		int i;
1295 
1296 		for (i = 0; i < max_target_cpus; ++i)
1297 			printf("cpu [%d] in arg\n", target_cpus[i]);
1298 	}
1299 #endif
1300 	return;
1301 
1302 error:
1303 	fprintf(stderr, "\"--cpu %s\" malformed\n", optarg);
1304 	exit(-1);
1305 }
1306 
1307 static void parse_cmd_args(int argc, int start, char **argv)
1308 {
1309 	int opt;
1310 	int option_index;
1311 
1312 	static struct option long_options[] = {
1313 		{ "bucket", required_argument, 0, 'b' },
1314 		{ "level", required_argument, 0, 'l' },
1315 		{ "trl-type", required_argument, 0, 'r' },
1316 		{ "trl", required_argument, 0, 't' },
1317 		{ "help", no_argument, 0, 'h' },
1318 		{ "clos", required_argument, 0, 'c' },
1319 		{ "desired", required_argument, 0, 'd' },
1320 		{ "epp", required_argument, 0, 'e' },
1321 		{ "min", required_argument, 0, 'n' },
1322 		{ "max", required_argument, 0, 'm' },
1323 		{ "priority", required_argument, 0, 'p' },
1324 		{ "weight", required_argument, 0, 'w' },
1325 		{ 0, 0, 0, 0 }
1326 	};
1327 
1328 	option_index = start;
1329 
1330 	optind = start + 1;
1331 	while ((opt = getopt_long(argc, argv, "b:l:t:c:d:e:n:m:p:w:h",
1332 				  long_options, &option_index)) != -1) {
1333 		switch (opt) {
1334 		case 'b':
1335 			fact_bucket = atoi(optarg);
1336 			break;
1337 		case 'h':
1338 			cmd_help = 1;
1339 			break;
1340 		case 'l':
1341 			tdp_level = atoi(optarg);
1342 			break;
1343 		case 't':
1344 			sscanf(optarg, "0x%llx", &fact_trl);
1345 			break;
1346 		case 'r':
1347 			if (!strncmp(optarg, "sse", 3)) {
1348 				fact_avx = 0x01;
1349 			} else if (!strncmp(optarg, "avx2", 4)) {
1350 				fact_avx = 0x02;
1351 			} else if (!strncmp(optarg, "avx512", 4)) {
1352 				fact_avx = 0x04;
1353 			} else {
1354 				fprintf(outf, "Invalid sse,avx options\n");
1355 				exit(1);
1356 			}
1357 			break;
1358 		/* CLOS related */
1359 		case 'c':
1360 			current_clos = atoi(optarg);
1361 			printf("clos %d\n", current_clos);
1362 			break;
1363 		case 'd':
1364 			clos_desired = atoi(optarg);
1365 			break;
1366 		case 'e':
1367 			clos_epp = atoi(optarg);
1368 			break;
1369 		case 'n':
1370 			clos_min = atoi(optarg);
1371 			break;
1372 		case 'm':
1373 			clos_max = atoi(optarg);
1374 			break;
1375 		case 'p':
1376 			clos_priority_type = atoi(optarg);
1377 			break;
1378 		case 'w':
1379 			clos_prop_prio = atoi(optarg);
1380 			break;
1381 		default:
1382 			printf("no match\n");
1383 		}
1384 	}
1385 }
1386 
1387 static void isst_help(void)
1388 {
1389 	printf("perf-profile:\tAn architectural mechanism that allows multiple optimized \n\
1390 		performance profiles per system via static and/or dynamic\n\
1391 		adjustment of core count, workload, Tjmax, and\n\
1392 		TDP, etc.\n");
1393 	printf("\nCommands : For feature=perf-profile\n");
1394 	printf("\tinfo\n");
1395 	printf("\tget-lock-status\n");
1396 	printf("\tget-config-levels\n");
1397 	printf("\tget-config-version\n");
1398 	printf("\tget-config-enabled\n");
1399 	printf("\tget-config-current-level\n");
1400 	printf("\tset-config-level\n");
1401 }
1402 
1403 static void pbf_help(void)
1404 {
1405 	printf("base-freq:\tEnables users to increase guaranteed base frequency\n\
1406 		on certain cores (high priority cores) in exchange for lower\n\
1407 		base frequency on remaining cores (low priority cores).\n");
1408 	printf("\tcommand : info\n");
1409 	printf("\tcommand : enable\n");
1410 	printf("\tcommand : disable\n");
1411 }
1412 
1413 static void fact_help(void)
1414 {
1415 	printf("turbo-freq:\tEnables the ability to set different turbo ratio\n\
1416 		limits to cores based on priority.\n");
1417 	printf("\nCommand: For feature=turbo-freq\n");
1418 	printf("\tcommand : info\n");
1419 	printf("\tcommand : enable\n");
1420 	printf("\tcommand : disable\n");
1421 }
1422 
1423 static void core_power_help(void)
1424 {
1425 	printf("core-power:\tInterface that allows user to define per core/tile\n\
1426 		priority.\n");
1427 	printf("\nCommands : For feature=core-power\n");
1428 	printf("\tinfo\n");
1429 	printf("\tenable\n");
1430 	printf("\tdisable\n");
1431 	printf("\tconfig\n");
1432 	printf("\tassoc\n");
1433 	printf("\tget-assoc\n");
1434 }
1435 
1436 struct process_cmd_help_struct {
1437 	char *feature;
1438 	void (*process_fn)(void);
1439 };
1440 
1441 static struct process_cmd_help_struct isst_help_cmds[] = {
1442 	{ "perf-profile", isst_help },
1443 	{ "base-freq", pbf_help },
1444 	{ "turbo-freq", fact_help },
1445 	{ "core-power", core_power_help },
1446 	{ NULL, NULL }
1447 };
1448 
1449 void process_command(int argc, char **argv)
1450 {
1451 	int i = 0, matched = 0;
1452 	char *feature = argv[optind];
1453 	char *cmd = argv[optind + 1];
1454 
1455 	if (!feature || !cmd)
1456 		return;
1457 
1458 	debug_printf("feature name [%s] command [%s]\n", feature, cmd);
1459 	if (!strcmp(cmd, "-h") || !strcmp(cmd, "--help")) {
1460 		while (isst_help_cmds[i].feature) {
1461 			if (!strcmp(isst_help_cmds[i].feature, feature)) {
1462 				isst_help_cmds[i].process_fn();
1463 				exit(0);
1464 			}
1465 			++i;
1466 		}
1467 	}
1468 
1469 	create_cpu_map();
1470 
1471 	i = 0;
1472 	while (isst_cmds[i].feature) {
1473 		if (!strcmp(isst_cmds[i].feature, feature) &&
1474 		    !strcmp(isst_cmds[i].command, cmd)) {
1475 			parse_cmd_args(argc, optind + 1, argv);
1476 			isst_cmds[i].process_fn();
1477 			matched = 1;
1478 			break;
1479 		}
1480 		++i;
1481 	}
1482 
1483 	if (!matched)
1484 		fprintf(stderr, "Invalid command\n");
1485 }
1486 
1487 static void usage(void)
1488 {
1489 	printf("Intel(R) Speed Select Technology\n");
1490 	printf("\nUsage:\n");
1491 	printf("intel-speed-select [OPTIONS] FEATURE COMMAND COMMAND_ARGUMENTS\n");
1492 	printf("\nUse this tool to enumerate and control the Intel Speed Select Technology features,\n");
1493 	printf("\nFEATURE : [perf-profile|base-freq|turbo-freq|core-power]\n");
1494 	printf("\nFor help on each feature, use --h|--help\n");
1495 	printf("\tFor example:  intel-speed-select perf-profile -h\n");
1496 
1497 	printf("\nFor additional help on each command for a feature, use --h|--help\n");
1498 	printf("\tFor example:  intel-speed-select perf-profile get-lock-status -h\n");
1499 	printf("\t\t This will print help for the command \"get-lock-status\" for the feature \"perf-profile\"\n");
1500 
1501 	printf("\nOPTIONS\n");
1502 	printf("\t[-c|--cpu] : logical cpu number\n");
1503 	printf("\t\tDefault: Die scoped for all dies in the system with multiple dies/package\n");
1504 	printf("\t\t\t Or Package scoped for all Packages when each package contains one die\n");
1505 	printf("\t[-d|--debug] : Debug mode\n");
1506 	printf("\t[-h|--help] : Print help\n");
1507 	printf("\t[-i|--info] : Print platform information\n");
1508 	printf("\t[-o|--out] : Output file\n");
1509 	printf("\t\t\tDefault : stderr\n");
1510 	printf("\t[-f|--format] : output format [json|text]. Default: text\n");
1511 	printf("\t[-v|--version] : Print version\n");
1512 
1513 	printf("\nResult format\n");
1514 	printf("\tResult display uses a common format for each command:\n");
1515 	printf("\tResults are formatted in text/JSON with\n");
1516 	printf("\t\tPackage, Die, CPU, and command specific results.\n");
1517 	printf("\t\t\tFor Set commands, status is 0 for success and rest for failures\n");
1518 	exit(1);
1519 }
1520 
1521 static void print_version(void)
1522 {
1523 	fprintf(outf, "Version %s\n", version_str);
1524 	fprintf(outf, "Build date %s time %s\n", __DATE__, __TIME__);
1525 	exit(0);
1526 }
1527 
1528 static void cmdline(int argc, char **argv)
1529 {
1530 	int opt;
1531 	int option_index = 0;
1532 
1533 	static struct option long_options[] = {
1534 		{ "cpu", required_argument, 0, 'c' },
1535 		{ "debug", no_argument, 0, 'd' },
1536 		{ "format", required_argument, 0, 'f' },
1537 		{ "help", no_argument, 0, 'h' },
1538 		{ "info", no_argument, 0, 'i' },
1539 		{ "out", required_argument, 0, 'o' },
1540 		{ "version", no_argument, 0, 'v' },
1541 		{ 0, 0, 0, 0 }
1542 	};
1543 
1544 	progname = argv[0];
1545 	while ((opt = getopt_long_only(argc, argv, "+c:df:hio:v", long_options,
1546 				       &option_index)) != -1) {
1547 		switch (opt) {
1548 		case 'c':
1549 			parse_cpu_command(optarg);
1550 			break;
1551 		case 'd':
1552 			debug_flag = 1;
1553 			printf("Debug Mode ON\n");
1554 			break;
1555 		case 'f':
1556 			if (!strncmp(optarg, "json", 4))
1557 				out_format_json = 1;
1558 			break;
1559 		case 'h':
1560 			usage();
1561 			break;
1562 		case 'i':
1563 			isst_print_platform_information();
1564 			break;
1565 		case 'o':
1566 			if (outf)
1567 				fclose(outf);
1568 			outf = fopen_or_exit(optarg, "w");
1569 			break;
1570 		case 'v':
1571 			print_version();
1572 			break;
1573 		default:
1574 			usage();
1575 		}
1576 	}
1577 
1578 	if (geteuid() != 0) {
1579 		fprintf(stderr, "Must run as root\n");
1580 		exit(0);
1581 	}
1582 
1583 	if (optind > (argc - 2)) {
1584 		fprintf(stderr, "Feature name and|or command not specified\n");
1585 		exit(0);
1586 	}
1587 	update_cpu_model();
1588 	printf("Intel(R) Speed Select Technology\n");
1589 	printf("Executing on CPU model:%d[0x%x]\n", cpu_model, cpu_model);
1590 	set_max_cpu_num();
1591 	set_cpu_present_cpu_mask();
1592 	set_cpu_target_cpu_mask();
1593 	isst_fill_platform_info();
1594 	if (isst_platform_info.api_version > supported_api_ver) {
1595 		printf("Incompatible API versions; Upgrade of tool is required\n");
1596 		exit(0);
1597 	}
1598 
1599 	process_command(argc, argv);
1600 }
1601 
1602 int main(int argc, char **argv)
1603 {
1604 	outf = stderr;
1605 	cmdline(argc, argv);
1606 	return 0;
1607 }
1608