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