2 * Copyright (c) 2012-2015 Solarflare Communications Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * The views and conclusions contained in the software and documentation are
27 * those of the authors and should not be interpreted as representing official
28 * policies, either expressed or implied, of the FreeBSD Project.
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
37 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
39 #if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
41 #include "ef10_tlv_layout.h"
43 /* Cursor for TLV partition format */
44 typedef struct tlv_cursor_s {
45 uint32_t *block; /* Base of data block */
46 uint32_t *current; /* Cursor position */
47 uint32_t *end; /* End tag position */
48 uint32_t *limit; /* Last dword of data block */
51 typedef struct nvram_partition_s {
56 * The full length of the NVRAM partition.
57 * This is different from tlv_partition_header.total_length,
58 * which can be smaller.
63 tlv_cursor_t tlv_cursor;
67 static __checkReturn efx_rc_t
69 __inout tlv_cursor_t *cursor);
74 __out uint32_t *block)
76 *block = __CPU_TO_LE_32(TLV_TAG_END);
81 __in tlv_cursor_t *cursor)
85 dword = cursor->current[0];
86 tag = __LE_TO_CPU_32(dword);
93 __in tlv_cursor_t *cursor)
95 uint32_t dword, length;
97 if (tlv_tag(cursor) == TLV_TAG_END)
100 dword = cursor->current[1];
101 length = __LE_TO_CPU_32(dword);
103 return ((size_t)length);
108 __in tlv_cursor_t *cursor)
110 if (tlv_tag(cursor) == TLV_TAG_END)
113 return ((uint8_t *)(&cursor->current[2]));
118 __in tlv_cursor_t *cursor)
120 if (tlv_tag(cursor) == TLV_TAG_END)
123 return ((uint8_t *)cursor->current);
127 * TLV item DWORD length is tag + length + value (rounded up to DWORD)
128 * equivalent to tlv_n_words_for_len in mc-comms tlv.c
130 #define TLV_DWORD_COUNT(length) \
131 (1 + 1 + (((length) + sizeof (uint32_t) - 1) / sizeof (uint32_t)))
136 __in tlv_cursor_t *cursor)
140 length = tlv_length(cursor);
142 return (cursor->current + TLV_DWORD_COUNT(length));
145 static __checkReturn efx_rc_t
147 __inout tlv_cursor_t *cursor)
151 if ((rc = tlv_validate_state(cursor)) != 0)
154 if (cursor->current == cursor->end) {
155 /* No more tags after END tag */
156 cursor->current = NULL;
161 /* Advance to next item and validate */
162 cursor->current = tlv_next_item_ptr(cursor);
164 if ((rc = tlv_validate_state(cursor)) != 0)
174 EFSYS_PROBE1(fail1, efx_rc_t, rc);
181 __in tlv_cursor_t *cursor)
185 cursor->current = cursor->block;
187 if ((rc = tlv_validate_state(cursor)) != 0)
193 EFSYS_PROBE1(fail1, efx_rc_t, rc);
200 __inout tlv_cursor_t *cursor,
205 rc = tlv_rewind(cursor);
207 if (tlv_tag(cursor) == tag)
210 rc = tlv_advance(cursor);
215 static __checkReturn efx_rc_t
217 __inout tlv_cursor_t *cursor)
221 /* Check cursor position */
222 if (cursor->current < cursor->block) {
226 if (cursor->current > cursor->limit) {
231 if (tlv_tag(cursor) != TLV_TAG_END) {
232 /* Check current item has space for tag and length */
233 if (cursor->current > (cursor->limit - 2)) {
234 cursor->current = NULL;
239 /* Check we have value data for current item and another tag */
240 if (tlv_next_item_ptr(cursor) > (cursor->limit - 1)) {
241 cursor->current = NULL;
256 EFSYS_PROBE1(fail1, efx_rc_t, rc);
263 __out tlv_cursor_t *cursor,
264 __in uint32_t *block,
265 __in uint32_t *limit,
266 __in uint32_t *current)
268 cursor->block = block;
269 cursor->limit = limit;
271 cursor->current = current;
274 return (tlv_validate_state(cursor));
277 static __checkReturn efx_rc_t
278 tlv_init_cursor_from_size(
279 __out tlv_cursor_t *cursor,
285 limit = (uint32_t *)(block + size - sizeof (uint32_t));
286 return (tlv_init_cursor(cursor, (uint32_t *)block,
287 limit, (uint32_t *)block));
290 static __checkReturn efx_rc_t
291 tlv_init_cursor_at_offset(
292 __out tlv_cursor_t *cursor,
300 limit = (uint32_t *)(block + size - sizeof (uint32_t));
301 current = (uint32_t *)(block + offset);
302 return (tlv_init_cursor(cursor, (uint32_t *)block, limit, current));
305 static __checkReturn efx_rc_t
307 __inout tlv_cursor_t *cursor)
312 if (cursor->end == NULL) {
313 pos = cursor->current;
314 if ((rc = tlv_find(cursor, TLV_TAG_END)) != 0)
317 cursor->end = cursor->current;
318 cursor->current = pos;
324 EFSYS_PROBE1(fail1, efx_rc_t, rc);
330 tlv_block_length_used(
331 __inout tlv_cursor_t *cursor)
335 if ((rc = tlv_validate_state(cursor)) != 0)
338 if ((rc = tlv_require_end(cursor)) != 0)
341 /* Return space used (including the END tag) */
342 return (cursor->end + 1 - cursor->block) * sizeof (uint32_t);
347 EFSYS_PROBE1(fail1, efx_rc_t, rc);
353 tlv_last_segment_end(
354 __in tlv_cursor_t *cursor)
356 tlv_cursor_t segment_cursor;
357 uint32_t *last_segment_end = cursor->block;
358 uint32_t *segment_start = cursor->block;
361 * Go through each segment and check that it has an end tag. If there
362 * is no end tag then the previous segment was the last valid one,
363 * so return the pointer to its end tag.
366 if (tlv_init_cursor(&segment_cursor, segment_start,
367 cursor->limit, segment_start) != 0)
369 if (tlv_require_end(&segment_cursor) != 0)
371 last_segment_end = segment_cursor.end;
372 segment_start = segment_cursor.end + 1;
375 return (last_segment_end);
381 __in tlv_cursor_t *cursor,
383 __in_bcount(size) uint8_t *data,
389 ptr = cursor->current;
391 *ptr++ = __CPU_TO_LE_32(tag);
392 *ptr++ = __CPU_TO_LE_32(len);
395 ptr[(len - 1) / sizeof (uint32_t)] = 0;
396 memcpy(ptr, data, len);
397 ptr += P2ROUNDUP(len, sizeof (uint32_t)) / sizeof (*ptr);
403 static __checkReturn efx_rc_t
405 __inout tlv_cursor_t *cursor,
412 uint32_t *last_segment_end;
415 if ((rc = tlv_validate_state(cursor)) != 0)
418 if ((rc = tlv_require_end(cursor)) != 0)
421 if (tag == TLV_TAG_END) {
426 last_segment_end = tlv_last_segment_end(cursor);
428 delta = TLV_DWORD_COUNT(size);
429 if (last_segment_end + 1 + delta > cursor->limit) {
434 /* Move data up: new space at cursor->current */
435 memmove(cursor->current + delta, cursor->current,
436 (last_segment_end + 1 - cursor->current) * sizeof (uint32_t));
438 /* Adjust the end pointer */
439 cursor->end += delta;
441 /* Write new TLV item */
442 tlv_write(cursor, tag, data, size);
453 EFSYS_PROBE1(fail1, efx_rc_t, rc);
458 static __checkReturn efx_rc_t
460 __inout tlv_cursor_t *cursor)
463 uint32_t *last_segment_end;
466 if ((rc = tlv_validate_state(cursor)) != 0)
469 if (tlv_tag(cursor) == TLV_TAG_END) {
474 delta = TLV_DWORD_COUNT(tlv_length(cursor));
476 if ((rc = tlv_require_end(cursor)) != 0)
479 last_segment_end = tlv_last_segment_end(cursor);
481 /* Shuffle things down, destroying the item at cursor->current */
482 memmove(cursor->current, cursor->current + delta,
483 (last_segment_end + 1 - cursor->current) * sizeof (uint32_t));
484 /* Zero the new space at the end of the TLV chain */
485 memset(last_segment_end + 1 - delta, 0, delta * sizeof (uint32_t));
486 /* Adjust the end pointer */
487 cursor->end -= delta;
496 EFSYS_PROBE1(fail1, efx_rc_t, rc);
501 static __checkReturn efx_rc_t
503 __inout tlv_cursor_t *cursor,
510 unsigned int old_ndwords;
511 unsigned int new_ndwords;
513 uint32_t *last_segment_end;
516 if ((rc = tlv_validate_state(cursor)) != 0)
519 if (tlv_tag(cursor) == TLV_TAG_END) {
523 if (tlv_tag(cursor) != tag) {
528 old_ndwords = TLV_DWORD_COUNT(tlv_length(cursor));
529 new_ndwords = TLV_DWORD_COUNT(size);
531 if ((rc = tlv_require_end(cursor)) != 0)
534 last_segment_end = tlv_last_segment_end(cursor);
536 if (new_ndwords > old_ndwords) {
537 /* Expand space used for TLV item */
538 delta = new_ndwords - old_ndwords;
539 pos = cursor->current + old_ndwords;
541 if (last_segment_end + 1 + delta > cursor->limit) {
546 /* Move up: new space at (cursor->current + old_ndwords) */
547 memmove(pos + delta, pos,
548 (last_segment_end + 1 - pos) * sizeof (uint32_t));
550 /* Adjust the end pointer */
551 cursor->end += delta;
553 } else if (new_ndwords < old_ndwords) {
554 /* Shrink space used for TLV item */
555 delta = old_ndwords - new_ndwords;
556 pos = cursor->current + new_ndwords;
558 /* Move down: remove words at (cursor->current + new_ndwords) */
559 memmove(pos, pos + delta,
560 (last_segment_end + 1 - pos) * sizeof (uint32_t));
562 /* Zero the new space at the end of the TLV chain */
563 memset(last_segment_end + 1 - delta, 0,
564 delta * sizeof (uint32_t));
566 /* Adjust the end pointer */
567 cursor->end -= delta;
571 tlv_write(cursor, tag, data, size);
584 EFSYS_PROBE1(fail1, efx_rc_t, rc);
589 static uint32_t checksum_tlv_partition(
590 __in nvram_partition_t *partition)
592 tlv_cursor_t *cursor;
598 cursor = &partition->tlv_cursor;
599 len = tlv_block_length_used(cursor);
600 EFSYS_ASSERT3U((len & 3), ==, 0);
603 ptr = partition->data;
604 end = &ptr[len >> 2];
607 csum += __LE_TO_CPU_32(*ptr++);
612 static __checkReturn efx_rc_t
613 tlv_update_partition_len_and_cks(
614 __in tlv_cursor_t *cursor)
617 nvram_partition_t partition;
618 struct tlv_partition_header *header;
619 struct tlv_partition_trailer *trailer;
623 * We just modified the partition, so the total length may not be
624 * valid. Don't use tlv_find(), which performs some sanity checks
625 * that may fail here.
627 partition.data = cursor->block;
628 memcpy(&partition.tlv_cursor, cursor, sizeof (*cursor));
629 header = (struct tlv_partition_header *)partition.data;
631 if (__LE_TO_CPU_32(header->tag) != TLV_TAG_PARTITION_HEADER) {
635 new_len = tlv_block_length_used(&partition.tlv_cursor);
640 header->total_length = __CPU_TO_LE_32(new_len);
641 /* Ensure the modified partition always has a new generation count. */
642 header->generation = __CPU_TO_LE_32(
643 __LE_TO_CPU_32(header->generation) + 1);
645 trailer = (struct tlv_partition_trailer *)((uint8_t *)header +
646 new_len - sizeof (*trailer) - sizeof (uint32_t));
647 trailer->generation = header->generation;
648 trailer->checksum = __CPU_TO_LE_32(
649 __LE_TO_CPU_32(trailer->checksum) -
650 checksum_tlv_partition(&partition));
657 EFSYS_PROBE1(fail1, efx_rc_t, rc);
662 /* Validate buffer contents (before writing to flash) */
663 __checkReturn efx_rc_t
664 ef10_nvram_buffer_validate(
667 __in_bcount(partn_size) caddr_t partn_data,
668 __in size_t partn_size)
671 struct tlv_partition_header *header;
672 struct tlv_partition_trailer *trailer;
678 EFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK);
680 if ((partn_data == NULL) || (partn_size == 0)) {
685 /* The partition header must be the first item (at offset zero) */
686 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)partn_data,
691 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
695 header = (struct tlv_partition_header *)tlv_item(&cursor);
697 /* Check TLV partition length (includes the END tag) */
698 total_length = __LE_TO_CPU_32(header->total_length);
699 if (total_length > partn_size) {
704 /* Check partition ends with PARTITION_TRAILER and END tags */
705 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {
709 trailer = (struct tlv_partition_trailer *)tlv_item(&cursor);
711 if ((rc = tlv_advance(&cursor)) != 0) {
715 if (tlv_tag(&cursor) != TLV_TAG_END) {
720 /* Check generation counts are consistent */
721 if (trailer->generation != header->generation) {
726 /* Verify partition checksum */
728 for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) {
729 cksum += *((uint32_t *)(partn_data + pos));
755 EFSYS_PROBE1(fail1, efx_rc_t, rc);
762 __checkReturn efx_rc_t
763 ef10_nvram_buffer_create(
765 __in uint16_t partn_type,
766 __in_bcount(partn_size) caddr_t partn_data,
767 __in size_t partn_size)
769 uint32_t *buf = (uint32_t *)partn_data;
772 struct tlv_partition_header header;
773 struct tlv_partition_trailer trailer;
775 unsigned min_buf_size = sizeof (struct tlv_partition_header) +
776 sizeof (struct tlv_partition_trailer);
777 if (partn_size < min_buf_size) {
782 memset(buf, 0xff, partn_size);
785 if ((rc = tlv_init_cursor(&cursor, buf,
786 (uint32_t *)((uint8_t *)buf + partn_size),
791 header.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_HEADER);
792 header.length = __CPU_TO_LE_32(sizeof (header) - 8);
793 header.type_id = __CPU_TO_LE_16(partn_type);
795 header.generation = __CPU_TO_LE_32(1);
796 header.total_length = 0; /* This will be fixed below. */
797 if ((rc = tlv_insert(
798 &cursor, TLV_TAG_PARTITION_HEADER,
799 (uint8_t *)&header.type_id, sizeof (header) - 8)) != 0)
801 if ((rc = tlv_advance(&cursor)) != 0)
804 trailer.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_TRAILER);
805 trailer.length = __CPU_TO_LE_32(sizeof (trailer) - 8);
806 trailer.generation = header.generation;
807 trailer.checksum = 0; /* This will be fixed below. */
808 if ((rc = tlv_insert(&cursor, TLV_TAG_PARTITION_TRAILER,
809 (uint8_t *)&trailer.generation, sizeof (trailer) - 8)) != 0)
812 if ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0)
815 /* Check that the partition is valid. */
816 if ((rc = ef10_nvram_buffer_validate(enp, partn_type,
817 partn_data, partn_size)) != 0)
835 EFSYS_PROBE1(fail1, efx_rc_t, rc);
842 __in uint32_t *position,
845 return (uint32_t)((uint8_t *)position - (uint8_t *)base);
848 __checkReturn efx_rc_t
849 ef10_nvram_buffer_find_item_start(
850 __in_bcount(buffer_size)
852 __in size_t buffer_size,
853 __out uint32_t *startp)
855 // Read past partition header to find start address of the first key
859 /* A PARTITION_HEADER tag must be the first item (at offset zero) */
860 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp,
861 buffer_size)) != 0) {
865 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
870 if ((rc = tlv_advance(&cursor)) != 0) {
874 *startp = byte_offset(cursor.current, cursor.block);
876 if ((rc = tlv_require_end(&cursor)) != 0)
888 EFSYS_PROBE1(fail1, efx_rc_t, rc);
893 __checkReturn efx_rc_t
894 ef10_nvram_buffer_find_end(
895 __in_bcount(buffer_size)
897 __in size_t buffer_size,
898 __in uint32_t offset,
899 __out uint32_t *endp)
901 // Read to end of partition
905 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp,
906 buffer_size)) != 0) {
911 if ((rc = tlv_require_end(&cursor)) != 0)
914 *endp = byte_offset(tlv_last_segment_end(&cursor)+1, cursor.block);
921 EFSYS_PROBE1(fail1, efx_rc_t, rc);
926 __checkReturn __success(return != B_FALSE) boolean_t
927 ef10_nvram_buffer_find_item(
928 __in_bcount(buffer_size)
930 __in size_t buffer_size,
931 __in uint32_t offset,
932 __out uint32_t *startp,
933 __out uint32_t *lengthp)
935 // Find TLV at offset and return key start and length
940 if (tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,
941 buffer_size, offset) != 0) {
945 while ((key = tlv_item(&cursor)) != NULL) {
946 tag = tlv_tag(&cursor);
947 if (tag == TLV_TAG_PARTITION_HEADER ||
948 tag == TLV_TAG_PARTITION_TRAILER) {
949 if (tlv_advance(&cursor) != 0) {
954 *startp = byte_offset(cursor.current, cursor.block);
955 *lengthp = byte_offset(tlv_next_item_ptr(&cursor),
963 __checkReturn efx_rc_t
964 ef10_nvram_buffer_get_item(
965 __in_bcount(buffer_size)
967 __in size_t buffer_size,
968 __in uint32_t offset,
969 __in uint32_t length,
970 __out_bcount_part(item_max_size, *lengthp)
972 __in size_t item_max_size,
973 __out uint32_t *lengthp)
977 uint32_t item_length;
979 if (item_max_size < length) {
984 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,
985 buffer_size, offset)) != 0) {
989 item_length = tlv_length(&cursor);
990 if (length < item_length) {
994 memcpy(itemp, tlv_value(&cursor), item_length);
996 *lengthp = item_length;
1005 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1010 __checkReturn efx_rc_t
1011 ef10_nvram_buffer_insert_item(
1012 __in_bcount(buffer_size)
1014 __in size_t buffer_size,
1015 __in uint32_t offset,
1016 __in_bcount(length) caddr_t keyp,
1017 __in uint32_t length,
1018 __out uint32_t *lengthp)
1021 tlv_cursor_t cursor;
1023 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,
1024 buffer_size, offset)) != 0) {
1028 rc = tlv_insert(&cursor, TLV_TAG_LICENSE, keyp, length);
1034 *lengthp = byte_offset(tlv_next_item_ptr(&cursor),
1042 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1047 __checkReturn efx_rc_t
1048 ef10_nvram_buffer_delete_item(
1049 __in_bcount(buffer_size)
1051 __in size_t buffer_size,
1052 __in uint32_t offset,
1053 __in uint32_t length,
1057 tlv_cursor_t cursor;
1059 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,
1060 buffer_size, offset)) != 0) {
1064 if ((rc = tlv_delete(&cursor)) != 0)
1072 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1077 __checkReturn efx_rc_t
1078 ef10_nvram_buffer_finish(
1079 __in_bcount(buffer_size)
1081 __in size_t buffer_size)
1084 tlv_cursor_t cursor;
1086 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp,
1087 buffer_size)) != 0) {
1092 if ((rc = tlv_require_end(&cursor)) != 0)
1095 if ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0)
1105 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1113 * Read and validate a segment from a partition. A segment is a complete
1114 * tlv chain between PARTITION_HEADER and PARTITION_END tags. There may
1115 * be multiple segments in a partition, so seg_offset allows segments
1116 * beyond the first to be read.
1118 static __checkReturn efx_rc_t
1119 ef10_nvram_read_tlv_segment(
1120 __in efx_nic_t *enp,
1121 __in uint32_t partn,
1122 __in size_t seg_offset,
1123 __in_bcount(max_seg_size) caddr_t seg_data,
1124 __in size_t max_seg_size)
1126 tlv_cursor_t cursor;
1127 struct tlv_partition_header *header;
1128 struct tlv_partition_trailer *trailer;
1129 size_t total_length;
1134 EFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK);
1136 if ((seg_data == NULL) || (max_seg_size == 0)) {
1141 /* Read initial chunk of the segment, starting at offset */
1142 if ((rc = ef10_nvram_partn_read_mode(enp, partn, seg_offset, seg_data,
1144 MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0) {
1148 /* A PARTITION_HEADER tag must be the first item at the given offset */
1149 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data,
1150 max_seg_size)) != 0) {
1154 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
1158 header = (struct tlv_partition_header *)tlv_item(&cursor);
1160 /* Check TLV segment length (includes the END tag) */
1161 total_length = __LE_TO_CPU_32(header->total_length);
1162 if (total_length > max_seg_size) {
1167 /* Read the remaining segment content */
1168 if (total_length > EF10_NVRAM_CHUNK) {
1169 if ((rc = ef10_nvram_partn_read_mode(enp, partn,
1170 seg_offset + EF10_NVRAM_CHUNK,
1171 seg_data + EF10_NVRAM_CHUNK,
1172 total_length - EF10_NVRAM_CHUNK,
1173 MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0)
1177 /* Check segment ends with PARTITION_TRAILER and END tags */
1178 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {
1182 trailer = (struct tlv_partition_trailer *)tlv_item(&cursor);
1184 if ((rc = tlv_advance(&cursor)) != 0) {
1188 if (tlv_tag(&cursor) != TLV_TAG_END) {
1193 /* Check data read from segment is consistent */
1194 if (trailer->generation != header->generation) {
1196 * The partition data may have been modified between successive
1197 * MCDI NVRAM_READ requests by the MC or another PCI function.
1199 * The caller must retry to obtain consistent partition data.
1205 /* Verify segment checksum */
1207 for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) {
1208 cksum += *((uint32_t *)(seg_data + pos));
1218 EFSYS_PROBE(fail11);
1220 EFSYS_PROBE(fail10);
1238 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1244 * Read a single TLV item from a host memory
1245 * buffer containing a TLV formatted segment.
1247 __checkReturn efx_rc_t
1248 ef10_nvram_buf_read_tlv(
1249 __in efx_nic_t *enp,
1250 __in_bcount(max_seg_size) caddr_t seg_data,
1251 __in size_t max_seg_size,
1253 __deref_out_bcount_opt(*sizep) caddr_t *datap,
1254 __out size_t *sizep)
1256 tlv_cursor_t cursor;
1262 if ((seg_data == NULL) || (max_seg_size == 0)) {
1267 /* Find requested TLV tag in segment data */
1268 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data,
1269 max_seg_size)) != 0) {
1273 if ((rc = tlv_find(&cursor, tag)) != 0) {
1277 value = (caddr_t)tlv_value(&cursor);
1278 length = tlv_length(&cursor);
1283 /* Copy out data from TLV item */
1284 EFSYS_KMEM_ALLOC(enp->en_esip, length, data);
1289 memcpy(data, value, length);
1304 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1309 /* Read a single TLV item from the first segment in a TLV formatted partition */
1310 __checkReturn efx_rc_t
1311 ef10_nvram_partn_read_tlv(
1312 __in efx_nic_t *enp,
1313 __in uint32_t partn,
1315 __deref_out_bcount_opt(*seg_sizep) caddr_t *seg_datap,
1316 __out size_t *seg_sizep)
1318 caddr_t seg_data = NULL;
1319 size_t partn_size = 0;
1325 /* Allocate sufficient memory for the entire partition */
1326 if ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0)
1329 if (partn_size == 0) {
1334 EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, seg_data);
1335 if (seg_data == NULL) {
1341 * Read the first segment in a TLV partition. Retry until consistent
1342 * segment contents are returned. Inconsistent data may be read if:
1343 * a) the segment contents are invalid
1344 * b) the MC has rebooted while we were reading the partition
1345 * c) the partition has been modified while we were reading it
1346 * Limit retry attempts to ensure forward progress.
1350 rc = ef10_nvram_read_tlv_segment(enp, partn, 0,
1351 seg_data, partn_size);
1352 } while ((rc == EAGAIN) && (--retry > 0));
1355 /* Failed to obtain consistent segment data */
1359 if ((rc = ef10_nvram_buf_read_tlv(enp, seg_data, partn_size,
1360 tag, &data, &length)) != 0)
1363 EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data);
1366 *seg_sizep = length;
1375 EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data);
1381 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1386 /* Compute the size of a segment. */
1387 static __checkReturn efx_rc_t
1388 ef10_nvram_buf_segment_size(
1389 __in caddr_t seg_data,
1390 __in size_t max_seg_size,
1391 __out size_t *seg_sizep)
1394 tlv_cursor_t cursor;
1395 struct tlv_partition_header *header;
1398 uint32_t *end_tag_position;
1399 uint32_t segment_length;
1401 /* A PARTITION_HEADER tag must be the first item at the given offset */
1402 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data,
1403 max_seg_size)) != 0) {
1407 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
1411 header = (struct tlv_partition_header *)tlv_item(&cursor);
1413 /* Check TLV segment length (includes the END tag) */
1414 *seg_sizep = __LE_TO_CPU_32(header->total_length);
1415 if (*seg_sizep > max_seg_size) {
1420 /* Check segment ends with PARTITION_TRAILER and END tags */
1421 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {
1426 if ((rc = tlv_advance(&cursor)) != 0) {
1430 if (tlv_tag(&cursor) != TLV_TAG_END) {
1434 end_tag_position = cursor.current;
1436 /* Verify segment checksum */
1438 for (pos = 0; (size_t)pos < *seg_sizep; pos += sizeof (uint32_t)) {
1439 cksum += *((uint32_t *)(seg_data + pos));
1447 * Calculate total length from HEADER to END tags and compare to
1448 * max_seg_size and the total_length field in the HEADER tag.
1450 segment_length = tlv_block_length_used(&cursor);
1452 if (segment_length > max_seg_size) {
1457 if (segment_length != *seg_sizep) {
1462 /* Skip over the first HEADER tag. */
1463 rc = tlv_rewind(&cursor);
1464 rc = tlv_advance(&cursor);
1467 if (tlv_tag(&cursor) == TLV_TAG_END) {
1468 /* Check that the END tag is the one found earlier. */
1469 if (cursor.current != end_tag_position)
1473 /* Check for duplicate HEADER tags before the END tag. */
1474 if (tlv_tag(&cursor) == TLV_TAG_PARTITION_HEADER) {
1479 rc = tlv_advance(&cursor);
1487 EFSYS_PROBE(fail12);
1489 EFSYS_PROBE(fail11);
1491 EFSYS_PROBE(fail10);
1509 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1515 * Add or update a single TLV item in a host memory buffer containing a TLV
1516 * formatted segment. Historically partitions consisted of only one segment.
1518 __checkReturn efx_rc_t
1519 ef10_nvram_buf_write_tlv(
1520 __inout_bcount(max_seg_size) caddr_t seg_data,
1521 __in size_t max_seg_size,
1523 __in_bcount(tag_size) caddr_t tag_data,
1524 __in size_t tag_size,
1525 __out size_t *total_lengthp)
1527 tlv_cursor_t cursor;
1528 struct tlv_partition_header *header;
1529 struct tlv_partition_trailer *trailer;
1530 uint32_t generation;
1535 /* A PARTITION_HEADER tag must be the first item (at offset zero) */
1536 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data,
1537 max_seg_size)) != 0) {
1541 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
1545 header = (struct tlv_partition_header *)tlv_item(&cursor);
1547 /* Update the TLV chain to contain the new data */
1548 if ((rc = tlv_find(&cursor, tag)) == 0) {
1549 /* Modify existing TLV item */
1550 if ((rc = tlv_modify(&cursor, tag,
1551 (uint8_t *)tag_data, tag_size)) != 0)
1554 /* Insert a new TLV item before the PARTITION_TRAILER */
1555 rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER);
1560 if ((rc = tlv_insert(&cursor, tag,
1561 (uint8_t *)tag_data, tag_size)) != 0) {
1567 /* Find the trailer tag */
1568 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {
1572 trailer = (struct tlv_partition_trailer *)tlv_item(&cursor);
1574 /* Update PARTITION_HEADER and PARTITION_TRAILER fields */
1575 *total_lengthp = tlv_block_length_used(&cursor);
1576 if (*total_lengthp > max_seg_size) {
1580 generation = __LE_TO_CPU_32(header->generation) + 1;
1582 header->total_length = __CPU_TO_LE_32(*total_lengthp);
1583 header->generation = __CPU_TO_LE_32(generation);
1584 trailer->generation = __CPU_TO_LE_32(generation);
1586 /* Recompute PARTITION_TRAILER checksum */
1587 trailer->checksum = 0;
1589 for (pos = 0; (size_t)pos < *total_lengthp; pos += sizeof (uint32_t)) {
1590 cksum += *((uint32_t *)(seg_data + pos));
1592 trailer->checksum = ~cksum + 1;
1609 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1615 * Add or update a single TLV item in the first segment of a TLV formatted
1616 * dynamic config partition. The first segment is the current active
1619 __checkReturn efx_rc_t
1620 ef10_nvram_partn_write_tlv(
1621 __in efx_nic_t *enp,
1622 __in uint32_t partn,
1624 __in_bcount(size) caddr_t data,
1627 return ef10_nvram_partn_write_segment_tlv(enp, partn, tag, data,
1632 * Read a segment from nvram at the given offset into a buffer (segment_data)
1633 * and optionally write a new tag to it.
1635 static __checkReturn efx_rc_t
1636 ef10_nvram_segment_write_tlv(
1637 __in efx_nic_t *enp,
1638 __in uint32_t partn,
1640 __in_bcount(size) caddr_t data,
1642 __inout caddr_t *seg_datap,
1643 __inout size_t *partn_offsetp,
1644 __inout size_t *src_remain_lenp,
1645 __inout size_t *dest_remain_lenp,
1646 __in boolean_t write)
1650 size_t original_segment_size;
1651 size_t modified_segment_size;
1654 * Read the segment from NVRAM into the segment_data buffer and validate
1655 * it, returning if it does not validate. This is not a failure unless
1656 * this is the first segment in a partition. In this case the caller
1657 * must propagate the error.
1659 status = ef10_nvram_read_tlv_segment(enp, partn, *partn_offsetp,
1660 *seg_datap, *src_remain_lenp);
1664 status = ef10_nvram_buf_segment_size(*seg_datap,
1665 *src_remain_lenp, &original_segment_size);
1670 /* Update the contents of the segment in the buffer */
1671 if ((rc = ef10_nvram_buf_write_tlv(*seg_datap,
1672 *dest_remain_lenp, tag, data, size,
1673 &modified_segment_size)) != 0)
1675 *dest_remain_lenp -= modified_segment_size;
1676 *seg_datap += modified_segment_size;
1679 * We won't modify this segment, but still need to update the
1680 * remaining lengths and pointers.
1682 *dest_remain_lenp -= original_segment_size;
1683 *seg_datap += original_segment_size;
1686 *partn_offsetp += original_segment_size;
1687 *src_remain_lenp -= original_segment_size;
1692 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1698 * Add or update a single TLV item in either the first segment or in all
1699 * segments in a TLV formatted dynamic config partition. Dynamic config
1700 * partitions on boards that support RFID are divided into a number of segments,
1701 * each formatted like a partition, with header, trailer and end tags. The first
1702 * segment is the current active configuration.
1704 * The segments are initialised by manftest and each contain a different
1705 * configuration e.g. firmware variant. The firmware can be instructed
1706 * via RFID to copy a segment to replace the first segment, hence changing the
1707 * active configuration. This allows ops to change the configuration of a board
1708 * prior to shipment using RFID.
1710 * Changes to the dynamic config may need to be written to all segments (e.g.
1711 * firmware versions) or just the first segment (changes to the active
1712 * configuration). See SF-111324-SW "The use of RFID in Solarflare Products".
1713 * If only the first segment is written the code still needs to be aware of the
1714 * possible presence of subsequent segments as writing to a segment may cause
1715 * its size to increase, which would overwrite the subsequent segments and
1718 __checkReturn efx_rc_t
1719 ef10_nvram_partn_write_segment_tlv(
1720 __in efx_nic_t *enp,
1721 __in uint32_t partn,
1723 __in_bcount(size) caddr_t data,
1725 __in boolean_t all_segments)
1727 size_t partn_size = 0;
1729 size_t total_length = 0;
1731 size_t current_offset = 0;
1732 size_t remaining_original_length;
1733 size_t remaining_modified_length;
1734 caddr_t segment_data;
1736 EFSYS_ASSERT3U(partn, ==, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG);
1738 /* Allocate sufficient memory for the entire partition */
1739 if ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0)
1742 EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, partn_data);
1743 if (partn_data == NULL) {
1748 remaining_original_length = partn_size;
1749 remaining_modified_length = partn_size;
1750 segment_data = partn_data;
1752 /* Lock the partition */
1753 if ((rc = ef10_nvram_partn_lock(enp, partn)) != 0)
1756 /* Iterate over each (potential) segment to update it. */
1758 boolean_t write = all_segments || current_offset == 0;
1760 rc = ef10_nvram_segment_write_tlv(enp, partn, tag, data, size,
1761 &segment_data, ¤t_offset, &remaining_original_length,
1762 &remaining_modified_length, write);
1764 if (current_offset == 0) {
1766 * If no data has been read then the first
1767 * segment is invalid, which is an error.
1773 } while (current_offset < partn_size);
1775 total_length = segment_data - partn_data;
1778 * We've run out of space. This should actually be dealt with by
1779 * ef10_nvram_buf_write_tlv returning ENOSPC.
1781 if (total_length > partn_size) {
1786 /* Erase the whole partition in NVRAM */
1787 if ((rc = ef10_nvram_partn_erase(enp, partn, 0, partn_size)) != 0)
1790 /* Write new partition contents from the buffer to NVRAM */
1791 if ((rc = ef10_nvram_partn_write(enp, partn, 0, partn_data,
1792 total_length)) != 0)
1795 /* Unlock the partition */
1796 ef10_nvram_partn_unlock(enp, partn);
1798 EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data);
1811 ef10_nvram_partn_unlock(enp, partn);
1815 EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data);
1819 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1825 * Get the size of a NVRAM partition. This is the total size allocated in nvram,
1826 * not the data used by the segments in the partition.
1828 __checkReturn efx_rc_t
1829 ef10_nvram_partn_size(
1830 __in efx_nic_t *enp,
1831 __in uint32_t partn,
1832 __out size_t *sizep)
1836 if ((rc = efx_mcdi_nvram_info(enp, partn, sizep,
1837 NULL, NULL, NULL)) != 0)
1843 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1848 __checkReturn efx_rc_t
1849 ef10_nvram_partn_lock(
1850 __in efx_nic_t *enp,
1851 __in uint32_t partn)
1855 if ((rc = efx_mcdi_nvram_update_start(enp, partn)) != 0)
1861 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1866 __checkReturn efx_rc_t
1867 ef10_nvram_partn_read_mode(
1868 __in efx_nic_t *enp,
1869 __in uint32_t partn,
1870 __in unsigned int offset,
1871 __out_bcount(size) caddr_t data,
1879 chunk = MIN(size, EF10_NVRAM_CHUNK);
1881 if ((rc = efx_mcdi_nvram_read(enp, partn, offset,
1882 data, chunk, mode)) != 0) {
1894 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1899 __checkReturn efx_rc_t
1900 ef10_nvram_partn_read(
1901 __in efx_nic_t *enp,
1902 __in uint32_t partn,
1903 __in unsigned int offset,
1904 __out_bcount(size) caddr_t data,
1908 * Read requests which come in through the EFX API expect to
1909 * read the current, active partition.
1911 return ef10_nvram_partn_read_mode(enp, partn, offset, data, size,
1912 MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT);
1915 __checkReturn efx_rc_t
1916 ef10_nvram_partn_erase(
1917 __in efx_nic_t *enp,
1918 __in uint32_t partn,
1919 __in unsigned int offset,
1923 uint32_t erase_size;
1925 if ((rc = efx_mcdi_nvram_info(enp, partn, NULL, NULL,
1926 &erase_size, NULL)) != 0)
1929 if (erase_size == 0) {
1930 if ((rc = efx_mcdi_nvram_erase(enp, partn, offset, size)) != 0)
1933 if (size % erase_size != 0) {
1938 if ((rc = efx_mcdi_nvram_erase(enp, partn, offset,
1941 offset += erase_size;
1955 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1960 __checkReturn efx_rc_t
1961 ef10_nvram_partn_write(
1962 __in efx_nic_t *enp,
1963 __in uint32_t partn,
1964 __in unsigned int offset,
1965 __out_bcount(size) caddr_t data,
1969 uint32_t write_size;
1972 if ((rc = efx_mcdi_nvram_info(enp, partn, NULL, NULL,
1973 NULL, &write_size)) != 0)
1976 if (write_size != 0) {
1978 * Check that the size is a multiple of the write chunk size if
1979 * the write chunk size is available.
1981 if (size % write_size != 0) {
1986 write_size = EF10_NVRAM_CHUNK;
1990 chunk = MIN(size, write_size);
1992 if ((rc = efx_mcdi_nvram_write(enp, partn, offset,
1993 data, chunk)) != 0) {
2009 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2015 ef10_nvram_partn_unlock(
2016 __in efx_nic_t *enp,
2017 __in uint32_t partn)
2023 if ((rc = efx_mcdi_nvram_update_finish(enp, partn, reboot)) != 0)
2029 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2032 __checkReturn efx_rc_t
2033 ef10_nvram_partn_set_version(
2034 __in efx_nic_t *enp,
2035 __in uint32_t partn,
2036 __in_ecount(4) uint16_t version[4])
2038 struct tlv_partition_version partn_version;
2042 /* Add or modify partition version TLV item */
2043 partn_version.version_w = __CPU_TO_LE_16(version[0]);
2044 partn_version.version_x = __CPU_TO_LE_16(version[1]);
2045 partn_version.version_y = __CPU_TO_LE_16(version[2]);
2046 partn_version.version_z = __CPU_TO_LE_16(version[3]);
2048 size = sizeof (partn_version) - (2 * sizeof (uint32_t));
2050 /* Write the version number to all segments in the partition */
2051 if ((rc = ef10_nvram_partn_write_segment_tlv(enp,
2052 NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
2053 TLV_TAG_PARTITION_VERSION(partn),
2054 (caddr_t)&partn_version.version_w, size, B_TRUE)) != 0)
2060 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2065 #endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */
2069 typedef struct ef10_parttbl_entry_s {
2072 efx_nvram_type_t nvtype;
2073 } ef10_parttbl_entry_t;
2075 /* Translate EFX NVRAM types to firmware partition types */
2076 static ef10_parttbl_entry_t hunt_parttbl[] = {
2077 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 1, EFX_NVRAM_MC_FIRMWARE},
2078 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 2, EFX_NVRAM_MC_FIRMWARE},
2079 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 3, EFX_NVRAM_MC_FIRMWARE},
2080 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 4, EFX_NVRAM_MC_FIRMWARE},
2081 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 1, EFX_NVRAM_MC_GOLDEN},
2082 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 2, EFX_NVRAM_MC_GOLDEN},
2083 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 3, EFX_NVRAM_MC_GOLDEN},
2084 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 4, EFX_NVRAM_MC_GOLDEN},
2085 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 1, EFX_NVRAM_BOOTROM},
2086 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 2, EFX_NVRAM_BOOTROM},
2087 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 3, EFX_NVRAM_BOOTROM},
2088 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 4, EFX_NVRAM_BOOTROM},
2089 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 1, EFX_NVRAM_BOOTROM_CFG},
2090 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT1, 2, EFX_NVRAM_BOOTROM_CFG},
2091 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT2, 3, EFX_NVRAM_BOOTROM_CFG},
2092 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT3, 4, EFX_NVRAM_BOOTROM_CFG},
2093 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 1, EFX_NVRAM_DYNAMIC_CFG},
2094 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 2, EFX_NVRAM_DYNAMIC_CFG},
2095 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 3, EFX_NVRAM_DYNAMIC_CFG},
2096 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 4, EFX_NVRAM_DYNAMIC_CFG},
2097 {NVRAM_PARTITION_TYPE_FPGA, 1, EFX_NVRAM_FPGA},
2098 {NVRAM_PARTITION_TYPE_FPGA, 2, EFX_NVRAM_FPGA},
2099 {NVRAM_PARTITION_TYPE_FPGA, 3, EFX_NVRAM_FPGA},
2100 {NVRAM_PARTITION_TYPE_FPGA, 4, EFX_NVRAM_FPGA},
2101 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 1, EFX_NVRAM_FPGA_BACKUP},
2102 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 2, EFX_NVRAM_FPGA_BACKUP},
2103 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 3, EFX_NVRAM_FPGA_BACKUP},
2104 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 4, EFX_NVRAM_FPGA_BACKUP},
2105 {NVRAM_PARTITION_TYPE_LICENSE, 1, EFX_NVRAM_LICENSE},
2106 {NVRAM_PARTITION_TYPE_LICENSE, 2, EFX_NVRAM_LICENSE},
2107 {NVRAM_PARTITION_TYPE_LICENSE, 3, EFX_NVRAM_LICENSE},
2108 {NVRAM_PARTITION_TYPE_LICENSE, 4, EFX_NVRAM_LICENSE}
2111 static ef10_parttbl_entry_t medford_parttbl[] = {
2112 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 1, EFX_NVRAM_MC_FIRMWARE},
2113 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 2, EFX_NVRAM_MC_FIRMWARE},
2114 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 3, EFX_NVRAM_MC_FIRMWARE},
2115 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 4, EFX_NVRAM_MC_FIRMWARE},
2116 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 1, EFX_NVRAM_MC_GOLDEN},
2117 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 2, EFX_NVRAM_MC_GOLDEN},
2118 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 3, EFX_NVRAM_MC_GOLDEN},
2119 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 4, EFX_NVRAM_MC_GOLDEN},
2120 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 1, EFX_NVRAM_BOOTROM},
2121 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 2, EFX_NVRAM_BOOTROM},
2122 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 3, EFX_NVRAM_BOOTROM},
2123 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 4, EFX_NVRAM_BOOTROM},
2124 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 1, EFX_NVRAM_BOOTROM_CFG},
2125 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 2, EFX_NVRAM_BOOTROM_CFG},
2126 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 3, EFX_NVRAM_BOOTROM_CFG},
2127 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 4, EFX_NVRAM_BOOTROM_CFG},
2128 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 1, EFX_NVRAM_DYNAMIC_CFG},
2129 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 2, EFX_NVRAM_DYNAMIC_CFG},
2130 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 3, EFX_NVRAM_DYNAMIC_CFG},
2131 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 4, EFX_NVRAM_DYNAMIC_CFG},
2132 {NVRAM_PARTITION_TYPE_FPGA, 1, EFX_NVRAM_FPGA},
2133 {NVRAM_PARTITION_TYPE_FPGA, 2, EFX_NVRAM_FPGA},
2134 {NVRAM_PARTITION_TYPE_FPGA, 3, EFX_NVRAM_FPGA},
2135 {NVRAM_PARTITION_TYPE_FPGA, 4, EFX_NVRAM_FPGA},
2136 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 1, EFX_NVRAM_FPGA_BACKUP},
2137 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 2, EFX_NVRAM_FPGA_BACKUP},
2138 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 3, EFX_NVRAM_FPGA_BACKUP},
2139 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 4, EFX_NVRAM_FPGA_BACKUP},
2140 {NVRAM_PARTITION_TYPE_LICENSE, 1, EFX_NVRAM_LICENSE},
2141 {NVRAM_PARTITION_TYPE_LICENSE, 2, EFX_NVRAM_LICENSE},
2142 {NVRAM_PARTITION_TYPE_LICENSE, 3, EFX_NVRAM_LICENSE},
2143 {NVRAM_PARTITION_TYPE_LICENSE, 4, EFX_NVRAM_LICENSE}
2146 static __checkReturn efx_rc_t
2148 __in efx_nic_t *enp,
2149 __out ef10_parttbl_entry_t **parttblp,
2150 __out size_t *parttbl_rowsp)
2152 switch (enp->en_family) {
2153 case EFX_FAMILY_HUNTINGTON:
2154 *parttblp = hunt_parttbl;
2155 *parttbl_rowsp = EFX_ARRAY_SIZE(hunt_parttbl);
2158 case EFX_FAMILY_MEDFORD:
2159 *parttblp = medford_parttbl;
2160 *parttbl_rowsp = EFX_ARRAY_SIZE(medford_parttbl);
2164 EFSYS_ASSERT(B_FALSE);
2170 __checkReturn efx_rc_t
2171 ef10_nvram_type_to_partn(
2172 __in efx_nic_t *enp,
2173 __in efx_nvram_type_t type,
2174 __out uint32_t *partnp)
2176 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
2177 ef10_parttbl_entry_t *parttbl = NULL;
2178 size_t parttbl_rows = 0;
2181 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
2182 EFSYS_ASSERT(partnp != NULL);
2184 if (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) {
2185 for (i = 0; i < parttbl_rows; i++) {
2186 ef10_parttbl_entry_t *entry = &parttbl[i];
2188 if (entry->nvtype == type &&
2189 entry->port == emip->emi_port) {
2190 *partnp = entry->partn;
2201 static __checkReturn efx_rc_t
2202 ef10_nvram_partn_to_type(
2203 __in efx_nic_t *enp,
2204 __in uint32_t partn,
2205 __out efx_nvram_type_t *typep)
2207 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
2208 ef10_parttbl_entry_t *parttbl = NULL;
2209 size_t parttbl_rows = 0;
2212 EFSYS_ASSERT(typep != NULL);
2214 if (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) {
2215 for (i = 0; i < parttbl_rows; i++) {
2216 ef10_parttbl_entry_t *entry = &parttbl[i];
2218 if (entry->partn == partn &&
2219 entry->port == emip->emi_port) {
2220 *typep = entry->nvtype;
2229 __checkReturn efx_rc_t
2231 __in efx_nic_t *enp)
2233 efx_nvram_type_t type;
2234 unsigned int npartns = 0;
2235 uint32_t *partns = NULL;
2240 /* Read available partitions from NVRAM partition map */
2241 size = MC_CMD_NVRAM_PARTITIONS_OUT_TYPE_ID_MAXNUM * sizeof (uint32_t);
2242 EFSYS_KMEM_ALLOC(enp->en_esip, size, partns);
2243 if (partns == NULL) {
2248 if ((rc = efx_mcdi_nvram_partitions(enp, (caddr_t)partns, size,
2253 for (i = 0; i < npartns; i++) {
2254 /* Check if the partition is supported for this port */
2255 if ((rc = ef10_nvram_partn_to_type(enp, partns[i], &type)) != 0)
2258 if ((rc = efx_mcdi_nvram_test(enp, partns[i])) != 0)
2262 EFSYS_KMEM_FREE(enp->en_esip, size, partns);
2269 EFSYS_KMEM_FREE(enp->en_esip, size, partns);
2271 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2275 #endif /* EFSYS_OPT_DIAG */
2277 __checkReturn efx_rc_t
2278 ef10_nvram_partn_get_version(
2279 __in efx_nic_t *enp,
2280 __in uint32_t partn,
2281 __out uint32_t *subtypep,
2282 __out_ecount(4) uint16_t version[4])
2286 /* FIXME: get highest partn version from all ports */
2287 /* FIXME: return partn description if available */
2289 if ((rc = efx_mcdi_nvram_metadata(enp, partn, subtypep,
2290 version, NULL, 0)) != 0)
2296 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2301 __checkReturn efx_rc_t
2302 ef10_nvram_partn_rw_start(
2303 __in efx_nic_t *enp,
2304 __in uint32_t partn,
2305 __out size_t *chunk_sizep)
2309 if ((rc = ef10_nvram_partn_lock(enp, partn)) != 0)
2312 if (chunk_sizep != NULL)
2313 *chunk_sizep = EF10_NVRAM_CHUNK;
2318 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2324 ef10_nvram_partn_rw_finish(
2325 __in efx_nic_t *enp,
2326 __in uint32_t partn)
2328 ef10_nvram_partn_unlock(enp, partn);
2331 #endif /* EFSYS_OPT_NVRAM */
2333 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */