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