X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Fpower%2Fpower_common.c;h=1e09facb863f29a723a74be4955638ec0fd5df5a;hb=080c84cde42fd06443b02f495cd0397a490a1f71;hp=67e3318ec71d69db06c09ea1011975e764f1a2d9;hpb=99a2dd955fba6e4cc23b77d590a033650ced9c45;p=dpdk.git diff --git a/lib/power/power_common.c b/lib/power/power_common.c index 67e3318ec7..1e09facb86 100644 --- a/lib/power/power_common.c +++ b/lib/power/power_common.c @@ -3,19 +3,25 @@ */ #include +#include #include #include +#include +#include + #include "power_common.h" #define POWER_SYSFILE_SCALING_DRIVER \ "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_driver" +#define POWER_SYSFILE_GOVERNOR \ + "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_governor" +#define POWER_CONVERT_TO_DECIMAL 10 int cpufreq_check_scaling_driver(const char *driver_name) { unsigned int lcore_id = 0; /* always check core 0 */ - char fullpath[PATH_MAX]; char readbuf[PATH_MAX]; size_t end_idx; char *s; @@ -24,10 +30,8 @@ cpufreq_check_scaling_driver(const char *driver_name) /* * Check if scaling driver matches what we expect. */ - snprintf(fullpath, sizeof(fullpath), POWER_SYSFILE_SCALING_DRIVER, + open_core_sysfs_file(&f, "r", POWER_SYSFILE_SCALING_DRIVER, lcore_id); - f = fopen(fullpath, "r"); - /* if there's no driver at all, bail out */ if (f == NULL) return 0; @@ -58,3 +62,143 @@ cpufreq_check_scaling_driver(const char *driver_name) */ return 1; } + +int +open_core_sysfs_file(FILE **f, const char *mode, const char *format, ...) +{ + char fullpath[PATH_MAX]; + va_list ap; + FILE *tmpf; + + va_start(ap, format); + vsnprintf(fullpath, sizeof(fullpath), format, ap); + va_end(ap); + tmpf = fopen(fullpath, mode); + *f = tmpf; + if (tmpf == NULL) + return -1; + + return 0; +} + +int +read_core_sysfs_u32(FILE *f, uint32_t *val) +{ + char buf[BUFSIZ]; + uint32_t fval; + char *s; + + s = fgets(buf, sizeof(buf), f); + if (s == NULL) + return -1; + + /* fgets puts null terminator in, but do this just in case */ + buf[BUFSIZ - 1] = '\0'; + + /* strip off any terminating newlines */ + *strchrnul(buf, '\n') = '\0'; + + fval = strtoul(buf, NULL, POWER_CONVERT_TO_DECIMAL); + + /* write the value */ + *val = fval; + + return 0; +} + +int +read_core_sysfs_s(FILE *f, char *buf, unsigned int len) +{ + char *s; + + s = fgets(buf, len, f); + if (s == NULL) + return -1; + + /* fgets puts null terminator in, but do this just in case */ + buf[len - 1] = '\0'; + + /* strip off any terminating newlines */ + *strchrnul(buf, '\n') = '\0'; + + return 0; +} + +int +write_core_sysfs_s(FILE *f, const char *str) +{ + int ret; + + ret = fseek(f, 0, SEEK_SET); + if (ret != 0) + return -1; + + ret = fputs(str, f); + if (ret < 0) + return -1; + + /* flush the output */ + ret = fflush(f); + if (ret != 0) + return -1; + + return 0; +} + +/** + * It is to check the current scaling governor by reading sys file, and then + * set it into 'performance' if it is not by writing the sys file. The original + * governor will be saved for rolling back. + */ +int +power_set_governor(unsigned int lcore_id, const char *new_governor, + char *orig_governor, size_t orig_governor_len) +{ + FILE *f_governor = NULL; + int ret = -1; + char buf[BUFSIZ]; + + open_core_sysfs_file(&f_governor, "rw+", POWER_SYSFILE_GOVERNOR, + lcore_id); + if (f_governor == NULL) { + RTE_LOG(ERR, POWER, "failed to open %s\n", + POWER_SYSFILE_GOVERNOR); + goto out; + } + + ret = read_core_sysfs_s(f_governor, buf, sizeof(buf)); + if (ret < 0) { + RTE_LOG(ERR, POWER, "Failed to read %s\n", + POWER_SYSFILE_GOVERNOR); + goto out; + } + + /* Save the original governor, if it was provided */ + if (orig_governor) + rte_strscpy(orig_governor, buf, orig_governor_len); + + /* Check if current governor is already what we want */ + if (strcmp(buf, new_governor) == 0) { + ret = 0; + POWER_DEBUG_TRACE("Power management governor of lcore %u is " + "already %s\n", lcore_id, new_governor); + goto out; + } + + /* Write the new governor */ + ret = write_core_sysfs_s(f_governor, new_governor); + if (ret < 0) { + RTE_LOG(ERR, POWER, "Failed to write %s\n", + POWER_SYSFILE_GOVERNOR); + goto out; + } + + ret = 0; + RTE_LOG(INFO, POWER, "Power management governor of lcore %u has been " + "set to '%s' successfully\n", lcore_id, new_governor); +out: + if (f_governor != NULL) + fclose(f_governor); + + return ret; +}