Commit fd5aadaa authored by Hans de Goede's avatar Hans de Goede

Merge remote-tracking branch 'intel-speed-select/intel-sst' into review-hans

Summary of changes:

Till the commit:
"tools/power/x86/intel-speed-select: Get punit core mapping
information"

All patches just lays foundation for adding new hardware interface
in addition to existing MSR/MMIO interface.

All patches prefixed with "Abstract" just adds individual hardware
callback for functions called from the core processing.

The mailbox processing is abstracted to a new file with callbacks.

In addition some changes to reduce duplicated code for display
of TRL level.

Patch "Introduce Punit ID concept and add related API" add further
abstraction in addition to existing package and die scope.

-----------
tools/power/x86/intel-speed-select: Get punit core mapping information
-Adds a new way to get package/die/punit information for each CPU.
-----------

Introduce TPMI interface support
- Implement all abstracted callbacks above to use TPMI IOCTL interface.
-----------

tools/power/x86/intel-speed-select: Display punit info
- With TPMI the granularity is per punit, which can be multiple in a
package/die.
----------

tools/power/x86/intel-speed-select: Remove cpu mask display for non-cpu
power domain
tools/power/x86/intel-speed-select: Display fact info for non-cpu power
domain
-There are some power domains with no CPUs, the above patches adds CPU
as invalid for these domains
----------

tools/power/x86/intel-speed-select: Use cgroup v2 isolation
- Adds new option to use Cgroup CPU isolation instead of offline of CPUs
----------

