xref: /dpdk/lib/power/power_common.c (revision 6f987b594fa6751b49769755fe1d1bf9f9d15ac4)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2020 Intel Corporation
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson 
599a2dd95SBruce Richardson #include <limits.h>
606cffd46SAnatoly Burakov #include <stdlib.h>
799a2dd95SBruce Richardson #include <stdio.h>
899a2dd95SBruce Richardson #include <string.h>
999a2dd95SBruce Richardson 
1006cffd46SAnatoly Burakov #include <rte_log.h>
1106cffd46SAnatoly Burakov #include <rte_string_fns.h>
125c9b07eeSSivaprasad Tummala #include <rte_lcore.h>
1306cffd46SAnatoly Burakov 
1499a2dd95SBruce Richardson #include "power_common.h"
1599a2dd95SBruce Richardson 
16*6f987b59SSivaprasad Tummala RTE_LOG_REGISTER_DEFAULT(rte_power_logtype, INFO);
178bae59edSStephen Hemminger 
1899a2dd95SBruce Richardson #define POWER_SYSFILE_SCALING_DRIVER   \
1999a2dd95SBruce Richardson 		"/sys/devices/system/cpu/cpu%u/cpufreq/scaling_driver"
2006cffd46SAnatoly Burakov #define POWER_SYSFILE_GOVERNOR  \
2106cffd46SAnatoly Burakov 		"/sys/devices/system/cpu/cpu%u/cpufreq/scaling_governor"
2206cffd46SAnatoly Burakov #define POWER_CONVERT_TO_DECIMAL 10
2399a2dd95SBruce Richardson 
2499a2dd95SBruce Richardson int
2599a2dd95SBruce Richardson cpufreq_check_scaling_driver(const char *driver_name)
2699a2dd95SBruce Richardson {
2799a2dd95SBruce Richardson 	unsigned int lcore_id = 0; /* always check core 0 */
2899a2dd95SBruce Richardson 	char readbuf[PATH_MAX];
2999a2dd95SBruce Richardson 	size_t end_idx;
3099a2dd95SBruce Richardson 	char *s;
3199a2dd95SBruce Richardson 	FILE *f;
3299a2dd95SBruce Richardson 
3399a2dd95SBruce Richardson 	/*
3499a2dd95SBruce Richardson 	 * Check if scaling driver matches what we expect.
3599a2dd95SBruce Richardson 	 */
3606cffd46SAnatoly Burakov 	open_core_sysfs_file(&f, "r", POWER_SYSFILE_SCALING_DRIVER,
3799a2dd95SBruce Richardson 			lcore_id);
3899a2dd95SBruce Richardson 	/* if there's no driver at all, bail out */
3999a2dd95SBruce Richardson 	if (f == NULL)
4099a2dd95SBruce Richardson 		return 0;
4199a2dd95SBruce Richardson 
4299a2dd95SBruce Richardson 	s = fgets(readbuf, sizeof(readbuf), f);
4399a2dd95SBruce Richardson 	/* don't need it any more */
4499a2dd95SBruce Richardson 	fclose(f);
4599a2dd95SBruce Richardson 
4699a2dd95SBruce Richardson 	/* if we can't read it, consider unsupported */
4799a2dd95SBruce Richardson 	if (s == NULL)
4899a2dd95SBruce Richardson 		return 0;
4999a2dd95SBruce Richardson 
5099a2dd95SBruce Richardson 	/* when read from sysfs, driver name has an extra newline at the end */
5199a2dd95SBruce Richardson 	end_idx = strnlen(readbuf, sizeof(readbuf));
5299a2dd95SBruce Richardson 	if (end_idx > 0 && readbuf[end_idx - 1] == '\n') {
5399a2dd95SBruce Richardson 		end_idx--;
5499a2dd95SBruce Richardson 		readbuf[end_idx] = '\0';
5599a2dd95SBruce Richardson 	}
5699a2dd95SBruce Richardson 
5799a2dd95SBruce Richardson 	/* does the driver name match? */
5899a2dd95SBruce Richardson 	if (strncmp(readbuf, driver_name, sizeof(readbuf)) != 0)
5999a2dd95SBruce Richardson 		return 0;
6099a2dd95SBruce Richardson 
6199a2dd95SBruce Richardson 	/*
6299a2dd95SBruce Richardson 	 * We might have a situation where the driver is supported, but we don't
6399a2dd95SBruce Richardson 	 * have permissions to do frequency scaling. This error should not be
6499a2dd95SBruce Richardson 	 * handled here, so consider the system to support scaling for now.
6599a2dd95SBruce Richardson 	 */
6699a2dd95SBruce Richardson 	return 1;
6799a2dd95SBruce Richardson }
6806cffd46SAnatoly Burakov 
6906cffd46SAnatoly Burakov int
7006cffd46SAnatoly Burakov open_core_sysfs_file(FILE **f, const char *mode, const char *format, ...)
7106cffd46SAnatoly Burakov {
7206cffd46SAnatoly Burakov 	char fullpath[PATH_MAX];
7306cffd46SAnatoly Burakov 	va_list ap;
7406cffd46SAnatoly Burakov 	FILE *tmpf;
7506cffd46SAnatoly Burakov 
7606cffd46SAnatoly Burakov 	va_start(ap, format);
7706cffd46SAnatoly Burakov 	vsnprintf(fullpath, sizeof(fullpath), format, ap);
7806cffd46SAnatoly Burakov 	va_end(ap);
7906cffd46SAnatoly Burakov 	tmpf = fopen(fullpath, mode);
8006cffd46SAnatoly Burakov 	*f = tmpf;
8106cffd46SAnatoly Burakov 	if (tmpf == NULL)
8206cffd46SAnatoly Burakov 		return -1;
8306cffd46SAnatoly Burakov 
8406cffd46SAnatoly Burakov 	return 0;
8506cffd46SAnatoly Burakov }
8606cffd46SAnatoly Burakov 
8706cffd46SAnatoly Burakov int
8806cffd46SAnatoly Burakov read_core_sysfs_u32(FILE *f, uint32_t *val)
8906cffd46SAnatoly Burakov {
9006cffd46SAnatoly Burakov 	char buf[BUFSIZ];
9106cffd46SAnatoly Burakov 	uint32_t fval;
9206cffd46SAnatoly Burakov 	char *s;
9306cffd46SAnatoly Burakov 
9406cffd46SAnatoly Burakov 	s = fgets(buf, sizeof(buf), f);
9506cffd46SAnatoly Burakov 	if (s == NULL)
9606cffd46SAnatoly Burakov 		return -1;
9706cffd46SAnatoly Burakov 
9806cffd46SAnatoly Burakov 	/* fgets puts null terminator in, but do this just in case */
9906cffd46SAnatoly Burakov 	buf[BUFSIZ - 1] = '\0';
10006cffd46SAnatoly Burakov 
10106cffd46SAnatoly Burakov 	/* strip off any terminating newlines */
10206cffd46SAnatoly Burakov 	*strchrnul(buf, '\n') = '\0';
10306cffd46SAnatoly Burakov 
10406cffd46SAnatoly Burakov 	fval = strtoul(buf, NULL, POWER_CONVERT_TO_DECIMAL);
10506cffd46SAnatoly Burakov 
10606cffd46SAnatoly Burakov 	/* write the value */
10706cffd46SAnatoly Burakov 	*val = fval;
10806cffd46SAnatoly Burakov 
10906cffd46SAnatoly Burakov 	return 0;
11006cffd46SAnatoly Burakov }
11106cffd46SAnatoly Burakov 
11206cffd46SAnatoly Burakov int
11306cffd46SAnatoly Burakov read_core_sysfs_s(FILE *f, char *buf, unsigned int len)
11406cffd46SAnatoly Burakov {
11506cffd46SAnatoly Burakov 	char *s;
11606cffd46SAnatoly Burakov 
11706cffd46SAnatoly Burakov 	s = fgets(buf, len, f);
11806cffd46SAnatoly Burakov 	if (s == NULL)
11906cffd46SAnatoly Burakov 		return -1;
12006cffd46SAnatoly Burakov 
12106cffd46SAnatoly Burakov 	/* fgets puts null terminator in, but do this just in case */
12206cffd46SAnatoly Burakov 	buf[len - 1] = '\0';
12306cffd46SAnatoly Burakov 
12406cffd46SAnatoly Burakov 	/* strip off any terminating newlines */
12506cffd46SAnatoly Burakov 	*strchrnul(buf, '\n') = '\0';
12606cffd46SAnatoly Burakov 
12706cffd46SAnatoly Burakov 	return 0;
12806cffd46SAnatoly Burakov }
12906cffd46SAnatoly Burakov 
13006cffd46SAnatoly Burakov int
13106cffd46SAnatoly Burakov write_core_sysfs_s(FILE *f, const char *str)
13206cffd46SAnatoly Burakov {
13306cffd46SAnatoly Burakov 	int ret;
13406cffd46SAnatoly Burakov 
13506cffd46SAnatoly Burakov 	ret = fseek(f, 0, SEEK_SET);
13606cffd46SAnatoly Burakov 	if (ret != 0)
13706cffd46SAnatoly Burakov 		return -1;
13806cffd46SAnatoly Burakov 
13906cffd46SAnatoly Burakov 	ret = fputs(str, f);
14006cffd46SAnatoly Burakov 	if (ret < 0)
14106cffd46SAnatoly Burakov 		return -1;
14206cffd46SAnatoly Burakov 
14306cffd46SAnatoly Burakov 	/* flush the output */
14406cffd46SAnatoly Burakov 	ret = fflush(f);
14506cffd46SAnatoly Burakov 	if (ret != 0)
14606cffd46SAnatoly Burakov 		return -1;
14706cffd46SAnatoly Burakov 
14806cffd46SAnatoly Burakov 	return 0;
14906cffd46SAnatoly Burakov }
15006cffd46SAnatoly Burakov 
15106cffd46SAnatoly Burakov /**
15206cffd46SAnatoly Burakov  * It is to check the current scaling governor by reading sys file, and then
15306cffd46SAnatoly Burakov  * set it into 'performance' if it is not by writing the sys file. The original
15406cffd46SAnatoly Burakov  * governor will be saved for rolling back.
15506cffd46SAnatoly Burakov  */
15606cffd46SAnatoly Burakov int
15706cffd46SAnatoly Burakov power_set_governor(unsigned int lcore_id, const char *new_governor,
15806cffd46SAnatoly Burakov 		char *orig_governor, size_t orig_governor_len)
15906cffd46SAnatoly Burakov {
16006cffd46SAnatoly Burakov 	FILE *f_governor = NULL;
16106cffd46SAnatoly Burakov 	int ret = -1;
16206cffd46SAnatoly Burakov 	char buf[BUFSIZ];
16306cffd46SAnatoly Burakov 
16406cffd46SAnatoly Burakov 	open_core_sysfs_file(&f_governor, "rw+", POWER_SYSFILE_GOVERNOR,
16506cffd46SAnatoly Burakov 			lcore_id);
16606cffd46SAnatoly Burakov 	if (f_governor == NULL) {
167ae67895bSDavid Marchand 		POWER_LOG(ERR, "failed to open %s",
16806cffd46SAnatoly Burakov 				POWER_SYSFILE_GOVERNOR);
16906cffd46SAnatoly Burakov 		goto out;
17006cffd46SAnatoly Burakov 	}
17106cffd46SAnatoly Burakov 
17206cffd46SAnatoly Burakov 	ret = read_core_sysfs_s(f_governor, buf, sizeof(buf));
17306cffd46SAnatoly Burakov 	if (ret < 0) {
174ae67895bSDavid Marchand 		POWER_LOG(ERR, "Failed to read %s",
17506cffd46SAnatoly Burakov 				POWER_SYSFILE_GOVERNOR);
17606cffd46SAnatoly Burakov 		goto out;
17706cffd46SAnatoly Burakov 	}
17806cffd46SAnatoly Burakov 
17906cffd46SAnatoly Burakov 	/* Save the original governor, if it was provided */
18006cffd46SAnatoly Burakov 	if (orig_governor)
18106cffd46SAnatoly Burakov 		rte_strscpy(orig_governor, buf, orig_governor_len);
18206cffd46SAnatoly Burakov 
18306cffd46SAnatoly Burakov 	/* Check if current governor is already what we want */
18406cffd46SAnatoly Burakov 	if (strcmp(buf, new_governor) == 0) {
18506cffd46SAnatoly Burakov 		ret = 0;
1860e21c7c0SDavid Marchand 		POWER_DEBUG_LOG("Power management governor of lcore %u is "
1870e21c7c0SDavid Marchand 				"already %s", lcore_id, new_governor);
18806cffd46SAnatoly Burakov 		goto out;
18906cffd46SAnatoly Burakov 	}
19006cffd46SAnatoly Burakov 
19106cffd46SAnatoly Burakov 	/* Write the new governor */
19206cffd46SAnatoly Burakov 	ret = write_core_sysfs_s(f_governor, new_governor);
19306cffd46SAnatoly Burakov 	if (ret < 0) {
194ae67895bSDavid Marchand 		POWER_LOG(ERR, "Failed to write %s",
19506cffd46SAnatoly Burakov 				POWER_SYSFILE_GOVERNOR);
19606cffd46SAnatoly Burakov 		goto out;
19706cffd46SAnatoly Burakov 	}
19806cffd46SAnatoly Burakov 
19906cffd46SAnatoly Burakov 	ret = 0;
200ae67895bSDavid Marchand 	POWER_LOG(INFO, "Power management governor of lcore %u has been "
201ae67895bSDavid Marchand 			"set to '%s' successfully", lcore_id, new_governor);
20206cffd46SAnatoly Burakov out:
20306cffd46SAnatoly Burakov 	if (f_governor != NULL)
20406cffd46SAnatoly Burakov 		fclose(f_governor);
20506cffd46SAnatoly Burakov 
20606cffd46SAnatoly Burakov 	return ret;
20706cffd46SAnatoly Burakov }
2085c9b07eeSSivaprasad Tummala 
2095c9b07eeSSivaprasad Tummala int power_get_lcore_mapped_cpu_id(uint32_t lcore_id, uint32_t *cpu_id)
2105c9b07eeSSivaprasad Tummala {
2115c9b07eeSSivaprasad Tummala 	rte_cpuset_t lcore_cpus;
2125c9b07eeSSivaprasad Tummala 	uint32_t cpu;
2135c9b07eeSSivaprasad Tummala 
2145c9b07eeSSivaprasad Tummala 	lcore_cpus = rte_lcore_cpuset(lcore_id);
2155c9b07eeSSivaprasad Tummala 	if (CPU_COUNT(&lcore_cpus) != 1) {
2165c9b07eeSSivaprasad Tummala 		POWER_LOG(ERR,
2175c9b07eeSSivaprasad Tummala 			"Power library does not support lcore %u mapping to %u CPUs",
2185c9b07eeSSivaprasad Tummala 			lcore_id, CPU_COUNT(&lcore_cpus));
2195c9b07eeSSivaprasad Tummala 		return -1;
2205c9b07eeSSivaprasad Tummala 	}
2215c9b07eeSSivaprasad Tummala 
2225c9b07eeSSivaprasad Tummala 	for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
2235c9b07eeSSivaprasad Tummala 		if (CPU_ISSET(cpu, &lcore_cpus))
2245c9b07eeSSivaprasad Tummala 			break;
2255c9b07eeSSivaprasad Tummala 	}
2265c9b07eeSSivaprasad Tummala 	*cpu_id = cpu;
2275c9b07eeSSivaprasad Tummala 
2285c9b07eeSSivaprasad Tummala 	return 0;
2295c9b07eeSSivaprasad Tummala }
230