[RFC PATCH 1/2] cmd/fru: cmd/fru: move FRU handling support to common region

Jae Hyun Yoo quic_jaehyoo at quicinc.com
Wed Jul 27 01:50:04 CEST 2022


From: Graeme Gregory <quic_ggregory at quicinc.com>

The FRU handling was added as a Xilinx board dependent support but it
would be useful for other boards too, so this commit moves the FRU
handling support to the common region to be enabled by CONFIG_CMD_FRU.
Since the Multirecord parsing logic should be implemented on each OEM
board specifically, it defines 'fru_parse_multirec' as a weak function
so that it can be replaced with the board specific implementation.

Signed-off-by: Graeme Gregory <quic_ggregory at quicinc.com>
Signed-off-by: Jae Hyun Yoo <quic_jaehyoo at quicinc.com>
---
 board/xilinx/Kconfig                      |  8 ---
 board/xilinx/common/Makefile              |  3 --
 board/xilinx/common/board.c               | 63 +++++++++++++++++++----
 cmd/Kconfig                               |  8 +++
 cmd/Makefile                              |  1 +
 {board/xilinx/common => cmd}/fru.c        |  3 +-
 common/Makefile                           |  2 +
 {board/xilinx/common => common}/fru_ops.c | 37 ++++++-------
 {board/xilinx/common => include}/fru.h    | 15 +-----
 9 files changed, 82 insertions(+), 58 deletions(-)
 rename {board/xilinx/common => cmd}/fru.c (99%)
 rename {board/xilinx/common => common}/fru_ops.c (93%)
 rename {board/xilinx/common => include}/fru.h (85%)

diff --git a/board/xilinx/Kconfig b/board/xilinx/Kconfig
index 17880661736d..110706b20fa3 100644
--- a/board/xilinx/Kconfig
+++ b/board/xilinx/Kconfig
@@ -74,11 +74,3 @@ config ZYNQ_GEM_I2C_MAC_OFFSET
 	  Set the MAC offset for i2C.
 
 endif
-
-config CMD_FRU
-	bool "FRU information for product"
-	help
-	  This option enables FRU commands to capture and display FRU
-	  information present in the device. The FRU Information is used
-	  to primarily to provide "inventory" information about the boards
-	  that the FRU Information Device is located on.
diff --git a/board/xilinx/common/Makefile b/board/xilinx/common/Makefile
index cdc3c9677432..e33baaae1159 100644
--- a/board/xilinx/common/Makefile
+++ b/board/xilinx/common/Makefile
@@ -8,6 +8,3 @@ obj-y	+= board.o
 ifndef CONFIG_ARCH_ZYNQ
 obj-$(CONFIG_DISPLAY_CPUINFO) += cpu-info.o
 endif
-ifndef CONFIG_SPL_BUILD
-obj-$(CONFIG_CMD_FRU) += fru.o fru_ops.o
-endif
diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c
index 9b4aded466ab..061082dbe6d6 100644
--- a/board/xilinx/common/board.c
+++ b/board/xilinx/common/board.c
@@ -8,6 +8,7 @@
 #include <efi.h>
 #include <efi_loader.h>
 #include <env.h>
+#include <fru.h>
 #include <log.h>
 #include <asm/global_data.h>
 #include <asm/sections.h>
@@ -25,8 +26,6 @@
 #include <linux/kernel.h>
 #include <uuid.h>
 
