[RFC v2 0/3] lib: tlv_eeprom: refactor API

The existing tlv_eeprom functionality has been designed as a single application living as a uboot command. The split into individual library and command, as well as attempts using this functionality extensively for board-identification have revealed several short-comings, such as: - Inconsistent naming convention - Inconsistent order of arguments - Stateful functions - Complex inter-dependencies between functions - Control of low-level information such as header checksums by command - Difficult to extend - No clear separation between eeprom access and tlv format - No support for multiple entries with same code (e.g. vendor extension)
Introduce a new API with clear names and support for duplicate tlv codes. Further rewrite the tlv_eeprom command, and the solidrun clearfog board logic to utilize these new functions.
This is the second draft, I am looking for: - comments on the library functions names + descriptions - comments on the use of udevice pointers, especially wrt. "tlv_eeprom_get_by_index" function that I am not sure about keeping
Please note that there are still bugs and untested functions in this version. I am planning to provide a complete result in the coming weeks.
Josua Mayer (3): lib: add tlv_eeprom library mvebu: clearfog: convert tlv parsing to use new library cmd: tlv_eeprom: port to new shared tlv library
board/solidrun/common/tlv_data.c | 46 +-- cmd/Kconfig | 7 +- cmd/tlv_eeprom.c | 507 +++++--------------------- configs/clearfog_defconfig | 2 + include/tlv_eeprom.h | 242 ++++++++++--- lib/Kconfig | 2 + lib/Makefile | 2 + lib/tlv/Kconfig | 18 + lib/tlv/Makefile | 4 + lib/tlv/tlv_eeprom.c | 599 +++++++++++++++++++++++++++++++ 10 files changed, 918 insertions(+), 511 deletions(-) create mode 100644 lib/tlv/Kconfig create mode 100644 lib/tlv/Makefile create mode 100644 lib/tlv/tlv_eeprom.c
Cc: Stefan Roese sr@denx.de Cc: Baruch Siach baruch@tkos.co.il Cc: Heinrich Schuchardt xypron.glpk@gmx.de

