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