File Index
Files and directories
Sign in
FILE

isst-config.c

File preview with syntax highlighting.

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