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