
On 7/29/22 23:54, Jae Hyun Yoo wrote:
Add product info area parsing support. Custom product info field parsing function 'fru_parse_product_custom' can be replaced with a board specific implementation.
Signed-off-by: Jae Hyun Yoo quic_jaehyoo@quicinc.com
Changes from RFC:
- Added manufacturer custom product info fields parsing flow.
Please, provide a unit test for the new functions.
Best regards
Heinrich
common/fru_ops.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++- include/fru.h | 22 +++++++ 2 files changed, 182 insertions(+), 1 deletion(-)
diff --git a/common/fru_ops.c b/common/fru_ops.c index c03eeffbddc6..9f350f875035 100644 --- a/common/fru_ops.c +++ b/common/fru_ops.c @@ -264,6 +264,91 @@ static int fru_parse_board(unsigned long addr) return ret; }
+__weak int fru_parse_product_custom(unsigned long addr) +{
- int len;
- u8 type;
- do {
len = fru_check_type_len(*(u8 *)addr, fru_data.prd.lang_code,
&type);
if (len == -EINVAL)
break;
addr += 1;
/* Skip empty field */
if (!len)
continue;
if (DEBUG_PARSE_CUSTOM_FIELDS)
print_hex_dump_bytes("Product Custom Field: ",
DUMP_PREFIX_NONE, (u8 *)addr, len);
addr += len;
- } while (true);
- return 0;
+}
+static int fru_parse_product(unsigned long addr) +{
- u8 i, type;
- int len, ret = 0;
- 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);
- for (i = 0; i < FRU_PRODUCT_AREA_TOTAL_FIELDS;
i++, data += FRU_BOARD_MAX_LEN) {
len = fru_check_type_len(*(u8 *)addr, fru_data.prd.lang_code,
&type);
/*
* Stop cature if it end of fields
*/
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;
/* Add offset to match data */
addr += 1;
/* If len is 0 it means empty field that's why skip writing */
if (!len)
continue;
/* Record data field */
memcpy(data, (u8 *)addr, len);
term = data + (u8)len;
*term = 0;
addr += len;
- }
- if (i < FRU_PRODUCT_AREA_TOTAL_FIELDS) {
printf("Product area require minimum %d fields\n",
FRU_PRODUCT_AREA_TOTAL_FIELDS);
return -EINVAL;
- }
- len = fru_check_type_len(*(u8 *)addr, fru_data.prd.lang_code, &type);
- /* If it has custom fields, do custom parsing */
- if (len != -EINVAL)
ret = fru_parse_product_custom(addr);
- return ret;
+}
- __weak int fru_parse_multirec_oem(unsigned long addr) { struct fru_multirec_hdr *mrc = (struct fru_multirec_hdr *)addr;
@@ -319,6 +404,9 @@ int fru_capture(unsigned long 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));
@@ -397,6 +485,71 @@ 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) +{
- u8 type;
- int len;
- u8 *data;
- static const char * const productinfo[] = {
"Manufacturer Name",
"Product Name",
"Part Number",
"Version Number",
"Serial No",
"Asset Number",
"File ID",
- };
- 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_BOARD_MAX_LEN;
- }
- return 0;
+}
- static void fru_display_common_hdr(struct fru_common_hdr *hdr, int verbose) { if (!verbose)
@@ -437,6 +590,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;
@@ -444,7 +599,11 @@ 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_product(&fru_data.prd, verbose); }
const struct fru_table *fru_get_fru_data(void)
diff --git a/include/fru.h b/include/fru.h index f64fe1cca5e6..14643fd9616c 100644 --- a/include/fru.h +++ b/include/fru.h @@ -49,6 +49,26 @@ struct fru_board_data { u8 file_id[FRU_BOARD_MAX_LEN]; };
+struct fru_product_data {
- u8 ver;
- u8 len;
- u8 lang_code;
- u8 manufacturer_type_len;
- u8 manufacturer_name[FRU_BOARD_MAX_LEN];
- u8 product_name_type_len;
- u8 product_name[FRU_BOARD_MAX_LEN];
- u8 part_number_type_len;
- u8 part_number[FRU_BOARD_MAX_LEN];
- u8 version_number_type_len;
- u8 version_number[FRU_BOARD_MAX_LEN];
- u8 serial_number_type_len;
- u8 serial_number[FRU_BOARD_MAX_LEN];
- u8 asset_number_type_len;
- u8 asset_number[FRU_BOARD_MAX_LEN];
- u8 file_id_type_len;
- u8 file_id[FRU_BOARD_MAX_LEN];
+};
- struct fru_multirec_hdr { u8 rec_type; u8 type;
@@ -60,6 +80,7 @@ struct fru_multirec_hdr { struct fru_table { struct fru_common_hdr hdr; struct fru_board_data brd;
- struct fru_product_data prd; bool captured; };
@@ -74,6 +95,7 @@ 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