brintos

brintos / linux-shallow public Read only

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