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_jaeh...@quicinc.com> --- Changes from RFC: * Added manufacturer custom product info fields parsing flow. 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 -- 2.25.1