@@ -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
@@ -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)
{
@@ -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
@@ -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']
@@ -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)
{
@@ -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
new file mode 100644
@@ -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;
+}
@@ -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_ */
@@ -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)
@@ -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.
*
@@ -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)
{
@@ -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
@@ -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)
{
@@ -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.
@@ -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;