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

Summary of changes:
- CPU 0 hotplug support is deprecated in the upstream kernel. This
  causes failures during level change for several customers. So, add a
  silent workaround to use Cgroup v2, without user option.
- Increase number of CPUs in a single request
- Fix turbo mode enable/disable issue
- Error handling for invalid input options
This commit is contained in:
Ilpo Järvinen 2023-10-18 17:07:11 +03:00
commit e485c7a193
No known key found for this signature in database
GPG Key ID: 59AC4F6153E5CE31
3 changed files with 168 additions and 51 deletions

View File

@ -4,8 +4,8 @@
* Copyright (c) 2019 Intel Corporation.
*/
#include <ctype.h>
#include <linux/isst_if.h>
#include <sys/utsname.h>
#include "isst.h"
@ -16,7 +16,7 @@ struct process_cmd_struct {
int arg;
};
static const char *version_str = "v1.17";
static const char *version_str = "v1.18";
static const int supported_api_ver = 2;
static struct isst_if_platform_info isst_platform_info;
@ -27,7 +27,7 @@ static FILE *outf;
static int cpu_model;
static int cpu_stepping;
#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];
@ -55,6 +55,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;
@ -474,42 +476,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 +492,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);
@ -906,7 +882,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];
@ -949,6 +925,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 +953,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 +994,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";
@ -1457,7 +1508,8 @@ display_result:
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;
@ -2125,7 +2177,7 @@ static void set_fact_enable(int arg)
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 +2186,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 +2293,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;
@ -2526,22 +2586,22 @@ 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;
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 +2619,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,6 +2633,9 @@ 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);
@ -2596,7 +2659,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 +2793,43 @@ error:
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 +2863,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 +2894,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 +2911,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 +2929,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 +3105,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");
@ -3048,6 +3159,7 @@ 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 }
};
@ -3078,7 +3190,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':
@ -3140,6 +3252,9 @@ static void cmdline(int argc, char **argv)
case 'g':
cgroupv2 = 1;
break;
case 'u':
cpu_0_cgroupv2 = 1;
break;
default:
usage();
}

View File

@ -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;
}

View File

@ -318,7 +318,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