[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