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