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