[PATCH] V2 devicetree/dt_sysinfo: Add OPAL reference compatible checks

Deb McLemore debmc at linux.vnet.ibm.com
Tue Jun 21 13:58:00 UTC 2016


We added a new device tree check for the OPAL compatible property.
We also added an OpenPOWER reference check to validate that the
machine model and device tree compatible property are a supported
match.  Future additions will add device tree hardware checks
(as applicable) to confirm that the device tree matches the topology of
the expected hardware configurations.

Signed-off-by: Deb McLemore <debmc at linux.vnet.ibm.com>
---
 .../arg-show-tests-full-0001.log                   |   3 +-
 src/devicetree/dt_base/dt_base.c                   |  82 +++++---
 src/devicetree/dt_sysinfo/dt_sysinfo.c             | 215 +++++++++++++++++----
 3 files changed, 237 insertions(+), 63 deletions(-)

diff --git a/fwts-test/arg-show-tests-full-0001/arg-show-tests-full-0001.log b/fwts-test/arg-show-tests-full-0001/arg-show-tests-full-0001.log
index 6784ed3..126c786 100644
--- a/fwts-test/arg-show-tests-full-0001/arg-show-tests-full-0001.log
+++ b/fwts-test/arg-show-tests-full-0001/arg-show-tests-full-0001.log
@@ -372,9 +372,10 @@ Batch tests:
   Check device tree presence
   Check device tree baseline validity
   Check device tree warnings
- dt_sysinfo      (2 tests):
+ dt_sysinfo      (3 tests):
   Check model property
   Check system-id property
+  Check OpenPOWER Reference compatible
  ebda            (1 test):
   Test EBDA is reserved in E820 table.
  ecdt            (1 test):