Create a new tlv library by rewriting parts, and reusing other parts of the tlv_eeprom command. This library is intended to simplify reading tlv data during system initialisation from board files, as well as increase maintainability by defining a clear API and functionally decouple from the command implementation.
Signed-off-by: Josua Mayer josua@solid-run.com Cc: Stefan Roese sr@denx.de Cc: Baruch Siach baruch@tkos.co.il Cc: Heinrich Schuchardt xypron.glpk@gmx.de --- cmd/Kconfig | 2 + include/tlv_eeprom.h | 272 ++++++++++++++++++++ lib/Kconfig | 2 + lib/Makefile | 2 + lib/tlv/Kconfig | 18 ++ lib/tlv/Makefile | 4 + lib/tlv/tlv_eeprom.c | 599 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 899 insertions(+) create mode 100644 lib/tlv/Kconfig create mode 100644 lib/tlv/Makefile create mode 100644 lib/tlv/tlv_eeprom.c
diff --git a/cmd/Kconfig b/cmd/Kconfig index 365371fb511..9c2149dc881 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -191,6 +191,7 @@ config CMD_REGINFO config CMD_TLV_EEPROM bool "tlv_eeprom" depends on I2C_EEPROM + depends on !EEPROM_TLV_LIB select CRC32 help Display and program the system EEPROM data block in ONIE Tlvinfo @@ -199,6 +200,7 @@ config CMD_TLV_EEPROM config SPL_CMD_TLV_EEPROM bool "tlv_eeprom for SPL" depends on SPL_I2C_EEPROM + depends on !SPL_EEPROM_TLV_LIB select SPL_DRIVERS_MISC select SPL_CRC32 help diff --git a/include/tlv_eeprom.h b/include/tlv_eeprom.h index fd45e5f6ebb..b08c98a5833 100644 --- a/include/tlv_eeprom.h +++ b/include/tlv_eeprom.h @@ -7,6 +7,8 @@ #ifndef __TLV_EEPROM_H_ #define __TLV_EEPROM_H_
+#if !defined(CONFIG_EEPROM_TLV_LIB) && !defined(CONFIG_SPL_EEPROM_TLV_LIB) + /* * The Definition of the TlvInfo EEPROM format can be found at onie.org or * github.com/onie @@ -150,4 +152,274 @@ static inline bool is_valid_tlvinfo_header(struct tlvinfo_header *hdr) (be16_to_cpu(hdr->totallen) <= TLV_TOTAL_LEN_MAX)); }
+#else + +/* + * The Definition of the TlvInfo EEPROM format can be found at onie.org or + * github.com/onie + */ + +#include <dm/device.h> +#include <i2c_eeprom.h> +#include <stdbool.h> + +/* tlv library internal state, per each tlv structure */ +struct tlvinfo_priv; + +/* + * TlvInfo header: Layout of the header for the TlvInfo format + * + * See the end of this file for details of this eeprom format + */ +struct __attribute__ ((__packed__)) tlvinfo_header { + char signature[8]; /* 0x00 - 0x07 EEPROM Tag "TlvInfo" */ + u8 version; /* 0x08 Structure version */ + u16 totallen; /* 0x09 - 0x0A Length of all data which follows */ +}; + +// Header Field Constants +#define TLV_INFO_HEADER_SIZE sizeof(struct tlvinfo_header) +#define TLV_INFO_ID_STRING "TlvInfo" +#define TLV_INFO_VERSION 0x01 +#define TLV_INFO_MAX_LEN 2048 +#define TLV_TOTAL_LEN_MAX (TLV_INFO_MAX_LEN - TLV_INFO_HEADER_SIZE) + +/* + * TlvInfo TLV: Layout of a TLV field + */ +struct __attribute__ ((__packed__)) tlvinfo_tlv { + u8 type; + u8 length; + u8 value[]; +}; + +#define TLV_INFO_ENTRY_SIZE sizeof(struct tlvinfo_tlv) +/* Maximum length of a TLV value in bytes */ +#define TLV_VALUE_MAX_LEN 255 + +/** + * The TLV Types. + * + * Keep these in sync with tlv_code_list in cmd/tlv_eeprom.c + */ +#define TLV_CODE_PRODUCT_NAME 0x21 +#define TLV_CODE_PART_NUMBER 0x22 +#define TLV_CODE_SERIAL_NUMBER 0x23 +#define TLV_CODE_MAC_BASE 0x24 +#define TLV_CODE_MANUF_DATE 0x25 +#define TLV_CODE_DEVICE_VERSION 0x26 +#define TLV_CODE_LABEL_REVISION 0x27 +#define TLV_CODE_PLATFORM_NAME 0x28 +#define TLV_CODE_ONIE_VERSION 0x29 +#define TLV_CODE_MAC_SIZE 0x2A +#define TLV_CODE_MANUF_NAME 0x2B +#define TLV_CODE_MANUF_COUNTRY 0x2C +#define TLV_CODE_VENDOR_NAME 0x2D +#define TLV_CODE_DIAG_VERSION 0x2E +#define TLV_CODE_SERVICE_TAG 0x2F +#define TLV_CODE_VENDOR_EXT 0xFD +#define TLV_CODE_CRC_32 0xFE + +/* how many EEPROMs can be used */ +#define MAX_TLV_DEVICES 2 + +/* + * EEPROM<->TLV API + */ + +/** + * Find EEPROM device by index. + * + * @index: index of eeprom in the system, 0 = first. + * @return: handle to eeprom device on success, error pointer otherwise. + */ +struct udevice *tlv_eeprom_get_by_index(unsigned int index); + +/** + * Read TLV formatted data from EEPROM. + * + * @dev: EEPROM device handle. + * @offset: Offset into EEPROM to read from. + * @buffer: Buffer for storing TLV structure. + * @buffer_size: Size of the buffer. + * @return: Buffer initialised with TLV structure, or error pointer. + */ +struct tlvinfo_priv *tlv_eeprom_read(struct udevice *dev, int offset, u8 *buffer, size_t buffer_size); + +/** + * Write TLV formatted data to EEPROM. + * + * @dev: EEPROM device handle. + * @offset: Offset into EEPROM to write to. + * @tlv: Pointer to TLV structure. + * @return: Status code. + */ +int tlv_eeprom_write(struct udevice *dev, int offset, struct tlvinfo_priv *priv); + +/* + * TLV API + */ + +/** + * Initialise new TLV structure. + * + * @buffer: Buffer for storing TLV structure. + * @buffer_size: Size of the buffer. + * @return: Buffer initialised with TLV structure, or error pointer. + */ +struct tlvinfo_priv *tlv_init(u8 *buffer, size_t buffer_size); + +/** + * Access TLV Header + */ +struct tlvinfo_header *tlv_header_get(struct tlvinfo_priv *priv); + +/** + * Add new entry to TLV structure. + * + * @priv: Pointer to TLV structure. + * @offset: Pointer inside TLV structure where to insert new element. May be NULL to insert at the end, otherwise the new entry shall be created before the specified offset, moving existing elements back. + * @code: TLV code number for this entry. + * @size: Data size for this entry. + * @return: Pointer to TLV entry, or error pointer. + */ +struct tlvinfo_tlv *tlv_entry_add(struct tlvinfo_priv *priv, struct tlvinfo_tlv *offset, u8 code, u8 size); + +/** + * Remove entry from TLV structure. + * + * @tlv: Pointer to TLV structure. + * @entry: Pointer to TLV entry. + * @return: Status code. + */ +int tlv_entry_remove(struct tlvinfo_priv *priv, struct tlvinfo_tlv *entry); + +/** + * Get the next TLV entry. + * + * @tlv: Pointer to TLV structure. + * @offset: Start search after this entry; Pass NULL to search from the beginning. + * @return: Pointer to TLV entry, or error code. + */ +struct tlvinfo_tlv *tlv_entry_next(struct tlvinfo_priv *priv, struct tlvinfo_tlv *offset); + +/** + * Get the next TLV entry by code. + * + * @tlv: Pointer to TLV structure. + * @code: TLV code number to search. + * @offset: Start search after this entry; Pass NULL to search from the beginning. + * @return: Pointer to TLV entry, or error code. + */ +struct tlvinfo_tlv *tlv_entry_next_by_code(struct tlvinfo_priv *priv, struct tlvinfo_tlv *offset, u8 code); + +/* + * TLV data get/set API + * (Convenience wrappers around struct tlvinfo_tlv) + */ + +/** + * Get TLV entry binary data. + * + * @entry: Pointer to TLV entry. + * @buffer: Destination buffer for data. + * @size: Size of the buffer. + * @return: Status code. + */ +int tlv_entry_get_raw(struct tlvinfo_tlv *entry, u8 *buffer, size_t size); + +/** + * Set TLV entry binary data. + * + * @entry: Pointer to TLV entry. + * @values: Source buffer with data. + * @size: Length of the data. + * @return: Status code. + * + * Note: The size of entries can not be changed! + */ +int tlv_entry_set_raw(struct tlvinfo_tlv *entry, const u8 *values, size_t length); + +/** + * Get TLV entry data as null-terminated string. + * + * @entry: Pointer to TLV entry. + * @buffer: Destination buffer for string. + * @size: Size of the buffer. + * @return: Status code. + */ +int tlv_entry_get_string(struct tlvinfo_tlv *entry, char *buffer, size_t size); + +/** + * Set TLV entry data from null-terminated string. + * + * @entry: Pointer to TLV entry. + * @values: Source buffer with string. + * @return: Status code. + * + * Note: The size of entries can not be changed! + */ +int tlv_entry_set_string(struct tlvinfo_tlv *entry, const char *string); + +/** + * Get TLV entry data as uint8 value. + * + * @entry: Pointer to TLV entry. + * @buffer: Destination buffer for data. + * @return: Status code. + */ +int tlv_entry_get_uint8(struct tlvinfo_tlv *entry, u8 *buffer); + +/** + * Set TLV entry data from uint8 value. + * + * @entry: Pointer to TLV entry. + * @value: Source value. + * @return: Status code. + * + * Note: The size of entries can not be changed! + */ +int tlv_entry_set_uint8(struct tlvinfo_tlv *entry, const u8 value); + +/** + * Get TLV entry data as uint16 value. + * + * @entry: Pointer to TLV entry. + * @buffer: Destination buffer for data. + * @return: Status code. + */ +int tlv_entry_get_uint16(struct tlvinfo_tlv *entry, u16 *buffer); + +/** + * Set TLV entry data from uint16 value. + * + * @entry: Pointer to TLV entry. + * @value: Source value. + * @return: Status code. + * + * Note: The size of fields can not be changed! + */ +int tlv_entry_set_uint16(struct tlvinfo_tlv *entry, const u16 value); + +/** + * Get TLV entry data as uint32 value. + * + * @entry: Pointer to TLV entry. + * @buffer: Destination buffer for data. + * @return: Status code. + */ +int tlv_entry_get_uint32(struct tlvinfo_tlv *entry, u32 *buffer); + +/** + * Set TLV entry data from uint16 value. + * + * @entry: Pointer to TLV entry. + * @value: Source value. + * @return: Status code. + * + * Note: The size of fields can not be changed! + */ +int tlv_entry_set_uint32(struct tlvinfo_tlv *entry, const u32 value); + +#endif #endif /* __TLV_EEPROM_H_ */ diff --git a/lib/Kconfig b/lib/Kconfig index c8b3ec1ec9c..5e8bdb66c7e 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -1111,3 +1111,5 @@ menu "FWU Multi Bank Updates" source lib/fwu_updates/Kconfig
endmenu + +source lib/tlv/Kconfig diff --git a/lib/Makefile b/lib/Makefile index 8d8ccc8bbc3..21c0d18bb8d 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -149,6 +149,8 @@ obj-$(CONFIG_LIB_ELF) += elf.o
obj-$(CONFIG_$(SPL_TPL_)SEMIHOSTING) += semihosting.o
+obj-y += tlv/ + # # Build a fast OID lookup registry from include/linux/oid_registry.h # diff --git a/lib/tlv/Kconfig b/lib/tlv/Kconfig new file mode 100644 index 00000000000..688b0317a5d --- /dev/null +++ b/lib/tlv/Kconfig @@ -0,0 +1,18 @@ +config EEPROM_TLV_LIB + bool "Enable EEPROM TLV library" + depends on I2C_EEPROM + select CRC32 + help + Selecting this option will enable the shared EEPROM TLV library code. + It provides functions for reading, writing and parsing of + TLV-encoded data from EEPROMs. + +config SPL_EEPROM_TLV_LIB + bool "Enable EEPROM TLV library for SPL" + depends on SPL_I2C_EEPROM + select SPL_CRC32 + select SPL_DRIVERS_MISC + help + Selecting this option will enable the shared EEPROM TLV library code. + It provides functions for reading, writing and parsing of + TLV-encoded data from EEPROMs. diff --git a/lib/tlv/Makefile b/lib/tlv/Makefile new file mode 100644 index 00000000000..93b8042d449 --- /dev/null +++ b/lib/tlv/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_$(SPL_)EEPROM_TLV_LIB) += tlv_eeprom.o diff --git a/lib/tlv/tlv_eeprom.c b/lib/tlv/tlv_eeprom.c new file mode 100644 index 00000000000..8f79941280b --- /dev/null +++ b/lib/tlv/tlv_eeprom.c @@ -0,0 +1,599 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <compiler.h> +#include <dm/uclass.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <string.h> +#include <tlv_eeprom.h> +#include <u-boot/crc.h> + +/* + * internal state specific to each TLV structure + */ +struct __attribute__ ((__packed__)) tlvinfo_priv { + size_t size; + size_t length; + struct tlvinfo_header header; + struct tlvinfo_tlv entries[]; +}; + +#define TLVINFO_PRIV_SIZE sizeof(struct tlvinfo_priv) + +/* + * Calculate offset in bytes relative to end of header + */ +static inline ssize_t tlv_offset(struct tlvinfo_priv *priv, struct tlvinfo_tlv *entry) +{ + return entry - priv->entries; +} + +/* + * Access tlv entry at specific offset in bytes relative to header + */ +static inline struct tlvinfo_tlv *tlv_at_offset(struct tlvinfo_priv *priv, size_t offset) +{ + u8 *buffer = (void *)priv->entries; + return (void *)&buffer[offset]; +} + +/* + * Move TLV data between offsets + */ +static inline void tlv_move(struct tlvinfo_priv *priv, size_t dest_offset, size_t src_offset) { + u8 *buffer = (void *)priv->entries; + memmove(&buffer[dest_offset], &buffer[src_offset], priv->length - src_offset); +} + +/** + * is_valid_tlvinfo_header + * + * Perform sanity checks on the first 11 bytes of the TlvInfo EEPROM + * data pointed to by the parameter: + * 1. First 8 bytes contain null-terminated ASCII string "TlvInfo" + * 2. Version byte is 1 + * 3. Total length bytes contain value which is less than or equal + * to the allowed maximum (2048-11) + */ +static inline bool is_valid_tlvinfo_header(struct tlvinfo_header *hdr) +{ + return ((strcmp(hdr->signature, TLV_INFO_ID_STRING) == 0) && + (hdr->version == TLV_INFO_VERSION) && + (be16_to_cpu(hdr->totallen) <= TLV_TOTAL_LEN_MAX)); +} + +/** + * Calculate TLV Checksum + */ +static inline uint32_t tlvinfo_calc_crc(struct tlvinfo_header *header) +{ + uint32_t crc; + + /* calculate crc32 for complete structure, excluding final 4 byte (crc location) */ + crc = crc32(0, (void *)header, TLV_INFO_HEADER_SIZE + be16_to_cpu(header->totallen) - 4); + + return crc; +} + +/** + * Validate the checksum in the provided TlvInfo EEPROM data. First, + * verify that the TlvInfo header is valid, then make sure the last + * TLV is a CRC-32 TLV. Then calculate the CRC over the EEPROM data + * and compare it to the value stored in the EEPROM CRC-32 TLV. + */ +static bool tlvinfo_check_crc(struct tlvinfo_priv *priv) +{ + struct tlvinfo_tlv *entry; + unsigned int calc_crc; + unsigned int stored_crc; + + // Is the eeprom header valid? + if (!is_valid_tlvinfo_header(&priv->header)) { + pr_debug("%s:%d: tlv header is invalid\n", __FILE__, __LINE__); + return false; + } + printf("header was valid\n"); + + /* read existing CRC entry */ + entry = tlv_entry_next_by_code(priv, NULL, TLV_CODE_CRC_32); + if (IS_ERR(entry)) { + pr_debug("%s:%d: have no tlv entry with type crc\n", __FILE__, __LINE__); + return false; + } + printf("found crc entry\n"); + + /* ensure crc entry size is correct */ + if (entry->length != 4) { + pr_debug("%s:%d: crc tlv entry has illegal length: Have %u, expect 4\n", __FILE__, __LINE__, entry->length); + return false; + } + printf("crc entry size was correct\n"); + + /* ensure crc is final entry */ + if (!IS_ERR(tlv_entry_next(priv, entry))) { + pr_debug("%s:%d: crc tlv entry is not last\n", __FILE__, __LINE__); + return false; + } + printf("crc was final entry\n"); + + /* copy stored crc value */ + tlv_entry_get_uint32(entry, &stored_crc); + printf("got uint32\n"); + + /* calculate crc from data */ + calc_crc = tlvinfo_calc_crc(&priv->header); + printf("calculated crc\n"); + + /* compare */ + return calc_crc == be32_to_cpu(stored_crc); +} + +struct udevice *tlv_eeprom_get_by_index(unsigned int index) +{ + int ret; + int count_dev = 0; + struct udevice *dev; + + for (ret = uclass_first_device_check(UCLASS_I2C_EEPROM, &dev); + dev; + ret = uclass_next_device_check(&dev)) { + if (ret == 0 && count_dev++ == index) + return dev; + if (count_dev >= MAX_TLV_DEVICES) + break; + } + + return ERR_PTR(-ENODEV); + + +/* struct uclass *uc; + struct udevice *dev; + int i; + + uclass_id_foreach_dev(UCLASS_I2C_EEPROM, dev, uc) { + pr_debug("%s:%d: have eeprom device at index %u\n", __FILE__, __LINE__, i); + if (i++ == index) + return dev; + } + + pr_debug("%s:%d: couldn't find eeprom device index %u\n", __FILE__, __LINE__, index); + return ERR_PTR(-ENODEV);*/ +} + +struct tlvinfo_priv *tlv_eeprom_read(struct udevice *dev, int offset, u8 *buffer, size_t buffer_size) +{ + int ret; + struct tlvinfo_priv *priv; + + if (!dev) { + pr_debug("%s:%d: device handle is NULL\n", __FILE__, __LINE__); + return ERR_PTR(-EINVAL); + } else if (IS_ERR(dev)) { + pr_debug("%s:%d: device handle is error: %i\n", __FILE__, __LINE__, (int)PTR_ERR(dev)); + return (void *)dev; + } + + /* check device type */ + if (device_get_uclass_id(dev) != UCLASS_I2C_EEPROM) { + pr_debug("%s:%d: device handle is not an eeprom\n", __FILE__, __LINE__); + return ERR_PTR(-EINVAL); + } + + /* initialise private data */ + priv = tlv_init(buffer, buffer_size); + if (IS_ERR(priv)) { + pr_debug("%s:%d: failed to initialise in-memory tlv structure: %i\n", __FILE__, __LINE__, (int)PTR_ERR(priv)); + return priv; + } + + printf("Fresh TLV Header: "%s" %u %u\n", priv->header.signature, priv->header.version, priv->header.totallen); + + /* read header */ + ret = i2c_eeprom_read(dev, offset, (void *)&priv->header, TLV_INFO_HEADER_SIZE); + if (ret) { + pr_debug("%s:%d: failed to read from eeprom: %i\n", __FILE__, __LINE__, ret); + printf("%s:%d: failed to read from eeprom: %i\n", __FILE__, __LINE__, ret); + return ERR_PTR(ret); + } + + printf("EEPROM TLV Header: "%s" %u %u\n", priv->header.signature, priv->header.version, priv->header.totallen); + + /* validate header */ + if (!is_valid_tlvinfo_header(&priv->header)) { + pr_warn("TLV header is invalid!\n"); + return ERR_PTR(-EINVAL); + } + + /* copy length from header */ + priv->length = be16_to_cpu(priv->header.totallen); + printf("EEPROM TLV Header decoded length: %zu\n", priv->length); + + /* check buffer is sufficient for complete tlv data */ + if (priv->size < priv->length) { + pr_warn("buffer too small for TLV data: Have %zu, need %zu\n", buffer_size, TLVINFO_PRIV_SIZE + TLV_INFO_HEADER_SIZE + priv->length); + return ERR_PTR(-ENOBUFS); + } + + /* read complete tlv data according to size indicated by header */ + ret = i2c_eeprom_read(dev, offset + TLV_INFO_HEADER_SIZE, (void *)&priv->entries, priv->length); + if (ret) { + pr_debug("%s:%d: failed to read from eeprom: %i\n", __FILE__, __LINE__, ret); + return ERR_PTR(ret); + } + + /* validate checksum */ + if (!tlvinfo_check_crc(priv)) { + pr_err("TLV Checksum is invalid or missing!\n"); + /* ignore this error to allow inspecting data */ + } + + /* return data */ + return priv; +} + +int tlv_eeprom_write(struct udevice *dev, int offset, struct tlvinfo_priv *priv) +{ + int ret; + + if (!dev) { + pr_debug("%s:%d: device handle is NULL\n", __FILE__, __LINE__); + return -EINVAL; + } else if (IS_ERR(dev)) { + pr_debug("%s:%d: device handle is error: %i\n", __FILE__, __LINE__, (int)PTR_ERR(dev)); + return PTR_ERR(dev); + } + + ret = i2c_eeprom_write(dev, offset, (void *)&priv->header, TLV_INFO_HEADER_SIZE + priv->length); + if (ret) + pr_debug("%s:%d: failed to write to eeprom: %i\n", __FILE__, __LINE__, ret); + + return ret; +} + +struct tlvinfo_priv *tlv_init(u8 *buffer, size_t buffer_size) +{ + struct tlvinfo_priv *priv; + struct tlvinfo_tlv *entry; + uint32_t crc; + + /* check buffer is sufficient for private data & header */ + if (!buffer || buffer_size < TLVINFO_PRIV_SIZE + TLV_INFO_HEADER_SIZE) { + pr_debug("%s:%d: buffer insufficient for private data and tlv header: Have %zu, need %zu\n", __FILE__, __LINE__, buffer_size, TLVINFO_PRIV_SIZE + TLV_INFO_HEADER_SIZE); + return ERR_PTR(-ENOBUFS); + } + + /* initialise private structure */ + priv = (void *)buffer; + priv->size = buffer_size - TLVINFO_PRIV_SIZE - TLV_INFO_HEADER_SIZE; + //priv->header = (void *)(buffer + TLVINFO_PRIV_SIZE); + //priv->entries = (void *)(buffer + TLVINFO_PRIV_SIZE + TLV_INFO_HEADER_SIZE); + priv->length = 0; + + /* initialise header */ + strcpy(priv->header.signature, TLV_INFO_ID_STRING); + priv->header.version = TLV_INFO_VERSION; + priv->header.totallen = cpu_to_be16(0); + + /* add crc entry */ + entry = tlv_entry_add(priv, NULL, TLV_CODE_CRC_32, 4); + if (IS_ERR(entry)) { + pr_debug("%s:%d: failed to create crc entry: %i\n", __FILE__, __LINE__, (int)PTR_ERR(entry)); + return (void *)entry; + } + + /* calculate crc */ + crc = cpu_to_be32(tlvinfo_calc_crc(&priv->header)); + tlv_entry_set_uint32(entry, crc); + + return priv; +} + +struct tlvinfo_header *tlv_header_get(struct tlvinfo_priv *priv) +{ + if (!priv) { + pr_debug("%s:%d: private handle is NULL\n", __FILE__, __LINE__); + return ERR_PTR(-EINVAL); + } else if (IS_ERR(priv)) { + pr_debug("%s:%d: private handle is error: %i\n", __FILE__, __LINE__, (int)PTR_ERR(priv)); + return (void *)PTR_ERR(priv); + } + + return &priv->header; +} + +struct tlvinfo_tlv *tlv_entry_add(struct tlvinfo_priv *priv, struct tlvinfo_tlv *_offset, u8 code, u8 size) +{ + struct tlvinfo_tlv *entry; + ssize_t offset; + + if (!priv) { + pr_debug("%s:%d: private handle is NULL\n", __FILE__, __LINE__); + return ERR_PTR(-EINVAL); + } else if (IS_ERR(priv)) { + pr_debug("%s:%d: private handle is error: %i\n", __FILE__, __LINE__, (int)PTR_ERR(priv)); + return (void *)PTR_ERR(priv); + } + + if (IS_ERR(_offset)) { + pr_debug("%s:%d: offset is error: %i\n", __FILE__, __LINE__, (int)PTR_ERR(_offset)); + return (void *)_offset; + } + + /* calculate internal offset */ + offset = priv->length; + if (_offset) { + offset = tlv_offset(priv, _offset); + + /* check offset element is inside structure */ + if (offset < 0 || + offset + TLV_INFO_ENTRY_SIZE > priv->length || + offset + TLV_INFO_ENTRY_SIZE + _offset->length > priv->length) { + pr_debug("%s:%d: reference element at offset %zd outside tlv structure\n", __FILE__, __LINE__, offset); + return ERR_PTR(-EINVAL); + } + } + + /* check buffer is sufficient for new entry */ + if (priv->size < priv->length + TLV_INFO_ENTRY_SIZE + size) { + pr_debug("%s:%d: buffer insufficient for additional tlv entry: Have %zu, need %zu\n", __FILE__, __LINE__, TLVINFO_PRIV_SIZE + TLV_INFO_HEADER_SIZE + priv->size, TLVINFO_PRIV_SIZE + TLV_INFO_HEADER_SIZE + priv->length + TLV_INFO_ENTRY_SIZE + size); + return ERR_PTR(-ENOBUFS); + } + + /* move existing data to make space */ + tlv_move(priv, offset + TLV_INFO_ENTRY_SIZE + entry->length, offset); + + /* initialise new entry */ + entry = priv->entries + offset; + entry->type = code; + entry->length = size; + memset(entry->value, 0, size); + + /* update total length */ + priv->length += TLV_INFO_ENTRY_SIZE + size; + priv->header.totallen = cpu_to_be16(priv->length); + + // TODO: update CRC?! + + return entry; +} + +int tlv_entry_remove(struct tlvinfo_priv *priv, struct tlvinfo_tlv *entry) +{ + ssize_t offset; + size_t end; + + if (!priv) { + pr_debug("%s:%d: private handle is NULL\n", __FILE__, __LINE__); + return -EINVAL; + } else if (IS_ERR(priv)) { + pr_debug("%s:%d: private handle is error: %i\n", __FILE__, __LINE__, (int)PTR_ERR(priv)); + return PTR_ERR(priv); + } + + if (!entry) { + pr_debug("%s:%d: entry is NULL\n", __FILE__, __LINE__); + return -EINVAL; + } else if (IS_ERR(entry)) { + pr_debug("%s:%d: entry is error: %i\n", __FILE__, __LINE__, (int)PTR_ERR(entry)); + return PTR_ERR(entry); + } + + /* calculate internal offset */ + offset = tlv_offset(priv, entry); + + /* check entry within structure */ + if (offset < 0 || + offset + TLV_INFO_ENTRY_SIZE > priv->length || + offset + TLV_INFO_ENTRY_SIZE + entry->length > priv->length) { + pr_debug("%s:%d: element at offset %zd outside tlv structure\n", __FILE__, __LINE__, offset); + return -EINVAL; + } + + /* move existing data from end into gap */ + end = offset + TLV_INFO_ENTRY_SIZE + entry->length; + tlv_move(priv, offset, end); + + /* update total length */ + priv->length -= end - offset; + priv->header.totallen = cpu_to_be16(priv->length); + + return 0; +} + +struct tlvinfo_tlv *tlv_entry_next(struct tlvinfo_priv *priv, struct tlvinfo_tlv *_offset) +{ + ssize_t offset = 0; + struct tlvinfo_tlv *entry; + + if (!priv) { + pr_debug("%s:%d: private handle is NULL\n", __FILE__, __LINE__); + return ERR_PTR(-EINVAL); + } else if (IS_ERR(priv)) { + pr_debug("%s:%d: private handle is error: %i\n", __FILE__, __LINE__, (int)PTR_ERR(priv)); + return (void *)PTR_ERR(priv); + } + + if (IS_ERR(_offset)) { + pr_debug("%s:%d: reference element is error: %i\n", __FILE__, __LINE__, (int)PTR_ERR(_offset)); + return (void *)_offset; + } + + /* by default search from beginning */ + entry = priv->entries; + + /* search after reference entry, if any */ + if (_offset) { + offset = tlv_offset(priv, _offset); + + /* check offset element is inside structure */ + if (offset < 0 || + offset + TLV_INFO_ENTRY_SIZE > priv->length || + offset + TLV_INFO_ENTRY_SIZE + _offset->length > priv->length) { + pr_debug("%s:%d: reference element at offset %zd outside tlv structure\n", __FILE__, __LINE__, offset); + return ERR_PTR(-EINVAL); + } + + /* seek beyond reference element */ + offset += _offset->length + TLV_INFO_ENTRY_SIZE; + entry = tlv_at_offset(priv, offset); + + pr_debug("%s:%d: searching at offset %zd relative to end of header\n", __FILE__, __LINE__, offset); + } + + /* check for end of tlv data */ + if (offset == priv->length) { + pr_debug("%s:%d: reached end of tlv data at offset %zu\n", __FILE__, __LINE__, offset); + return ERR_PTR(-ENOENT); + } + + /* check element is inside structure */ + if (offset + TLV_INFO_ENTRY_SIZE > priv->length || + offset + TLV_INFO_ENTRY_SIZE + entry->length > priv->length) { + pr_debug("%s:%d: found element at offset %zd outside tlv structure\n", __FILE__, __LINE__, offset); + return ERR_PTR(-EINVAL); + } + + return entry; +} + +struct tlvinfo_tlv *tlv_entry_next_by_code(struct tlvinfo_priv *priv, struct tlvinfo_tlv *offset, u8 code) +{ + struct tlvinfo_tlv *entry; + + for (entry = tlv_entry_next(priv, offset); + !IS_ERR(entry); + entry = tlv_entry_next(priv, entry)) + if (entry->type == code) + return entry; + + return ERR_PTR(-ENOENT); +} + +int tlv_entry_get_raw(struct tlvinfo_tlv *entry, u8 *buffer, size_t size) +{ + if (!entry) { + pr_debug("%s:%d: tlv entry is NULL\n", __FILE__, __LINE__); + return -EINVAL; + } else if (IS_ERR(entry)) { + pr_debug("%s:%d: tlv entry is error: %i\n", __FILE__, __LINE__, (int)PTR_ERR(entry)); + return PTR_ERR(entry); + } + + if (!buffer || entry->length > size) { + pr_debug("%s:%d: buffer insufficient: Have %zu, need %u\n", __FILE__, __LINE__, size, entry->length); + return -ENOBUFS; + } + + memcpy(buffer, &entry->value[0], entry->length); + + return 0; +} + +int tlv_entry_set_raw(struct tlvinfo_tlv *entry, const u8 *values, size_t length) +{ + if (!entry) { + pr_debug("%s:%d: tlv entry is NULL\n", __FILE__, __LINE__); + return -EINVAL; + } else if (IS_ERR(entry)) { + pr_debug("%s:%d: tlv entry is error: %i\n", __FILE__, __LINE__, (int)PTR_ERR(entry)); + return PTR_ERR(entry); + } + + if (entry->length < length) { + pr_debug("%s:%d: tlv entry too small: Have %u, need %zu\n", __FILE__, __LINE__, entry->length, length); + return -ENOBUFS; + } + + memcpy(&entry->value[0], values, length); + + return 0; +} + +int tlv_entry_get_string(struct tlvinfo_tlv *entry, char *buffer, size_t size) +{ + if (!entry) { + pr_debug("%s:%d: tlv entry is NULL\n", __FILE__, __LINE__); + return -EINVAL; + } else if (IS_ERR(entry)) { + pr_debug("%s:%d: tlv entry is error: %i\n", __FILE__, __LINE__, (int)PTR_ERR(entry)); + return PTR_ERR(entry); + } + + if (!buffer || size <= entry->length) { + pr_debug("%s:%d: buffer insufficient: Have %zu, need %u\n", __FILE__, __LINE__, size, entry->length + 1); + return -ENOBUFS; + } + + memcpy(buffer, &entry->value[0], entry->length); + buffer[entry->length] = '\0'; + return 0; +} + +int tlv_entry_set_string(struct tlvinfo_tlv *entry, const char *string) +{ + if (!entry) { + pr_debug("%s:%d: tlv entry is NULL\n", __FILE__, __LINE__); + return -EINVAL; + } else if (IS_ERR(entry)) { + pr_debug("%s:%d: tlv entry is error: %i\n", __FILE__, __LINE__, (int)PTR_ERR(entry)); + return PTR_ERR(entry); + } + + if (!string) { + pr_debug("%s:%d: string is NULL\n", __FILE__, __LINE__); + return -EINVAL; + } + + strncpy(&entry->value[0], string, entry->length); + return 0; +} + +int tlv_entry_get_uint8(struct tlvinfo_tlv *entry, u8 *buffer) +{ + return tlv_entry_get_raw(entry, buffer, sizeof(uint8_t)); +} + +int tlv_entry_set_uint8(struct tlvinfo_tlv *entry, const u8 value) +{ + return tlv_entry_set_raw(entry, &value, sizeof(value)); +} + +int tlv_entry_get_uint16(struct tlvinfo_tlv *entry, u16 *buffer) +{ + int ret; + uint16_t val; + + ret = tlv_entry_get_raw(entry, (uint8_t *)&val, sizeof(val)); + if (ret) + return ret; + + *buffer = be16_to_cpu(val); + return 0; +} + +int tlv_entry_set_uint16(struct tlvinfo_tlv *entry, const u16 value) +{ + uint16_t raw = cpu_to_be16(value); + + return tlv_entry_set_raw(entry, (uint8_t *)&raw, sizeof(raw)); +} + +int tlv_entry_get_uint32(struct tlvinfo_tlv *entry, u32 *buffer) +{ + int ret; + uint32_t val; + + ret = tlv_entry_get_raw(entry, (uint8_t *)&val, sizeof(val)); + if (ret) + return ret; + + *buffer = be32_to_cpu(val); + return 0; +} + +int tlv_entry_set_uint32(struct tlvinfo_tlv *entry, const u32 value) +{ + uint32_t raw = cpu_to_be32(value); + + return tlv_entry_set_raw(entry, (uint8_t *)&raw, sizeof(raw)); +}

