diff --git a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c index 1f0774fef26f7..89161ccf3f1a2 100644 --- a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c +++ b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c @@ -35,7 +35,7 @@ /* Supported SST hardware version by this driver */ #define ISST_MAJOR_VERSION 0 -#define ISST_MINOR_VERSION 1 +#define ISST_MINOR_VERSION 2 /* * Used to indicate if value read from MMIO needs to get multiplied @@ -381,7 +381,7 @@ static int sst_main(struct auxiliary_device *auxdev, struct tpmi_per_power_domai return -ENODEV; } - if (TPMI_MINOR_VERSION(pd_info->sst_header.interface_version) != ISST_MINOR_VERSION) + if (TPMI_MINOR_VERSION(pd_info->sst_header.interface_version) > ISST_MINOR_VERSION) dev_info(dev, "SST: Ignore: Unsupported minor version:%lx\n", TPMI_MINOR_VERSION(pd_info->sst_header.interface_version)); @@ -1017,6 +1017,7 @@ static int isst_if_set_perf_feature(void __user *argp) #define SST_PP_INFO_10_OFFSET 80 #define SST_PP_INFO_11_OFFSET 88 +#define SST_PP_INFO_12_OFFSET 96 #define SST_PP_P1_SSE_START 0 #define SST_PP_P1_SSE_WIDTH 8 @@ -1069,6 +1070,15 @@ static int isst_if_set_perf_feature(void __user *argp) #define SST_PP_CORE_RATIO_PM_FABRIC_START 48 #define SST_PP_CORE_RATIO_PM_FABRIC_WIDTH 8 +#define SST_PP_CORE_RATIO_P0_FABRIC_1_START 0 +#define SST_PP_CORE_RATIO_P0_FABRIC_1_WIDTH 8 + +#define SST_PP_CORE_RATIO_P1_FABRIC_1_START 8 +#define SST_PP_CORE_RATIO_P1_FABRIC_1_WIDTH 8 + +#define SST_PP_CORE_RATIO_PM_FABRIC_1_START 16 +#define SST_PP_CORE_RATIO_PM_FABRIC_1_WIDTH 8 + static int isst_if_get_perf_level_info(void __user *argp) { struct isst_perf_level_data_info perf_level; @@ -1168,6 +1178,59 @@ static int isst_if_get_perf_level_info(void __user *argp) return 0; } +static int isst_if_get_perf_level_fabric_info(void __user *argp) +{ + struct isst_perf_level_fabric_info perf_level_fabric; + struct tpmi_per_power_domain_info *power_domain_info; + int start = SST_PP_CORE_RATIO_P0_FABRIC_START; + int width = SST_PP_CORE_RATIO_P0_FABRIC_WIDTH; + int offset = SST_PP_INFO_11_OFFSET; + int i; + + if (copy_from_user(&perf_level_fabric, argp, sizeof(perf_level_fabric))) + return -EFAULT; + + power_domain_info = get_instance(perf_level_fabric.socket_id, + perf_level_fabric.power_domain_id); + if (!power_domain_info) + return -EINVAL; + + if (perf_level_fabric.level > power_domain_info->max_level) + return -EINVAL; + + if (power_domain_info->pp_header.feature_rev < 2) + return -EINVAL; + + if (!(power_domain_info->pp_header.level_en_mask & BIT(perf_level_fabric.level))) + return -EINVAL; + + /* For revision 2, maximum number of fabrics is 2 */ + perf_level_fabric.max_fabrics = 2; + + for (i = 0; i < perf_level_fabric.max_fabrics; i++) { + _read_pp_level_info("p0_fabric_freq_mhz", perf_level_fabric.p0_fabric_freq_mhz[i], + perf_level_fabric.level, offset, start, width, + SST_MUL_FACTOR_FREQ) + start += width; + + _read_pp_level_info("p1_fabric_freq_mhz", perf_level_fabric.p1_fabric_freq_mhz[i], + perf_level_fabric.level, offset, start, width, + SST_MUL_FACTOR_FREQ) + start += width; + + _read_pp_level_info("pm_fabric_freq_mhz", perf_level_fabric.pm_fabric_freq_mhz[i], + perf_level_fabric.level, offset, start, width, + SST_MUL_FACTOR_FREQ) + offset = SST_PP_INFO_12_OFFSET; + start = SST_PP_CORE_RATIO_P0_FABRIC_1_START; + } + + if (copy_to_user(argp, &perf_level_fabric, sizeof(perf_level_fabric))) + return -EFAULT; + + return 0; +} + #define SST_PP_FUSED_CORE_COUNT_START 0 #define SST_PP_FUSED_CORE_COUNT_WIDTH 8 @@ -1329,9 +1392,14 @@ static int isst_if_get_tpmi_instance_count(void __user *argp) #define SST_TF_INFO_0_OFFSET 0 #define SST_TF_INFO_1_OFFSET 8 #define SST_TF_INFO_2_OFFSET 16 +#define SST_TF_INFO_8_OFFSET 64 +#define SST_TF_INFO_8_BUCKETS 3 #define SST_TF_MAX_LP_CLIP_RATIOS TRL_MAX_LEVELS +#define SST_TF_FEATURE_REV_START 4 +#define SST_TF_FEATURE_REV_WIDTH 8 + #define SST_TF_LP_CLIP_RATIO_0_START 16 #define SST_TF_LP_CLIP_RATIO_0_WIDTH 8 @@ -1341,10 +1409,14 @@ static int isst_if_get_tpmi_instance_count(void __user *argp) #define SST_TF_NUM_CORE_0_START 0 #define SST_TF_NUM_CORE_0_WIDTH 8 +#define SST_TF_NUM_MOD_0_START 0 +#define SST_TF_NUM_MOD_0_WIDTH 16 + static int isst_if_get_turbo_freq_info(void __user *argp) { static struct isst_turbo_freq_info turbo_freq; struct tpmi_per_power_domain_info *power_domain_info; + u8 feature_rev; int i, j; if (copy_from_user(&turbo_freq, argp, sizeof(turbo_freq))) @@ -1361,6 +1433,10 @@ static int isst_if_get_turbo_freq_info(void __user *argp) turbo_freq.max_trl_levels = TRL_MAX_LEVELS; turbo_freq.max_clip_freqs = SST_TF_MAX_LP_CLIP_RATIOS; + _read_tf_level_info("feature_rev", feature_rev, turbo_freq.level, + SST_TF_INFO_0_OFFSET, SST_TF_FEATURE_REV_START, + SST_TF_FEATURE_REV_WIDTH, SST_MUL_FACTOR_NONE); + for (i = 0; i < turbo_freq.max_clip_freqs; ++i) _read_tf_level_info("lp_clip*", turbo_freq.lp_clip_freq_mhz[i], turbo_freq.level, SST_TF_INFO_0_OFFSET, @@ -1377,12 +1453,34 @@ static int isst_if_get_turbo_freq_info(void __user *argp) SST_MUL_FACTOR_FREQ) } + memset(turbo_freq.bucket_core_counts, 0, sizeof(turbo_freq.bucket_core_counts)); + + if (feature_rev >= 2) { + bool has_tf_info_8 = false; + + for (i = 0; i < SST_TF_INFO_8_BUCKETS; ++i) { + _read_tf_level_info("bucket_*_mod_count", turbo_freq.bucket_core_counts[i], + turbo_freq.level, SST_TF_INFO_8_OFFSET, + SST_TF_NUM_MOD_0_WIDTH * i, SST_TF_NUM_MOD_0_WIDTH, + SST_MUL_FACTOR_NONE) + + if (turbo_freq.bucket_core_counts[i]) + has_tf_info_8 = true; + } + + if (has_tf_info_8) + goto done_core_count; + } + for (i = 0; i < TRL_MAX_BUCKETS; ++i) _read_tf_level_info("bucket_*_core_count", turbo_freq.bucket_core_counts[i], turbo_freq.level, SST_TF_INFO_1_OFFSET, SST_TF_NUM_CORE_0_WIDTH * i, SST_TF_NUM_CORE_0_WIDTH, SST_MUL_FACTOR_NONE) + +done_core_count: + if (copy_to_user(argp, &turbo_freq, sizeof(turbo_freq))) return -EFAULT; @@ -1421,6 +1519,9 @@ static long isst_if_def_ioctl(struct file *file, unsigned int cmd, case ISST_IF_GET_PERF_LEVEL_INFO: ret = isst_if_get_perf_level_info(argp); break; + case ISST_IF_GET_PERF_LEVEL_FABRIC_INFO: + ret = isst_if_get_perf_level_fabric_info(argp); + break; case ISST_IF_GET_PERF_LEVEL_CPU_MASK: ret = isst_if_get_perf_level_mask(argp); break; diff --git a/include/uapi/linux/isst_if.h b/include/uapi/linux/isst_if.h index 0df1a1c3caf4f..8197a4800604e 100644 --- a/include/uapi/linux/isst_if.h +++ b/include/uapi/linux/isst_if.h @@ -375,6 +375,30 @@ struct isst_perf_level_data_info { __u16 trl_freq_mhz[TRL_MAX_LEVELS][TRL_MAX_BUCKETS]; }; +#define MAX_FABRIC_COUNT 8 + +/** + * struct isst_perf_level_fabric_info - Structure to get SST-PP fabric details + * @socket_id: Socket/package id + * @power_domain_id: Power Domain id + * @level: SST-PP level for which caller wants to get information + * @max_fabrics: Count of fabrics in resonse + * @p0_fabric_freq_mhz: Fabric (Uncore) maximum frequency + * @p1_fabric_freq_mhz: Fabric (Uncore) TDP frequency + * @pm_fabric_freq_mhz: Fabric (Uncore) minimum frequency + * + * Structure used to get information on frequencies for fabrics. + */ +struct isst_perf_level_fabric_info { + __u8 socket_id; + __u8 power_domain_id; + __u16 level; + __u16 max_fabrics; + __u16 p0_fabric_freq_mhz[MAX_FABRIC_COUNT]; + __u16 p1_fabric_freq_mhz[MAX_FABRIC_COUNT]; + __u16 pm_fabric_freq_mhz[MAX_FABRIC_COUNT]; +}; + /** * struct isst_perf_level_cpu_mask - Structure to get SST-PP level CPU mask * @socket_id: Socket/package id @@ -471,5 +495,7 @@ struct isst_turbo_freq_info { #define ISST_IF_GET_BASE_FREQ_INFO _IOR(ISST_IF_MAGIC, 14, struct isst_base_freq_info *) #define ISST_IF_GET_BASE_FREQ_CPU_MASK _IOR(ISST_IF_MAGIC, 15, struct isst_perf_level_cpu_mask *) #define ISST_IF_GET_TURBO_FREQ_INFO _IOR(ISST_IF_MAGIC, 16, struct isst_turbo_freq_info *) +#define ISST_IF_GET_PERF_LEVEL_FABRIC_INFO _IOR(ISST_IF_MAGIC, 17,\ + struct isst_perf_level_fabric_info *) #endif diff --git a/tools/power/x86/intel-speed-select/Makefile b/tools/power/x86/intel-speed-select/Makefile index 7221f2f55e8bf..6b299aae2ded8 100644 --- a/tools/power/x86/intel-speed-select/Makefile +++ b/tools/power/x86/intel-speed-select/Makefile @@ -13,7 +13,13 @@ endif # Do not use make's built-in rules # (this improves performance and avoids hard-to-debug behaviour); MAKEFLAGS += -r -override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include -I/usr/include/libnl3 + +NL3_CFLAGS = $(shell pkg-config --cflags libnl-3.0 2>/dev/null) +ifeq ($(NL3_CFLAGS),) +NL3_CFLAGS = -I/usr/include/libnl3 +endif + +override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include $(NL3_CFLAGS) override LDFLAGS += -lnl-genl-3 -lnl-3 ALL_TARGETS := intel-speed-select diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index 5fcc2a92957e7..2faff1aead526 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -4,8 +4,8 @@ * Copyright (c) 2019 Intel Corporation. */ +#include #include -#include #include "isst.h" @@ -16,9 +16,9 @@ struct process_cmd_struct { int arg; }; -static const char *version_str = "v1.17"; +static const char *version_str = "v1.26"; -static const int supported_api_ver = 2; +static const int supported_api_ver = 3; static struct isst_if_platform_info isst_platform_info; static char *progname; static int debug_flag; @@ -26,8 +26,9 @@ static FILE *outf; static int cpu_model; static int cpu_stepping; +static int cpu_family; -#define MAX_CPUS_IN_ONE_REQ 256 +#define MAX_CPUS_IN_ONE_REQ 512 static short max_target_cpus; static unsigned short target_cpus[MAX_CPUS_IN_ONE_REQ]; @@ -46,6 +47,9 @@ static int force_online_offline; static int auto_mode; static int fact_enable_fail; static int cgroupv2; +static int max_pkg_id; +static int max_die_id; +static int max_die_id_package_0; /* clos related */ static int current_clos = -1; @@ -55,6 +59,8 @@ static int clos_min = -1; static int clos_max = -1; static int clos_desired = -1; static int clos_priority_type; +static int cpu_0_cgroupv2; +static int cpu_0_workaround(int isolate); struct _cpu_map { unsigned short core_id; @@ -74,6 +80,23 @@ struct cpu_topology { short die_id; }; +static int read_only; + +static void print_version(void) +{ + fprintf(outf, "Version %s\n", version_str); +} + +static void check_privilege(void) +{ + if (!read_only) + return; + + isst_display_error_info_message(1, "Insufficient privileges", 0, 0); + isst_ctdp_display_information_end(outf); + exit(1); +} + FILE *get_output_file(void) { return outf; @@ -138,15 +161,25 @@ int is_icx_platform(void) return 0; } +static int is_dmr_plus_platform(void) +{ + if (cpu_family == 19) + return 1; + + return 0; +} + static int update_cpu_model(void) { unsigned int ebx, ecx, edx; - unsigned int fms, family; + unsigned int fms; __cpuid(1, fms, ebx, ecx, edx); - family = (fms >> 8) & 0xf; + cpu_family = (fms >> 8) & 0xf; + if (cpu_family == 0xf) + cpu_family += (fms >> 20) & 0xff; cpu_model = (fms >> 4) & 0xf; - if (family == 6 || family == 0xf) + if (cpu_family == 6 || cpu_family == 0xf) cpu_model += ((fms >> 16) & 0xf) << 4; cpu_stepping = fms & 0xf; @@ -474,42 +507,15 @@ static unsigned int is_cpu_online(int cpu) return online; } -static int get_kernel_version(int *major, int *minor) -{ - struct utsname buf; - int ret; - - ret = uname(&buf); - if (ret) - return ret; - - ret = sscanf(buf.release, "%d.%d", major, minor); - if (ret != 2) - return ret; - - return 0; -} - -#define CPU0_HOTPLUG_DEPRECATE_MAJOR_VER 6 -#define CPU0_HOTPLUG_DEPRECATE_MINOR_VER 5 - void set_cpu_online_offline(int cpu, int state) { char buffer[128]; int fd, ret; - if (!cpu) { - int major, minor; - - ret = get_kernel_version(&major, &minor); - if (!ret) { - if (major > CPU0_HOTPLUG_DEPRECATE_MAJOR_VER || (major == CPU0_HOTPLUG_DEPRECATE_MAJOR_VER && - minor >= CPU0_HOTPLUG_DEPRECATE_MINOR_VER)) { - debug_printf("Ignore CPU 0 offline/online for kernel version >= %d.%d\n", major, minor); - debug_printf("Use cgroups to isolate CPU 0\n"); - return; - } - } + if (cpu_0_cgroupv2 && !cpu) { + fprintf(stderr, "Will use cgroup v2 for CPU 0\n"); + cpu_0_workaround(!state); + return; } snprintf(buffer, sizeof(buffer), @@ -517,9 +523,10 @@ void set_cpu_online_offline(int cpu, int state) fd = open(buffer, O_WRONLY); if (fd < 0) { - if (!cpu && state) { + if (!cpu) { 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"); + fprintf(stderr, "Will use cgroup v2\n"); + cpu_0_workaround(!state); return; } err(-1, "%s open failed", buffer); @@ -579,6 +586,8 @@ void for_each_online_power_domain_in_set(void (*callback)(struct isst_id *, void if (id.pkg < 0 || id.die < 0 || id.punit < 0) continue; + id.die = id.die % (max_die_id_package_0 + 1); + valid_mask[id.pkg][id.die] = 1; if (cpus[id.pkg][id.die][id.punit] == -1) @@ -586,6 +595,18 @@ void for_each_online_power_domain_in_set(void (*callback)(struct isst_id *, void } for (i = 0; i < MAX_PACKAGE_COUNT; i++) { + if (max_die_id > max_pkg_id) { + for (k = 0; k < MAX_PUNIT_PER_DIE && k < MAX_DIE_PER_PACKAGE; k++) { + id.cpu = cpus[i][k][k]; + id.pkg = i; + id.die = get_physical_die_id(id.cpu); + id.punit = k; + if (isst_is_punit_valid(&id)) + callback(&id, arg1, arg2, arg3, arg4); + } + continue; + } + for (j = 0; j < MAX_DIE_PER_PACKAGE; j++) { /* * Fix me: @@ -596,7 +617,10 @@ void for_each_online_power_domain_in_set(void (*callback)(struct isst_id *, void for (k = 0; k < MAX_PUNIT_PER_DIE; k++) { id.cpu = cpus[i][j][k]; id.pkg = i; - id.die = j; + if (id.cpu >= 0) + id.die = get_physical_die_id(id.cpu); + else + id.die = id.pkg; id.punit = k; if (isst_is_punit_valid(&id)) callback(&id, arg1, arg2, arg3, arg4); @@ -798,6 +822,8 @@ static void create_cpu_map(void) cpu_map[i].die_id = die_id; cpu_map[i].core_id = core_id; + if (max_pkg_id < pkg_id) + max_pkg_id = pkg_id; punit_id = 0; @@ -819,6 +845,12 @@ static void create_cpu_map(void) cpu_cnt[pkg_id][die_id][punit_id]++; + if (max_die_id < die_id) + max_die_id = die_id; + + if (!pkg_id && max_die_id_package_0 < die_id) + max_die_id_package_0 = die_id; + debug_printf( "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, @@ -906,7 +938,7 @@ int enable_cpuset_controller(void) return 0; } -int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int level) +int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int level, int cpu_0_only) { int i, first, curr_index, index, ret, fd; static char str[512], dir_name[64]; @@ -936,9 +968,11 @@ int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int lev ret = write(fd, "member", strlen("member")); if (ret == -1) { printf("Can't update to member\n"); + close(fd); return ret; } + close(fd); return 0; } @@ -949,6 +983,12 @@ int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int lev curr_index = 0; first = 1; str[0] = '\0'; + + if (cpu_0_only) { + snprintf(str, str_len, "0"); + goto create_partition; + } + for (i = 0; i < get_topo_max_cpus(); ++i) { if (!is_cpu_in_power_domain(i, id)) continue; @@ -971,6 +1011,7 @@ int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int lev first = 0; } +create_partition: debug_printf("isolated CPUs list: package:%d curr_index:%d [%s]\n", id->pkg, curr_index ,str); snprintf(cpuset_cpus, sizeof(cpuset_cpus), "%s/cpuset.cpus", dir_name); @@ -1011,6 +1052,74 @@ int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int lev return 0; } +static int cpu_0_workaround(int isolate) +{ + int fd, fd1, len, ret; + cpu_set_t cpu_mask; + struct isst_id id; + char str[2]; + + debug_printf("isolate CPU 0 state: %d\n", isolate); + + if (isolate) + goto isolate; + + /* First check if CPU 0 was isolated to remove isolation. */ + + /* If the cpuset.cpus doesn't exist, that means that none of the CPUs are isolated*/ + fd = open("/sys/fs/cgroup/0-0-0/cpuset.cpus", O_RDONLY, 0); + if (fd < 0) + return 0; + + len = read(fd, str, sizeof(str)); + /* Error check, but unlikely to fail. If fails that means that not isolated */ + if (len == -1) + return 0; + + + /* Is CPU 0 is in isolate list, the display is sorted so first element will be CPU 0*/ + if (str[0] != '0') { + close(fd); + return 0; + } + + fd1 = open("/sys/fs/cgroup/0-0-0/cpuset.cpus.partition", O_RDONLY, 0); + /* Unlikely that, this attribute is not present, but handle error */ + if (fd1 < 0) { + close(fd); + return 0; + } + + /* Is CPU 0 already changed partition to "member" */ + len = read(fd1, str, sizeof(str)); + if (len != -1 && str[0] == 'm') { + close(fd1); + close(fd); + return 0; + } + + close(fd1); + close(fd); + + debug_printf("CPU 0 was isolated before, so remove isolation\n"); + +isolate: + ret = enable_cpuset_controller(); + if (ret) + goto isolate_fail; + + CPU_ZERO(&cpu_mask); + memset(&id, 0, sizeof(struct isst_id)); + CPU_SET(0, &cpu_mask); + + ret = isolate_cpus(&id, sizeof(cpu_mask), &cpu_mask, isolate, 1); +isolate_fail: + if (ret) + fprintf(stderr, "Can't isolate CPU 0\n"); + + return ret; +} + static int isst_fill_platform_info(void) { const char *pathname = "/dev/isst_interface"; @@ -1034,8 +1143,9 @@ static int isst_fill_platform_info(void) close(fd); if (isst_platform_info.api_version > supported_api_ver) { + print_version(); printf("Incompatible API versions; Upgrade of tool is required\n"); - return -1; + exit(1); } set_platform_ops: @@ -1438,7 +1548,8 @@ static void set_tdp_level_for_cpu(struct isst_id *id, void *arg1, void *arg2, vo usleep(2000); /* Adjusting uncore freq */ - isst_adjust_uncore_freq(id, tdp_level, &ctdp_level); + if (!is_dmr_plus_platform()) + isst_adjust_uncore_freq(id, tdp_level, &ctdp_level); fprintf(stderr, "Option is set to online/offline\n"); ctdp_level.core_cpumask_size = @@ -1457,7 +1568,8 @@ static void set_tdp_level_for_cpu(struct isst_id *id, void *arg1, void *arg2, vo if (ret) goto use_offline; - ret = isolate_cpus(id, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask, tdp_level); + ret = isolate_cpus(id, ctdp_level.core_cpumask_size, + ctdp_level.core_cpumask, tdp_level, 0); if (ret) goto use_offline; @@ -1487,6 +1599,8 @@ static void set_tdp_level_for_cpu(struct isst_id *id, void *arg1, void *arg2, vo static void set_tdp_level(int arg) { + check_privilege(); + if (cmd_help) { fprintf(stderr, "Set Config TDP level\n"); fprintf(stderr, @@ -1637,6 +1751,9 @@ static int no_turbo(void) return parse_int_file(0, "/sys/devices/system/cpu/intel_pstate/no_turbo"); } +#define U32_MAX ((unsigned int)~0U) +#define S32_MAX ((int)(U32_MAX >> 1)) + static void adjust_scaling_max_from_base_freq(int cpu) { int base_freq, scaling_max_freq; @@ -1644,7 +1761,7 @@ static void adjust_scaling_max_from_base_freq(int cpu) 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); + set_cpufreq_scaling_min_max(cpu, 1, S32_MAX); } static void adjust_scaling_min_from_base_freq(int cpu) @@ -1955,6 +2072,8 @@ static void set_pbf_enable(int arg) { int enable = arg; + check_privilege(); + if (cmd_help) { if (enable) { fprintf(stderr, @@ -2002,6 +2121,7 @@ static void dump_fact_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, struct isst_fact_info fact_info; int ret; + memset(&fact_info, 0, sizeof(fact_info)); 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); @@ -2120,12 +2240,14 @@ static void set_fact_enable(int arg) int i, ret, enable = arg; struct isst_id id; + check_privilege(); + if (cmd_help) { if (enable) { fprintf(stderr, "Enable Intel Speed Select Technology Turbo frequency feature\n"); fprintf(stderr, - "Optional: -t|--trl : Specify turbo ratio limit\n"); + "Optional: -t|--trl : Specify turbo ratio limit in hex starting with 0x\n"); fprintf(stderr, "\tOptional Arguments: -a|--auto : Designate specified target CPUs with"); fprintf(stderr, @@ -2134,7 +2256,7 @@ static void set_fact_enable(int arg) fprintf(stderr, "Disable Intel Speed Select Technology turbo frequency feature\n"); fprintf(stderr, - "Optional: -t|--trl : Specify turbo ratio limit\n"); + "Optional: -t|--trl : Specify turbo ratio limit in hex starting with 0x\n"); fprintf(stderr, "\tOptional Arguments: -a|--auto : Also disable core-power associations\n"); } @@ -2241,6 +2363,14 @@ static void enable_clos_qos_config(struct isst_id *id, void *arg1, void *arg2, v { int ret; int status = *(int *)arg4; + int cp_state, cp_cap; + + if (!isst_read_pm_config(id, &cp_state, &cp_cap)) { + if (!cp_cap) { + isst_display_error_info_message(1, "core-power not supported", 0, 0); + return; + } + } if (is_skx_based_platform()) clos_priority_type = 1; @@ -2261,6 +2391,8 @@ static void set_clos_enable(int arg) { int enable = arg; + check_privilege(); + if (cmd_help) { if (enable) { fprintf(stderr, @@ -2391,6 +2523,8 @@ static void set_clos_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, static void set_clos_config(int arg) { + check_privilege(); + if (cmd_help) { fprintf(stderr, "Set core-power configuration for one of the four clos ids\n"); @@ -2456,6 +2590,8 @@ static void set_clos_assoc_for_cpu(struct isst_id *id, void *arg1, void *arg2, v static void set_clos_assoc(int arg) { + check_privilege(); + if (cmd_help) { fprintf(stderr, "Associate a clos id to a CPU\n"); fprintf(stderr, @@ -2526,22 +2662,24 @@ static void set_turbo_mode_for_cpu(struct isst_id *id, int status) } if (status) { - isst_display_result(id, outf, "turbo-mode", "enable", 0); - } else { isst_display_result(id, outf, "turbo-mode", "disable", 0); + } else { + isst_display_result(id, outf, "turbo-mode", "enable", 0); } } static void set_turbo_mode(int arg) { - int i, enable = arg; + int i, disable = arg; struct isst_id id; + check_privilege(); + if (cmd_help) { - if (enable) - fprintf(stderr, "Set turbo mode enable\n"); - else + if (disable) fprintf(stderr, "Set turbo mode disable\n"); + else + fprintf(stderr, "Set turbo mode enable\n"); exit(0); } @@ -2559,7 +2697,7 @@ static void set_turbo_mode(int arg) if (online) { set_isst_id(&id, i); - set_turbo_mode_for_cpu(&id, enable); + set_turbo_mode_for_cpu(&id, disable); } } @@ -2573,12 +2711,16 @@ static void get_set_trl(struct isst_id *id, void *arg1, void *arg2, void *arg3, int set = *(int *)arg4; int ret; + if (id->cpu < 0) + return; + if (set && !fact_trl) { isst_display_error_info_message(1, "Invalid TRL. Specify with [-t|--trl]", 0, 0); exit(0); } if (set) { + check_privilege(); ret = isst_set_trl(id, fact_trl); isst_display_result(id, outf, "turbo-mode", "set-trl", ret); return; @@ -2596,7 +2738,7 @@ 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"); + fprintf(stderr, "\t t|--trl: Specify turbo ratio limit for setting TRL in hex starting with 0x\n"); } else { fprintf(stderr, "Get TRL (turbo ratio limits)\n"); } @@ -2730,6 +2872,43 @@ void parse_cpu_command(char *optarg) exit(-1); } +static void check_optarg(char *option, int hex) +{ + if (optarg) { + char *start = optarg; + int i; + + if (hex && strlen(optarg) < 3) { + /* At least 0x plus one character must be present */ + fprintf(stderr, "malformed arguments for:%s [%s]\n", option, optarg); + exit(0); + } + + if (hex) { + if (optarg[0] != '0' || tolower(optarg[1]) != 'x') { + fprintf(stderr, "malformed arguments for:%s [%s]\n", + option, optarg); + exit(0); + } + start = &optarg[2]; + } + + for (i = 0; i < strlen(start); ++i) { + if (hex) { + if (!isxdigit(start[i])) { + fprintf(stderr, "malformed arguments for:%s [%s]\n", + option, optarg); + exit(0); + } + } else if (!isdigit(start[i])) { + fprintf(stderr, "malformed arguments for:%s [%s]\n", + option, optarg); + exit(0); + } + } + } +} + static void parse_cmd_args(int argc, int start, char **argv) { int opt; @@ -2763,18 +2942,21 @@ static void parse_cmd_args(int argc, int start, char **argv) auto_mode = 1; break; case 'b': + check_optarg("bucket", 0); fact_bucket = atoi(optarg); break; case 'h': cmd_help = 1; break; case 'l': + check_optarg("level", 0); tdp_level = atoi(optarg); break; case 'o': force_online_offline = 1; break; case 't': + check_optarg("trl", 1); sscanf(optarg, "0x%llx", &fact_trl); break; case 'r': @@ -2791,13 +2973,16 @@ static void parse_cmd_args(int argc, int start, char **argv) break; /* CLOS related */ case 'c': + check_optarg("clos", 0); current_clos = atoi(optarg); break; case 'd': + check_optarg("desired", 0); clos_desired = atoi(optarg); clos_desired /= isst_get_disp_freq_multiplier(); break; case 'e': + check_optarg("epp", 0); 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); @@ -2805,14 +2990,17 @@ static void parse_cmd_args(int argc, int start, char **argv) } break; case 'n': + check_optarg("min", 0); clos_min = atoi(optarg); clos_min /= isst_get_disp_freq_multiplier(); break; case 'm': + check_optarg("max", 0); clos_max = atoi(optarg); clos_max /= isst_get_disp_freq_multiplier(); break; case 'p': + check_optarg("priority", 0); 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); @@ -2820,6 +3008,7 @@ static void parse_cmd_args(int argc, int start, char **argv) } break; case 'w': + check_optarg("weight", 0); 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); @@ -2995,6 +3184,7 @@ static void usage(void) 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("\t[-u|--cpu0-workaround : Don't try to online/offline CPU0 instead use cgroup v2.\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"); @@ -3011,12 +3201,6 @@ static void usage(void) 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); exit(0); } @@ -3048,17 +3232,28 @@ static void cmdline(int argc, char **argv) { "no-daemon", no_argument, 0, 'n' }, { "poll-interval", required_argument, 0, 'w' }, { "cgroupv2", required_argument, 0, 'g' }, + { "cpu0-workaround", required_argument, 0, 'u' }, { 0, 0, 0, 0 } }; if (geteuid() != 0) { - fprintf(stderr, "Must run as root\n"); - exit(0); + int fd; + + fd = open(pathname, O_RDWR); + if (fd < 0) { + fprintf(stderr, "Must run as root\n"); + exit(0); + } + fprintf(stderr, "\nNot running as root, Only read only operations are supported\n"); + close(fd); + read_only = 1; } ret = update_cpu_model(); - if (ret) - err(-1, "Invalid CPU model (%d)\n", cpu_model); + if (ret) { + fprintf(stderr, "Invalid CPU model (%d)\n", cpu_model); + exit(1); + } printf("Intel(R) Speed Select Technology\n"); printf("Executing on CPU model:%d[0x%x]\n", cpu_model, cpu_model); @@ -3078,7 +3273,7 @@ static void cmdline(int argc, char **argv) goto out; progname = argv[0]; - while ((opt = getopt_long_only(argc, argv, "+c:df:hio:vabw:ng", long_options, + while ((opt = getopt_long_only(argc, argv, "+c:df:hio:vabw:ngu", long_options, &option_index)) != -1) { switch (opt) { case 'a': @@ -3122,6 +3317,7 @@ static void cmdline(int argc, char **argv) break; case 'v': print_version(); + exit(0); break; case 'b': oob_mode = 1; @@ -3140,6 +3336,9 @@ static void cmdline(int argc, char **argv) case 'g': cgroupv2 = 1; break; + case 'u': + cpu_0_cgroupv2 = 1; + break; default: usage(); } diff --git a/tools/power/x86/intel-speed-select/isst-core-mbox.c b/tools/power/x86/intel-speed-select/isst-core-mbox.c index 24bea57f4ff53..c81ecd602bcfa 100644 --- a/tools/power/x86/intel-speed-select/isst-core-mbox.c +++ b/tools/power/x86/intel-speed-select/isst-core-mbox.c @@ -746,6 +746,7 @@ static int mbox_set_pbf_fact_status(struct isst_id *id, int pbf, int enable) static int _get_fact_bucket_info(struct isst_id *id, int level, struct isst_fact_bucket_info *bucket_info) { + int trl_max_levels = isst_get_trl_max_levels(); unsigned int resp; int i, k, ret; @@ -769,7 +770,7 @@ static int _get_fact_bucket_info(struct isst_id *id, int level, } } - for (k = 0; k < 3; ++k) { + for (k = 0; k < trl_max_levels; ++k) { for (i = 0; i < 2; ++i) { int j; diff --git a/tools/power/x86/intel-speed-select/isst-core-tpmi.c b/tools/power/x86/intel-speed-select/isst-core-tpmi.c index 3458768562e5e..ebaad0dc8ca6f 100644 --- a/tools/power/x86/intel-speed-select/isst-core-tpmi.c +++ b/tools/power/x86/intel-speed-select/isst-core-tpmi.c @@ -194,8 +194,14 @@ static int tpmi_get_ctdp_control(struct isst_id *id, int 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; + if (api_version() > 2) { + ctdp_level->fact_support = info.sst_tf_support & BIT(config_index); + ctdp_level->pbf_support = info.sst_bf_support & BIT(config_index); + } else { + 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)); @@ -221,6 +227,7 @@ static int tpmi_get_ctdp_control(struct isst_id *id, int config_index, 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_fabric_info fabric_info; struct isst_perf_level_data_info info; int ret; @@ -247,6 +254,17 @@ static int tpmi_get_tdp_info(struct isst_id *id, int config_index, ctdp_level->uncore_p1 = info.p1_fabric_freq_mhz; ctdp_level->uncore_pm = info.pm_fabric_freq_mhz; + fabric_info.socket_id = id->pkg; + fabric_info.power_domain_id = id->punit; + fabric_info.level = config_index; + + ret = tpmi_process_ioctl(ISST_IF_GET_PERF_LEVEL_FABRIC_INFO, &fabric_info); + if (ret != -1) { + ctdp_level->uncore1_p0 = fabric_info.p0_fabric_freq_mhz[1]; + ctdp_level->uncore1_p1 = fabric_info.p1_fabric_freq_mhz[1]; + ctdp_level->uncore1_pm = fabric_info.pm_fabric_freq_mhz[1]; + } + 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, @@ -323,7 +341,7 @@ static int tpmi_get_get_trls(struct isst_id *id, int config_index, return 0; } -static int tpmi_get_get_trl(struct isst_id *id, int level, int config_index, +static int tpmi_get_get_trl(struct isst_id *id, int config_index, int level, int *trl) { struct isst_pkg_ctdp_level_info ctdp_level; @@ -434,13 +452,16 @@ static int tpmi_get_pbf_info(struct isst_id *id, int level, return _pbf_get_coremask_info(id, level, pbf_info); } +#define FEATURE_ENABLE_WAIT_US 1000 +#define FEATURE_ENABLE_RETRIES 5 + 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; + int ret, i; ret = isst_get_ctdp_levels(id, &pkg_dev); if (ret) @@ -485,6 +506,30 @@ static int tpmi_set_pbf_fact_status(struct isst_id *id, int pbf, int enable) if (ret == -1) return ret; + for (i = 0; i < FEATURE_ENABLE_RETRIES; ++i) { + + usleep(FEATURE_ENABLE_WAIT_US); + + /* Check status */ + ret = isst_get_ctdp_control(id, current_level, &ctdp_level); + if (ret) + return ret; + + debug_printf("pbf_enabled:%d fact_enabled:%d\n", + ctdp_level.pbf_enabled, ctdp_level.fact_enabled); + + if (pbf) { + if (ctdp_level.pbf_enabled == enable) + break; + } else { + if (ctdp_level.fact_enabled == enable) + break; + } + } + + if (i == FEATURE_ENABLE_RETRIES) + return -1; + return 0; } @@ -495,6 +540,7 @@ static int tpmi_get_fact_info(struct isst_id *id, int level, int fact_bucket, int i, j; int ret; + memset(&info, 0, sizeof(info)); info.socket_id = id->pkg; info.power_domain_id = id->punit; info.level = level; @@ -641,7 +687,8 @@ static int tpmi_pm_qos_config(struct isst_id *id, int enable_clos, int priority_type) { struct isst_core_power info; - int i, ret, saved_punit; + int cp_state = 0, cp_cap = 0; + int i, j, ret, saved_punit; info.get_set = 1; info.socket_id = id->pkg; @@ -661,6 +708,19 @@ static int tpmi_pm_qos_config(struct isst_id *id, int enable_clos, id->punit = saved_punit; return ret; } + /* Get status */ + for (j = 0; j < FEATURE_ENABLE_RETRIES; ++j) { + usleep(FEATURE_ENABLE_WAIT_US); + ret = tpmi_read_pm_config(id, &cp_state, &cp_cap); + debug_printf("ret:%d cp_state:%d enable_clos:%d\n", ret, + cp_state, enable_clos); + if (ret || cp_state == enable_clos) + break; + } + if (j == FEATURE_ENABLE_RETRIES) { + id->punit = saved_punit; + return -1; + } } } diff --git a/tools/power/x86/intel-speed-select/isst-core.c b/tools/power/x86/intel-speed-select/isst-core.c index f55fef4c13a7a..e05561d00458f 100644 --- a/tools/power/x86/intel-speed-select/isst-core.c +++ b/tools/power/x86/intel-speed-select/isst-core.c @@ -23,6 +23,7 @@ int isst_set_platform_ops(int api_version) isst_ops = mbox_get_platform_ops(); break; case 2: + case 3: isst_ops = tpmi_get_platform_ops(); break; default: @@ -282,6 +283,8 @@ int isst_set_trl(struct isst_id *id, unsigned long long trl) return 0; } +#define MSR_TRL_FREQ_MULTIPLIER 100 + int isst_set_trl_from_current_tdp(struct isst_id *id, unsigned long long trl) { unsigned long long msr_trl; @@ -309,6 +312,10 @@ int isst_set_trl_from_current_tdp(struct isst_id *id, unsigned long long trl) for (i = 0; i < 8; ++i) { unsigned long long _trl = trl[i]; + /* MSR is always in 100 MHz unit */ + if (isst_get_disp_freq_multiplier() == 1) + _trl /= MSR_TRL_FREQ_MULTIPLIER; + msr_trl |= (_trl << (i * 8)); } } diff --git a/tools/power/x86/intel-speed-select/isst-daemon.c b/tools/power/x86/intel-speed-select/isst-daemon.c index 12053fa435429..66df21b2b5737 100644 --- a/tools/power/x86/intel-speed-select/isst-daemon.c +++ b/tools/power/x86/intel-speed-select/isst-daemon.c @@ -90,7 +90,8 @@ void process_level_change(struct isst_id *id) if (ret) goto use_offline; - isolate_cpus(id, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask, pkg_dev.current_level); + isolate_cpus(id, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask, + pkg_dev.current_level, 0); goto free_mask; } diff --git a/tools/power/x86/intel-speed-select/isst-display.c b/tools/power/x86/intel-speed-select/isst-display.c index 14c9b037859ac..e4884eb028379 100644 --- a/tools/power/x86/intel-speed-select/isst-display.c +++ b/tools/power/x86/intel-speed-select/isst-display.c @@ -172,24 +172,43 @@ static int print_package_info(struct isst_id *id, FILE *outf) int level = 1; if (out_format_is_json()) { - 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 + if (api_version() > 1) { + if (id->die < 0 && id->cpu < 0) + snprintf(header, sizeof(header), + "package-%d:die-IO:powerdomain-%d:cpu-None", + id->pkg, id->punit); + else if (id->cpu < 0) + snprintf(header, sizeof(header), + "package-%d:die-%d:powerdomain-%d:cpu-None", + id->pkg, id->die, id->punit); + else + 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, level++, header, NULL); - snprintf(header, sizeof(header), "die-%d", id->die); + if (id->die < 0) + snprintf(header, sizeof(header), "die-IO"); + else + snprintf(header, sizeof(header), "die-%d", id->die); 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); + + if (id->cpu < 0) + snprintf(header, sizeof(header), "cpu-None"); + else + snprintf(header, sizeof(header), "cpu-%d", id->cpu); + format_and_print(outf, level, header, NULL); return level; @@ -199,8 +218,8 @@ static void _isst_pbf_display_information(struct isst_id *id, FILE *outf, int le struct isst_pbf_info *pbf_info, int disp_level) { - char header[256]; - char value[512]; + static char header[256]; + static char value[1024]; snprintf(header, sizeof(header), "speed-select-base-freq-properties"); format_and_print(outf, disp_level, header, NULL); @@ -338,8 +357,8 @@ void isst_ctdp_display_core_info(struct isst_id *id, FILE *outf, char *prefix, void isst_ctdp_display_information(struct isst_id *id, FILE *outf, int tdp_level, struct isst_pkg_ctdp *pkg_dev) { - char header[256]; - char value[512]; + static char header[256]; + static char value[1024]; static int level; int trl_max_levels = isst_get_trl_max_levels(); int i; @@ -441,6 +460,26 @@ void isst_ctdp_display_information(struct isst_id *id, FILE *outf, int tdp_level format_and_print(outf, level + 2, header, value); } + if (ctdp_level->uncore1_p1) { + snprintf(header, sizeof(header), "uncore-1-frequency-base(MHz)"); + snprintf(value, sizeof(value), "%d", + ctdp_level->uncore1_p1 * isst_get_disp_freq_multiplier()); + format_and_print(outf, level + 2, header, value); + } + if (ctdp_level->uncore1_pm) { + snprintf(header, sizeof(header), "uncore-1-frequency-min(MHz)"); + snprintf(value, sizeof(value), "%d", + ctdp_level->uncore1_pm * isst_get_disp_freq_multiplier()); + format_and_print(outf, level + 2, header, value); + } + + if (ctdp_level->uncore1_p0) { + snprintf(header, sizeof(header), "uncore-1-frequency-max(MHz)"); + snprintf(value, sizeof(value), "%d", + ctdp_level->uncore1_p0 * isst_get_disp_freq_multiplier()); + format_and_print(outf, level + 2, header, value); + } + if (ctdp_level->mem_freq) { snprintf(header, sizeof(header), "max-mem-frequency(MHz)"); snprintf(value, sizeof(value), "%d", diff --git a/tools/power/x86/intel-speed-select/isst.h b/tools/power/x86/intel-speed-select/isst.h index 8def22dec4a27..960f647cfc2d9 100644 --- a/tools/power/x86/intel-speed-select/isst.h +++ b/tools/power/x86/intel-speed-select/isst.h @@ -80,7 +80,7 @@ #define DISP_FREQ_MULTIPLIER 100 #define MAX_PACKAGE_COUNT 32 -#define MAX_DIE_PER_PACKAGE 2 +#define MAX_DIE_PER_PACKAGE 16 #define MAX_PUNIT_PER_DIE 8 /* Unified structure to specific a CPU or a Power Domain */ @@ -147,6 +147,9 @@ struct isst_pkg_ctdp_level_info { int uncore_p0; int uncore_p1; int uncore_pm; + int uncore1_p0; + int uncore1_p1; + int uncore1_pm; int sse_p1; int avx2_p1; int avx512_p1; @@ -318,7 +321,8 @@ 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 isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, + int level, int cpu_0_only); extern int use_cgroupv2(void); #endif