diff --git a/src/devicetree/dt_base/dt_base.c b/src/devicetree/dt_base/dt_base.c
index efb05fc..d9a5285 100644
--- a/src/devicetree/dt_base/dt_base.c
+++ b/src/devicetree/dt_base/dt_base.c
@@ -28,8 +28,9 @@
 static int dt_base_check_present(fwts_framework *fw)
 {
 	if (fw->fdt == NULL) {
-		fwts_failed(fw, LOG_LEVEL_HIGH, "DeviceTreeBaseAbsent",
-				"No device tree could be loaded");
+		fwts_failed(fw, LOG_LEVEL_HIGH,
+			"DeviceTreeBaseAbsent",
+			"No device tree could be loaded");
 		return FWTS_ERROR;
 	}
 
@@ -41,13 +42,18 @@ static int dt_base_check_valid(fwts_framework *fw)
 {
 	int rc;
 
-	if (fw->fdt == NULL)
-		return FWTS_ABORTED;
+	if (fw->fdt == NULL) {
+		fwts_failed(fw, LOG_LEVEL_HIGH,
+			"DeviceTreeBaseInvalid",
+			"No device tree could be loaded");
+		return FWTS_ERROR;
+	}
 
 	rc = fdt_check_header(fw->fdt);
 	if (rc != 0) {
-		fwts_failed(fw, LOG_LEVEL_HIGH, "DeviceTreeBaseInvalid",
-				"Device tree data is invalid");
+		fwts_failed(fw, LOG_LEVEL_HIGH,
+			"DeviceTreeBaseInvalid",
+			"Device tree data is invalid");
 		return FWTS_ERROR;
 	}
 
@@ -57,44 +63,56 @@ static int dt_base_check_valid(fwts_framework *fw)
 
 static int dt_base_check_warnings(fwts_framework *fw)
 {
-	int rc, status, in_fd, out_fd, ret = FWTS_ERROR;
+	int status = 0, in_fd = 0, out_fd = 0, ret = FWTS_ERROR;
 	ssize_t in_len, out_len;
 	const char *command;
 	char *output = NULL;
 	pid_t pid;
 
-	if (!fw->fdt)
-		return FWTS_ABORTED;
+	if (!fw->fdt) {
+		fwts_failed(fw, LOG_LEVEL_LOW,
+			"DTMissing",
+			"Device Tree is missing,"
+			" unable to continue without DT");
+		goto err;
+	}
 
 	command = "dtc -I dtb -O dtb -o /dev/null 2>&1";
-	rc = fwts_pipe_open_rw(command, &pid, &in_fd, &out_fd);
-	if (rc)
-		return FWTS_ABORTED;
+	if (fwts_pipe_open_rw(command, &pid, &in_fd, &out_fd)) {
+		fwts_failed(fw, LOG_LEVEL_HIGH,
+			"DTMissing",
+			"There was a problem obtaining the"
+			" device tree info,"
+			" unable to continue without DT data");
+		goto err;
+	}
 
 	in_len = fdt_totalsize(fw->fdt);
 
-	rc = fwts_pipe_readwrite(in_fd, fw->fdt, in_len,
-			out_fd, &output, &out_len);
-	if (rc) {
-		fwts_failed(fw, LOG_LEVEL_HIGH, "DeviceTreeBaseDTCPipe",
-				"failed to pipe data to dtc");
-		fwts_pipe_close2(in_fd, out_fd, pid);
-		return FWTS_ERROR;
+	if (fwts_pipe_readwrite(in_fd, fw->fdt, in_len,
+			out_fd, &output, &out_len)) {
+		fwts_failed(fw, LOG_LEVEL_HIGH,
+			"DeviceTreeBaseDTCPipe",
+			"failed to pipe data to dtc");
+		goto err;
 	}
 
 	status = fwts_pipe_close2(in_fd, out_fd, pid);
+	in_fd = out_fd = 0;
 
 	if (status) {
-		fwts_failed(fw, LOG_LEVEL_HIGH, "DeviceTreeBaseDTCFailed",
-				"dtc reports fatal device tree errors:\n%s\n",
-				output);
+		fwts_failed(fw, LOG_LEVEL_HIGH,
+			"DeviceTreeBaseDTCFailed",
+			"dtc reports fatal device tree errors:%s",
+			output);
 		goto err;
 	}
 
 	if (out_len > 0) {
-		fwts_failed(fw, LOG_LEVEL_MEDIUM, "DeviceTreeBaseDTCWarnings",
-				"dtc reports warnings from device tree:\n%s\n",
-				output);
+		fwts_failed(fw, LOG_LEVEL_MEDIUM,
+			"DeviceTreeBaseDTCWarnings",
+			"dtc reports warnings from device tree:%s",
+			output);
 		goto err;
 	}
 
@@ -103,14 +121,20 @@ static int dt_base_check_warnings(fwts_framework *fw)
 	ret = FWTS_OK;
 
 err:
-	free(output);
+	if (output)
+		free(output);
+	if (in_fd || out_fd)
+		fwts_pipe_close2(in_fd, out_fd, pid);
 	return ret;
 }
 
 static fwts_framework_minor_test dt_base_tests[] = {
-	{ dt_base_check_present,  "Check device tree presence" },
-	{ dt_base_check_valid,    "Check device tree baseline validity" },
-	{ dt_base_check_warnings, "Check device tree warnings" },
+	{ dt_base_check_present,
+		"Check device tree presence" },
+	{ dt_base_check_valid,
+		"Check device tree baseline validity" },
+	{ dt_base_check_warnings,
+		"Check device tree warnings" },
 	{ NULL, NULL },
 };
 
diff --git a/src/devicetree/dt_sysinfo/dt_sysinfo.c b/src/devicetree/dt_sysinfo/dt_sysinfo.c
index 593c496..477210a 100644
--- a/src/devicetree/dt_sysinfo/dt_sysinfo.c
+++ b/src/devicetree/dt_sysinfo/dt_sysinfo.c
@@ -26,19 +26,42 @@
 
 #include "fwts.h"
 
-static int check_property_printable(fwts_framework *fw, const char *name,
-		const char *buf, size_t len)
+static const char op_powernv[] = "ibm,powernv";
+
+static const char *firestone_models[] = {
+	"8335-GTA        ",
+	"8335-GTX        ",
+};
+
+static const char *garrison_models[] = {
+	"8335-GTB        ",
+};
+
+static struct reference_platform {
+	const char	*compatible;
+	const char	**models;
+	int		n_models;
+} openpower_reference_platforms[] = {
+	{"ibm,firestone", firestone_models,
+		FWTS_ARRAY_LEN(firestone_models)},
+	{"ibm,garrison", garrison_models,
+		FWTS_ARRAY_LEN(garrison_models)},
+};
+
+static int check_property_printable(fwts_framework *fw,
+	const char *name,
+	const char *buf,
+	size_t len)
 {
 	bool printable = true;
 	unsigned int i;
-	int rc;
 
 	/* we need at least one character plus a nul */
 	if (len < 2) {
-		fwts_failed(fw, LOG_LEVEL_LOW, "DTPrintablePropertyShort",
-				"property %s is too short", name);
-		rc = FWTS_ERROR;
-		goto out;
+		fwts_failed(fw, LOG_LEVEL_LOW,
+			"DTPrintablePropertyShort",
+			"property %s is too short", name);
+		return FWTS_ERROR;
 	}
 
 	/* check all characters are printable */
@@ -49,34 +72,42 @@ static int check_property_printable(fwts_framework *fw, const char *name,
 	}
 
 	if (!printable) {
-		fwts_failed(fw, LOG_LEVEL_LOW, "DTPrintablePropertyInvalid",
-				"property %s contains unprintable characters",
-				name);
-		rc = FWTS_ERROR;
-		goto out;
+		fwts_failed(fw, LOG_LEVEL_LOW,
+			"DTPrintablePropertyInvalid",
+			"property %s contains unprintable characters",
+			name);
+		return FWTS_ERROR;
 	}
 
 	/* check for a trailing nul */
 	if (buf[len-1] != '\0') {
-		fwts_failed(fw, LOG_LEVEL_LOW, "DTPrintablePropertyNoNul",
-				"property %s isn't nul-terminated", name);
-		rc = FWTS_ERROR;
-		goto out;
+		fwts_failed(fw, LOG_LEVEL_LOW,
+			"DTPrintablePropertyNoNul",
+			"property %s isn't nul-terminated", name);
+		return FWTS_ERROR;
 	}
 
-	rc = FWTS_OK;
+	fwts_log_info_verbatim(fw,
+		"DTPrintableProperty with a string"
+		" value of \"%s\" passed",
+		buf);
 
-out:
-	return rc;
+	return FWTS_OK;
 }
 
-static int dt_sysinfo_check_root_property(fwts_framework *fw, const char *name)
+static int dt_sysinfo_check_root_property(
+	fwts_framework *fw,
+	const char *name,
+	bool print_flag)
 {
-	int rc, node, len;
+	int node, len;
 	const char *buf;
 
-	if (!fw->fdt)
+	if (!fw->fdt) {
+		fwts_failed(fw, LOG_LEVEL_LOW, "DTMissing",
+			"Device Tree is missing, aborting");
 		return FWTS_ABORTED;
+	}
 
 	node = fdt_path_offset(fw->fdt, "/");
 	if (node < 0) {
@@ -87,33 +118,151 @@ static int dt_sysinfo_check_root_property(fwts_framework *fw, const char *name)
 
 	buf = fdt_getprop(fw->fdt, node, name, &len);
 	if (buf == NULL) {
-		fwts_failed(fw, LOG_LEVEL_LOW, "DTSyinfoPropertyMissing",
-				"can't read property %s: %s",
-				name, fdt_strerror(len));
+		fwts_failed(fw, LOG_LEVEL_LOW,
+			"DTSysinfoPropertyMissing",
+			"can't read property %s: %s",
+			name, fdt_strerror(len));
 		return FWTS_ERROR;
 	}
 
-	rc = check_property_printable(fw, name, buf, len);
+	if (print_flag) {
+		if (check_property_printable(fw, name, buf, len))
+			return FWTS_ERROR; /* failures logged prior */
+	}
 
-	if (rc == FWTS_OK)
-		fwts_passed(fw, "sysinfo property %s is valid", name);
+	fwts_passed(fw, "sysinfo property %s is valid", name);
 
-	return rc;
+	return FWTS_OK;
 }
 
 static int dt_sysinfo_check_model(fwts_framework *fw)
 {
-	return dt_sysinfo_check_root_property(fw, "model");
+	return dt_sysinfo_check_root_property(fw, "model", true);
 }
 
 static int dt_sysinfo_check_system_id(fwts_framework *fw)
 {
-	return dt_sysinfo_check_root_property(fw, "system-id");
+	return dt_sysinfo_check_root_property(fw, "system-id", true);
+}
+
+static int prd_fdt_stringlist_contains_last(const char *strlist,
+	int listlen,
+	const char *str)
+{
+	int len = strlen(str);
+	const char *p;
+
+	/* checking for either str only or last in string */
+	if (listlen < 2 ) /* need at least one byte plus nul */
+		return 0;
+
+	p = memrchr(strlist, '\0', listlen-1);
+	if (!p) {
+		if (memcmp(str, strlist, len+1) == 0)
+			return 1;
+	} else {
+		if (memcmp(str, p+1, len+1) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+static bool machine_matches_reference_model(fwts_framework *fw,
+	const char *compatible,
+	int compat_len,
+	const char *model)
+{
+	int i, j;
+	bool found = false;
+
+	for (i = 0;
+		i < (int)FWTS_ARRAY_LEN(openpower_reference_platforms);
+		i++) {
+		struct reference_platform *plat =
+			&openpower_reference_platforms[i];
+		if (prd_fdt_stringlist_contains_last(compatible,
+			compat_len, plat->compatible)) {
+			for (j = 0; j < plat->n_models; j++) {
+				if (!strcmp(model, plat->models[j])) {
+					fwts_log_info_verbatim(fw,
+			"Matched reference model, "
+			"device tree \"compatible\" is \"%s\" and "
+			"\"model\" is \"%s\"",
+			plat->compatible, model);
+					found = true;
+					break;
+				}
+			}
+		} else {
+			continue;
+		}
+		if (found)
+			break;
+	}
+	return found;
+}
+
+static int dt_sysinfo_check_ref_plat_compatible(fwts_framework *fw)
+{
+	int node, compat_len, model_len;
+	const char *model_buf, *compat_buf;
+
+	node = fdt_path_offset(fw->fdt, "/");
+	if (node < 0) {
+		fwts_failed(fw, LOG_LEVEL_HIGH, "DTRootNodeMissing",
+			"root device tree node is missing");
+		return FWTS_ERROR;
+	}
+	if (fdt_node_check_compatible(fw->fdt, node, op_powernv)) {
+		fwts_failed(fw, LOG_LEVEL_HIGH, "DTCompatibleMissing",
+			"DeviceTree failed validation, could not find"
+			" the \"compatible\" property of \"%s\" in the "
+			"root of the device tree", "ibm,powernv");
+		return FWTS_ERROR;
+	} else {
+		compat_buf = fdt_getprop(fw->fdt, node,
+				"compatible", &compat_len);
+		model_buf = fdt_getprop(fw->fdt, node,
+				"model", &model_len);
+
+		if (!model_buf || !compat_buf) {
+			fwts_failed(fw,LOG_LEVEL_HIGH,
+				"DTSysinfoPropertyMissing",
+				"can't read properties for OpenPOWER"
+				" Reference Compatible check");
+			return FWTS_ERROR;
+		}
+
+		if (machine_matches_reference_model(fw,
+				compat_buf,
+				compat_len,
+				model_buf)) {
+			fwts_passed(fw, "OpenPOWER Reference "
+				"Compatible passed");
+		} else {
+			fwts_failed(fw, LOG_LEVEL_HIGH,
+				"DTOpenPOWERReferenceFailed",
+			"Unable to find an OpenPOWER supported"
+			" match");
+			/* adding verbatim to show proper string */
+			fwts_log_info_verbatim(fw,
+			"Unable to find an OpenPOWER reference"
+			" match for \"%s\"", model_buf);
+			return FWTS_ERROR;
+		}
+	}
+
+	return FWTS_OK;
 }
 
 static fwts_framework_minor_test dt_sysinfo_tests[] = {
-	{ dt_sysinfo_check_model,	"Check model property" },
-	{ dt_sysinfo_check_system_id,	"Check system-id property" },
+	{ dt_sysinfo_check_model,
+		"Check model property" },
+	{ dt_sysinfo_check_system_id,
+		"Check system-id property" },
+	{ dt_sysinfo_check_ref_plat_compatible,
+		"Check OpenPOWER Reference compatible" },
 	{ NULL, NULL },
 };
 
-- 
1.8.3.1




More information about the fwts-devel mailing list