1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2020 Intel Corporation 3 */ 4 5 #include <limits.h> 6 #include <stdlib.h> 7 #include <stdio.h> 8 #include <string.h> 9 10 #include <rte_log.h> 11 #include <rte_string_fns.h> 12 #include <rte_lcore.h> 13 14 #include "power_common.h" 15 16 RTE_LOG_REGISTER_DEFAULT(rte_power_logtype, INFO); 17 18 #define POWER_SYSFILE_SCALING_DRIVER \ 19 "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_driver" 20 #define POWER_SYSFILE_GOVERNOR \ 21 "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_governor" 22 #define POWER_CONVERT_TO_DECIMAL 10 23 24 int 25 cpufreq_check_scaling_driver(const char *driver_name) 26 { 27 unsigned int lcore_id = 0; /* always check core 0 */ 28 char readbuf[PATH_MAX]; 29 size_t end_idx; 30 char *s; 31 FILE *f; 32 33 /* 34 * Check if scaling driver matches what we expect. 35 */ 36 open_core_sysfs_file(&f, "r", POWER_SYSFILE_SCALING_DRIVER, 37 lcore_id); 38 /* if there's no driver at all, bail out */ 39 if (f == NULL) 40 return 0; 41 42 s = fgets(readbuf, sizeof(readbuf), f); 43 /* don't need it any more */ 44 fclose(f); 45 46 /* if we can't read it, consider unsupported */ 47 if (s == NULL) 48 return 0; 49 50 /* when read from sysfs, driver name has an extra newline at the end */ 51 end_idx = strnlen(readbuf, sizeof(readbuf)); 52 if (end_idx > 0 && readbuf[end_idx - 1] == '\n') { 53 end_idx--; 54 readbuf[end_idx] = '\0'; 55 } 56 57 /* does the driver name match? */ 58 if (strncmp(readbuf, driver_name, sizeof(readbuf)) != 0) 59 return 0; 60 61 /* 62 * We might have a situation where the driver is supported, but we don't 63 * have permissions to do frequency scaling. This error should not be 64 * handled here, so consider the system to support scaling for now. 65 */ 66 return 1; 67 } 68 69 int 70 open_core_sysfs_file(FILE **f, const char *mode, const char *format, ...) 71 { 72 char fullpath[PATH_MAX]; 73 va_list ap; 74 FILE *tmpf; 75 76 va_start(ap, format); 77 vsnprintf(fullpath, sizeof(fullpath), format, ap); 78 va_end(ap); 79 tmpf = fopen(fullpath, mode); 80 *f = tmpf; 81 if (tmpf == NULL) 82 return -1; 83 84 return 0; 85 } 86 87 int 88 read_core_sysfs_u32(FILE *f, uint32_t *val) 89 { 90 char buf[BUFSIZ]; 91 uint32_t fval; 92 char *s; 93 94 s = fgets(buf, sizeof(buf), f); 95 if (s == NULL) 96 return -1; 97 98 /* fgets puts null terminator in, but do this just in case */ 99 buf[BUFSIZ - 1] = '\0'; 100 101 /* strip off any terminating newlines */ 102 *strchrnul(buf, '\n') = '\0'; 103 104 fval = strtoul(buf, NULL, POWER_CONVERT_TO_DECIMAL); 105 106 /* write the value */ 107 *val = fval; 108 109 return 0; 110 } 111 112 int 113 read_core_sysfs_s(FILE *f, char *buf, unsigned int len) 114 { 115 char *s; 116 117 s = fgets(buf, len, f); 118 if (s == NULL) 119 return -1; 120 121 /* fgets puts null terminator in, but do this just in case */ 122 buf[len - 1] = '\0'; 123 124 /* strip off any terminating newlines */ 125 *strchrnul(buf, '\n') = '\0'; 126 127 return 0; 128 } 129 130 int 131 write_core_sysfs_s(FILE *f, const char *str) 132 { 133 int ret; 134 135 ret = fseek(f, 0, SEEK_SET); 136 if (ret != 0) 137 return -1; 138 139 ret = fputs(str, f); 140 if (ret < 0) 141 return -1; 142 143 /* flush the output */ 144 ret = fflush(f); 145 if (ret != 0) 146 return -1; 147 148 return 0; 149 } 150 151 /** 152 * It is to check the current scaling governor by reading sys file, and then 153 * set it into 'performance' if it is not by writing the sys file. The original 154 * governor will be saved for rolling back. 155 */ 156 int 157 power_set_governor(unsigned int lcore_id, const char *new_governor, 158 char *orig_governor, size_t orig_governor_len) 159 { 160 FILE *f_governor = NULL; 161 int ret = -1; 162 char buf[BUFSIZ]; 163 164 open_core_sysfs_file(&f_governor, "rw+", POWER_SYSFILE_GOVERNOR, 165 lcore_id); 166 if (f_governor == NULL) { 167 POWER_LOG(ERR, "failed to open %s", 168 POWER_SYSFILE_GOVERNOR); 169 goto out; 170 } 171 172 ret = read_core_sysfs_s(f_governor, buf, sizeof(buf)); 173 if (ret < 0) { 174 POWER_LOG(ERR, "Failed to read %s", 175 POWER_SYSFILE_GOVERNOR); 176 goto out; 177 } 178 179 /* Save the original governor, if it was provided */ 180 if (orig_governor) 181 rte_strscpy(orig_governor, buf, orig_governor_len); 182 183 /* Check if current governor is already what we want */ 184 if (strcmp(buf, new_governor) == 0) { 185 ret = 0; 186 POWER_DEBUG_LOG("Power management governor of lcore %u is " 187 "already %s", lcore_id, new_governor); 188 goto out; 189 } 190 191 /* Write the new governor */ 192 ret = write_core_sysfs_s(f_governor, new_governor); 193 if (ret < 0) { 194 POWER_LOG(ERR, "Failed to write %s", 195 POWER_SYSFILE_GOVERNOR); 196 goto out; 197 } 198 199 ret = 0; 200 POWER_LOG(INFO, "Power management governor of lcore %u has been " 201 "set to '%s' successfully", lcore_id, new_governor); 202 out: 203 if (f_governor != NULL) 204 fclose(f_governor); 205 206 return ret; 207 } 208 209 int power_get_lcore_mapped_cpu_id(uint32_t lcore_id, uint32_t *cpu_id) 210 { 211 rte_cpuset_t lcore_cpus; 212 uint32_t cpu; 213 214 lcore_cpus = rte_lcore_cpuset(lcore_id); 215 if (CPU_COUNT(&lcore_cpus) != 1) { 216 POWER_LOG(ERR, 217 "Power library does not support lcore %u mapping to %u CPUs", 218 lcore_id, CPU_COUNT(&lcore_cpus)); 219 return -1; 220 } 221 222 for (cpu = 0; cpu < CPU_SETSIZE; cpu++) { 223 if (CPU_ISSET(cpu, &lcore_cpus)) 224 break; 225 } 226 *cpu_id = cpu; 227 228 return 0; 229 } 230