tools/power/x86/intel-speed-select: Change TRL display for Emerald Rapids
- Emerald Rapid has multiple TRL levels and moves away from TRL level
based on instruction type
parents 6f561677 19799d3a
intel-speed-select-y += isst-config.o isst-core.o isst-display.o isst-daemon.o hfi-events.o
intel-speed-select-y += isst-config.o isst-core.o isst-display.o isst-daemon.o hfi-events.o isst-core-mbox.o isst-core-tpmi.o
......@@ -15,9 +15,9 @@ struct process_cmd_struct {
int arg;
};
static const char *version_str = "v1.14";
static const char *version_str = "v1.15";
static const int supported_api_ver = 1;
static const int supported_api_ver = 2;
static struct isst_if_platform_info isst_platform_info;
static char *progname;
static int debug_flag;
......@@ -44,9 +44,7 @@ static int cmd_help;
static int force_online_offline;
static int auto_mode;
static int fact_enable_fail;
static int mbox_delay;
static int mbox_retries = 3;
static int cgroupv2;
/* clos related */
static int current_clos = -1;
......@@ -61,6 +59,7 @@ struct _cpu_map {
unsigned short core_id;
unsigned short pkg_id;
unsigned short die_id;
unsigned short punit_id;
unsigned short punit_cpu;
unsigned short punit_cpu_core;
unsigned short initialized;
......@@ -79,6 +78,11 @@ FILE *get_output_file(void)
return outf;
}
int is_debug_enabled(void)
{
return debug_flag;
}
void debug_printf(const char *format, ...)
{
va_list args;
......@@ -110,12 +114,21 @@ int is_skx_based_platform(void)
int is_spr_platform(void)
{
if (cpu_model == 0x8F || cpu_model == 0xCF)
if (cpu_model == 0x8F)
return 1;
return 0;
}
int is_emr_platform(void)
{
if (cpu_model == 0xCF)
return 1;
return 0;
}
int is_icx_platform(void)
{
if (cpu_model == 0x6A || cpu_model == 0x6C)
......@@ -163,6 +176,11 @@ static int update_cpu_model(void)
return 0;
}
int api_version(void)
{
return isst_platform_info.api_version;
}
/* Open a file, and exit on failure */
static FILE *fopen_or_exit(const char *path, const char *mode)
{
......@@ -378,6 +396,17 @@ static int get_physical_die_id(int cpu)
return ret;
}
static int get_physical_punit_id(int cpu)
{
if (cpu < 0)
return -1;
if (cpu_map && cpu_map[cpu].initialized)
return cpu_map[cpu].punit_id;
return -1;
}
void set_isst_id(struct isst_id *id, int cpu)
{
id->cpu = cpu;
......@@ -389,6 +418,10 @@ void set_isst_id(struct isst_id *id, int cpu)
id->die = get_physical_die_id(cpu);
if (id->die >= MAX_DIE_PER_PACKAGE)
id->die = -1;
id->punit = get_physical_punit_id(cpu);
if (id->punit >= MAX_PUNIT_PER_DIE)
id->punit = -1;
}
int is_cpu_in_power_domain(int cpu, struct isst_id *id)
......@@ -397,7 +430,7 @@ int is_cpu_in_power_domain(int cpu, struct isst_id *id)
set_isst_id(&tid, cpu);
if (id->pkg == tid.pkg && id->die == tid.die)
if (id->pkg == tid.pkg && id->die == tid.die && id->punit == tid.punit)
return 1;
return 0;
......@@ -481,51 +514,59 @@ static void force_all_cpus_online(void)
unlink("/var/run/isst_cpu_topology.dat");
}
void for_each_online_package_in_set(void (*callback)(struct isst_id *, void *, void *,
void for_each_online_power_domain_in_set(void (*callback)(struct isst_id *, void *, void *,
void *, void *),
void *arg1, void *arg2, void *arg3,
void *arg4)
{
int max_packages[MAX_PACKAGE_COUNT * MAX_PACKAGE_COUNT];
int pkg_index = 0, i;
struct isst_id id;
int cpus[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE][MAX_PUNIT_PER_DIE];
int valid_mask[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE] = {0};
int i, j, k;
memset(cpus, -1, sizeof(cpus));
memset(max_packages, 0xff, sizeof(max_packages));
for (i = 0; i < topo_max_cpus; ++i) {
int j, online, pkg_id, die_id = 0, skip = 0;
int online;
if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
continue;
if (i)
online = parse_int_file(
1, "/sys/devices/system/cpu/cpu%d/online", i);
else
online =
1; /* online entry for CPU 0 needs some special configs */
die_id = get_physical_die_id(i);
if (die_id < 0)
die_id = 0;
online = parse_int_file(
i != 0, "/sys/devices/system/cpu/cpu%d/online", i);
if (online < 0)
online = 1; /* online entry for CPU 0 needs some special configs */
pkg_id = parse_int_file(0,
"/sys/devices/system/cpu/cpu%d/topology/physical_package_id", i);
if (pkg_id < 0)
if (!online)
continue;
/* Create an unique id for package, die combination to store */
pkg_id = (MAX_PACKAGE_COUNT * pkg_id + die_id);
set_isst_id(&id, i);
for (j = 0; j < pkg_index; ++j) {
if (max_packages[j] == pkg_id) {
skip = 1;
break;
}
}
if (id.pkg < 0 || id.die < 0 || id.punit < 0)
continue;
set_isst_id(&id, i);
if (!skip && online && callback) {
callback(&id, arg1, arg2, arg3, arg4);
max_packages[pkg_index++] = pkg_id;
valid_mask[id.pkg][id.die] = 1;
if (cpus[id.pkg][id.die][id.punit] == -1)
cpus[id.pkg][id.die][id.punit] = i;
}
for (i = 0; i < MAX_PACKAGE_COUNT; i++) {
for (j = 0; j < MAX_DIE_PER_PACKAGE; j++) {
/*
* Fix me:
* How to check a non-cpu die for a package/die with all cpu offlined?
*/
if (!valid_mask[i][j])
continue;
for (k = 0; k < MAX_PUNIT_PER_DIE; k++) {
id.cpu = cpus[i][j][k];
id.pkg = i;
id.die = j;
id.punit = k;
if (isst_is_punit_valid(&id))
callback(&id, arg1, arg2, arg3, arg4);
}
}
}
}
......@@ -610,7 +651,7 @@ void free_cpu_set(cpu_set_t *cpu_set)
CPU_FREE(cpu_set);
}
static int cpu_cnt[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE];
static int cpu_cnt[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE][MAX_PUNIT_PER_DIE];
int get_max_punit_core_id(struct isst_id *id)
{
......@@ -632,10 +673,50 @@ int get_max_punit_core_id(struct isst_id *id)
int get_cpu_count(struct isst_id *id)
{
if (id->pkg < 0 || id->die < 0)
if (id->pkg < 0 || id->die < 0 || id->punit < 0)
return 0;
return cpu_cnt[id->pkg][id->die];
return cpu_cnt[id->pkg][id->die][id->punit];
}
static void update_punit_cpu_info(__u32 physical_cpu, struct _cpu_map *cpu_map)
{
if (api_version() > 1) {
/*
* MSR 0x54 format
* [15:11] PM_DOMAIN_ID
* [10:3] MODULE_ID (aka IDI_AGENT_ID)
* [2:0] LP_ID (We don't care about these bits we only
* care die and core id
* For Atom:
* [2] Always 0
* [1:0] core ID within module
* For Core
* [2:1] Always 0
* [0] thread ID
*/
cpu_map->punit_id = (physical_cpu >> 11) & 0x1f;
cpu_map->punit_cpu_core = (physical_cpu >> 3) & 0xff;
cpu_map->punit_cpu = physical_cpu & 0x7ff;
} else {
int punit_id;
/*
* MSR 0x53 format
* Format
* Bit 0 – thread ID
* Bit 8:1 – core ID
* Bit 13:9 – punit ID
*/
cpu_map->punit_cpu = physical_cpu & 0x1ff;
cpu_map->punit_cpu_core = (cpu_map->punit_cpu >> 1); // shift to get core id
punit_id = (physical_cpu >> 9) & 0x1f;
if (punit_id >= MAX_PUNIT_PER_DIE)
punit_id = 0;
cpu_map->punit_id = punit_id;
}
}
static void create_cpu_map(void)
......@@ -660,7 +741,7 @@ static void create_cpu_map(void)
for (i = 0; i < topo_max_cpus; ++i) {
char buffer[256];
int pkg_id, die_id, core_id;
int pkg_id, die_id, core_id, punit_id;
/* check if CPU is online */
snprintf(buffer, sizeof(buffer),
......@@ -682,31 +763,32 @@ static void create_cpu_map(void)
cpu_map[i].pkg_id = pkg_id;
cpu_map[i].die_id = die_id;
cpu_map[i].core_id = core_id;
cpu_map[i].initialized = 1;
cpu_cnt[pkg_id][die_id]++;
if (fd < 0)
continue;
map.cmd_count = 1;
map.cpu_map[0].logical_cpu = i;
debug_printf(" map logical_cpu:%d\n",
map.cpu_map[0].logical_cpu);
if (ioctl(fd, ISST_IF_GET_PHY_ID, &map) == -1) {
perror("ISST_IF_GET_PHY_ID");
fprintf(outf, "Error: map logical_cpu:%d\n",
map.cpu_map[0].logical_cpu);
continue;
punit_id = 0;
if (fd >= 0) {
map.cmd_count = 1;
map.cpu_map[0].logical_cpu = i;
debug_printf(" map logical_cpu:%d\n",
map.cpu_map[0].logical_cpu);
if (ioctl(fd, ISST_IF_GET_PHY_ID, &map) == -1) {
perror("ISST_IF_GET_PHY_ID");
fprintf(outf, "Error: map logical_cpu:%d\n",
map.cpu_map[0].logical_cpu);
} else {
update_punit_cpu_info(map.cpu_map[0].physical_cpu, &cpu_map[i]);
}
}
cpu_map[i].punit_cpu = map.cpu_map[0].physical_cpu;
cpu_map[i].punit_cpu_core = (map.cpu_map[0].physical_cpu >>
1); // shift to get core id
cpu_map[i].initialized = 1;
cpu_cnt[pkg_id][die_id][punit_id]++;
debug_printf(
"map logical_cpu:%d core: %d die:%d pkg:%d punit_cpu:%d punit_core:%d\n",
"map logical_cpu:%d core: %d die:%d pkg:%d punit:%d punit_cpu:%d punit_core:%d\n",
i, cpu_map[i].core_id, cpu_map[i].die_id,
cpu_map[i].pkg_id, cpu_map[i].punit_cpu,
cpu_map[i].punit_cpu_core);
cpu_map[i].pkg_id, cpu_map[i].punit_id,
cpu_map[i].punit_cpu, cpu_map[i].punit_cpu_core);
}
if (fd >= 0)
close(fd);
......@@ -728,6 +810,9 @@ void set_cpu_mask_from_punit_coremask(struct isst_id *id, unsigned long long cor
{
int i, cnt = 0;
if (id->cpu < 0)
return;
*cpu_cnt = 0;
for (i = 0; i < 64; ++i) {
......@@ -759,182 +844,135 @@ int find_phy_core_num(int logical_cpu)
return -EINVAL;
}
static int isst_send_mmio_command(unsigned int cpu, unsigned int reg, int write,
unsigned int *value)
int use_cgroupv2(void)
{
struct isst_if_io_regs io_regs;
const char *pathname = "/dev/isst_interface";
int cmd;
int fd;
debug_printf("mmio_cmd cpu:%d reg:%d write:%d\n", cpu, reg, write);
return cgroupv2;
}
fd = open(pathname, O_RDWR);
if (fd < 0)
err(-1, "%s open failed", pathname);
int enable_cpuset_controller(void)
{
int fd, ret;
io_regs.req_count = 1;
io_regs.io_reg[0].logical_cpu = cpu;
io_regs.io_reg[0].reg = reg;
cmd = ISST_IF_IO_CMD;
if (write) {
io_regs.io_reg[0].read_write = 1;
io_regs.io_reg[0].value = *value;
} else {
io_regs.io_reg[0].read_write = 0;
fd = open("/sys/fs/cgroup/cgroup.subtree_control", O_RDWR, 0);
if (fd < 0) {
debug_printf("Can't activate cpuset controller\n");
debug_printf("Either you are not root user or CGroup v2 is not supported\n");
return fd;
}
if (ioctl(fd, cmd, &io_regs) == -1) {
if (errno == ENOTTY) {
perror("ISST_IF_IO_COMMAND\n");
fprintf(stderr, "Check presence of kernel modules: isst_if_mmio\n");
exit(0);
}
fprintf(outf, "Error: mmio_cmd cpu:%d reg:%x read_write:%x\n",
cpu, reg, write);
} else {
if (!write)
*value = io_regs.io_reg[0].value;
ret = write(fd, " +cpuset", strlen(" +cpuset"));
close(fd);
debug_printf(
"mmio_cmd response: cpu:%d reg:%x rd_write:%x resp:%x\n",
cpu, reg, write, *value);
if (ret == -1) {
debug_printf("Can't activate cpuset controller: Write failed\n");
return ret;
}
close(fd);
return 0;
}
int isst_send_mbox_command(unsigned int cpu, unsigned char command,
unsigned char sub_command, unsigned int parameter,
unsigned int req_data, unsigned int *resp)
int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int level)
{
const char *pathname = "/dev/isst_interface";
int fd, retry;
struct isst_if_mbox_cmds mbox_cmds = { 0 };
debug_printf(
"mbox_send: cpu:%d command:%x sub_command:%x parameter:%x req_data:%x\n",
cpu, command, sub_command, parameter, req_data);
int i, first, curr_index, index, ret, fd;
static char str[512], dir_name[64];
static char cpuset_cpus[128];
int str_len = sizeof(str);
DIR *dir;
if (!is_skx_based_platform() && command == CONFIG_CLOS &&
sub_command != CLOS_PM_QOS_CONFIG) {
unsigned int value;
int write = 0;
int clos_id, core_id, ret = 0;
snprintf(dir_name, sizeof(dir_name), "/sys/fs/cgroup/%d-%d-%d", id->pkg, id->die, id->punit);
dir = opendir(dir_name);
if (!dir) {
ret = mkdir(dir_name, 0744);
if (ret) {
debug_printf("Can't create dir:%s errno:%d\n", dir_name, errno);
return ret;
}
}
closedir(dir);
debug_printf("CPU %d\n", cpu);
if (!level) {
sprintf(cpuset_cpus, "%s/cpuset.cpus.partition", dir_name);
if (parameter & BIT(MBOX_CMD_WRITE_BIT)) {
value = req_data;
write = 1;
fd = open(cpuset_cpus, O_RDWR, 0);
if (fd < 0) {
return fd;
}
switch (sub_command) {
case CLOS_PQR_ASSOC:
core_id = parameter & 0xff;
ret = isst_send_mmio_command(
cpu, PQR_ASSOC_OFFSET + core_id * 4, write,
&value);
if (!ret && !write)
*resp = value;
break;
case CLOS_PM_CLOS:
clos_id = parameter & 0x03;
ret = isst_send_mmio_command(
cpu, PM_CLOS_OFFSET + clos_id * 4, write,
&value);
if (!ret && !write)
*resp = value;
break;
case CLOS_STATUS:
break;
default:
break;
ret = write(fd, "member", strlen("member"));
if (ret == -1) {
printf("Can't update to member\n");
return ret;
}
return ret;
}
mbox_cmds.cmd_count = 1;
mbox_cmds.mbox_cmd[0].logical_cpu = cpu;
mbox_cmds.mbox_cmd[0].command = command;
mbox_cmds.mbox_cmd[0].sub_command = sub_command;
mbox_cmds.mbox_cmd[0].parameter = parameter;
mbox_cmds.mbox_cmd[0].req_data = req_data;
return 0;
}
if (mbox_delay)
usleep(mbox_delay * 1000);
if (!CPU_COUNT_S(mask_size, cpu_mask)) {
return -1;
}
fd = open(pathname, O_RDWR);
if (fd < 0)
err(-1, "%s open failed", pathname);
curr_index = 0;
first = 1;
str[0] = '\0';
for (i = 0; i < get_topo_max_cpus(); ++i) {
if (!is_cpu_in_power_domain(i, id))
continue;
retry = mbox_retries;
if (CPU_ISSET_S(i, mask_size, cpu_mask))
continue;
do {
if (ioctl(fd, ISST_IF_MBOX_COMMAND, &mbox_cmds) == -1) {
if (errno == ENOTTY) {
perror("ISST_IF_MBOX_COMMAND\n");
fprintf(stderr, "Check presence of kernel modules: isst_if_mbox_pci or isst_if_mbox_msr\n");
exit(0);
}
debug_printf(
"Error: mbox_cmd cpu:%d command:%x sub_command:%x parameter:%x req_data:%x errorno:%d\n",
cpu, command, sub_command, parameter, req_data, errno);
--retry;
} else {
*resp = mbox_cmds.mbox_cmd[0].resp_data;
debug_printf(
"mbox_cmd response: cpu:%d command:%x sub_command:%x parameter:%x req_data:%x resp:%x\n",
cpu, command, sub_command, parameter, req_data, *resp);
break;
if (!first) {
index = snprintf(&str[curr_index],
str_len - curr_index, ",");
curr_index += index;
if (curr_index >= str_len)
break;
}
} while (retry);
index = snprintf(&str[curr_index], str_len - curr_index, "%d",
i);
curr_index += index;
if (curr_index >= str_len)
break;
first = 0;
}
close(fd);
debug_printf("isolated CPUs list: package:%d curr_index:%d [%s]\n", id->pkg, curr_index ,str);
if (!retry) {
debug_printf("Failed mbox command even after retries\n");
return -1;
snprintf(cpuset_cpus, sizeof(cpuset_cpus), "%s/cpuset.cpus", dir_name);
fd = open(cpuset_cpus, O_RDWR, 0);
if (fd < 0) {
return fd;
}
return 0;
}
int isst_send_msr_command(unsigned int cpu, unsigned int msr, int write,
unsigned long long *req_resp)
{
struct isst_if_msr_cmds msr_cmds;
const char *pathname = "/dev/isst_interface";
int fd;
ret = write(fd, str, strlen(str));
close(fd);
fd = open(pathname, O_RDWR);
if (fd < 0)
err(-1, "%s open failed", pathname);
if (ret == -1) {
debug_printf("Can't activate cpuset controller: Write failed\n");
return ret;
}
msr_cmds.cmd_count = 1;
msr_cmds.msr_cmd[0].logical_cpu = cpu;
msr_cmds.msr_cmd[0].msr = msr;
msr_cmds.msr_cmd[0].read_write = write;
if (write)
msr_cmds.msr_cmd[0].data = *req_resp;
if (ioctl(fd, ISST_IF_MSR_COMMAND, &msr_cmds) == -1) {
perror("ISST_IF_MSR_COMMAND");
fprintf(outf, "Error: msr_cmd cpu:%d msr:%x read_write:%d\n",
cpu, msr, write);
} else {
if (!write)
*req_resp = msr_cmds.msr_cmd[0].data;
snprintf(cpuset_cpus, sizeof(cpuset_cpus), "%s/cpuset.cpus.partition", dir_name);
debug_printf(
"msr_cmd response: cpu:%d msr:%x rd_write:%x resp:%llx %llx\n",
cpu, msr, write, *req_resp, msr_cmds.msr_cmd[0].data);
fd = open(cpuset_cpus, O_RDWR, 0);
if (fd < 0) {
return fd;
}
ret = write(fd, "isolated", strlen("isolated"));
if (ret == -1) {
debug_printf("Can't update to isolated\n");
ret = write(fd, "root", strlen("root"));
if (ret == -1)
debug_printf("Can't update to root\n");
}
close(fd);
if (ret < 0)
return ret;
return 0;
}
......@@ -943,6 +981,11 @@ static int isst_fill_platform_info(void)
const char *pathname = "/dev/isst_interface";
int fd;
if (is_clx_n_platform()) {
isst_platform_info.api_version = 1;
goto set_platform_ops;
}
fd = open(pathname, O_RDWR);
if (fd < 0)
err(-1, "%s open failed", pathname);
......@@ -959,77 +1002,96 @@ static int isst_fill_platform_info(void)
printf("Incompatible API versions; Upgrade of tool is required\n");
return -1;
}
set_platform_ops:
if (isst_set_platform_ops(isst_platform_info.api_version)) {
fprintf(stderr, "Failed to set platform callbacks\n");
exit(0);
}
return 0;
}
static void isst_print_extended_platform_info(void)
void get_isst_status(struct isst_id *id, void *arg1, void *arg2, void *arg3, void *arg4)
{
int cp_state, cp_cap, fact_support = 0, pbf_support = 0;
struct isst_pkg_ctdp_level_info ctdp_level;
struct isst_pkg_ctdp pkg_dev;
int ret, i, j;
FILE *filep;
struct isst_id id;
for (i = 0; i < 256; ++i) {
char path[256];
snprintf(path, sizeof(path),
"/sys/devices/system/cpu/cpu%d/topology/thread_siblings", i);
filep = fopen(path, "r");
if (filep)
break;
}
struct isst_id *tid = (struct isst_id *)arg2;
int *mask = (int *)arg3;
int *max_level = (int *)arg4;
int j, ret;
if (!filep)
/* Only check the first cpu power domain */
if (id->cpu < 0 || tid->cpu >= 0)
return;
fclose(filep);
set_isst_id(&id, i);
ret = isst_get_ctdp_levels(&id, &pkg_dev);
ret = isst_get_ctdp_levels(id, &pkg_dev);
if (ret)
return;
if (pkg_dev.enabled) {
fprintf(outf, "Intel(R) SST-PP (feature perf-profile) is supported\n");
} else {
fprintf(outf, "Intel(R) SST-PP (feature perf-profile) is not supported\n");
fprintf(outf, "Only performance level 0 (base level) is present\n");
}
if (pkg_dev.enabled)
*mask |= BIT(0);
if (pkg_dev.locked)
fprintf(outf, "TDP level change control is locked\n");
else
fprintf(outf, "TDP level change control is unlocked, max level: %d \n", pkg_dev.levels);
*mask |= BIT(1);
if (*max_level < pkg_dev.levels)
*max_level = pkg_dev.levels;
for (j = 0; j <= pkg_dev.levels; ++j) {
ret = isst_get_ctdp_control(&id, j, &ctdp_level);
struct isst_pkg_ctdp_level_info ctdp_level;
ret = isst_get_ctdp_control(id, j, &ctdp_level);
if (ret)
continue;
if (!fact_support && ctdp_level.fact_support)
fact_support = 1;
if (ctdp_level.fact_support)
*mask |= BIT(2);
if (ctdp_level.pbf_support)
*mask |= BIT(3);
}
tid->cpu = id->cpu;
tid->pkg = id->pkg;
tid->die = id->die;
tid->punit = id->punit;
}
static void isst_print_extended_platform_info(void)
{
int cp_state, cp_cap;
struct isst_id id;
int mask = 0, max_level = 0;
if (!pbf_support && ctdp_level.pbf_support)
pbf_support = 1;
id.cpu = -1;
for_each_online_power_domain_in_set(get_isst_status, NULL, &id, &mask, &max_level);
if (mask & BIT(0)) {
fprintf(outf, "Intel(R) SST-PP (feature perf-profile) is supported\n");
} else {
fprintf(outf, "Intel(R) SST-PP (feature perf-profile) is not supported\n");
fprintf(outf, "Only performance level 0 (base level) is present\n");
}
if (fact_support)
if (mask & BIT(1))
fprintf(outf, "TDP level change control is locked\n");
else
fprintf(outf, "TDP level change control is unlocked, max level: %d\n", max_level);
if (mask & BIT(2))
fprintf(outf, "Intel(R) SST-TF (feature turbo-freq) is supported\n");
else
fprintf(outf, "Intel(R) SST-TF (feature turbo-freq) is not supported\n");
if (pbf_support)
if (mask & BIT(3))
fprintf(outf, "Intel(R) SST-BF (feature base-freq) is supported\n");
else
fprintf(outf, "Intel(R) SST-BF (feature base-freq) is not supported\n");
ret = isst_read_pm_config(&id, &cp_state, &cp_cap);
if (ret) {
if (isst_read_pm_config(&id, &cp_state, &cp_cap)) {
fprintf(outf, "Intel(R) SST-CP (feature core-power) status is unknown\n");
return;
}
if (cp_cap)
fprintf(outf, "Intel(R) SST-CP (feature core-power) is supported\n");
else
......@@ -1038,10 +1100,6 @@ static void isst_print_extended_platform_info(void)
static void isst_print_platform_information(void)
{
struct isst_if_platform_info platform_info;
const char *pathname = "/dev/isst_interface";
int fd;
if (is_clx_n_platform()) {
fprintf(stderr, "\nThis option in not supported on this platform\n");
exit(0);
......@@ -1051,25 +1109,15 @@ static void isst_print_platform_information(void)
set_max_cpu_num();
create_cpu_map();
fd = open(pathname, O_RDWR);
if (fd < 0)
err(-1, "%s open failed", pathname);
if (ioctl(fd, ISST_IF_GET_PLATFORM_INFO, &platform_info) == -1) {
perror("ISST_IF_GET_PLATFORM_INFO");
} else {
fprintf(outf, "Platform: API version : %d\n",
platform_info.api_version);
fprintf(outf, "Platform: Driver version : %d\n",
platform_info.driver_version);
fprintf(outf, "Platform: mbox supported : %d\n",
platform_info.mbox_supported);
fprintf(outf, "Platform: mmio supported : %d\n",
platform_info.mmio_supported);
isst_print_extended_platform_info();
}
close(fd);
fprintf(outf, "Platform: API version : %d\n",
isst_platform_info.api_version);
fprintf(outf, "Platform: Driver version : %d\n",
isst_platform_info.driver_version);
fprintf(outf, "Platform: mbox supported : %d\n",
isst_platform_info.mbox_supported);
fprintf(outf, "Platform: mmio supported : %d\n",
isst_platform_info.mmio_supported);
isst_print_extended_platform_info();
exit(0);
}
......@@ -1110,7 +1158,7 @@ static void exec_on_get_ctdp_cpu(struct isst_id *id, void *arg1, void *arg2, voi
exec_on_get_ctdp_cpu, isst_get_ctdp_##suffix, \
&ctdp, desc, &ctdp.object); \
else \
for_each_online_package_in_set(exec_on_get_ctdp_cpu, \
for_each_online_power_domain_in_set(exec_on_get_ctdp_cpu, \
isst_get_ctdp_##suffix, \
&ctdp, desc, \
&ctdp.object); \
......@@ -1314,92 +1362,91 @@ static void dump_isst_config(int arg)
if (max_target_cpus)
for_each_online_target_cpu_in_set(fn, NULL, NULL, NULL, NULL);
else
for_each_online_package_in_set(fn, NULL, NULL, NULL, NULL);
for_each_online_power_domain_in_set(fn, NULL, NULL, NULL, NULL);
isst_ctdp_display_information_end(outf);
}
static int set_uncore_min_max(struct isst_id *id, int max, int freq)
{
char buffer[128], freq_str[16];
int fd, ret, len;
if (max)
snprintf(buffer, sizeof(buffer),
"/sys/devices/system/cpu/intel_uncore_frequency/package_%02d_die_%02d/max_freq_khz", id->pkg, id->die);
else
snprintf(buffer, sizeof(buffer),
"/sys/devices/system/cpu/intel_uncore_frequency/package_%02d_die_%02d/min_freq_khz", id->pkg, id->die);
fd = open(buffer, O_WRONLY);
if (fd < 0)
return fd;
snprintf(freq_str, sizeof(freq_str), "%d", freq);
len = strlen(freq_str);
ret = write(fd, freq_str, len);
if (ret == -1) {
close(fd);
return ret;
}
close(fd);
return 0;
}
static void adjust_scaling_max_from_base_freq(int cpu);
static void set_tdp_level_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
void *arg4)
{
struct isst_pkg_ctdp pkg_dev;
int ret;
ret = isst_get_ctdp_levels(id, &pkg_dev);
if (ret) {
isst_display_error_info_message(1, "Get TDP level failed", 0, 0);
isst_ctdp_display_information_end(outf);
exit(1);
}
if (pkg_dev.current_level == tdp_level) {
debug_printf("TDP level already set. Skipped\n");
goto display_result;
}
ret = isst_set_tdp_level(id, tdp_level);
if (ret) {
isst_display_error_info_message(1, "Set TDP level failed", 0, 0);
isst_ctdp_display_information_end(outf);
exit(1);
} else {
isst_display_result(id, outf, "perf-profile", "set_tdp_level",
ret);
if (force_online_offline) {
struct isst_pkg_ctdp_level_info ctdp_level;
/* Wait for updated base frequencies */
usleep(2000);
/* Adjusting uncore freq */
isst_get_uncore_p0_p1_info(id, tdp_level, &ctdp_level);
if (ctdp_level.uncore_pm)
set_uncore_min_max(id, 0, ctdp_level.uncore_pm * 100000);
if (ctdp_level.uncore_p0)
set_uncore_min_max(id, 1, ctdp_level.uncore_p0 * 100000);
fprintf(stderr, "Option is set to online/offline\n");
ctdp_level.core_cpumask_size =
alloc_cpu_set(&ctdp_level.core_cpumask);
ret = isst_get_coremask_info(id, tdp_level, &ctdp_level);
if (ret) {
isst_display_error_info_message(1, "Can't get coremask, online/offline option is ignored", 0, 0);
return;
}
if (ctdp_level.cpu_count) {
int i, max_cpus = get_topo_max_cpus();
for (i = 0; i < max_cpus; ++i) {
if (!is_cpu_in_power_domain(i, id))
continue;
if (CPU_ISSET_S(i, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask)) {
fprintf(stderr, "online cpu %d\n", i);
set_cpu_online_offline(i, 1);
adjust_scaling_max_from_base_freq(i);
} else {
fprintf(stderr, "offline cpu %d\n", i);
set_cpu_online_offline(i, 0);
}
}
display_result:
isst_display_result(id, outf, "perf-profile", "set_tdp_level", ret);
if (force_online_offline && id->cpu >= 0) {
struct isst_pkg_ctdp_level_info ctdp_level;
/* Wait for updated base frequencies */
usleep(2000);
/* Adjusting uncore freq */
isst_adjust_uncore_freq(id, tdp_level, &ctdp_level);
fprintf(stderr, "Option is set to online/offline\n");
ctdp_level.core_cpumask_size =
alloc_cpu_set(&ctdp_level.core_cpumask);
ret = isst_get_coremask_info(id, tdp_level, &ctdp_level);
if (ret) {
isst_display_error_info_message(1, "Can't get coremask, online/offline option is ignored", 0, 0);
goto free_mask;
}
if (use_cgroupv2()) {
int ret;
fprintf(stderr, "Using cgroup v2 in lieu of online/offline\n");
ret = enable_cpuset_controller();
if (ret)
goto use_offline;
ret = isolate_cpus(id, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask, tdp_level);
if (ret)
goto use_offline;
goto free_mask;
}
use_offline:
if (ctdp_level.cpu_count) {
int i, max_cpus = get_topo_max_cpus();
for (i = 0; i < max_cpus; ++i) {
if (!is_cpu_in_power_domain(i, id))
continue;
if (CPU_ISSET_S(i, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask)) {
fprintf(stderr, "online cpu %d\n", i);
set_cpu_online_offline(i, 1);
adjust_scaling_max_from_base_freq(i);
} else {
fprintf(stderr, "offline cpu %d\n", i);
set_cpu_online_offline(i, 0);
}
}
}
free_mask:
free_cpu_set(ctdp_level.core_cpumask);
}
}
......@@ -1425,7 +1472,7 @@ static void set_tdp_level(int arg)
for_each_online_target_cpu_in_set(set_tdp_level_for_cpu, NULL,
NULL, NULL, NULL);
else
for_each_online_package_in_set(set_tdp_level_for_cpu, NULL,
for_each_online_power_domain_in_set(set_tdp_level_for_cpu, NULL,
NULL, NULL, NULL);
isst_ctdp_display_information_end(outf);
}
......@@ -1463,7 +1510,7 @@ static void dump_pbf_config_for_cpu(struct isst_id *id, void *arg1, void *arg2,
exit(1);
} else {
isst_pbf_display_information(id, outf, tdp_level, &pbf_info);
isst_get_pbf_info_complete(&pbf_info);
free_cpu_set(pbf_info.core_cpumask);
}
}
......@@ -1494,7 +1541,7 @@ static void dump_pbf_config(int arg)
if (max_target_cpus)
for_each_online_target_cpu_in_set(fn, NULL, NULL, NULL, NULL);
else
for_each_online_package_in_set(fn, NULL, NULL, NULL, NULL);
for_each_online_power_domain_in_set(fn, NULL, NULL, NULL, NULL);
isst_ctdp_display_information_end(outf);
}
......@@ -1662,6 +1709,9 @@ static void set_scaling_min_to_cpuinfo_max(struct isst_id *id)
{
int i;
if (id->cpu < 0)
return;
for (i = 0; i < get_topo_max_cpus(); ++i) {
if (!is_cpu_in_power_domain(i, id))
continue;
......@@ -1679,6 +1729,9 @@ static void set_scaling_min_to_cpuinfo_min(struct isst_id *id)
{
int i;
if (id->cpu < 0)
return;
for (i = 0; i < get_topo_max_cpus(); ++i) {
if (!is_cpu_in_power_domain(i, id))
continue;
......@@ -1758,6 +1811,9 @@ static int set_pbf_core_power(struct isst_id *id)
struct isst_pkg_ctdp pkg_dev;
int ret;
if (id->cpu < 0)
return 0;
ret = isst_get_ctdp_levels(id, &pkg_dev);
if (ret) {
debug_printf("isst_get_ctdp_levels failed");
......@@ -1900,7 +1956,7 @@ static void set_pbf_enable(int arg)
for_each_online_target_cpu_in_set(set_pbf_for_cpu, NULL, NULL,
NULL, &enable);
else
for_each_online_package_in_set(set_pbf_for_cpu, NULL, NULL,
for_each_online_power_domain_in_set(set_pbf_for_cpu, NULL, NULL,
NULL, &enable);
isst_ctdp_display_information_end(outf);
}
......@@ -1946,7 +2002,7 @@ static void dump_fact_config(int arg)
for_each_online_target_cpu_in_set(dump_fact_config_for_cpu,
NULL, NULL, NULL, NULL);
else
for_each_online_package_in_set(dump_fact_config_for_cpu, NULL,
for_each_online_power_domain_in_set(dump_fact_config_for_cpu, NULL,
NULL, NULL, NULL);
isst_ctdp_display_information_end(outf);
}
......@@ -2003,7 +2059,7 @@ static void set_fact_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *a
struct isst_pkg_ctdp pkg_dev;
ret = isst_get_ctdp_levels(id, &pkg_dev);
if (!ret)
if (!ret && id->cpu >= 0)
ret = isst_set_trl(id, fact_trl);
if (ret && auto_mode)
isst_pm_qos_config(id, 0, 0);
......@@ -2055,7 +2111,7 @@ static void set_fact_enable(int arg)
for_each_online_target_cpu_in_set(set_fact_for_cpu, NULL, NULL,
NULL, &enable);
else
for_each_online_package_in_set(set_fact_for_cpu, NULL, NULL,
for_each_online_power_domain_in_set(set_fact_for_cpu, NULL, NULL,
NULL, &enable);
isst_ctdp_display_information_end(outf);
......@@ -2194,7 +2250,7 @@ static void set_clos_enable(int arg)
for_each_online_target_cpu_in_set(enable_clos_qos_config, NULL,
NULL, NULL, &enable);
else
for_each_online_package_in_set(enable_clos_qos_config, NULL,
for_each_online_power_domain_in_set(enable_clos_qos_config, NULL,
NULL, NULL, &enable);
isst_ctdp_display_information_end(outf);
}
......@@ -2205,6 +2261,9 @@ static void dump_clos_config_for_cpu(struct isst_id *id, void *arg1, void *arg2,
struct isst_clos_config clos_config;
int ret;
if (id->cpu < 0)
return;
ret = isst_pm_get_clos(id, current_clos, &clos_config);
if (ret)
isst_display_error_info_message(1, "isst_pm_get_clos failed", 0, 0);
......@@ -2233,7 +2292,7 @@ static void dump_clos_config(int arg)
for_each_online_target_cpu_in_set(dump_clos_config_for_cpu,
NULL, NULL, NULL, NULL);
else
for_each_online_package_in_set(dump_clos_config_for_cpu, NULL,
for_each_online_power_domain_in_set(dump_clos_config_for_cpu, NULL,
NULL, NULL, NULL);
isst_ctdp_display_information_end(outf);
}
......@@ -2269,7 +2328,7 @@ static void dump_clos_info(int arg)
for_each_online_target_cpu_in_set(get_clos_info_for_cpu, NULL,
NULL, NULL, NULL);
else
for_each_online_package_in_set(get_clos_info_for_cpu, NULL,
for_each_online_power_domain_in_set(get_clos_info_for_cpu, NULL,
NULL, NULL, NULL);
isst_ctdp_display_information_end(outf);
......@@ -2281,6 +2340,9 @@ static void set_clos_config_for_cpu(struct isst_id *id, void *arg1, void *arg2,
struct isst_clos_config clos_config;
int ret;
if (id->cpu < 0)
return;
clos_config.epp = clos_epp;
clos_config.clos_prop_prio = clos_prop_prio;
clos_config.clos_min = clos_min;
......@@ -2341,7 +2403,7 @@ static void set_clos_config(int arg)
for_each_online_target_cpu_in_set(set_clos_config_for_cpu, NULL,
NULL, NULL, NULL);
else
for_each_online_package_in_set(set_clos_config_for_cpu, NULL,
for_each_online_power_domain_in_set(set_clos_config_for_cpu, NULL,
NULL, NULL, NULL);
isst_ctdp_display_information_end(outf);
}
......@@ -2508,7 +2570,7 @@ static void process_trl(int arg)
for_each_online_target_cpu_in_set(get_set_trl, NULL,
NULL, NULL, &arg);
else
for_each_online_package_in_set(get_set_trl, NULL,
for_each_online_power_domain_in_set(get_set_trl, NULL,
NULL, NULL, &arg);
isst_ctdp_display_information_end(outf);
}
......@@ -2683,7 +2745,7 @@ static void parse_cmd_args(int argc, int start, char **argv)
break;
case 'd':
clos_desired = atoi(optarg);
clos_desired /= DISP_FREQ_MULTIPLIER;
clos_desired /= isst_get_disp_freq_multiplier();
break;
case 'e':
clos_epp = atoi(optarg);
......@@ -2694,11 +2756,11 @@ static void parse_cmd_args(int argc, int start, char **argv)
break;
case 'n':
clos_min = atoi(optarg);
clos_min /= DISP_FREQ_MULTIPLIER;
clos_min /= isst_get_disp_freq_multiplier();
break;
case 'm':
clos_max = atoi(optarg);
clos_max /= DISP_FREQ_MULTIPLIER;
clos_max /= isst_get_disp_freq_multiplier();
break;
case 'p':
clos_priority_type = atoi(optarg);
......@@ -2882,6 +2944,7 @@ static void usage(void)
printf("\t[-b|--oob : Start a daemon to process HFI events for perf profile change from Out of Band agent.\n");
printf("\t[-n|--no-daemon : Don't run as daemon. By default --oob will turn on daemon mode\n");
printf("\t[-w|--delay : Delay for reading config level state change in OOB poll mode.\n");
printf("\t[-g|--cgroupv2 : Try to use cgroup v2 CPU isolation instead of CPU online/offline.\n");
printf("\nResult format\n");
printf("\tResult display uses a common format for each command:\n");
printf("\tResults are formatted in text/JSON with\n");
......@@ -2918,6 +2981,7 @@ static void cmdline(int argc, char **argv)
int oob_mode = 0;
int poll_interval = -1;
int no_daemon = 0;
int mbox_delay = 0, mbox_retries = 3;
static struct option long_options[] = {
{ "all-cpus-online", no_argument, 0, 'a' },
......@@ -2933,6 +2997,7 @@ static void cmdline(int argc, char **argv)
{ "oob", no_argument, 0, 'b' },
{ "no-daemon", no_argument, 0, 'n' },
{ "poll-interval", required_argument, 0, 'w' },
{ "cgroupv2", required_argument, 0, 'g' },
{ 0, 0, 0, 0 }
};
......@@ -2958,8 +3023,12 @@ static void cmdline(int argc, char **argv)
fclose(fp);
}
ret = isst_fill_platform_info();
if (ret)
goto out;
progname = argv[0];
while ((opt = getopt_long_only(argc, argv, "+c:df:hio:vabw:n", long_options,
while ((opt = getopt_long_only(argc, argv, "+c:df:hio:vabw:ng", long_options,
&option_index)) != -1) {
switch (opt) {
case 'a':
......@@ -3018,6 +3087,9 @@ static void cmdline(int argc, char **argv)
}
poll_interval = ret;
break;
case 'g':
cgroupv2 = 1;
break;
default:
usage();
}
......@@ -3027,6 +3099,10 @@ static void cmdline(int argc, char **argv)
usage();
exit(0);
}
isst_update_platform_param(ISST_PARAM_MBOX_DELAY, mbox_delay);
isst_update_platform_param(ISST_PARAM_MBOX_RETRIES, mbox_retries);
set_max_cpu_num();
if (force_cpus_online)
force_all_cpus_online();
......@@ -3044,9 +3120,6 @@ static void cmdline(int argc, char **argv)
}
if (!is_clx_n_platform()) {
ret = isst_fill_platform_info();
if (ret)
goto out;
process_command(argc, argv, isst_help_cmds, isst_cmds);
} else {
process_command(argc, argv, clx_n_help_cmds, clx_n_cmds);
......
// SPDX-License-Identifier: GPL-2.0
/*
* Intel Speed Select -- Enumerate and control features for Mailbox Interface
* Copyright (c) 2023 Intel Corporation.
*/
#include "isst.h"
static int mbox_delay;
static int mbox_retries = 3;
#define MAX_TRL_LEVELS_EMR 5
static int mbox_get_disp_freq_multiplier(void)
{
return DISP_FREQ_MULTIPLIER;
}
static int mbox_get_trl_max_levels(void)
{
if (is_emr_platform())
return MAX_TRL_LEVELS_EMR;
return 3;
}
static char *mbox_get_trl_level_name(int level)
{
if (is_emr_platform()) {
static char level_str[18];
if (level >= MAX_TRL_LEVELS_EMR)
return NULL;
snprintf(level_str, sizeof(level_str), "level-%d", level);
return level_str;
}
switch (level) {
case 0:
return "sse";
case 1:
return "avx2";
case 2:
return "avx512";
default:
return NULL;
}
}
static void mbox_update_platform_param(enum isst_platform_param param, int value)
{
switch (param) {
case ISST_PARAM_MBOX_DELAY:
mbox_delay = value;
break;
case ISST_PARAM_MBOX_RETRIES:
mbox_retries = value;
break;
default:
break;
}
}
static int mbox_is_punit_valid(struct isst_id *id)
{
if (id->cpu < 0)
return 0;
if (id->pkg < 0 || id->die < 0 || id->punit)
return 0;
return 1;
}
static int _send_mmio_command(unsigned int cpu, unsigned int reg, int write,
unsigned int *value)
{
struct isst_if_io_regs io_regs;
const char *pathname = "/dev/isst_interface";
int cmd;
FILE *outf = get_output_file();
int fd;
debug_printf("mmio_cmd cpu:%d reg:%d write:%d\n", cpu, reg, write);
fd = open(pathname, O_RDWR);
if (fd < 0)
err(-1, "%s open failed", pathname);
io_regs.req_count = 1;
io_regs.io_reg[0].logical_cpu = cpu;
io_regs.io_reg[0].reg = reg;
cmd = ISST_IF_IO_CMD;
if (write) {
io_regs.io_reg[0].read_write = 1;
io_regs.io_reg[0].value = *value;
} else {
io_regs.io_reg[0].read_write = 0;
}
if (ioctl(fd, cmd, &io_regs) == -1) {
if (errno == ENOTTY) {
perror("ISST_IF_IO_COMMAND\n");
fprintf(stderr, "Check presence of kernel modules: isst_if_mmio\n");
exit(0);
}
fprintf(outf, "Error: mmio_cmd cpu:%d reg:%x read_write:%x\n",
cpu, reg, write);
} else {
if (!write)
*value = io_regs.io_reg[0].value;
debug_printf(
"mmio_cmd response: cpu:%d reg:%x rd_write:%x resp:%x\n",
cpu, reg, write, *value);
}
close(fd);
return 0;
}
int _send_mbox_command(unsigned int cpu, unsigned char command,
unsigned char sub_command, unsigned int parameter,
unsigned int req_data, unsigned int *resp)
{
const char *pathname = "/dev/isst_interface";
int fd, retry;
struct isst_if_mbox_cmds mbox_cmds = { 0 };
debug_printf(
"mbox_send: cpu:%d command:%x sub_command:%x parameter:%x req_data:%x\n",
cpu, command, sub_command, parameter, req_data);
if (!is_skx_based_platform() && command == CONFIG_CLOS &&
sub_command != CLOS_PM_QOS_CONFIG) {
unsigned int value;
int write = 0;
int clos_id, core_id, ret = 0;
debug_printf("CPU %d\n", cpu);
if (parameter & BIT(MBOX_CMD_WRITE_BIT)) {
value = req_data;
write = 1;
}
switch (sub_command) {
case CLOS_PQR_ASSOC:
core_id = parameter & 0xff;
ret = _send_mmio_command(
cpu, PQR_ASSOC_OFFSET + core_id * 4, write,
&value);
if (!ret && !write)
*resp = value;
break;
case CLOS_PM_CLOS:
clos_id = parameter & 0x03;
ret = _send_mmio_command(
cpu, PM_CLOS_OFFSET + clos_id * 4, write,
&value);
if (!ret && !write)
*resp = value;
break;
case CLOS_STATUS:
break;
default:
break;
}
return ret;
}
mbox_cmds.cmd_count = 1;
mbox_cmds.mbox_cmd[0].logical_cpu = cpu;
mbox_cmds.mbox_cmd[0].command = command;
mbox_cmds.mbox_cmd[0].sub_command = sub_command;
mbox_cmds.mbox_cmd[0].parameter = parameter;
mbox_cmds.mbox_cmd[0].req_data = req_data;
if (mbox_delay)
usleep(mbox_delay * 1000);
fd = open(pathname, O_RDWR);
if (fd < 0)
err(-1, "%s open failed", pathname);
retry = mbox_retries;
do {
if (ioctl(fd, ISST_IF_MBOX_COMMAND, &mbox_cmds) == -1) {
if (errno == ENOTTY) {
perror("ISST_IF_MBOX_COMMAND\n");
fprintf(stderr, "Check presence of kernel modules: isst_if_mbox_pci or isst_if_mbox_msr\n");
exit(0);
}
debug_printf(
"Error: mbox_cmd cpu:%d command:%x sub_command:%x parameter:%x req_data:%x errorno:%d\n",
cpu, command, sub_command, parameter, req_data, errno);
--retry;
} else {
*resp = mbox_cmds.mbox_cmd[0].resp_data;
debug_printf(
"mbox_cmd response: cpu:%d command:%x sub_command:%x parameter:%x req_data:%x resp:%x\n",
cpu, command, sub_command, parameter, req_data, *resp);
break;
}
} while (retry);
close(fd);
if (!retry) {
debug_printf("Failed mbox command even after retries\n");
return -1;
}
return 0;
}
static int mbox_read_pm_config(struct isst_id *id, int *cp_state, int *cp_cap)
{
unsigned int resp;
int ret;
ret = _send_mbox_command(id->cpu, READ_PM_CONFIG, PM_FEATURE, 0, 0,
&resp);
if (ret)
return ret;
debug_printf("cpu:%d READ_PM_CONFIG resp:%x\n", id->cpu, resp);
*cp_state = resp & BIT(16);
*cp_cap = resp & BIT(0) ? 1 : 0;
return 0;
}
static int mbox_get_config_levels(struct isst_id *id, struct isst_pkg_ctdp *pkg_dev)
{
unsigned int resp;
int ret;
ret = _send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_GET_LEVELS_INFO, 0, 0, &resp);
if (ret) {
pkg_dev->levels = 0;
pkg_dev->locked = 1;
pkg_dev->current_level = 0;
pkg_dev->version = 0;
pkg_dev->enabled = 0;
return 0;
}
debug_printf("cpu:%d CONFIG_TDP_GET_LEVELS_INFO resp:%x\n", id->cpu, resp);
pkg_dev->version = resp & 0xff;
pkg_dev->levels = (resp >> 8) & 0xff;
pkg_dev->current_level = (resp >> 16) & 0xff;
pkg_dev->locked = !!(resp & BIT(24));
pkg_dev->enabled = !!(resp & BIT(31));
return 0;
}
static int mbox_get_ctdp_control(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
{
int cp_state, cp_cap;
unsigned int resp;
int ret;
ret = _send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_GET_TDP_CONTROL, 0,
config_index, &resp);
if (ret)
return ret;
ctdp_level->fact_support = resp & BIT(0);
ctdp_level->pbf_support = !!(resp & BIT(1));
ctdp_level->fact_enabled = !!(resp & BIT(16));
ctdp_level->pbf_enabled = !!(resp & BIT(17));
ret = isst_read_pm_config(id, &cp_state, &cp_cap);
if (ret) {
debug_printf("cpu:%d pm_config is not supported\n", id->cpu);
} else {
debug_printf("cpu:%d pm_config SST-CP state:%d cap:%d\n", id->cpu, cp_state, cp_cap);
ctdp_level->sst_cp_support = cp_cap;
ctdp_level->sst_cp_enabled = cp_state;
}
debug_printf(
"cpu:%d CONFIG_TDP_GET_TDP_CONTROL resp:%x fact_support:%d pbf_support: %d fact_enabled:%d pbf_enabled:%d\n",
id->cpu, resp, ctdp_level->fact_support, ctdp_level->pbf_support,
ctdp_level->fact_enabled, ctdp_level->pbf_enabled);
return 0;
}
static void _get_uncore_p0_p1_info(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
{
unsigned int resp;
int ret;
ctdp_level->uncore_pm = 0;
ctdp_level->uncore_p0 = 0;
ctdp_level->uncore_p1 = 0;
ret = _send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_GET_RATIO_INFO, 0,
(BIT(16) | config_index) , &resp);
if (ret) {
goto try_uncore_mbox;
}
ctdp_level->uncore_p0 = resp & GENMASK(7, 0);
ctdp_level->uncore_p1 = (resp & GENMASK(15, 8)) >> 8;
ctdp_level->uncore_pm = (resp & GENMASK(31, 24)) >> 24;
debug_printf(
"cpu:%d ctdp:%d CONFIG_TDP_GET_RATIO_INFO resp:%x uncore p0:%d uncore p1:%d uncore pm:%d\n",
id->cpu, config_index, resp, ctdp_level->uncore_p0, ctdp_level->uncore_p1,
ctdp_level->uncore_pm);
return;
try_uncore_mbox:
ret = _send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_GET_UNCORE_P0_P1_INFO, 0,
config_index, &resp);
if (ret) {
ctdp_level->uncore_p0 = 0;
ctdp_level->uncore_p1 = 0;
return;
}
ctdp_level->uncore_p0 = resp & GENMASK(7, 0);
ctdp_level->uncore_p1 = (resp & GENMASK(15, 8)) >> 8;
debug_printf(
"cpu:%d ctdp:%d CONFIG_TDP_GET_UNCORE_P0_P1_INFO resp:%x uncore p0:%d uncore p1:%d\n",
id->cpu, config_index, resp, ctdp_level->uncore_p0,
ctdp_level->uncore_p1);
}
static int _set_uncore_min_max(struct isst_id *id, int max, int freq)
{
char buffer[128], freq_str[16];
int fd, ret, len;
if (max)
snprintf(buffer, sizeof(buffer),
"/sys/devices/system/cpu/intel_uncore_frequency/package_%02d_die_%02d/max_freq_khz", id->pkg, id->die);
else
snprintf(buffer, sizeof(buffer),
"/sys/devices/system/cpu/intel_uncore_frequency/package_%02d_die_%02d/min_freq_khz", id->pkg, id->die);
fd = open(buffer, O_WRONLY);
if (fd < 0)
return fd;
snprintf(freq_str, sizeof(freq_str), "%d", freq);
len = strlen(freq_str);
ret = write(fd, freq_str, len);
if (ret == -1) {
close(fd);
return ret;
}
close(fd);
return 0;
}
static void mbox_adjust_uncore_freq(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
{
_get_uncore_p0_p1_info(id, config_index, ctdp_level);
if (ctdp_level->uncore_pm)
_set_uncore_min_max(id, 0, ctdp_level->uncore_pm * 100000);
if (ctdp_level->uncore_p0)
_set_uncore_min_max(id, 1, ctdp_level->uncore_p0 * 100000);
}
static void _get_p1_info(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
{
unsigned int resp;
int ret;
ret = _send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_GET_P1_INFO, 0,
config_index, &resp);
if (ret) {
ctdp_level->sse_p1 = 0;
ctdp_level->avx2_p1 = 0;
ctdp_level->avx512_p1 = 0;
return;
}
ctdp_level->sse_p1 = resp & GENMASK(7, 0);
ctdp_level->avx2_p1 = (resp & GENMASK(15, 8)) >> 8;
ctdp_level->avx512_p1 = (resp & GENMASK(23, 16)) >> 16;
ctdp_level->amx_p1 = (resp & GENMASK(31, 24)) >> 24;
debug_printf(
"cpu:%d ctdp:%d CONFIG_TDP_GET_P1_INFO resp:%x sse_p1:%d avx2_p1:%d avx512_p1:%d amx_p1:%d\n",
id->cpu, config_index, resp, ctdp_level->sse_p1,
ctdp_level->avx2_p1, ctdp_level->avx512_p1, ctdp_level->amx_p1);
}
static void _get_uncore_mem_freq(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
{
unsigned int resp;
int ret;
ret = _send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_GET_MEM_FREQ,
0, config_index, &resp);
if (ret) {
ctdp_level->mem_freq = 0;
return;
}
ctdp_level->mem_freq = resp & GENMASK(7, 0);
if (is_spr_platform() || is_emr_platform()) {
ctdp_level->mem_freq *= 200;
} else if (is_icx_platform()) {
if (ctdp_level->mem_freq < 7) {
ctdp_level->mem_freq = (12 - ctdp_level->mem_freq) * 133.33 * 2 * 10;
ctdp_level->mem_freq /= 10;
if (ctdp_level->mem_freq % 10 > 5)
ctdp_level->mem_freq++;
} else {
ctdp_level->mem_freq = 0;
}
} else {
ctdp_level->mem_freq = 0;
}
debug_printf(
"cpu:%d ctdp:%d CONFIG_TDP_GET_MEM_FREQ resp:%x uncore mem_freq:%d\n",
id->cpu, config_index, resp, ctdp_level->mem_freq);
}
static int mbox_get_tdp_info(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
{
unsigned int resp;
int ret;
ret = _send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_GET_TDP_INFO,
0, config_index, &resp);
if (ret) {
isst_display_error_info_message(1, "Invalid level, Can't get TDP information at level", 1, config_index);
return ret;
}
ctdp_level->pkg_tdp = resp & GENMASK(14, 0);
ctdp_level->tdp_ratio = (resp & GENMASK(23, 16)) >> 16;
debug_printf(
"cpu:%d ctdp:%d CONFIG_TDP_GET_TDP_INFO resp:%x tdp_ratio:%d pkg_tdp:%d\n",
id->cpu, config_index, resp, ctdp_level->tdp_ratio,
ctdp_level->pkg_tdp);
ret = _send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_GET_TJMAX_INFO,
0, config_index, &resp);
if (ret)
return ret;
ctdp_level->t_proc_hot = resp & GENMASK(7, 0);
_get_uncore_p0_p1_info(id, config_index, ctdp_level);
_get_p1_info(id, config_index, ctdp_level);
_get_uncore_mem_freq(id, config_index, ctdp_level);
debug_printf(
"cpu:%d ctdp:%d CONFIG_TDP_GET_TJMAX_INFO resp:%x t_proc_hot:%d\n",
id->cpu, config_index, resp, ctdp_level->t_proc_hot);
return 0;
}
static int mbox_get_pwr_info(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
{
unsigned int resp;
int ret;
ret = _send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_GET_PWR_INFO,
0, config_index, &resp);
if (ret)
return ret;
ctdp_level->pkg_max_power = resp & GENMASK(14, 0);
ctdp_level->pkg_min_power = (resp & GENMASK(30, 16)) >> 16;
debug_printf(
"cpu:%d ctdp:%d CONFIG_TDP_GET_PWR_INFO resp:%x pkg_max_power:%d pkg_min_power:%d\n",
id->cpu, config_index, resp, ctdp_level->pkg_max_power,
ctdp_level->pkg_min_power);
return 0;
}
static int mbox_get_coremask_info(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
{
unsigned int resp;
int i, ret;
ctdp_level->cpu_count = 0;
for (i = 0; i < 2; ++i) {
unsigned long long mask;
int cpu_count = 0;
ret = _send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_GET_CORE_MASK, 0,
(i << 8) | config_index, &resp);
if (ret)
return ret;
debug_printf(
"cpu:%d ctdp:%d mask:%d CONFIG_TDP_GET_CORE_MASK resp:%x\n",
id->cpu, config_index, i, resp);
mask = (unsigned long long)resp << (32 * i);
set_cpu_mask_from_punit_coremask(id, mask,
ctdp_level->core_cpumask_size,
ctdp_level->core_cpumask,
&cpu_count);
ctdp_level->cpu_count += cpu_count;
debug_printf("cpu:%d ctdp:%d mask:%d cpu count:%d\n", id->cpu,
config_index, i, ctdp_level->cpu_count);
}
return 0;
}
static int mbox_get_get_trl(struct isst_id *id, int level, int avx_level, int *trl)
{
unsigned int req, resp;
int ret;
req = level | (avx_level << 16);
ret = _send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_GET_TURBO_LIMIT_RATIOS, 0, req,
&resp);
if (ret)
return ret;
debug_printf(
"cpu:%d CONFIG_TDP_GET_TURBO_LIMIT_RATIOS req:%x resp:%x\n",
id->cpu, req, resp);
trl[0] = resp & GENMASK(7, 0);
trl[1] = (resp & GENMASK(15, 8)) >> 8;
trl[2] = (resp & GENMASK(23, 16)) >> 16;
trl[3] = (resp & GENMASK(31, 24)) >> 24;
req = level | BIT(8) | (avx_level << 16);
ret = _send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_GET_TURBO_LIMIT_RATIOS, 0, req,
&resp);
if (ret)
return ret;
debug_printf("cpu:%d CONFIG_TDP_GET_TURBO_LIMIT req:%x resp:%x\n", id->cpu,
req, resp);
trl[4] = resp & GENMASK(7, 0);
trl[5] = (resp & GENMASK(15, 8)) >> 8;
trl[6] = (resp & GENMASK(23, 16)) >> 16;
trl[7] = (resp & GENMASK(31, 24)) >> 24;
return 0;
}
static int mbox_get_get_trls(struct isst_id *id, int level, struct isst_pkg_ctdp_level_info *ctdp_level)
{
int trl_max_levels = isst_get_trl_max_levels();
int i, ret;
for (i = 0; i < trl_max_levels; i++) {
ret = mbox_get_get_trl(id, level, i, ctdp_level->trl_ratios[i]);
if (ret)
return ret;
}
return 0;
}
static int mbox_get_trl_bucket_info(struct isst_id *id, int level, unsigned long long *buckets_info)
{
int ret;
debug_printf("cpu:%d bucket info via MSR\n", id->cpu);
*buckets_info = 0;
ret = isst_send_msr_command(id->cpu, 0x1ae, 0, buckets_info);
if (ret)
return ret;
debug_printf("cpu:%d bucket info via MSR successful 0x%llx\n", id->cpu,
*buckets_info);
return 0;
}
static int mbox_set_tdp_level(struct isst_id *id, int tdp_level)
{
unsigned int resp;
int ret;
if (isst_get_config_tdp_lock_status(id)) {
isst_display_error_info_message(1, "TDP is locked", 0, 0);
return -1;
}
ret = _send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_SET_LEVEL, 0,
tdp_level, &resp);
if (ret) {
isst_display_error_info_message(1, "Set TDP level failed for level", 1, tdp_level);
return ret;
}
return 0;
}
static int mbox_get_pbf_info(struct isst_id *id, int level, struct isst_pbf_info *pbf_info)
{
int max_punit_core, max_mask_index;
unsigned int req, resp;
int i, ret;
max_punit_core = get_max_punit_core_id(id);
max_mask_index = max_punit_core > 32 ? 2 : 1;
for (i = 0; i < max_mask_index; ++i) {
unsigned long long mask;
int count;
ret = _send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_PBF_GET_CORE_MASK_INFO,
0, (i << 8) | level, &resp);
if (ret)
break;
debug_printf(
"cpu:%d CONFIG_TDP_PBF_GET_CORE_MASK_INFO resp:%x\n",
id->cpu, resp);
mask = (unsigned long long)resp << (32 * i);
set_cpu_mask_from_punit_coremask(id, mask,
pbf_info->core_cpumask_size,
pbf_info->core_cpumask,
&count);
}
req = level;
ret = _send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_PBF_GET_P1HI_P1LO_INFO, 0, req,
&resp);
if (ret)
return ret;
debug_printf("cpu:%d CONFIG_TDP_PBF_GET_P1HI_P1LO_INFO resp:%x\n", id->cpu,
resp);
pbf_info->p1_low = resp & 0xff;
pbf_info->p1_high = (resp & GENMASK(15, 8)) >> 8;
req = level;
ret = _send_mbox_command(
id->cpu, CONFIG_TDP, CONFIG_TDP_PBF_GET_TDP_INFO, 0, req, &resp);
if (ret)
return ret;
debug_printf("cpu:%d CONFIG_TDP_PBF_GET_TDP_INFO resp:%x\n", id->cpu, resp);
pbf_info->tdp = resp & 0xffff;
req = level;
ret = _send_mbox_command(
id->cpu, CONFIG_TDP, CONFIG_TDP_PBF_GET_TJ_MAX_INFO, 0, req, &resp);
if (ret)
return ret;
debug_printf("cpu:%d CONFIG_TDP_PBF_GET_TJ_MAX_INFO resp:%x\n", id->cpu,
resp);
pbf_info->t_control = (resp >> 8) & 0xff;
pbf_info->t_prochot = resp & 0xff;
return 0;
}
static int mbox_set_pbf_fact_status(struct isst_id *id, int pbf, int enable)
{
struct isst_pkg_ctdp pkg_dev;
struct isst_pkg_ctdp_level_info ctdp_level;
int current_level;
unsigned int req = 0, resp;
int ret;
ret = isst_get_ctdp_levels(id, &pkg_dev);
if (ret)
debug_printf("cpu:%d No support for dynamic ISST\n", id->cpu);
current_level = pkg_dev.current_level;
ret = isst_get_ctdp_control(id, current_level, &ctdp_level);
if (ret)
return ret;
if (pbf) {
if (ctdp_level.fact_enabled)
req = BIT(16);
if (enable)
req |= BIT(17);
else
req &= ~BIT(17);
} else {
if (enable && !ctdp_level.sst_cp_enabled)
isst_display_error_info_message(0, "Make sure to execute before: core-power enable", 0, 0);
if (ctdp_level.pbf_enabled)
req = BIT(17);
if (enable)
req |= BIT(16);
else
req &= ~BIT(16);
}
ret = _send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_SET_TDP_CONTROL, 0, req, &resp);
if (ret)
return ret;
debug_printf("cpu:%d CONFIG_TDP_SET_TDP_CONTROL pbf/fact:%d req:%x\n",
id->cpu, pbf, req);
return 0;
}
static int _get_fact_bucket_info(struct isst_id *id, int level,
struct isst_fact_bucket_info *bucket_info)
{
unsigned int resp;
int i, k, ret;
for (i = 0; i < 2; ++i) {
int j;
ret = _send_mbox_command(
id->cpu, CONFIG_TDP,
CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_NUMCORES, 0,
(i << 8) | level, &resp);
if (ret)
return ret;
debug_printf(
"cpu:%d CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_NUMCORES index:%d level:%d resp:%x\n",
id->cpu, i, level, resp);
for (j = 0; j < 4; ++j) {
bucket_info[j + (i * 4)].hp_cores =
(resp >> (j * 8)) & 0xff;
}
}
for (k = 0; k < 3; ++k) {
for (i = 0; i < 2; ++i) {
int j;
ret = _send_mbox_command(
id->cpu, CONFIG_TDP,
CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_RATIOS, 0,
(k << 16) | (i << 8) | level, &resp);
if (ret)
return ret;
debug_printf(
"cpu:%d CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_RATIOS index:%d level:%d avx:%d resp:%x\n",
id->cpu, i, level, k, resp);
for (j = 0; j < 4; ++j) {
bucket_info[j + (i * 4)].hp_ratios[k] =
(resp >> (j * 8)) & 0xff;
}
}
}
return 0;
}
static int mbox_get_fact_info(struct isst_id *id, int level, int fact_bucket, struct isst_fact_info *fact_info)
{
unsigned int resp;
int j, ret, print;
ret = _send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_GET_FACT_LP_CLIPPING_RATIO, 0,
level, &resp);
if (ret)
return ret;
debug_printf("cpu:%d CONFIG_TDP_GET_FACT_LP_CLIPPING_RATIO resp:%x\n",
id->cpu, resp);
fact_info->lp_ratios[0] = resp & 0xff;
fact_info->lp_ratios[1] = (resp >> 8) & 0xff;
fact_info->lp_ratios[2] = (resp >> 16) & 0xff;
ret = _get_fact_bucket_info(id, level, fact_info->bucket_info);
if (ret)
return ret;
print = 0;
for (j = 0; j < ISST_FACT_MAX_BUCKETS; ++j) {
if (fact_bucket != 0xff && fact_bucket != j)
continue;
if (!fact_info->bucket_info[j].hp_cores)
break;
print = 1;
}
if (!print) {
isst_display_error_info_message(1, "Invalid bucket", 0, 0);
return -1;
}
return 0;
}
static int mbox_get_clos_information(struct isst_id *id, int *enable, int *type)
{
unsigned int resp;
int ret;
ret = _send_mbox_command(id->cpu, CONFIG_CLOS, CLOS_PM_QOS_CONFIG, 0, 0,
&resp);
if (ret)
return ret;
debug_printf("cpu:%d CLOS_PM_QOS_CONFIG resp:%x\n", id->cpu, resp);
if (resp & BIT(1))
*enable = 1;
else
*enable = 0;
if (resp & BIT(2))
*type = 1;
else
*type = 0;
return 0;
}
static int _write_pm_config(struct isst_id *id, int cp_state)
{
unsigned int req, resp;
int ret;
if (cp_state)
req = BIT(16);
else
req = 0;
ret = _send_mbox_command(id->cpu, WRITE_PM_CONFIG, PM_FEATURE, 0, req,
&resp);
if (ret)
return ret;
debug_printf("cpu:%d WRITE_PM_CONFIG resp:%x\n", id->cpu, resp);
return 0;
}
static int mbox_pm_qos_config(struct isst_id *id, int enable_clos, int priority_type)
{
unsigned int req, resp;
int ret;
if (!enable_clos) {
struct isst_pkg_ctdp pkg_dev;
struct isst_pkg_ctdp_level_info ctdp_level;
ret = isst_get_ctdp_levels(id, &pkg_dev);
if (ret) {
debug_printf("isst_get_ctdp_levels\n");
return ret;
}
ret = isst_get_ctdp_control(id, pkg_dev.current_level,
&ctdp_level);
if (ret)
return ret;
if (ctdp_level.fact_enabled) {
isst_display_error_info_message(1, "Ignoring request, turbo-freq feature is still enabled", 0, 0);
return -EINVAL;
}
ret = _write_pm_config(id, 0);
if (ret)
isst_display_error_info_message(0, "WRITE_PM_CONFIG command failed, ignoring error", 0, 0);
} else {
ret = _write_pm_config(id, 1);
if (ret)
isst_display_error_info_message(0, "WRITE_PM_CONFIG command failed, ignoring error", 0, 0);
}
ret = _send_mbox_command(id->cpu, CONFIG_CLOS, CLOS_PM_QOS_CONFIG, 0, 0,
&resp);
if (ret) {
isst_display_error_info_message(1, "CLOS_PM_QOS_CONFIG command failed", 0, 0);
return ret;
}
debug_printf("cpu:%d CLOS_PM_QOS_CONFIG resp:%x\n", id->cpu, resp);
req = resp;
if (enable_clos)
req = req | BIT(1);
else
req = req & ~BIT(1);
if (priority_type > 1)
isst_display_error_info_message(1, "Invalid priority type: Changing type to ordered", 0, 0);
if (priority_type)
req = req | BIT(2);
else
req = req & ~BIT(2);
ret = _send_mbox_command(id->cpu, CONFIG_CLOS, CLOS_PM_QOS_CONFIG,
BIT(MBOX_CMD_WRITE_BIT), req, &resp);
if (ret)
return ret;
debug_printf("cpu:%d CLOS_PM_QOS_CONFIG priority type:%d req:%x\n", id->cpu,
priority_type, req);
return 0;
}
static int mbox_pm_get_clos(struct isst_id *id, int clos, struct isst_clos_config *clos_config)
{
unsigned int resp;
int ret;
ret = _send_mbox_command(id->cpu, CONFIG_CLOS, CLOS_PM_CLOS, clos, 0,
&resp);
if (ret)
return ret;
clos_config->epp = resp & 0x0f;
clos_config->clos_prop_prio = (resp >> 4) & 0x0f;
clos_config->clos_min = (resp >> 8) & 0xff;
clos_config->clos_max = (resp >> 16) & 0xff;
clos_config->clos_desired = (resp >> 24) & 0xff;
return 0;
}
static int mbox_set_clos(struct isst_id *id, int clos, struct isst_clos_config *clos_config)
{
unsigned int req, resp;
unsigned int param;
int ret;
req = clos_config->epp & 0x0f;
req |= (clos_config->clos_prop_prio & 0x0f) << 4;
req |= (clos_config->clos_min & 0xff) << 8;
req |= (clos_config->clos_max & 0xff) << 16;
req |= (clos_config->clos_desired & 0xff) << 24;
param = BIT(MBOX_CMD_WRITE_BIT) | clos;
ret = _send_mbox_command(id->cpu, CONFIG_CLOS, CLOS_PM_CLOS, param, req,
&resp);
if (ret)
return ret;
debug_printf("cpu:%d CLOS_PM_CLOS param:%x req:%x\n", id->cpu, param, req);
return 0;
}
static int mbox_clos_get_assoc_status(struct isst_id *id, int *clos_id)
{
unsigned int resp;
unsigned int param;
int core_id, ret;
core_id = find_phy_core_num(id->cpu);
param = core_id;
ret = _send_mbox_command(id->cpu, CONFIG_CLOS, CLOS_PQR_ASSOC, param, 0,
&resp);
if (ret)
return ret;
debug_printf("cpu:%d CLOS_PQR_ASSOC param:%x resp:%x\n", id->cpu, param,
resp);
*clos_id = (resp >> 16) & 0x03;
return 0;
}
static int mbox_clos_associate(struct isst_id *id, int clos_id)
{
unsigned int req, resp;
unsigned int param;
int core_id, ret;
req = (clos_id & 0x03) << 16;
core_id = find_phy_core_num(id->cpu);
param = BIT(MBOX_CMD_WRITE_BIT) | core_id;
ret = _send_mbox_command(id->cpu, CONFIG_CLOS, CLOS_PQR_ASSOC, param,
req, &resp);
if (ret)
return ret;
debug_printf("cpu:%d CLOS_PQR_ASSOC param:%x req:%x\n", id->cpu, param,
req);
return 0;
}
static struct isst_platform_ops mbox_ops = {
.get_disp_freq_multiplier = mbox_get_disp_freq_multiplier,
.get_trl_max_levels = mbox_get_trl_max_levels,
.get_trl_level_name = mbox_get_trl_level_name,
.update_platform_param = mbox_update_platform_param,
.is_punit_valid = mbox_is_punit_valid,
.read_pm_config = mbox_read_pm_config,
.get_config_levels = mbox_get_config_levels,
.get_ctdp_control = mbox_get_ctdp_control,
.get_tdp_info = mbox_get_tdp_info,
.get_pwr_info = mbox_get_pwr_info,
.get_coremask_info = mbox_get_coremask_info,
.get_get_trl = mbox_get_get_trl,
.get_get_trls = mbox_get_get_trls,
.get_trl_bucket_info = mbox_get_trl_bucket_info,
.set_tdp_level = mbox_set_tdp_level,
.get_pbf_info = mbox_get_pbf_info,
.set_pbf_fact_status = mbox_set_pbf_fact_status,
.get_fact_info = mbox_get_fact_info,
.adjust_uncore_freq = mbox_adjust_uncore_freq,
.get_clos_information = mbox_get_clos_information,
.pm_qos_config = mbox_pm_qos_config,
.pm_get_clos = mbox_pm_get_clos,
.set_clos = mbox_set_clos,
.clos_get_assoc_status = mbox_clos_get_assoc_status,
.clos_associate = mbox_clos_associate,
};
struct isst_platform_ops *mbox_get_platform_ops(void)
{
return &mbox_ops;
}
// SPDX-License-Identifier: GPL-2.0
/*
* Intel Speed Select -- Enumerate and control features for TPMI Interface
* Copyright (c) 2022 Intel Corporation.
*/
#include <linux/isst_if.h>
#include "isst.h"
int tpmi_process_ioctl(int ioctl_no, void *info)
{
const char *pathname = "/dev/isst_interface";
int fd;
if (is_debug_enabled()) {
debug_printf("Issue IOCTL: ");
switch (ioctl_no) {
case ISST_IF_CORE_POWER_STATE:
debug_printf("ISST_IF_CORE_POWER_STATE\n");
break;
case ISST_IF_CLOS_PARAM:
debug_printf("ISST_IF_CLOS_PARAM\n");
break;
case ISST_IF_CLOS_ASSOC:
debug_printf("ISST_IF_CLOS_ASSOC\n");
break;
case ISST_IF_PERF_LEVELS:
debug_printf("ISST_IF_PERF_LEVELS\n");
break;
case ISST_IF_PERF_SET_LEVEL:
debug_printf("ISST_IF_PERF_SET_LEVEL\n");
break;
case ISST_IF_PERF_SET_FEATURE:
debug_printf("ISST_IF_PERF_SET_FEATURE\n");
break;
case ISST_IF_GET_PERF_LEVEL_INFO:
debug_printf("ISST_IF_GET_PERF_LEVEL_INFO\n");
break;
case ISST_IF_GET_PERF_LEVEL_CPU_MASK:
debug_printf("ISST_IF_GET_PERF_LEVEL_CPU_MASK\n");
break;
case ISST_IF_GET_BASE_FREQ_INFO:
debug_printf("ISST_IF_GET_BASE_FREQ_INFO\n");
break;
case ISST_IF_GET_BASE_FREQ_CPU_MASK:
debug_printf("ISST_IF_GET_BASE_FREQ_CPU_MASK\n");
break;
case ISST_IF_GET_TURBO_FREQ_INFO:
debug_printf("ISST_IF_GET_TURBO_FREQ_INFO\n");
break;
case ISST_IF_COUNT_TPMI_INSTANCES:
debug_printf("ISST_IF_COUNT_TPMI_INSTANCES\n");
break;
default:
debug_printf("%d\n", ioctl_no);
break;
}
}
fd = open(pathname, O_RDWR);
if (fd < 0)
return -1;
if (ioctl(fd, ioctl_no, info) == -1) {
debug_printf("IOCTL %d Failed\n", ioctl_no);
close(fd);
return -1;
}
close(fd);
return 0;
}
static int tpmi_get_disp_freq_multiplier(void)
{
return 1;
}
static int tpmi_get_trl_max_levels(void)
{
return TRL_MAX_LEVELS;
}
static char *tpmi_get_trl_level_name(int level)
{
switch (level) {
case 0:
return "level-0";
case 1:
return "level-1";
case 2:
return "level-2";
case 3:
return "level-3";
case 4:
return "level-4";
case 5:
return "level-5";
case 6:
return "level-6";
case 7:
return "level-7";
default:
return NULL;
}
}
static void tpmi_update_platform_param(enum isst_platform_param param, int value)
{
/* No params need to be updated for now */
}
static int tpmi_is_punit_valid(struct isst_id *id)
{
struct isst_tpmi_instance_count info;
int ret;
if (id->punit < 0)
return 0;
info.socket_id = id->pkg;
ret = tpmi_process_ioctl(ISST_IF_COUNT_TPMI_INSTANCES, &info);
if (ret == -1)
return 0;
if (info.valid_mask & BIT(id->punit))
return 1;
return 0;
}
static int tpmi_read_pm_config(struct isst_id *id, int *cp_state, int *cp_cap)
{
struct isst_core_power info;
int ret;
info.get_set = 0;
info.socket_id = id->pkg;
info.power_domain_id = id->punit;
ret = tpmi_process_ioctl(ISST_IF_CORE_POWER_STATE, &info);
if (ret == -1)
return ret;
*cp_state = info.enable;
*cp_cap = info.supported;
return 0;
}
int tpmi_get_config_levels(struct isst_id *id, struct isst_pkg_ctdp *pkg_dev)
{
struct isst_perf_level_info info;
int ret;
info.socket_id = id->pkg;
info.power_domain_id = id->punit;
ret = tpmi_process_ioctl(ISST_IF_PERF_LEVELS, &info);
if (ret == -1)
return ret;
pkg_dev->version = info.feature_rev;
pkg_dev->levels = info.max_level;
pkg_dev->locked = info.locked;
pkg_dev->current_level = info.current_level;
pkg_dev->locked = info.locked;
pkg_dev->enabled = info.enabled;
return 0;
}
static int tpmi_get_ctdp_control(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
{
struct isst_core_power core_power_info;
struct isst_perf_level_info info;
int level_mask;
int ret;
info.socket_id = id->pkg;
info.power_domain_id = id->punit;
ret = tpmi_process_ioctl(ISST_IF_PERF_LEVELS, &info);
if (ret == -1)
return -1;
if (config_index != 0xff)
level_mask = 1 << config_index;
else
level_mask = config_index;
if (!(info.level_mask & level_mask))
return -1;
ctdp_level->fact_support = info.sst_tf_support;
ctdp_level->pbf_support = info.sst_bf_support;
ctdp_level->fact_enabled = !!(info.feature_state & BIT(1));
ctdp_level->pbf_enabled = !!(info.feature_state & BIT(0));
core_power_info.get_set = 0;
core_power_info.socket_id = id->pkg;
core_power_info.power_domain_id = id->punit;
ret = tpmi_process_ioctl(ISST_IF_CORE_POWER_STATE, &core_power_info);
if (ret == -1)
return ret;
ctdp_level->sst_cp_support = core_power_info.supported;
ctdp_level->sst_cp_enabled = core_power_info.enable;
debug_printf
("cpu:%d CONFIG_TDP_GET_TDP_CONTROL fact_support:%d pbf_support: %d fact_enabled:%d pbf_enabled:%d\n",
id->cpu, ctdp_level->fact_support, ctdp_level->pbf_support,
ctdp_level->fact_enabled, ctdp_level->pbf_enabled);
return 0;
}
static int tpmi_get_tdp_info(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
{
struct isst_perf_level_data_info info;
int ret;
info.socket_id = id->pkg;
info.power_domain_id = id->punit;
info.level = config_index;
ret = tpmi_process_ioctl(ISST_IF_GET_PERF_LEVEL_INFO, &info);
if (ret == -1)
return ret;
ctdp_level->pkg_tdp = info.thermal_design_power_w;
ctdp_level->tdp_ratio = info.tdp_ratio;
ctdp_level->sse_p1 = info.base_freq_mhz;
ctdp_level->avx2_p1 = info.base_freq_avx2_mhz;
ctdp_level->avx512_p1 = info.base_freq_avx512_mhz;
ctdp_level->amx_p1 = info.base_freq_amx_mhz;
ctdp_level->t_proc_hot = info.tjunction_max_c;
ctdp_level->mem_freq = info.max_memory_freq_mhz;
ctdp_level->cooling_type = info.cooling_type;
ctdp_level->uncore_p0 = info.p0_fabric_freq_mhz;
ctdp_level->uncore_p1 = info.p1_fabric_freq_mhz;
ctdp_level->uncore_pm = info.pm_fabric_freq_mhz;
debug_printf
("cpu:%d ctdp:%d CONFIG_TDP_GET_TDP_INFO tdp_ratio:%d pkg_tdp:%d ctdp_level->t_proc_hot:%d\n",
id->cpu, config_index, ctdp_level->tdp_ratio, ctdp_level->pkg_tdp,
ctdp_level->t_proc_hot);
return 0;
}
static int tpmi_get_pwr_info(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
{
/* TBD */
ctdp_level->pkg_max_power = 0;
ctdp_level->pkg_min_power = 0;
debug_printf
("cpu:%d ctdp:%d CONFIG_TDP_GET_PWR_INFO pkg_max_power:%d pkg_min_power:%d\n",
id->cpu, config_index, ctdp_level->pkg_max_power,
ctdp_level->pkg_min_power);
return 0;
}
int tpmi_get_coremask_info(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
{
struct isst_perf_level_cpu_mask info;
int ret, cpu_count;
info.socket_id = id->pkg;
info.power_domain_id = id->punit;
info.level = config_index;
info.punit_cpu_map = 1;
ret = tpmi_process_ioctl(ISST_IF_GET_PERF_LEVEL_CPU_MASK, &info);
if (ret == -1)
return ret;
set_cpu_mask_from_punit_coremask(id, info.mask,
ctdp_level->core_cpumask_size,
ctdp_level->core_cpumask, &cpu_count);
ctdp_level->cpu_count = cpu_count;
debug_printf("cpu:%d ctdp:%d core_mask ino cpu count:%d\n",
id->cpu, config_index, ctdp_level->cpu_count);
return 0;
}
static int tpmi_get_get_trls(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
{
struct isst_perf_level_data_info info;
int ret, i, j;
info.socket_id = id->pkg;
info.power_domain_id = id->punit;
info.level = config_index;
ret = tpmi_process_ioctl(ISST_IF_GET_PERF_LEVEL_INFO, &info);
if (ret == -1)
return ret;
if (info.max_buckets > TRL_MAX_BUCKETS)
info.max_buckets = TRL_MAX_BUCKETS;
if (info.max_trl_levels > TRL_MAX_LEVELS)
info.max_trl_levels = TRL_MAX_LEVELS;
for (i = 0; i < info.max_trl_levels; ++i)
for (j = 0; j < info.max_buckets; ++j)
ctdp_level->trl_ratios[i][j] = info.trl_freq_mhz[i][j];
return 0;
}
static int tpmi_get_get_trl(struct isst_id *id, int level, int config_index,
int *trl)
{
struct isst_pkg_ctdp_level_info ctdp_level;
int ret, i;
ret = tpmi_get_get_trls(id, config_index, &ctdp_level);
if (ret)
return ret;
/* FIX ME: Just return for level 0 */
for (i = 0; i < 8; ++i)
trl[i] = ctdp_level.trl_ratios[0][i];
return 0;
}
static int tpmi_get_trl_bucket_info(struct isst_id *id, int config_index,
unsigned long long *buckets_info)
{
struct isst_perf_level_data_info info;
unsigned char *mask = (unsigned char *)buckets_info;
int ret, i;
info.socket_id = id->pkg;
info.power_domain_id = id->punit;
info.level = config_index;
ret = tpmi_process_ioctl(ISST_IF_GET_PERF_LEVEL_INFO, &info);
if (ret == -1)
return ret;
if (info.max_buckets > TRL_MAX_BUCKETS)
info.max_buckets = TRL_MAX_BUCKETS;
for (i = 0; i < info.max_buckets; ++i)
mask[i] = info.bucket_core_counts[i];
debug_printf("cpu:%d TRL bucket info: 0x%llx\n", id->cpu,
*buckets_info);
return 0;
}
static int tpmi_set_tdp_level(struct isst_id *id, int tdp_level)
{
struct isst_perf_level_control info;
int ret;
info.socket_id = id->pkg;
info.power_domain_id = id->punit;
info.level = tdp_level;
ret = tpmi_process_ioctl(ISST_IF_PERF_SET_LEVEL, &info);
if (ret == -1)
return ret;
return 0;
}
static int _pbf_get_coremask_info(struct isst_id *id, int config_index,
struct isst_pbf_info *pbf_info)
{
struct isst_perf_level_cpu_mask info;
int ret, cpu_count;
info.socket_id = id->pkg;
info.power_domain_id = id->punit;
info.level = config_index;
info.punit_cpu_map = 1;
ret = tpmi_process_ioctl(ISST_IF_GET_BASE_FREQ_CPU_MASK, &info);
if (ret == -1)
return ret;
set_cpu_mask_from_punit_coremask(id, info.mask,
pbf_info->core_cpumask_size,
pbf_info->core_cpumask, &cpu_count);
debug_printf("cpu:%d ctdp:%d pbf core_mask info cpu count:%d\n",
id->cpu, config_index, cpu_count);
return 0;
}
static int tpmi_get_pbf_info(struct isst_id *id, int level,
struct isst_pbf_info *pbf_info)
{
struct isst_base_freq_info info;
int ret;
info.socket_id = id->pkg;
info.power_domain_id = id->punit;
info.level = level;
ret = tpmi_process_ioctl(ISST_IF_GET_BASE_FREQ_INFO, &info);
if (ret == -1)
return ret;
pbf_info->p1_low = info.low_base_freq_mhz;
pbf_info->p1_high = info.high_base_freq_mhz;
pbf_info->tdp = info.thermal_design_power_w;
pbf_info->t_prochot = info.tjunction_max_c;
debug_printf("cpu:%d ctdp:%d pbf info:%d:%d:%d:%d\n",
id->cpu, level, pbf_info->p1_low, pbf_info->p1_high,
pbf_info->tdp, pbf_info->t_prochot);
return _pbf_get_coremask_info(id, level, pbf_info);
}
static int tpmi_set_pbf_fact_status(struct isst_id *id, int pbf, int enable)
{
struct isst_pkg_ctdp pkg_dev;
struct isst_pkg_ctdp_level_info ctdp_level;
int current_level;
struct isst_perf_feature_control info;
int ret;
ret = isst_get_ctdp_levels(id, &pkg_dev);
if (ret)
debug_printf("cpu:%d No support for dynamic ISST\n", id->cpu);
current_level = pkg_dev.current_level;
ret = isst_get_ctdp_control(id, current_level, &ctdp_level);
if (ret)
return ret;
info.socket_id = id->pkg;
info.power_domain_id = id->punit;
info.feature = 0;
if (pbf) {
if (ctdp_level.fact_enabled)
info.feature |= BIT(1);
if (enable)
info.feature |= BIT(0);
else
info.feature &= ~BIT(0);
} else {
if (enable && !ctdp_level.sst_cp_enabled)
isst_display_error_info_message(0,
"Make sure to execute before: core-power enable",
0, 0);
if (ctdp_level.pbf_enabled)
info.feature |= BIT(0);
if (enable)
info.feature |= BIT(1);
else
info.feature &= ~BIT(1);
}
ret = tpmi_process_ioctl(ISST_IF_PERF_SET_FEATURE, &info);
if (ret == -1)
return ret;
return 0;
}
static int tpmi_get_fact_info(struct isst_id *id, int level, int fact_bucket,
struct isst_fact_info *fact_info)
{
struct isst_turbo_freq_info info;
int i, j;
int ret;
info.socket_id = id->pkg;
info.power_domain_id = id->punit;
info.level = level;
ret = tpmi_process_ioctl(ISST_IF_GET_TURBO_FREQ_INFO, &info);
if (ret == -1)
return ret;
for (i = 0; i < info.max_clip_freqs; ++i)
fact_info->lp_ratios[i] = info.lp_clip_freq_mhz[i];
if (info.max_buckets > TRL_MAX_BUCKETS)
info.max_buckets = TRL_MAX_BUCKETS;
if (info.max_trl_levels > TRL_MAX_LEVELS)
info.max_trl_levels = TRL_MAX_LEVELS;
for (i = 0; i < info.max_trl_levels; ++i) {
for (j = 0; j < info.max_buckets; ++j)
fact_info->bucket_info[j].hp_ratios[i] =
info.trl_freq_mhz[i][j];
}
for (i = 0; i < info.max_buckets; ++i)
fact_info->bucket_info[i].hp_cores = info.bucket_core_counts[i];
return 0;
}
static void _set_uncore_min_max(struct isst_id *id, int max, int freq)
{
DIR *dir;
FILE *filep;
struct dirent *entry;
char buffer[512];
unsigned int tmp_id;
int ret;
dir = opendir("/sys/devices/system/cpu/intel_uncore_frequency/");
if (!dir)
return;
while ((entry = readdir(dir)) != NULL ) {
/* Check domain_id */
snprintf(buffer, sizeof(buffer),
"/sys/devices/system/cpu/intel_uncore_frequency/%s/domain_id", entry->d_name);
filep = fopen(buffer, "r");
if (!filep)
goto end;
ret = fscanf(filep, "%u", &tmp_id);
fclose(filep);
if (ret != 1)
goto end;
if (tmp_id != id->punit)
continue;
/* Check package_id */
snprintf(buffer, sizeof(buffer),
"/sys/devices/system/cpu/intel_uncore_frequency/%s/package_id", entry->d_name);
filep = fopen(buffer, "r");
if (!filep)
goto end;
ret = fscanf(filep, "%u", &tmp_id);
fclose(filep);
if (ret != 1)
goto end;
if (tmp_id != id->pkg)
continue;
/* Found the right sysfs path, adjust and quit */
if (max)
snprintf(buffer, sizeof(buffer),
"/sys/devices/system/cpu/intel_uncore_frequency/%s/max_freq_khz", entry->d_name);
else
snprintf(buffer, sizeof(buffer),
"/sys/devices/system/cpu/intel_uncore_frequency/%s/min_freq_khz", entry->d_name);
filep = fopen(buffer, "w");
if (!filep)
goto end;
fprintf(filep, "%d\n", freq);
fclose(filep);
break;
}
end:
closedir(dir);
}
static void tpmi_adjust_uncore_freq(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
{
struct isst_perf_level_data_info info;
int ret;
info.socket_id = id->pkg;
info.power_domain_id = id->punit;
info.level = config_index;
ret = tpmi_process_ioctl(ISST_IF_GET_PERF_LEVEL_INFO, &info);
if (ret == -1)
return;
ctdp_level->uncore_p0 = info.p0_fabric_freq_mhz;
ctdp_level->uncore_p1 = info.p1_fabric_freq_mhz;
ctdp_level->uncore_pm = info.pm_fabric_freq_mhz;
if (ctdp_level->uncore_pm)
_set_uncore_min_max(id, 0, ctdp_level->uncore_pm * 100000);
if (ctdp_level->uncore_p0)
_set_uncore_min_max(id, 1, ctdp_level->uncore_p0 * 100000);
return;
}
static int tpmi_get_clos_information(struct isst_id *id, int *enable, int *type)
{
struct isst_core_power info;
int ret;
info.get_set = 0;
info.socket_id = id->pkg;
info.power_domain_id = id->punit;
ret = tpmi_process_ioctl(ISST_IF_CORE_POWER_STATE, &info);
if (ret == -1)
return ret;
*enable = info.enable;
*type = info.priority_type;
return 0;
}
static int tpmi_pm_qos_config(struct isst_id *id, int enable_clos,
int priority_type)
{
struct isst_core_power info;
int ret;
info.get_set = 1;
info.socket_id = id->pkg;
info.power_domain_id = id->punit;
info.enable = enable_clos;
info.priority_type = priority_type;
ret = tpmi_process_ioctl(ISST_IF_CORE_POWER_STATE, &info);
if (ret == -1)
return ret;
return 0;
}
int tpmi_pm_get_clos(struct isst_id *id, int clos,
struct isst_clos_config *clos_config)
{
struct isst_clos_param info;
int ret;
info.get_set = 0;
info.socket_id = id->pkg;
info.power_domain_id = id->punit;
info.clos = clos;
ret = tpmi_process_ioctl(ISST_IF_CLOS_PARAM, &info);
if (ret == -1)
return ret;
clos_config->epp = 0;
clos_config->clos_prop_prio = info.prop_prio;
clos_config->clos_min = info.min_freq_mhz;
clos_config->clos_max = info.max_freq_mhz;
clos_config->clos_desired = 0;
debug_printf("cpu:%d clos:%d min:%d max:%d\n", id->cpu, clos,
clos_config->clos_min, clos_config->clos_max);
return 0;
}
int tpmi_set_clos(struct isst_id *id, int clos,
struct isst_clos_config *clos_config)
{
struct isst_clos_param info;
int ret;
info.get_set = 1;
info.socket_id = id->pkg;
info.power_domain_id = id->punit;
info.clos = clos;
info.prop_prio = clos_config->clos_prop_prio;
info.min_freq_mhz = clos_config->clos_min;
info.max_freq_mhz = clos_config->clos_max;
if (info.min_freq_mhz <= 0xff)
info.min_freq_mhz *= 100;
if (info.max_freq_mhz <= 0xff)
info.max_freq_mhz *= 100;
ret = tpmi_process_ioctl(ISST_IF_CLOS_PARAM, &info);
if (ret == -1)
return ret;
debug_printf("set cpu:%d clos:%d min:%d max:%d\n", id->cpu, clos,
clos_config->clos_min, clos_config->clos_max);
return 0;
}
static int tpmi_clos_get_assoc_status(struct isst_id *id, int *clos_id)
{
struct isst_if_clos_assoc_cmds assoc_cmds;
int ret;
assoc_cmds.cmd_count = 1;
assoc_cmds.get_set = 0;
assoc_cmds.punit_cpu_map = 1;
assoc_cmds.assoc_info[0].logical_cpu = find_phy_core_num(id->cpu);
assoc_cmds.assoc_info[0].socket_id = id->pkg;
assoc_cmds.assoc_info[0].power_domain_id = id->punit;
ret = tpmi_process_ioctl(ISST_IF_CLOS_ASSOC, &assoc_cmds);
if (ret == -1)
return ret;
*clos_id = assoc_cmds.assoc_info[0].clos;
return 0;
}
static int tpmi_clos_associate(struct isst_id *id, int clos_id)
{
struct isst_if_clos_assoc_cmds assoc_cmds;
int ret;
assoc_cmds.cmd_count = 1;
assoc_cmds.get_set = 1;
assoc_cmds.punit_cpu_map = 1;
assoc_cmds.assoc_info[0].logical_cpu = find_phy_core_num(id->cpu);
assoc_cmds.assoc_info[0].clos = clos_id;
assoc_cmds.assoc_info[0].socket_id = id->pkg;
assoc_cmds.assoc_info[0].power_domain_id = id->punit;
ret = tpmi_process_ioctl(ISST_IF_CLOS_ASSOC, &assoc_cmds);
if (ret == -1)
return ret;
return 0;
}
static struct isst_platform_ops tpmi_ops = {
.get_disp_freq_multiplier = tpmi_get_disp_freq_multiplier,
.get_trl_max_levels = tpmi_get_trl_max_levels,
.get_trl_level_name = tpmi_get_trl_level_name,
.update_platform_param = tpmi_update_platform_param,
.is_punit_valid = tpmi_is_punit_valid,
.read_pm_config = tpmi_read_pm_config,
.get_config_levels = tpmi_get_config_levels,
.get_ctdp_control = tpmi_get_ctdp_control,
.get_tdp_info = tpmi_get_tdp_info,
.get_pwr_info = tpmi_get_pwr_info,
.get_coremask_info = tpmi_get_coremask_info,
.get_get_trl = tpmi_get_get_trl,
.get_get_trls = tpmi_get_get_trls,
.get_trl_bucket_info = tpmi_get_trl_bucket_info,
.set_tdp_level = tpmi_set_tdp_level,
.get_pbf_info = tpmi_get_pbf_info,
.set_pbf_fact_status = tpmi_set_pbf_fact_status,
.get_fact_info = tpmi_get_fact_info,
.adjust_uncore_freq = tpmi_adjust_uncore_freq,
.get_clos_information = tpmi_get_clos_information,
.pm_qos_config = tpmi_pm_qos_config,
.pm_get_clos = tpmi_pm_get_clos,
.set_clos = tpmi_set_clos,
.clos_get_assoc_status = tpmi_clos_get_assoc_status,
.clos_associate = tpmi_clos_associate,
};
struct isst_platform_ops *tpmi_get_platform_ops(void)
{
return &tpmi_ops;
}
......@@ -6,304 +6,141 @@
#include "isst.h"
int isst_write_pm_config(struct isst_id *id, int cp_state)
{
unsigned int req, resp;
int ret;
if (cp_state)
req = BIT(16);
else
req = 0;
ret = isst_send_mbox_command(id->cpu, WRITE_PM_CONFIG, PM_FEATURE, 0, req,
&resp);
if (ret)
return ret;
debug_printf("cpu:%d WRITE_PM_CONFIG resp:%x\n", id->cpu, resp);
static struct isst_platform_ops *isst_ops;
#define CHECK_CB(_name) \
do { \
if (!isst_ops || !isst_ops->_name) { \
fprintf(stderr, "Invalid ops\n"); \
exit(0); \
} \
} while (0)
int isst_set_platform_ops(int api_version)
{
switch (api_version) {
case 1:
isst_ops = mbox_get_platform_ops();
break;
case 2:
isst_ops = tpmi_get_platform_ops();
break;
default:
isst_ops = NULL;
break;
}
if (!isst_ops)
return -1;
return 0;
}
int isst_read_pm_config(struct isst_id *id, int *cp_state, int *cp_cap)
void isst_update_platform_param(enum isst_platform_param param, int value)
{
unsigned int resp;
int ret;
ret = isst_send_mbox_command(id->cpu, READ_PM_CONFIG, PM_FEATURE, 0, 0,
&resp);
if (ret)
return ret;
debug_printf("cpu:%d READ_PM_CONFIG resp:%x\n", id->cpu, resp);
CHECK_CB(update_platform_param);
*cp_state = resp & BIT(16);
*cp_cap = resp & BIT(0) ? 1 : 0;
return 0;
isst_ops->update_platform_param(param, value);
}
int isst_get_ctdp_levels(struct isst_id *id, struct isst_pkg_ctdp *pkg_dev)
int isst_get_disp_freq_multiplier(void)
{
unsigned int resp;
int ret;
ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_GET_LEVELS_INFO, 0, 0, &resp);
if (ret) {
pkg_dev->levels = 0;
pkg_dev->locked = 1;
pkg_dev->current_level = 0;
pkg_dev->version = 0;
pkg_dev->enabled = 0;
return 0;
}
CHECK_CB(get_disp_freq_multiplier);
return isst_ops->get_disp_freq_multiplier();
}
debug_printf("cpu:%d CONFIG_TDP_GET_LEVELS_INFO resp:%x\n", id->cpu, resp);
int isst_get_trl_max_levels(void)
{
CHECK_CB(get_trl_max_levels);
return isst_ops->get_trl_max_levels();
}
pkg_dev->version = resp & 0xff;
pkg_dev->levels = (resp >> 8) & 0xff;
pkg_dev->current_level = (resp >> 16) & 0xff;
pkg_dev->locked = !!(resp & BIT(24));
pkg_dev->enabled = !!(resp & BIT(31));
char *isst_get_trl_level_name(int level)
{
CHECK_CB(get_trl_level_name);
return isst_ops->get_trl_level_name(level);
}
return 0;
int isst_is_punit_valid(struct isst_id *id)
{
CHECK_CB(is_punit_valid);
return isst_ops->is_punit_valid(id);
}
int isst_get_ctdp_control(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
int isst_send_msr_command(unsigned int cpu, unsigned int msr, int write,
unsigned long long *req_resp)
{
int cp_state, cp_cap;
unsigned int resp;
int ret;
struct isst_if_msr_cmds msr_cmds;
const char *pathname = "/dev/isst_interface";
FILE *outf = get_output_file();
int fd;
ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_GET_TDP_CONTROL, 0,
config_index, &resp);
if (ret)
return ret;
fd = open(pathname, O_RDWR);
if (fd < 0)
err(-1, "%s open failed", pathname);
ctdp_level->fact_support = resp & BIT(0);
ctdp_level->pbf_support = !!(resp & BIT(1));
ctdp_level->fact_enabled = !!(resp & BIT(16));
ctdp_level->pbf_enabled = !!(resp & BIT(17));
msr_cmds.cmd_count = 1;
msr_cmds.msr_cmd[0].logical_cpu = cpu;
msr_cmds.msr_cmd[0].msr = msr;
msr_cmds.msr_cmd[0].read_write = write;
if (write)
msr_cmds.msr_cmd[0].data = *req_resp;
ret = isst_read_pm_config(id, &cp_state, &cp_cap);
if (ret) {
debug_printf("cpu:%d pm_config is not supported\n", id->cpu);
if (ioctl(fd, ISST_IF_MSR_COMMAND, &msr_cmds) == -1) {
perror("ISST_IF_MSR_COMMAND");
fprintf(outf, "Error: msr_cmd cpu:%d msr:%x read_write:%d\n",
cpu, msr, write);
} else {
debug_printf("cpu:%d pm_config SST-CP state:%d cap:%d\n", id->cpu, cp_state, cp_cap);
ctdp_level->sst_cp_support = cp_cap;
ctdp_level->sst_cp_enabled = cp_state;
}
debug_printf(
"cpu:%d CONFIG_TDP_GET_TDP_CONTROL resp:%x fact_support:%d pbf_support: %d fact_enabled:%d pbf_enabled:%d\n",
id->cpu, resp, ctdp_level->fact_support, ctdp_level->pbf_support,
ctdp_level->fact_enabled, ctdp_level->pbf_enabled);
return 0;
}
int isst_get_tdp_info(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
{
unsigned int resp;
int ret;
if (!write)
*req_resp = msr_cmds.msr_cmd[0].data;
ret = isst_send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_GET_TDP_INFO,
0, config_index, &resp);
if (ret) {
isst_display_error_info_message(1, "Invalid level, Can't get TDP information at level", 1, config_index);
return ret;
debug_printf(
"msr_cmd response: cpu:%d msr:%x rd_write:%x resp:%llx %llx\n",
cpu, msr, write, *req_resp, msr_cmds.msr_cmd[0].data);
}
ctdp_level->pkg_tdp = resp & GENMASK(14, 0);
ctdp_level->tdp_ratio = (resp & GENMASK(23, 16)) >> 16;
close(fd);
debug_printf(
"cpu:%d ctdp:%d CONFIG_TDP_GET_TDP_INFO resp:%x tdp_ratio:%d pkg_tdp:%d\n",
id->cpu, config_index, resp, ctdp_level->tdp_ratio,
ctdp_level->pkg_tdp);
return 0;
}
int isst_get_pwr_info(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
int isst_read_pm_config(struct isst_id *id, int *cp_state, int *cp_cap)
{
unsigned int resp;
int ret;
ret = isst_send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_GET_PWR_INFO,
0, config_index, &resp);
if (ret)
return ret;
ctdp_level->pkg_max_power = resp & GENMASK(14, 0);
ctdp_level->pkg_min_power = (resp & GENMASK(30, 16)) >> 16;
debug_printf(
"cpu:%d ctdp:%d CONFIG_TDP_GET_PWR_INFO resp:%x pkg_max_power:%d pkg_min_power:%d\n",
id->cpu, config_index, resp, ctdp_level->pkg_max_power,
ctdp_level->pkg_min_power);
return 0;
CHECK_CB(read_pm_config);
return isst_ops->read_pm_config(id, cp_state, cp_cap);
}
void isst_get_uncore_p0_p1_info(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
int isst_get_ctdp_levels(struct isst_id *id, struct isst_pkg_ctdp *pkg_dev)
{
unsigned int resp;
int ret;
ctdp_level->uncore_pm = 0;
ctdp_level->uncore_p0 = 0;
ctdp_level->uncore_p1 = 0;
ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_GET_RATIO_INFO, 0,
(BIT(16) | config_index), &resp);
if (ret)
goto try_uncore_mbox;
ctdp_level->uncore_p0 = resp & GENMASK(7, 0);
ctdp_level->uncore_p1 = (resp & GENMASK(15, 8)) >> 8;
ctdp_level->uncore_pm = (resp & GENMASK(31, 24)) >> 24;
debug_printf(
"cpu:%d ctdp:%d CONFIG_TDP_GET_RATIO_INFO resp:%x uncore p0:%d uncore p1:%d uncore pm:%d\n",
id->cpu, config_index, resp, ctdp_level->uncore_p0, ctdp_level->uncore_p1,
ctdp_level->uncore_pm);
return;
try_uncore_mbox:
ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_GET_UNCORE_P0_P1_INFO, 0,
config_index, &resp);
if (ret) {
ctdp_level->uncore_p0 = 0;
ctdp_level->uncore_p1 = 0;
return;
}
ctdp_level->uncore_p0 = resp & GENMASK(7, 0);
ctdp_level->uncore_p1 = (resp & GENMASK(15, 8)) >> 8;
debug_printf(
"cpu:%d ctdp:%d CONFIG_TDP_GET_UNCORE_P0_P1_INFO resp:%x uncore p0:%d uncore p1:%d\n",
id->cpu, config_index, resp, ctdp_level->uncore_p0,
ctdp_level->uncore_p1);
CHECK_CB(get_config_levels);
return isst_ops->get_config_levels(id, pkg_dev);
}
void isst_get_p1_info(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
int isst_get_ctdp_control(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
{
unsigned int resp;
int ret;
ret = isst_send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_GET_P1_INFO, 0,
config_index, &resp);
if (ret) {
ctdp_level->sse_p1 = 0;
ctdp_level->avx2_p1 = 0;
ctdp_level->avx512_p1 = 0;
return;
}
ctdp_level->sse_p1 = resp & GENMASK(7, 0);
ctdp_level->avx2_p1 = (resp & GENMASK(15, 8)) >> 8;
ctdp_level->avx512_p1 = (resp & GENMASK(23, 16)) >> 16;
debug_printf(
"cpu:%d ctdp:%d CONFIG_TDP_GET_P1_INFO resp:%x sse_p1:%d avx2_p1:%d avx512_p1:%d\n",
id->cpu, config_index, resp, ctdp_level->sse_p1,
ctdp_level->avx2_p1, ctdp_level->avx512_p1);
CHECK_CB(get_ctdp_control);
return isst_ops->get_ctdp_control(id, config_index, ctdp_level);
}
void isst_get_uncore_mem_freq(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
int isst_get_tdp_info(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
{
unsigned int resp;
int ret;
ret = isst_send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_GET_MEM_FREQ,
0, config_index, &resp);
if (ret) {
ctdp_level->mem_freq = 0;
return;
}
ctdp_level->mem_freq = resp & GENMASK(7, 0);
if (is_spr_platform()) {
ctdp_level->mem_freq *= 200;
} else if (is_icx_platform()) {
if (ctdp_level->mem_freq < 7) {
ctdp_level->mem_freq = (12 - ctdp_level->mem_freq) * 133.33 * 2 * 10;
ctdp_level->mem_freq /= 10;
if (ctdp_level->mem_freq % 10 > 5)
ctdp_level->mem_freq++;
} else {
ctdp_level->mem_freq = 0;
}
} else {
ctdp_level->mem_freq = 0;
}
debug_printf(
"cpu:%d ctdp:%d CONFIG_TDP_GET_MEM_FREQ resp:%x uncore mem_freq:%d\n",
id->cpu, config_index, resp, ctdp_level->mem_freq);
CHECK_CB(get_tdp_info);
return isst_ops->get_tdp_info(id, config_index, ctdp_level);
}
int isst_get_tjmax_info(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
int isst_get_pwr_info(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
{
unsigned int resp;
int ret;
ret = isst_send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_GET_TJMAX_INFO,
0, config_index, &resp);
if (ret)
return ret;
ctdp_level->t_proc_hot = resp & GENMASK(7, 0);
debug_printf(
"cpu:%d ctdp:%d CONFIG_TDP_GET_TJMAX_INFO resp:%x t_proc_hot:%d\n",
id->cpu, config_index, resp, ctdp_level->t_proc_hot);
return 0;
CHECK_CB(get_pwr_info);
return isst_ops->get_pwr_info(id, config_index, ctdp_level);
}
int isst_get_coremask_info(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
{
unsigned int resp;
int i, ret;
ctdp_level->cpu_count = 0;
for (i = 0; i < 2; ++i) {
unsigned long long mask;
int cpu_count = 0;
ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_GET_CORE_MASK, 0,
(i << 8) | config_index, &resp);
if (ret)
return ret;
debug_printf(
"cpu:%d ctdp:%d mask:%d CONFIG_TDP_GET_CORE_MASK resp:%x\n",
id->cpu, config_index, i, resp);
mask = (unsigned long long)resp << (32 * i);
set_cpu_mask_from_punit_coremask(id, mask,
ctdp_level->core_cpumask_size,
ctdp_level->core_cpumask,
&cpu_count);
ctdp_level->cpu_count += cpu_count;
debug_printf("cpu:%d ctdp:%d mask:%d cpu count:%d\n", id->cpu,
config_index, i, ctdp_level->cpu_count);
}
return 0;
CHECK_CB(get_coremask_info);
return isst_ops->get_coremask_info(id, config_index, ctdp_level);
}
int isst_get_get_trl_from_msr(struct isst_id *id, int *trl)
......@@ -329,89 +166,33 @@ int isst_get_get_trl_from_msr(struct isst_id *id, int *trl)
int isst_get_get_trl(struct isst_id *id, int level, int avx_level, int *trl)
{
unsigned int req, resp;
int ret;
req = level | (avx_level << 16);
ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_GET_TURBO_LIMIT_RATIOS, 0, req,
&resp);
if (ret)
return ret;
debug_printf(
"cpu:%d CONFIG_TDP_GET_TURBO_LIMIT_RATIOS req:%x resp:%x\n",
id->cpu, req, resp);
trl[0] = resp & GENMASK(7, 0);
trl[1] = (resp & GENMASK(15, 8)) >> 8;
trl[2] = (resp & GENMASK(23, 16)) >> 16;
trl[3] = (resp & GENMASK(31, 24)) >> 24;
req = level | BIT(8) | (avx_level << 16);
ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_GET_TURBO_LIMIT_RATIOS, 0, req,
&resp);
if (ret)
return ret;
debug_printf("cpu:%d CONFIG_TDP_GET_TURBO_LIMIT req:%x resp:%x\n", id->cpu,
req, resp);
trl[4] = resp & GENMASK(7, 0);
trl[5] = (resp & GENMASK(15, 8)) >> 8;
trl[6] = (resp & GENMASK(23, 16)) >> 16;
trl[7] = (resp & GENMASK(31, 24)) >> 24;
return 0;
CHECK_CB(get_get_trl);
return isst_ops->get_get_trl(id, level, avx_level, trl);
}
int isst_get_trl_bucket_info(struct isst_id *id, unsigned long long *buckets_info)
int isst_get_get_trls(struct isst_id *id, int level, struct isst_pkg_ctdp_level_info *ctdp_level)
{
int ret;
debug_printf("cpu:%d bucket info via MSR\n", id->cpu);
*buckets_info = 0;
ret = isst_send_msr_command(id->cpu, 0x1ae, 0, buckets_info);
if (ret)
return ret;
debug_printf("cpu:%d bucket info via MSR successful 0x%llx\n", id->cpu,
*buckets_info);
CHECK_CB(get_get_trls);
return isst_ops->get_get_trls(id, level, ctdp_level);
}
return 0;
int isst_get_trl_bucket_info(struct isst_id *id, int level, unsigned long long *buckets_info)
{
CHECK_CB(get_trl_bucket_info);
return isst_ops->get_trl_bucket_info(id, level, buckets_info);
}
int isst_set_tdp_level(struct isst_id *id, int tdp_level)
{
unsigned int resp;
int ret;
if (isst_get_config_tdp_lock_status(id)) {
isst_display_error_info_message(1, "TDP is locked", 0, 0);
return -1;
}
ret = isst_send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_SET_LEVEL, 0,
tdp_level, &resp);
if (ret) {
isst_display_error_info_message(1, "Set TDP level failed for level", 1, tdp_level);
return ret;
}
return 0;
CHECK_CB(set_tdp_level);
return isst_ops->set_tdp_level(id, tdp_level);
}
int isst_get_pbf_info(struct isst_id *id, int level, struct isst_pbf_info *pbf_info)
{
struct isst_pkg_ctdp_level_info ctdp_level;
struct isst_pkg_ctdp pkg_dev;
int i, ret, max_punit_core, max_mask_index;
unsigned int req, resp;
int ret;
ret = isst_get_ctdp_levels(id, &pkg_dev);
if (ret) {
......@@ -435,194 +216,23 @@ int isst_get_pbf_info(struct isst_id *id, int level, struct isst_pbf_info *pbf_i
pbf_info->core_cpumask_size = alloc_cpu_set(&pbf_info->core_cpumask);
max_punit_core = get_max_punit_core_id(id);
max_mask_index = max_punit_core > 32 ? 2 : 1;
for (i = 0; i < max_mask_index; ++i) {
unsigned long long mask;
int count;
ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_PBF_GET_CORE_MASK_INFO,
0, (i << 8) | level, &resp);
if (ret)
break;
debug_printf(
"cpu:%d CONFIG_TDP_PBF_GET_CORE_MASK_INFO resp:%x\n",
id->cpu, resp);
mask = (unsigned long long)resp << (32 * i);
set_cpu_mask_from_punit_coremask(id, mask,
pbf_info->core_cpumask_size,
pbf_info->core_cpumask,
&count);
}
req = level;
ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_PBF_GET_P1HI_P1LO_INFO, 0, req,
&resp);
if (ret)
return ret;
debug_printf("cpu:%d CONFIG_TDP_PBF_GET_P1HI_P1LO_INFO resp:%x\n", id->cpu,
resp);
pbf_info->p1_low = resp & 0xff;
pbf_info->p1_high = (resp & GENMASK(15, 8)) >> 8;
req = level;
ret = isst_send_mbox_command(
id->cpu, CONFIG_TDP, CONFIG_TDP_PBF_GET_TDP_INFO, 0, req, &resp);
if (ret)
return ret;
debug_printf("cpu:%d CONFIG_TDP_PBF_GET_TDP_INFO resp:%x\n", id->cpu, resp);
pbf_info->tdp = resp & 0xffff;
req = level;
ret = isst_send_mbox_command(
id->cpu, CONFIG_TDP, CONFIG_TDP_PBF_GET_TJ_MAX_INFO, 0, req, &resp);
if (ret)
return ret;
debug_printf("cpu:%d CONFIG_TDP_PBF_GET_TJ_MAX_INFO resp:%x\n", id->cpu,
resp);
pbf_info->t_control = (resp >> 8) & 0xff;
pbf_info->t_prochot = resp & 0xff;
return 0;
}
void isst_get_pbf_info_complete(struct isst_pbf_info *pbf_info)
{
free_cpu_set(pbf_info->core_cpumask);
CHECK_CB(get_pbf_info);
return isst_ops->get_pbf_info(id, level, pbf_info);
}
int isst_set_pbf_fact_status(struct isst_id *id, int pbf, int enable)
{
struct isst_pkg_ctdp pkg_dev;
struct isst_pkg_ctdp_level_info ctdp_level;
int current_level;
unsigned int req = 0, resp;
int ret;
ret = isst_get_ctdp_levels(id, &pkg_dev);
if (ret)
debug_printf("cpu:%d No support for dynamic ISST\n", id->cpu);
current_level = pkg_dev.current_level;
ret = isst_get_ctdp_control(id, current_level, &ctdp_level);
if (ret)
return ret;
if (pbf) {
if (ctdp_level.fact_enabled)
req = BIT(16);
if (enable)
req |= BIT(17);
else
req &= ~BIT(17);
} else {
if (enable && !ctdp_level.sst_cp_enabled)
isst_display_error_info_message(0, "Make sure to execute before: core-power enable", 0, 0);
if (ctdp_level.pbf_enabled)
req = BIT(17);
if (enable)
req |= BIT(16);
else
req &= ~BIT(16);
}
ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_SET_TDP_CONTROL, 0, req, &resp);
if (ret)
return ret;
debug_printf("cpu:%d CONFIG_TDP_SET_TDP_CONTROL pbf/fact:%d req:%x\n",
id->cpu, pbf, req);
return 0;
CHECK_CB(set_pbf_fact_status);
return isst_ops->set_pbf_fact_status(id, pbf, enable);
}
int isst_get_fact_bucket_info(struct isst_id *id, int level,
struct isst_fact_bucket_info *bucket_info)
{
unsigned int resp;
int i, k, ret;
for (i = 0; i < 2; ++i) {
int j;
ret = isst_send_mbox_command(
id->cpu, CONFIG_TDP,
CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_NUMCORES, 0,
(i << 8) | level, &resp);
if (ret)
return ret;
debug_printf(
"cpu:%d CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_NUMCORES index:%d level:%d resp:%x\n",
id->cpu, i, level, resp);
for (j = 0; j < 4; ++j) {
bucket_info[j + (i * 4)].high_priority_cores_count =
(resp >> (j * 8)) & 0xff;
}
}
for (k = 0; k < 3; ++k) {
for (i = 0; i < 2; ++i) {
int j;
ret = isst_send_mbox_command(
id->cpu, CONFIG_TDP,
CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_RATIOS, 0,
(k << 16) | (i << 8) | level, &resp);
if (ret)
return ret;
debug_printf(
"cpu:%d CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_RATIOS index:%d level:%d avx:%d resp:%x\n",
id->cpu, i, level, k, resp);
for (j = 0; j < 4; ++j) {
switch (k) {
case 0:
bucket_info[j + (i * 4)].sse_trl =
(resp >> (j * 8)) & 0xff;
break;
case 1:
bucket_info[j + (i * 4)].avx_trl =
(resp >> (j * 8)) & 0xff;
break;
case 2:
bucket_info[j + (i * 4)].avx512_trl =
(resp >> (j * 8)) & 0xff;
break;
default:
break;
}
}
}
}
return 0;
}
int isst_get_fact_info(struct isst_id *id, int level, int fact_bucket, struct isst_fact_info *fact_info)
{
struct isst_pkg_ctdp_level_info ctdp_level;
struct isst_pkg_ctdp pkg_dev;
unsigned int resp;
int j, ret, print;
int ret;
ret = isst_get_ctdp_levels(id, &pkg_dev);
if (ret) {
......@@ -643,40 +253,8 @@ int isst_get_fact_info(struct isst_id *id, int level, int fact_bucket, struct is
isst_display_error_info_message(1, "turbo-freq feature is not present at this level", 1, level);
return -1;
}
ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
CONFIG_TDP_GET_FACT_LP_CLIPPING_RATIO, 0,
level, &resp);
if (ret)
return ret;
debug_printf("cpu:%d CONFIG_TDP_GET_FACT_LP_CLIPPING_RATIO resp:%x\n",
id->cpu, resp);
fact_info->lp_clipping_ratio_license_sse = resp & 0xff;
fact_info->lp_clipping_ratio_license_avx2 = (resp >> 8) & 0xff;
fact_info->lp_clipping_ratio_license_avx512 = (resp >> 16) & 0xff;
ret = isst_get_fact_bucket_info(id, level, fact_info->bucket_info);
if (ret)
return ret;
print = 0;
for (j = 0; j < ISST_FACT_MAX_BUCKETS; ++j) {
if (fact_bucket != 0xff && fact_bucket != j)
continue;
if (!fact_info->bucket_info[j].high_priority_cores_count)
break;
print = 1;
}
if (!print) {
isst_display_error_info_message(1, "Invalid bucket", 0, 0);
return -1;
}
return 0;
CHECK_CB(get_fact_info);
return isst_ops->get_fact_info(id, level, fact_bucket, fact_info);
}
int isst_get_trl(struct isst_id *id, unsigned long long *trl)
......@@ -709,6 +287,9 @@ int isst_set_trl_from_current_tdp(struct isst_id *id, unsigned long long trl)
unsigned long long msr_trl;
int ret;
if (id->cpu < 0)
return 0;
if (trl) {
msr_trl = trl;
} else {
......@@ -770,6 +351,13 @@ void isst_get_process_ctdp_complete(struct isst_id *id, struct isst_pkg_ctdp *pk
}
}
void isst_adjust_uncore_freq(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level)
{
CHECK_CB(adjust_uncore_freq);
return isst_ops->adjust_uncore_freq(id, config_index, ctdp_level);
}
int isst_get_process_ctdp(struct isst_id *id, int tdp_level, struct isst_pkg_ctdp *pkg_dev)
{
int i, ret, valid = 0;
......@@ -838,8 +426,8 @@ int isst_get_process_ctdp(struct isst_id *id, int tdp_level, struct isst_pkg_ctd
ctdp_level->tdp_ratio = ctdp_level->sse_p1;
}
isst_get_get_trl_from_msr(id, ctdp_level->trl_sse_active_cores);
isst_get_trl_bucket_info(id, &ctdp_level->buckets_info);
isst_get_get_trl_from_msr(id, ctdp_level->trl_ratios[0]);
isst_get_trl_bucket_info(id, i, &ctdp_level->trl_cores);
continue;
}
......@@ -851,38 +439,19 @@ int isst_get_process_ctdp(struct isst_id *id, int tdp_level, struct isst_pkg_ctd
if (ret)
return ret;
ret = isst_get_tjmax_info(id, i, ctdp_level);
if (ret)
return ret;
ctdp_level->core_cpumask_size =
alloc_cpu_set(&ctdp_level->core_cpumask);
ret = isst_get_coremask_info(id, i, ctdp_level);
if (ret)
return ret;
ret = isst_get_trl_bucket_info(id, &ctdp_level->buckets_info);
if (ret)
return ret;
ret = isst_get_get_trl(id, i, 0,
ctdp_level->trl_sse_active_cores);
ret = isst_get_trl_bucket_info(id, i, &ctdp_level->trl_cores);
if (ret)
return ret;
ret = isst_get_get_trl(id, i, 1,
ctdp_level->trl_avx_active_cores);
ret = isst_get_get_trls(id, i, ctdp_level);
if (ret)
return ret;
ret = isst_get_get_trl(id, i, 2,
ctdp_level->trl_avx_512_active_cores);
if (ret)
return ret;
isst_get_uncore_p0_p1_info(id, i, ctdp_level);
isst_get_p1_info(id, i, ctdp_level);
isst_get_uncore_mem_freq(id, i, ctdp_level);
}
if (!valid)
......@@ -893,178 +462,37 @@ int isst_get_process_ctdp(struct isst_id *id, int tdp_level, struct isst_pkg_ctd
int isst_clos_get_clos_information(struct isst_id *id, int *enable, int *type)
{
unsigned int resp;
int ret;
ret = isst_send_mbox_command(id->cpu, CONFIG_CLOS, CLOS_PM_QOS_CONFIG, 0, 0,
&resp);
if (ret)
return ret;
debug_printf("cpu:%d CLOS_PM_QOS_CONFIG resp:%x\n", id->cpu, resp);
if (resp & BIT(1))
*enable = 1;
else
*enable = 0;
if (resp & BIT(2))
*type = 1;
else
*type = 0;
return 0;
CHECK_CB(get_clos_information);
return isst_ops->get_clos_information(id, enable, type);
}
int isst_pm_qos_config(struct isst_id *id, int enable_clos, int priority_type)
{
unsigned int req, resp;
int ret;
if (!enable_clos) {
struct isst_pkg_ctdp pkg_dev;
struct isst_pkg_ctdp_level_info ctdp_level;
ret = isst_get_ctdp_levels(id, &pkg_dev);
if (ret) {
debug_printf("isst_get_ctdp_levels\n");
return ret;
}
ret = isst_get_ctdp_control(id, pkg_dev.current_level,
&ctdp_level);
if (ret)
return ret;
if (ctdp_level.fact_enabled) {
isst_display_error_info_message(1, "Ignoring request, turbo-freq feature is still enabled", 0, 0);
return -EINVAL;
}
ret = isst_write_pm_config(id, 0);
if (ret)
isst_display_error_info_message(0, "WRITE_PM_CONFIG command failed, ignoring error", 0, 0);
} else {
ret = isst_write_pm_config(id, 1);
if (ret)
isst_display_error_info_message(0, "WRITE_PM_CONFIG command failed, ignoring error", 0, 0);
}
ret = isst_send_mbox_command(id->cpu, CONFIG_CLOS, CLOS_PM_QOS_CONFIG, 0, 0,
&resp);
if (ret) {
isst_display_error_info_message(1, "CLOS_PM_QOS_CONFIG command failed", 0, 0);
return ret;
}
debug_printf("cpu:%d CLOS_PM_QOS_CONFIG resp:%x\n", id->cpu, resp);
req = resp;
if (enable_clos)
req = req | BIT(1);
else
req = req & ~BIT(1);
if (priority_type > 1)
isst_display_error_info_message(1, "Invalid priority type: Changing type to ordered", 0, 0);
if (priority_type)
req = req | BIT(2);
else
req = req & ~BIT(2);
ret = isst_send_mbox_command(id->cpu, CONFIG_CLOS, CLOS_PM_QOS_CONFIG,
BIT(MBOX_CMD_WRITE_BIT), req, &resp);
if (ret)
return ret;
debug_printf("cpu:%d CLOS_PM_QOS_CONFIG priority type:%d req:%x\n", id->cpu,
priority_type, req);
return 0;
CHECK_CB(pm_qos_config);
return isst_ops->pm_qos_config(id, enable_clos, priority_type);
}
int isst_pm_get_clos(struct isst_id *id, int clos, struct isst_clos_config *clos_config)
{
unsigned int resp;
int ret;
ret = isst_send_mbox_command(id->cpu, CONFIG_CLOS, CLOS_PM_CLOS, clos, 0,
&resp);
if (ret)
return ret;
clos_config->epp = resp & 0x0f;
clos_config->clos_prop_prio = (resp >> 4) & 0x0f;
clos_config->clos_min = (resp >> 8) & 0xff;
clos_config->clos_max = (resp >> 16) & 0xff;
clos_config->clos_desired = (resp >> 24) & 0xff;
return 0;
CHECK_CB(pm_get_clos);
return isst_ops->pm_get_clos(id, clos, clos_config);
}
int isst_set_clos(struct isst_id *id, int clos, struct isst_clos_config *clos_config)
{
unsigned int req, resp;
unsigned int param;
int ret;
req = clos_config->epp & 0x0f;
req |= (clos_config->clos_prop_prio & 0x0f) << 4;
req |= (clos_config->clos_min & 0xff) << 8;
req |= (clos_config->clos_max & 0xff) << 16;
req |= (clos_config->clos_desired & 0xff) << 24;
param = BIT(MBOX_CMD_WRITE_BIT) | clos;
ret = isst_send_mbox_command(id->cpu, CONFIG_CLOS, CLOS_PM_CLOS, param, req,
&resp);
if (ret)
return ret;
debug_printf("cpu:%d CLOS_PM_CLOS param:%x req:%x\n", id->cpu, param, req);
return 0;
CHECK_CB(set_clos);
return isst_ops->set_clos(id, clos, clos_config);
}
int isst_clos_get_assoc_status(struct isst_id *id, int *clos_id)
{
unsigned int resp;
unsigned int param;
int core_id, ret;
core_id = find_phy_core_num(id->cpu);
param = core_id;
ret = isst_send_mbox_command(id->cpu, CONFIG_CLOS, CLOS_PQR_ASSOC, param, 0,
&resp);
if (ret)
return ret;
debug_printf("cpu:%d CLOS_PQR_ASSOC param:%x resp:%x\n", id->cpu, param,
resp);
*clos_id = (resp >> 16) & 0x03;
return 0;
CHECK_CB(clos_get_assoc_status);
return isst_ops->clos_get_assoc_status(id, clos_id);
}
int isst_clos_associate(struct isst_id *id, int clos_id)
{
unsigned int req, resp;
unsigned int param;
int core_id, ret;
CHECK_CB(clos_associate);
return isst_ops->clos_associate(id, clos_id);
req = (clos_id & 0x03) << 16;
core_id = find_phy_core_num(id->cpu);
param = BIT(MBOX_CMD_WRITE_BIT) | core_id;
ret = isst_send_mbox_command(id->cpu, CONFIG_CLOS, CLOS_PQR_ASSOC, param,
req, &resp);
if (ret)
return ret;
debug_printf("cpu:%d CLOS_PQR_ASSOC param:%x req:%x\n", id->cpu, param,
req);
return 0;
}
......@@ -20,16 +20,17 @@
#include "isst.h"
static int per_package_levels_info[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE];
static time_t per_package_levels_tm[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE];
static int per_package_levels_info[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE][MAX_PUNIT_PER_DIE];
static time_t per_package_levels_tm[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE][MAX_PUNIT_PER_DIE];
static void init_levels(void)
{
int i, j;
int i, j, k;
for (i = 0; i < MAX_PACKAGE_COUNT; ++i)
for (j = 0; j < MAX_DIE_PER_PACKAGE; ++j)
per_package_levels_info[i][j] = -1;
for (k = 0; k < MAX_PUNIT_PER_DIE; ++k)
per_package_levels_info[i][j][k] = -1;
}
void process_level_change(struct isst_id *id)
......@@ -39,16 +40,16 @@ void process_level_change(struct isst_id *id)
time_t tm;
int ret;
if (id->pkg < 0 || id->die < 0) {
if (id->pkg < 0 || id->die < 0 || id->punit < 0) {
debug_printf("Invalid package/die info for cpu:%d\n", id->cpu);
return;
}
tm = time(NULL);
if (tm - per_package_levels_tm[id->pkg][id->die] < 2)
if (tm - per_package_levels_tm[id->pkg][id->die][id->punit] < 2)
return;
per_package_levels_tm[id->pkg][id->die] = tm;
per_package_levels_tm[id->pkg][id->die][id->punit] = tm;
ret = isst_get_ctdp_levels(id, &pkg_dev);
if (ret) {
......@@ -64,14 +65,14 @@ void process_level_change(struct isst_id *id)
return;
}
if (per_package_levels_info[id->pkg][id->die] == pkg_dev.current_level)
if (per_package_levels_info[id->pkg][id->die][id->punit] == pkg_dev.current_level)
return;
debug_printf("**Config level change for cpu:%d pkg:%d die:%d from %d to %d\n",
id->cpu, id->pkg, id->die, per_package_levels_info[id->pkg][id->die],
id->cpu, id->pkg, id->die, per_package_levels_info[id->pkg][id->die][id->punit],
pkg_dev.current_level);
per_package_levels_info[id->pkg][id->die] = pkg_dev.current_level;
per_package_levels_info[id->pkg][id->die][id->punit] = pkg_dev.current_level;
ctdp_level.core_cpumask_size =
alloc_cpu_set(&ctdp_level.core_cpumask);
......@@ -82,6 +83,19 @@ void process_level_change(struct isst_id *id)
return;
}
if (use_cgroupv2()) {
int ret;
ret = enable_cpuset_controller();
if (ret)
goto use_offline;
isolate_cpus(id, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask, pkg_dev.current_level);
goto free_mask;
}
use_offline:
if (ctdp_level.cpu_count) {
int i, max_cpus = get_topo_max_cpus();
for (i = 0; i < max_cpus; ++i) {
......@@ -96,7 +110,7 @@ void process_level_change(struct isst_id *id)
}
}
}
free_mask:
free_cpu_set(ctdp_level.core_cpumask);
}
......@@ -108,7 +122,7 @@ static void _poll_for_config_change(struct isst_id *id, void *arg1, void *arg2,
static void poll_for_config_change(void)
{
for_each_online_package_in_set(_poll_for_config_change, NULL, NULL,
for_each_online_power_domain_in_set(_poll_for_config_change, NULL, NULL,
NULL, NULL);
}
......
......@@ -169,21 +169,30 @@ static void format_and_print(FILE *outf, int level, char *header, char *value)
static int print_package_info(struct isst_id *id, FILE *outf)
{
char header[256];
int level = 1;
if (out_format_is_json()) {
snprintf(header, sizeof(header), "package-%d:die-%d:cpu-%d",
id->pkg, id->die, id->cpu);
format_and_print(outf, 1, header, NULL);
if (api_version() > 1)
snprintf(header, sizeof(header), "package-%d:die-%d:powerdomain-%d:cpu-%d",
id->pkg, id->die, id->punit, id->cpu);
else
snprintf(header, sizeof(header), "package-%d:die-%d:cpu-%d",
id->pkg, id->die, id->cpu);
format_and_print(outf, level, header, NULL);
return 1;
}
snprintf(header, sizeof(header), "package-%d", id->pkg);
format_and_print(outf, 1, header, NULL);
format_and_print(outf, level++, header, NULL);
snprintf(header, sizeof(header), "die-%d", id->die);
format_and_print(outf, 2, header, NULL);
format_and_print(outf, level++, header, NULL);
if (api_version() > 1) {
snprintf(header, sizeof(header), "powerdomain-%d", id->punit);
format_and_print(outf, level++, header, NULL);
}
snprintf(header, sizeof(header), "cpu-%d", id->cpu);
format_and_print(outf, 3, header, NULL);
format_and_print(outf, level, header, NULL);
return 3;
return level;
}
static void _isst_pbf_display_information(struct isst_id *id, FILE *outf, int level,
......@@ -198,7 +207,7 @@ static void _isst_pbf_display_information(struct isst_id *id, FILE *outf, int le
snprintf(header, sizeof(header), "high-priority-base-frequency(MHz)");
snprintf(value, sizeof(value), "%d",
pbf_info->p1_high * DISP_FREQ_MULTIPLIER);
pbf_info->p1_high * isst_get_disp_freq_multiplier());
format_and_print(outf, disp_level + 1, header, value);
snprintf(header, sizeof(header), "high-priority-cpu-mask");
......@@ -214,7 +223,7 @@ static void _isst_pbf_display_information(struct isst_id *id, FILE *outf, int le
snprintf(header, sizeof(header), "low-priority-base-frequency(MHz)");
snprintf(value, sizeof(value), "%d",
pbf_info->p1_low * DISP_FREQ_MULTIPLIER);
pbf_info->p1_low * isst_get_disp_freq_multiplier());
format_and_print(outf, disp_level + 1, header, value);
if (is_clx_n_platform())
......@@ -235,6 +244,7 @@ static void _isst_fact_display_information(struct isst_id *id, FILE *outf, int l
int base_level)
{
struct isst_fact_bucket_info *bucket_info = fact_info->bucket_info;
int trl_max_levels = isst_get_trl_max_levels();
char header[256];
char value[256];
int print = 0, j;
......@@ -243,7 +253,8 @@ static void _isst_fact_display_information(struct isst_id *id, FILE *outf, int l
if (fact_bucket != 0xff && fact_bucket != j)
continue;
if (!bucket_info[j].high_priority_cores_count)
/* core count must be valid for CPU power domain */
if (!bucket_info[j].hp_cores && id->cpu >= 0)
break;
print = 1;
......@@ -256,10 +267,12 @@ static void _isst_fact_display_information(struct isst_id *id, FILE *outf, int l
snprintf(header, sizeof(header), "speed-select-turbo-freq-properties");
format_and_print(outf, base_level, header, NULL);
for (j = 0; j < ISST_FACT_MAX_BUCKETS; ++j) {
int i;
if (fact_bucket != 0xff && fact_bucket != j)
continue;
if (!bucket_info[j].high_priority_cores_count)
if (!bucket_info[j].hp_cores)
break;
snprintf(header, sizeof(header), "bucket-%d", j);
......@@ -267,75 +280,49 @@ static void _isst_fact_display_information(struct isst_id *id, FILE *outf, int l
snprintf(header, sizeof(header), "high-priority-cores-count");
snprintf(value, sizeof(value), "%d",
bucket_info[j].high_priority_cores_count);
bucket_info[j].hp_cores);
format_and_print(outf, base_level + 2, header, value);
if (fact_avx & 0x01) {
snprintf(header, sizeof(header),
"high-priority-max-frequency(MHz)");
snprintf(value, sizeof(value), "%d",
bucket_info[j].sse_trl * DISP_FREQ_MULTIPLIER);
format_and_print(outf, base_level + 2, header, value);
}
if (fact_avx & 0x02) {
snprintf(header, sizeof(header),
"high-priority-max-avx2-frequency(MHz)");
snprintf(value, sizeof(value), "%d",
bucket_info[j].avx_trl * DISP_FREQ_MULTIPLIER);
format_and_print(outf, base_level + 2, header, value);
}
if (fact_avx & 0x04) {
snprintf(header, sizeof(header),
"high-priority-max-avx512-frequency(MHz)");
for (i = 0; i < trl_max_levels; i++) {
if (!bucket_info[j].hp_ratios[i] || (fact_avx != 0xFF && !(fact_avx & (1 << i))))
continue;
if (i == 0 && api_version() == 1 && !is_emr_platform())
snprintf(header, sizeof(header),
"high-priority-max-frequency(MHz)");
else
snprintf(header, sizeof(header),
"high-priority-max-%s-frequency(MHz)", isst_get_trl_level_name(i));
snprintf(value, sizeof(value), "%d",
bucket_info[j].avx512_trl *
DISP_FREQ_MULTIPLIER);
bucket_info[j].hp_ratios[i] * isst_get_disp_freq_multiplier());
format_and_print(outf, base_level + 2, header, value);
}
}
snprintf(header, sizeof(header),
"speed-select-turbo-freq-clip-frequencies");
format_and_print(outf, base_level + 1, header, NULL);
snprintf(header, sizeof(header), "low-priority-max-frequency(MHz)");
snprintf(value, sizeof(value), "%d",
fact_info->lp_clipping_ratio_license_sse *
DISP_FREQ_MULTIPLIER);
format_and_print(outf, base_level + 2, header, value);
snprintf(header, sizeof(header),
"low-priority-max-avx2-frequency(MHz)");
snprintf(value, sizeof(value), "%d",
fact_info->lp_clipping_ratio_license_avx2 *
DISP_FREQ_MULTIPLIER);
format_and_print(outf, base_level + 2, header, value);
snprintf(header, sizeof(header),
"low-priority-max-avx512-frequency(MHz)");
snprintf(value, sizeof(value), "%d",
fact_info->lp_clipping_ratio_license_avx512 *
DISP_FREQ_MULTIPLIER);
format_and_print(outf, base_level + 2, header, value);
for (j = 0; j < trl_max_levels; j++) {
if (!fact_info->lp_ratios[j])
continue;
/* No AVX level name for SSE to be consistent with previous formatting */
if (j == 0 && api_version() == 1 && !is_emr_platform())
snprintf(header, sizeof(header), "low-priority-max-frequency(MHz)");
else
snprintf(header, sizeof(header), "low-priority-max-%s-frequency(MHz)",
isst_get_trl_level_name(j));
snprintf(value, sizeof(value), "%d",
fact_info->lp_ratios[j] * isst_get_disp_freq_multiplier());
format_and_print(outf, base_level + 2, header, value);
}
}
void isst_ctdp_display_core_info(struct isst_id *id, FILE *outf, char *prefix,
unsigned int val, char *str0, char *str1)
{
char header[256];
char value[256];
int level = 1;
int level = print_package_info(id, outf);
if (out_format_is_json()) {
snprintf(header, sizeof(header), "package-%d:die-%d:cpu-%d",
id->pkg, id->die, id->cpu);
format_and_print(outf, level++, header, NULL);
} else {
snprintf(header, sizeof(header), "package-%d", id->pkg);
format_and_print(outf, level++, header, NULL);
snprintf(header, sizeof(header), "die-%d", id->die);
format_and_print(outf, level++, header, NULL);
snprintf(header, sizeof(header), "cpu-%d", id->cpu);
format_and_print(outf, level++, header, NULL);
}
level++;
if (str0 && !val)
snprintf(value, sizeof(value), "%s", str0);
......@@ -354,6 +341,7 @@ void isst_ctdp_display_information(struct isst_id *id, FILE *outf, int tdp_level
char header[256];
char value[512];
static int level;
int trl_max_levels = isst_get_trl_max_levels();
int i;
if (pkg_dev->processed)
......@@ -361,7 +349,7 @@ void isst_ctdp_display_information(struct isst_id *id, FILE *outf, int tdp_level
for (i = 0; i <= pkg_dev->levels; ++i) {
struct isst_pkg_ctdp_level_info *ctdp_level;
int j;
int j, k;
ctdp_level = &pkg_dev->ctdp_level[i];
if (!ctdp_level->processed)
......@@ -371,31 +359,33 @@ void isst_ctdp_display_information(struct isst_id *id, FILE *outf, int tdp_level
ctdp_level->level);
format_and_print(outf, level + 1, header, NULL);
snprintf(header, sizeof(header), "cpu-count");
j = get_cpu_count(id);
snprintf(value, sizeof(value), "%d", j);
format_and_print(outf, level + 2, header, value);
j = CPU_COUNT_S(ctdp_level->core_cpumask_size,
ctdp_level->core_cpumask);
if (j) {
snprintf(header, sizeof(header), "enable-cpu-count");
if (id->cpu >= 0) {
snprintf(header, sizeof(header), "cpu-count");
j = get_cpu_count(id);
snprintf(value, sizeof(value), "%d", j);
format_and_print(outf, level + 2, header, value);
}
if (ctdp_level->core_cpumask_size) {
snprintf(header, sizeof(header), "enable-cpu-mask");
printcpumask(sizeof(value), value,
ctdp_level->core_cpumask_size,
ctdp_level->core_cpumask);
format_and_print(outf, level + 2, header, value);
j = CPU_COUNT_S(ctdp_level->core_cpumask_size,
ctdp_level->core_cpumask);
if (j) {
snprintf(header, sizeof(header), "enable-cpu-count");
snprintf(value, sizeof(value), "%d", j);
format_and_print(outf, level + 2, header, value);
}
snprintf(header, sizeof(header), "enable-cpu-list");
printcpulist(sizeof(value), value,
ctdp_level->core_cpumask_size,
ctdp_level->core_cpumask);
format_and_print(outf, level + 2, header, value);
if (ctdp_level->core_cpumask_size) {
snprintf(header, sizeof(header), "enable-cpu-mask");
printcpumask(sizeof(value), value,
ctdp_level->core_cpumask_size,
ctdp_level->core_cpumask);
format_and_print(outf, level + 2, header, value);
snprintf(header, sizeof(header), "enable-cpu-list");
printcpulist(sizeof(value), value,
ctdp_level->core_cpumask_size,
ctdp_level->core_cpumask);
format_and_print(outf, level + 2, header, value);
}
}
snprintf(header, sizeof(header), "thermal-design-power-ratio");
......@@ -406,41 +396,48 @@ void isst_ctdp_display_information(struct isst_id *id, FILE *outf, int tdp_level
if (!ctdp_level->sse_p1)
ctdp_level->sse_p1 = ctdp_level->tdp_ratio;
snprintf(value, sizeof(value), "%d",
ctdp_level->sse_p1 * DISP_FREQ_MULTIPLIER);
ctdp_level->sse_p1 * isst_get_disp_freq_multiplier());
format_and_print(outf, level + 2, header, value);
if (ctdp_level->avx2_p1) {
snprintf(header, sizeof(header), "base-frequency-avx2(MHz)");
snprintf(value, sizeof(value), "%d",
ctdp_level->avx2_p1 * DISP_FREQ_MULTIPLIER);
ctdp_level->avx2_p1 * isst_get_disp_freq_multiplier());
format_and_print(outf, level + 2, header, value);
}
if (ctdp_level->avx512_p1) {
snprintf(header, sizeof(header), "base-frequency-avx512(MHz)");
snprintf(value, sizeof(value), "%d",
ctdp_level->avx512_p1 * DISP_FREQ_MULTIPLIER);
ctdp_level->avx512_p1 * isst_get_disp_freq_multiplier());
format_and_print(outf, level + 2, header, value);
}
if (ctdp_level->uncore_pm) {
snprintf(header, sizeof(header), "uncore-frequency-min(MHz)");
snprintf(value, sizeof(value), "%d",
ctdp_level->uncore_pm * DISP_FREQ_MULTIPLIER);
ctdp_level->uncore_pm * isst_get_disp_freq_multiplier());
format_and_print(outf, level + 2, header, value);
}
if (ctdp_level->uncore_p0) {
snprintf(header, sizeof(header), "uncore-frequency-max(MHz)");
snprintf(value, sizeof(value), "%d",
ctdp_level->uncore_p0 * DISP_FREQ_MULTIPLIER);
ctdp_level->uncore_p0 * isst_get_disp_freq_multiplier());
format_and_print(outf, level + 2, header, value);
}
if (ctdp_level->amx_p1) {
snprintf(header, sizeof(header), "base-frequency-amx(MHz)");
snprintf(value, sizeof(value), "%d",
ctdp_level->amx_p1 * isst_get_disp_freq_multiplier());
format_and_print(outf, level + 2, header, value);
}
if (ctdp_level->uncore_p1) {
snprintf(header, sizeof(header), "uncore-frequency-base(MHz)");
snprintf(value, sizeof(value), "%d",
ctdp_level->uncore_p1 * DISP_FREQ_MULTIPLIER);
ctdp_level->uncore_p1 * isst_get_disp_freq_multiplier());
format_and_print(outf, level + 2, header, value);
}
......@@ -451,6 +448,13 @@ void isst_ctdp_display_information(struct isst_id *id, FILE *outf, int tdp_level
format_and_print(outf, level + 2, header, value);
}
if (api_version() > 1) {
snprintf(header, sizeof(header), "cooling_type");
snprintf(value, sizeof(value), "%d",
ctdp_level->cooling_type);
format_and_print(outf, level + 2, header, value);
}
snprintf(header, sizeof(header),
"speed-select-turbo-freq");
if (ctdp_level->fact_support) {
......@@ -505,54 +509,24 @@ void isst_ctdp_display_information(struct isst_id *id, FILE *outf, int tdp_level
format_and_print(outf, level + 2, header, value);
}
snprintf(header, sizeof(header), "turbo-ratio-limits-sse");
format_and_print(outf, level + 2, header, NULL);
for (j = 0; j < 8; ++j) {
snprintf(header, sizeof(header), "bucket-%d", j);
format_and_print(outf, level + 3, header, NULL);
for (k = 0; k < trl_max_levels; k++) {
if (!ctdp_level->trl_ratios[k][0])
continue;
snprintf(header, sizeof(header), "core-count");
snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff);
format_and_print(outf, level + 4, header, value);
snprintf(header, sizeof(header),
"max-turbo-frequency(MHz)");
snprintf(value, sizeof(value), "%d",
ctdp_level->trl_sse_active_cores[j] *
DISP_FREQ_MULTIPLIER);
format_and_print(outf, level + 4, header, value);
}
if (ctdp_level->trl_avx_active_cores[0]) {
snprintf(header, sizeof(header), "turbo-ratio-limits-avx2");
snprintf(header, sizeof(header), "turbo-ratio-limits-%s", isst_get_trl_level_name(k));
format_and_print(outf, level + 2, header, NULL);
for (j = 0; j < 8; ++j) {
snprintf(header, sizeof(header), "bucket-%d", j);
format_and_print(outf, level + 3, header, NULL);
snprintf(header, sizeof(header), "core-count");
snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff);
format_and_print(outf, level + 4, header, value);
snprintf(header, sizeof(header), "max-turbo-frequency(MHz)");
snprintf(value, sizeof(value), "%d", ctdp_level->trl_avx_active_cores[j] * DISP_FREQ_MULTIPLIER);
format_and_print(outf, level + 4, header, value);
}
}
if (ctdp_level->trl_avx_512_active_cores[0]) {
snprintf(header, sizeof(header), "turbo-ratio-limits-avx512");
format_and_print(outf, level + 2, header, NULL);
for (j = 0; j < 8; ++j) {
snprintf(header, sizeof(header), "bucket-%d", j);
format_and_print(outf, level + 3, header, NULL);
snprintf(header, sizeof(header), "core-count");
snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff);
snprintf(value, sizeof(value), "%llu", (ctdp_level->trl_cores >> (j * 8)) & 0xff);
format_and_print(outf, level + 4, header, value);
snprintf(header, sizeof(header), "max-turbo-frequency(MHz)");
snprintf(value, sizeof(value), "%d", ctdp_level->trl_avx_512_active_cores[j] * DISP_FREQ_MULTIPLIER);
snprintf(value, sizeof(value), "%d", ctdp_level->trl_ratios[k][j] * isst_get_disp_freq_multiplier());
format_and_print(outf, level + 4, header, value);
}
}
......@@ -631,18 +605,18 @@ void isst_clos_display_information(struct isst_id *id, FILE *outf, int clos,
format_and_print(outf, level + 2, header, value);
snprintf(header, sizeof(header), "clos-min");
snprintf(value, sizeof(value), "%d MHz", clos_config->clos_min * DISP_FREQ_MULTIPLIER);
snprintf(value, sizeof(value), "%d MHz", clos_config->clos_min * isst_get_disp_freq_multiplier());
format_and_print(outf, level + 2, header, value);
snprintf(header, sizeof(header), "clos-max");
if (clos_config->clos_max == 0xff)
if ((clos_config->clos_max * isst_get_disp_freq_multiplier()) == 25500)
snprintf(value, sizeof(value), "Max Turbo frequency");
else
snprintf(value, sizeof(value), "%d MHz", clos_config->clos_max * DISP_FREQ_MULTIPLIER);
snprintf(value, sizeof(value), "%d MHz", clos_config->clos_max * isst_get_disp_freq_multiplier());
format_and_print(outf, level + 2, header, value);
snprintf(header, sizeof(header), "clos-desired");
snprintf(value, sizeof(value), "%d MHz", clos_config->clos_desired * DISP_FREQ_MULTIPLIER);
snprintf(value, sizeof(value), "%d MHz", clos_config->clos_desired * isst_get_disp_freq_multiplier());
format_and_print(outf, level + 2, header, value);
format_and_print(outf, level, NULL, NULL);
......@@ -717,8 +691,7 @@ void isst_display_result(struct isst_id *id, FILE *outf, char *feature, char *cm
char value[256];
int level = 3;
if (id->cpu >= 0)
level = print_package_info(id, outf);
level = print_package_info(id, outf);
snprintf(header, sizeof(header), "%s", feature);
format_and_print(outf, level + 1, header, NULL);
......
......@@ -28,6 +28,8 @@
#include <stdarg.h>
#include <sys/ioctl.h>
#include <linux/isst_if.h>
#define BIT(x) (1 << (x))
#define BIT_ULL(nr) (1ULL << (nr))
#define GENMASK(h, l) (((~0UL) << (l)) & (~0UL >> (sizeof(long) * 8 - 1 - (h))))
......@@ -77,29 +79,29 @@
#define DISP_FREQ_MULTIPLIER 100
#define MAX_PACKAGE_COUNT 8
#define MAX_DIE_PER_PACKAGE 2
#define MAX_PACKAGE_COUNT 8
#define MAX_DIE_PER_PACKAGE 2
#define MAX_PUNIT_PER_DIE 8
/* Unified structure to specific a CPU or a Power Domain */
struct isst_id {
int cpu;
int pkg;
int die;
int punit;
};
struct isst_clos_config {
unsigned int clos_min;
unsigned int clos_max;
unsigned char epp;
unsigned char clos_prop_prio;
unsigned char clos_min;
unsigned char clos_max;
unsigned char clos_desired;
};
struct isst_fact_bucket_info {
int high_priority_cores_count;
int sse_trl;
int avx_trl;
int avx512_trl;
int hp_cores;
int hp_ratios[TRL_MAX_LEVELS];
};
struct isst_pbf_info {
......@@ -117,9 +119,7 @@ struct isst_pbf_info {
#define ISST_TRL_MAX_ACTIVE_CORES 8
#define ISST_FACT_MAX_BUCKETS 8
struct isst_fact_info {
int lp_clipping_ratio_license_sse;
int lp_clipping_ratio_license_avx2;
int lp_clipping_ratio_license_avx512;
int lp_ratios[TRL_MAX_LEVELS];
struct isst_fact_bucket_info bucket_info[ISST_FACT_MAX_BUCKETS];
};
......@@ -143,20 +143,20 @@ struct isst_pkg_ctdp_level_info {
int pkg_max_power;
int fact;
int t_proc_hot;
int cooling_type;
int uncore_p0;
int uncore_p1;
int uncore_pm;
int sse_p1;
int avx2_p1;
int avx512_p1;
int amx_p1;
int mem_freq;
size_t core_cpumask_size;
cpu_set_t *core_cpumask;
int cpu_count;
unsigned long long buckets_info;
int trl_sse_active_cores[ISST_TRL_MAX_ACTIVE_CORES];
int trl_avx_active_cores[ISST_TRL_MAX_ACTIVE_CORES];
int trl_avx_512_active_cores[ISST_TRL_MAX_ACTIVE_CORES];
unsigned long long trl_cores; /* Buckets info */
int trl_ratios[TRL_MAX_LEVELS][ISST_TRL_MAX_ACTIVE_CORES];
int kobj_bucket_index;
int active_bucket;
int fact_max_index;
......@@ -178,13 +178,48 @@ struct isst_pkg_ctdp {
struct isst_pkg_ctdp_level_info ctdp_level[ISST_MAX_TDP_LEVELS];
};
enum isst_platform_param {
ISST_PARAM_MBOX_DELAY,
ISST_PARAM_MBOX_RETRIES,
};
struct isst_platform_ops {
int (*get_disp_freq_multiplier)(void);
int (*get_trl_max_levels)(void);
char *(*get_trl_level_name)(int level);
void (*update_platform_param)(enum isst_platform_param param, int value);
int (*is_punit_valid)(struct isst_id *id);
int (*read_pm_config)(struct isst_id *id, int *cp_state, int *cp_cap);
int (*get_config_levels)(struct isst_id *id, struct isst_pkg_ctdp *pkg_ctdp);
int (*get_ctdp_control)(struct isst_id *id, int config_index, struct isst_pkg_ctdp_level_info *ctdp_level);
int (*get_tdp_info)(struct isst_id *id, int config_index, struct isst_pkg_ctdp_level_info *ctdp_level);
int (*get_pwr_info)(struct isst_id *id, int config_index, struct isst_pkg_ctdp_level_info *ctdp_level);
int (*get_coremask_info)(struct isst_id *id, int config_index, struct isst_pkg_ctdp_level_info *ctdp_level);
int (*get_get_trl)(struct isst_id *id, int level, int avx_level, int *trl);
int (*get_get_trls)(struct isst_id *id, int level, struct isst_pkg_ctdp_level_info *ctdp_level);
int (*get_trl_bucket_info)(struct isst_id *id, int level, unsigned long long *buckets_info);
int (*set_tdp_level)(struct isst_id *id, int tdp_level);
int (*get_pbf_info)(struct isst_id *id, int level, struct isst_pbf_info *pbf_info);
int (*set_pbf_fact_status)(struct isst_id *id, int pbf, int enable);
int (*get_fact_info)(struct isst_id *id, int level, int fact_bucket, struct isst_fact_info *fact_info);
void (*adjust_uncore_freq)(struct isst_id *id, int config_index, struct isst_pkg_ctdp_level_info *ctdp_level);
int (*get_clos_information)(struct isst_id *id, int *enable, int *type);
int (*pm_qos_config)(struct isst_id *id, int enable_clos, int priority_type);
int (*pm_get_clos)(struct isst_id *id, int clos, struct isst_clos_config *clos_config);
int (*set_clos)(struct isst_id *id, int clos, struct isst_clos_config *clos_config);
int (*clos_get_assoc_status)(struct isst_id *id, int *clos_id);
int (*clos_associate)(struct isst_id *id, int clos_id);
};
extern int is_cpu_in_power_domain(int cpu, struct isst_id *id);
extern int get_topo_max_cpus(void);
extern int get_cpu_count(struct isst_id *id);
extern int get_max_punit_core_id(struct isst_id *id);
extern int api_version(void);
/* Common interfaces */
FILE *get_output_file(void);
extern int is_debug_enabled(void);
extern void debug_printf(const char *format, ...);
extern int out_format_is_json(void);
extern void set_isst_id(struct isst_id *id, int cpu);
......@@ -196,21 +231,22 @@ extern void set_cpu_mask_from_punit_coremask(struct isst_id *id,
size_t core_cpumask_size,
cpu_set_t *core_cpumask,
int *cpu_cnt);
extern int isst_send_mbox_command(unsigned int cpu, unsigned char command,
unsigned char sub_command,
unsigned int write,
unsigned int req_data, unsigned int *resp);
extern int isst_send_msr_command(unsigned int cpu, unsigned int command,
int write, unsigned long long *req_resp);
extern int isst_set_platform_ops(int api_version);
extern void isst_update_platform_param(enum isst_platform_param, int vale);
extern int isst_get_disp_freq_multiplier(void);
extern int isst_get_trl_max_levels(void);
extern char *isst_get_trl_level_name(int level);
extern int isst_is_punit_valid(struct isst_id *id);
extern int isst_get_ctdp_levels(struct isst_id *id, struct isst_pkg_ctdp *pkg_dev);
extern int isst_get_ctdp_control(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level);
extern int isst_get_coremask_info(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level);
extern void isst_get_uncore_p0_p1_info(struct isst_id *id, int config_index,
extern void isst_adjust_uncore_freq(struct isst_id *id, int config_index,
struct isst_pkg_ctdp_level_info *ctdp_level);
extern int isst_get_process_ctdp(struct isst_id *id, int tdp_level,
struct isst_pkg_ctdp *pkg_dev);
......@@ -228,11 +264,8 @@ extern int isst_set_tdp_level(struct isst_id *id, int tdp_level);
extern int isst_set_pbf_fact_status(struct isst_id *id, int pbf, int enable);
extern int isst_get_pbf_info(struct isst_id *id, int level,
struct isst_pbf_info *pbf_info);
extern void isst_get_pbf_info_complete(struct isst_pbf_info *pbf_info);
extern int isst_get_fact_info(struct isst_id *id, int level, int fact_bucket,
struct isst_fact_info *fact_info);
extern int isst_get_fact_bucket_info(struct isst_id *id, int level,
struct isst_fact_bucket_info *bucket_info);
extern void isst_fact_display_information(struct isst_id *id, FILE *outf, int level,
int fact_bucket, int fact_avx,
struct isst_fact_info *fact_info);
......@@ -265,11 +298,12 @@ extern int isst_read_pm_config(struct isst_id *id, int *cp_state, int *cp_cap);
extern void isst_display_error_info_message(int error, char *msg, int arg_valid, int arg);
extern int is_skx_based_platform(void);
extern int is_spr_platform(void);
extern int is_emr_platform(void);
extern int is_icx_platform(void);
extern void isst_trl_display_information(struct isst_id *id, FILE *outf, unsigned long long trl);
extern void set_cpu_online_offline(int cpu, int state);
extern void for_each_online_package_in_set(void (*callback)(struct isst_id *, void *, void *,
extern void for_each_online_power_domain_in_set(void (*callback)(struct isst_id *, void *, void *,
void *, void *),
void *arg1, void *arg2, void *arg3,
void *arg4);
......@@ -277,4 +311,14 @@ extern int isst_daemon(int debug_mode, int poll_interval, int no_daemon);
extern void process_level_change(struct isst_id *id);
extern int hfi_main(void);
extern void hfi_exit(void);
/* Interface specific callbacks */
extern struct isst_platform_ops *mbox_get_platform_ops(void);
extern struct isst_platform_ops *tpmi_get_platform_ops(void);
/* Cgroup related interface */
extern int enable_cpuset_controller(void);
extern int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int level);
extern int use_cgroupv2(void);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment