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