]> git.droids-corp.org - dpdk.git/commitdiff
power: add environment capability probing
authorAnatoly Burakov <anatoly.burakov@intel.com>
Fri, 19 Jun 2020 10:53:54 +0000 (11:53 +0100)
committerThomas Monjalon <thomas@monjalon.net>
Sat, 11 Jul 2020 11:31:16 +0000 (13:31 +0200)
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>
15 files changed:
lib/librte_power/Makefile
lib/librte_power/guest_channel.c
lib/librte_power/guest_channel.h
lib/librte_power/meson.build
lib/librte_power/power_acpi_cpufreq.c
lib/librte_power/power_acpi_cpufreq.h
lib/librte_power/power_common.c [new file with mode: 0644]
lib/librte_power/power_common.h
lib/librte_power/power_kvm_vm.c
lib/librte_power/power_kvm_vm.h
lib/librte_power/power_pstate_cpufreq.c
lib/librte_power/power_pstate_cpufreq.h
lib/librte_power/rte_power.c
lib/librte_power/rte_power.h
lib/librte_power/rte_power_version.map

index 087d643ee51458952040636ca0eb0a2376b58e90..3b067b615fcbd00130dfbb0558894253c4dc82ae 100644 (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
index b984d55bc893b07526024df6f7cf7ccd24099bd6..7b5926e5c45d03541bdc9ae26f708fb1bf3dab16 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright(c) 2010-2014 Intel Corporation
  */
 
+#include <glob.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 
 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)
 {
index 025961606c47b783422b9ae6c9cfd9442a74580a..e15db46fc78c5a8e3428b12d7237c5a642ceee65 100644 (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
index cdf08f6df39ddacc31e18f7f96266509fac03808..78c031c943ee5094b525d02a004a5ebf2bd8b782 100644 (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']
index f443fce69f5d9eb0f90e3fef36425a34205c211f..583815a07e9fe75c0053d2551206232895f91f42 100644 (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 @@ out:
        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)
 {
index 1af7416073b865612722a3a00125fa077e6dd2cf..038857b3a651dd3cdc80985c757fa4587301d4ed 100644 (file)
 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
diff --git a/lib/librte_power/power_common.c b/lib/librte_power/power_common.c
new file mode 100644 (file)
index 0000000..59023d9
--- /dev/null
@@ -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;
+}
index feeb5777b71c45487e393ed9fd096ae5a745ba94..fab3ca995abf1fca1e9ccbeb632f06b649103b2f 100644 (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_ */
index 2bb17beb173c7e0ad080c252afb5cf5959ccf7d7..409c3e03ab22959e4475b3b83c229467174c3396 100644 (file)
 
 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)
index 94d4aa121348fdaf0926f9d76fd20ec70e0faef7..73b4c82e573e9edda3165d2d6c62682dc47d272c 100644 (file)
 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.
  *
index 2d8a9499dcfcb01ac98089fea948aee5824adc37..2526441a4c0b16aa173651e36ea2e733af4de3b8 100644 (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 @@ out:
        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)
 {
index 6fd801881f2571d6b1e5646e43b3e674cb335812..0be0bd6b818054fceb13bc9b7f5ac3349842a816 100644 (file)
 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
index 6b7722727550014c738b46a54c3bc8b5f642a4ca..98eaba9154552327f3d8902ccc591d26d8c74db0 100644 (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)
 {
index 427058b8118cd9810fdd75622359e3adec9be29a..bbbde4dfb4f60989dfb1c0a7a0089fd9528070f5 100644 (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.
index 55a168f56e1f41074871ec14440a6dbdd74a8a75..00ee5753e291aeb6dcdc28bc5a29bfc47c5e38c8 100644 (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;