u-boot.lists.denx.de archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/7] cmd/fru: move FRU handling support to common region
@ 2022-08-23 21:52 Jae Hyun Yoo
  2022-08-23 21:52 ` [PATCH v3 1/7] xilinx: common: refactor FRU handling support Jae Hyun Yoo
                   ` (6 more replies)
  0 siblings, 7 replies; 15+ messages in thread
From: Jae Hyun Yoo @ 2022-08-23 21:52 UTC (permalink / raw)
  To: Michal Simek, Ovidiu Panait, Simon Glass, Mario Six,
	Masahisa Kojima, Pali Rohár, Heinrich Schuchardt,
	Ashok Reddy Soma, Thomas Huth, Huang Jianan, Chris Morgan,
	Roland Gaudig, Patrick Delaunay, Alexandru Gagniuc
  Cc: Jamie Iles, Graeme Gregory, Cédric Le Goater, Jae Hyun Yoo, u-boot

Hello,

The FRU handling was added as a Xilinx board dependent support but it
is also useful for other boards, so this commit moves the FRU handling
support to the common region so that it can be enabled by CONFIG_CMD_FRU.

To provide manufacturer specific custom info fields and multi-records
parsing, it refactors the FRU handling logic using linked list so that each
board support can utilize them in their own custom way. This series adds
'Product Info' parsing support, usage document and unit test script too.

Please review!

Thanks,
Jae

Graeme Gregory (1):
  cmd: fru: move FRU handling support to common region

Jae Hyun Yoo (6):
  xilinx: common: refactor FRU handling support
  cmd: fru: fix a sandbox segfault issue
  cmd: fru: add product info area parsing support
  doc: fru: add documentation for the fru command and APIs
  test: py: fru: add a test for the fru command
  test: cmd: fru: add unit test for the fru command

 board/xilinx/Kconfig               |   8 -
 board/xilinx/common/Makefile       |   3 -
 board/xilinx/common/board.c        |  68 ++-
 board/xilinx/common/fru.h          | 108 -----
 board/xilinx/common/fru_ops.c      | 415 -----------------
 cmd/Kconfig                        |   8 +
 cmd/Makefile                       |   1 +
 {board/xilinx/common => cmd}/fru.c |  54 ++-
 configs/sandbox_defconfig          |   1 +
 doc/usage/cmd/fru.rst              | 144 ++++++
 doc/usage/index.rst                |   1 +
 include/fru.h                      | 328 +++++++++++++
 include/test/suites.h              |   1 +
 lib/Makefile                       |   1 +
 lib/fru_ops.c                      | 725 +++++++++++++++++++++++++++++
 test/cmd/Makefile                  |   1 +
 test/cmd/fru.c                     |  84 ++++
 test/cmd_ut.c                      |   6 +
 test/py/tests/test_fru.py          |  47 ++
 19 files changed, 1447 insertions(+), 557 deletions(-)
 delete mode 100644 board/xilinx/common/fru.h
 delete mode 100644 board/xilinx/common/fru_ops.c
 rename {board/xilinx/common => cmd}/fru.c (50%)
 create mode 100644 doc/usage/cmd/fru.rst
 create mode 100644 include/fru.h
 create mode 100644 lib/fru_ops.c
 create mode 100644 test/cmd/fru.c
 create mode 100644 test/py/tests/test_fru.py

-- 
2.25.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v3 1/7] xilinx: common: refactor FRU handling support
  2022-08-23 21:52 [PATCH v3 0/7] cmd/fru: move FRU handling support to common region Jae Hyun Yoo
@ 2022-08-23 21:52 ` Jae Hyun Yoo
  2022-08-23 21:52 ` [PATCH v3 2/7] cmd: fru: move FRU handling support to common region Jae Hyun Yoo
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Jae Hyun Yoo @ 2022-08-23 21:52 UTC (permalink / raw)
  To: Michal Simek, Ovidiu Panait, Simon Glass, Mario Six,
	Masahisa Kojima, Pali Rohár, Heinrich Schuchardt,
	Ashok Reddy Soma, Thomas Huth, Huang Jianan, Chris Morgan,
	Roland Gaudig, Patrick Delaunay, Alexandru Gagniuc
  Cc: Jamie Iles, Graeme Gregory, Cédric Le Goater, Jae Hyun Yoo, u-boot

Refactor FRU handling support to remove Xilinx customization dependency.
With this change, single or multiple custom board fields and
multi-records can be added dynamically using linked list so that each
board support can utilize them in their own custom way.

It's a preparation change for moving the FRU command support to common
region.

Signed-off-by: Jae Hyun Yoo <quic_jaehyoo@quicinc.com>
---
Changes from v2:
 * None.

Changes from v1:
 * Newly added in v2.

 board/xilinx/common/board.c   |  63 ++++++++--
 board/xilinx/common/fru.c     |  12 +-
 board/xilinx/common/fru.h     |  76 +++++++-----
 board/xilinx/common/fru_ops.c | 228 ++++++++++++++++++++++++----------
 4 files changed, 264 insertions(+), 115 deletions(-)

diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c
index 9b4aded466ab..e979f0176273 100644
--- a/board/xilinx/common/board.c
+++ b/board/xilinx/common/board.c
@@ -88,6 +88,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 +119,19 @@ struct xilinx_legacy_format {
 	char unused3[29]; /* 0xe3 */
 };
 