Update the existing code reading tlv data from eeprom to use the new tlv library functions rather than relying on tlv_eeprom command internals.
Signed-off-by: Josua Mayer josua@solid-run.com --- board/solidrun/common/tlv_data.c | 46 ++++++++++++-------------------- configs/clearfog_defconfig | 4 ++- 2 files changed, 20 insertions(+), 30 deletions(-)
diff --git a/board/solidrun/common/tlv_data.c b/board/solidrun/common/tlv_data.c index 11d6e4a1380..31b4b473c75 100644 --- a/board/solidrun/common/tlv_data.c +++ b/board/solidrun/common/tlv_data.c @@ -5,6 +5,7 @@
#include <common.h> #include <compiler.h> +#include <linux/err.h> #include <tlv_eeprom.h> #include "tlv_data.h"
@@ -50,44 +51,31 @@ static void parse_tlv_vendor_ext(struct tlvinfo_tlv *tlv_entry, td->ram_size = val[5]; }
-static void parse_tlv_data(u8 *eeprom, struct tlvinfo_header *hdr, - struct tlvinfo_tlv *entry, struct tlv_data *td) +static void parse_tlv_data(u8 *eeprom, struct tlvinfo_priv *tlv, + struct tlv_data *td) { - unsigned int tlv_offset, tlv_len; - - tlv_offset = sizeof(struct tlvinfo_header); - tlv_len = sizeof(struct tlvinfo_header) + be16_to_cpu(hdr->totallen); - while (tlv_offset < tlv_len) { - entry = (struct tlvinfo_tlv *)&eeprom[tlv_offset]; - - switch (entry->type) { - case TLV_CODE_PRODUCT_NAME: - store_product_name(entry, td); - break; - case TLV_CODE_VENDOR_EXT: - parse_tlv_vendor_ext(entry, td); - break; - default: - break; - } - - tlv_offset += sizeof(struct tlvinfo_tlv) + entry->length; - } + struct tlvinfo_tlv *entry; + + entry = tlv_entry_next_by_code(tlv, NULL, TLV_CODE_PRODUCT_NAME); + if (!IS_ERR(entry)) + store_product_name(entry, td); + + entry = tlv_entry_next_by_code(tlv, NULL, TLV_CODE_VENDOR_EXT); + if (!IS_ERR(entry)) + parse_tlv_vendor_ext(entry, td); }
void read_tlv_data(struct tlv_data *td) { u8 eeprom_data[TLV_TOTAL_LEN_MAX]; - struct tlvinfo_header *tlv_hdr; - struct tlvinfo_tlv *tlv_entry; - int ret, i; + struct tlvinfo_priv *priv; + int i;
for (i = 0; i < 2; i++) { - ret = read_tlvinfo_tlv_eeprom(eeprom_data, &tlv_hdr, - &tlv_entry, i); - if (ret < 0) + priv = tlv_eeprom_read(tlv_eeprom_get_by_index(i), 0, eeprom_data, ARRAY_SIZE(eeprom_data)); + if (IS_ERR(priv)) continue; - parse_tlv_data(eeprom_data, tlv_hdr, tlv_entry, td); + parse_tlv_data(eeprom_data, priv, td); } }
diff --git a/configs/clearfog_defconfig b/configs/clearfog_defconfig index b3ed1ec7bbe..fa86b23ef40 100644 --- a/configs/clearfog_defconfig +++ b/configs/clearfog_defconfig @@ -35,7 +35,7 @@ CONFIG_SPL_SYS_MALLOC_SIMPLE=y # CONFIG_SPL_SHARES_INIT_SP_ADDR is not set CONFIG_SPL_I2C=y CONFIG_SYS_MAXARGS=32 -CONFIG_CMD_TLV_EEPROM=y +# CONFIG_CMD_TLV_EEPROM is not set CONFIG_SPL_CMD_TLV_EEPROM=y # CONFIG_CMD_FLASH is not set CONFIG_CMD_GPIO=y @@ -81,3 +81,5 @@ CONFIG_USB=y CONFIG_USB_XHCI_HCD=y CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x1 CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_DATA_PART_OFFSET=0x0 +CONFIG_EEPROM_TLV_LIB=y +CONFIG_SPL_EEPROM_TLV_LIB=y

