power: add environment capability probing

Currently, there is no way to know if the power management env is
supported without trying to initialize it. The init API also does
not distinguish between failure due to some error and failure due to
power management not being available on the platform in the first
place.

Thus, add an API that provides capability of probing support for a
specific power management API.

Suggested-by: Jerin Jacob <jerinj@marvell.com>
Signed-off-by: Anatoly Burakov <anatoly.burakov@intel.com>
This commit is contained in:
Anatoly Burakov 2020-06-19 11:53:54 +01:00 committed by Thomas Monjalon
parent e0194feb32
commit 20ab67608a
15 changed files with 181 additions and 1 deletions

View file

@ -16,6 +16,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_POWER) := rte_power.c power_acpi_cpufreq.c
SRCS-$(CONFIG_RTE_LIBRTE_POWER) += power_kvm_vm.c guest_channel.c
SRCS-$(CONFIG_RTE_LIBRTE_POWER) += rte_power_empty_poll.c
SRCS-$(CONFIG_RTE_LIBRTE_POWER) += power_pstate_cpufreq.c
SRCS-$(CONFIG_RTE_LIBRTE_POWER) += power_common.c
# install this header file
SYMLINK-$(CONFIG_RTE_LIBRTE_POWER)-include := rte_power.h rte_power_empty_poll.h

View file

@ -2,6 +2,7 @@
* Copyright(c) 2010-2014 Intel Corporation
*/
#include <glob.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@ -25,6 +26,31 @@
static int global_fds[RTE_MAX_LCORE] = { [0 ... RTE_MAX_LCORE-1] = -1 };
int
guest_channel_host_check_exists(const char *path)
{
char glob_path[PATH_MAX];
glob_t g;
int ret;
/* we cannot know in advance which cores have VM channels, so glob */
snprintf(glob_path, PATH_MAX, "%s.*", path);
ret = glob(glob_path, GLOB_NOSORT, NULL, &g);
if (ret != 0) {
/* couldn't read anything */
ret = 0;
goto out;
}
/* do we have at least one match? */
ret = g.gl_pathc > 0;
out:
globfree(&g);
return ret;
}
int
guest_channel_host_connect(const char *path, unsigned int lcore_id)
{

View file

@ -10,6 +10,18 @@ extern "C" {
#include <channel_commands.h>
/**
* Check if any Virtio-Serial VM end-points exist in path.
*
* @param path
* The path to the serial device on the filesystem
*
* @return
* - 1 if at least one potential end-point found.
* - 0 if no end-points found.
*/
int guest_channel_host_check_exists(const char *path);
/**
* Connect to the Virtio-Serial VM end-point located in path. It is
* thread safe for unique lcore_ids. This function must be only called once from

View file

@ -8,6 +8,7 @@ endif
sources = files('rte_power.c', 'power_acpi_cpufreq.c',
'power_kvm_vm.c', 'guest_channel.c',
'rte_power_empty_poll.c',
'power_pstate_cpufreq.c')
'power_pstate_cpufreq.c',
'power_common.c')
headers = files('rte_power.h','rte_power_empty_poll.h')
deps += ['timer']

View file

@ -59,6 +59,7 @@
"/sys/devices/system/cpu/cpu%u/cpufreq/scaling_available_frequencies"
#define POWER_SYSFILE_SETSPEED \
"/sys/devices/system/cpu/cpu%u/cpufreq/scaling_setspeed"
#define POWER_ACPI_DRIVER "acpi-cpufreq"
/*
* MSR related
@ -289,6 +290,12 @@ power_init_for_setting_freq(struct rte_power_info *pi)
return -1;
}
int
power_acpi_cpufreq_check_supported(void)
{
return cpufreq_check_scaling_driver(POWER_ACPI_DRIVER);
}
int
power_acpi_cpufreq_init(unsigned int lcore_id)
{

View file

@ -20,6 +20,16 @@
extern "C" {
#endif
/**
* Check if ACPI power management is supported.
*
* @return
* - 1 if supported
* - 0 if unsupported
* - -1 if error, with rte_errno indicating reason for error.
*/
int power_acpi_cpufreq_check_supported(void);
/**
* Initialize power management for a specific lcore. It will check and set the
* governor to userspace for the lcore, get the available frequencies, and

View file

@ -0,0 +1,52 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2020 Intel Corporation
*/
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include "power_common.h"
#define POWER_SYSFILE_SCALING_DRIVER \
"/sys/devices/system/cpu/cpu%u/cpufreq/scaling_driver"
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];
char *s;
FILE *f;
/*
* Check if scaling driver matches what we expect.
*/
snprintf(fullpath, sizeof(fullpath), POWER_SYSFILE_SCALING_DRIVER,
lcore_id);
f = fopen(fullpath, "r");
/* if there's no driver at all, bail out */
if (f == NULL)
return 0;
s = fgets(readbuf, sizeof(readbuf), f);
/* don't need it any more */
fclose(f);
/* if we can't read it, consider unsupported */
if (s == NULL)
return 0;
/* does the driver name match? */
if (strncmp(readbuf, driver_name, sizeof(readbuf)) != 0)
return 0;
/*
* We might have a situation where the driver is supported, but we don't
* have permissions to do frequency scaling. This error should not be
* handled here, so consider the system to support scaling for now.
*/
return 1;
}