+struct xilinx_multirec_mac {
+	u8 xlnx_iana_id[3];
+	u8 ver;
+	u8 macid[EEPROM_HDR_NO_OF_MAC_ADDR][ETH_ALEN];
+};
+
+enum xilinx_board_custom_field {
+	brd_custom_field_rev = 0,
+	brd_custom_field_pcie,
+	brd_custom_field_uuid,
+	brd_custom_field_max
+};
+
 static void xilinx_eeprom_legacy_cleanup(char *eeprom, int size)
 {
 	int i;
@@ -200,9 +216,14 @@ static bool xilinx_detect_legacy(u8 *buffer)
 static int xilinx_read_eeprom_fru(struct udevice *dev, char *name,
 				  struct xilinx_board_description *desc)
 {
+	u8 parsed_macid[EEPROM_HDR_NO_OF_MAC_ADDR][ETH_ALEN] = { 0 };
+	struct fru_custom_info custom_info[brd_custom_field_max] = { 0 };
+	struct fru_custom_field_node *ci_node;
+	struct fru_multirec_node *mr_node;
+	const struct fru_table *fru_data;
 	int i, ret, eeprom_size;
 	u8 *fru_content;
-	u8 id = 0;
+	u8 id = 0, field = 0;
 
 	/* FIXME this is shortcut - if eeprom type is wrong it will fail */
 	eeprom_size = i2c_eeprom_size(dev);
@@ -237,30 +258,56 @@ static int xilinx_read_eeprom_fru(struct udevice *dev, char *name,
 		goto end;
 	}
 
+	fru_data = fru_get_fru_data();
+
+	list_for_each_entry(ci_node, &fru_data->brd.custom_fields, list) {
+		custom_info[field].type_len = ci_node->info.type_len;
+		memcpy(custom_info[field].data, ci_node->info.data,
+		       ci_node->info.type_len & FRU_TYPELEN_LEN_MASK);
+		if (++field < brd_custom_field_max)
+			break;
+	}
+
+	list_for_each_entry(mr_node, &fru_data->multi_recs, list) {
+		struct fru_multirec_hdr *hdr = &mr_node->info.hdr;
+
+		if (hdr->rec_type == EEPROM_MULTIREC_TYPE_XILINX_OEM) {
+			struct xilinx_multirec_mac *mac;
+
+			mac = (struct xilinx_multirec_mac *)mr_node->info.data;
+			if (mac->ver == EEPROM_MULTIREC_DUT_MACID) {
+				int mac_len = hdr->len -
+					      EEPROM_MULTIREC_MAC_OFFSET;
+
+				memcpy(parsed_macid, mac->macid, mac_len);
+			}
+		}
+	}
+
 	/* 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 *)custom_info[brd_custom_field_uuid].data,
 		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 *)custom_info[brd_custom_field_rev].data,
 		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/board/xilinx/common/fru.c b/board/xilinx/common/fru.c
index f6ca46c3cecc..0d72911df04d 100644
--- a/board/xilinx/common/fru.c
+++ b/board/xilinx/common/fru.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
  * (C) Copyright 2019 - 2020 Xilinx, Inc.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <common.h>
@@ -43,7 +44,7 @@ static int do_fru_generate(struct cmd_tbl *cmdtp, int flag, int argc,
 
 	addr = hextoul(argv[2], NULL);
 
-	return fru_generate(addr, argv[3], argv[4], argv[5], argv[6], argv[7]);
+	return fru_generate(addr, argc - 3, argv + 3);
 }
 
 static struct cmd_tbl cmd_fru_sub[] = {
@@ -78,14 +79,15 @@ static char fru_help_text[] =
 	"fru display - Displays content of FRU table that was captured using\n"
 	"              fru capture command\n"
 	"fru board_gen <addr> <manufacturer> <board name> <serial number>\n"
-	"              <part number> <revision> - Generate FRU format with\n"
-	"              board info area filled based on parameters. <addr> is\n"
-	"              pointing to place where FRU is generated.\n"
+	"              <part number> <file id> [custom ...] - Generate FRU\n"
+	"              format with board info area filled based on\n"
+	"                parameters. <addr> is pointing to place where FRU is\n"
+	"                generated.\n"
 	;
 #endif
 
 U_BOOT_CMD(
-	fru, 8, 1, do_fru,
+	fru, CONFIG_SYS_MAXARGS, 1, do_fru,
 	"FRU table info",
 	fru_help_text
 )
diff --git a/board/xilinx/common/fru.h b/board/xilinx/common/fru.h
index 59f6b722cf12..41655864dbf5 100644
--- a/board/xilinx/common/fru.h
+++ b/board/xilinx/common/fru.h
@@ -2,11 +2,13 @@
 /*
  * (C) Copyright 2019 Xilinx, Inc.
  * Siva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef __FRU_H
 #define __FRU_H
-#include <net.h>
+
+#include <linux/list.h>
 
 struct fru_common_hdr {
 	u8 version;
@@ -17,21 +19,31 @@ struct fru_common_hdr {
 	u8 off_multirec;
 	u8 pad;
 	u8 crc;
-};
+} __packed;
 
-#define FRU_BOARD_MAX_LEN	32
-#define FRU_MAX_NO_OF_MAC_ADDR	4
+#define FRU_INFO_FIELD_LEN_MAX		32
+#define FRU_MULTIREC_DATA_LEN_MAX	255
 
-struct __packed fru_board_info_header {
+struct fru_board_info_header {
 	u8 ver;
 	u8 len;
 	u8 lang_code;
 	u8 time[3];
-};
+} __packed;
 
-struct __packed fru_board_info_member {
+struct fru_board_info_member {
 	u8 type_len;
 	u8 *name;
+} __packed;
+
+struct fru_custom_info {
+	u8 type_len;
+	u8 data[FRU_INFO_FIELD_LEN_MAX];
+} __packed;
+
+struct fru_custom_field_node {
+	struct list_head list;
+	struct fru_custom_info info;
 };
 
 struct fru_board_data {
@@ -40,22 +52,16 @@ struct fru_board_data {
 	u8 lang_code;
 	u8 time[3];
 	u8 manufacturer_type_len;
-	u8 manufacturer_name[FRU_BOARD_MAX_LEN];
+	u8 manufacturer_name[FRU_INFO_FIELD_LEN_MAX];
 	u8 product_name_type_len;
-	u8 product_name[FRU_BOARD_MAX_LEN];
+	u8 product_name[FRU_INFO_FIELD_LEN_MAX];
 	u8 serial_number_type_len;
-	u8 serial_number[FRU_BOARD_MAX_LEN];
+	u8 serial_number[FRU_INFO_FIELD_LEN_MAX];
 	u8 part_number_type_len;
-	u8 part_number[FRU_BOARD_MAX_LEN];
+	u8 part_number[FRU_INFO_FIELD_LEN_MAX];
 	u8 file_id_type_len;
-	u8 file_id[FRU_BOARD_MAX_LEN];
-	/* Xilinx custom fields */
-	u8 rev_type_len;
-	u8 rev[FRU_BOARD_MAX_LEN];
-	u8 pcie_type_len;
-	u8 pcie[FRU_BOARD_MAX_LEN];
-	u8 uuid_type_len;
-	u8 uuid[FRU_BOARD_MAX_LEN];
+	u8 file_id[FRU_INFO_FIELD_LEN_MAX];
+	struct list_head custom_fields;
 };
 
 struct fru_multirec_hdr {
@@ -64,32 +70,35 @@ struct fru_multirec_hdr {
 	u8 len;
 	u8 csum;
 	u8 hdr_csum;
-};
+} __packed;
 
-struct fru_multirec_mac {
-	u8 xlnx_iana_id[3];
-	u8 ver;
-	u8 macid[FRU_MAX_NO_OF_MAC_ADDR][ETH_ALEN];
+struct fru_multirec_info {
+	struct fru_multirec_hdr hdr;
+	u8 data[FRU_MULTIREC_DATA_LEN_MAX];
+} __packed;
+
+struct fru_multirec_node {
+	struct list_head list;
+	struct fru_multirec_info info;
 };
 
 struct fru_table {
 	struct fru_common_hdr hdr;
 	struct fru_board_data brd;
-	struct fru_multirec_mac mac;
+	struct list_head multi_recs;
 	bool captured;
 };
 
-#define FRU_TYPELEN_CODE_MASK	0xC0
-#define FRU_TYPELEN_LEN_MASK	0x3F
+#define FRU_TYPELEN_CODE_MASK		0xC0
+#define FRU_TYPELEN_LEN_MASK		0x3F
 #define FRU_COMMON_HDR_VER_MASK		0xF
 #define FRU_COMMON_HDR_LEN_MULTIPLIER	8
 #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
+#define FRU_MULTIREC_TYPE_OEM_START	0xC0
+#define FRU_MULTIREC_TYPE_OEM_END	0xFF
 
 /* This should be minimum of fields */
 #define FRU_BOARD_AREA_TOTAL_FIELDS	5
@@ -99,10 +108,9 @@ struct fru_table {
 
 int fru_display(int verbose);
 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);
+int fru_generate(unsigned long addr, int argc, char *const argv[]);
 u8 fru_checksum(u8 *addr, u8 len);
-
-extern struct fru_table fru_data;
+int fru_check_type_len(u8 type_len, u8 language, u8 *type);
+const struct fru_table *fru_get_fru_data(void);
 
 #endif /* FRU_H */
diff --git a/board/xilinx/common/fru_ops.c b/board/xilinx/common/fru_ops.c
index 49846ae3d660..e005ecae21fa 100644
--- a/board/xilinx/common/fru_ops.c
+++ b/board/xilinx/common/fru_ops.c
@@ -1,21 +1,24 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
  * (C) Copyright 2019 - 2020 Xilinx, Inc.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <common.h>
-#include <cpu_func.h>
 #include <env.h>
 #include <fdtdec.h>
+#include <hexdump.h>
 #include <log.h>
 #include <malloc.h>
-#include <net.h>
 #include <asm/io.h>
-#include <asm/arch/hardware.h>
+#include <linux/compat.h>
 
 #include "fru.h"
 
-struct fru_table fru_data __section(".data");
+struct fru_table fru_data __section(".data") = {
+	.brd.custom_fields = LIST_HEAD_INIT(fru_data.brd.custom_fields),
+	.multi_recs = LIST_HEAD_INIT(fru_data.multi_recs),
+};
 
 static u16 fru_cal_area_len(u8 len)
 {
@@ -57,7 +60,7 @@ u8 fru_checksum(u8 *addr, u8 len)
 	return checksum;
 }
 
-static int fru_check_type_len(u8 type_len, u8 language, u8 *type)
+int fru_check_type_len(u8 type_len, u8 language, u8 *type)
 {
 	int len;
 
@@ -89,8 +92,7 @@ static u8 fru_gen_type_len(u8 *addr, char *name)
 	return 1 + len;
 }
 
-int fru_generate(unsigned long addr, char *manufacturer, char *board_name,
-		 char *serial_no, char *part_no, char *revision)
+int fru_generate(unsigned long addr, int argc, char *const argv[])
 {
 	struct fru_common_hdr *header = (struct fru_common_hdr *)addr;
 	struct fru_board_info_header *board_info;
@@ -126,18 +128,10 @@ int fru_generate(unsigned long addr, char *manufacturer, char *board_name,
 	/* Member fields are just after board_info header */
 	member = (u8 *)board_info + sizeof(*board_info);
 
-	len = fru_gen_type_len(member, manufacturer); /* Board Manufacturer */
-	member += len;
-	len = fru_gen_type_len(member, board_name); /* Board Product name */
-	member += len;
-	len = fru_gen_type_len(member, serial_no); /* Board Serial number */
-	member += len;
-	len = fru_gen_type_len(member, part_no); /* Board part number */
-	member += len;
-	len = fru_gen_type_len(member, "U-Boot generator"); /* File ID */
-	member += len;
-	len = fru_gen_type_len(member, revision); /* Revision */
-	member += len;
+	while (--argc > 0 && ++argv) {
+		len = fru_gen_type_len(member, *argv);
+		member += len;
+	}
 
 	*member++ = 0xc1; /* Indication of no more fields */
 
@@ -168,6 +162,35 @@ int fru_generate(unsigned long addr, char *manufacturer, char *board_name,
 	return 0;
 }
 
+static void fru_delete_custom_fields(struct list_head *custom_fields)
+{
+	struct fru_custom_field_node *node, *next;
+
+	list_for_each_entry_safe(node, next, custom_fields, list) {
+		list_del(&node->list);
+		kfree(node);
+	}
+}
+
+static int fru_append_custom_info(unsigned long addr,
+				  struct list_head *custom_fields)
+{
+	struct fru_custom_info *info = (struct fru_custom_info *)addr;
+	struct fru_custom_field_node *ci_new;
+
+	ci_new = kzalloc(sizeof(*ci_new), GFP_KERNEL);
+	if (!ci_new)
+		return -ENOMEM;
+
+	ci_new->info.type_len = info->type_len;
+	memcpy(&ci_new->info.data, (void *)info->data,
+	       ci_new->info.type_len & FRU_TYPELEN_LEN_MASK);
+
+	list_add_tail(&ci_new->list, custom_fields);
+
+	return 0;
+}
+
 static int fru_parse_board(unsigned long addr)
 {
 	u8 i, type;
@@ -179,9 +202,10 @@ static int fru_parse_board(unsigned long addr)
 	data = (u8 *)&fru_data.brd.manufacturer_type_len;
 
 	/* Record max structure limit not to write data over allocated space */
-	limit = (u8 *)&fru_data.brd + sizeof(struct fru_board_data);
+	limit = (u8 *)&fru_data.brd + sizeof(struct fru_board_data) -
+		sizeof(struct fru_custom_field_node *);
 
-	for (i = 0; ; i++, data += FRU_BOARD_MAX_LEN) {
+	for (i = 0; ; i++, data += FRU_INFO_FIELD_LEN_MAX) {
 		len = fru_check_type_len(*(u8 *)addr, fru_data.brd.lang_code,
 					 &type);
 		/*
@@ -190,11 +214,14 @@ static int fru_parse_board(unsigned long addr)
 		if (len == -EINVAL)
 			break;
 
-		/* Stop when amount of chars is more then fields to record */
-		if (data + len > limit)
-			break;
-		/* This record type/len field */
-		*data++ = *(u8 *)addr;
+		if (i < FRU_BOARD_AREA_TOTAL_FIELDS) {
+			/* Stop when length is more then fields to record */
+			if (data + len > limit)
+				break;
+
+			/* This record type/len field */
+			*data++ = *(u8 *)addr;
+		}
 
 		/* Add offset to match data */
 		addr += 1;
@@ -203,10 +230,23 @@ static int fru_parse_board(unsigned long addr)
 		if (!len)
 			continue;
 
-		/* Record data field */
-		memcpy(data, (u8 *)addr, len);
-		term = data + (u8)len;
-		*term = 0;
+		if (i < FRU_BOARD_AREA_TOTAL_FIELDS) {
+			/* Record data field */
+			memcpy(data, (u8 *)addr, len);
+			term = data + (u8)len;
+			*term = 0;
+		} else {
+			struct list_head *custom_fields;
+
+			custom_fields = &fru_data.brd.custom_fields;
+
+			/* Add a custom info field */
+			if (fru_append_custom_info(addr - 1, custom_fields)) {
+				fru_delete_custom_fields(custom_fields);
+				return -EINVAL;
+			}
+		}
+
 		addr += len;
 	}
 
@@ -219,34 +259,52 @@ static int fru_parse_board(unsigned long addr)
 	return 0;
 }
 
+static void fru_delete_multirecs(struct list_head *multi_recs)
+{
+	struct fru_multirec_node *node, *next;
+
+	list_for_each_entry_safe(node, next, multi_recs, list) {
+		list_del(&node->list);
+		kfree(node);
+	}
+}
+
+static int fru_append_multirec(unsigned long addr,
+			       struct list_head *multi_recs)
+{
+	struct fru_multirec_info *mr_src = (struct fru_multirec_info *)addr;
+	struct fru_multirec_node *mr_new;
+
+	mr_new = kzalloc(sizeof(*mr_new), GFP_KERNEL);
+	if (!mr_new)
+		return -ENOMEM;
+
+	memcpy(&mr_new->info.hdr, (void *)&mr_src->hdr, sizeof(mr_src->hdr));
+	memcpy(&mr_new->info.data, (void *)mr_src->data, mr_src->hdr.len);
+
+	list_add_tail(&mr_new->list, multi_recs);
+
+	return 0;
+}
+
 static 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 *mr_hdr;
 
-	debug("%s: multirec addr %lx\n", __func__, addr);
+	debug("%s: multirec addr %lx\n", __func__, (ulong)addr);
 
 	do {
-		memcpy(&mrc.rec_type, (void *)addr, hdr_len);
-
-		checksum = fru_checksum((u8 *)addr, hdr_len);
-		if (checksum) {
+		if (fru_checksum((u8 *)addr, hdr_len)) {
 			debug("%s header CRC error\n", __func__);
 			return -EINVAL;
 		}
 
-		if (mrc.rec_type == FRU_MULTIREC_TYPE_OEM) {
-			struct fru_multirec_mac *mac = (void *)addr + hdr_len;
+		fru_append_multirec(addr, &fru_data.multi_recs);
 
-			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));
+		mr_hdr = (struct fru_multirec_hdr *)addr;
+		addr += mr_hdr->len + hdr_len;
+	} while (!(mr_hdr->type & FRU_LAST_REC));
 
 	return 0;
 }
@@ -255,7 +313,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) {
@@ -264,33 +321,28 @@ int fru_capture(unsigned long addr)
 	}
 
 	hdr = (struct fru_common_hdr *)addr;
+	fru_delete_custom_fields(&fru_data.brd.custom_fields);
+	fru_delete_multirecs(&fru_data.multi_recs);
 	memset((void *)&fru_data, 0, sizeof(fru_data));
-	memcpy((void *)&fru_data, (void *)hdr,
-	       sizeof(struct fru_common_hdr));
+	INIT_LIST_HEAD(&fru_data.brd.custom_fields);
+	INIT_LIST_HEAD(&fru_data.multi_recs);
+	memcpy((void *)&fru_data, (void *)hdr, sizeof(struct fru_common_hdr));
 
 	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", (ulong)addr);
 
 	return 0;
 }
 
 static int fru_display_board(struct fru_board_data *brd, int verbose)
 {
-	u32 time = 0;
-	u8 type;
-	int len;
-	u8 *data;
 	static const char * const typecode[] = {
 		"Binary/Unspecified",
 		"BCD plus",
@@ -301,12 +353,15 @@ static int fru_display_board(struct fru_board_data *brd, int verbose)
 	static const char * const boardinfo[] = {
 		"Manufacturer Name",
 		"Product Name",
-		"Serial No",
+		"Serial Number",
 		"Part Number",
 		"File ID",
-		/* Xilinx spec */
-		"Revision Number",
 	};
+	struct fru_custom_field_node *node;
+	u32 time = 0;
+	u8 *data;
+	u8 type;
+	int len;
 
 	if (verbose) {
 		printf("*****BOARD INFO*****\n");
@@ -358,7 +413,32 @@ static int fru_display_board(struct fru_board_data *brd, int verbose)
 			debug("Unsupported type %x\n", type);
 		}
 
-		data += FRU_BOARD_MAX_LEN;
+		data += FRU_INFO_FIELD_LEN_MAX;
+	}
+
+	list_for_each_entry(node, &brd->custom_fields, list) {
+		printf(" Custom Type/Length: 0x%x\n", node->info.type_len);
+		print_hex_dump_bytes("  ", DUMP_PREFIX_OFFSET, node->info.data,
+				     node->info.type_len &
+				     FRU_TYPELEN_LEN_MASK);
+	}
+
+	return 0;
+}
+
+static int fru_display_multirec(struct list_head *multi_recs, int verbose)
+{
+	struct fru_multirec_node *node;
+
+	if (verbose)
+		printf("*****MULTIRECORDS*****\n");
+
+	list_for_each_entry(node, multi_recs, list) {
+		printf("Type ID: 0x%x, Type: 0x%x Length: %d\n",
+		       node->info.hdr.rec_type, node->info.hdr.type,
+		       node->info.hdr.len);
+		print_hex_dump_bytes(" ", DUMP_PREFIX_OFFSET, node->info.data,
+				     node->info.hdr.len);
 	}
 
 	return 0;
@@ -404,6 +484,8 @@ static void fru_display_common_hdr(struct fru_common_hdr *hdr, int verbose)
 
 int fru_display(int verbose)
 {
+	int ret;
+
 	if (!fru_data.captured) {
 		printf("FRU data not available please run fru parse\n");
 		return -EINVAL;
@@ -411,5 +493,14 @@ int fru_display(int verbose)
 
 	fru_display_common_hdr(&fru_data.hdr, verbose);
 
-	return fru_display_board(&fru_data.brd, verbose);
+	ret = fru_display_board(&fru_data.brd, verbose);
+	if (ret)
+		return ret;
+
+	return fru_display_multirec(&fru_data.multi_recs, verbose);
 }
+
+const struct fru_table *fru_get_fru_data(void)
+{
+	return &fru_data;
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 2/7] cmd: fru: move FRU handling support to common region
  2022-08-23 21:52 [PATCH v3 0/7] cmd/fru: move FRU handling support to common region Jae Hyun Yoo
  2022-08-23 21:52 ` [PATCH v3 1/7] xilinx: common: refactor FRU handling support Jae Hyun Yoo
@ 2022-08-23 21:52 ` Jae Hyun Yoo
  2022-08-23 21:52 ` [PATCH v3 3/7] cmd: fru: fix a sandbox segfault issue Jae Hyun Yoo
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Jae Hyun Yoo @ 2022-08-23 21:52 UTC (permalink / raw)
  To: Michal Simek, Ovidiu Panait, Simon Glass, Mario Six,
	Masahisa Kojima, Pali Rohár, Heinrich Schuchardt,
	Ashok Reddy Soma, Thomas Huth, Huang Jianan, Chris Morgan,
	Roland Gaudig, Patrick Delaunay, Alexandru Gagniuc
  Cc: Jamie Iles, Graeme Gregory, Cédric Le Goater, Jae Hyun Yoo, u-boot

From: Graeme Gregory <quic_ggregory@quicinc.com>

The FRU handling was added as a Xilinx board dependent support but it
is also useful for other boards too, so this commit moves the FRU
handling support to the common region so that it can be enabled by
CONFIG_CMD_FRU.

Signed-off-by: Graeme Gregory <quic_ggregory@quicinc.com>
Signed-off-by: Jae Hyun Yoo <quic_jaehyoo@quicinc.com>
---
Changes from v2:
 * None.

Changes from v1:
 * Split out the custom field and multi-record handling part as a
   seperate patch. (Michal)
 * Moved fru_ops.c to lib. (Heinrich)
 * Added what does FRU stand for. (Heinrich)

Changes from RFC:
 * Made FRU typecode string table as a generic and sharable table. (Michal)
 * Made OEM multirecord parsing call happen only on customizable type IDs.
   (Michal)
 * Added manufacturer custom board info fields parsing flow. (Michal)

 board/xilinx/Kconfig                   | 8 --------
 board/xilinx/common/Makefile           | 3 ---
 board/xilinx/common/board.c            | 3 +--
 cmd/Kconfig                            | 8 ++++++++
 cmd/Makefile                           | 1 +
 {board/xilinx/common => cmd}/fru.c     | 3 +--
 {board/xilinx/common => include}/fru.h | 0
 lib/Makefile                           | 1 +
 {board/xilinx/common => lib}/fru_ops.c | 3 +--
 9 files changed, 13 insertions(+), 17 deletions(-)
 rename {board/xilinx/common => cmd}/fru.c (99%)
 rename {board/xilinx/common => include}/fru.h (100%)
 rename {board/xilinx/common => lib}/fru_ops.c (99%)

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 e979f0176273..e58b11d7f757 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)
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 211ebe9c8783..29b2e11e1247 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1063,6 +1063,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 (Field Replaceable Unit) 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 6e87522b62e8..58e353611a5a 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 0d72911df04d..2ec5012af5ac 100644
--- a/board/xilinx/common/fru.c
+++ b/cmd/fru.c
@@ -7,10 +7,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/board/xilinx/common/fru.h b/include/fru.h
similarity index 100%
rename from board/xilinx/common/fru.h
rename to include/fru.h
diff --git a/lib/Makefile b/lib/Makefile
index e3deb1528794..ef8933ae3aee 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -39,6 +39,7 @@ obj-y += crc16-ccitt.o
 obj-$(CONFIG_ERRNO_STR) += errno_str.o
 obj-$(CONFIG_FIT) += fdtdec_common.o
 obj-$(CONFIG_TEST_FDTDEC) += fdtdec_test.o
+obj-$(CONFIG_CMD_FRU) += fru_ops.o
 obj-$(CONFIG_GZIP_COMPRESSED) += gzip.o
 obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += smbios.o
 obj-$(CONFIG_SMBIOS_PARSER) += smbios-parser.o
diff --git a/board/xilinx/common/fru_ops.c b/lib/fru_ops.c
similarity index 99%
rename from board/xilinx/common/fru_ops.c
rename to lib/fru_ops.c
index e005ecae21fa..c0360f219c37 100644
--- a/board/xilinx/common/fru_ops.c
+++ b/lib/fru_ops.c
@@ -7,14 +7,13 @@
 #include <common.h>
 #include <env.h>
 #include <fdtdec.h>
+#include <fru.h>
 #include <hexdump.h>
 #include <log.h>
 #include <malloc.h>
 #include <asm/io.h>
 #include <linux/compat.h>
 
-#include "fru.h"
-
 struct fru_table fru_data __section(".data") = {
 	.brd.custom_fields = LIST_HEAD_INIT(fru_data.brd.custom_fields),
 	.multi_recs = LIST_HEAD_INIT(fru_data.multi_recs),
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 3/7] cmd: fru: fix a sandbox segfault issue
  2022-08-23 21:52 [PATCH v3 0/7] cmd/fru: move FRU handling support to common region Jae Hyun Yoo
  2022-08-23 21:52 ` [PATCH v3 1/7] xilinx: common: refactor FRU handling support Jae Hyun Yoo
  2022-08-23 21:52 ` [PATCH v3 2/7] cmd: fru: move FRU handling support to common region Jae Hyun Yoo
@ 2022-08-23 21:52 ` Jae Hyun Yoo
  2022-08-23 21:52 ` [PATCH v3 4/7] cmd: fru: add product info area parsing support Jae Hyun Yoo
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Jae Hyun Yoo @ 2022-08-23 21:52 UTC (permalink / raw)
  To: Michal Simek, Ovidiu Panait, Simon Glass, Mario Six,
	Masahisa Kojima, Pali Rohár, Heinrich Schuchardt,
	Ashok Reddy Soma, Thomas Huth, Huang Jianan, Chris Morgan,
	Roland Gaudig, Patrick Delaunay, Alexandru Gagniuc
  Cc: Jamie Iles, Graeme Gregory, Cédric Le Goater, Jae Hyun Yoo, u-boot

This command doesn't work with sandbox because direct memory access
causes a segfault error. Fix it up using map_sysmem().

Signed-off-by: Jae Hyun Yoo <quic_jaehyoo@quicinc.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
---
Changes from v2:
 * Added a 'Reviewed-by' tag. (Simon)

Changes from v1:
 * Newly added in v2.

 board/xilinx/common/board.c |  2 +-
 cmd/fru.c                   | 19 ++++++++++++++++---
 include/fru.h               |  4 ++--
 lib/fru_ops.c               | 17 ++++++++---------
 4 files changed, 27 insertions(+), 15 deletions(-)

diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c
index e58b11d7f757..3292083c5250 100644
--- a/board/xilinx/common/board.c
+++ b/board/xilinx/common/board.c
@@ -241,7 +241,7 @@ static int xilinx_read_eeprom_fru(struct udevice *dev, char *name,
 		goto end;
 	}
 
-	fru_capture((unsigned long)fru_content);
+	fru_capture(fru_content);
 	if (gd->flags & GD_FLG_RELOC || (_DEBUG && CONFIG_IS_ENABLED(DTB_RESELECT))) {
 		printf("Xilinx I2C FRU format at %s:\n", name);
 		ret = fru_display(0);
diff --git a/cmd/fru.c b/cmd/fru.c
index 2ec5012af5ac..b2cadbec9780 100644
--- a/cmd/fru.c
+++ b/cmd/fru.c
@@ -9,12 +9,15 @@
 #include <fdtdec.h>
 #include <fru.h>
 #include <malloc.h>
+#include <mapmem.h>
 
 static int do_fru_capture(struct cmd_tbl *cmdtp, int flag, int argc,
 			  char *const argv[])
 {
 	unsigned long addr;
+	const void *buf;
 	char *endp;
+	int ret;
 
 	if (argc < cmdtp->maxargs)
 		return CMD_RET_USAGE;
@@ -23,7 +26,11 @@ static int do_fru_capture(struct cmd_tbl *cmdtp, int flag, int argc,
 	if (*argv[1] == 0 || *endp != 0)
 		return -1;
 
-	return fru_capture(addr);
+	buf = map_sysmem(addr, 0);
+	ret = fru_capture(buf);
+	unmap_sysmem(buf);
+
+	return ret;
 }
 
 static int do_fru_display(struct cmd_tbl *cmdtp, int flag, int argc,
@@ -37,13 +44,19 @@ static int do_fru_generate(struct cmd_tbl *cmdtp, int flag, int argc,
 			   char *const argv[])
 {
 	unsigned long addr;
+	const void *buf;
+	int ret;
 
 	if (argc < cmdtp->maxargs)
 		return CMD_RET_USAGE;
 
-	addr = hextoul(argv[2], NULL);
+	addr = hextoul(argv[3], NULL);
+
+	buf = map_sysmem(addr, 0);
+	ret = fru_generate(buf, argc - 3, argv + 3);
+	unmap_sysmem(buf);
 
-	return fru_generate(addr, argc - 3, argv + 3);
+	return ret;
 }
 
 static struct cmd_tbl cmd_fru_sub[] = {
diff --git a/include/fru.h b/include/fru.h
index 41655864dbf5..b158b80b5866 100644
--- a/include/fru.h
+++ b/include/fru.h
@@ -107,8 +107,8 @@ struct fru_table {
 #define FRU_TYPELEN_TYPE_ASCII8		3
 
 int fru_display(int verbose);
-int fru_capture(unsigned long addr);
-int fru_generate(unsigned long addr, int argc, char *const argv[]);
+int fru_capture(const void *addr);
+int fru_generate(const void *addr, int argc, char *const argv[]);
 u8 fru_checksum(u8 *addr, u8 len);
 int fru_check_type_len(u8 type_len, u8 language, u8 *type);
 const struct fru_table *fru_get_fru_data(void);
diff --git a/lib/fru_ops.c b/lib/fru_ops.c
index c0360f219c37..6ed1388b2fc8 100644
--- a/lib/fru_ops.c
+++ b/lib/fru_ops.c
@@ -91,7 +91,7 @@ static u8 fru_gen_type_len(u8 *addr, char *name)
 	return 1 + len;
 }
 
-int fru_generate(unsigned long addr, int argc, char *const argv[])
+int fru_generate(const void *addr, int argc, char *const argv[])
 {
 	struct fru_common_hdr *header = (struct fru_common_hdr *)addr;
 	struct fru_board_info_header *board_info;
@@ -155,8 +155,8 @@ int fru_generate(unsigned long addr, int argc, char *const argv[])
 
 	debug("checksum %x(addr %x)\n", *member, len);
 
-	env_set_hex("fru_addr", addr);
-	env_set_hex("filesize", (unsigned long)member - addr + 1);
+	env_set_hex("fru_addr", (ulong)addr);
+	env_set_hex("filesize", (ulong)member - (ulong)addr + 1);
 
 	return 0;
 }
@@ -171,7 +171,7 @@ static void fru_delete_custom_fields(struct list_head *custom_fields)
 	}
 }
 
-static int fru_append_custom_info(unsigned long addr,
+static int fru_append_custom_info(const void *addr,
 				  struct list_head *custom_fields)
 {
 	struct fru_custom_info *info = (struct fru_custom_info *)addr;
@@ -190,7 +190,7 @@ static int fru_append_custom_info(unsigned long addr,
 	return 0;
 }
 
-static int fru_parse_board(unsigned long addr)
+static int fru_parse_board(const void *addr)
 {
 	u8 i, type;
 	int len;
@@ -268,8 +268,7 @@ static void fru_delete_multirecs(struct list_head *multi_recs)
 	}
 }
 
-static int fru_append_multirec(unsigned long addr,
-			       struct list_head *multi_recs)
+static int fru_append_multirec(const void *addr, struct list_head *multi_recs)
 {
 	struct fru_multirec_info *mr_src = (struct fru_multirec_info *)addr;
 	struct fru_multirec_node *mr_new;
@@ -286,7 +285,7 @@ static int fru_append_multirec(unsigned long addr,
 	return 0;
 }
 
-static int fru_parse_multirec(unsigned long addr)
+static int fru_parse_multirec(const void *addr)
 {
 	u8 hdr_len = sizeof(struct fru_multirec_hdr);
 	struct fru_multirec_hdr *mr_hdr;
@@ -308,7 +307,7 @@ static int fru_parse_multirec(unsigned long addr)
 	return 0;
 }
 
-int fru_capture(unsigned long addr)
+int fru_capture(const void *addr)
 {
 	struct fru_common_hdr *hdr;
 	u8 checksum = 0;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 4/7] cmd: fru: add product info area parsing support
  2022-08-23 21:52 [PATCH v3 0/7] cmd/fru: move FRU handling support to common region Jae Hyun Yoo
                   ` (2 preceding siblings ...)
  2022-08-23 21:52 ` [PATCH v3 3/7] cmd: fru: fix a sandbox segfault issue Jae Hyun Yoo
@ 2022-08-23 21:52 ` Jae Hyun Yoo
  2022-08-25  1:25   ` Simon Glass
  2022-08-23 21:52 ` [PATCH v3 5/7] doc: fru: add documentation for the fru command and APIs Jae Hyun Yoo
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 15+ messages in thread
From: Jae Hyun Yoo @ 2022-08-23 21:52 UTC (permalink / raw)
  To: Michal Simek, Ovidiu Panait, Simon Glass, Mario Six,
	Masahisa Kojima, Pali Rohár, Heinrich Schuchardt,
	Ashok Reddy Soma, Thomas Huth, Huang Jianan, Chris Morgan,
	Roland Gaudig, Patrick Delaunay, Alexandru Gagniuc
  Cc: Jamie Iles, Graeme Gregory, Cédric Le Goater, Jae Hyun Yoo, u-boot

Add product info area parsing support. Custom board fields can be
added dynamically using linked list so that each board support can
utilize them in their own custom way.

Signed-off-by: Jae Hyun Yoo <quic_jaehyoo@quicinc.com>
---
Changes from v2:
 * Changed 'struct fru_board_info_member' to 'struct fru_common_info_member'.

Changes from v1:
 * Refactored using linked list instead of calling a custom parsing callback.

Changes from RFC:
 * Added manufacturer custom product info fields parsing flow.

 cmd/fru.c     |  28 ++++--
 include/fru.h |  34 ++++++-
 lib/fru_ops.c | 244 +++++++++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 286 insertions(+), 20 deletions(-)

diff --git a/cmd/fru.c b/cmd/fru.c
index b2cadbec9780..42bdaae09449 100644
--- a/cmd/fru.c
+++ b/cmd/fru.c
@@ -43,11 +43,22 @@ static int do_fru_display(struct cmd_tbl *cmdtp, int flag, int argc,
 static int do_fru_generate(struct cmd_tbl *cmdtp, int flag, int argc,
 			   char *const argv[])
 {
+	int (*fru_generate)(const void *addr, int argc, char *const argv[]);
 	unsigned long addr;
 	const void *buf;
-	int ret;
+	int ret, maxargs;
+
+	if (!strncmp(argv[2], "-b", 3)) {
+		fru_generate = fru_board_generate;
+		maxargs = cmdtp->maxargs + FRU_BOARD_AREA_TOTAL_FIELDS;
+	} else if (!strncmp(argv[2], "-p", 3)) {
+		fru_generate = fru_product_generate;
+		maxargs = cmdtp->maxargs + FRU_PRODUCT_AREA_TOTAL_FIELDS;
+	} else {
+		return CMD_RET_USAGE;
+	}
 
-	if (argc < cmdtp->maxargs)
+	if (argc < maxargs)
 		return CMD_RET_USAGE;
 
 	addr = hextoul(argv[3], NULL);
@@ -62,7 +73,7 @@ static int do_fru_generate(struct cmd_tbl *cmdtp, int flag, int argc,
 static struct cmd_tbl cmd_fru_sub[] = {
 	U_BOOT_CMD_MKENT(capture, 3, 0, do_fru_capture, "", ""),
 	U_BOOT_CMD_MKENT(display, 2, 0, do_fru_display, "", ""),
-	U_BOOT_CMD_MKENT(board_gen, 8, 0, do_fru_generate, "", ""),
+	U_BOOT_CMD_MKENT(generate, 4, 0, do_fru_generate, "", ""),
 };
 
 static int do_fru(struct cmd_tbl *cmdtp, int flag, int argc,
@@ -90,11 +101,16 @@ static char fru_help_text[] =
 	"capture <addr> - Parse and capture FRU table present at address.\n"
 	"fru display - Displays content of FRU table that was captured using\n"
 	"              fru capture command\n"
-	"fru board_gen <addr> <manufacturer> <board name> <serial number>\n"
-	"              <part number> <file id> [custom ...] - Generate FRU\n"
-	"              format with board info area filled based on\n"
+	"fru generate -b <addr> <manufacturer> <board name> <serial number>\n"
+	"                <part number> <file id> [custom ...] - Generate FRU\n"
+	"                format with board info area filled based on\n"
 	"                parameters. <addr> is pointing to place where FRU is\n"
 	"                generated.\n"
+	"fru generate -p <addr> <manufacturer> <product name> <part number>\n"
+	"                <version number> <serial number> <asset number>\n"
+	"                <file id> [custom ...] - Generate FRU format with\n"
+	"                product info area filled based on parameters. <addr>\n"
+	"                is pointing to place where FRU is generated.\n"
 	;
 #endif
 
diff --git a/include/fru.h b/include/fru.h
index b158b80b5866..2b19033a3843 100644
--- a/include/fru.h
+++ b/include/fru.h
@@ -31,7 +31,13 @@ struct fru_board_info_header {
 	u8 time[3];
 } __packed;
 
-struct fru_board_info_member {
+struct fru_product_info_header {
+	u8 ver;
+	u8 len;
+	u8 lang_code;
+} __packed;
+
+struct fru_common_info_member {
 	u8 type_len;
 	u8 *name;
 } __packed;
@@ -64,6 +70,27 @@ struct fru_board_data {
 	struct list_head custom_fields;
 };
 
+struct fru_product_data {
+	u8 ver;
+	u8 len;
+	u8 lang_code;
+	u8 manufacturer_type_len;
+	u8 manufacturer_name[FRU_INFO_FIELD_LEN_MAX];
+	u8 product_name_type_len;
+	u8 product_name[FRU_INFO_FIELD_LEN_MAX];
+	u8 part_number_type_len;
+	u8 part_number[FRU_INFO_FIELD_LEN_MAX];
+	u8 version_number_type_len;
+	u8 version_number[FRU_INFO_FIELD_LEN_MAX];
+	u8 serial_number_type_len;
+	u8 serial_number[FRU_INFO_FIELD_LEN_MAX];
+	u8 asset_number_type_len;
+	u8 asset_number[FRU_INFO_FIELD_LEN_MAX];
+	u8 file_id_type_len;
+	u8 file_id[FRU_INFO_FIELD_LEN_MAX];
+	struct list_head custom_fields;
+};
+
 struct fru_multirec_hdr {
 	u8 rec_type;
 	u8 type;
@@ -85,6 +112,7 @@ struct fru_multirec_node {
 struct fru_table {
 	struct fru_common_hdr hdr;
 	struct fru_board_data brd;
+	struct fru_product_data prd;
 	struct list_head multi_recs;
 	bool captured;
 };
@@ -102,13 +130,15 @@ struct fru_table {
 
 /* This should be minimum of fields */
 #define FRU_BOARD_AREA_TOTAL_FIELDS	5
+#define FRU_PRODUCT_AREA_TOTAL_FIELDS	7
 #define FRU_TYPELEN_TYPE_SHIFT		6
 #define FRU_TYPELEN_TYPE_BINARY		0
 #define FRU_TYPELEN_TYPE_ASCII8		3
 
 int fru_display(int verbose);
 int fru_capture(const void *addr);
-int fru_generate(const void *addr, int argc, char *const argv[]);
+int fru_board_generate(const void *addr, int argc, char *const argv[]);
+int fru_product_generate(const void *addr, int argc, char *const argv[]);
 u8 fru_checksum(u8 *addr, u8 len);
 int fru_check_type_len(u8 type_len, u8 language, u8 *type);
 const struct fru_table *fru_get_fru_data(void);
diff --git a/lib/fru_ops.c b/lib/fru_ops.c
index 6ed1388b2fc8..b6197d3e250f 100644
--- a/lib/fru_ops.c
+++ b/lib/fru_ops.c
@@ -16,9 +16,18 @@
 
 struct fru_table fru_data __section(".data") = {
 	.brd.custom_fields = LIST_HEAD_INIT(fru_data.brd.custom_fields),
+	.prd.custom_fields = LIST_HEAD_INIT(fru_data.prd.custom_fields),
 	.multi_recs = LIST_HEAD_INIT(fru_data.multi_recs),
 };
 
+static const char * const fru_typecode_str[] = {
+	"Binary/Unspecified",
+	"BCD plus",
+	"6-bit ASCII",
+	"8-bit ASCII",
+	"2-byte UNICODE"
+};
+
 static u16 fru_cal_area_len(u8 len)
 {
 	return len * FRU_COMMON_HDR_LEN_MULTIPLIER;
@@ -77,9 +86,9 @@ int fru_check_type_len(u8 type_len, u8 language, u8 *type)
 static u8 fru_gen_type_len(u8 *addr, char *name)
 {
 	int len = strlen(name);
-	struct fru_board_info_member *member;
+	struct fru_common_info_member *member;
 
-	member = (struct fru_board_info_member *)addr;
+	member = (struct fru_common_info_member *)addr;
 	member->type_len = FRU_TYPELEN_TYPE_ASCII8 << FRU_TYPELEN_TYPE_SHIFT;
 	member->type_len |= len;
 
@@ -91,7 +100,7 @@ static u8 fru_gen_type_len(u8 *addr, char *name)
 	return 1 + len;
 }
 
-int fru_generate(const void *addr, int argc, char *const argv[])
+int fru_board_generate(const void *addr, int argc, char *const argv[])
 {
 	struct fru_common_hdr *header = (struct fru_common_hdr *)addr;
 	struct fru_board_info_header *board_info;
@@ -161,6 +170,74 @@ int fru_generate(const void *addr, int argc, char *const argv[])
 	return 0;
 }
 
+int fru_product_generate(const void *addr, int argc, char *const argv[])
+{
+	struct fru_common_hdr *header = (struct fru_common_hdr *)addr;
+	struct fru_product_info_header *product_info;
+	u8 *member;
+	u8 len, pad, modulo;
+
+	header->version = 1; /* Only version 1.0 is supported now */
+	header->off_internal = 0; /* not present */
+	header->off_chassis = 0; /* not present */
+	header->off_board = 0; /* not present */
+	header->off_product = (sizeof(*header)) / 8; /* Starting offset 8 */
+	header->off_multirec = 0; /* not present */
+	header->pad = 0;
+	/*
+	 * This unsigned byte can be used to calculate a zero checksum
+	 * for the data area following the header. I.e. the modulo 256 sum of
+	 * the record data bytes plus the checksum byte equals zero.
+	 */
+	header->crc = 0; /* Clear before calculation */
+	header->crc = 0 - fru_checksum((u8 *)header, sizeof(*header));
+
+	/* board info is just right after header */
+	product_info = (void *)((u8 *)header + sizeof(*header));
+
+	debug("header %lx, product_info %lx\n", (ulong)header,
+	      (ulong)product_info);
+
+	product_info->ver = 1; /* 1.0 spec */
+	product_info->lang_code = 0; /* English */
+
+	/* Member fields are just after board_info header */
+	member = (u8 *)product_info + sizeof(*product_info);
+
+	while (--argc > 0 && ++argv) {
+		len = fru_gen_type_len(member, *argv);
+		member += len;
+	}
+
+	*member++ = 0xc1; /* Indication of no more fields */
+
+	len = member - (u8 *)product_info; /* Find current length */
+	len += 1; /* Add checksum there too for calculation */
+
+	modulo = len % 8;
+
+	if (modulo) {
+		/* Do not fill last item which is checksum */
+		for (pad = 0; pad < 8 - modulo; pad++)
+			*member++ = 0;
+
+		/* Increase structure size */
+		len += 8 - modulo;
+	}
+
+	product_info->len = len / 8; /* Size in multiples of 8 bytes */
+
+	*member = 0; /* Clear before calculation */
+	*member = 0 - fru_checksum((u8 *)product_info, len);
+
+	debug("checksum %x(addr %x)\n", *member, len);
+
+	env_set_hex("fru_addr", (ulong)addr);
+	env_set_hex("filesize", (ulong)member - (ulong)addr + 1);
+
+	return 0;
+}
+
 static void fru_delete_custom_fields(struct list_head *custom_fields)
 {
 	struct fru_custom_field_node *node, *next;
@@ -258,6 +335,74 @@ static int fru_parse_board(const void *addr)
 	return 0;
 }
 
+static int fru_parse_product(const void *addr)
+{
+	u8 i, type;
+	int len;
+	u8 *data, *term, *limit;
+
+	memcpy(&fru_data.prd.ver, (void *)addr, 6);
+	addr += 3;
+	data = (u8 *)&fru_data.prd.manufacturer_type_len;
+
+	/* Record max structure limit not to write data over allocated space */
+	limit = (u8 *)&fru_data.prd + sizeof(struct fru_product_data) -
+		sizeof(struct fru_custom_field_node *);
+
+	for (i = 0; ; i++, data += FRU_INFO_FIELD_LEN_MAX) {
+		len = fru_check_type_len(*(u8 *)addr, fru_data.prd.lang_code,
+					 &type);
+		/*
+		 * Stop cature if it end of fields
+		 */
+		if (len == -EINVAL)
+			break;
+
+		if (i < FRU_PRODUCT_AREA_TOTAL_FIELDS) {
+			/* Stop when length is more then fields to record */
+			if (data + len > limit)
+				break;
+
+			/* This record type/len field */
+			*data++ = *(u8 *)addr;
+		}
+
+		/* Add offset to match data */
+		addr += 1;
+
+		/* If len is 0 it means empty field that's why skip writing */
+		if (!len)
+			continue;
+
+		if (i < FRU_PRODUCT_AREA_TOTAL_FIELDS) {
+			/* Record data field */
+			memcpy(data, (u8 *)addr, len);
+			term = data + (u8)len;
+			*term = 0;
+		} else {
+			struct list_head *custom_fields;
+
+			custom_fields = &fru_data.prd.custom_fields;
+
+			/* Add a custom info field */
+			if (fru_append_custom_info(addr - 1, custom_fields)) {
+				fru_delete_custom_fields(custom_fields);
+				return -EINVAL;
+			}
+		}
+
+		addr += len;
+	}
+
+	if (i < FRU_PRODUCT_AREA_TOTAL_FIELDS) {
+		printf("Product area require minimum %d fields\n",
+		       FRU_PRODUCT_AREA_TOTAL_FIELDS);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static void fru_delete_multirecs(struct list_head *multi_recs)
 {
 	struct fru_multirec_node *node, *next;
@@ -320,9 +465,11 @@ int fru_capture(const void *addr)
 
 	hdr = (struct fru_common_hdr *)addr;
 	fru_delete_custom_fields(&fru_data.brd.custom_fields);
+	fru_delete_custom_fields(&fru_data.prd.custom_fields);
 	fru_delete_multirecs(&fru_data.multi_recs);
 	memset((void *)&fru_data, 0, sizeof(fru_data));
 	INIT_LIST_HEAD(&fru_data.brd.custom_fields);
+	INIT_LIST_HEAD(&fru_data.prd.custom_fields);
 	INIT_LIST_HEAD(&fru_data.multi_recs);
 	memcpy((void *)&fru_data, (void *)hdr, sizeof(struct fru_common_hdr));
 
@@ -331,6 +478,9 @@ int fru_capture(const void *addr)
 	if (hdr->off_board)
 		fru_parse_board(addr + fru_cal_area_len(hdr->off_board));
 
+	if (hdr->off_product)
+		fru_parse_product(addr + fru_cal_area_len(hdr->off_product));
+
 	if (hdr->off_multirec)
 		fru_parse_multirec(addr + fru_cal_area_len(hdr->off_multirec));
 
@@ -341,13 +491,6 @@ int fru_capture(const void *addr)
 
 static int fru_display_board(struct fru_board_data *brd, int verbose)
 {
-	static const char * const typecode[] = {
-		"Binary/Unspecified",
-		"BCD plus",
-		"6-bit ASCII",
-		"8-bit ASCII",
-		"2-byte UNICODE"
-	};
 	static const char * const boardinfo[] = {
 		"Manufacturer Name",
 		"Product Name",
@@ -389,9 +532,9 @@ static int fru_display_board(struct fru_board_data *brd, int verbose)
 		if (type <= FRU_TYPELEN_TYPE_ASCII8 &&
 		    (brd->lang_code == FRU_LANG_CODE_ENGLISH ||
 		     brd->lang_code == FRU_LANG_CODE_ENGLISH_1))
-			debug("Type code: %s\n", typecode[type]);
+			debug("Type code: %s\n", fru_typecode_str[type]);
 		else
-			debug("Type code: %s\n", typecode[type + 1]);
+			debug("Type code: %s\n", fru_typecode_str[type + 1]);
 
 		if (!len) {
 			debug("%s not found\n", boardinfo[i]);
@@ -424,6 +567,79 @@ static int fru_display_board(struct fru_board_data *brd, int verbose)
 	return 0;
 }
 
+static int fru_display_product(struct fru_product_data *prd, int verbose)
+{
+	static const char * const productinfo[] = {
+		"Manufacturer Name",
+		"Product Name",
+		"Part Number",
+		"Version Number",
+		"Serial Number",
+		"Asset Number",
+		"File ID",
+	};
+	struct fru_custom_field_node *node;
+	u8 *data;
+	u8 type;
+	int len;
+
+	if (verbose) {
+		printf("*****PRODUCT INFO*****\n");
+		printf("Version:%d\n", fru_version(prd->ver));
+		printf("Product Area Length:%d\n", fru_cal_area_len(prd->len));
+	}
+
+	if (fru_check_language(prd->lang_code))
+		return -EINVAL;
+
+	data = (u8 *)&prd->manufacturer_type_len;
+
+	for (u8 i = 0; i < (sizeof(productinfo) / sizeof(*productinfo)); i++) {
+		len = fru_check_type_len(*data++, prd->lang_code,
+					 &type);
+		if (len == -EINVAL) {
+			printf("**** EOF for Product Area ****\n");
+			break;
+		}
+
+		if (type <= FRU_TYPELEN_TYPE_ASCII8 &&
+		    (prd->lang_code == FRU_LANG_CODE_ENGLISH ||
+		     prd->lang_code == FRU_LANG_CODE_ENGLISH_1))
+			debug("Type code: %s\n", fru_typecode_str[type]);
+		else
+			debug("Type code: %s\n", fru_typecode_str[type + 1]);
+
+		if (!len) {
+			debug("%s not found\n", productinfo[i]);
+			continue;
+		}
+
+		switch (type) {
+		case FRU_TYPELEN_TYPE_BINARY:
+			debug("Length: %d\n", len);
+			printf(" %s: 0x%x\n", productinfo[i], *data);
+			break;
+		case FRU_TYPELEN_TYPE_ASCII8:
+			debug("Length: %d\n", len);
+			printf(" %s: %s\n", productinfo[i], data);
+			break;
+		default:
+			debug("Unsupported type %x\n", type);
+		}
+
+		data += FRU_INFO_FIELD_LEN_MAX;
+	}
+
+	list_for_each_entry(node, &prd->custom_fields, list) {
+		printf(" Custom Type/Length: 0x%x\n", node->info.type_len);
+		print_hex_dump_bytes("  ", DUMP_PREFIX_OFFSET, node->info.data,
+				     node->info.type_len &
+				     FRU_TYPELEN_LEN_MASK);
+	}
+
+	return 0;
+}
+
 static int fru_display_multirec(struct list_head *multi_recs, int verbose)
 {
 	struct fru_multirec_node *node;
@@ -495,6 +711,10 @@ int fru_display(int verbose)
 	if (ret)
 		return ret;
 
+	ret = fru_display_product(&fru_data.prd, verbose);
+	if (ret)
+		return ret;
+
 	return fru_display_multirec(&fru_data.multi_recs, verbose);
 }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 5/7] doc: fru: add documentation for the fru command and APIs
  2022-08-23 21:52 [PATCH v3 0/7] cmd/fru: move FRU handling support to common region Jae Hyun Yoo
                   ` (3 preceding siblings ...)
  2022-08-23 21:52 ` [PATCH v3 4/7] cmd: fru: add product info area parsing support Jae Hyun Yoo
@ 2022-08-23 21:52 ` Jae Hyun Yoo
  2022-08-23 21:52 ` [PATCH v3 6/7] test: py: fru: add a test for the fru command Jae Hyun Yoo
  2022-08-23 21:53 ` [PATCH v3 7/7] test: cmd: fru: add unit " Jae Hyun Yoo
  6 siblings, 0 replies; 15+ messages in thread
From: Jae Hyun Yoo @ 2022-08-23 21:52 UTC (permalink / raw)
  To: Michal Simek, Ovidiu Panait, Simon Glass, Mario Six,
	Masahisa Kojima, Pali Rohár, Heinrich Schuchardt,
	Ashok Reddy Soma, Thomas Huth, Huang Jianan, Chris Morgan,
	Roland Gaudig, Patrick Delaunay, Alexandru Gagniuc
  Cc: Jamie Iles, Graeme Gregory, Cédric Le Goater, Jae Hyun Yoo, u-boot

Add a usage document for the 'fru' u-boot command.
Add kerneldocs for <fru.h>.

Signed-off-by: Jae Hyun Yoo <quic_jaehyoo@quicinc.com>
---
Changes from v2:
 * Added kerneldocs to 'include/fru.h'. (Simon)

Changes from v1:
 * Newly added in v2. (Heinrich)

 doc/usage/cmd/fru.rst | 144 +++++++++++++++++++++++++++++++++
 doc/usage/index.rst   |   1 +
 include/fru.h         | 182 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 327 insertions(+)
 create mode 100644 doc/usage/cmd/fru.rst

diff --git a/doc/usage/cmd/fru.rst b/doc/usage/cmd/fru.rst
new file mode 100644
index 000000000000..d65bbc6dcbba
--- /dev/null
+++ b/doc/usage/cmd/fru.rst
@@ -0,0 +1,144 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+fru command
+===========
+
+Synopsis
+--------
+
+::
+
+    fru capture <addr>
+    fru display
+    fru generate -b <addr> <manufacturer> <board name> <serial number> <part number> <file id> [<custom> ...]
+    fru generate -p <addr> <manufacturer> <product name> <part number> <version number> <serial number> <asset number> <file id> [<custom> ...]
+
+Description
+-----------
+
+The *fru* commands is used to generate, capture and display FRU (Field
+Replaceable Unit) information data.
+
+Capture
+~~~~~~~
+
+The *fru capture* command parses and captures FRU configuration table at
+a specified address.
+
+    addr
+        memory address which FRU configuration table is stored.
+
+Display
+~~~~~~~
+
+The *fru display* command displays FRU information that is parsed using
+fru capture command.
+
+Generate
+~~~~~~~~
+
+The *fru generate* command generates a FRU configuration table which has Board
+or Product Info Area using the given field parameters.
+
+    -b
+        generate FRU which has board info area.
+
+        addr
+            memory address which FRU configuration table will be stored.
+
+        manufacturer
+            board manufacturer string.
+
+        board name
+            board product name string.
+
+        serial number
+            board serial number string.
+
+        serial number
+            board serial number string.
+
+        part number
+            board part number string.
+
+        file id
+            FRU File ID string. The FRU File version field is a pre-defined
+            field provided as a manufacturing aid for verifying the file that
+            was used during manufacture or field update to load the FRU
+            information. The content is manufacturer-specific.
+
+        custom
+            additional custom board info area fields, if any.
+
+    -p
+        generate FRU which has product info area.
+
+        addr
+            memory address which FRU configuration table will be stored.
+
+        manufacturer
+            product manufacturer string.
+
+        board name
+            product name string.
+
+        part number
+            product part/model number string.
+
+        version number
+            product version number string.
+
+        serial number
+            product serial number string.
+
+        asset number
+            asset tag.
+
+        file id
+            FRU File ID string. The FRU File version field is a pre-defined
+            field provided as a manufacturing aid for verifying the file that
+            was used during manufacture or field update to load the FRU
+            information. The content is manufacturer-specific.
+
+        custom
+            additional custom product info area fields, if any.
+
+Example
+-------
+
+::
+
+    => fru generate -b 90000000 abc def ghi jkl mno prs tuv wxy
+    => fru capture 90000000
+    => fru display
+    *****COMMON HEADER*****
+    Version:1
+    *** No Internal Area ***
+    *** No Chassis Info Area ***
+    Board Area Offset:8
+    *** No Product Info Area ***
+    *** No MultiRecord Area ***
+    *****BOARD INFO*****
+    Version:1
+    Board Area Length:40
+    Time in Minutes from 0:00hrs 1/1/96: 0
+     Manufacturer Name: abc
+     Product Name: def
+     Serial Number: ghi
+     Part Number: jkl
+     File ID: mno
+     Custom Type/Length: 0xc3
+      00000000: 70 72 73                                         prs
+     Custom Type/Length: 0xc3
+      00000000: 74 75 76                                         tuv
+     Custom Type/Length: 0xc3
+      00000000: 77 78 79                                         wxy
+    *****PRODUCT INFO*****
+    Version:0
+    Product Area Length:0
+    *****MULTIRECORDS*****
+
+Configuration
+-------------
+
+The fru command is only available if CONFIG_CMD_FRU=y.
diff --git a/doc/usage/index.rst b/doc/usage/index.rst
index 28f9683a3e6f..e96a16356307 100644
--- a/doc/usage/index.rst
+++ b/doc/usage/index.rst
@@ -45,6 +45,7 @@ Shell commands
    cmd/fatload
    cmd/fdt
    cmd/for
+   cmd/fru
    cmd/gpio
    cmd/load
    cmd/loadm
diff --git a/include/fru.h b/include/fru.h
index 2b19033a3843..1d11fd1a5964 100644
--- a/include/fru.h
+++ b/include/fru.h
@@ -10,6 +10,21 @@
 
 #include <linux/list.h>
 
+/**
+ * struct fru_common_hdr - FRU common header
+ *
+ * @version:		Common header format version
+ * @off_internal:	Internal use area starting offset
+ * @off_chassis:	Chassis info area starting offset
+ * @off_board:		Board area starting offset
+ * @off_product:	Product info area starting offset
+ * @off_multirec:	MultiRecord area starting offset
+ * @pad:		PAD, write as 00h
+ * @crc:		Common header checksum (zero checksum)
+ *
+ * Offsets are all in multiples of 8 bytes). 00h indicates that the area is not
+ * present.
+ */
 struct fru_common_hdr {
 	u8 version;
 	u8 off_internal;
@@ -24,6 +39,17 @@ struct fru_common_hdr {
 #define FRU_INFO_FIELD_LEN_MAX		32
 #define FRU_MULTIREC_DATA_LEN_MAX	255
 
+/**
+ * struct fru_board_info_header - Board info area header
+ *
+ * @ver:	Board area format version
+ * @len:	Board area length (in multiples of 8 bytes)
+ * @lang_code:	Language code
+ * @time:	Mfg. date / time
+ *		Number of minutes from 0:00 hrs 1/1/96.
+ *		LSbyte first (little endian)
+ *		00_00_00h = unspecified
+ */
 struct fru_board_info_header {
 	u8 ver;
 	u8 len;
@@ -31,27 +57,71 @@ struct fru_board_info_header {
 	u8 time[3];
 } __packed;
 
+/**
+ * struct fru_product_info_header - Product info area header
+ *
+ * @ver:	Product area format version
+ * @len:	Product area length (in multiples of 8 bytes)
+ * @lang_code:	Language code
+ */
 struct fru_product_info_header {
 	u8 ver;
 	u8 len;
 	u8 lang_code;
 } __packed;
 
+/**
+ * struct fru_common_info_member - FRU common info member
+ *
+ * @type_len:	type/length byte
+ * @name:	Member information bytes
+ */
 struct fru_common_info_member {
 	u8 type_len;
 	u8 *name;
 } __packed;
 
+/**
+ * struct fru_custom_info - Custom info field
+ *
+ * @type_len:	Type/length byte
+ * @data:	Custom information bytes
+ */
 struct fru_custom_info {
 	u8 type_len;
 	u8 data[FRU_INFO_FIELD_LEN_MAX];
 } __packed;
 
+/**
+ * struct fru_custom_field_node - Linked list head for Custom info fields
+ *
+ * @list:	Linked list head
+ * @info:	Custom info field of the node
+ */
 struct fru_custom_field_node {
 	struct list_head list;
 	struct fru_custom_info info;
 };
 
+/**
+ * struct fru_board_data - Board info area
+ *
+ * @ver:			Board area format version
+ * @len:			Board area length (in multiples of 8 bytes)
+ * @lang_code:			Language code
+ * @time:			Mfg. date / time
+ * @manufacturer_type_len:	Type/length byte
+ * @manufacturer_name:		Board manufacturer name
+ * @product_name_type_len:	Type/length byte
+ * @product_name:		Board product name
+ * @serial_number_type_len:	Type/length byte
+ * @serial_number:		Board serial number
+ * @part_number_type_len:	Type/length byte
+ * @part_number:		Board part number
+ * @file_id_type_len:		Type/length byte
+ * @file_id:			FRU file ID
+ * @custom_fields:		Linked list head for Custom info fields
+ */
 struct fru_board_data {
 	u8 ver;
 	u8 len;
@@ -70,6 +140,28 @@ struct fru_board_data {
 	struct list_head custom_fields;
 };
 
+/**
+ * struct fru_product_data - Product info area
+ *
+ * @ver:			Product area format version
+ * @len:			Product area length (in multiples of 8 bytes)
+ * @lang_code:			Language code
+ * @manufacturer_type_len:	Type/length byte
+ * @manufacturer_name:		Product manufacturer name
+ * @product_name_type_len:	Type/length byte
+ * @product_name:		Product name
+ * @part_number_type_len:	Type/length byte
+ * @part_number:		Product part number
+ * @version_number_type_len:	Type/length byte
+ * @version_number:		Product version number
+ * @serial_number_type_len:	Type/length byte
+ * @serial_number:		Product serial number
+ * @asset_number_type_len:	Type/length byte
+ * @asset_number:		Product asset number
+ * @file_id_type_len:		Type/length byte
+ * @file_id:			FRU file ID
+ * @custom_fields:		Linked list head for Custom info fields
+ */
 struct fru_product_data {
 	u8 ver;
 	u8 len;
@@ -91,6 +183,15 @@ struct fru_product_data {
 	struct list_head custom_fields;
 };
 
+/**
+ * struct fru_multirec_hdr - MultiRecord area header
+ *
+ * @rec_type:	Product area format version
+ * @type:	Product area length (in multiples of 8 bytes)
+ * @len:	Language code
+ * @csum:	Type/length byte
+ * @hdr_csum:	Product manufacturer name
+ */
 struct fru_multirec_hdr {
 	u8 rec_type;
 	u8 type;
@@ -99,16 +200,37 @@ struct fru_multirec_hdr {
 	u8 hdr_csum;
 } __packed;
 
+/**
+ * struct fru_multirec_info - MultiRecord info field
+ *
+ * @hdr:	MultiRecord area header
+ * @data:	MultiRecord information bytes
+ */
 struct fru_multirec_info {
 	struct fru_multirec_hdr hdr;
 	u8 data[FRU_MULTIREC_DATA_LEN_MAX];
 } __packed;
 
+/**
+ * struct fru_multirec_node - Linked list head for MultiRecords
+ *
+ * @list:	Linked list head
+ * @info:	MultiRecord info field of the node
+ */
 struct fru_multirec_node {
 	struct list_head list;
 	struct fru_multirec_info info;
 };
 
+/**
+ * struct fru_table - FRU table storage
+ *
+ * @hdr:	FRU common header
+ * @brd:	Board info
+ * @prd:	Product info
+ * @multi_recs:	MultiRecords
+ * @captured:	TRUE when this table is captured and parsed
+ */
 struct fru_table {
 	struct fru_common_hdr hdr;
 	struct fru_board_data brd;
@@ -135,12 +257,72 @@ struct fru_table {
 #define FRU_TYPELEN_TYPE_BINARY		0
 #define FRU_TYPELEN_TYPE_ASCII8		3
 
+/**
+ * fru_display() - display captured FRU information
+ *
+ * @verbose:	Enable (1) verbose output or not (0)
+ *
+ * Returns 0 on success or a negative error code.
+ */
 int fru_display(int verbose);
+
+/**
+ * fru_display() - parse and capture FRU configuration table
+ *
+ * @addr:	Address where the FRU configuration table is stored
+ *
+ * Returns 0 on success or a negative error code.
+ */
 int fru_capture(const void *addr);
+
+/**
+ * fru_board_generate() - generate FRU which has board info area
+ *
+ * @addr:	Address to store generated FRU configuration table at
+ * @argc:	Length of @argv
+ * @argv:	Vector of arguments. See doc/usage/fru.rst for more details
+ *
+ * Returns 0 on success or a negative error code.
+ */
 int fru_board_generate(const void *addr, int argc, char *const argv[]);
+
+/**
+ * fru_product_generate() - generate FRU which has product info area
+ *
+ * @addr:	Address to store generated FRU configuration table at
+ * @argc:	Length of @argv
+ * @argv:	Vector of arguments. See doc/usage/fru.rst for more details
+ *
+ * Returns 0 on success or a negative error code.
+ */
 int fru_product_generate(const void *addr, int argc, char *const argv[]);
+
+/**
+ * fru_checksum() - calculate checksum of FRU info
+ *
+ * @addr:	Address of the FRU info data source
+ * @len:	Length of the FRU info data
+ *
+ * Returns a calculated checksum.
+ */
 u8 fru_checksum(u8 *addr, u8 len);
+
+/**
+ * fru_check_type_len() - check and parse type/len byte
+ *
+ * @type_len:	Type/len byte
+ * @language:	Language code byte
+ * @type:	Pointer to a variable to store parsed type
+ *
+ * Returns length of the type, -EINVAL on the FRU_TYPELEN_EOF type
+ */
 int fru_check_type_len(u8 type_len, u8 language, u8 *type);
+
+/**
+ * fru_get_fru_data() - get pointer to captured FRU info table
+ *
+ * Returns pointer to captured FRU table
+ */
 const struct fru_table *fru_get_fru_data(void);
 
 #endif /* FRU_H */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 6/7] test: py: fru: add a test for the fru command
  2022-08-23 21:52 [PATCH v3 0/7] cmd/fru: move FRU handling support to common region Jae Hyun Yoo
                   ` (4 preceding siblings ...)
  2022-08-23 21:52 ` [PATCH v3 5/7] doc: fru: add documentation for the fru command and APIs Jae Hyun Yoo
@ 2022-08-23 21:52 ` Jae Hyun Yoo
  2022-08-25  1:25   ` Simon Glass
  2022-08-23 21:53 ` [PATCH v3 7/7] test: cmd: fru: add unit " Jae Hyun Yoo
  6 siblings, 1 reply; 15+ messages in thread
From: Jae Hyun Yoo @ 2022-08-23 21:52 UTC (permalink / raw)
  To: Michal Simek, Ovidiu Panait, Simon Glass, Mario Six,
	Masahisa Kojima, Pali Rohár, Heinrich Schuchardt,
	Ashok Reddy Soma, Thomas Huth, Huang Jianan, Chris Morgan,
	Roland Gaudig, Patrick Delaunay, Alexandru Gagniuc
  Cc: Jamie Iles, Graeme Gregory, Cédric Le Goater, Jae Hyun Yoo, u-boot

Add a simple test for the 'fru' command.

Signed-off-by: Jae Hyun Yoo <quic_jaehyoo@quicinc.com>
---
Changes from v2:
 * Added CONFIG_CMD_FRU=y only into the sandbox_defconfig. (Simon)

Changes from v1:
 * Newly added in v2. (Heinrich)

 configs/sandbox_defconfig |  1 +
 test/py/tests/test_fru.py | 47 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+)
 create mode 100644 test/py/tests/test_fru.py

diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index eba7bcbb483b..293e39706cf2 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -115,6 +115,7 @@ CONFIG_CMD_EXT4_WRITE=y
 CONFIG_CMD_SQUASHFS=y
 CONFIG_CMD_MTDPARTS=y
 CONFIG_CMD_STACKPROTECTOR_TEST=y
+CONFIG_CMD_FRU=y
 CONFIG_MAC_PARTITION=y
 CONFIG_AMIGA_PARTITION=y
 CONFIG_OF_CONTROL=y
diff --git a/test/py/tests/test_fru.py b/test/py/tests/test_fru.py
new file mode 100644
index 000000000000..e5e1d7d00639
--- /dev/null
+++ b/test/py/tests/test_fru.py
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+
+import pytest
+import u_boot_utils
+
+@pytest.mark.buildconfigspec('cmd_fru')
+def test_fru_board(u_boot_console):
+    """Test that fru command generates and captures board FRU information as
+    expected."""
+
+    ram_base = u_boot_utils.find_ram_base(u_boot_console)
+    addr = '0x%x' % ram_base
+    expected_response = 'rc:0'
+    response = u_boot_console.run_command('fru generate -b ' + addr + ' abcd efgh ijkl mnop qrst uvwx; echo rc:$?')
+    assert(expected_response in response)
+    response = u_boot_console.run_command('fru capture ' + addr + '; echo rc:$?')
+    assert(expected_response in response)
+    response = u_boot_console.run_command('fru display')
+    assert('Manufacturer Name: abcd' in response)
+    assert('Product Name: efgh' in response)
+    assert('Serial Number: ijkl' in response)
+    assert('Part Number: mnop' in response)
+    assert('File ID: qrst' in response)
+    assert('Custom Type/Length: 0xc4' in response)
+
+@pytest.mark.buildconfigspec('cmd_fru')
+def test_fru_product(u_boot_console):
+    """Test that fru command generates and captures product FRU information as
+    expected."""
+
+    ram_base = u_boot_utils.find_ram_base(u_boot_console)
+    addr = '0x%x' % ram_base
+    expected_response = 'rc:0'
+    response = u_boot_console.run_command('fru generate -p ' + addr + ' abcd efgh ijkl mnop qrst uvwx yz01 2345; echo rc:$?')
+    assert(expected_response in response)
+    response = u_boot_console.run_command('fru capture ' + addr + '; echo rc:$?')
+    assert(expected_response in response)
+    response = u_boot_console.run_command('fru display')
+    assert('Manufacturer Name: abcd' in response)
+    assert('Product Name: efgh' in response)
+    assert('Part Number: ijkl' in response)
+    assert('Version Number: mnop' in response)
+    assert('Serial Number: qrst' in response)
+    assert('Asset Number: uvwx' in response)
+    assert('File ID: yz01' in response)
+    assert('Custom Type/Length: 0xc4' in response)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 7/7] test: cmd: fru: add unit test for the fru command
  2022-08-23 21:52 [PATCH v3 0/7] cmd/fru: move FRU handling support to common region Jae Hyun Yoo
                   ` (5 preceding siblings ...)
  2022-08-23 21:52 ` [PATCH v3 6/7] test: py: fru: add a test for the fru command Jae Hyun Yoo
@ 2022-08-23 21:53 ` Jae Hyun Yoo
  2022-08-25  1:25   ` Simon Glass
  6 siblings, 1 reply; 15+ messages in thread
From: Jae Hyun Yoo @ 2022-08-23 21:53 UTC (permalink / raw)
  To: Michal Simek, Ovidiu Panait, Simon Glass, Mario Six,
	Masahisa Kojima, Pali Rohár, Heinrich Schuchardt,
	Ashok Reddy Soma, Thomas Huth, Huang Jianan, Chris Morgan,
	Roland Gaudig, Patrick Delaunay, Alexandru Gagniuc
  Cc: Jamie Iles, Graeme Gregory, Cédric Le Goater, Jae Hyun Yoo, u-boot

Add test cases for the fru command.

Signed-off-by: Jae Hyun Yoo <quic_jaehyoo@quicinc.com>
---
Changes from v2:
 * Newly added in v3. (Simon)

 include/test/suites.h |  1 +
 test/cmd/Makefile     |  1 +
 test/cmd/fru.c        | 84 +++++++++++++++++++++++++++++++++++++++++++
 test/cmd_ut.c         |  6 ++++
 4 files changed, 92 insertions(+)
 create mode 100644 test/cmd/fru.c

diff --git a/include/test/suites.h b/include/test/suites.h
index 44025ccecd6f..1d4a8c3e4a66 100644
--- a/include/test/suites.h
+++ b/include/test/suites.h
@@ -39,6 +39,7 @@ int do_ut_compression(struct cmd_tbl *cmdtp, int flag, int argc,
 int do_ut_dm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
 int do_ut_env(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
 int do_ut_fdt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
+int do_ut_fru(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
 int do_ut_lib(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
 int do_ut_loadm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
 int do_ut_log(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]);
diff --git a/test/cmd/Makefile b/test/cmd/Makefile
index c331757425ea..5995384dad91 100644
--- a/test/cmd/Makefile
+++ b/test/cmd/Makefile
@@ -8,6 +8,7 @@ endif
 obj-y += mem.o
 obj-$(CONFIG_CMD_ADDRMAP) += addrmap.o
 obj-$(CONFIG_CMD_FDT) += fdt.o
+obj-$(CONFIG_CMD_FRU) += fru.o
 obj-$(CONFIG_CMD_LOADM) += loadm.o
 obj-$(CONFIG_CMD_MEM_SEARCH) += mem_search.o
 obj-$(CONFIG_CMD_PINMUX) += pinmux.o
diff --git a/test/cmd/fru.c b/test/cmd/fru.c
new file mode 100644
index 000000000000..fa560622cf0b
--- /dev/null
+++ b/test/cmd/fru.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Executes tests for fru command
+ *
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <common.h>
+#include <console.h>
+#include <mapmem.h>
+#include <test/suites.h>
+#include <test/ut.h>
+
+#define FRU_TEST(_name, _flags)	UNIT_TEST(_name, _flags, fru_test)
+
+#define CMD_FRU_TEST_SRC_BUF_SIZE 1024
+
+static const char cmd_gen_b[] =
+	"fru generate -b %08lx abcd efgh ijkl mnop qrst uvwx";
+static const char cmd_gen_p[] =
+	"fru generate -p %08lx abcd efgh ijkl mnop qrst uvwx yz01 2345";
+
+static const char cmd_capture[] = "fru capture %08lx";
+
+static int fru_test_board(struct unit_test_state *uts)
+{
+	u8 fru_src[CMD_FRU_TEST_SRC_BUF_SIZE];
+	int i;
+
+	ut_assertok(console_record_reset_enable());
+	ut_assertok(run_commandf(cmd_gen_b, (ulong)map_to_sysmem(fru_src)));
+	ut_assertok(run_commandf(cmd_capture, (ulong)map_to_sysmem(fru_src)));
+	ut_assertok(run_command("fru display", 0));
+	for (i = 0; i < 11; i++)
+		ut_assert_skipline();
+	ut_assert_nextline(" Manufacturer Name: abcd");
+	ut_assert_nextline(" Product Name: efgh");
+	ut_assert_nextline(" Serial Number: ijkl");
+	ut_assert_nextline(" Part Number: mnop");
+	ut_assert_nextline(" File ID: qrst");
+	ut_assert_nextline(" Custom Type/Length: 0xc4");
+	ut_assert_nextline("  00000000: 75 76 77 78                                      uvwx");
+	for (i = 0; i < 4; i++)
+		ut_assert_skipline();
+	ut_assertok(ut_check_console_end(uts));
+
+	return 0;
+}
+FRU_TEST(fru_test_board, UT_TESTF_CONSOLE_REC);
+
+static int fru_test_product(struct unit_test_state *uts)
+{
+	u8 fru_src[CMD_FRU_TEST_SRC_BUF_SIZE];
+	int i;
+
+	ut_assertok(console_record_reset_enable());
+	ut_assertok(run_commandf(cmd_gen_p, (ulong)map_to_sysmem(fru_src)));
+	ut_assertok(run_commandf(cmd_capture, (ulong)map_to_sysmem(fru_src)));
+	ut_assertok(run_command("fru display", 0));
+	for (i = 0; i < 14; i++)
+		ut_assert_skipline();
+	ut_assert_nextline(" Manufacturer Name: abcd");
+	ut_assert_nextline(" Product Name: efgh");
+	ut_assert_nextline(" Part Number: ijkl");
+	ut_assert_nextline(" Version Number: mnop");
+	ut_assert_nextline(" Serial Number: qrst");
+	ut_assert_nextline(" Asset Number: uvwx");
+	ut_assert_nextline(" File ID: yz01");
+	ut_assert_nextline(" Custom Type/Length: 0xc4");
+	ut_assert_nextline("  00000000: 32 33 34 35                                      2345");
+	ut_assert_skipline();
+	ut_assertok(ut_check_console_end(uts));
+
+	return 0;
+}
+FRU_TEST(fru_test_product, UT_TESTF_CONSOLE_REC);
+
+int do_ut_fru(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+	struct unit_test *tests = UNIT_TEST_SUITE_START(fru_test);
+	const int n_ents = UNIT_TEST_SUITE_COUNT(fru_test);
+
+	return cmd_ut_category("fru", "fru_test_", tests, n_ents, argc, argv);
+}
diff --git a/test/cmd_ut.c b/test/cmd_ut.c
index 3789c6b784c0..4c163da8176c 100644
--- a/test/cmd_ut.c
+++ b/test/cmd_ut.c
@@ -80,6 +80,9 @@ static struct cmd_tbl cmd_ut_sub[] = {
 #ifdef CONFIG_CMD_LOADM
 	U_BOOT_CMD_MKENT(loadm, CONFIG_SYS_MAXARGS, 1, do_ut_loadm, "", ""),
 #endif
+#ifdef CONFIG_CMD_FRU
+	U_BOOT_CMD_MKENT(fru, CONFIG_SYS_MAXARGS, 1, do_ut_fru, "", ""),
+#endif
 };
 
 static int do_ut_all(struct cmd_tbl *cmdtp, int flag, int argc,
@@ -167,6 +170,9 @@ static char ut_help_text[] =
 #endif
 #ifdef CONFIG_CMD_LOADM
 	"ut loadm [test-name]- test of parameters and load memory blob\n"
+#endif
+#ifdef CONFIG_CMD_FRU
+	"ut fru [test-name] - test of the fru command\n"
 #endif
 	;
 #endif /* CONFIG_SYS_LONGHELP */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v3 4/7] cmd: fru: add product info area parsing support
  2022-08-23 21:52 ` [PATCH v3 4/7] cmd: fru: add product info area parsing support Jae Hyun Yoo
@ 2022-08-25  1:25   ` Simon Glass
  2022-08-25 14:33     ` Jae Hyun Yoo
  0 siblings, 1 reply; 15+ messages in thread
From: Simon Glass @ 2022-08-25  1:25 UTC (permalink / raw)
  To: Jae Hyun Yoo
  Cc: Michal Simek, Ovidiu Panait, Mario Six, Masahisa Kojima,
	Pali Rohár, Heinrich Schuchardt, Ashok Reddy Soma,
	Thomas Huth, Huang Jianan, Chris Morgan, Roland Gaudig,
	Patrick Delaunay, Alexandru Gagniuc, Jamie Iles, Graeme Gregory,
	Cédric Le Goater, U-Boot Mailing List

Hi Jae,

On Tue, 23 Aug 2022 at 14:53, Jae Hyun Yoo <quic_jaehyoo@quicinc.com> wrote:
>
> Add product info area parsing support. Custom board fields can be
> added dynamically using linked list so that each board support can
> utilize them in their own custom way.
>
> Signed-off-by: Jae Hyun Yoo <quic_jaehyoo@quicinc.com>
> ---
> Changes from v2:
>  * Changed 'struct fru_board_info_member' to 'struct fru_common_info_member'.
>
> Changes from v1:
>  * Refactored using linked list instead of calling a custom parsing callback.
>
> Changes from RFC:
>  * Added manufacturer custom product info fields parsing flow.
>
>  cmd/fru.c     |  28 ++++--
>  include/fru.h |  34 ++++++-
>  lib/fru_ops.c | 244 +++++++++++++++++++++++++++++++++++++++++++++++---
>  3 files changed, 286 insertions(+), 20 deletions(-)
>

Please add tests for this code.

Regards,
Simon

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v3 7/7] test: cmd: fru: add unit test for the fru command
  2022-08-23 21:53 ` [PATCH v3 7/7] test: cmd: fru: add unit " Jae Hyun Yoo
@ 2022-08-25  1:25   ` Simon Glass
  2022-08-25 14:34     ` Jae Hyun Yoo
  0 siblings, 1 reply; 15+ messages in thread
From: Simon Glass @ 2022-08-25  1:25 UTC (permalink / raw)
  To: Jae Hyun Yoo
  Cc: Michal Simek, Ovidiu Panait, Mario Six, Masahisa Kojima,
	Pali Rohár, Heinrich Schuchardt, Ashok Reddy Soma,
	Thomas Huth, Huang Jianan, Chris Morgan, Roland Gaudig,
	Patrick Delaunay, Alexandru Gagniuc, Jamie Iles, Graeme Gregory,
	Cédric Le Goater, U-Boot Mailing List

On Tue, 23 Aug 2022 at 14:53, Jae Hyun Yoo <quic_jaehyoo@quicinc.com> wrote:
>
> Add test cases for the fru command.
>
> Signed-off-by: Jae Hyun Yoo <quic_jaehyoo@quicinc.com>
> ---
> Changes from v2:
>  * Newly added in v3. (Simon)
>
>  include/test/suites.h |  1 +
>  test/cmd/Makefile     |  1 +
>  test/cmd/fru.c        | 84 +++++++++++++++++++++++++++++++++++++++++++
>  test/cmd_ut.c         |  6 ++++
>  4 files changed, 92 insertions(+)
>  create mode 100644 test/cmd/fru.c

Reviewed-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v3 6/7] test: py: fru: add a test for the fru command
  2022-08-23 21:52 ` [PATCH v3 6/7] test: py: fru: add a test for the fru command Jae Hyun Yoo
@ 2022-08-25  1:25   ` Simon Glass
  2022-08-25 14:35     ` Jae Hyun Yoo
  0 siblings, 1 reply; 15+ messages in thread
From: Simon Glass @ 2022-08-25  1:25 UTC (permalink / raw)
  To: Jae Hyun Yoo
  Cc: Michal Simek, Ovidiu Panait, Mario Six, Masahisa Kojima,
	Pali Rohár, Heinrich Schuchardt, Ashok Reddy Soma,
	Thomas Huth, Huang Jianan, Chris Morgan, Roland Gaudig,
	Patrick Delaunay, Alexandru Gagniuc, Jamie Iles, Graeme Gregory,
	Cédric Le Goater, U-Boot Mailing List

Hi,

On Tue, 23 Aug 2022 at 14:53, Jae Hyun Yoo <quic_jaehyoo@quicinc.com> wrote:
>
> Add a simple test for the 'fru' command.
>
> Signed-off-by: Jae Hyun Yoo <quic_jaehyoo@quicinc.com>
> ---
> Changes from v2:
>  * Added CONFIG_CMD_FRU=y only into the sandbox_defconfig. (Simon)
>
> Changes from v1:
>  * Newly added in v2. (Heinrich)
>
>  configs/sandbox_defconfig |  1 +
>  test/py/tests/test_fru.py | 47 +++++++++++++++++++++++++++++++++++++++
>  2 files changed, 48 insertions(+)
>  create mode 100644 test/py/tests/test_fru.py

Can you just rely on the C test and not have this?

Regards,
Simon

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v3 4/7] cmd: fru: add product info area parsing support
  2022-08-25  1:25   ` Simon Glass
@ 2022-08-25 14:33     ` Jae Hyun Yoo
  2022-08-25 15:08       ` Simon Glass
  0 siblings, 1 reply; 15+ messages in thread
From: Jae Hyun Yoo @ 2022-08-25 14:33 UTC (permalink / raw)
  To: Simon Glass
  Cc: Michal Simek, Ovidiu Panait, Mario Six, Masahisa Kojima,
	Pali Rohár, Heinrich Schuchardt, Ashok Reddy Soma,
	Thomas Huth, Huang Jianan, Chris Morgan, Roland Gaudig,
	Patrick Delaunay, Alexandru Gagniuc, Jamie Iles, Graeme Gregory,
	Cédric Le Goater, U-Boot Mailing List

Hi Simon,

On 8/24/2022 6:25 PM, Simon Glass wrote:
> Hi Jae,
> 
> On Tue, 23 Aug 2022 at 14:53, Jae Hyun Yoo <quic_jaehyoo@quicinc.com> wrote:
>>
>> Add product info area parsing support. Custom board fields can be
>> added dynamically using linked list so that each board support can
>> utilize them in their own custom way.
>>
>> Signed-off-by: Jae Hyun Yoo <quic_jaehyoo@quicinc.com>
>> ---
>> Changes from v2:
>>   * Changed 'struct fru_board_info_member' to 'struct fru_common_info_member'.
>>
>> Changes from v1:
>>   * Refactored using linked list instead of calling a custom parsing callback.
>>
>> Changes from RFC:
>>   * Added manufacturer custom product info fields parsing flow.
>>
>>   cmd/fru.c     |  28 ++++--
>>   include/fru.h |  34 ++++++-
>>   lib/fru_ops.c | 244 +++++++++++++++++++++++++++++++++++++++++++++++---
>>   3 files changed, 286 insertions(+), 20 deletions(-)
>>
> 
> Please add tests for this code.

I already added c and python version unit test scripts in this series.

Thanks,
Jae

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v3 7/7] test: cmd: fru: add unit test for the fru command
  2022-08-25  1:25   ` Simon Glass
@ 2022-08-25 14:34     ` Jae Hyun Yoo
  0 siblings, 0 replies; 15+ messages in thread
From: Jae Hyun Yoo @ 2022-08-25 14:34 UTC (permalink / raw)
  To: Simon Glass
  Cc: Michal Simek, Ovidiu Panait, Mario Six, Masahisa Kojima,
	Pali Rohár, Heinrich Schuchardt, Ashok Reddy Soma,
	Thomas Huth, Huang Jianan, Chris Morgan, Roland Gaudig,
	Patrick Delaunay, Alexandru Gagniuc, Jamie Iles, Graeme Gregory,
	Cédric Le Goater, U-Boot Mailing List

Hi Simon,

On 8/24/2022 6:25 PM, Simon Glass wrote:
> On Tue, 23 Aug 2022 at 14:53, Jae Hyun Yoo <quic_jaehyoo@quicinc.com> wrote:
>>
>> Add test cases for the fru command.
>>
>> Signed-off-by: Jae Hyun Yoo <quic_jaehyoo@quicinc.com>
>> ---
>> Changes from v2:
>>   * Newly added in v3. (Simon)
>>
>>   include/test/suites.h |  1 +
>>   test/cmd/Makefile     |  1 +
>>   test/cmd/fru.c        | 84 +++++++++++++++++++++++++++++++++++++++++++
>>   test/cmd_ut.c         |  6 ++++
>>   4 files changed, 92 insertions(+)
>>   create mode 100644 test/cmd/fru.c
> 
> Reviewed-by: Simon Glass <sjg@chromium.org>

Oh, you found this unit test script. Thanks for your review!

Jae

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v3 6/7] test: py: fru: add a test for the fru command
  2022-08-25  1:25   ` Simon Glass
@ 2022-08-25 14:35     ` Jae Hyun Yoo
  0 siblings, 0 replies; 15+ messages in thread
From: Jae Hyun Yoo @ 2022-08-25 14:35 UTC (permalink / raw)
  To: Simon Glass
  Cc: Michal Simek, Ovidiu Panait, Mario Six, Masahisa Kojima,
	Pali Rohár, Heinrich Schuchardt, Ashok Reddy Soma,
	Thomas Huth, Huang Jianan, Chris Morgan, Roland Gaudig,
	Patrick Delaunay, Alexandru Gagniuc, Jamie Iles, Graeme Gregory,
	Cédric Le Goater, U-Boot Mailing List

On 8/24/2022 6:25 PM, Simon Glass wrote:
> Hi,
> 
> On Tue, 23 Aug 2022 at 14:53, Jae Hyun Yoo <quic_jaehyoo@quicinc.com> wrote:
>>
>> Add a simple test for the 'fru' command.
>>
>> Signed-off-by: Jae Hyun Yoo <quic_jaehyoo@quicinc.com>
>> ---
>> Changes from v2:
>>   * Added CONFIG_CMD_FRU=y only into the sandbox_defconfig. (Simon)
>>
>> Changes from v1:
>>   * Newly added in v2. (Heinrich)
>>
>>   configs/sandbox_defconfig |  1 +
>>   test/py/tests/test_fru.py | 47 +++++++++++++++++++++++++++++++++++++++
>>   2 files changed, 48 insertions(+)
>>   create mode 100644 test/py/tests/test_fru.py
> 
> Can you just rely on the C test and not have this?

Sure, I'll drop this python test script in the next spin.
Thanks for your review!

Regards,
Jae


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v3 4/7] cmd: fru: add product info area parsing support
  2022-08-25 14:33     ` Jae Hyun Yoo
@ 2022-08-25 15:08       ` Simon Glass
  0 siblings, 0 replies; 15+ messages in thread
From: Simon Glass @ 2022-08-25 15:08 UTC (permalink / raw)
  To: Jae Hyun Yoo
  Cc: Michal Simek, Ovidiu Panait, Mario Six, Masahisa Kojima,
	Pali Rohár, Heinrich Schuchardt, Ashok Reddy Soma,
	Thomas Huth, Huang Jianan, Chris Morgan, Roland Gaudig,
	Patrick Delaunay, Alexandru Gagniuc, Jamie Iles, Graeme Gregory,
	Cédric Le Goater, U-Boot Mailing List

Hi Jae,

On Thu, 25 Aug 2022 at 08:33, Jae Hyun Yoo <quic_jaehyoo@quicinc.com> wrote:
>
> Hi Simon,
>
> On 8/24/2022 6:25 PM, Simon Glass wrote:
> > Hi Jae,
> >
> > On Tue, 23 Aug 2022 at 14:53, Jae Hyun Yoo <quic_jaehyoo@quicinc.com> wrote:
> >>
> >> Add product info area parsing support. Custom board fields can be
> >> added dynamically using linked list so that each board support can
> >> utilize them in their own custom way.
> >>
> >> Signed-off-by: Jae Hyun Yoo <quic_jaehyoo@quicinc.com>
> >> ---
> >> Changes from v2:
> >>   * Changed 'struct fru_board_info_member' to 'struct fru_common_info_member'.
> >>
> >> Changes from v1:
> >>   * Refactored using linked list instead of calling a custom parsing callback.
> >>
> >> Changes from RFC:
> >>   * Added manufacturer custom product info fields parsing flow.
> >>
> >>   cmd/fru.c     |  28 ++++--
> >>   include/fru.h |  34 ++++++-
> >>   lib/fru_ops.c | 244 +++++++++++++++++++++++++++++++++++++++++++++++---
> >>   3 files changed, 286 insertions(+), 20 deletions(-)
> >>
> >
> > Please add tests for this code.
>
> I already added c and python version unit test scripts in this series.

Yes, I saw them later, thanks.

Regards,
Simon

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2022-08-25 15:08 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-23 21:52 [PATCH v3 0/7] cmd/fru: move FRU handling support to common region Jae Hyun Yoo
2022-08-23 21:52 ` [PATCH v3 1/7] xilinx: common: refactor FRU handling support Jae Hyun Yoo
2022-08-23 21:52 ` [PATCH v3 2/7] cmd: fru: move FRU handling support to common region Jae Hyun Yoo
2022-08-23 21:52 ` [PATCH v3 3/7] cmd: fru: fix a sandbox segfault issue Jae Hyun Yoo
2022-08-23 21:52 ` [PATCH v3 4/7] cmd: fru: add product info area parsing support Jae Hyun Yoo
2022-08-25  1:25   ` Simon Glass
2022-08-25 14:33     ` Jae Hyun Yoo
2022-08-25 15:08       ` Simon Glass
2022-08-23 21:52 ` [PATCH v3 5/7] doc: fru: add documentation for the fru command and APIs Jae Hyun Yoo
2022-08-23 21:52 ` [PATCH v3 6/7] test: py: fru: add a test for the fru command Jae Hyun Yoo
2022-08-25  1:25   ` Simon Glass
2022-08-25 14:35     ` Jae Hyun Yoo
2022-08-23 21:53 ` [PATCH v3 7/7] test: cmd: fru: add unit " Jae Hyun Yoo
2022-08-25  1:25   ` Simon Glass
2022-08-25 14:34     ` Jae Hyun Yoo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).