Rewrite tlv_eeprom command for using the new tlv library, and drop all unused functions. From this point on, tlv_eeprom command internal functions shall not be reused externally.
mac_read_from_eeprom & populate_serial_number are kept in place for now as is, however these probably deserve a new location.
Signed-off-by: Josua Mayer josua@solid-run.com --- cmd/Kconfig | 9 +- cmd/tlv_eeprom.c | 507 +++++++------------------------------ configs/clearfog_defconfig | 2 +- include/tlv_eeprom.h | 148 ----------- 4 files changed, 92 insertions(+), 574 deletions(-)
diff --git a/cmd/Kconfig b/cmd/Kconfig index 9c2149dc881..4b7ea8cd358 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -190,19 +190,14 @@ config CMD_REGINFO
config CMD_TLV_EEPROM bool "tlv_eeprom" - depends on I2C_EEPROM - depends on !EEPROM_TLV_LIB - select CRC32 + depends on EEPROM_TLV_LIB help Display and program the system EEPROM data block in ONIE Tlvinfo format. TLV stands for Type-Length-Value.
config SPL_CMD_TLV_EEPROM bool "tlv_eeprom for SPL" - depends on SPL_I2C_EEPROM - depends on !SPL_EEPROM_TLV_LIB - select SPL_DRIVERS_MISC - select SPL_CRC32 + depends on SPL_EEPROM_TLV_LIB help Read system EEPROM data block in ONIE Tlvinfo format from SPL.
diff --git a/cmd/tlv_eeprom.c b/cmd/tlv_eeprom.c index 0ca4d714645..02e1dd88d35 100644 --- a/cmd/tlv_eeprom.c +++ b/cmd/tlv_eeprom.c @@ -7,69 +7,36 @@ * Copyright (C) 2014 Srideep srideep_devireddy@dell.com * Copyright (C) 2013 Miles Tseng miles_tseng@accton.com * Copyright (C) 2014,2016 david_yang david_yang@accton.com + * Copyright (C) 2023 Josua Mayer josua@solid-run.com */
-#include <common.h> #include <command.h> -#include <dm.h> -#include <i2c.h> -#include <i2c_eeprom.h> -#include <env.h> -#include <init.h> +#include <linux/err.h> #include <net.h> -#include <asm/global_data.h> -#include <linux/ctype.h> -#include <u-boot/crc.h> - -#include "tlv_eeprom.h" +#include <stdio.h> +#include <tlv_eeprom.h> +#include <vsprintf.h>
DECLARE_GLOBAL_DATA_PTR;
-#define MAX_TLV_DEVICES 2 +#define DEBUG
-/* File scope function prototypes */ -static bool is_checksum_valid(u8 *eeprom); -static int read_eeprom(int devnum, u8 *eeprom); -static void show_eeprom(int devnum, u8 *eeprom); static void decode_tlv(struct tlvinfo_tlv *tlv); -static void update_crc(u8 *eeprom); -static int prog_eeprom(int devnum, u8 *eeprom); -static bool tlvinfo_find_tlv(u8 *eeprom, u8 tcode, int *eeprom_index); -static bool tlvinfo_delete_tlv(u8 *eeprom, u8 code); -static bool tlvinfo_add_tlv(u8 *eeprom, int tcode, char *strval); +static bool tlvinfo_add_tlv(struct tlvinfo_priv *header, int tcode, char *strval); static int set_mac(char *buf, const char *string); static int set_date(char *buf, const char *string); static int set_bytes(char *buf, const char *string, int *converted_accum); -static void show_tlv_devices(int current_dev);
-/* The EERPOM contents after being read into memory */ +/* The EEPROM contents after being read into memory */ static u8 eeprom[TLV_INFO_MAX_LEN];
-static struct udevice *tlv_devices[MAX_TLV_DEVICES]; - -#define to_header(p) ((struct tlvinfo_header *)p) -#define to_entry(p) ((struct tlvinfo_tlv *)p) - -#define HDR_SIZE sizeof(struct tlvinfo_header) -#define ENT_SIZE sizeof(struct tlvinfo_tlv) +static void show_tlv_devices(int current_dev);
static inline bool is_digit(char c) { return (c >= '0' && c <= '9'); }
-/** - * is_valid_tlv - * - * Perform basic sanity checks on a TLV field. The TLV is pointed to - * by the parameter provided. - * 1. The type code is not reserved (0x00 or 0xFF) - */ -static inline bool is_valid_tlv(struct tlvinfo_tlv *tlv) -{ - return((tlv->type != 0x00) && (tlv->type != 0xFF)); -} - /** * is_hex * @@ -78,79 +45,8 @@ static inline bool is_valid_tlv(struct tlvinfo_tlv *tlv) static inline u8 is_hex(char p) { return (((p >= '0') && (p <= '9')) || - ((p >= 'A') && (p <= 'F')) || - ((p >= 'a') && (p <= 'f'))); -} - -/** - * is_checksum_valid - * - * Validate the checksum in the provided TlvInfo EEPROM data. First, - * verify that the TlvInfo header is valid, then make sure the last - * TLV is a CRC-32 TLV. Then calculate the CRC over the EEPROM data - * and compare it to the value stored in the EEPROM CRC-32 TLV. - */ -static bool is_checksum_valid(u8 *eeprom) -{ - struct tlvinfo_header *eeprom_hdr = to_header(eeprom); - struct tlvinfo_tlv *eeprom_crc; - unsigned int calc_crc; - unsigned int stored_crc; - - // Is the eeprom header valid? - if (!is_valid_tlvinfo_header(eeprom_hdr)) - return false; - - // Is the last TLV a CRC? - eeprom_crc = to_entry(&eeprom[HDR_SIZE + - be16_to_cpu(eeprom_hdr->totallen) - (ENT_SIZE + 4)]); - if (eeprom_crc->type != TLV_CODE_CRC_32 || eeprom_crc->length != 4) - return false; - - // Calculate the checksum - calc_crc = crc32(0, (void *)eeprom, - HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen) - 4); - stored_crc = (eeprom_crc->value[0] << 24) | - (eeprom_crc->value[1] << 16) | - (eeprom_crc->value[2] << 8) | - eeprom_crc->value[3]; - return calc_crc == stored_crc; -} - -/** - * read_eeprom - * - * Read the EEPROM into memory, if it hasn't already been read. - */ -static int read_eeprom(int devnum, u8 *eeprom) -{ - int ret; - struct tlvinfo_header *eeprom_hdr = to_header(eeprom); - struct tlvinfo_tlv *eeprom_tlv = to_entry(&eeprom[HDR_SIZE]); - - /* Read the header */ - ret = read_tlv_eeprom((void *)eeprom_hdr, 0, HDR_SIZE, devnum); - /* If the header was successfully read, read the TLVs */ - if (ret == 0 && is_valid_tlvinfo_header(eeprom_hdr)) - ret = read_tlv_eeprom((void *)eeprom_tlv, HDR_SIZE, - be16_to_cpu(eeprom_hdr->totallen), devnum); - else if (ret == -ENODEV) - return ret; - - // If the contents are invalid, start over with default contents - if (!is_valid_tlvinfo_header(eeprom_hdr) || - !is_checksum_valid(eeprom)) { - strcpy(eeprom_hdr->signature, TLV_INFO_ID_STRING); - eeprom_hdr->version = TLV_INFO_VERSION; - eeprom_hdr->totallen = cpu_to_be16(0); - update_crc(eeprom); - } - -#ifdef DEBUG - show_eeprom(devnum, eeprom); -#endif - - return ret; + ((p >= 'A') && (p <= 'F')) || + ((p >= 'a') && (p <= 'f'))); }
/** @@ -158,20 +54,13 @@ static int read_eeprom(int devnum, u8 *eeprom) * * Display the contents of the EEPROM */ -static void show_eeprom(int devnum, u8 *eeprom) +static void show_eeprom(int devnum, struct tlvinfo_priv *tlv) { - int tlv_end; - int curr_tlv; #ifdef DEBUG int i; #endif - struct tlvinfo_header *eeprom_hdr = to_header(eeprom); - struct tlvinfo_tlv *eeprom_tlv; - - if (!is_valid_tlvinfo_header(eeprom_hdr)) { - printf("EEPROM does not contain data in a valid TlvInfo format.\n"); - return; - } + struct tlvinfo_tlv *entry = NULL; + struct tlvinfo_header *eeprom_hdr = tlv_header_get(tlv);
printf("TLV: %u\n", devnum); printf("TlvInfo Header:\n"); @@ -181,21 +70,13 @@ static void show_eeprom(int devnum, u8 *eeprom)
printf("TLV Name Code Len Value\n"); printf("-------------------- ---- --- -----\n"); - curr_tlv = HDR_SIZE; - tlv_end = HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen); - while (curr_tlv < tlv_end) { - eeprom_tlv = to_entry(&eeprom[curr_tlv]); - if (!is_valid_tlv(eeprom_tlv)) { - printf("Invalid TLV field starting at EEPROM offset %d\n", - curr_tlv); - return; - } - decode_tlv(eeprom_tlv); - curr_tlv += ENT_SIZE + eeprom_tlv->length; + entry = tlv_entry_next(tlv, entry); + while (!IS_ERR(entry)) { + decode_tlv(entry); + entry = tlv_entry_next(tlv, entry); } - - printf("Checksum is %s.\n", - is_checksum_valid(eeprom) ? "valid" : "invalid"); + if (PTR_ERR(entry) != -ENOENT) + printf("Failed to get next entry: %ld\n", PTR_ERR(entry));
#ifdef DEBUG printf("EEPROM dump: (0x%x bytes)", TLV_INFO_MAX_LEN); @@ -341,66 +222,6 @@ static void decode_tlv(struct tlvinfo_tlv *tlv) printf("%-20s 0x%02X %3d %s\n", name, tlv->type, tlv->length, value); }
-/** - * update_crc - * - * This function updates the CRC-32 TLV. If there is no CRC-32 TLV, then - * one is added. This function should be called after each update to the - * EEPROM structure, to make sure the CRC is always correct. - */ -static void update_crc(u8 *eeprom) -{ - struct tlvinfo_header *eeprom_hdr = to_header(eeprom); - struct tlvinfo_tlv *eeprom_crc; - unsigned int calc_crc; - int eeprom_index; - - // Discover the CRC TLV - if (!tlvinfo_find_tlv(eeprom, TLV_CODE_CRC_32, &eeprom_index)) { - unsigned int totallen = be16_to_cpu(eeprom_hdr->totallen); - - if ((totallen + ENT_SIZE + 4) > TLV_TOTAL_LEN_MAX) - return; - eeprom_index = HDR_SIZE + totallen; - eeprom_hdr->totallen = cpu_to_be16(totallen + ENT_SIZE + 4); - } - eeprom_crc = to_entry(&eeprom[eeprom_index]); - eeprom_crc->type = TLV_CODE_CRC_32; - eeprom_crc->length = 4; - - // Calculate the checksum - calc_crc = crc32(0, (void *)eeprom, - HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen) - 4); - eeprom_crc->value[0] = (calc_crc >> 24) & 0xFF; - eeprom_crc->value[1] = (calc_crc >> 16) & 0xFF; - eeprom_crc->value[2] = (calc_crc >> 8) & 0xFF; - eeprom_crc->value[3] = (calc_crc >> 0) & 0xFF; -} - -/** - * prog_eeprom - * - * Write the EEPROM data from CPU memory to the hardware. - */ -static int prog_eeprom(int devnum, u8 *eeprom) -{ - int ret = 0; - struct tlvinfo_header *eeprom_hdr = to_header(eeprom); - int eeprom_len; - - update_crc(eeprom); - - eeprom_len = HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen); - ret = write_tlv_eeprom(eeprom, eeprom_len, devnum); - if (ret) { - printf("Programming failed.\n"); - return -1; - } - - printf("Programming passed.\n"); - return 0; -} - /** * show_tlv_code_list - Display the list of TLV codes and names */ @@ -425,7 +246,8 @@ void show_tlv_code_list(void) int do_tlv_eeprom(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { char cmd; - struct tlvinfo_header *eeprom_hdr = to_header(eeprom); + struct tlvinfo_priv *tlv; + struct tlvinfo_tlv *entry; static unsigned int current_dev; /* Set to 1 if we've read EEPROM into memory */ static int has_been_read; @@ -434,15 +256,17 @@ int do_tlv_eeprom(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) // If no arguments, read the EERPOM and display its contents if (argc == 1) { if (!has_been_read) { - ret = read_eeprom(current_dev, eeprom); - if (ret) { - printf("Failed to read EEPROM data from device.\n"); + tlv = tlv_eeprom_read(tlv_eeprom_get_by_index(current_dev), + 0, eeprom, ARRAY_SIZE(eeprom)); + if (IS_ERR(tlv)) { + printf("Failed to read EEPROM data from device: %ld\n", + PTR_ERR(tlv)); return 0; }
has_been_read = 1; } - show_eeprom(current_dev, eeprom); + show_eeprom(current_dev, tlv); return 0; }
@@ -469,9 +293,11 @@ int do_tlv_eeprom(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) // Read the EEPROM contents if (cmd == 'r') { has_been_read = 0; - ret = read_eeprom(current_dev, eeprom); - if (ret) { - printf("Failed to read EEPROM data from device.\n"); + tlv = tlv_eeprom_read(tlv_eeprom_get_by_index(current_dev), + 0, eeprom, ARRAY_SIZE(eeprom)); + if (IS_ERR(tlv)) { + printf("Failed to read EEPROM data from device: %ld\n", + PTR_ERR(tlv)); return 0; }
@@ -489,13 +315,20 @@ int do_tlv_eeprom(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) if (argc == 2) { switch (cmd) { case 'w': /* write */ - prog_eeprom(current_dev, eeprom); + ret = tlv_eeprom_write(tlv_eeprom_get_by_index(current_dev), 0, tlv); + if (ret) + printf("Programming failed: %i\n", ret); + else + printf("Programming passed.\n"); break; case 'e': /* erase */ - strcpy(eeprom_hdr->signature, TLV_INFO_ID_STRING); - eeprom_hdr->version = TLV_INFO_VERSION; - eeprom_hdr->totallen = cpu_to_be16(0); - update_crc(eeprom); + tlv = tlv_init(eeprom, ARRAY_SIZE(eeprom)); + if (IS_ERR(tlv)) { + printf("Failed to initiailise TLV structure in memory: %ld\n", + PTR_ERR(tlv)); + return 0; + } + printf("EEPROM data in memory reset.\n"); break; case 'l': /* list */ @@ -521,9 +354,14 @@ int do_tlv_eeprom(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) int tcode;
tcode = simple_strtoul(argv[2], NULL, 0); - tlvinfo_delete_tlv(eeprom, tcode); + entry = tlv_entry_next_by_code(tlv, NULL, tcode); + ret = tlv_entry_remove(tlv, tlv_entry_next_by_code(tlv, NULL, tcode)); + if (ret != ENOENT) { + printf("Failed to remove existing tlv entry: %d.\n", ret); + return 0; + } if (argc == 4) - tlvinfo_add_tlv(eeprom, tcode, argv[3]); + tlvinfo_add_tlv(tlv, tcode, argv[3]); } else { return CMD_RET_USAGE; } @@ -557,64 +395,6 @@ U_BOOT_CMD(tlv_eeprom, 4, 1, do_tlv_eeprom, " - List the understood TLV codes and names.\n" );
-/** - * tlvinfo_find_tlv - * - * This function finds the TLV with the supplied code in the EERPOM. - * An offset from the beginning of the EEPROM is returned in the - * eeprom_index parameter if the TLV is found. - */ -static bool tlvinfo_find_tlv(u8 *eeprom, u8 tcode, int *eeprom_index) -{ - struct tlvinfo_header *eeprom_hdr = to_header(eeprom); - struct tlvinfo_tlv *eeprom_tlv; - int eeprom_end; - - // Search through the TLVs, looking for the first one which matches the - // supplied type code. - *eeprom_index = HDR_SIZE; - eeprom_end = HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen); - while (*eeprom_index < eeprom_end) { - eeprom_tlv = to_entry(&eeprom[*eeprom_index]); - if (!is_valid_tlv(eeprom_tlv)) - return false; - if (eeprom_tlv->type == tcode) - return true; - *eeprom_index += ENT_SIZE + eeprom_tlv->length; - } - return(false); -} - -/** - * tlvinfo_delete_tlv - * - * This function deletes the TLV with the specified type code from the - * EEPROM. - */ -static bool tlvinfo_delete_tlv(u8 *eeprom, u8 code) -{ - int eeprom_index; - int tlength; - struct tlvinfo_header *eeprom_hdr = to_header(eeprom); - struct tlvinfo_tlv *eeprom_tlv; - - // Find the TLV and then move all following TLVs "forward" - if (tlvinfo_find_tlv(eeprom, code, &eeprom_index)) { - eeprom_tlv = to_entry(&eeprom[eeprom_index]); - tlength = ENT_SIZE + eeprom_tlv->length; - memcpy(&eeprom[eeprom_index], &eeprom[eeprom_index + tlength], - HDR_SIZE + - be16_to_cpu(eeprom_hdr->totallen) - eeprom_index - - tlength); - eeprom_hdr->totallen = - cpu_to_be16(be16_to_cpu(eeprom_hdr->totallen) - - tlength); - update_crc(eeprom); - return true; - } - return false; -} - /** * tlvinfo_add_tlv * @@ -622,14 +402,13 @@ static bool tlvinfo_delete_tlv(u8 *eeprom, u8 code) * the format in which it will be stored in the EEPROM. */ #define MAX_TLV_VALUE_LEN 256 -static bool tlvinfo_add_tlv(u8 *eeprom, int tcode, char *strval) +static bool tlvinfo_add_tlv(struct tlvinfo_priv *tlv, int tcode, char *strval) { - struct tlvinfo_header *eeprom_hdr = to_header(eeprom); - struct tlvinfo_tlv *eeprom_tlv; + int ret; + struct tlvinfo_tlv *entry; int new_tlv_len = 0; u32 value; char data[MAX_TLV_VALUE_LEN]; - int eeprom_index;
// Encode each TLV type into the format to be stored in the EERPOM switch (tcode) { @@ -688,29 +467,21 @@ static bool tlvinfo_add_tlv(u8 *eeprom, int tcode, char *strval) break; }
- // Is there room for this TLV? - if ((be16_to_cpu(eeprom_hdr->totallen) + ENT_SIZE + new_tlv_len) > - TLV_TOTAL_LEN_MAX) { + entry = tlv_entry_add(tlv, NULL, tcode, new_tlv_len); + if (IS_ERR(entry) && PTR_ERR(entry) == -ENOMEM) { printf("ERROR: There is not enough room in the EERPOM to save data.\n"); return false; + } else if (IS_ERR(entry)) { + printf("Failed to create new tlv entry: %ld\n", PTR_ERR(entry)); + return false; }
- // Add TLV at the end, overwriting CRC TLV if it exists - if (tlvinfo_find_tlv(eeprom, TLV_CODE_CRC_32, &eeprom_index)) - eeprom_hdr->totallen = - cpu_to_be16(be16_to_cpu(eeprom_hdr->totallen) - - ENT_SIZE - 4); - else - eeprom_index = HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen); - eeprom_tlv = to_entry(&eeprom[eeprom_index]); - eeprom_tlv->type = tcode; - eeprom_tlv->length = new_tlv_len; - memcpy(eeprom_tlv->value, data, new_tlv_len); - - // Update the total length and calculate (add) a new CRC-32 TLV - eeprom_hdr->totallen = cpu_to_be16(be16_to_cpu(eeprom_hdr->totallen) + - ENT_SIZE + new_tlv_len); - update_crc(eeprom); + // copy data into new entry + ret = tlv_entry_set_raw(entry, data, new_tlv_len); + if (ret) { + printf("Failed to set new tlv entry value: %d\n", ret); + return false; + }
return true; } @@ -901,115 +672,15 @@ static int set_bytes(char *buf, const char *string, int *converted_accum)
static void show_tlv_devices(int current_dev) { - unsigned int dev; + int dev; + int i;
- for (dev = 0; dev < MAX_TLV_DEVICES; dev++) - if (tlv_devices[dev]) + for (i = 0; i < MAX_TLV_DEVICES; i++) + if (!IS_ERR(tlv_eeprom_get_by_index(dev))) printf("TLV: %u%s\n", dev, (dev == current_dev) ? " (*)" : ""); }
-static int find_tlv_devices(struct udevice **tlv_devices_p) -{ - int ret; - int count_dev = 0; - struct udevice *dev; - - for (ret = uclass_first_device_check(UCLASS_I2C_EEPROM, &dev); - dev; - ret = uclass_next_device_check(&dev)) { - if (ret == 0) - tlv_devices_p[count_dev++] = dev; - if (count_dev >= MAX_TLV_DEVICES) - break; - } - - return (count_dev == 0) ? -ENODEV : 0; -} - -static struct udevice *find_tlv_device_by_index(int dev_num) -{ - struct udevice *local_tlv_devices[MAX_TLV_DEVICES] = {}; - struct udevice **tlv_devices_p; - int ret; - - if (gd->flags & (GD_FLG_RELOC | GD_FLG_SPL_INIT)) { - /* Assume BSS is initialized; use static data */ - if (tlv_devices[dev_num]) - return tlv_devices[dev_num]; - tlv_devices_p = tlv_devices; - } else { - tlv_devices_p = local_tlv_devices; - } - - ret = find_tlv_devices(tlv_devices_p); - if (ret == 0 && tlv_devices_p[dev_num]) - return tlv_devices_p[dev_num]; - - return NULL; -} - -/** - * read_tlv_eeprom - read the hwinfo from i2c EEPROM - */ -int read_tlv_eeprom(void *eeprom, int offset, int len, int dev_num) -{ - struct udevice *dev; - - if (dev_num >= MAX_TLV_DEVICES) - return -EINVAL; - - dev = find_tlv_device_by_index(dev_num); - if (!dev) - return -ENODEV; - - return i2c_eeprom_read(dev, offset, eeprom, len); -} - -/** - * write_tlv_eeprom - write the hwinfo to i2c EEPROM - */ -int write_tlv_eeprom(void *eeprom, int len, int dev) -{ - if (!(gd->flags & GD_FLG_RELOC)) - return -ENODEV; - if (!tlv_devices[dev]) - return -ENODEV; - - return i2c_eeprom_write(tlv_devices[dev], 0, eeprom, len); -} - -int read_tlvinfo_tlv_eeprom(void *eeprom, struct tlvinfo_header **hdr, - struct tlvinfo_tlv **first_entry, int dev_num) -{ - int ret; - struct tlvinfo_header *tlv_hdr; - struct tlvinfo_tlv *tlv_ent; - - /* Read TLV header */ - ret = read_tlv_eeprom(eeprom, 0, HDR_SIZE, dev_num); - if (ret < 0) - return ret; - - tlv_hdr = eeprom; - if (!is_valid_tlvinfo_header(tlv_hdr)) - return -EINVAL; - - /* Read TLV entries */ - tlv_ent = to_entry(&tlv_hdr[1]); - ret = read_tlv_eeprom(tlv_ent, HDR_SIZE, - be16_to_cpu(tlv_hdr->totallen), dev_num); - if (ret < 0) - return ret; - if (!is_checksum_valid(eeprom)) - return -EINVAL; - - *hdr = tlv_hdr; - *first_entry = tlv_ent; - - return 0; -} - /** * mac_read_from_eeprom * @@ -1026,31 +697,31 @@ int read_tlvinfo_tlv_eeprom(void *eeprom, struct tlvinfo_header **hdr, int mac_read_from_eeprom(void) { unsigned int i; - int eeprom_index; + struct tlvinfo_header *eeprom_hdr; struct tlvinfo_tlv *eeprom_tlv; - int maccount; + uint16_t maccount; u8 macbase[6]; - struct tlvinfo_header *eeprom_hdr = to_header(eeprom); + struct tlvinfo_priv *tlv; int devnum = 0; // TODO: support multiple EEPROMs
puts("EEPROM: ");
- if (read_eeprom(devnum, eeprom)) { + tlv = tlv_eeprom_read(tlv_eeprom_get_by_index(devnum), 0, eeprom, ARRAY_SIZE(eeprom)); + if (IS_ERR(tlv)) { printf("Read failed.\n"); return -1; } + eeprom_hdr = tlv_header_get(tlv);
- maccount = 1; - if (tlvinfo_find_tlv(eeprom, TLV_CODE_MAC_SIZE, &eeprom_index)) { - eeprom_tlv = to_entry(&eeprom[eeprom_index]); - maccount = (eeprom_tlv->value[0] << 8) | eeprom_tlv->value[1]; - } + maccount = 0; + eeprom_tlv = tlv_entry_next_by_code(tlv, NULL, TLV_CODE_MAC_SIZE); + if (!IS_ERR(eeprom_tlv)) + tlv_entry_get_uint16(eeprom_tlv, &maccount);
memcpy(macbase, "\0\0\0\0\0\0", 6); - if (tlvinfo_find_tlv(eeprom, TLV_CODE_MAC_BASE, &eeprom_index)) { - eeprom_tlv = to_entry(&eeprom[eeprom_index]); - memcpy(macbase, eeprom_tlv->value, 6); - } + eeprom_tlv = tlv_entry_next_by_code(tlv, NULL, TLV_CODE_MAC_BASE); + if (!IS_ERR(eeprom_tlv)) + tlv_entry_get_raw(eeprom_tlv, macbase, ARRAY_SIZE(macbase));
for (i = 0; i < maccount; i++) { if (is_valid_ethaddr(macbase)) { @@ -1103,22 +774,22 @@ int mac_read_from_eeprom(void) int populate_serial_number(void) { char serialstr[257]; - int eeprom_index; + struct tlvinfo_priv *tlv; struct tlvinfo_tlv *eeprom_tlv; int devnum = 0; // TODO: support multiple EEPROMs
if (env_get("serial#")) return 0;
- if (read_eeprom(devnum, eeprom)) { + tlv = tlv_eeprom_read(tlv_eeprom_get_by_index(devnum), 0, eeprom, ARRAY_SIZE(eeprom)); + if (IS_ERR(tlv)) { printf("Read failed.\n"); return -1; }
- if (tlvinfo_find_tlv(eeprom, TLV_CODE_SERIAL_NUMBER, &eeprom_index)) { - eeprom_tlv = to_entry(&eeprom[eeprom_index]); - memcpy(serialstr, eeprom_tlv->value, eeprom_tlv->length); - serialstr[eeprom_tlv->length] = 0; + eeprom_tlv = tlv_entry_next_by_code(tlv, NULL, TLV_CODE_SERIAL_NUMBER); + if (!IS_ERR(eeprom_tlv)) { + tlv_entry_get_string(eeprom_tlv, serialstr, ARRAY_SIZE(serialstr)); env_set("serial#", serialstr); }
diff --git a/configs/clearfog_defconfig b/configs/clearfog_defconfig index fa86b23ef40..98a87068f59 100644 --- a/configs/clearfog_defconfig +++ b/configs/clearfog_defconfig @@ -35,7 +35,7 @@ CONFIG_SPL_SYS_MALLOC_SIMPLE=y # CONFIG_SPL_SHARES_INIT_SP_ADDR is not set CONFIG_SPL_I2C=y CONFIG_SYS_MAXARGS=32 -# CONFIG_CMD_TLV_EEPROM is not set +CONFIG_CMD_TLV_EEPROM=y CONFIG_SPL_CMD_TLV_EEPROM=y # CONFIG_CMD_FLASH is not set CONFIG_CMD_GPIO=y diff --git a/include/tlv_eeprom.h b/include/tlv_eeprom.h index b08c98a5833..e8f07b233c0 100644 --- a/include/tlv_eeprom.h +++ b/include/tlv_eeprom.h @@ -7,153 +7,6 @@ #ifndef __TLV_EEPROM_H_ #define __TLV_EEPROM_H_
-#if !defined(CONFIG_EEPROM_TLV_LIB) && !defined(CONFIG_SPL_EEPROM_TLV_LIB) - -/* - * The Definition of the TlvInfo EEPROM format can be found at onie.org or - * github.com/onie - */ - -/* - * TlvInfo header: Layout of the header for the TlvInfo format - * - * See the end of this file for details of this eeprom format - */ -struct __attribute__ ((__packed__)) tlvinfo_header { - char signature[8]; /* 0x00 - 0x07 EEPROM Tag "TlvInfo" */ - u8 version; /* 0x08 Structure version */ - u16 totallen; /* 0x09 - 0x0A Length of all data which follows */ -}; - -// Header Field Constants -#define TLV_INFO_ID_STRING "TlvInfo" -#define TLV_INFO_VERSION 0x01 -#define TLV_INFO_MAX_LEN 2048 -#define TLV_TOTAL_LEN_MAX (TLV_INFO_MAX_LEN - \ - sizeof(struct tlvinfo_header)) - -/* - * TlvInfo TLV: Layout of a TLV field - */ -struct __attribute__ ((__packed__)) tlvinfo_tlv { - u8 type; - u8 length; - u8 value[0]; -}; - -/* Maximum length of a TLV value in bytes */ -#define TLV_VALUE_MAX_LEN 255 - -/** - * The TLV Types. - * - * Keep these in sync with tlv_code_list in cmd/tlv_eeprom.c - */ -#define TLV_CODE_PRODUCT_NAME 0x21 -#define TLV_CODE_PART_NUMBER 0x22 -#define TLV_CODE_SERIAL_NUMBER 0x23 -#define TLV_CODE_MAC_BASE 0x24 -#define TLV_CODE_MANUF_DATE 0x25 -#define TLV_CODE_DEVICE_VERSION 0x26 -#define TLV_CODE_LABEL_REVISION 0x27 -#define TLV_CODE_PLATFORM_NAME 0x28 -#define TLV_CODE_ONIE_VERSION 0x29 -#define TLV_CODE_MAC_SIZE 0x2A -#define TLV_CODE_MANUF_NAME 0x2B -#define TLV_CODE_MANUF_COUNTRY 0x2C -#define TLV_CODE_VENDOR_NAME 0x2D -#define TLV_CODE_DIAG_VERSION 0x2E -#define TLV_CODE_SERVICE_TAG 0x2F -#define TLV_CODE_VENDOR_EXT 0xFD -#define TLV_CODE_CRC_32 0xFE - -#if CONFIG_IS_ENABLED(CMD_TLV_EEPROM) - -/** - * read_tlv_eeprom - Read the EEPROM binary data from the hardware - * @eeprom: Pointer to buffer to hold the binary data - * @offset: Offset within EEPROM block to read data from - * @len : Maximum size of buffer - * @dev : EEPROM device to read - * - * Note: this routine does not validate the EEPROM data. - * - */ - -int read_tlv_eeprom(void *eeprom, int offset, int len, int dev); - -/** - * write_tlv_eeprom - Write the entire EEPROM binary data to the hardware - * @eeprom: Pointer to buffer to hold the binary data - * @len : Maximum size of buffer - * @dev : EEPROM device to write - * - * Note: this routine does not validate the EEPROM data. - * - */ -int write_tlv_eeprom(void *eeprom, int len, int dev); - -/** - * read_tlvinfo_tlv_eeprom - Read the TLV from EEPROM, and validate - * @eeprom: Pointer to buffer to hold the binary data. Must point to a buffer - * of size at least TLV_INFO_MAX_LEN. - * @hdr : Points to pointer to TLV header (output) - * @first_entry : Points to pointer to first TLV entry (output) - * @dev : EEPROM device to read - * - * Store the raw EEPROM data from EEPROM @dev in the @eeprom buffer. If TLV is - * valid set *@hdr and *@first_entry. - * - * Returns 0 when read from EEPROM is successful, and the data is valid. - * Returns <0 error value when EEPROM read fails. Return -EINVAL when TLV is - * invalid. - * - */ - -int read_tlvinfo_tlv_eeprom(void *eeprom, struct tlvinfo_header **hdr, - struct tlvinfo_tlv **first_entry, int dev); - -#else /* !CONFIG_IS_ENABLED(CMD_TLV_EEPROM) */ - -static inline int read_tlv_eeprom(void *eeprom, int offset, int len, int dev) -{ - return -ENOSYS; -} - -static inline int write_tlv_eeprom(void *eeprom, int len) -{ - return -ENOSYS; -} - -static inline int -read_tlvinfo_tlv_eeprom(void *eeprom, struct tlvinfo_header **hdr, - struct tlvinfo_tlv **first_entry, int dev) -{ - return -ENOSYS; -} - -#endif /* CONFIG_IS_ENABLED(CMD_TLV_EEPROM) */ - -/** - * is_valid_tlvinfo_header - * - * Perform sanity checks on the first 11 bytes of the TlvInfo EEPROM - * data pointed to by the parameter: - * 1. First 8 bytes contain null-terminated ASCII string "TlvInfo" - * 2. Version byte is 1 - * 3. Total length bytes contain value which is less than or equal - * to the allowed maximum (2048-11) - * - */ -static inline bool is_valid_tlvinfo_header(struct tlvinfo_header *hdr) -{ - return ((strcmp(hdr->signature, TLV_INFO_ID_STRING) == 0) && - (hdr->version == TLV_INFO_VERSION) && - (be16_to_cpu(hdr->totallen) <= TLV_TOTAL_LEN_MAX)); -} - -#else - /* * The Definition of the TlvInfo EEPROM format can be found at onie.org or * github.com/onie @@ -421,5 +274,4 @@ int tlv_entry_get_uint32(struct tlvinfo_tlv *entry, u32 *buffer); */ int tlv_entry_set_uint32(struct tlvinfo_tlv *entry, const u32 value);
-#endif #endif /* __TLV_EEPROM_H_ */
participants (1)
-
Josua Mayer