cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

isst-config.c (74300B)


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