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 <rte_log.h>
11 : : #include <rte_string_fns.h>
12 : : #include <rte_lcore.h>
13 : :
14 : : #include "power_common.h"
15 : :
16 [ - + ]: 252 : 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 : 4 : 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 : 4 : open_core_sysfs_file(&f, "r", POWER_SYSFILE_SCALING_DRIVER,
37 : : lcore_id);
38 : : /* if there's no driver at all, bail out */
39 [ - + ]: 4 : if (f == NULL)
40 : : return 0;
41 : :
42 : : s = fgets(readbuf, sizeof(readbuf), f);
43 : : /* don't need it any more */
44 : 0 : fclose(f);
45 : :
46 : : /* if we can't read it, consider unsupported */
47 [ # # ]: 0 : if (s == NULL)
48 : : return 0;
49 : :
50 : : /* when read from sysfs, driver name has an extra newline at the end */
51 : 0 : end_idx = strnlen(readbuf, sizeof(readbuf));
52 [ # # # # ]: 0 : if (end_idx > 0 && readbuf[end_idx - 1] == '\n') {
53 : : end_idx--;
54 : 0 : readbuf[end_idx] = '\0';
55 : : }
56 : :
57 : : /* does the driver name match? */
58 [ # # ]: 0 : if (strncmp(readbuf, driver_name, sizeof(readbuf)) != 0)
59 : 0 : 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 : 4 : 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 : 4 : va_start(ap, format);
77 : : vsnprintf(fullpath, sizeof(fullpath), format, ap);
78 : 4 : va_end(ap);
79 : 4 : tmpf = fopen(fullpath, mode);
80 : 4 : *f = tmpf;
81 [ + - ]: 4 : if (tmpf == NULL)
82 : 4 : return -1;
83 : :
84 : : return 0;
85 : : }
86 : :
87 : : int
88 : 0 : 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 [ # # ]: 0 : if (s == NULL)
96 : : return -1;
97 : :
98 : : /* fgets puts null terminator in, but do this just in case */
99 : 0 : buf[BUFSIZ - 1] = '\0';
100 : :
101 : : /* strip off any terminating newlines */
102 : 0 : *strchrnul(buf, '\n') = '\0';
103 : :
104 : 0 : fval = strtoul(buf, NULL, POWER_CONVERT_TO_DECIMAL);
105 : :
106 : : /* write the value */
107 : 0 : *val = fval;
108 : :
109 : 0 : return 0;
110 : : }
111 : :
112 : : int
113 : 0 : read_core_sysfs_s(FILE *f, char *buf, unsigned int len)
114 : : {
115 : : char *s;
116 : :
117 [ # # ]: 0 : s = fgets(buf, len, f);
118 [ # # ]: 0 : if (s == NULL)
119 : : return -1;
120 : :
121 : : /* fgets puts null terminator in, but do this just in case */
122 : 0 : buf[len - 1] = '\0';
123 : :
124 : : /* strip off any terminating newlines */
125 : 0 : *strchrnul(buf, '\n') = '\0';
126 : :
127 : 0 : return 0;
128 : : }
129 : :
130 : : int
131 : 0 : write_core_sysfs_s(FILE *f, const char *str)
132 : : {
133 : : int ret;
134 : :
135 : 0 : ret = fseek(f, 0, SEEK_SET);
136 [ # # ]: 0 : if (ret != 0)
137 : : return -1;
138 : :
139 : 0 : ret = fputs(str, f);
140 [ # # ]: 0 : if (ret < 0)
141 : : return -1;
142 : :
143 : : /* flush the output */
144 : 0 : ret = fflush(f);
145 [ # # ]: 0 : if (ret != 0)
146 : 0 : 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 : 0 : power_set_governor(unsigned int lcore_id, const char *new_governor,
158 : : char *orig_governor, size_t orig_governor_len)
159 : : {
160 : 0 : FILE *f_governor = NULL;
161 : : int ret = -1;
162 : : char buf[BUFSIZ];
163 : :
164 : 0 : open_core_sysfs_file(&f_governor, "rw+", POWER_SYSFILE_GOVERNOR,
165 : : lcore_id);
166 [ # # ]: 0 : if (f_governor == NULL) {
167 : 0 : POWER_LOG(ERR, "failed to open %s",
168 : : POWER_SYSFILE_GOVERNOR);
169 : 0 : goto out;
170 : : }
171 : :
172 : 0 : ret = read_core_sysfs_s(f_governor, buf, sizeof(buf));
173 [ # # ]: 0 : if (ret < 0) {
174 : 0 : POWER_LOG(ERR, "Failed to read %s",
175 : : POWER_SYSFILE_GOVERNOR);
176 : 0 : goto out;
177 : : }
178 : :
179 : : /* Save the original governor, if it was provided */
180 [ # # ]: 0 : if (orig_governor)
181 : 0 : rte_strscpy(orig_governor, buf, orig_governor_len);
182 : :
183 : : /* Check if current governor is already what we want */
184 [ # # ]: 0 : 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 : 0 : goto out;
189 : : }
190 : :
191 : : /* Write the new governor */
192 : 0 : ret = write_core_sysfs_s(f_governor, new_governor);
193 [ # # ]: 0 : if (ret < 0) {
194 : 0 : POWER_LOG(ERR, "Failed to write %s",
195 : : POWER_SYSFILE_GOVERNOR);
196 : 0 : goto out;
197 : : }
198 : :
199 : : ret = 0;
200 : 0 : POWER_LOG(INFO, "Power management governor of lcore %u has been "
201 : : "set to '%s' successfully", lcore_id, new_governor);
202 : 0 : out:
203 [ # # ]: 0 : if (f_governor != NULL)
204 : 0 : fclose(f_governor);
205 : :
206 : 0 : return ret;
207 : : }
208 : :
209 : 0 : 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 : 0 : lcore_cpus = rte_lcore_cpuset(lcore_id);
215 [ # # ]: 0 : if (CPU_COUNT(&lcore_cpus) != 1) {
216 : 0 : POWER_LOG(ERR,
217 : : "Power library does not support lcore %u mapping to %u CPUs",
218 : : lcore_id, CPU_COUNT(&lcore_cpus));
219 : 0 : return -1;
220 : : }
221 : :
222 [ # # ]: 0 : for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
223 [ # # ]: 0 : if (CPU_ISSET(cpu, &lcore_cpus))
224 : : break;
225 : : }
226 : 0 : *cpu_id = cpu;
227 : :
228 : 0 : return 0;
229 : : }
|