[06/10] lib/device-tree: Parse package versions from ibm, firmware-versions

Message ID 20170825055940.24134-7-sam@mendozajonas.com
State New
Headers show

Commit Message

Samuel Mendoza-Jonas Aug. 25, 2017, 5:59 a.m.
On OpenPOWER platforms the current firmware versions are also advertised
via the 'ibm,firmware-versions' node in the device tree. These are
already split into name and version fields, so use this when available
rather than parsing the version strings from flash ourselves.

Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
---
 configure.ac                  |  12 +++--
 discover/hostboot.c           |  11 ++--
 discover/hostboot.h           |   5 +-
 discover/platform-powerpc.c   |   5 +-
 lib/Makefile.am               |  16 +++++-
 lib/device-tree/device-tree.c | 117 ++++++++++++++++++++++++++++++++++++++++++
 lib/device-tree/device-tree.h |  34 ++++++++++++
 7 files changed, 185 insertions(+), 15 deletions(-)
 create mode 100644 lib/device-tree/device-tree.c
 create mode 100644 lib/device-tree/device-tree.h

Patch

diff --git a/configure.ac b/configure.ac
index 77d6979..7a09a4a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -69,13 +69,17 @@  AC_CHECK_LIB([devmapper], [dm_task_create],
 
 AC_ARG_WITH([fdt],
 	AS_HELP_STRING([--without-fdt],
-		[Build without libfdt (default: no)]))
+		[Build without libfdt (default: no)])
+)
 
 AS_IF([test "x$with_fdt" != "xno"],
 	AC_CHECK_LIB([fdt], [fdt_check_header],
-		[FDT_LIBS=-lfdt; have_libfdt=yes]))
-
-AM_CONDITIONAL([HAVE_LIBFDT], [test x"$have_libfdt" = xyes])
+		[FDT_LIBS=-lfdt; have_libfdt=yes])
+)
+AS_IF([test "x$have_libfdt" = "xyes"],
+      [AC_DEFINE(FDT_SUPPORT, 1, [Enable libfdt support])]
+)
+AM_CONDITIONAL([HAVE_LIBFDT], [test x"$have_libfdt" = x"yes"])
 
 AC_CHECK_HEADERS([stdarg.h])
 AC_CHECK_HEADERS([varargs.h])
diff --git a/discover/hostboot.c b/discover/hostboot.c
index c63e363..54c6e0a 100644
--- a/discover/hostboot.c
+++ b/discover/hostboot.c
@@ -55,7 +55,7 @@  static int parse_hostboot_versions(void *ctx, char **strings,
 	return n_versions;
 }
 
-void hostboot_load_versions(struct system_info *info)
+int hostboot_load_versions(struct system_info *info)
 {
 	char **strings = NULL;
 	int n = 0;
@@ -63,13 +63,13 @@  void hostboot_load_versions(struct system_info *info)
 	n = flash_parse_version(info, &strings, true);
 	if (n < 0) {
 		pb_log("Failed to read platform versions for current side\n");
-		return;
+		return n;
 	}
 
 	n = parse_hostboot_versions(info, strings, n, &info->platform_primary);
 	if (n < 0) {
 		pb_log("Failed to parse platform versions for current side\n");
-		return;
+		return n;
 	}
 	info->n_primary = n;
 
@@ -80,16 +80,17 @@  void hostboot_load_versions(struct system_info *info)
 	n = flash_parse_version(info, &strings, false);
 	if (n < 0) {
 		pb_log("Failed to read platform versions for other side\n");
-		return;
+		return n;
 	}
 
 	n = parse_hostboot_versions(info, strings, n, &info->platform_other);
 	if (n < 0) {
 		pb_log("Failed to parse platform versions for current side\n");
-		return;
+		return n;
 	}
 	info->n_other = n;
 
 
 	talloc_free(strings);
+	return 0;
 }
diff --git a/discover/hostboot.h b/discover/hostboot.h
index cb1e497..dd85336 100644
--- a/discover/hostboot.h
+++ b/discover/hostboot.h
@@ -5,11 +5,12 @@ 
 #include <types/types.h>
 
 #ifdef MTD_SUPPORT
-void hostboot_load_versions(struct system_info *info);
+int hostboot_load_versions(struct system_info *info);
 #else
-static inline void hostboot_load_versions(struct system_info *info)
+static inline int hostboot_load_versions(struct system_info *info)
 {
 	(void)info;
+	return 0;
 }
 #endif
 #endif /* HOSTBOOT_H */
diff --git a/discover/platform-powerpc.c b/discover/platform-powerpc.c
index a4b955e..a2b3ba5 100644
--- a/discover/platform-powerpc.c
+++ b/discover/platform-powerpc.c
@@ -46,7 +46,7 @@  struct platform_powerpc {
 				bool persistent);
 	int 		(*set_os_boot_sensor)(
 				struct platform_powerpc *platform);
-	void		(*get_platform_versions)(struct system_info *info);
+	int		(*get_platform_versions)(struct system_info *info);
 };
 
 static const char *known_params[] = {
@@ -1339,7 +1339,8 @@  static int get_sysinfo(struct platform *p, struct system_info *sysinfo)
 		get_ipmi_bmc_versions(p, sysinfo);
 
 	if (platform->get_platform_versions)
-		platform->get_platform_versions(sysinfo);
+		if (platform->get_platform_versions(sysinfo))
+			pb_log("Failed to read platform versions\n");
 
 	return 0;
 }
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 6915314..429ce52 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -60,8 +60,12 @@  lib_libpbcore_la_SOURCES = \
 	lib/flash/flash.h \
 	lib/version/version.c \
 	lib/version/version.h \