View file

@ -7,4 +7,7 @@
#define RTE_POWER_INVALID_FREQ_INDEX (~0)
/* check if scaling driver matches one we want */
int cpufreq_check_scaling_driver(const char *driver);
#endif /* _POWER_COMMON_H_ */

View file

@ -15,6 +15,11 @@
static struct channel_packet pkt[RTE_MAX_LCORE];
int
power_kvm_vm_check_supported(void)
{
return guest_channel_host_check_exists(FD_PATH);
}
int
power_kvm_vm_init(unsigned int lcore_id)

View file

@ -20,6 +20,16 @@
extern "C" {
#endif
/**
* Check if KVM power management is supported.
*
* @return
* - 1 if supported
* - 0 if unsupported
* - -1 if error, with rte_errno indicating reason for error.
*/
int power_kvm_vm_check_supported(void);
/**
* Initialize power management for a specific lcore.
*

View file

@ -71,6 +71,7 @@
"/sys/devices/system/cpu/cpu%u/cpufreq/cpuinfo_min_freq"
#define POWER_SYSFILE_BASE_FREQ \
"/sys/devices/system/cpu/cpu%u/cpufreq/base_frequency"
#define POWER_PSTATE_DRIVER "intel_pstate"
#define POWER_MSR_PATH "/dev/cpu/%u/msr"
/*
@ -531,6 +532,12 @@ power_get_available_freqs(struct pstate_power_info *pi)
return ret;
}
int
power_pstate_cpufreq_check_supported(void)
{
return cpufreq_check_scaling_driver(POWER_PSTATE_DRIVER);
}
int
power_pstate_cpufreq_init(unsigned int lcore_id)
{

View file

@ -20,6 +20,16 @@
extern "C" {
#endif
/**
* Check if pstate power management is supported.
*
* @return
* - 1 if supported
* - 0 if unsupported
* - -1 if error, with rte_errno indicating reason for error.
*/
int power_pstate_cpufreq_check_supported(void);
/**
* Initialize power management for a specific lcore. It will check and set the
* governor to performance for the lcore, get the available frequencies, and

View file

@ -2,6 +2,7 @@
* Copyright(c) 2010-2014 Intel Corporation
*/
#include <rte_errno.h>
#include <rte_spinlock.h>
#include "rte_power.h"
@ -43,6 +44,22 @@ reset_power_function_ptrs(void)
rte_power_get_capabilities = NULL;
}
int
rte_power_check_env_supported(enum power_management_env env)
{
switch (env) {
case PM_ENV_ACPI_CPUFREQ:
return power_acpi_cpufreq_check_supported();
case PM_ENV_PSTATE_CPUFREQ:
return power_pstate_cpufreq_check_supported();
case PM_ENV_KVM_VM:
return power_kvm_vm_check_supported();
default:
rte_errno = EINVAL;
return -1;
}
}
int
rte_power_set_env(enum power_management_env env)
{

View file

@ -23,6 +23,24 @@ extern "C" {
enum power_management_env {PM_ENV_NOT_SET, PM_ENV_ACPI_CPUFREQ, PM_ENV_KVM_VM,
PM_ENV_PSTATE_CPUFREQ};
/**
* @warning
* @b EXPERIMENTAL: this API may change, or be removed, without prior notice
*
* Check if a specific power management environment type is supported on a
* currently running system.
*
* @param env
* The environment type to check support for.
*
* @return
* - 1 if supported
* - 0 if unsupported
* - -1 if error, with rte_errno indicating reason for error.
*/
__rte_experimental
int rte_power_check_env_supported(enum power_management_env env);
/**
* Set the default power management implementation. If this is not called prior
* to rte_power_init(), then auto-detect of the environment will take place.

View file

@ -26,6 +26,7 @@ EXPERIMENTAL {
global:
rte_empty_poll_detection;
rte_power_check_env_supported;
rte_power_empty_poll_stat_fetch;
rte_power_empty_poll_stat_free;
rte_power_empty_poll_stat_init;