1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2020 Intel Corporation
11 #include <rte_string_fns.h>
13 #include "power_common.h"
15 #define POWER_SYSFILE_SCALING_DRIVER \
16 "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_driver"
17 #define POWER_SYSFILE_GOVERNOR \
18 "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_governor"
19 #define POWER_CONVERT_TO_DECIMAL 10
22 cpufreq_check_scaling_driver(const char *driver_name)
24 unsigned int lcore_id = 0; /* always check core 0 */
25 char readbuf[PATH_MAX];
31 * Check if scaling driver matches what we expect.
33 open_core_sysfs_file(&f, "r", POWER_SYSFILE_SCALING_DRIVER,
35 /* if there's no driver at all, bail out */
39 s = fgets(readbuf, sizeof(readbuf), f);
40 /* don't need it any more */
43 /* if we can't read it, consider unsupported */
47 /* when read from sysfs, driver name has an extra newline at the end */
48 end_idx = strnlen(readbuf, sizeof(readbuf));
49 if (end_idx > 0 && readbuf[end_idx - 1] == '\n') {
51 readbuf[end_idx] = '\0';
54 /* does the driver name match? */
55 if (strncmp(readbuf, driver_name, sizeof(readbuf)) != 0)
59 * We might have a situation where the driver is supported, but we don't
60 * have permissions to do frequency scaling. This error should not be
61 * handled here, so consider the system to support scaling for now.
67 open_core_sysfs_file(FILE **f, const char *mode, const char *format, ...)
69 char fullpath[PATH_MAX];
74 vsnprintf(fullpath, sizeof(fullpath), format, ap);
76 tmpf = fopen(fullpath, mode);
85 read_core_sysfs_u32(FILE *f, uint32_t *val)
91 s = fgets(buf, sizeof(buf), f);
95 /* fgets puts null terminator in, but do this just in case */
96 buf[BUFSIZ - 1] = '\0';
98 /* strip off any terminating newlines */
99 *strchrnul(buf, '\n') = '\0';
101 fval = strtoul(buf, NULL, POWER_CONVERT_TO_DECIMAL);
103 /* write the value */
110 read_core_sysfs_s(FILE *f, char *buf, unsigned int len)
114 s = fgets(buf, len, f);
118 /* fgets puts null terminator in, but do this just in case */
121 /* strip off any terminating newlines */
122 *strchrnul(buf, '\n') = '\0';
128 write_core_sysfs_s(FILE *f, const char *str)
132 ret = fseek(f, 0, SEEK_SET);
140 /* flush the output */
149 * It is to check the current scaling governor by reading sys file, and then
150 * set it into 'performance' if it is not by writing the sys file. The original
151 * governor will be saved for rolling back.
154 power_set_governor(unsigned int lcore_id, const char *new_governor,
155 char *orig_governor, size_t orig_governor_len)
157 FILE *f_governor = NULL;
161 open_core_sysfs_file(&f_governor, "rw+", POWER_SYSFILE_GOVERNOR,
163 if (f_governor == NULL) {
164 RTE_LOG(ERR, POWER, "failed to open %s\n",
165 POWER_SYSFILE_GOVERNOR);
169 ret = read_core_sysfs_s(f_governor, buf, sizeof(buf));
171 RTE_LOG(ERR, POWER, "Failed to read %s\n",
172 POWER_SYSFILE_GOVERNOR);
176 /* Save the original governor, if it was provided */
178 rte_strscpy(orig_governor, buf, orig_governor_len);
180 /* Check if current governor is already what we want */
181 if (strcmp(buf, new_governor) == 0) {
183 POWER_DEBUG_TRACE("Power management governor of lcore %u is "
184 "already %s\n", lcore_id, new_governor);
188 /* Write the new governor */
189 ret = write_core_sysfs_s(f_governor, new_governor);
191 RTE_LOG(ERR, POWER, "Failed to write %s\n",
192 POWER_SYSFILE_GOVERNOR);
197 RTE_LOG(INFO, POWER, "Power management governor of lcore %u has been "
198 "set to '%s' successfully\n", lcore_id, new_governor);
200 if (f_governor != NULL)