uboot/cmd/tlv_eeprom.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * See file CREDITS for list of people who contributed to this
   4 * project.
   5 *
   6 * Copyright (C) 2013 Curt Brune <curt@cumulusnetworks.com>
   7 * Copyright (C) 2014 Srideep <srideep_devireddy@dell.com>
   8 * Copyright (C) 2013 Miles Tseng <miles_tseng@accton.com>
   9 * Copyright (C) 2014,2016 david_yang <david_yang@accton.com>
  10 */
  11
  12#include <common.h>
  13#include <command.h>
  14#include <dm.h>
  15#include <i2c.h>
  16#include <i2c_eeprom.h>
  17#include <env.h>
  18#include <init.h>
  19#include <net.h>
  20#include <linux/ctype.h>
  21#include <u-boot/crc.h>
  22
  23#include "tlv_eeprom.h"
  24
  25DECLARE_GLOBAL_DATA_PTR;
  26
  27#define MAX_TLV_DEVICES 2
  28
  29/* File scope function prototypes */
  30static bool is_checksum_valid(u8 *eeprom);
  31static int read_eeprom(u8 *eeprom);
  32static void show_eeprom(u8 *eeprom);
  33static void decode_tlv(struct tlvinfo_tlv *tlv);
  34static void update_crc(u8 *eeprom);
  35static int prog_eeprom(u8 *eeprom);
  36static bool tlvinfo_find_tlv(u8 *eeprom, u8 tcode, int *eeprom_index);
  37static bool tlvinfo_delete_tlv(u8 *eeprom, u8 code);
  38static bool tlvinfo_add_tlv(u8 *eeprom, int tcode, char *strval);
  39static int set_mac(char *buf, const char *string);
  40static int set_date(char *buf, const char *string);
  41static int set_bytes(char *buf, const char *string, int *converted_accum);
  42static void show_tlv_devices(void);
  43
  44/* Set to 1 if we've read EEPROM into memory */
  45static int has_been_read;
  46/* The EERPOM contents after being read into memory */
  47static u8 eeprom[TLV_INFO_MAX_LEN];
  48
  49static struct udevice *tlv_devices[MAX_TLV_DEVICES];
  50static unsigned int current_dev;
  51
  52#define to_header(p) ((struct tlvinfo_header *)p)
  53#define to_entry(p) ((struct tlvinfo_tlv *)p)
  54
  55#define HDR_SIZE sizeof(struct tlvinfo_header)
  56#define ENT_SIZE sizeof(struct tlvinfo_tlv)
  57
  58static inline bool is_digit(char c)
  59{
  60        return (c >= '0' && c <= '9');
  61}
  62
  63/**
  64 *  is_valid_tlv
  65 *
  66 *  Perform basic sanity checks on a TLV field. The TLV is pointed to
  67 *  by the parameter provided.
  68 *      1. The type code is not reserved (0x00 or 0xFF)
  69 */
  70static inline bool is_valid_tlv(struct tlvinfo_tlv *tlv)
  71{
  72        return((tlv->type != 0x00) && (tlv->type != 0xFF));
  73}
  74
  75/**
  76 *  is_hex
  77 *
  78 *  Tests if character is an ASCII hex digit
  79 */
  80static inline u8 is_hex(char p)
  81{
  82        return (((p >= '0') && (p <= '9')) ||
  83                ((p >= 'A') && (p <= 'F')) ||
  84                ((p >= 'a') && (p <= 'f')));
  85}
  86
  87/**
  88 *  is_checksum_valid
  89 *
  90 *  Validate the checksum in the provided TlvInfo EEPROM data. First,
  91 *  verify that the TlvInfo header is valid, then make sure the last
  92 *  TLV is a CRC-32 TLV. Then calculate the CRC over the EEPROM data
  93 *  and compare it to the value stored in the EEPROM CRC-32 TLV.
  94 */
  95static bool is_checksum_valid(u8 *eeprom)
  96{
  97        struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
  98        struct tlvinfo_tlv    *eeprom_crc;
  99        unsigned int       calc_crc;
 100        unsigned int       stored_crc;
 101
 102        // Is the eeprom header valid?
 103        if (!is_valid_tlvinfo_header(eeprom_hdr))
 104                return false;
 105
 106        // Is the last TLV a CRC?
 107        eeprom_crc = to_entry(&eeprom[HDR_SIZE +
 108                be16_to_cpu(eeprom_hdr->totallen) - (ENT_SIZE + 4)]);
 109        if (eeprom_crc->type != TLV_CODE_CRC_32 || eeprom_crc->length != 4)
 110                return false;
 111
 112        // Calculate the checksum
 113        calc_crc = crc32(0, (void *)eeprom,
 114                         HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen) - 4);
 115        stored_crc = (eeprom_crc->value[0] << 24) |
 116                (eeprom_crc->value[1] << 16) |
 117                (eeprom_crc->value[2] <<  8) |
 118                eeprom_crc->value[3];
 119        return calc_crc == stored_crc;
 120}
 121
 122/**
 123 *  read_eeprom
 124 *
 125 *  Read the EEPROM into memory, if it hasn't already been read.
 126 */
 127static int read_eeprom(u8 *eeprom)
 128{
 129        int ret;
 130        struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
 131        struct tlvinfo_tlv *eeprom_tlv = to_entry(&eeprom[HDR_SIZE]);
 132
 133        if (has_been_read)
 134                return 0;
 135
 136        /* Read the header */
 137        ret = read_tlv_eeprom((void *)eeprom_hdr, 0, HDR_SIZE, current_dev);
 138        /* If the header was successfully read, read the TLVs */
 139        if (ret == 0 && is_valid_tlvinfo_header(eeprom_hdr))
 140                ret = read_tlv_eeprom((void *)eeprom_tlv, HDR_SIZE,
 141                                      be16_to_cpu(eeprom_hdr->totallen),
 142                                      current_dev);
 143
 144        // If the contents are invalid, start over with default contents
 145        if (!is_valid_tlvinfo_header(eeprom_hdr) ||
 146            !is_checksum_valid(eeprom)) {
 147                strcpy(eeprom_hdr->signature, TLV_INFO_ID_STRING);
 148                eeprom_hdr->version = TLV_INFO_VERSION;
 149                eeprom_hdr->totallen = cpu_to_be16(0);
 150                update_crc(eeprom);
 151        }
 152
 153        has_been_read = 1;
 154
 155#ifdef DEBUG
 156        show_eeprom(eeprom);
 157#endif
 158
 159        return ret;
 160}
 161
 162/**
 163 *  show_eeprom
 164 *
 165 *  Display the contents of the EEPROM
 166 */
 167static void show_eeprom(u8 *eeprom)
 168{
 169        int tlv_end;
 170        int curr_tlv;
 171        struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
 172        struct tlvinfo_tlv    *eeprom_tlv;
 173
 174        if (!is_valid_tlvinfo_header(eeprom_hdr)) {
 175                printf("EEPROM does not contain data in a valid TlvInfo format.\n");
 176                return;
 177        }
 178
 179        printf("TLV: %u\n", current_dev);
 180        printf("TlvInfo Header:\n");
 181        printf("   Id String:    %s\n", eeprom_hdr->signature);
 182        printf("   Version:      %d\n", eeprom_hdr->version);
 183        printf("   Total Length: %d\n", be16_to_cpu(eeprom_hdr->totallen));
 184
 185        printf("TLV Name             Code Len Value\n");
 186        printf("-------------------- ---- --- -----\n");
 187        curr_tlv = HDR_SIZE;
 188        tlv_end  = HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen);
 189        while (curr_tlv < tlv_end) {
 190                eeprom_tlv = to_entry(&eeprom[curr_tlv]);
 191                if (!is_valid_tlv(eeprom_tlv)) {
 192                        printf("Invalid TLV field starting at EEPROM offset %d\n",
 193                               curr_tlv);
 194                        return;
 195                }
 196                decode_tlv(eeprom_tlv);
 197                curr_tlv += ENT_SIZE + eeprom_tlv->length;
 198        }
 199
 200        printf("Checksum is %s.\n",
 201               is_checksum_valid(eeprom) ? "valid" : "invalid");
 202
 203#ifdef DEBUG
 204        printf("EEPROM dump: (0x%x bytes)", TLV_INFO_MAX_LEN);
 205        for (i = 0; i < TLV_INFO_MAX_LEN; i++) {
 206                if ((i % 16) == 0)
 207                        printf("\n%02X: ", i);
 208                printf("%02X ", eeprom[i]);
 209        }
 210        printf("\n");
 211#endif
 212}
 213
 214/**
 215 *  Struct for displaying the TLV codes and names.
 216 */
 217struct tlv_code_desc {
 218        u8    m_code;
 219        char *m_name;
 220};
 221
 222/**
 223 *  List of TLV codes and names.
 224 */
 225static struct tlv_code_desc tlv_code_list[] = {
 226        { TLV_CODE_PRODUCT_NAME,   "Product Name"},
 227        { TLV_CODE_PART_NUMBER,    "Part Number"},
 228        { TLV_CODE_SERIAL_NUMBER,  "Serial Number"},
 229        { TLV_CODE_MAC_BASE,       "Base MAC Address"},
 230        { TLV_CODE_MANUF_DATE,     "Manufacture Date"},
 231        { TLV_CODE_DEVICE_VERSION, "Device Version"},
 232        { TLV_CODE_LABEL_REVISION, "Label Revision"},
 233        { TLV_CODE_PLATFORM_NAME,  "Platform Name"},
 234        { TLV_CODE_ONIE_VERSION,   "ONIE Version"},
 235        { TLV_CODE_MAC_SIZE,       "MAC Addresses"},
 236        { TLV_CODE_MANUF_NAME,     "Manufacturer"},
 237        { TLV_CODE_MANUF_COUNTRY,  "Country Code"},
 238        { TLV_CODE_VENDOR_NAME,    "Vendor Name"},
 239        { TLV_CODE_DIAG_VERSION,   "Diag Version"},
 240        { TLV_CODE_SERVICE_TAG,    "Service Tag"},
 241        { TLV_CODE_VENDOR_EXT,     "Vendor Extension"},
 242        { TLV_CODE_CRC_32,         "CRC-32"},
 243};
 244
 245/**
 246 *  Look up a TLV name by its type.
 247 */
 248static inline const char *tlv_type2name(u8 type)
 249{
 250        char *name = "Unknown";
 251        int   i;
 252
 253        for (i = 0; i < ARRAY_SIZE(tlv_code_list); i++) {
 254                if (tlv_code_list[i].m_code == type) {
 255                        name = tlv_code_list[i].m_name;
 256                        break;
 257                }
 258        }
 259
 260        return name;
 261}
 262
 263/*
 264 *  decode_tlv
 265 *
 266 *  Print a string representing the contents of the TLV field. The format of
 267 *  the string is:
 268 *      1. The name of the field left justified in 20 characters
 269 *      2. The type code in hex right justified in 5 characters
 270 *      3. The length in decimal right justified in 4 characters
 271 *      4. The value, left justified in however many characters it takes
 272 *  The validity of EEPROM contents and the TLV field have been verified
 273 *  prior to calling this function.
 274 */
 275#define DECODE_NAME_MAX     20
 276
 277/*
 278 * The max decode value is currently for the 'raw' type or the 'vendor
 279 * extension' type, both of which have the same decode format.  The
 280 * max decode string size is computed as follows:
 281 *
 282 *   strlen(" 0xFF") * TLV_VALUE_MAX_LEN + 1
 283 *
 284 */
 285#define DECODE_VALUE_MAX    ((5 * TLV_VALUE_MAX_LEN) + 1)
 286
 287static void decode_tlv(struct tlvinfo_tlv *tlv)
 288{
 289        char name[DECODE_NAME_MAX];
 290        char value[DECODE_VALUE_MAX];
 291        int i;
 292
 293        strncpy(name, tlv_type2name(tlv->type), DECODE_NAME_MAX);
 294
 295        switch (tlv->type) {
 296        case TLV_CODE_PRODUCT_NAME:
 297        case TLV_CODE_PART_NUMBER:
 298        case TLV_CODE_SERIAL_NUMBER:
 299        case TLV_CODE_MANUF_DATE:
 300        case TLV_CODE_LABEL_REVISION:
 301        case TLV_CODE_PLATFORM_NAME:
 302        case TLV_CODE_ONIE_VERSION:
 303        case TLV_CODE_MANUF_NAME:
 304        case TLV_CODE_MANUF_COUNTRY:
 305        case TLV_CODE_VENDOR_NAME:
 306        case TLV_CODE_DIAG_VERSION:
 307        case TLV_CODE_SERVICE_TAG:
 308                memcpy(value, tlv->value, tlv->length);
 309                value[tlv->length] = 0;
 310                break;
 311        case TLV_CODE_MAC_BASE:
 312                sprintf(value, "%02X:%02X:%02X:%02X:%02X:%02X",
 313                        tlv->value[0], tlv->value[1], tlv->value[2],
 314                        tlv->value[3], tlv->value[4], tlv->value[5]);
 315                break;
 316        case TLV_CODE_DEVICE_VERSION:
 317                sprintf(value, "%u", tlv->value[0]);
 318                break;
 319        case TLV_CODE_MAC_SIZE:
 320                sprintf(value, "%u", (tlv->value[0] << 8) | tlv->value[1]);
 321                break;
 322        case TLV_CODE_VENDOR_EXT:
 323                value[0] = 0;
 324                for (i = 0; (i < (DECODE_VALUE_MAX / 5)) && (i < tlv->length);
 325                                i++) {
 326                        sprintf(value, "%s 0x%02X", value, tlv->value[i]);
 327                }
 328                break;
 329        case TLV_CODE_CRC_32:
 330                sprintf(value, "0x%02X%02X%02X%02X",
 331                        tlv->value[0], tlv->value[1],
 332                        tlv->value[2], tlv->value[3]);
 333                break;
 334        default:
 335                value[0] = 0;
 336                for (i = 0; (i < (DECODE_VALUE_MAX / 5)) && (i < tlv->length);
 337                                i++) {
 338                        sprintf(value, "%s 0x%02X", value, tlv->value[i]);
 339                }
 340                break;
 341        }
 342
 343        name[DECODE_NAME_MAX - 1] = 0;
 344        printf("%-20s 0x%02X %3d %s\n", name, tlv->type, tlv->length, value);
 345}
 346
 347/**
 348 *  update_crc
 349 *
 350 *  This function updates the CRC-32 TLV. If there is no CRC-32 TLV, then
 351 *  one is added. This function should be called after each update to the
 352 *  EEPROM structure, to make sure the CRC is always correct.
 353 */
 354static void update_crc(u8 *eeprom)
 355{
 356        struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
 357        struct tlvinfo_tlv    *eeprom_crc;
 358        unsigned int      calc_crc;
 359        int               eeprom_index;
 360
 361        // Discover the CRC TLV
 362        if (!tlvinfo_find_tlv(eeprom, TLV_CODE_CRC_32, &eeprom_index)) {
 363                unsigned int totallen = be16_to_cpu(eeprom_hdr->totallen);
 364
 365                if ((totallen + ENT_SIZE + 4) > TLV_TOTAL_LEN_MAX)
 366                        return;
 367                eeprom_index = HDR_SIZE + totallen;
 368                eeprom_hdr->totallen = cpu_to_be16(totallen + ENT_SIZE + 4);
 369        }
 370        eeprom_crc = to_entry(&eeprom[eeprom_index]);
 371        eeprom_crc->type = TLV_CODE_CRC_32;
 372        eeprom_crc->length = 4;
 373
 374        // Calculate the checksum
 375        calc_crc = crc32(0, (void *)eeprom,
 376                         HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen) - 4);
 377        eeprom_crc->value[0] = (calc_crc >> 24) & 0xFF;
 378        eeprom_crc->value[1] = (calc_crc >> 16) & 0xFF;
 379        eeprom_crc->value[2] = (calc_crc >>  8) & 0xFF;
 380        eeprom_crc->value[3] = (calc_crc >>  0) & 0xFF;
 381}
 382
 383/**
 384 *  prog_eeprom
 385 *
 386 *  Write the EEPROM data from CPU memory to the hardware.
 387 */
 388static int prog_eeprom(u8 *eeprom)
 389{
 390        int ret = 0;
 391        struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
 392        int eeprom_len;
 393
 394        update_crc(eeprom);
 395
 396        eeprom_len = HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen);
 397        ret = write_tlv_eeprom(eeprom, eeprom_len);
 398        if (ret) {
 399                printf("Programming failed.\n");
 400                return -1;
 401        }
 402
 403        printf("Programming passed.\n");
 404        return 0;
 405}
 406
 407/**
 408 *  show_tlv_code_list - Display the list of TLV codes and names
 409 */
 410void show_tlv_code_list(void)
 411{
 412        int i;
 413
 414        printf("TLV Code    TLV Name\n");
 415        printf("========    =================\n");
 416        for (i = 0; i < ARRAY_SIZE(tlv_code_list); i++) {
 417                printf("0x%02X        %s\n",
 418                       tlv_code_list[i].m_code,
 419                       tlv_code_list[i].m_name);
 420        }
 421}
 422
 423/**
 424 *  do_tlv_eeprom
 425 *
 426 *  This function implements the tlv_eeprom command.
 427 */
 428int do_tlv_eeprom(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 429{
 430        char cmd;
 431        struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
 432
 433        // If no arguments, read the EERPOM and display its contents
 434        if (argc == 1) {
 435                read_eeprom(eeprom);
 436                show_eeprom(eeprom);
 437                return 0;
 438        }
 439
 440        // We only look at the first character to the command, so "read" and
 441        // "reset" will both be treated as "read".
 442        cmd = argv[1][0];
 443
 444        // Read the EEPROM contents
 445        if (cmd == 'r') {
 446                has_been_read = 0;
 447                if (!read_eeprom(eeprom))
 448                        printf("EEPROM data loaded from device to memory.\n");
 449                return 0;
 450        }
 451
 452        // Subsequent commands require that the EEPROM has already been read.
 453        if (!has_been_read) {
 454                printf("Please read the EEPROM data first, using the 'tlv_eeprom read' command.\n");
 455                return 0;
 456        }
 457
 458        // Handle the commands that don't take parameters
 459        if (argc == 2) {
 460                switch (cmd) {
 461                case 'w':   /* write */
 462                        prog_eeprom(eeprom);
 463                        break;
 464                case 'e':   /* erase */
 465                        strcpy(eeprom_hdr->signature, TLV_INFO_ID_STRING);
 466                        eeprom_hdr->version = TLV_INFO_VERSION;
 467                        eeprom_hdr->totallen = cpu_to_be16(0);
 468                        update_crc(eeprom);
 469                        printf("EEPROM data in memory reset.\n");
 470                        break;
 471                case 'l':   /* list */
 472                        show_tlv_code_list();
 473                        break;
 474                case 'd':   /* dev */
 475                        show_tlv_devices();
 476                        break;
 477                default:
 478                        cmd_usage(cmdtp);
 479                        break;
 480                }
 481                return 0;
 482        }
 483
 484        // The set command takes one or two args.
 485        if (argc > 4) {
 486                cmd_usage(cmdtp);
 487                return 0;
 488        }
 489
 490        // Set command. If the TLV exists in the EEPROM, delete it. Then if
 491        // data was supplied for this TLV add the TLV with the new contents at
 492        // the end.
 493        if (cmd == 's') {
 494                int tcode;
 495
 496                tcode = simple_strtoul(argv[2], NULL, 0);
 497                tlvinfo_delete_tlv(eeprom, tcode);
 498                if (argc == 4)
 499                        tlvinfo_add_tlv(eeprom, tcode, argv[3]);
 500        } else if (cmd == 'd') { /* 'dev' command */
 501                unsigned int devnum;
 502
 503                devnum = simple_strtoul(argv[2], NULL, 0);
 504                if (devnum > MAX_TLV_DEVICES || !tlv_devices[devnum]) {
 505                        printf("Invalid device number\n");
 506                        return 0;
 507                }
 508                current_dev = devnum;
 509                has_been_read = 0;
 510        } else {
 511                cmd_usage(cmdtp);
 512        }
 513
 514        return 0;
 515}
 516
 517/**
 518 *  This macro defines the tlv_eeprom command line command.
 519 */
 520U_BOOT_CMD(tlv_eeprom, 4, 1,  do_tlv_eeprom,
 521           "Display and program the system EEPROM data block.",
 522           "[read|write|set <type_code> <string_value>|erase|list]\n"
 523           "tlv_eeprom\n"
 524           "    - With no arguments display the current contents.\n"
 525           "tlv_eeprom dev [dev]\n"
 526           "    - List devices or set current EEPROM device.\n"
 527           "tlv_eeprom read\n"
 528           "    - Load EEPROM data from device to memory.\n"
 529           "tlv_eeprom write\n"
 530           "    - Write the EEPROM data to persistent storage.\n"
 531           "tlv_eeprom set <type_code> <string_value>\n"
 532           "    - Set a field to a value.\n"
 533           "    - If no string_value, field is deleted.\n"
 534           "    - Use 'tlv_eeprom write' to make changes permanent.\n"
 535           "tlv_eeprom erase\n"
 536           "    - Reset the in memory EEPROM data.\n"
 537           "    - Use 'tlv_eeprom read' to refresh the in memory EEPROM data.\n"
 538           "    - Use 'tlv_eeprom write' to make changes permanent.\n"
 539           "tlv_eeprom list\n"
 540           "    - List the understood TLV codes and names.\n"
 541        );
 542
 543/**
 544 *  tlvinfo_find_tlv
 545 *
 546 *  This function finds the TLV with the supplied code in the EERPOM.
 547 *  An offset from the beginning of the EEPROM is returned in the
 548 *  eeprom_index parameter if the TLV is found.
 549 */
 550static bool tlvinfo_find_tlv(u8 *eeprom, u8 tcode, int *eeprom_index)
 551{
 552        struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
 553        struct tlvinfo_tlv    *eeprom_tlv;
 554        int eeprom_end;
 555
 556        // Search through the TLVs, looking for the first one which matches the
 557        // supplied type code.
 558        *eeprom_index = HDR_SIZE;
 559        eeprom_end = HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen);
 560        while (*eeprom_index < eeprom_end) {
 561                eeprom_tlv = to_entry(&eeprom[*eeprom_index]);
 562                if (!is_valid_tlv(eeprom_tlv))
 563                        return false;
 564                if (eeprom_tlv->type == tcode)
 565                        return true;
 566                *eeprom_index += ENT_SIZE + eeprom_tlv->length;
 567        }
 568        return(false);
 569}
 570
 571/**
 572 *  tlvinfo_delete_tlv
 573 *
 574 *  This function deletes the TLV with the specified type code from the
 575 *  EEPROM.
 576 */
 577static bool tlvinfo_delete_tlv(u8 *eeprom, u8 code)
 578{
 579        int eeprom_index;
 580        int tlength;
 581        struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
 582        struct tlvinfo_tlv *eeprom_tlv;
 583
 584        // Find the TLV and then move all following TLVs "forward"
 585        if (tlvinfo_find_tlv(eeprom, code, &eeprom_index)) {
 586                eeprom_tlv = to_entry(&eeprom[eeprom_index]);
 587                tlength = ENT_SIZE + eeprom_tlv->length;
 588                memcpy(&eeprom[eeprom_index], &eeprom[eeprom_index + tlength],
 589                       HDR_SIZE +
 590                       be16_to_cpu(eeprom_hdr->totallen) - eeprom_index -
 591                       tlength);
 592                eeprom_hdr->totallen =
 593                        cpu_to_be16(be16_to_cpu(eeprom_hdr->totallen) -
 594                                    tlength);
 595                update_crc(eeprom);
 596                return true;
 597        }
 598        return false;
 599}
 600
 601/**
 602 *  tlvinfo_add_tlv
 603 *
 604 *  This function adds a TLV to the EEPROM, converting the value (a string) to
 605 *  the format in which it will be stored in the EEPROM.
 606 */
 607#define MAX_TLV_VALUE_LEN   256
 608static bool tlvinfo_add_tlv(u8 *eeprom, int tcode, char *strval)
 609{
 610        struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
 611        struct tlvinfo_tlv *eeprom_tlv;
 612        int new_tlv_len = 0;
 613        u32 value;
 614        char data[MAX_TLV_VALUE_LEN];
 615        int eeprom_index;
 616
 617        // Encode each TLV type into the format to be stored in the EERPOM
 618        switch (tcode) {
 619        case TLV_CODE_PRODUCT_NAME:
 620        case TLV_CODE_PART_NUMBER:
 621        case TLV_CODE_SERIAL_NUMBER:
 622        case TLV_CODE_LABEL_REVISION:
 623        case TLV_CODE_PLATFORM_NAME:
 624        case TLV_CODE_ONIE_VERSION:
 625        case TLV_CODE_MANUF_NAME:
 626        case TLV_CODE_MANUF_COUNTRY:
 627        case TLV_CODE_VENDOR_NAME:
 628        case TLV_CODE_DIAG_VERSION:
 629        case TLV_CODE_SERVICE_TAG:
 630                strncpy(data, strval, MAX_TLV_VALUE_LEN);
 631                new_tlv_len = min_t(size_t, MAX_TLV_VALUE_LEN, strlen(strval));
 632                break;
 633        case TLV_CODE_DEVICE_VERSION:
 634                value = simple_strtoul(strval, NULL, 0);
 635                if (value >= 256) {
 636                        printf("ERROR: Device version must be 255 or less. Value supplied: %u",
 637                               value);
 638                        return false;
 639                }
 640                data[0] = value & 0xFF;
 641                new_tlv_len = 1;
 642                break;
 643        case TLV_CODE_MAC_SIZE:
 644                value = simple_strtoul(strval, NULL, 0);
 645                if (value >= 65536) {
 646                        printf("ERROR: MAC Size must be 65535 or less. Value supplied: %u",
 647                               value);
 648                        return false;
 649                }
 650                data[0] = (value >> 8) & 0xFF;
 651                data[1] = value & 0xFF;
 652                new_tlv_len = 2;
 653                break;
 654        case TLV_CODE_MANUF_DATE:
 655                if (set_date(data, strval) != 0)
 656                        return false;
 657                new_tlv_len = 19;
 658                break;
 659        case TLV_CODE_MAC_BASE:
 660                if (set_mac(data, strval) != 0)
 661                        return false;
 662                new_tlv_len = 6;
 663                break;
 664        case TLV_CODE_CRC_32:
 665                printf("WARNING: The CRC TLV is set automatically and cannot be set manually.\n");
 666                return false;
 667        case TLV_CODE_VENDOR_EXT:
 668        default:
 669                if (set_bytes(data, strval, &new_tlv_len) != 0)
 670                        return false;
 671                break;
 672        }
 673
 674        // Is there room for this TLV?
 675        if ((be16_to_cpu(eeprom_hdr->totallen) + ENT_SIZE + new_tlv_len) >
 676                        TLV_TOTAL_LEN_MAX) {
 677                printf("ERROR: There is not enough room in the EERPOM to save data.\n");
 678                return false;
 679        }
 680
 681        // Add TLV at the end, overwriting CRC TLV if it exists
 682        if (tlvinfo_find_tlv(eeprom, TLV_CODE_CRC_32, &eeprom_index))
 683                eeprom_hdr->totallen =
 684                        cpu_to_be16(be16_to_cpu(eeprom_hdr->totallen) -
 685                                        ENT_SIZE - 4);
 686        else
 687                eeprom_index = HDR_SIZE + be16_to_cpu(eeprom_hdr->totallen);
 688        eeprom_tlv = to_entry(&eeprom[eeprom_index]);
 689        eeprom_tlv->type = tcode;
 690        eeprom_tlv->length = new_tlv_len;
 691        memcpy(eeprom_tlv->value, data, new_tlv_len);
 692
 693        // Update the total length and calculate (add) a new CRC-32 TLV
 694        eeprom_hdr->totallen = cpu_to_be16(be16_to_cpu(eeprom_hdr->totallen) +
 695                        ENT_SIZE + new_tlv_len);
 696        update_crc(eeprom);
 697
 698        return true;
 699}
 700
 701/**
 702 *  set_mac
 703 *
 704 *  Converts a string MAC address into a binary buffer.
 705 *
 706 *  This function takes a pointer to a MAC address string
 707 *  (i.e."XX:XX:XX:XX:XX:XX", where "XX" is a two-digit hex number).
 708 *  The string format is verified and then converted to binary and
 709 *  stored in a buffer.
 710 */
 711static int set_mac(char *buf, const char *string)
 712{
 713        char *p = (char *)string;
 714        int   i;
 715        int   err = 0;
 716        char *end;
 717
 718        if (!p) {
 719                printf("ERROR: NULL mac addr string passed in.\n");
 720                return -1;
 721        }
 722
 723        if (strlen(p) != 17) {
 724                printf("ERROR: MAC address strlen() != 17 -- %zu\n", strlen(p));
 725                printf("ERROR: Bad MAC address format: %s\n", string);
 726                return -1;
 727        }
 728
 729        for (i = 0; i < 17; i++) {
 730                if ((i % 3) == 2) {
 731                        if (p[i] != ':') {
 732                                err++;
 733                                printf("ERROR: mac: p[%i] != :, found: `%c'\n",
 734                                       i, p[i]);
 735                                break;
 736                        }
 737                        continue;
 738                } else if (!is_hex(p[i])) {
 739                        err++;
 740                        printf("ERROR: mac: p[%i] != hex digit, found: `%c'\n",
 741                               i, p[i]);
 742                        break;
 743                }
 744        }
 745
 746        if (err != 0) {
 747                printf("ERROR: Bad MAC address format: %s\n", string);
 748                return -1;
 749        }
 750
 751        /* Convert string to binary */
 752        for (i = 0, p = (char *)string; i < 6; i++) {
 753                buf[i] = p ? simple_strtoul(p, &end, 16) : 0;
 754                if (p)
 755                        p = (*end) ? end + 1 : end;
 756        }
 757
 758        if (!is_valid_ethaddr((u8 *)buf)) {
 759                printf("ERROR: MAC address must not be 00:00:00:00:00:00, a multicast address or FF:FF:FF:FF:FF:FF.\n");
 760                printf("ERROR: Bad MAC address format: %s\n", string);
 761                return -1;
 762        }
 763
 764        return 0;
 765}
 766
 767/**
 768 *  set_date
 769 *
 770 *  Validates the format of the data string
 771 *
 772 *  This function takes a pointer to a date string (i.e. MM/DD/YYYY hh:mm:ss)
 773 *  and validates that the format is correct. If so the string is copied
 774 *  to the supplied buffer.
 775 */
 776static int set_date(char *buf, const char *string)
 777{
 778        int i;
 779
 780        if (!string) {
 781                printf("ERROR: NULL date string passed in.\n");
 782                return -1;
 783        }
 784
 785        if (strlen(string) != 19) {
 786                printf("ERROR: Date strlen() != 19 -- %zu\n", strlen(string));
 787                printf("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
 788                       string);
 789                return -1;
 790        }
 791
 792        for (i = 0; string[i] != 0; i++) {
 793                switch (i) {
 794                case 2:
 795                case 5:
 796                        if (string[i] != '/') {
 797                                printf("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
 798                                       string);
 799                                return -1;
 800                        }
 801                        break;
 802                case 10:
 803                        if (string[i] != ' ') {
 804                                printf("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
 805                                       string);
 806                                return -1;
 807                        }
 808                        break;
 809                case 13:
 810                case 16:
 811                        if (string[i] != ':') {
 812                                printf("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
 813                                       string);
 814                                return -1;
 815                        }
 816                        break;
 817                default:
 818                        if (!is_digit(string[i])) {
 819                                printf("ERROR: Bad date format (MM/DD/YYYY hh:mm:ss): %s\n",
 820                                       string);
 821                                return -1;
 822                        }
 823                        break;
 824                }
 825        }
 826
 827        strcpy(buf, string);
 828        return 0;
 829}
 830
 831/**
 832 *  set_bytes
 833 *
 834 *  Converts a space-separated string of decimal numbers into a
 835 *  buffer of bytes.
 836 *
 837 *  This function takes a pointer to a space-separated string of decimal
 838 *  numbers (i.e. "128 0x55 0321") with "C" standard radix specifiers
 839 *  and converts them to an array of bytes.
 840 */
 841static int set_bytes(char *buf, const char *string, int *converted_accum)
 842{
 843        char *p = (char *)string;
 844        int   i;
 845        uint  byte;
 846
 847        if (!p) {
 848                printf("ERROR: NULL string passed in.\n");
 849                return -1;
 850        }
 851
 852        /* Convert string to bytes */
 853        for (i = 0, p = (char *)string; (i < TLV_VALUE_MAX_LEN) && (*p != 0);
 854                        i++) {
 855                while ((*p == ' ') || (*p == '\t') || (*p == ',') ||
 856                       (*p == ';')) {
 857                        p++;
 858                }
 859                if (*p != 0) {
 860                        if (!is_digit(*p)) {
 861                                printf("ERROR: Non-digit found in byte string: (%s)\n",
 862                                       string);
 863                                return -1;
 864                        }
 865                        byte = simple_strtoul(p, &p, 0);
 866                        if (byte >= 256) {
 867                                printf("ERROR: The value specified is greater than 255: (%u) in string: %s\n",
 868                                       byte, string);
 869                                return -1;
 870                        }
 871                        buf[i] = byte & 0xFF;
 872                }
 873        }
 874
 875        if (i == TLV_VALUE_MAX_LEN && (*p != 0)) {
 876                printf("ERROR: Trying to assign too many bytes (max: %d) in string: %s\n",
 877                       TLV_VALUE_MAX_LEN, string);
 878                return -1;
 879        }
 880
 881        *converted_accum = i;
 882        return 0;
 883}
 884
 885static void show_tlv_devices(void)
 886{
 887        unsigned int dev;
 888
 889        for (dev = 0; dev < MAX_TLV_DEVICES; dev++)
 890                if (tlv_devices[dev])
 891                        printf("TLV: %u%s\n", dev,
 892                               (dev == current_dev) ? " (*)" : "");
 893}
 894
 895static int find_tlv_devices(struct udevice **tlv_devices_p)
 896{
 897        int ret;
 898        int count_dev = 0;
 899        struct udevice *dev;
 900
 901        for (ret = uclass_first_device_check(UCLASS_I2C_EEPROM, &dev);
 902                        dev;
 903                        ret = uclass_next_device_check(&dev)) {
 904                if (ret == 0)
 905                        tlv_devices_p[count_dev++] = dev;
 906                if (count_dev >= MAX_TLV_DEVICES)
 907                        break;
 908        }
 909
 910        return (count_dev == 0) ? -ENODEV : 0;
 911}
 912
 913static struct udevice *find_tlv_device_by_index(int dev_num)
 914{
 915        struct udevice *local_tlv_devices[MAX_TLV_DEVICES] = {};
 916        struct udevice **tlv_devices_p;
 917        int ret;
 918
 919        if (gd->flags & (GD_FLG_RELOC | GD_FLG_SPL_INIT)) {
 920                /* Assume BSS is initialized; use static data */
 921                if (tlv_devices[dev_num])
 922                        return tlv_devices[dev_num];
 923                tlv_devices_p = tlv_devices;
 924        } else {
 925                tlv_devices_p = local_tlv_devices;
 926        }
 927
 928        ret = find_tlv_devices(tlv_devices_p);
 929        if (ret == 0 && tlv_devices_p[dev_num])
 930                return tlv_devices_p[dev_num];
 931
 932        return NULL;
 933}
 934
 935/**
 936 * read_tlv_eeprom - read the hwinfo from i2c EEPROM
 937 */
 938int read_tlv_eeprom(void *eeprom, int offset, int len, int dev_num)
 939{
 940        struct udevice *dev;
 941
 942        if (dev_num >= MAX_TLV_DEVICES)
 943                return -EINVAL;
 944
 945        dev = find_tlv_device_by_index(dev_num);
 946        if (!dev)
 947                return -ENODEV;
 948
 949        return i2c_eeprom_read(dev, offset, eeprom, len);
 950}
 951
 952/**
 953 * write_tlv_eeprom - write the hwinfo to i2c EEPROM
 954 */
 955int write_tlv_eeprom(void *eeprom, int len)
 956{
 957        if (!(gd->flags & GD_FLG_RELOC))
 958                return -ENODEV;
 959        if (!tlv_devices[current_dev])
 960                return -ENODEV;
 961
 962        return i2c_eeprom_write(tlv_devices[current_dev], 0, eeprom, len);
 963}
 964
 965int read_tlvinfo_tlv_eeprom(void *eeprom, struct tlvinfo_header **hdr,
 966                            struct tlvinfo_tlv **first_entry, int dev_num)
 967{
 968        int ret;
 969        struct tlvinfo_header *tlv_hdr;
 970        struct tlvinfo_tlv *tlv_ent;
 971
 972        /* Read TLV header */
 973        ret = read_tlv_eeprom(eeprom, 0, HDR_SIZE, dev_num);
 974        if (ret < 0)
 975                return ret;
 976
 977        tlv_hdr = eeprom;
 978        if (!is_valid_tlvinfo_header(tlv_hdr))
 979                return -EINVAL;
 980
 981        /* Read TLV entries */
 982        tlv_ent = to_entry(&tlv_hdr[1]);
 983        ret = read_tlv_eeprom(tlv_ent, HDR_SIZE,
 984                              be16_to_cpu(tlv_hdr->totallen), dev_num);
 985        if (ret < 0)
 986                return ret;
 987        if (!is_checksum_valid(eeprom))
 988                return -EINVAL;
 989
 990        *hdr = tlv_hdr;
 991        *first_entry = tlv_ent;
 992
 993        return 0;
 994}
 995
 996/**
 997 *  mac_read_from_eeprom
 998 *
 999 *  Read the MAC addresses from EEPROM
1000 *
1001 *  This function reads the MAC addresses from EEPROM and sets the
1002 *  appropriate environment variables for each one read.
1003 *
1004 *  The environment variables are only set if they haven't been set already.
1005 *  This ensures that any user-saved variables are never overwritten.
1006 *
1007 *  This function must be called after relocation.
1008 */
1009int mac_read_from_eeprom(void)
1010{
1011        unsigned int i;
1012        int eeprom_index;
1013        struct tlvinfo_tlv *eeprom_tlv;
1014        int maccount;
1015        u8 macbase[6];
1016        struct tlvinfo_header *eeprom_hdr = to_header(eeprom);
1017
1018        puts("EEPROM: ");
1019
1020        if (read_eeprom(eeprom)) {
1021                printf("Read failed.\n");
1022                return -1;
1023        }
1024
1025        maccount = 1;
1026        if (tlvinfo_find_tlv(eeprom, TLV_CODE_MAC_SIZE, &eeprom_index)) {
1027                eeprom_tlv = to_entry(&eeprom[eeprom_index]);
1028                maccount = (eeprom_tlv->value[0] << 8) | eeprom_tlv->value[1];
1029        }
1030
1031        memcpy(macbase, "\0\0\0\0\0\0", 6);
1032        if (tlvinfo_find_tlv(eeprom, TLV_CODE_MAC_BASE, &eeprom_index)) {
1033                eeprom_tlv = to_entry(&eeprom[eeprom_index]);
1034                memcpy(macbase, eeprom_tlv->value, 6);
1035        }
1036
1037        for (i = 0; i < maccount; i++) {
1038                if (is_valid_ethaddr(macbase)) {
1039                        char ethaddr[18];
1040                        char enetvar[11];
1041
1042                        sprintf(ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
1043                                macbase[0], macbase[1], macbase[2],
1044                                macbase[3], macbase[4], macbase[5]);
1045                        sprintf(enetvar, i ? "eth%daddr" : "ethaddr", i);
1046                        /* Only initialize environment variables that are blank
1047                         * (i.e. have not yet been set)
1048                         */
1049                        if (!env_get(enetvar))
1050                                env_set(enetvar, ethaddr);
1051
1052                        macbase[5]++;
1053                        if (macbase[5] == 0) {
1054                                macbase[4]++;
1055                                if (macbase[4] == 0) {
1056                                        macbase[3]++;
1057                                        if (macbase[3] == 0) {
1058                                                macbase[0] = 0;
1059                                                macbase[1] = 0;
1060                                                macbase[2] = 0;
1061                                        }
1062                                }
1063                        }
1064                }
1065        }
1066
1067        printf("%s v%u len=%u\n", eeprom_hdr->signature, eeprom_hdr->version,
1068               be16_to_cpu(eeprom_hdr->totallen));
1069
1070        return 0;
1071}
1072
1073/**
1074 *  populate_serial_number - read the serial number from EEPROM
1075 *
1076 *  This function reads the serial number from the EEPROM and sets the
1077 *  appropriate environment variable.
1078 *
1079 *  The environment variable is only set if it has not been set
1080 *  already.  This ensures that any user-saved variables are never
1081 *  overwritten.
1082 *
1083 *  This function must be called after relocation.
1084 */
1085int populate_serial_number(void)
1086{
1087        char serialstr[257];
1088        int eeprom_index;
1089        struct tlvinfo_tlv *eeprom_tlv;
1090
1091        if (env_get("serial#"))
1092                return 0;
1093
1094        if (read_eeprom(eeprom)) {
1095                printf("Read failed.\n");
1096                return -1;
1097        }
1098
1099        if (tlvinfo_find_tlv(eeprom, TLV_CODE_SERIAL_NUMBER, &eeprom_index)) {
1100                eeprom_tlv = to_entry(&eeprom[eeprom_index]);
1101                memcpy(serialstr, eeprom_tlv->value, eeprom_tlv->length);
1102                serialstr[eeprom_tlv->length] = 0;
1103                env_set("serial#", serialstr);
1104        }
1105
1106        return 0;
1107}
1108