diff options
Diffstat (limited to 'tools/power/x86/intel-speed-select/isst-config.c')
-rw-r--r-- | tools/power/x86/intel-speed-select/isst-config.c | 1388 |
1 files changed, 1018 insertions, 370 deletions
diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index 2b2b8167c65b..a160bad291eb 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -15,7 +15,8 @@ struct process_cmd_struct { int arg; }; -static const char *version_str = "v1.2"; +static const char *version_str = "v1.13"; + static const int supported_api_ver = 1; static struct isst_if_platform_info isst_platform_info; static char *progname; @@ -25,7 +26,7 @@ static FILE *outf; static int cpu_model; static int cpu_stepping; -#define MAX_CPUS_IN_ONE_REQ 64 +#define MAX_CPUS_IN_ONE_REQ 256 static short max_target_cpus; static unsigned short target_cpus[MAX_CPUS_IN_ONE_REQ]; @@ -42,6 +43,10 @@ static int out_format_json; 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; /* clos related */ static int current_clos = -1; @@ -58,9 +63,22 @@ struct _cpu_map { unsigned short die_id; unsigned short punit_cpu; unsigned short punit_cpu_core; + unsigned short initialized; }; struct _cpu_map *cpu_map; +struct cpu_topology { + short cpu; + short core_id; + short pkg_id; + short die_id; +}; + +FILE *get_output_file(void) +{ + return outf; +} + void debug_printf(const char *format, ...) { va_list args; @@ -82,6 +100,30 @@ int is_clx_n_platform(void) return 0; } +int is_skx_based_platform(void) +{ + if (cpu_model == 0x55) + return 1; + + return 0; +} + +int is_spr_platform(void) +{ + if (cpu_model == 0x8F) + return 1; + + return 0; +} + +int is_icx_platform(void) +{ + if (cpu_model == 0x6A || cpu_model == 0x6C) + return 1; + + return 0; +} + static int update_cpu_model(void) { unsigned int ebx, ecx, edx; @@ -175,31 +217,192 @@ int out_format_is_json(void) return out_format_json; } -int get_physical_package_id(int cpu) +static int get_stored_topology_info(int cpu, int *core_id, int *pkg_id, int *die_id) +{ + const char *pathname = "/var/run/isst_cpu_topology.dat"; + struct cpu_topology cpu_top; + FILE *fp; + int ret; + + fp = fopen(pathname, "rb"); + if (!fp) + return -1; + + ret = fseek(fp, cpu * sizeof(cpu_top), SEEK_SET); + if (ret) + goto err_ret; + + ret = fread(&cpu_top, sizeof(cpu_top), 1, fp); + if (ret != 1) { + ret = -1; + goto err_ret; + } + + *pkg_id = cpu_top.pkg_id; + *core_id = cpu_top.core_id; + *die_id = cpu_top.die_id; + ret = 0; + +err_ret: + fclose(fp); + + return ret; +} + +static void store_cpu_topology(void) +{ + const char *pathname = "/var/run/isst_cpu_topology.dat"; + FILE *fp; + int i; + + fp = fopen(pathname, "rb"); + if (fp) { + /* Mapping already exists */ + fclose(fp); + return; + } + + fp = fopen(pathname, "wb"); + if (!fp) { + fprintf(stderr, "Can't create file:%s\n", pathname); + return; + } + + fprintf(stderr, "Caching topology information\n"); + + for (i = 0; i < topo_max_cpus; ++i) { + struct cpu_topology cpu_top; + + cpu_top.core_id = parse_int_file(0, + "/sys/devices/system/cpu/cpu%d/topology/core_id", i); + if (cpu_top.core_id < 0) + cpu_top.core_id = -1; + + cpu_top.pkg_id = parse_int_file(0, + "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", i); + if (cpu_top.pkg_id < 0) + cpu_top.pkg_id = -1; + + cpu_top.die_id = parse_int_file(0, + "/sys/devices/system/cpu/cpu%d/topology/die_id", i); + if (cpu_top.die_id < 0) + cpu_top.die_id = -1; + + cpu_top.cpu = i; + + if (fwrite(&cpu_top, sizeof(cpu_top), 1, fp) != 1) { + fprintf(stderr, "Can't write to:%s\n", pathname); + break; + } + } + + fclose(fp); +} + +static int get_physical_package_id(int cpu) { - return parse_int_file( - 0, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", - cpu); + int ret; + + if (cpu < 0) + return -1; + + if (cpu_map && cpu_map[cpu].initialized) + return cpu_map[cpu].pkg_id; + + ret = parse_int_file(0, + "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", + cpu); + if (ret < 0) { + int core_id, pkg_id, die_id; + + ret = get_stored_topology_info(cpu, &core_id, &pkg_id, &die_id); + if (!ret) + return pkg_id; + } + + return ret; } -int get_physical_core_id(int cpu) +static int get_physical_core_id(int cpu) { - return parse_int_file( - 0, "/sys/devices/system/cpu/cpu%d/topology/core_id", cpu); + int ret; + + if (cpu < 0) + return -1; + + if (cpu_map && cpu_map[cpu].initialized) + return cpu_map[cpu].core_id; + + ret = parse_int_file(0, + "/sys/devices/system/cpu/cpu%d/topology/core_id", + cpu); + if (ret < 0) { + int core_id, pkg_id, die_id; + + ret = get_stored_topology_info(cpu, &core_id, &pkg_id, &die_id); + if (!ret) + return core_id; + } + + return ret; } -int get_physical_die_id(int cpu) +static int get_physical_die_id(int cpu) { int ret; - ret = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/topology/die_id", - cpu); + if (cpu < 0) + return -1; + + if (cpu_map && cpu_map[cpu].initialized) + return cpu_map[cpu].die_id; + + ret = parse_int_file(0, + "/sys/devices/system/cpu/cpu%d/topology/die_id", + cpu); + if (ret < 0) { + int core_id, pkg_id, die_id; + + ret = get_stored_topology_info(cpu, &core_id, &pkg_id, &die_id); + if (!ret) { + if (die_id < 0) + die_id = 0; + + return die_id; + } + } + if (ret < 0) ret = 0; return ret; } +void set_isst_id(struct isst_id *id, int cpu) +{ + id->cpu = cpu; + + id->pkg = get_physical_package_id(cpu); + if (id < 0 || id->pkg >= MAX_PACKAGE_COUNT) + id->pkg = -1; + + id->die = get_physical_die_id(cpu); + if (id < 0 || id->die >= MAX_DIE_PER_PACKAGE) + id->die = -1; +} + +int is_cpu_in_power_domain(int cpu, struct isst_id *id) +{ + struct isst_id tid; + + set_isst_id(&tid, cpu); + + if (id->pkg == tid.pkg && id->die == tid.die) + return 1; + + return 0; +} + int get_cpufreq_base_freq(int cpu) { return parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/base_frequency", cpu); @@ -210,7 +413,7 @@ int get_topo_max_cpus(void) return topo_max_cpus; } -static void set_cpu_online_offline(int cpu, int state) +void set_cpu_online_offline(int cpu, int state) { char buffer[128]; int fd, ret; @@ -219,8 +422,14 @@ static void set_cpu_online_offline(int cpu, int state) "/sys/devices/system/cpu/cpu%d/online", cpu); fd = open(buffer, O_WRONLY); - if (fd < 0) + if (fd < 0) { + if (!cpu && state) { + fprintf(stderr, "This system is not configured for CPU 0 online/offline\n"); + fprintf(stderr, "Ignoring online request for CPU 0 as this is already online\n"); + return; + } err(-1, "%s open failed", buffer); + } if (state) ret = write(fd, "1\n", 2); @@ -233,15 +442,26 @@ static void set_cpu_online_offline(int cpu, int state) close(fd); } -#define MAX_PACKAGE_COUNT 8 -#define MAX_DIE_PER_PACKAGE 2 -static void for_each_online_package_in_set(void (*callback)(int, void *, void *, - void *, void *), - void *arg1, void *arg2, void *arg3, - void *arg4) +static void force_all_cpus_online(void) +{ + int i; + + fprintf(stderr, "Forcing all CPUs online\n"); + + for (i = 0; i < topo_max_cpus; ++i) + set_cpu_online_offline(i, 1); + + unlink("/var/run/isst_cpu_topology.dat"); +} + +void for_each_online_package_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; memset(max_packages, 0xff, sizeof(max_packages)); for (i = 0; i < topo_max_cpus; ++i) { @@ -259,7 +479,12 @@ static void for_each_online_package_in_set(void (*callback)(int, void *, void *, die_id = get_physical_die_id(i); if (die_id < 0) die_id = 0; - pkg_id = get_physical_package_id(i); + + pkg_id = parse_int_file(0, + "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", i); + if (pkg_id < 0) + continue; + /* Create an unique id for package, die combination to store */ pkg_id = (MAX_PACKAGE_COUNT * pkg_id + die_id); @@ -270,18 +495,20 @@ static void for_each_online_package_in_set(void (*callback)(int, void *, void *, } } + set_isst_id(&id, i); if (!skip && online && callback) { - callback(i, arg1, arg2, arg3, arg4); + callback(&id, arg1, arg2, arg3, arg4); max_packages[pkg_index++] = pkg_id; } } } static void for_each_online_target_cpu_in_set( - void (*callback)(int, void *, void *, void *, void *), void *arg1, + void (*callback)(struct isst_id *, void *, void *, void *, void *), void *arg1, void *arg2, void *arg3, void *arg4) { - int i; + int i, found = 0; + struct isst_id id; for (i = 0; i < topo_max_cpus; ++i) { int online; @@ -295,9 +522,15 @@ static void for_each_online_target_cpu_in_set( online = 1; /* online entry for CPU 0 needs some special configs */ - if (online && callback) - callback(i, arg1, arg2, arg3, arg4); + set_isst_id(&id, i); + if (online && callback) { + callback(&id, arg1, arg2, arg3, arg4); + found = 1; + } } + + if (!found) + fprintf(stderr, "No valid CPU in the list\n"); } #define BITMASK_SIZE 32 @@ -305,14 +538,27 @@ static void set_max_cpu_num(void) { FILE *filep; unsigned long dummy; + int i; topo_max_cpus = 0; - filep = fopen_or_exit( - "/sys/devices/system/cpu/cpu0/topology/thread_siblings", "r"); + 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; + } + + if (!filep) { + fprintf(stderr, "Can't get max cpu number\n"); + exit(0); + } + while (fscanf(filep, "%lx,", &dummy) == 1) topo_max_cpus += BITMASK_SIZE; fclose(filep); - topo_max_cpus--; /* 0 based */ debug_printf("max cpus %d\n", topo_max_cpus); } @@ -338,103 +584,85 @@ void free_cpu_set(cpu_set_t *cpu_set) } static int cpu_cnt[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE]; -static long long core_mask[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE]; -static void set_cpu_present_cpu_mask(void) -{ - size_t size; - DIR *dir; - int i; - size = alloc_cpu_set(&present_cpumask); - present_cpumask_size = size; - for (i = 0; i < topo_max_cpus; ++i) { - char buffer[256]; - - snprintf(buffer, sizeof(buffer), - "/sys/devices/system/cpu/cpu%d", i); - dir = opendir(buffer); - if (dir) { - int pkg_id, die_id; - - CPU_SET_S(i, size, present_cpumask); - die_id = get_physical_die_id(i); - if (die_id < 0) - die_id = 0; - - pkg_id = get_physical_package_id(i); - if (pkg_id < MAX_PACKAGE_COUNT && - die_id < MAX_DIE_PER_PACKAGE) { - int core_id = get_physical_core_id(i); - - cpu_cnt[pkg_id][die_id]++; - core_mask[pkg_id][die_id] |= (1ULL << core_id); - } - } - closedir(dir); - } -} - -int get_core_count(int pkg_id, int die_id) +int get_max_punit_core_id(struct isst_id *id) { - int cnt = 0; + int max_id = 0; + int i; - if (pkg_id < MAX_PACKAGE_COUNT && die_id < MAX_DIE_PER_PACKAGE) { - int i; + for (i = 0; i < topo_max_cpus; ++i) + { + if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask)) + continue; - for (i = 0; i < sizeof(long long) * 8; ++i) { - if (core_mask[pkg_id][die_id] & (1ULL << i)) - cnt++; - } + if (is_cpu_in_power_domain(i, id) && + cpu_map[i].punit_cpu_core > max_id) + max_id = cpu_map[i].punit_cpu_core; } - return cnt; -} - -int get_cpu_count(int pkg_id, int die_id) -{ - if (pkg_id < MAX_PACKAGE_COUNT && die_id < MAX_DIE_PER_PACKAGE) - return cpu_cnt[pkg_id][die_id]; - - return 0; + return max_id; } -static void set_cpu_target_cpu_mask(void) +int get_cpu_count(struct isst_id *id) { - size_t size; - int i; - - size = alloc_cpu_set(&target_cpumask); - target_cpumask_size = size; - for (i = 0; i < max_target_cpus; ++i) { - if (!CPU_ISSET_S(target_cpus[i], present_cpumask_size, - present_cpumask)) - continue; + if (id->pkg < 0 || id->die < 0) + return 0; - CPU_SET_S(target_cpus[i], size, target_cpumask); - } + return cpu_cnt[id->pkg][id->die]; } static void create_cpu_map(void) { const char *pathname = "/dev/isst_interface"; + size_t size; + DIR *dir; int i, fd = 0; struct isst_if_cpu_maps map; - cpu_map = malloc(sizeof(*cpu_map) * topo_max_cpus); + /* Use calloc to make sure the memory is initialized to Zero */ + cpu_map = calloc(topo_max_cpus, sizeof(*cpu_map)); if (!cpu_map) err(3, "cpumap"); fd = open(pathname, O_RDWR); - if (fd < 0) + if (fd < 0 && !is_clx_n_platform()) err(-1, "%s open failed", pathname); + size = alloc_cpu_set(&present_cpumask); + present_cpumask_size = size; + for (i = 0; i < topo_max_cpus; ++i) { - if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask)) + char buffer[256]; + int pkg_id, die_id, core_id; + + /* check if CPU is online */ + snprintf(buffer, sizeof(buffer), + "/sys/devices/system/cpu/cpu%d", i); + dir = opendir(buffer); + if (!dir) + continue; + closedir(dir); + + CPU_SET_S(i, size, present_cpumask); + + pkg_id = get_physical_package_id(i); + die_id = get_physical_die_id(i); + core_id = get_physical_core_id(i); + + if (pkg_id < 0 || die_id < 0 || core_id < 0) continue; + 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) { @@ -443,9 +671,6 @@ static void create_cpu_map(void) map.cpu_map[0].logical_cpu); continue; } - cpu_map[i].core_id = get_physical_core_id(i); - cpu_map[i].pkg_id = get_physical_package_id(i); - cpu_map[i].die_id = get_physical_die_id(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 @@ -456,46 +681,37 @@ static void create_cpu_map(void) cpu_map[i].pkg_id, cpu_map[i].punit_cpu, cpu_map[i].punit_cpu_core); } - - if (fd) + if (fd >= 0) close(fd); -} -int find_logical_cpu(int pkg_id, int die_id, int punit_core_id) -{ - int i; + size = alloc_cpu_set(&target_cpumask); + target_cpumask_size = size; + for (i = 0; i < max_target_cpus; ++i) { + if (!CPU_ISSET_S(target_cpus[i], present_cpumask_size, + present_cpumask)) + continue; - for (i = 0; i < topo_max_cpus; ++i) { - if (cpu_map[i].pkg_id == pkg_id && - cpu_map[i].die_id == die_id && - cpu_map[i].punit_cpu_core == punit_core_id) - return i; + CPU_SET_S(target_cpus[i], size, target_cpumask); } - - return -EINVAL; } -void set_cpu_mask_from_punit_coremask(int cpu, unsigned long long core_mask, +void set_cpu_mask_from_punit_coremask(struct isst_id *id, unsigned long long core_mask, size_t core_cpumask_size, cpu_set_t *core_cpumask, int *cpu_cnt) { int i, cnt = 0; - int die_id, pkg_id; *cpu_cnt = 0; - die_id = get_physical_die_id(cpu); - pkg_id = get_physical_package_id(cpu); for (i = 0; i < 64; ++i) { - if (core_mask & BIT(i)) { + if (core_mask & BIT_ULL(i)) { int j; for (j = 0; j < topo_max_cpus; ++j) { if (!CPU_ISSET_S(j, present_cpumask_size, present_cpumask)) continue; - if (cpu_map[j].pkg_id == pkg_id && - cpu_map[j].die_id == die_id && + if (is_cpu_in_power_domain(j, id) && cpu_map[j].punit_cpu_core == i) { CPU_SET_S(j, core_cpumask_size, core_cpumask); @@ -542,7 +758,11 @@ static int isst_send_mmio_command(unsigned int cpu, unsigned int reg, int write, } if (ioctl(fd, cmd, &io_regs) == -1) { - perror("ISST_IF_IO_CMD"); + 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 { @@ -564,14 +784,15 @@ int isst_send_mbox_command(unsigned int cpu, unsigned char command, unsigned int req_data, unsigned int *resp) { const char *pathname = "/dev/isst_interface"; - int fd; + 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 (isst_platform_info.mmio_supported && command == CONFIG_CLOS) { + 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; @@ -615,25 +836,42 @@ int isst_send_mbox_command(unsigned int cpu, unsigned char 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); - if (ioctl(fd, ISST_IF_MBOX_COMMAND, &mbox_cmds) == -1) { - perror("ISST_IF_MBOX_COMMAND"); - fprintf(outf, - "Error: mbox_cmd cpu:%d command:%x sub_command:%x parameter:%x req_data:%x\n", - cpu, command, sub_command, parameter, req_data); - return -1; - } 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); - } + 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; } @@ -656,7 +894,7 @@ int isst_send_msr_command(unsigned int cpu, unsigned int msr, int write, msr_cmds.msr_cmd[0].data = *req_resp; if (ioctl(fd, ISST_IF_MSR_COMMAND, &msr_cmds) == -1) { - perror("ISST_IF_MSR_COMMAD"); + perror("ISST_IF_MSR_COMMAND"); fprintf(outf, "Error: msr_cmd cpu:%d msr:%x read_write:%d\n", cpu, msr, write); } else { @@ -697,12 +935,95 @@ static int isst_fill_platform_info(void) return 0; } +static void isst_print_extended_platform_info(void) +{ + 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; + } + + if (!filep) + return; + + fclose(filep); + + set_isst_id(&id, i); + 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.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); + + for (j = 0; j <= pkg_dev.levels; ++j) { + ret = isst_get_ctdp_control(&id, j, &ctdp_level); + if (ret) + continue; + + if (!fact_support && ctdp_level.fact_support) + fact_support = 1; + + if (!pbf_support && ctdp_level.pbf_support) + pbf_support = 1; + } + + if (fact_support) + 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) + 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) { + 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 + fprintf(outf, "Intel(R) SST-CP (feature core-power) is not supported\n"); +} + 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); + } + + /* Early initialization to create working cpu_map */ + set_max_cpu_num(); + create_cpu_map(); + fd = open(pathname, O_RDWR); if (fd < 0) err(-1, "%s open failed", pathname); @@ -718,6 +1039,7 @@ static void isst_print_platform_information(void) platform_info.mbox_supported); fprintf(outf, "Platform: mmio supported : %d\n", platform_info.mmio_supported); + isst_print_extended_platform_info(); } close(fd); @@ -725,22 +1047,24 @@ static void isst_print_platform_information(void) exit(0); } -static void exec_on_get_ctdp_cpu(int cpu, void *arg1, void *arg2, void *arg3, +static char *local_str0, *local_str1; +static void exec_on_get_ctdp_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, void *arg4) { - int (*fn_ptr)(int cpu, void *arg); + int (*fn_ptr)(struct isst_id *id, void *arg); int ret; fn_ptr = arg1; - ret = fn_ptr(cpu, arg2); + ret = fn_ptr(id, arg2); if (ret) - perror("get_tdp_*"); + isst_display_error_info_message(1, "get_tdp_* failed", 0, 0); else - isst_ctdp_display_core_info(cpu, outf, arg3, - *(unsigned int *)arg4); + isst_ctdp_display_core_info(id, outf, arg3, + *(unsigned int *)arg4, + local_str0, local_str1); } -#define _get_tdp_level(desc, suffix, object, help) \ +#define _get_tdp_level(desc, suffix, object, help, str0, str1) \ static void get_tdp_##object(int arg) \ { \ struct isst_pkg_ctdp ctdp; \ @@ -751,6 +1075,8 @@ static void exec_on_get_ctdp_cpu(int cpu, void *arg1, void *arg2, void *arg3, help); \ exit(0); \ } \ + local_str0 = str0; \ + local_str1 = str1; \ isst_ctdp_display_information_start(outf); \ if (max_target_cpus) \ for_each_online_target_cpu_in_set( \ @@ -764,12 +1090,12 @@ static void exec_on_get_ctdp_cpu(int cpu, void *arg1, void *arg2, void *arg3, isst_ctdp_display_information_end(outf); \ } -_get_tdp_level("get-config-levels", levels, levels, "TDP levels"); -_get_tdp_level("get-config-version", levels, version, "TDP version"); -_get_tdp_level("get-config-enabled", levels, enabled, "TDP enable status"); +_get_tdp_level("get-config-levels", levels, levels, "Max TDP level", NULL, NULL); +_get_tdp_level("get-config-version", levels, version, "TDP version", NULL, NULL); +_get_tdp_level("get-config-enabled", levels, enabled, "perf-profile enable status", "disabled", "enabled"); _get_tdp_level("get-config-current_level", levels, current_level, - "Current TDP Level"); -_get_tdp_level("get-lock-status", levels, locked, "TDP lock status"); + "Current TDP Level", NULL, NULL); +_get_tdp_level("get-lock-status", levels, locked, "TDP lock status", "unlocked", "locked"); struct isst_pkg_ctdp clx_n_pkg_dev; @@ -801,9 +1127,9 @@ static int clx_n_get_base_ratio(void) return (int)(value); } -static int clx_n_config(int cpu) +static int clx_n_config(struct isst_id *id) { - int i, ret, pkg_id, die_id; + int i, ret; unsigned long cpu_bf; struct isst_pkg_ctdp_level_info *ctdp_level; struct isst_pbf_info *pbf_info; @@ -825,15 +1151,11 @@ static int clx_n_config(int cpu) pbf_info->p1_high = 0; pbf_info->p1_low = ~0; - pkg_id = get_physical_package_id(cpu); - die_id = get_physical_die_id(cpu); - for (i = 0; i < topo_max_cpus; i++) { if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask)) continue; - if (pkg_id != get_physical_package_id(i) || - die_id != get_physical_die_id(i)) + if (!is_cpu_in_power_domain(i, id)) continue; CPU_SET_S(i, ctdp_level->core_cpumask_size, @@ -870,8 +1192,7 @@ static int clx_n_config(int cpu) if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask)) continue; - if (pkg_id != get_physical_package_id(i) || - die_id != get_physical_die_id(i)) + if (!is_cpu_in_power_domain(i, id)) continue; cpu_bf = parse_int_file(1, @@ -897,39 +1218,47 @@ error_ret: return ret; } -static void dump_clx_n_config_for_cpu(int cpu, void *arg1, void *arg2, +static void dump_clx_n_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, void *arg4) { int ret; - ret = clx_n_config(cpu); + if (tdp_level != 0xff && tdp_level != 0) { + isst_display_error_info_message(1, "Invalid level", 1, tdp_level); + exit(0); + } + + ret = clx_n_config(id); if (ret) { - perror("isst_get_process_ctdp"); + debug_printf("clx_n_config failed"); } else { struct isst_pkg_ctdp_level_info *ctdp_level; struct isst_pbf_info *pbf_info; ctdp_level = &clx_n_pkg_dev.ctdp_level[0]; pbf_info = &ctdp_level->pbf_info; - isst_ctdp_display_information(cpu, outf, tdp_level, &clx_n_pkg_dev); + clx_n_pkg_dev.processed = 1; + isst_ctdp_display_information(id, outf, tdp_level, &clx_n_pkg_dev); free_cpu_set(ctdp_level->core_cpumask); free_cpu_set(pbf_info->core_cpumask); } } -static void dump_isst_config_for_cpu(int cpu, void *arg1, void *arg2, +static void dump_isst_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, void *arg4) { struct isst_pkg_ctdp pkg_dev; int ret; memset(&pkg_dev, 0, sizeof(pkg_dev)); - ret = isst_get_process_ctdp(cpu, tdp_level, &pkg_dev); + ret = isst_get_process_ctdp(id, tdp_level, &pkg_dev); if (ret) { - perror("isst_get_process_ctdp"); + isst_display_error_info_message(1, "Failed to get perf-profile info on cpu", 1, id->cpu); + isst_ctdp_display_information_end(outf); + exit(1); } else { - isst_ctdp_display_information(cpu, outf, tdp_level, &pkg_dev); - isst_get_process_ctdp_complete(cpu, &pkg_dev); + isst_ctdp_display_information(id, outf, tdp_level, &pkg_dev); + isst_get_process_ctdp_complete(id, &pkg_dev); } } @@ -963,34 +1292,44 @@ static void dump_isst_config(int arg) isst_ctdp_display_information_end(outf); } -static void set_tdp_level_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, +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) { int ret; - ret = isst_set_tdp_level(cpu, tdp_level); - if (ret) - perror("set_tdp_level_for_cpu"); - else { - isst_display_result(cpu, outf, "perf-profile", "set_tdp_level", + 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; - int pkg_id = get_physical_package_id(cpu); - int die_id = get_physical_die_id(cpu); + + /* Wait for updated base frequencies */ + usleep(2000); fprintf(stderr, "Option is set to online/offline\n"); ctdp_level.core_cpumask_size = alloc_cpu_set(&ctdp_level.core_cpumask); - isst_get_coremask_info(cpu, tdp_level, &ctdp_level); + 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 (pkg_id != get_physical_package_id(i) || die_id != get_physical_die_id(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); @@ -1009,11 +1348,13 @@ static void set_tdp_level(int arg) "\t Arguments: -l|--level : Specify tdp level\n"); fprintf(stderr, "\t Optional Arguments: -o | online : online/offline for the tdp level\n"); + fprintf(stderr, + "\t online/offline operation has limitations, refer to Linux hotplug documentation\n"); exit(0); } if (tdp_level == 0xff) { - fprintf(outf, "Invalid command: specify tdp_level\n"); + isst_display_error_info_message(1, "Invalid command: specify tdp_level", 0, 0); exit(1); } isst_ctdp_display_information_start(outf); @@ -1026,37 +1367,39 @@ static void set_tdp_level(int arg) isst_ctdp_display_information_end(outf); } -static void clx_n_dump_pbf_config_for_cpu(int cpu, void *arg1, void *arg2, +static void clx_n_dump_pbf_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, void *arg4) { int ret; - ret = clx_n_config(cpu); + ret = clx_n_config(id); if (ret) { - perror("isst_get_process_ctdp"); + isst_display_error_info_message(1, "clx_n_config failed", 0, 0); } else { struct isst_pkg_ctdp_level_info *ctdp_level; struct isst_pbf_info *pbf_info; ctdp_level = &clx_n_pkg_dev.ctdp_level[0]; pbf_info = &ctdp_level->pbf_info; - isst_pbf_display_information(cpu, outf, tdp_level, pbf_info); + isst_pbf_display_information(id, outf, tdp_level, pbf_info); free_cpu_set(ctdp_level->core_cpumask); free_cpu_set(pbf_info->core_cpumask); } } -static void dump_pbf_config_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, +static void dump_pbf_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, void *arg4) { struct isst_pbf_info pbf_info; int ret; - ret = isst_get_pbf_info(cpu, tdp_level, &pbf_info); + ret = isst_get_pbf_info(id, tdp_level, &pbf_info); if (ret) { - perror("isst_get_pbf_info"); + isst_display_error_info_message(1, "Failed to get base-freq info at this level", 1, tdp_level); + isst_ctdp_display_information_end(outf); + exit(1); } else { - isst_pbf_display_information(cpu, outf, tdp_level, &pbf_info); + isst_pbf_display_information(id, outf, tdp_level, &pbf_info); isst_get_pbf_info_complete(&pbf_info); } } @@ -1074,7 +1417,7 @@ static void dump_pbf_config(int arg) } if (tdp_level == 0xff) { - fprintf(outf, "Invalid command: specify tdp_level\n"); + isst_display_error_info_message(1, "Invalid command: specify tdp_level", 0, 0); exit(1); } @@ -1093,23 +1436,23 @@ static void dump_pbf_config(int arg) isst_ctdp_display_information_end(outf); } -static int set_clos_param(int cpu, int clos, int epp, int wt, int min, int max) +static int set_clos_param(struct isst_id *id, int clos, int epp, int wt, int min, int max) { struct isst_clos_config clos_config; int ret; - ret = isst_pm_get_clos(cpu, clos, &clos_config); + ret = isst_pm_get_clos(id, clos, &clos_config); if (ret) { - perror("isst_pm_get_clos"); + isst_display_error_info_message(1, "isst_pm_get_clos failed", 0, 0); return ret; } clos_config.clos_min = min; clos_config.clos_max = max; clos_config.epp = epp; clos_config.clos_prop_prio = wt; - ret = isst_set_clos(cpu, clos, &clos_config); + ret = isst_set_clos(id, clos, &clos_config); if (ret) { - perror("isst_pm_set_clos"); + isst_display_error_info_message(1, "isst_set_clos failed", 0, 0); return ret; } @@ -1144,16 +1487,41 @@ static int set_cpufreq_scaling_min_max(int cpu, int max, int freq) return 0; } -static int set_clx_pbf_cpufreq_scaling_min_max(int cpu) +static int no_turbo(void) +{ + return parse_int_file(0, "/sys/devices/system/cpu/intel_pstate/no_turbo"); +} + +static void adjust_scaling_max_from_base_freq(int cpu) +{ + int base_freq, scaling_max_freq; + + scaling_max_freq = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu); + base_freq = get_cpufreq_base_freq(cpu); + if (scaling_max_freq < base_freq || no_turbo()) + set_cpufreq_scaling_min_max(cpu, 1, base_freq); +} + +static void adjust_scaling_min_from_base_freq(int cpu) +{ + int base_freq, scaling_min_freq; + + scaling_min_freq = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu); + base_freq = get_cpufreq_base_freq(cpu); + if (scaling_min_freq < base_freq) + set_cpufreq_scaling_min_max(cpu, 0, base_freq); +} + +static int set_clx_pbf_cpufreq_scaling_min_max(struct isst_id *id) { struct isst_pkg_ctdp_level_info *ctdp_level; struct isst_pbf_info *pbf_info; - int i, pkg_id, die_id, freq, freq_high, freq_low; + int i, freq, freq_high, freq_low; int ret; - ret = clx_n_config(cpu); + ret = clx_n_config(id); if (ret) { - perror("set_clx_pbf_cpufreq_scaling_min_max"); + debug_printf("cpufreq_scaling_min_max failed for CLX"); return ret; } @@ -1162,11 +1530,8 @@ static int set_clx_pbf_cpufreq_scaling_min_max(int cpu) freq_high = pbf_info->p1_high * 100000; freq_low = pbf_info->p1_low * 100000; - pkg_id = get_physical_package_id(cpu); - die_id = get_physical_die_id(cpu); for (i = 0; i < get_topo_max_cpus(); ++i) { - if (pkg_id != get_physical_package_id(i) || - die_id != get_physical_die_id(i)) + if (!is_cpu_in_power_domain(i, id)) continue; if (CPU_ISSET_S(i, pbf_info->core_cpumask_size, @@ -1229,83 +1594,75 @@ static int set_cpufreq_scaling_min_max_from_cpuinfo(int cpu, int cpuinfo_max, in return 0; } -static void set_scaling_min_to_cpuinfo_max(int cpu) +static void set_scaling_min_to_cpuinfo_max(struct isst_id *id) { - int i, pkg_id, die_id; + int i; - pkg_id = get_physical_package_id(cpu); - die_id = get_physical_die_id(cpu); for (i = 0; i < get_topo_max_cpus(); ++i) { - if (pkg_id != get_physical_package_id(i) || - die_id != get_physical_die_id(i)) + if (!is_cpu_in_power_domain(i, id)) continue; + adjust_scaling_max_from_base_freq(i); set_cpufreq_scaling_min_max_from_cpuinfo(i, 1, 0); + adjust_scaling_min_from_base_freq(i); } } -static void set_scaling_min_to_cpuinfo_min(int cpu) +static void set_scaling_min_to_cpuinfo_min(struct isst_id *id) { - int i, pkg_id, die_id; + int i; - pkg_id = get_physical_package_id(cpu); - die_id = get_physical_die_id(cpu); for (i = 0; i < get_topo_max_cpus(); ++i) { - if (pkg_id != get_physical_package_id(i) || - die_id != get_physical_die_id(i)) + if (!is_cpu_in_power_domain(i, id)) continue; + adjust_scaling_max_from_base_freq(i); set_cpufreq_scaling_min_max_from_cpuinfo(i, 0, 0); } } -static void set_scaling_max_to_cpuinfo_max(int cpu) +static void set_scaling_max_to_cpuinfo_max(struct isst_id *id) { - int i, pkg_id, die_id; + int i; - pkg_id = get_physical_package_id(cpu); - die_id = get_physical_die_id(cpu); for (i = 0; i < get_topo_max_cpus(); ++i) { - if (pkg_id != get_physical_package_id(i) || - die_id != get_physical_die_id(i)) + if (!is_cpu_in_power_domain(i, id)) continue; set_cpufreq_scaling_min_max_from_cpuinfo(i, 1, 1); } } -static int set_core_priority_and_min(int cpu, int mask_size, +static int set_core_priority_and_min(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int min_high, int min_low) { - int pkg_id, die_id, ret, i; + int ret, i; if (!CPU_COUNT_S(mask_size, cpu_mask)) return -1; - ret = set_clos_param(cpu, 0, 0, 0, min_high, 0xff); + ret = set_clos_param(id, 0, 0, 0, min_high, 0xff); if (ret) return ret; - ret = set_clos_param(cpu, 1, 15, 15, min_low, 0xff); + ret = set_clos_param(id, 1, 15, 15, min_low, 0xff); if (ret) return ret; - ret = set_clos_param(cpu, 2, 15, 15, min_low, 0xff); + ret = set_clos_param(id, 2, 15, 15, min_low, 0xff); if (ret) return ret; - ret = set_clos_param(cpu, 3, 15, 15, min_low, 0xff); + ret = set_clos_param(id, 3, 15, 15, min_low, 0xff); if (ret) return ret; - pkg_id = get_physical_package_id(cpu); - die_id = get_physical_die_id(cpu); for (i = 0; i < get_topo_max_cpus(); ++i) { int clos; + struct isst_id tid; - if (pkg_id != get_physical_package_id(i) || - die_id != get_physical_die_id(i)) + if (!is_cpu_in_power_domain(i, id)) continue; if (CPU_ISSET_S(i, mask_size, cpu_mask)) @@ -1314,9 +1671,10 @@ static int set_core_priority_and_min(int cpu, int mask_size, clos = 3; debug_printf("Associate cpu: %d clos: %d\n", i, clos); - ret = isst_clos_associate(i, clos); + set_isst_id(&tid, i); + ret = isst_clos_associate(&tid, clos); if (ret) { - perror("isst_clos_associate"); + isst_display_error_info_message(1, "isst_clos_associate failed", 0, 0); return ret; } } @@ -1324,95 +1682,111 @@ static int set_core_priority_and_min(int cpu, int mask_size, return 0; } -static int set_pbf_core_power(int cpu) +static int set_pbf_core_power(struct isst_id *id) { struct isst_pbf_info pbf_info; struct isst_pkg_ctdp pkg_dev; int ret; - ret = isst_get_ctdp_levels(cpu, &pkg_dev); + ret = isst_get_ctdp_levels(id, &pkg_dev); if (ret) { - perror("isst_get_ctdp_levels"); + debug_printf("isst_get_ctdp_levels failed"); return ret; } debug_printf("Current_level: %d\n", pkg_dev.current_level); - ret = isst_get_pbf_info(cpu, pkg_dev.current_level, &pbf_info); + ret = isst_get_pbf_info(id, pkg_dev.current_level, &pbf_info); if (ret) { - perror("isst_get_pbf_info"); + debug_printf("isst_get_pbf_info failed"); return ret; } debug_printf("p1_high: %d p1_low: %d\n", pbf_info.p1_high, pbf_info.p1_low); - ret = set_core_priority_and_min(cpu, pbf_info.core_cpumask_size, + ret = set_core_priority_and_min(id, pbf_info.core_cpumask_size, pbf_info.core_cpumask, pbf_info.p1_high, pbf_info.p1_low); if (ret) { - perror("set_core_priority_and_min"); + debug_printf("set_core_priority_and_min failed"); return ret; } - ret = isst_pm_qos_config(cpu, 1, 1); + ret = isst_pm_qos_config(id, 1, 1); if (ret) { - perror("isst_pm_qos_config"); + debug_printf("isst_pm_qos_config failed"); return ret; } return 0; } -static void set_pbf_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, +static void set_pbf_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, void *arg4) { + struct isst_pkg_ctdp_level_info ctdp_level; + struct isst_pkg_ctdp pkg_dev; int ret; int status = *(int *)arg4; if (is_clx_n_platform()) { + ret = 0; if (status) { - ret = 0; - if (auto_mode) - set_clx_pbf_cpufreq_scaling_min_max(cpu); + set_clx_pbf_cpufreq_scaling_min_max(id); } else { - ret = -1; - if (auto_mode) { - set_scaling_max_to_cpuinfo_max(cpu); - set_scaling_min_to_cpuinfo_min(cpu); - } + set_scaling_max_to_cpuinfo_max(id); + set_scaling_min_to_cpuinfo_min(id); } goto disp_result; } + ret = isst_get_ctdp_levels(id, &pkg_dev); + if (ret) { + isst_display_error_info_message(1, "Failed to get number of levels", 0, 0); + goto disp_result; + } + + ret = isst_get_ctdp_control(id, pkg_dev.current_level, &ctdp_level); + if (ret) { + isst_display_error_info_message(1, "Failed to get current level", 0, 0); + goto disp_result; + } + + if (!ctdp_level.pbf_support) { + isst_display_error_info_message(1, "base-freq feature is not present at this level", 1, pkg_dev.current_level); + ret = -1; + goto disp_result; + } + if (auto_mode && status) { - ret = set_pbf_core_power(cpu); + ret = set_pbf_core_power(id); if (ret) goto disp_result; } - ret = isst_set_pbf_fact_status(cpu, 1, status); + ret = isst_set_pbf_fact_status(id, 1, status); if (ret) { - perror("isst_set_pbf"); + debug_printf("isst_set_pbf_fact_status failed"); if (auto_mode) - isst_pm_qos_config(cpu, 0, 0); + isst_pm_qos_config(id, 0, 0); } else { if (auto_mode) { if (status) - set_scaling_min_to_cpuinfo_max(cpu); + set_scaling_min_to_cpuinfo_max(id); else - set_scaling_min_to_cpuinfo_min(cpu); + set_scaling_min_to_cpuinfo_min(id); } } if (auto_mode && !status) - isst_pm_qos_config(cpu, 0, 0); + isst_pm_qos_config(id, 0, 1); disp_result: if (status) - isst_display_result(cpu, outf, "base-freq", "enable", + isst_display_result(id, outf, "base-freq", "enable", ret); else - isst_display_result(cpu, outf, "base-freq", "disable", + isst_display_result(id, outf, "base-freq", "disable", ret); } @@ -1424,10 +1798,25 @@ static void set_pbf_enable(int arg) if (enable) { fprintf(stderr, "Enable Intel Speed Select Technology base frequency feature\n"); + if (is_clx_n_platform()) { + fprintf(stderr, + "\tOn this platform this command doesn't enable feature in the hardware.\n"); + fprintf(stderr, + "\tIt updates the cpufreq scaling_min_freq to match cpufreq base_frequency.\n"); + exit(0); + + } fprintf(stderr, "\tOptional Arguments: -a|--auto : Use priority of cores to set core-power associations\n"); } else { + if (is_clx_n_platform()) { + fprintf(stderr, + "\tOn this platform this command doesn't disable feature in the hardware.\n"); + fprintf(stderr, + "\tIt updates the cpufreq scaling_min_freq to match cpuinfo_min_freq\n"); + exit(0); + } fprintf(stderr, "Disable Intel Speed Select Technology base frequency feature\n"); fprintf(stderr, @@ -1446,18 +1835,21 @@ static void set_pbf_enable(int arg) isst_ctdp_display_information_end(outf); } -static void dump_fact_config_for_cpu(int cpu, void *arg1, void *arg2, +static void dump_fact_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, void *arg4) { struct isst_fact_info fact_info; int ret; - ret = isst_get_fact_info(cpu, tdp_level, &fact_info); - if (ret) - perror("isst_get_fact_bucket_info"); - else - isst_fact_display_information(cpu, outf, tdp_level, fact_bucket, + ret = isst_get_fact_info(id, tdp_level, fact_bucket, &fact_info); + if (ret) { + isst_display_error_info_message(1, "Failed to get turbo-freq info at this level", 1, tdp_level); + isst_ctdp_display_information_end(outf); + exit(1); + } else { + isst_fact_display_information(id, outf, tdp_level, fact_bucket, fact_avx, &fact_info); + } } static void dump_fact_config(int arg) @@ -1475,7 +1867,7 @@ static void dump_fact_config(int arg) } if (tdp_level == 0xff) { - fprintf(outf, "Invalid command: specify tdp_level\n"); + isst_display_error_info_message(1, "Invalid command: specify tdp_level\n", 0, 0); exit(1); } @@ -1489,23 +1881,49 @@ static void dump_fact_config(int arg) isst_ctdp_display_information_end(outf); } -static void set_fact_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, +static void set_fact_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, void *arg4) { + struct isst_pkg_ctdp_level_info ctdp_level; + struct isst_pkg_ctdp pkg_dev; int ret; int status = *(int *)arg4; - if (auto_mode && status) { - ret = isst_pm_qos_config(cpu, 1, 1); + if (status && no_turbo()) { + isst_display_error_info_message(1, "Turbo mode is disabled", 0, 0); + ret = -1; + goto disp_results; + } + + ret = isst_get_ctdp_levels(id, &pkg_dev); + if (ret) { + isst_display_error_info_message(1, "Failed to get number of levels", 0, 0); + goto disp_results; + } + + ret = isst_get_ctdp_control(id, pkg_dev.current_level, &ctdp_level); + if (ret) { + isst_display_error_info_message(1, "Failed to get current level", 0, 0); + goto disp_results; + } + + if (!ctdp_level.fact_support) { + isst_display_error_info_message(1, "turbo-freq feature is not present at this level", 1, pkg_dev.current_level); + ret = -1; + goto disp_results; + } + + if (status) { + ret = isst_pm_qos_config(id, 1, 1); if (ret) goto disp_results; } - ret = isst_set_pbf_fact_status(cpu, 0, status); + ret = isst_set_pbf_fact_status(id, 0, status); if (ret) { - perror("isst_set_fact"); + debug_printf("isst_set_pbf_fact_status failed"); if (auto_mode) - isst_pm_qos_config(cpu, 0, 0); + isst_pm_qos_config(id, 0, 0); goto disp_results; } @@ -1514,29 +1932,32 @@ static void set_fact_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, if (status) { struct isst_pkg_ctdp pkg_dev; - ret = isst_get_ctdp_levels(cpu, &pkg_dev); + ret = isst_get_ctdp_levels(id, &pkg_dev); if (!ret) - ret = isst_set_trl(cpu, fact_trl); + ret = isst_set_trl(id, fact_trl); if (ret && auto_mode) - isst_pm_qos_config(cpu, 0, 0); + isst_pm_qos_config(id, 0, 0); } else { if (auto_mode) - isst_pm_qos_config(cpu, 0, 0); + isst_pm_qos_config(id, 0, 0); } disp_results: if (status) { - isst_display_result(cpu, outf, "turbo-freq", "enable", ret); + isst_display_result(id, outf, "turbo-freq", "enable", ret); + if (ret) + fact_enable_fail = ret; } else { /* Since we modified TRL during Fact enable, restore it */ - isst_set_trl_from_current_tdp(cpu, fact_trl); - isst_display_result(cpu, outf, "turbo-freq", "disable", ret); + isst_set_trl_from_current_tdp(id, fact_trl); + isst_display_result(id, outf, "turbo-freq", "disable", ret); } } static void set_fact_enable(int arg) { int i, ret, enable = arg; + struct isst_id id; if (cmd_help) { if (enable) { @@ -1568,7 +1989,7 @@ static void set_fact_enable(int arg) NULL, &enable); isst_ctdp_display_information_end(outf); - if (enable && auto_mode) { + if (!fact_enable_fail && enable && auto_mode) { /* * When we adjust CLOS param, we have to set for siblings also. * So for the each user specified CPU, also add the sibling @@ -1610,19 +2031,20 @@ static void set_fact_enable(int arg) if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask)) continue; - ret = set_clos_param(i, 0, 0, 0, 0, 0xff); + set_isst_id(&id, i); + ret = set_clos_param(&id, 0, 0, 0, 0, 0xff); if (ret) goto error_disp; - ret = set_clos_param(i, 1, 15, 15, 0, 0xff); + ret = set_clos_param(&id, 1, 15, 15, 0, 0xff); if (ret) goto error_disp; - ret = set_clos_param(i, 2, 15, 15, 0, 0xff); + ret = set_clos_param(&id, 2, 15, 15, 0, 0xff); if (ret) goto error_disp; - ret = set_clos_param(i, 3, 15, 15, 0, 0xff); + ret = set_clos_param(&id, 3, 15, 15, 0, 0xff); if (ret) goto error_disp; @@ -1632,35 +2054,39 @@ static void set_fact_enable(int arg) clos = 3; debug_printf("Associate cpu: %d clos: %d\n", i, clos); - ret = isst_clos_associate(i, clos); + ret = isst_clos_associate(&id, clos); if (ret) goto error_disp; } - isst_display_result(-1, outf, "turbo-freq --auto", "enable", 0); + set_isst_id(&id, -1); + isst_display_result(&id, outf, "turbo-freq --auto", "enable", 0); } return; error_disp: - isst_display_result(i, outf, "turbo-freq --auto", "enable", ret); + isst_display_result(&id, outf, "turbo-freq --auto", "enable", ret); } -static void enable_clos_qos_config(int cpu, void *arg1, void *arg2, void *arg3, +static void enable_clos_qos_config(struct isst_id *id, void *arg1, void *arg2, void *arg3, void *arg4) { int ret; int status = *(int *)arg4; - ret = isst_pm_qos_config(cpu, status, clos_priority_type); + if (is_skx_based_platform()) + clos_priority_type = 1; + + ret = isst_pm_qos_config(id, status, clos_priority_type); if (ret) - perror("isst_pm_qos_config"); + isst_display_error_info_message(1, "isst_pm_qos_config failed", 0, 0); if (status) - isst_display_result(cpu, outf, "core-power", "enable", + isst_display_result(id, outf, "core-power", "enable", ret); else - isst_display_result(cpu, outf, "core-power", "disable", + isst_display_result(id, outf, "core-power", "disable", ret); } @@ -1672,9 +2098,11 @@ static void set_clos_enable(int arg) if (enable) { fprintf(stderr, "Enable core-power for a package/die\n"); - fprintf(stderr, - "\tClos Enable: Specify priority type with [--priority|-p]\n"); - fprintf(stderr, "\t\t 0: Proportional, 1: Ordered\n"); + if (!is_skx_based_platform()) { + fprintf(stderr, + "\tClos Enable: Specify priority type with [--priority|-p]\n"); + fprintf(stderr, "\t\t 0: Proportional, 1: Ordered\n"); + } } else { fprintf(stderr, "Disable core-power: [No command arguments are required]\n"); @@ -1697,17 +2125,17 @@ static void set_clos_enable(int arg) isst_ctdp_display_information_end(outf); } -static void dump_clos_config_for_cpu(int cpu, void *arg1, void *arg2, +static void dump_clos_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, void *arg4) { struct isst_clos_config clos_config; int ret; - ret = isst_pm_get_clos(cpu, current_clos, &clos_config); + ret = isst_pm_get_clos(id, current_clos, &clos_config); if (ret) - perror("isst_pm_get_clos"); + isst_display_error_info_message(1, "isst_pm_get_clos failed", 0, 0); else - isst_clos_display_information(cpu, outf, current_clos, + isst_clos_display_information(id, outf, current_clos, &clos_config); } @@ -1721,7 +2149,8 @@ static void dump_clos_config(int arg) exit(0); } if (current_clos < 0 || current_clos > 3) { - fprintf(stderr, "Invalid clos id\n"); + isst_display_error_info_message(1, "Invalid clos id\n", 0, 0); + isst_ctdp_display_information_end(outf); exit(0); } @@ -1735,16 +2164,21 @@ static void dump_clos_config(int arg) isst_ctdp_display_information_end(outf); } -static void get_clos_info_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, +static void get_clos_info_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, void *arg4) { int enable, ret, prio_type; - ret = isst_clos_get_clos_information(cpu, &enable, &prio_type); + ret = isst_clos_get_clos_information(id, &enable, &prio_type); if (ret) - perror("isst_clos_get_info"); - else - isst_clos_display_clos_information(cpu, outf, enable, prio_type); + isst_display_error_info_message(1, "isst_clos_get_info failed", 0, 0); + else { + int cp_state, cp_cap; + + isst_read_pm_config(id, &cp_state, &cp_cap); + isst_clos_display_clos_information(id, outf, enable, prio_type, + cp_state, cp_cap); + } } static void dump_clos_info(int arg) @@ -1752,42 +2186,37 @@ static void dump_clos_info(int arg) if (cmd_help) { fprintf(stderr, "Print Intel Speed Select Technology core power information\n"); - fprintf(stderr, "\tSpecify targeted cpu id with [--cpu|-c]\n"); - exit(0); - } - - if (!max_target_cpus) { - fprintf(stderr, - "Invalid target cpu. Specify with [-c|--cpu]\n"); + fprintf(stderr, "\t Optionally specify targeted cpu id with [--cpu|-c]\n"); exit(0); } isst_ctdp_display_information_start(outf); - for_each_online_target_cpu_in_set(get_clos_info_for_cpu, NULL, - NULL, NULL, NULL); + if (max_target_cpus) + 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, + NULL, NULL, NULL); isst_ctdp_display_information_end(outf); } -static void set_clos_config_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, +static void set_clos_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, void *arg4) { struct isst_clos_config clos_config; int ret; - clos_config.pkg_id = get_physical_package_id(cpu); - clos_config.die_id = get_physical_die_id(cpu); - clos_config.epp = clos_epp; clos_config.clos_prop_prio = clos_prop_prio; clos_config.clos_min = clos_min; clos_config.clos_max = clos_max; clos_config.clos_desired = clos_desired; - ret = isst_set_clos(cpu, current_clos, &clos_config); + ret = isst_set_clos(id, current_clos, &clos_config); if (ret) - perror("isst_set_clos"); + isst_display_error_info_message(1, "isst_set_clos failed", 0, 0); else - isst_display_result(cpu, outf, "core-power", "config", ret); + isst_display_result(id, outf, "core-power", "config", ret); } static void set_clos_config(int arg) @@ -1797,26 +2226,27 @@ static void set_clos_config(int arg) "Set core-power configuration for one of the four clos ids\n"); fprintf(stderr, "\tSpecify targeted clos id with [--clos|-c]\n"); - fprintf(stderr, "\tSpecify clos EPP with [--epp|-e]\n"); - fprintf(stderr, - "\tSpecify clos Proportional Priority [--weight|-w]\n"); + if (!is_skx_based_platform()) { + fprintf(stderr, "\tSpecify clos EPP with [--epp|-e]\n"); + fprintf(stderr, + "\tSpecify clos Proportional Priority [--weight|-w]\n"); + } fprintf(stderr, "\tSpecify clos min in MHz with [--min|-n]\n"); fprintf(stderr, "\tSpecify clos max in MHz with [--max|-m]\n"); - fprintf(stderr, "\tSpecify clos desired in MHz with [--desired|-d]\n"); exit(0); } if (current_clos < 0 || current_clos > 3) { - fprintf(stderr, "Invalid clos id\n"); + isst_display_error_info_message(1, "Invalid clos id\n", 0, 0); exit(0); } - if (clos_epp < 0 || clos_epp > 0x0F) { - fprintf(stderr, "clos epp is not specified, default: 0\n"); + if (!is_skx_based_platform() && (clos_epp < 0 || clos_epp > 0x0F)) { + fprintf(stderr, "clos epp is not specified or invalid, default: 0\n"); clos_epp = 0; } - if (clos_prop_prio < 0 || clos_prop_prio > 0x0F) { + if (!is_skx_based_platform() && (clos_prop_prio < 0 || clos_prop_prio > 0x0F)) { fprintf(stderr, - "clos frequency weight is not specified, default: 0\n"); + "clos frequency weight is not specified or invalid, default: 0\n"); clos_prop_prio = 0; } if (clos_min < 0) { @@ -1824,11 +2254,11 @@ static void set_clos_config(int arg) clos_min = 0; } if (clos_max < 0) { - fprintf(stderr, "clos max is not specified, default: 25500 MHz\n"); + fprintf(stderr, "clos max is not specified, default: Max frequency (ratio 0xff)\n"); clos_max = 0xff; } - if (clos_desired < 0) { - fprintf(stderr, "clos desired is not specified, default: 0\n"); + if (clos_desired) { + fprintf(stderr, "clos desired is not supported on this platform\n"); clos_desired = 0x00; } @@ -1842,16 +2272,16 @@ static void set_clos_config(int arg) isst_ctdp_display_information_end(outf); } -static void set_clos_assoc_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, +static void set_clos_assoc_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, void *arg4) { int ret; - ret = isst_clos_associate(cpu, current_clos); + ret = isst_clos_associate(id, current_clos); if (ret) - perror("isst_clos_associate"); + debug_printf("isst_clos_associate failed"); else - isst_display_result(cpu, outf, "core-power", "assoc", ret); + isst_display_result(id, outf, "core-power", "assoc", ret); } static void set_clos_assoc(int arg) @@ -1860,32 +2290,35 @@ static void set_clos_assoc(int arg) fprintf(stderr, "Associate a clos id to a CPU\n"); fprintf(stderr, "\tSpecify targeted clos id with [--clos|-c]\n"); + fprintf(stderr, + "\tFor example to associate clos 1 to CPU 0: issue\n"); + fprintf(stderr, + "\tintel-speed-select --cpu 0 core-power assoc --clos 1\n"); exit(0); } if (current_clos < 0 || current_clos > 3) { - fprintf(stderr, "Invalid clos id\n"); + isst_display_error_info_message(1, "Invalid clos id\n", 0, 0); exit(0); } if (max_target_cpus) for_each_online_target_cpu_in_set(set_clos_assoc_for_cpu, NULL, NULL, NULL, NULL); else { - fprintf(stderr, - "Invalid target cpu. Specify with [-c|--cpu]\n"); + isst_display_error_info_message(1, "Invalid target cpu. Specify with [-c|--cpu]", 0, 0); } } -static void get_clos_assoc_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, +static void get_clos_assoc_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, void *arg4) { int clos, ret; - ret = isst_clos_get_assoc_status(cpu, &clos); + ret = isst_clos_get_assoc_status(id, &clos); if (ret) - perror("isst_clos_get_assoc_status"); + isst_display_error_info_message(1, "isst_clos_get_assoc_status failed", 0, 0); else - isst_clos_display_assoc_information(cpu, outf, clos); + isst_clos_display_assoc_information(id, outf, clos); } static void get_clos_assoc(int arg) @@ -1897,8 +2330,7 @@ static void get_clos_assoc(int arg) } if (!max_target_cpus) { - fprintf(stderr, - "Invalid target cpu. Specify with [-c|--cpu]\n"); + isst_display_error_info_message(1, "Invalid target cpu. Specify with [-c|--cpu]", 0, 0); exit(0); } @@ -1908,6 +2340,105 @@ static void get_clos_assoc(int arg) isst_ctdp_display_information_end(outf); } +static void set_turbo_mode_for_cpu(struct isst_id *id, int status) +{ + int base_freq; + + if (status) { + base_freq = get_cpufreq_base_freq(id->cpu); + set_cpufreq_scaling_min_max(id->cpu, 1, base_freq); + } else { + set_scaling_max_to_cpuinfo_max(id); + } + + if (status) { + isst_display_result(id, outf, "turbo-mode", "enable", 0); + } else { + isst_display_result(id, outf, "turbo-mode", "disable", 0); + } +} + +static void set_turbo_mode(int arg) +{ + int i, enable = arg; + struct isst_id id; + + if (cmd_help) { + if (enable) + fprintf(stderr, "Set turbo mode enable\n"); + else + fprintf(stderr, "Set turbo mode disable\n"); + exit(0); + } + + isst_ctdp_display_information_start(outf); + + for (i = 0; i < topo_max_cpus; ++i) { + int online; + + 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 */ + + if (online) { + set_isst_id(&id, i); + set_turbo_mode_for_cpu(&id, enable); + } + + } + isst_ctdp_display_information_end(outf); +} + +static void get_set_trl(struct isst_id *id, void *arg1, void *arg2, void *arg3, + void *arg4) +{ + unsigned long long trl; + int set = *(int *)arg4; + int ret; + + if (set && !fact_trl) { + isst_display_error_info_message(1, "Invalid TRL. Specify with [-t|--trl]", 0, 0); + exit(0); + } + + if (set) { + ret = isst_set_trl(id, fact_trl); + isst_display_result(id, outf, "turbo-mode", "set-trl", ret); + return; + } + + ret = isst_get_trl(id, &trl); + if (ret) + isst_display_result(id, outf, "turbo-mode", "get-trl", ret); + else + isst_trl_display_information(id, outf, trl); +} + +static void process_trl(int arg) +{ + if (cmd_help) { + if (arg) { + fprintf(stderr, "Set TRL (turbo ratio limits)\n"); + fprintf(stderr, "\t t|--trl: Specify turbo ratio limit for setting TRL\n"); + } else { + fprintf(stderr, "Get TRL (turbo ratio limits)\n"); + } + exit(0); + } + + isst_ctdp_display_information_start(outf); + if (max_target_cpus) + 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, + NULL, NULL, &arg); + isst_ctdp_display_information_end(outf); +} + static struct process_cmd_struct clx_n_cmds[] = { { "perf-profile", "info", dump_isst_config, 0 }, { "base-freq", "info", dump_pbf_config, 0 }, @@ -1938,6 +2469,10 @@ static struct process_cmd_struct isst_cmds[] = { { "core-power", "get-config", dump_clos_config, 0 }, { "core-power", "assoc", set_clos_assoc, 0 }, { "core-power", "get-assoc", get_clos_assoc, 0 }, + { "turbo-mode", "enable", set_turbo_mode, 0 }, + { "turbo-mode", "disable", set_turbo_mode, 1 }, + { "turbo-mode", "get-trl", process_trl, 0 }, + { "turbo-mode", "set-trl", process_trl, 1 }, { NULL, NULL, NULL } }; @@ -2035,7 +2570,7 @@ static void parse_cmd_args(int argc, int start, char **argv) option_index = start; optind = start + 1; - while ((opt = getopt_long(argc, argv, "b:l:t:c:d:e:n:m:p:w:hoa", + while ((opt = getopt_long(argc, argv, "b:l:t:c:d:e:n:m:p:w:r:hoa", long_options, &option_index)) != -1) { switch (opt) { case 'a': @@ -2061,7 +2596,7 @@ static void parse_cmd_args(int argc, int start, char **argv) fact_avx = 0x01; } else if (!strncmp(optarg, "avx2", 4)) { fact_avx = 0x02; - } else if (!strncmp(optarg, "avx512", 4)) { + } else if (!strncmp(optarg, "avx512", 6)) { fact_avx = 0x04; } else { fprintf(outf, "Invalid sse,avx options\n"); @@ -2078,6 +2613,10 @@ static void parse_cmd_args(int argc, int start, char **argv) break; case 'e': clos_epp = atoi(optarg); + if (is_skx_based_platform()) { + isst_display_error_info_message(1, "epp can't be specified on this platform", 0, 0); + exit(0); + } break; case 'n': clos_min = atoi(optarg); @@ -2089,14 +2628,25 @@ static void parse_cmd_args(int argc, int start, char **argv) break; case 'p': clos_priority_type = atoi(optarg); + if (is_skx_based_platform() && !clos_priority_type) { + isst_display_error_info_message(1, "Invalid clos priority type: proportional for this platform", 0, 0); + exit(0); + } break; case 'w': clos_prop_prio = atoi(optarg); + if (is_skx_based_platform()) { + isst_display_error_info_message(1, "weight can't be specified on this platform", 0, 0); + exit(0); + } break; default: - printf("no match\n"); + printf("Unknown option: ignore\n"); } } + + if (argv[optind]) + printf("Garbage at the end of command: ignore\n"); } static void isst_help(void) @@ -2138,6 +2688,16 @@ static void fact_help(void) printf("\tcommand : disable\n"); } +static void turbo_mode_help(void) +{ + printf("turbo-mode:\tEnables users to enable/disable turbo mode by adjusting frequency settings. Also allows to get and set turbo ratio limits (TRL).\n"); + printf("\tcommand : enable\n"); + printf("\tcommand : disable\n"); + printf("\tcommand : get-trl\n"); + printf("\tcommand : set-trl\n"); +} + + static void core_power_help(void) { printf("core-power:\tInterface that allows user to define per core/tile\n\ @@ -2162,6 +2722,7 @@ static struct process_cmd_help_struct isst_help_cmds[] = { { "base-freq", pbf_help }, { "turbo-freq", fact_help }, { "core-power", core_power_help }, + { "turbo-mode", turbo_mode_help }, { NULL, NULL } }; @@ -2193,9 +2754,6 @@ void process_command(int argc, char **argv, } } - if (!is_clx_n_platform()) - create_cpu_map(); - i = 0; while (cmds[i].feature) { if (!strcmp(cmds[i].feature, feature) && @@ -2214,11 +2772,18 @@ void process_command(int argc, char **argv, static void usage(void) { - printf("Intel(R) Speed Select Technology\n"); + if (is_clx_n_platform()) { + fprintf(stderr, "\nThere is limited support of Intel Speed Select features on this platform.\n"); + fprintf(stderr, "Everything is pre-configured using BIOS options, this tool can't enable any feature in the hardware.\n\n"); + } + printf("\nUsage:\n"); printf("intel-speed-select [OPTIONS] FEATURE COMMAND COMMAND_ARGUMENTS\n"); - printf("\nUse this tool to enumerate and control the Intel Speed Select Technology features,\n"); - printf("\nFEATURE : [perf-profile|base-freq|turbo-freq|core-power]\n"); + printf("\nUse this tool to enumerate and control the Intel Speed Select Technology features:\n"); + if (is_clx_n_platform()) + printf("\nFEATURE : [perf-profile|base-freq]\n"); + else + printf("\nFEATURE : [perf-profile|base-freq|turbo-freq|core-power|turbo-mode]\n"); printf("\nFor help on each feature, use -h|--help\n"); printf("\tFor example: intel-speed-select perf-profile -h\n"); @@ -2231,48 +2796,101 @@ static void usage(void) printf("\t\tDefault: Die scoped for all dies in the system with multiple dies/package\n"); printf("\t\t\t Or Package scoped for all Packages when each package contains one die\n"); printf("\t[-d|--debug] : Debug mode\n"); + printf("\t[-f|--format] : output format [json|text]. Default: text\n"); printf("\t[-h|--help] : Print help\n"); printf("\t[-i|--info] : Print platform information\n"); + printf("\t[-a|--all-cpus-online] : Force online every CPU in the system\n"); printf("\t[-o|--out] : Output file\n"); printf("\t\t\tDefault : stderr\n"); - printf("\t[-f|--format] : output format [json|text]. Default: text\n"); + printf("\t[-p|--pause] : Delay between two mail box commands in milliseconds\n"); + printf("\t[-r|--retry] : Retry count for mail box commands on failure, default 3\n"); printf("\t[-v|--version] : Print version\n"); - + 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("\nResult format\n"); printf("\tResult display uses a common format for each command:\n"); printf("\tResults are formatted in text/JSON with\n"); printf("\t\tPackage, Die, CPU, and command specific results.\n"); + + printf("\nExamples\n"); + printf("\tTo get platform information:\n"); + printf("\t\tintel-speed-select --info\n"); + printf("\tTo get full perf-profile information dump:\n"); + printf("\t\tintel-speed-select perf-profile info\n"); + printf("\tTo get full base-freq information dump:\n"); + printf("\t\tintel-speed-select base-freq info -l 0\n"); + if (!is_clx_n_platform()) { + printf("\tTo get full turbo-freq information dump:\n"); + printf("\t\tintel-speed-select turbo-freq info -l 0\n"); + } exit(1); } static void print_version(void) { fprintf(outf, "Version %s\n", version_str); - fprintf(outf, "Build date %s time %s\n", __DATE__, __TIME__); exit(0); } static void cmdline(int argc, char **argv) { - int opt; + const char *pathname = "/dev/isst_interface"; + char *ptr; + FILE *fp; + int opt, force_cpus_online = 0; int option_index = 0; int ret; + int oob_mode = 0; + int poll_interval = -1; + int no_daemon = 0; static struct option long_options[] = { + { "all-cpus-online", no_argument, 0, 'a' }, { "cpu", required_argument, 0, 'c' }, { "debug", no_argument, 0, 'd' }, { "format", required_argument, 0, 'f' }, { "help", no_argument, 0, 'h' }, { "info", no_argument, 0, 'i' }, + { "pause", required_argument, 0, 'p' }, { "out", required_argument, 0, 'o' }, + { "retry", required_argument, 0, 'r' }, { "version", no_argument, 0, 'v' }, + { "oob", no_argument, 0, 'b' }, + { "no-daemon", no_argument, 0, 'n' }, + { "poll-interval", required_argument, 0, 'w' }, { 0, 0, 0, 0 } }; + if (geteuid() != 0) { + fprintf(stderr, "Must run as root\n"); + exit(0); + } + + ret = update_cpu_model(); + if (ret) + err(-1, "Invalid CPU model (%d)\n", cpu_model); + printf("Intel(R) Speed Select Technology\n"); + printf("Executing on CPU model:%d[0x%x]\n", cpu_model, cpu_model); + + if (!is_clx_n_platform()) { + fp = fopen(pathname, "rb"); + if (!fp) { + fprintf(stderr, "Intel speed select drivers are not loaded on this system.\n"); + fprintf(stderr, "Verify that kernel config includes CONFIG_INTEL_SPEED_SELECT_INTERFACE.\n"); + fprintf(stderr, "If the config is included then this is not a supported platform.\n"); + exit(0); + } + fclose(fp); + } + progname = argv[0]; - while ((opt = getopt_long_only(argc, argv, "+c:df:hio:v", long_options, + while ((opt = getopt_long_only(argc, argv, "+c:df:hio:vabw:n", long_options, &option_index)) != -1) { switch (opt) { + case 'a': + force_cpus_online = 1; + break; case 'c': parse_cpu_command(optarg); break; @@ -2295,31 +2913,61 @@ static void cmdline(int argc, char **argv) fclose(outf); outf = fopen_or_exit(optarg, "w"); break; + case 'p': + ret = strtol(optarg, &ptr, 10); + if (!ret) + fprintf(stderr, "Invalid pause interval, ignore\n"); + else + mbox_delay = ret; + break; + case 'r': + ret = strtol(optarg, &ptr, 10); + if (!ret) + fprintf(stderr, "Invalid retry count, ignore\n"); + else + mbox_retries = ret; + break; case 'v': print_version(); break; + case 'b': + oob_mode = 1; + break; + case 'n': + no_daemon = 1; + break; + case 'w': + ret = strtol(optarg, &ptr, 10); + if (!ret) { + fprintf(stderr, "Invalid poll interval count\n"); + exit(0); + } + poll_interval = ret; + break; default: usage(); } } - if (geteuid() != 0) { - fprintf(stderr, "Must run as root\n"); + if (optind > (argc - 2) && !oob_mode) { + usage(); exit(0); } + set_max_cpu_num(); + if (force_cpus_online) + force_all_cpus_online(); + store_cpu_topology(); + create_cpu_map(); - if (optind > (argc - 2)) { - fprintf(stderr, "Feature name and|or command not specified\n"); - exit(0); + if (oob_mode) { + if (debug_flag) + fprintf(stderr, "OOB mode is enabled in debug mode\n"); + + ret = isst_daemon(debug_flag, poll_interval, no_daemon); + if (ret) + fprintf(stderr, "OOB mode enable failed\n"); + goto out; } - ret = update_cpu_model(); - if (ret) - err(-1, "Invalid CPU model (%d)\n", cpu_model); - printf("Intel(R) Speed Select Technology\n"); - printf("Executing on CPU model:%d[0x%x]\n", cpu_model, cpu_model); - set_max_cpu_num(); - set_cpu_present_cpu_mask(); - set_cpu_target_cpu_mask(); if (!is_clx_n_platform()) { ret = isst_fill_platform_info(); |