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