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