+	lib/device-tree/device-tree.h
 	$(gpg_int_SOURCES)
 
+lib_libpbcore_la_LDFLAGS = \
+	$(AM_LDFLAGS)
+
 if ENABLE_MTD
 lib_libpbcore_la_SOURCES += \
 	lib/flash/flash.c
@@ -69,10 +73,18 @@  lib_libpbcore_la_SOURCES += \
 lib_libpbcore_la_CPPFLAGS += \
 	$(AM_CPPFLAGS)
 
-lib_libpbcore_la_LDFLAGS = \
-	$(AM_LDFLAGS) \
+lib_libpbcore_la_LDFLAGS += \
 	$(LIBFLASH_LIBS)
 
 lib_libpbcore_la_SOURCES += \
 	lib/flash/flash.c
 endif
+
+if HAVE_LIBFDT
+lib_libpbcore_la_SOURCES += \
+	lib/device-tree/device-tree.c
+
+lib_libpbcore_la_LDFLAGS += \
+	$(FDT_LIBS)
+
+endif
diff --git a/lib/device-tree/device-tree.c b/lib/device-tree/device-tree.c
new file mode 100644
index 0000000..bce884c
--- /dev/null
+++ b/lib/device-tree/device-tree.c
@@ -0,0 +1,117 @@ 
+/*
+ *  Copyright (C) 2017 IBM Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define _GNU_SOURCE
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <libfdt.h>
+
+#include <log/log.h>
+#include <talloc/talloc.h>
+#include <file/file.h>
+
+#include "device-tree.h"
+
+int device_tree_find_firmware_versions(struct system_info *info)
+{
+	const char *path = "/sys/firmware/fdt";
+	struct firmware_version *versions = NULL;
+	unsigned int n_versions = 0;
+	int rc, offset, plen, dtb_len = 0;
+	char *buf = NULL;
+	const char *name;
+	const fdt32_t *prop;
+	void *dtb;
+
+	rc = read_file(info, path, &buf, &dtb_len);
+	if (rc) {
+		pb_log("device-tree: Failed to read dtb: %m\n");
+		return rc;
+	}
+
+	rc = fdt_check_header(buf);
+	if (rc) {
+		pb_log("device-tree: invalid dtb\n");
+		return rc;
+	}
+
+	if (dtb_len != (int)fdt_totalsize(buf)) {
+		pb_log("device-tree: dtb size mismatch\n");
+		dtb_len = fdt_totalsize(buf);
+	}
+
+	dtb = talloc_array(info, char, dtb_len);
+	if (!dtb) {
+		pb_log("Failed to allocate dtb\n");
+		return -1;
+	}
+
+	fdt_open_into(buf, dtb, dtb_len);
+
+	offset = fdt_subnode_offset(dtb, 0, "ibm,firmware-versions");
+	if (offset < 0) {
+		pb_log("Could not find ibm,firmware-versions node\n");
+		goto out;
+	}
+
+	offset = fdt_first_property_offset(dtb, offset);
+	if (offset < 0) {
+		pb_log("Could not find first version property\n");
+		goto out;
+	}
+
+	while (offset > 0) {
+		prop = fdt_getprop_by_offset(dtb, offset, &name, &plen);
+		if (!prop) {
+			pb_log("No property at %d?\n", offset);
+			continue;
+		}
+		if (strncmp(name, "phandle", strlen("phandle")) != 0) {
+			pb_log("\t%s - %s\n", name, (const char *)prop);
+			versions = talloc_realloc(info, versions,
+					struct firmware_version,
+					n_versions + 1);
+			if (!versions) {
+				pb_log("Failed to reallocate version array\n");
+				n_versions = 0;
+				rc = -1;
+				break;
+			}
+			versions[n_versions].name = talloc_strdup(versions,
+					name);
+			versions[n_versions].version = talloc_strdup(versions,
+					(const char *)prop);
+			n_versions++;
+		}
+
+		offset = fdt_next_property_offset(dtb, offset);
+	}
+
+	if (versions && n_versions) {
+		info->platform_primary = versions;
+		info->n_primary = n_versions;
+	}
+
+out:
+	if (buf)
+		talloc_free(buf);
+	if (dtb)
+		talloc_free(dtb);
+	return rc;
+}
diff --git a/lib/device-tree/device-tree.h b/lib/device-tree/device-tree.h
new file mode 100644
index 0000000..876e4a8
--- /dev/null
+++ b/lib/device-tree/device-tree.h
@@ -0,0 +1,34 @@ 
+/*
+ *  Copyright (C) 2017 IBM Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef DEVICE_TREE_H
+#define DEVICE_TREE_H
+
+#include "config.h"
+#include <types/types.h>
+
+#ifdef FDT_SUPPORT
+int device_tree_find_firmware_versions(struct system_info *info);
+#else
+static int device_tree_find_firmware_versions(struct system_info *info)
+{
+	(void)info;
+	return -1;
+}
+#endif
+
+#endif /* DEVICE_TREE_H */