-#include "fru.h"
-
 #if CONFIG_IS_ENABLED(EFI_HAVE_CAPSULE_SUPPORT)
 struct efi_fw_image fw_images[] = {
 #if defined(XILINX_BOOT_IMAGE_GUID)
@@ -88,6 +87,9 @@ int zynq_board_read_rom_ethaddr(unsigned char *ethaddr)
 #define EEPROM_HDR_NO_OF_MAC_ADDR	4
 #define EEPROM_HDR_ETH_ALEN		ETH_ALEN
 #define EEPROM_HDR_UUID_LEN		16
+#define EEPROM_MULTIREC_TYPE_XILINX_OEM	0xD2
+#define EEPROM_MULTIREC_MAC_OFFSET	4
+#define EEPROM_MULTIREC_DUT_MACID	0x31
 
 struct xilinx_board_description {
 	u32 header;
@@ -116,6 +118,14 @@ struct xilinx_legacy_format {
 	char unused3[29]; /* 0xe3 */
 };
 
+struct fru_multirec_mac {
+	u8 xlnx_iana_id[3];
+	u8 ver;
+	u8 macid[EEPROM_HDR_NO_OF_MAC_ADDR][ETH_ALEN];
+};
+
+static u8 parsed_macid[EEPROM_HDR_NO_OF_MAC_ADDR][ETH_ALEN];
+
 static void xilinx_eeprom_legacy_cleanup(char *eeprom, int size)
 {
 	int i;
@@ -197,9 +207,42 @@ static bool xilinx_detect_legacy(u8 *buffer)
 	return true;
 }
 
+int fru_parse_multirec(unsigned long addr)
+{
+	u8 hdr_len = sizeof(struct fru_multirec_hdr);
+	struct fru_multirec_hdr mrc;
+	u8 checksum;
+	int mac_len;
+
+	debug("%s: multirec addr %lx\n", __func__, addr);
+
+	do {
+		memcpy(&mrc.rec_type, (void *)addr, hdr_len);
+
+		checksum = fru_checksum((u8 *)addr, hdr_len);
+		if (checksum) {
+			debug("%s header CRC error\n", __func__);
+			return -EINVAL;
+		}
+
+		if (mrc.rec_type == EEPROM_MULTIREC_TYPE_XILINX_OEM) {
+			struct fru_multirec_mac *mac = (void *)addr + hdr_len;
+
+			if (mac->ver == EEPROM_MULTIREC_DUT_MACID) {
+				mac_len = mrc.len - EEPROM_MULTIREC_MAC_OFFSET;
+				memcpy(parsed_macid, mac->macid, mac_len);
+			}
+		}
+		addr += mrc.len + hdr_len;
+	} while (!(mrc.type & FRU_LAST_REC));
+
+	return 0;
+}
+
 static int xilinx_read_eeprom_fru(struct udevice *dev, char *name,
 				  struct xilinx_board_description *desc)
 {
+	const struct fru_table *fru_data;
 	int i, ret, eeprom_size;
 	u8 *fru_content;
 	u8 id = 0;
@@ -237,30 +280,32 @@ static int xilinx_read_eeprom_fru(struct udevice *dev, char *name,
 		goto end;
 	}
 
+	fru_data = fru_get_fru_data();
+
 	/* It is clear that FRU was captured and structures were filled */
-	strlcpy(desc->manufacturer, (char *)fru_data.brd.manufacturer_name,
+	strlcpy(desc->manufacturer, (char *)fru_data->brd.manufacturer_name,
 		sizeof(desc->manufacturer));
-	strlcpy(desc->uuid, (char *)fru_data.brd.uuid,
+	strlcpy(desc->uuid, (char *)fru_data->brd.uuid,
 		sizeof(desc->uuid));
-	strlcpy(desc->name, (char *)fru_data.brd.product_name,
+	strlcpy(desc->name, (char *)fru_data->brd.product_name,
 		sizeof(desc->name));
 	for (i = 0; i < sizeof(desc->name); i++) {
 		if (desc->name[i] == ' ')
 			desc->name[i] = '\0';
 	}
-	strlcpy(desc->revision, (char *)fru_data.brd.rev,
+	strlcpy(desc->revision, (char *)fru_data->brd.rev,
 		sizeof(desc->revision));
 	for (i = 0; i < sizeof(desc->revision); i++) {
 		if (desc->revision[i] == ' ')
 			desc->revision[i] = '\0';
 	}
-	strlcpy(desc->serial, (char *)fru_data.brd.serial_number,
+	strlcpy(desc->serial, (char *)fru_data->brd.serial_number,
 		sizeof(desc->serial));
 
 	while (id < EEPROM_HDR_NO_OF_MAC_ADDR) {
-		if (is_valid_ethaddr((const u8 *)fru_data.mac.macid[id]))
+		if (is_valid_ethaddr((const u8 *)parsed_macid[id]))
 			memcpy(&desc->mac_addr[id],
-			       (char *)fru_data.mac.macid[id], ETH_ALEN);
+			       (char *)parsed_macid[id], ETH_ALEN);
 		id++;
 	}
 
diff --git a/cmd/Kconfig b/cmd/Kconfig
index a8260aa170d0..644c907bf83a 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1053,6 +1053,14 @@ config CMD_FPGAD
 	  fpga_get_reg() function. This functions similarly to the 'md'
 	  command.
 
+config CMD_FRU
+	bool "FRU information for product"
+	help
+	  This option enables FRU commands to capture and display FRU
+	  information present in the device. The FRU Information is used
+	  to primarily to provide "inventory" information about the boards
+	  that the FRU Information Device is located on.
+
 config CMD_FUSE
 	bool "fuse - support for the fuse subssystem"
 	help
diff --git a/cmd/Makefile b/cmd/Makefile
index 5e43a1e022e8..10a18d02eb08 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -74,6 +74,7 @@ obj-$(CONFIG_CMD_SQUASHFS) += sqfs.o
 obj-$(CONFIG_CMD_FLASH) += flash.o
 obj-$(CONFIG_CMD_FPGA) += fpga.o
 obj-$(CONFIG_CMD_FPGAD) += fpgad.o
+obj-$(CONFIG_CMD_FRU) += fru.o
 obj-$(CONFIG_CMD_FS_GENERIC) += fs.o
 obj-$(CONFIG_CMD_FUSE) += fuse.o
 obj-$(CONFIG_CMD_GETTIME) += gettime.o
diff --git a/board/xilinx/common/fru.c b/cmd/fru.c
similarity index 99%
rename from board/xilinx/common/fru.c
rename to cmd/fru.c
index f6ca46c3cecc..dd0b56f05698 100644
--- a/board/xilinx/common/fru.c
+++ b/cmd/fru.c
@@ -6,10 +6,9 @@
 #include <common.h>
 #include <command.h>
 #include <fdtdec.h>
+#include <fru.h>
 #include <malloc.h>
 
-#include "fru.h"
-
 static int do_fru_capture(struct cmd_tbl *cmdtp, int flag, int argc,
 			  char *const argv[])
 {
diff --git a/common/Makefile b/common/Makefile
index 2ed8672c3ac1..d5c9de33ac07 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -112,3 +112,5 @@ obj-$(CONFIG_$(SPL_TPL_)STACKPROTECTOR) += stackprot.o
 obj-$(CONFIG_SCP03) += scp03.o
 
 obj-$(CONFIG_QFW) += qfw.o
+
+obj-$(CONFIG_CMD_FRU) += fru_ops.o
diff --git a/board/xilinx/common/fru_ops.c b/common/fru_ops.c
similarity index 93%
rename from board/xilinx/common/fru_ops.c
rename to common/fru_ops.c
index 49846ae3d660..0c5e264226ed 100644
--- a/board/xilinx/common/fru_ops.c
+++ b/common/fru_ops.c
@@ -9,7 +9,6 @@
 #include <fdtdec.h>
 #include <log.h>
 #include <malloc.h>
-#include <net.h>
 #include <asm/io.h>
 #include <asm/arch/hardware.h>
 
@@ -219,12 +218,11 @@ static int fru_parse_board(unsigned long addr)
 	return 0;
 }
 
-static int fru_parse_multirec(unsigned long addr)
+__weak int fru_parse_multirec(unsigned long addr)
 {
-	struct fru_multirec_hdr mrc;
-	u8 checksum = 0;
 	u8 hdr_len = sizeof(struct fru_multirec_hdr);
-	int mac_len = 0;
+	struct fru_multirec_hdr mrc;
+	u8 checksum;
 
 	debug("%s: multirec addr %lx\n", __func__, addr);
 
@@ -237,14 +235,9 @@ static int fru_parse_multirec(unsigned long addr)
 			return -EINVAL;
 		}
 
-		if (mrc.rec_type == FRU_MULTIREC_TYPE_OEM) {
-			struct fru_multirec_mac *mac = (void *)addr + hdr_len;
+		debug("%s: multirec rec_type: 0x%x, type: 0x%x, len: %d\n",
+		      __func__, mrc.rec_type, mrc.type, mrc.len);
 
-			if (mac->ver == FRU_DUT_MACID) {
-				mac_len = mrc.len - FRU_MULTIREC_MAC_OFFSET;
-				memcpy(&fru_data.mac.macid, mac->macid, mac_len);
-			}
-		}
 		addr += mrc.len + hdr_len;
 	} while (!(mrc.type & FRU_LAST_REC));
 
@@ -255,7 +248,6 @@ int fru_capture(unsigned long addr)
 {
 	struct fru_common_hdr *hdr;
 	u8 checksum = 0;
-	unsigned long multirec_addr = addr;
 
 	checksum = fru_checksum((u8 *)addr, sizeof(struct fru_common_hdr));
 	if (checksum) {
@@ -270,17 +262,13 @@ int fru_capture(unsigned long addr)
 
 	fru_data.captured = true;
 
-	if (hdr->off_board) {
-		addr += fru_cal_area_len(hdr->off_board);
-		fru_parse_board(addr);
-	}
+	if (hdr->off_board)
+		fru_parse_board(addr + fru_cal_area_len(hdr->off_board));
 
-	env_set_hex("fru_addr", addr);
+	if (hdr->off_multirec)
+		fru_parse_multirec(addr + fru_cal_area_len(hdr->off_multirec));
 
-	if (hdr->off_multirec) {
-		multirec_addr += fru_cal_area_len(hdr->off_multirec);
-		fru_parse_multirec(multirec_addr);
-	}
+	env_set_hex("fru_addr", addr);
 
 	return 0;
 }
@@ -413,3 +401,8 @@ int fru_display(int verbose)
 
 	return fru_display_board(&fru_data.brd, verbose);
 }
+
+const struct fru_table *fru_get_fru_data(void)
+{
+	return &fru_data;
+}
diff --git a/board/xilinx/common/fru.h b/include/fru.h
similarity index 85%
rename from board/xilinx/common/fru.h
rename to include/fru.h
index 59f6b722cf12..b497a8835695 100644
--- a/board/xilinx/common/fru.h
+++ b/include/fru.h
@@ -6,7 +6,6 @@
 
 #ifndef __FRU_H
 #define __FRU_H
-#include <net.h>
 
 struct fru_common_hdr {
 	u8 version;
@@ -20,7 +19,6 @@ struct fru_common_hdr {
 };
 
 #define FRU_BOARD_MAX_LEN	32
-#define FRU_MAX_NO_OF_MAC_ADDR	4
 
 struct __packed fru_board_info_header {
 	u8 ver;
@@ -66,16 +64,9 @@ struct fru_multirec_hdr {
 	u8 hdr_csum;
 };
 
-struct fru_multirec_mac {
-	u8 xlnx_iana_id[3];
-	u8 ver;
-	u8 macid[FRU_MAX_NO_OF_MAC_ADDR][ETH_ALEN];
-};
-
 struct fru_table {
 	struct fru_common_hdr hdr;
 	struct fru_board_data brd;
-	struct fru_multirec_mac mac;
 	bool captured;
 };
 
@@ -86,10 +77,7 @@ struct fru_table {
 #define FRU_LANG_CODE_ENGLISH		0
 #define FRU_LANG_CODE_ENGLISH_1		25
 #define FRU_TYPELEN_EOF			0xC1
-#define FRU_MULTIREC_TYPE_OEM		0xD2
-#define FRU_MULTIREC_MAC_OFFSET		4
 #define FRU_LAST_REC			BIT(7)
-#define FRU_DUT_MACID			0x31
 
 /* This should be minimum of fields */
 #define FRU_BOARD_AREA_TOTAL_FIELDS	5
@@ -102,7 +90,6 @@ int fru_capture(unsigned long addr);
 int fru_generate(unsigned long addr, char *manufacturer, char *board_name,
 		 char *serial_no, char *part_no, char *revision);
 u8 fru_checksum(u8 *addr, u8 len);
-
-extern struct fru_table fru_data;
+const struct fru_table *fru_get_fru_data(void);
 
 #endif /* FRU_H */
-- 
2.25.1



More information about the U-Boot mailing list