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