[PATCH v2] cpufreq: Add test cases to validate the frequency and pstate table
Shilpasri G Bhat
shilpa.bhat at linux.vnet.ibm.com
Mon May 2 13:03:36 UTC 2016
Add test case to parse CPU frequency and pstate table to check for
invalid entries that are beyond the specified minimum and maximum
limits.
Signed-off-by: Shilpasri G Bhat <shilpa.bhat at linux.vnet.ibm.com>
---
Changes from v1:
- Use libfdt to read device tree properties from fw->fdt instead of reading
them from sysfs files as suggested by Jeremy Kerr.
src/cpu/cpufreq/cpufreq.c | 124 ++++++++++++++++++++++++++++++++++++++
src/lib/include/fwts_devicetree.h | 22 +++++++
src/lib/src/fwts_devicetree.c | 34 +++++++++++
3 files changed, 180 insertions(+)
diff --git a/src/cpu/cpufreq/cpufreq.c b/src/cpu/cpufreq/cpufreq.c
index bdcadca..fe178c7 100644
--- a/src/cpu/cpufreq/cpufreq.c
+++ b/src/cpu/cpufreq/cpufreq.c
@@ -40,6 +40,10 @@
#include <ctype.h>
#include <inttypes.h>
+#if FWTS_HAS_DEVICETREE
+#include <libfdt.h>
+#endif
+
#define FWTS_CPU_PATH "/sys/devices/system/cpu"
#define MAX_FREQS 256
@@ -393,6 +397,122 @@ static int cpufreq_test_cpu_performance(fwts_framework *fw)
return FWTS_OK;
}
+static int cpufreq_test_frequency_limits(fwts_framework *fw)
+{
+ char path[PATH_MAX];
+ int min, max, i;
+ bool ok = true;
+
+ cpu_mkpath(path, sizeof(path), &cpus[0], "cpuinfo_min_freq");
+ if (fwts_get_int(path, &min) != FWTS_OK) {
+ fwts_log_warning(fw, "Failed to read the minimum CPU frequency %s",
+ path);
+ return FWTS_ERROR;
+ }
+
+ cpu_mkpath(path, sizeof(path), &cpus[0], "cpuinfo_max_freq");
+ if (fwts_get_int(path, &max) != FWTS_OK) {
+ fwts_log_warning(fw, "Failed to read the maximum CPU frequency %s",
+ path);
+ return FWTS_ERROR;
+ }
+
+ for (i = 0; i < cpus[0].n_freqs; i++) {
+ if (cpus[0].freqs[i].Hz > (uint64_t)max) {
+ fwts_log_warning(fw, "%s is greater than max frequency %s",
+ hz_to_human(cpus[0].freqs[i].Hz),
+ hz_to_human(max));
+ ok = false;
+ }
+ if (cpus[0].freqs[i].Hz < (uint64_t)min) {
+ fwts_log_warning(fw, "%s is lesser than min frequency %s",
+ hz_to_human(cpus[0].freqs[i].Hz),
+ hz_to_human(min));
+ ok = false;
+ }
+ }
+ if (ok)
+ fwts_passed(fw, "CPU frequencies are within the min and max limits");
+ else
+ fwts_failed(fw, LOG_LEVEL_MEDIUM, "CPUFreqLimitsTest",
+ "Contains frequencies beyond max and min limits");
+ return FWTS_OK;
+}
+
+#if FWTS_HAS_DEVICETREE
+static int cpufreq_test_pstate_limits(fwts_framework *fw)
+{
+ const char *power_mgt_path = "/ibm,opal/power-mgt/";
+ int pstate_min, pstate_max, pstates[MAX_FREQS], nr_pstates;
+ bool ok = true;
+ int offset, len, ret, i;
+
+ if (!fw->fdt) {
+ fwts_skipped(fw, "Device tree not found");
+ return FWTS_SKIP;
+ }
+
+ offset = fdt_path_offset(fw->fdt, power_mgt_path);
+ if (offset < 0) {
+ fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTNodeMissing",
+ "power management node is missing");
+ return FWTS_ERROR;
+ }
+
+ ret = fwts_dt_property_read_u32(fw->fdt, offset, "ibm,pstate-min",
+ &pstate_min);
+ if (ret != FWTS_OK) {
+ fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTPropertyReadError",
+ "Failed to read property ibm,pstate-min %s",
+ fdt_strerror(pstate_min));
+ return FWTS_ERROR;
+ }
+
+ ret = fwts_dt_property_read_u32(fw->fdt, offset, "ibm,pstate-max",
+ &pstate_max);
+ if (ret != FWTS_OK) {
+ fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTPropertyReadError",
+ "Failed to read property ibm,pstate-max %s",
+ fdt_strerror(pstate_max));
+ return FWTS_ERROR;
+ }
+
+ ret = fwts_dt_property_read_u32_arr(fw->fdt, offset, "ibm,pstate-ids",
+ pstates, &len);
+ if (ret != FWTS_OK) {
+ fwts_failed(fw, LOG_LEVEL_MEDIUM, "DTPropertyReadError",
+ "Failed to read property ibm,pstate-ids %s",
+ fdt_strerror(len));
+ return FWTS_ERROR;
+ }
+
+ nr_pstates = pstate_max - pstate_min;
+ if (len != nr_pstates)
+ fwts_log_warning(fw, "Wrong number of pstates. Expected %d pstates, but found %d pstates",
+ nr_pstates, len);
+
+ for (i = 0; i < nr_pstates; i++) {
+ if (pstates[i] > pstate_max) {
+ fwts_log_warning(fw, "Invalid Pstate id %d greater than max pstate %d",
+ pstates[i], pstate_max);
+ ok = false;
+ }
+ if (pstates[i] < pstate_min) {
+ fwts_log_warning(fw, "Invalid Pstate id %d lesser than min pstate %d",
+ pstates[i], pstate_min);
+ ok = false;
+ }
+ }
+
+ if (ok)
+ fwts_passed(fw, "CPU pstates are within the min and max limits");
+ else
+ fwts_failed(fw, LOG_LEVEL_MEDIUM, "CPUPstateLimitsTest",
+ "Contains pstates beyond max and min limits");
+ return FWTS_OK;
+}
+#endif
+
static int sw_tests_possible(fwts_framework *fw)
{
int i, online_cpus = 0;
@@ -861,6 +981,10 @@ static fwts_framework_minor_test cpufreq_tests[] = {
{ cpufreq_test_sw_any, "CPU frequency SW_ANY control" },
{ cpufreq_test_sw_all, "CPU frequency SW_ALL control" },
{ cpufreq_test_cpu_performance, "CPU frequency performance tests." },
+ { cpufreq_test_frequency_limits, "CPU frequency limits test" },
+#if FWTS_HAS_DEVICETREE
+ { cpufreq_test_pstate_limits, "CPU Pstate limits test (device_tree)" },
+#endif
{ NULL, NULL }
};
diff --git a/src/lib/include/fwts_devicetree.h b/src/lib/include/fwts_devicetree.h
index 7c67dc5..0299b64 100644
--- a/src/lib/include/fwts_devicetree.h
+++ b/src/lib/include/fwts_devicetree.h
@@ -31,6 +31,10 @@
#if FWTS_HAS_DEVICETREE
int fwts_devicetree_read(fwts_framework *fwts);
+int fwts_dt_property_read_u32(void *fdt, int offset, const char *pname,
+ int *value);
+int fwts_dt_property_read_u32_arr(void *fdt, int offset, const char *pname,
+ int *value, int *len);
#else /* !FWTS_HAS_DEVICETREE */
static inline int fwts_devicetree_read(fwts_framework *fwts
@@ -38,6 +42,24 @@ static inline int fwts_devicetree_read(fwts_framework *fwts
{
return FWTS_OK;
}
+
+static inline int fwts_dt_property_read_u32(void *fdt __attribute__((unused)),
+ int offset __attribute__((unused)),
+ const char *pname __attribute__((unused)),
+ int *value __attribute__((unused)))
+{
+ return FWTS_OK;
+}
+
+static inline int fwts_dt_property_read_u32_arr(void *fdt
+ __attribute__((unused)),
+ int offset __attribute__((unused)),
+ const char *pname __attribute__((unused)),
+ int *value __attribute__((unused)),
+ int *len __attribute__((unused)))
+{
+ return FWTS_OK;
+}
#endif
#endif
diff --git a/src/lib/src/fwts_devicetree.c b/src/lib/src/fwts_devicetree.c
index baa4e6b..b8ef55f 100644
--- a/src/lib/src/fwts_devicetree.c
+++ b/src/lib/src/fwts_devicetree.c
@@ -20,6 +20,7 @@
#define _GNU_SOURCE
#include <stdio.h>
+#include <libfdt.h>
#include "fwts.h"
@@ -64,3 +65,36 @@ int fwts_devicetree_read(fwts_framework *fwts)
return FWTS_OK;
}
+int fwts_dt_property_read_u32(void *fdt, int offset, const char *pname,
+ int *value)
+{
+ int len;
+ const int *buf;
+
+ buf = fdt_getprop(fdt, offset, pname, &len);
+ if (buf == NULL) {
+ *value = len;
+ return FWTS_ERROR;
+ }
+ *value = be32toh(*buf);
+ return FWTS_OK;
+}
+
+int fwts_dt_property_read_u32_arr(void *fdt, int offset, const char *pname,
+ int *value, int *len)
+{
+ int i;
+ const int *buf;
+
+ buf = fdt_getprop(fdt, offset, pname, len);
+ if (buf == NULL) {
+ *value = *len;
+ return FWTS_ERROR;
+ }
+
+ *len = *len / sizeof(int);
+ *len = *len - 1;
+ for (i = 0; i < *len; i++)
+ value[i] = be32toh(buf[i]);
+ return FWTS_OK;
+}
--
1.9.1
More information about the fwts-devel
mailing list