1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * Copyright (C) 2013 Curt Brune <curt@cumulusnetworks.com>
- * 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>
- */
- #include <common.h>
- #include <command.h>
- #include <dm.h>
- #include <i2c.h>
- #include <i2c_eeprom.h>
- #include <env.h>
- #include <linux/ctype.h>
- #include <u-boot/crc.h>
- #include "tlv_eeprom.h"
- DECLARE_GLOBAL_DATA_PTR;
- #define MAX_TLV_DEVICES 2
- /* File scope function prototypes */
- static bool is_checksum_valid(u8 *eeprom);
- static int read_eeprom(u8 *eeprom);
- static void show_eeprom(u8 *eeprom);
- static void decode_tlv(struct tlvinfo_tlv *tlv);
- static void update_crc(u8 *eeprom);
- static int prog_eeprom(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 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(void);
- /* Set to 1 if we've read EEPROM into memory */
- static int has_been_read;
- /* The EERPOM contents after being read into memory */
- static u8 eeprom[TLV_INFO_MAX_LEN];
- static struct udevice *tlv_devices[MAX_TLV_DEVICES];
- static unsigned int current_dev;
- #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 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
- *
- * Tests if character is an ASCII hex digit
- */
- 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(u8 *eeprom)
- {
- int ret;
- struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
- struct tlvinfo_tlv *eeprom_tlv = to_entry(&eeprom[HDR_SIZE]);
- if (has_been_read)
- return 0;
- /* Read the header */
- ret = read_tlv_eeprom((void *)eeprom_hdr, 0, HDR_SIZE, current_dev);
- /* 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),
- current_dev);
- // 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);
- }
- has_been_read = 1;
- #ifdef DEBUG
- show_eeprom(eeprom);
- #endif
- return ret;
- }
- /**
- * show_eeprom
- *
- * Display the contents of the EEPROM
- */
- static void show_eeprom(u8 *eeprom)
- {
- int tlv_end;
- int curr_tlv;
- 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;
- }
- printf("TLV: %u\n", current_dev);
- printf("TlvInfo Header:\n");
- printf(" Id String: %s\n", eeprom_hdr->signature);
- printf(" Version: %d\n", eeprom_hdr->version);
- printf(" Total Length: %d\n", be16_to_cpu(eeprom_hdr->totallen));
- 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;
- }
- printf("Checksum is %s.\n",
- is_checksum_valid(eeprom) ? "valid" : "invalid");
- #ifdef DEBUG
- printf("EEPROM dump: (0x%x bytes)", TLV_INFO_MAX_LEN);
- for (i = 0; i < TLV_INFO_MAX_LEN; i++) {
- if ((i % 16) == 0)
- printf("\n%02X: ", i);
- printf("%02X ", eeprom[i]);
- }
- printf("\n");
- #endif
- }
- /**
- * Struct for displaying the TLV codes and names.
- */
- struct tlv_code_desc {
- u8 m_code;
- char *m_name;
- };
- /**
- * List of TLV codes and names.
- */
- static struct tlv_code_desc tlv_code_list[] = {
- { TLV_CODE_PRODUCT_NAME, "Product Name"},
- { TLV_CODE_PART_NUMBER, "Part Number"},
- { TLV_CODE_SERIAL_NUMBER, "Serial Number"},
- { TLV_CODE_MAC_BASE, "Base MAC Address"},
- { TLV_CODE_MANUF_DATE, "Manufacture Date"},
- { TLV_CODE_DEVICE_VERSION, "Device Version"},
- { TLV_CODE_LABEL_REVISION, "Label Revision"},
- { TLV_CODE_PLATFORM_NAME, "Platform Name"},
- { TLV_CODE_ONIE_VERSION, "ONIE Version"},
- { TLV_CODE_MAC_SIZE, "MAC Addresses"},
- { TLV_CODE_MANUF_NAME, "Manufacturer"},
- { TLV_CODE_MANUF_COUNTRY, "Country Code"},
- { TLV_CODE_VENDOR_NAME, "Vendor Name"},
- { TLV_CODE_DIAG_VERSION, "Diag Version"},
- { TLV_CODE_SERVICE_TAG, "Service Tag"},
- { TLV_CODE_VENDOR_EXT, "Vendor Extension"},
- { TLV_CODE_CRC_32, "CRC-32"},
- };
- /**
- * Look up a TLV name by its type.
- */
- static inline const char *tlv_type2name(u8 type)
- {
- char *name = "Unknown";
- int i;
- for (i = 0; i < ARRAY_SIZE(tlv_code_list); i++) {
- if (tlv_code_list[i].m_code == type) {
- name = tlv_code_list[i].m_name;
- break;
- }
- }
- return name;
- }
- /*
- * decode_tlv
- *
- * Print a string representing the contents of the TLV field. The format of
- * the string is:
- * 1. The name of the field left justified in 20 characters
- * 2. The type code in hex right justified in 5 characters
- * 3. The length in decimal right justified in 4 characters
- * 4. The value, left justified in however many characters it takes
- * The validity of EEPROM contents and the TLV field have been verified
- * prior to calling this function.
- */
- #define DECODE_NAME_MAX 20
- /*
- * The max decode value is currently for the 'raw' type or the 'vendor
- * extension' type, both of which have the same decode format. The
- * max decode string size is computed as follows:
- *
- * strlen(" 0xFF") * TLV_VALUE_MAX_LEN + 1
- *
- */
- #define DECODE_VALUE_MAX ((5 * TLV_VALUE_MAX_LEN) + 1)
- static void decode_tlv(struct tlvinfo_tlv *tlv)
- {
- char name[DECODE_NAME_MAX];
- char value[DECODE_VALUE_MAX];
- int i;
- strncpy(name, tlv_type2name(tlv->type), DECODE_NAME_MAX);
- switch (tlv->type) {
- case TLV_CODE_PRODUCT_NAME:
- case TLV_CODE_PART_NUMBER:
- case TLV_CODE_SERIAL_NUMBER:
- case TLV_CODE_MANUF_DATE:
- case TLV_CODE_LABEL_REVISION:
- case TLV_CODE_PLATFORM_NAME:
- case TLV_CODE_ONIE_VERSION:
- case TLV_CODE_MANUF_NAME:
- case TLV_CODE_MANUF_COUNTRY:
- case TLV_CODE_VENDOR_NAME:
- case TLV_CODE_DIAG_VERSION:
- case TLV_CODE_SERVICE_TAG:
- memcpy(value, tlv->value, tlv->length);
- value[tlv->length] = 0;
- break;
- case TLV_CODE_MAC_BASE:
- sprintf(value, "%02X:%02X:%02X:%02X:%02X:%02X",
- tlv->value[0], tlv->value[1], tlv->value[2],
- tlv->value[3], tlv->value[4], tlv->value[5]);
- break;
- case TLV_CODE_DEVICE_VERSION:
- sprintf(value, "%u", tlv->value[0]);
- break;
- case TLV_CODE_MAC_SIZE:
- sprintf(value, "%u", (tlv->value[0] << 8) | tlv->value[1]);
- break;
- case TLV_CODE_VENDOR_EXT:
- value[0] = 0;
- for (i = 0; (i < (DECODE_VALUE_MAX / 5)) && (i < tlv->length);
- i++) {
- sprintf(value, "%s 0x%02X", value, tlv->value[i]);
- }
- break;
- case TLV_CODE_CRC_32:
- sprintf(value, "0x%02X%02X%02X%02X",
- tlv->value[0], tlv->value[1],
- tlv->value[2], tlv->value[3]);
- break;
- default:
- value[0] = 0;
- for (i = 0; (i < (DECODE_VALUE_MAX / 5)) && (i < tlv->length);
- i++) {
- sprintf(value, "%s 0x%02X", value, tlv->value[i]);
- }
- break;
- }
- name[DECODE_NAME_MAX - 1] = 0;
- 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(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);
- 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
- */
- void show_tlv_code_list(void)
- {
- int i;
- printf("TLV Code TLV Name\n");
- printf("======== =================\n");
- for (i = 0; i < ARRAY_SIZE(tlv_code_list); i++) {
- printf("0x%02X %s\n",
- tlv_code_list[i].m_code,
- tlv_code_list[i].m_name);
- }
- }
- /**
- * do_tlv_eeprom
- *
- * This function implements the tlv_eeprom command.
- */
- int do_tlv_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
- {
- char cmd;
- struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
- // If no arguments, read the EERPOM and display its contents
- if (argc == 1) {
- read_eeprom(eeprom);
- show_eeprom(eeprom);
- return 0;
- }
- // We only look at the first character to the command, so "read" and
- // "reset" will both be treated as "read".
- cmd = argv[1][0];
- // Read the EEPROM contents
- if (cmd == 'r') {
- has_been_read = 0;
- if (!read_eeprom(eeprom))
- printf("EEPROM data loaded from device to memory.\n");
- return 0;
- }
- // Subsequent commands require that the EEPROM has already been read.
- if (!has_been_read) {
- printf("Please read the EEPROM data first, using the 'tlv_eeprom read' command.\n");
- return 0;
- }
- // Handle the commands that don't take parameters
- if (argc == 2) {
- switch (cmd) {
- case 'w': /* write */
- prog_eeprom(eeprom);
- 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);
- printf("EEPROM data in memory reset.\n");
- break;
- case 'l': /* list */
- show_tlv_code_list();
- break;
- case 'd': /* dev */
- show_tlv_devices();
- break;
- default:
- cmd_usage(cmdtp);
- break;
- }
- return 0;
- }
- // The set command takes one or two args.
- if (argc > 4) {
- cmd_usage(cmdtp);
- return 0;
- }
- // Set command. If the TLV exists in the EEPROM, delete it. Then if
- // data was supplied for this TLV add the TLV with the new contents at
- // the end.
- if (cmd == 's') {
- int tcode;
- tcode = simple_strtoul(argv[2], NULL, 0);
- tlvinfo_delete_tlv(eeprom, tcode);
- if (argc == 4)
- tlvinfo_add_tlv(eeprom, tcode, argv[3]);
- } else if (cmd == 'd') { /* 'dev' command */
- unsigned int devnum;
- devnum = simple_strtoul(argv[2], NULL, 0);
- if (devnum > MAX_TLV_DEVICES || !tlv_devices[devnum]) {
- printf("Invalid device number\n");
- return 0;
- }
- current_dev = devnum;
- has_been_read = 0;
- } else {
- cmd_usage(cmdtp);
- }
- return 0;
- }
- /**
- * This macro defines the tlv_eeprom command line command.
- */
- U_BOOT_CMD(tlv_eeprom, 4, 1, do_tlv_eeprom,
- "Display and program the system EEPROM data block.",
- "[read|write|set <type_code> <string_value>|erase|list]\n"
- "tlv_eeprom\n"
- " - With no arguments display the current contents.\n"
- "tlv_eeprom dev [dev]\n"
- " - List devices or set current EEPROM device.\n"
- "tlv_eeprom read\n"
- " - Load EEPROM data from device to memory.\n"
- "tlv_eeprom write\n"
- " - Write the EEPROM data to persistent storage.\n"
- "tlv_eeprom set <type_code> <string_value>\n"
- " - Set a field to a value.\n"
- " - If no string_value, field is deleted.\n"
- " - Use 'tlv_eeprom write' to make changes permanent.\n"
- "tlv_eeprom erase\n"
- " - Reset the in memory EEPROM data.\n"
- " - Use 'tlv_eeprom read' to refresh the in memory EEPROM data.\n"
- " - Use 'tlv_eeprom write' to make changes permanent.\n"
- "tlv_eeprom list\n"
- " - 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
- *
- * This function adds a TLV to the EEPROM, converting the value (a string) to
- * 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)
- {
- struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
- struct tlvinfo_tlv *eeprom_tlv;
- 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) {
- case TLV_CODE_PRODUCT_NAME:
- case TLV_CODE_PART_NUMBER:
- case TLV_CODE_SERIAL_NUMBER:
- case TLV_CODE_LABEL_REVISION:
- case TLV_CODE_PLATFORM_NAME:
- case TLV_CODE_ONIE_VERSION:
- case TLV_CODE_MANUF_NAME:
- case TLV_CODE_MANUF_COUNTRY:
- case TLV_CODE_VENDOR_NAME:
- case TLV_CODE_DIAG_VERSION:
- case TLV_CODE_SERVICE_TAG:
- strncpy(data, strval, MAX_TLV_VALUE_LEN);
- new_tlv_len = min_t(size_t, MAX_TLV_VALUE_LEN, strlen(strval));
- break;
- case TLV_CODE_DEVICE_VERSION:
- value = simple_strtoul(strval, NULL, 0);
- if (value >= 256) {
- printf("ERROR: Device version must be 255 or less. Value supplied: %u",
- value);
- return false;
- }
- data[0] = value & 0xFF;
- new_tlv_len = 1;
- break;
- case TLV_CODE_MAC_SIZE:
- value = simple_strtoul(strval, NULL, 0);
- if (value >= 65536) {
- printf("ERROR: MAC Size must be 65535 or less. Value supplied: %u",
- value);
- return false;
- }
- data[0] = (value >> 8) & 0xFF;
- data[1] = value & 0xFF;
- new_tlv_len = 2;
- break;
- case TLV_CODE_MANUF_DATE:
- if (set_date(data, strval) != 0)
- return false;
- new_tlv_len = 19;
- break;
- case TLV_CODE_MAC_BASE:
- if (set_mac(data, strval) != 0)
- return false;
- new_tlv_len = 6;
- break;
- case TLV_CODE_CRC_32:
- printf("WARNING: The CRC TLV is set automatically and cannot be set manually.\n");
- return false;
- case TLV_CODE_VENDOR_EXT:
- default:
- if (set_bytes(data, strval, &new_tlv_len) != 0)
- return false;
- break;
- }
- // Is there room for this TLV?
- if ((be16_to_cpu(eeprom_hdr->totallen) + ENT_SIZE + new_tlv_len) >
- TLV_TOTAL_LEN_MAX) {
- printf("ERROR: There is not enough room in the EERPOM to save data.\n");
- 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);
- return true;
- }
- /**
- * set_mac
- *
- * Converts a string MAC address into a binary buffer.
- *
- * This function takes a pointer to a MAC address string
- * (i.e."XX:XX:XX:XX:XX:XX", where "XX" is a two-digit hex number).
- * The string format is verified and then converted to binary and
- * stored in a buffer.
- */
- static int set_mac(char *buf, const char *string)
- {
- char *p = (char *)string;
- int i;
- int err = 0;
- char *end;
- if (!p) {
- printf("ERROR: NULL mac addr string passed in.\n");
- return -1;
- }
- if (strlen(p) != 17) {
- printf("ERROR: MAC address strlen() != 17 -- %zu\n", strlen(p));
- printf("ERROR: Bad MAC address format: %s\n", string);
- return -1;
- }
- for (i = 0; i < 17; i++) {
- if ((i % 3) == 2) {
- if (p[i] != ':') {
- err++;
- printf("ERROR: mac: p[%i] != :, found: `%c'\n",
- i, p[i]);
- break;
- }
- continue;
- } else if (!is_hex(p[i])) {
- err++;
- printf("ERROR: mac: p[%i] != hex digit, found: `%c'\n",
- i, p[i]);
- break;
- }
- }
- if (err != 0) {
- printf("ERROR: Bad MAC address format: %s\n", string);
- return -1;
- }
- /* Convert string to binary */
- for (i = 0, p = (char *)string; i < 6; i++) {
- buf[i] = p ? simple_strtoul(p, &end, 16) : 0;
- if (p)
- p = (*end) ? end + 1 : end;
- }
- if (!is_valid_ethaddr((u8 *)buf)) {
- printf("ERROR: MAC address must not be 00:00:00:00:00:00, a multicast address or FF:FF:FF:FF:FF:FF.\n");
- printf("ERROR: Bad MAC address format: %s\n", string);
- return -1;
- }
- return 0;
- }
- /**
- * set_date
- *
- * Validates the format of the data string
- *
- * This function takes a pointer to a date string (i.e. MM/DD/YYYY hh:mm:ss)
- * and validates that the format is correct. If so the string is copied
- * to the supplied buffer.
- */
- static int set_date(char *buf, const char *string)
- {
- int i;
- if (!string) {
- printf("ERROR: NULL date string passed in.\n");
- return -1;
- }
- if (strlen(string) != 19) {
- printf("ERROR: Date strlen() != 19 -- %zu\n", strlen(string));
- printf("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
- string);
- return -1;
- }
- for (i = 0; string[i] != 0; i++) {
- switch (i) {
- case 2:
- case 5:
- if (string[i] != '/') {
- printf("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
- string);
- return -1;
- }
- break;
- case 10:
- if (string[i] != ' ') {
- printf("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
- string);
- return -1;
- }
- break;
- case 13:
- case 16:
- if (string[i] != ':') {
- printf("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
- string);
- return -1;
- }
- break;
- default:
- if (!is_digit(string[i])) {
- printf("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
- string);
- return -1;
- }
- break;
- }
- }
- strcpy(buf, string);
- return 0;
- }
- /**
- * set_bytes
- *
- * Converts a space-separated string of decimal numbers into a
- * buffer of bytes.
- *
- * This function takes a pointer to a space-separated string of decimal
- * numbers (i.e. "128 0x55 0321") with "C" standard radix specifiers
- * and converts them to an array of bytes.
- */
- static int set_bytes(char *buf, const char *string, int *converted_accum)
- {
- char *p = (char *)string;
- int i;
- uint byte;
- if (!p) {
- printf("ERROR: NULL string passed in.\n");
- return -1;
- }
- /* Convert string to bytes */
- for (i = 0, p = (char *)string; (i < TLV_VALUE_MAX_LEN) && (*p != 0);
- i++) {
- while ((*p == ' ') || (*p == '\t') || (*p == ',') ||
- (*p == ';')) {
- p++;
- }
- if (*p != 0) {
- if (!is_digit(*p)) {
- printf("ERROR: Non-digit found in byte string: (%s)\n",
- string);
- return -1;
- }
- byte = simple_strtoul(p, &p, 0);
- if (byte >= 256) {
- printf("ERROR: The value specified is greater than 255: (%u) in string: %s\n",
- byte, string);
- return -1;
- }
- buf[i] = byte & 0xFF;
- }
- }
- if (i == TLV_VALUE_MAX_LEN && (*p != 0)) {
- printf("ERROR: Trying to assign too many bytes (max: %d) in string: %s\n",
- TLV_VALUE_MAX_LEN, string);
- return -1;
- }
- *converted_accum = i;
- return 0;
- }
- static void show_tlv_devices(void)
- {
- unsigned int dev;
- for (dev = 0; dev < MAX_TLV_DEVICES; dev++)
- if (tlv_devices[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)
- {
- if (!(gd->flags & GD_FLG_RELOC))
- return -ENODEV;
- if (!tlv_devices[current_dev])
- return -ENODEV;
- return i2c_eeprom_write(tlv_devices[current_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
- *
- * Read the MAC addresses from EEPROM
- *
- * This function reads the MAC addresses from EEPROM and sets the
- * appropriate environment variables for each one read.
- *
- * The environment variables are only set if they haven't been set already.
- * This ensures that any user-saved variables are never overwritten.
- *
- * This function must be called after relocation.
- */
- int mac_read_from_eeprom(void)
- {
- unsigned int i;
- int eeprom_index;
- struct tlvinfo_tlv *eeprom_tlv;
- int maccount;
- u8 macbase[6];
- struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
- puts("EEPROM: ");
- if (read_eeprom(eeprom)) {
- printf("Read failed.\n");
- return -1;
- }
- 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];
- }
- 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);
- }
- for (i = 0; i < maccount; i++) {
- if (is_valid_ethaddr(macbase)) {
- char ethaddr[18];
- char enetvar[11];
- sprintf(ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
- macbase[0], macbase[1], macbase[2],
- macbase[3], macbase[4], macbase[5]);
- sprintf(enetvar, i ? "eth%daddr" : "ethaddr", i);
- /* Only initialize environment variables that are blank
- * (i.e. have not yet been set)
- */
- if (!env_get(enetvar))
- env_set(enetvar, ethaddr);
- macbase[5]++;
- if (macbase[5] == 0) {
- macbase[4]++;
- if (macbase[4] == 0) {
- macbase[3]++;
- if (macbase[3] == 0) {
- macbase[0] = 0;
- macbase[1] = 0;
- macbase[2] = 0;
- }
- }
- }
- }
- }
- printf("%s v%u len=%u\n", eeprom_hdr->signature, eeprom_hdr->version,
- be16_to_cpu(eeprom_hdr->totallen));
- return 0;
- }
- /**
- * populate_serial_number - read the serial number from EEPROM
- *
- * This function reads the serial number from the EEPROM and sets the
- * appropriate environment variable.
- *
- * The environment variable is only set if it has not been set
- * already. This ensures that any user-saved variables are never
- * overwritten.
- *
- * This function must be called after relocation.
- */
- int populate_serial_number(void)
- {
- char serialstr[257];
- int eeprom_index;
- struct tlvinfo_tlv *eeprom_tlv;
- if (env_get("serial#"))
- return 0;
- if (read_eeprom(eeprom)) {
- 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;
- env_set("serial#", serialstr);
- }
- return 0;
- }
|