2 * Copyright (c) 2012-2016 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.
34 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
36 #if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
38 #include "ef10_tlv_layout.h"
40 /* Cursor for TLV partition format */
41 typedef struct tlv_cursor_s {
42 uint32_t *block; /* Base of data block */
43 uint32_t *current; /* Cursor position */
44 uint32_t *end; /* End tag position */
45 uint32_t *limit; /* Last dword of data block */
48 typedef struct nvram_partition_s {
53 * The full length of the NVRAM partition.
54 * This is different from tlv_partition_header.total_length,
55 * which can be smaller.
60 tlv_cursor_t tlv_cursor;
64 static __checkReturn efx_rc_t
66 __inout tlv_cursor_t *cursor);
71 __out uint32_t *block)
73 *block = __CPU_TO_LE_32(TLV_TAG_END);
78 __in tlv_cursor_t *cursor)
82 dword = cursor->current[0];
83 tag = __LE_TO_CPU_32(dword);
90 __in tlv_cursor_t *cursor)
92 uint32_t dword, length;
94 if (tlv_tag(cursor) == TLV_TAG_END)
97 dword = cursor->current[1];
98 length = __LE_TO_CPU_32(dword);
100 return ((size_t)length);
105 __in tlv_cursor_t *cursor)
107 if (tlv_tag(cursor) == TLV_TAG_END)
110 return ((uint8_t *)(&cursor->current[2]));
115 __in tlv_cursor_t *cursor)
117 if (tlv_tag(cursor) == TLV_TAG_END)
120 return ((uint8_t *)cursor->current);
124 * TLV item DWORD length is tag + length + value (rounded up to DWORD)
125 * equivalent to tlv_n_words_for_len in mc-comms tlv.c
127 #define TLV_DWORD_COUNT(length) \
128 (1 + 1 + (((length) + sizeof (uint32_t) - 1) / sizeof (uint32_t)))
133 __in tlv_cursor_t *cursor)
137 length = tlv_length(cursor);
139 return (cursor->current + TLV_DWORD_COUNT(length));
142 static __checkReturn efx_rc_t
144 __inout tlv_cursor_t *cursor)
148 if ((rc = tlv_validate_state(cursor)) != 0)
151 if (cursor->current == cursor->end) {
152 /* No more tags after END tag */
153 cursor->current = NULL;
158 /* Advance to next item and validate */
159 cursor->current = tlv_next_item_ptr(cursor);
161 if ((rc = tlv_validate_state(cursor)) != 0)
171 EFSYS_PROBE1(fail1, efx_rc_t, rc);
178 __in tlv_cursor_t *cursor)
182 cursor->current = cursor->block;
184 if ((rc = tlv_validate_state(cursor)) != 0)
190 EFSYS_PROBE1(fail1, efx_rc_t, rc);
197 __inout tlv_cursor_t *cursor,
202 rc = tlv_rewind(cursor);
204 if (tlv_tag(cursor) == tag)
207 rc = tlv_advance(cursor);
212 static __checkReturn efx_rc_t
214 __inout tlv_cursor_t *cursor)
218 /* Check cursor position */
219 if (cursor->current < cursor->block) {
223 if (cursor->current > cursor->limit) {
228 if (tlv_tag(cursor) != TLV_TAG_END) {
229 /* Check current item has space for tag and length */
230 if (cursor->current > (cursor->limit - 2)) {
231 cursor->current = NULL;
236 /* Check we have value data for current item and another tag */
237 if (tlv_next_item_ptr(cursor) > (cursor->limit - 1)) {
238 cursor->current = NULL;
253 EFSYS_PROBE1(fail1, efx_rc_t, rc);
260 __out tlv_cursor_t *cursor,
261 __in uint32_t *block,
262 __in uint32_t *limit,
263 __in uint32_t *current)
265 cursor->block = block;
266 cursor->limit = limit;
268 cursor->current = current;
271 return (tlv_validate_state(cursor));
274 static __checkReturn efx_rc_t
275 tlv_init_cursor_from_size(
276 __out tlv_cursor_t *cursor,
282 limit = (uint32_t *)(block + size - sizeof (uint32_t));
283 return (tlv_init_cursor(cursor, (uint32_t *)block,
284 limit, (uint32_t *)block));
287 static __checkReturn efx_rc_t
288 tlv_init_cursor_at_offset(
289 __out tlv_cursor_t *cursor,
297 limit = (uint32_t *)(block + size - sizeof (uint32_t));
298 current = (uint32_t *)(block + offset);
299 return (tlv_init_cursor(cursor, (uint32_t *)block, limit, current));
302 static __checkReturn efx_rc_t
304 __inout tlv_cursor_t *cursor)
309 if (cursor->end == NULL) {
310 pos = cursor->current;
311 if ((rc = tlv_find(cursor, TLV_TAG_END)) != 0)
314 cursor->end = cursor->current;
315 cursor->current = pos;
321 EFSYS_PROBE1(fail1, efx_rc_t, rc);
327 tlv_block_length_used(
328 __inout tlv_cursor_t *cursor)
332 if ((rc = tlv_validate_state(cursor)) != 0)
335 if ((rc = tlv_require_end(cursor)) != 0)
338 /* Return space used (including the END tag) */
339 return (cursor->end + 1 - cursor->block) * sizeof (uint32_t);
344 EFSYS_PROBE1(fail1, efx_rc_t, rc);
350 tlv_last_segment_end(
351 __in tlv_cursor_t *cursor)
353 tlv_cursor_t segment_cursor;
354 uint32_t *last_segment_end = cursor->block;
355 uint32_t *segment_start = cursor->block;
358 * Go through each segment and check that it has an end tag. If there
359 * is no end tag then the previous segment was the last valid one,
360 * so return the pointer to its end tag.
363 if (tlv_init_cursor(&segment_cursor, segment_start,
364 cursor->limit, segment_start) != 0)
366 if (tlv_require_end(&segment_cursor) != 0)
368 last_segment_end = segment_cursor.end;
369 segment_start = segment_cursor.end + 1;
372 return (last_segment_end);
378 __in tlv_cursor_t *cursor,
380 __in_bcount(size) uint8_t *data,
386 ptr = cursor->current;
388 *ptr++ = __CPU_TO_LE_32(tag);
389 *ptr++ = __CPU_TO_LE_32(len);
392 ptr[(len - 1) / sizeof (uint32_t)] = 0;
393 memcpy(ptr, data, len);
394 ptr += P2ROUNDUP(len, sizeof (uint32_t)) / sizeof (*ptr);
400 static __checkReturn efx_rc_t
402 __inout tlv_cursor_t *cursor,
409 uint32_t *last_segment_end;
412 if ((rc = tlv_validate_state(cursor)) != 0)
415 if ((rc = tlv_require_end(cursor)) != 0)
418 if (tag == TLV_TAG_END) {
423 last_segment_end = tlv_last_segment_end(cursor);
425 delta = TLV_DWORD_COUNT(size);
426 if (last_segment_end + 1 + delta > cursor->limit) {
431 /* Move data up: new space at cursor->current */
432 memmove(cursor->current + delta, cursor->current,
433 (last_segment_end + 1 - cursor->current) * sizeof (uint32_t));
435 /* Adjust the end pointer */
436 cursor->end += delta;
438 /* Write new TLV item */
439 tlv_write(cursor, tag, data, size);
450 EFSYS_PROBE1(fail1, efx_rc_t, rc);
455 static __checkReturn efx_rc_t
457 __inout tlv_cursor_t *cursor)
460 uint32_t *last_segment_end;
463 if ((rc = tlv_validate_state(cursor)) != 0)
466 if (tlv_tag(cursor) == TLV_TAG_END) {
471 delta = TLV_DWORD_COUNT(tlv_length(cursor));
473 if ((rc = tlv_require_end(cursor)) != 0)
476 last_segment_end = tlv_last_segment_end(cursor);
478 /* Shuffle things down, destroying the item at cursor->current */
479 memmove(cursor->current, cursor->current + delta,
480 (last_segment_end + 1 - cursor->current) * sizeof (uint32_t));
481 /* Zero the new space at the end of the TLV chain */
482 memset(last_segment_end + 1 - delta, 0, delta * sizeof (uint32_t));
483 /* Adjust the end pointer */
484 cursor->end -= delta;
493 EFSYS_PROBE1(fail1, efx_rc_t, rc);
498 static __checkReturn efx_rc_t
500 __inout tlv_cursor_t *cursor,
507 unsigned int old_ndwords;
508 unsigned int new_ndwords;
510 uint32_t *last_segment_end;
513 if ((rc = tlv_validate_state(cursor)) != 0)
516 if (tlv_tag(cursor) == TLV_TAG_END) {
520 if (tlv_tag(cursor) != tag) {
525 old_ndwords = TLV_DWORD_COUNT(tlv_length(cursor));
526 new_ndwords = TLV_DWORD_COUNT(size);
528 if ((rc = tlv_require_end(cursor)) != 0)
531 last_segment_end = tlv_last_segment_end(cursor);
533 if (new_ndwords > old_ndwords) {
534 /* Expand space used for TLV item */
535 delta = new_ndwords - old_ndwords;
536 pos = cursor->current + old_ndwords;
538 if (last_segment_end + 1 + delta > cursor->limit) {
543 /* Move up: new space at (cursor->current + old_ndwords) */
544 memmove(pos + delta, pos,
545 (last_segment_end + 1 - pos) * sizeof (uint32_t));
547 /* Adjust the end pointer */
548 cursor->end += delta;
550 } else if (new_ndwords < old_ndwords) {
551 /* Shrink space used for TLV item */
552 delta = old_ndwords - new_ndwords;
553 pos = cursor->current + new_ndwords;
555 /* Move down: remove words at (cursor->current + new_ndwords) */
556 memmove(pos, pos + delta,
557 (last_segment_end + 1 - pos) * sizeof (uint32_t));
559 /* Zero the new space at the end of the TLV chain */
560 memset(last_segment_end + 1 - delta, 0,
561 delta * sizeof (uint32_t));
563 /* Adjust the end pointer */
564 cursor->end -= delta;
568 tlv_write(cursor, tag, data, size);
581 EFSYS_PROBE1(fail1, efx_rc_t, rc);
586 static uint32_t checksum_tlv_partition(
587 __in nvram_partition_t *partition)
589 tlv_cursor_t *cursor;
595 cursor = &partition->tlv_cursor;
596 len = tlv_block_length_used(cursor);
597 EFSYS_ASSERT3U((len & 3), ==, 0);
600 ptr = partition->data;
601 end = &ptr[len >> 2];
604 csum += __LE_TO_CPU_32(*ptr++);
609 static __checkReturn efx_rc_t
610 tlv_update_partition_len_and_cks(
611 __in tlv_cursor_t *cursor)
614 nvram_partition_t partition;
615 struct tlv_partition_header *header;
616 struct tlv_partition_trailer *trailer;
620 * We just modified the partition, so the total length may not be
621 * valid. Don't use tlv_find(), which performs some sanity checks
622 * that may fail here.
624 partition.data = cursor->block;
625 memcpy(&partition.tlv_cursor, cursor, sizeof (*cursor));
626 header = (struct tlv_partition_header *)partition.data;
628 if (__LE_TO_CPU_32(header->tag) != TLV_TAG_PARTITION_HEADER) {
632 new_len = tlv_block_length_used(&partition.tlv_cursor);
637 header->total_length = __CPU_TO_LE_32(new_len);
638 /* Ensure the modified partition always has a new generation count. */
639 header->generation = __CPU_TO_LE_32(
640 __LE_TO_CPU_32(header->generation) + 1);
642 trailer = (struct tlv_partition_trailer *)((uint8_t *)header +
643 new_len - sizeof (*trailer) - sizeof (uint32_t));
644 trailer->generation = header->generation;
645 trailer->checksum = __CPU_TO_LE_32(
646 __LE_TO_CPU_32(trailer->checksum) -
647 checksum_tlv_partition(&partition));
654 EFSYS_PROBE1(fail1, efx_rc_t, rc);
659 /* Validate buffer contents (before writing to flash) */
660 __checkReturn efx_rc_t
661 ef10_nvram_buffer_validate(
664 __in_bcount(partn_size) caddr_t partn_data,
665 __in size_t partn_size)
668 struct tlv_partition_header *header;
669 struct tlv_partition_trailer *trailer;
675 EFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK);
677 if ((partn_data == NULL) || (partn_size == 0)) {
682 /* The partition header must be the first item (at offset zero) */
683 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)partn_data,
688 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
692 header = (struct tlv_partition_header *)tlv_item(&cursor);
694 /* Check TLV partition length (includes the END tag) */
695 total_length = __LE_TO_CPU_32(header->total_length);
696 if (total_length > partn_size) {
701 /* Check partition ends with PARTITION_TRAILER and END tags */
702 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {
706 trailer = (struct tlv_partition_trailer *)tlv_item(&cursor);
708 if ((rc = tlv_advance(&cursor)) != 0) {
712 if (tlv_tag(&cursor) != TLV_TAG_END) {
717 /* Check generation counts are consistent */
718 if (trailer->generation != header->generation) {
723 /* Verify partition checksum */
725 for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) {
726 cksum += *((uint32_t *)(partn_data + pos));
752 EFSYS_PROBE1(fail1, efx_rc_t, rc);
759 __checkReturn efx_rc_t
760 ef10_nvram_buffer_create(
762 __in uint16_t partn_type,
763 __in_bcount(partn_size) caddr_t partn_data,
764 __in size_t partn_size)
766 uint32_t *buf = (uint32_t *)partn_data;
769 struct tlv_partition_header header;
770 struct tlv_partition_trailer trailer;
772 unsigned int min_buf_size = sizeof (struct tlv_partition_header) +
773 sizeof (struct tlv_partition_trailer);
774 if (partn_size < min_buf_size) {
779 memset(buf, 0xff, partn_size);
782 if ((rc = tlv_init_cursor(&cursor, buf,
783 (uint32_t *)((uint8_t *)buf + partn_size),
788 header.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_HEADER);
789 header.length = __CPU_TO_LE_32(sizeof (header) - 8);
790 header.type_id = __CPU_TO_LE_16(partn_type);
792 header.generation = __CPU_TO_LE_32(1);
793 header.total_length = 0; /* This will be fixed below. */
794 if ((rc = tlv_insert(
795 &cursor, TLV_TAG_PARTITION_HEADER,
796 (uint8_t *)&header.type_id, sizeof (header) - 8)) != 0)
798 if ((rc = tlv_advance(&cursor)) != 0)
801 trailer.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_TRAILER);
802 trailer.length = __CPU_TO_LE_32(sizeof (trailer) - 8);
803 trailer.generation = header.generation;
804 trailer.checksum = 0; /* This will be fixed below. */
805 if ((rc = tlv_insert(&cursor, TLV_TAG_PARTITION_TRAILER,
806 (uint8_t *)&trailer.generation, sizeof (trailer) - 8)) != 0)
809 if ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0)
812 /* Check that the partition is valid. */
813 if ((rc = ef10_nvram_buffer_validate(enp, partn_type,
814 partn_data, partn_size)) != 0)
832 EFSYS_PROBE1(fail1, efx_rc_t, rc);
839 __in uint32_t *position,
842 return (uint32_t)((uint8_t *)position - (uint8_t *)base);
845 __checkReturn efx_rc_t
846 ef10_nvram_buffer_find_item_start(
847 __in_bcount(buffer_size)
849 __in size_t buffer_size,
850 __out uint32_t *startp)
852 /* Read past partition header to find start address of the first key */
856 /* A PARTITION_HEADER tag must be the first item (at offset zero) */
857 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp,
858 buffer_size)) != 0) {
862 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
867 if ((rc = tlv_advance(&cursor)) != 0) {
871 *startp = byte_offset(cursor.current, cursor.block);
873 if ((rc = tlv_require_end(&cursor)) != 0)
885 EFSYS_PROBE1(fail1, efx_rc_t, rc);
890 __checkReturn efx_rc_t
891 ef10_nvram_buffer_find_end(
892 __in_bcount(buffer_size)
894 __in size_t buffer_size,
895 __in uint32_t offset,
896 __out uint32_t *endp)
898 /* Read to end of partition */
901 uint32_t *segment_used;
903 _NOTE(ARGUNUSED(offset))
905 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp,
906 buffer_size)) != 0) {
911 segment_used = cursor.block;
914 * Go through each segment and check that it has an end tag. If there
915 * is no end tag then the previous segment was the last valid one,
916 * so return the used space including that end tag.
918 while (tlv_tag(&cursor) == TLV_TAG_PARTITION_HEADER) {
919 if (tlv_require_end(&cursor) != 0) {
920 if (segment_used == cursor.block) {
922 * First segment is corrupt, so there is
923 * no valid data in partition.
930 segment_used = cursor.end + 1;
932 cursor.current = segment_used;
934 /* Return space used (including the END tag) */
935 *endp = (segment_used - cursor.block) * sizeof (uint32_t);
942 EFSYS_PROBE1(fail1, efx_rc_t, rc);
947 __checkReturn __success(return != B_FALSE) boolean_t
948 ef10_nvram_buffer_find_item(
949 __in_bcount(buffer_size)
951 __in size_t buffer_size,
952 __in uint32_t offset,
953 __out uint32_t *startp,
954 __out uint32_t *lengthp)
956 /* Find TLV at offset and return key start and length */
961 if (tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,
962 buffer_size, offset) != 0) {
966 while ((key = tlv_item(&cursor)) != NULL) {
967 tag = tlv_tag(&cursor);
968 if (tag == TLV_TAG_PARTITION_HEADER ||
969 tag == TLV_TAG_PARTITION_TRAILER) {
970 if (tlv_advance(&cursor) != 0) {
975 *startp = byte_offset(cursor.current, cursor.block);
976 *lengthp = byte_offset(tlv_next_item_ptr(&cursor),
984 __checkReturn efx_rc_t
985 ef10_nvram_buffer_get_item(
986 __in_bcount(buffer_size)
988 __in size_t buffer_size,
989 __in uint32_t offset,
990 __in uint32_t length,
991 __out_bcount_part(item_max_size, *lengthp)
993 __in size_t item_max_size,
994 __out uint32_t *lengthp)
998 uint32_t item_length;
1000 if (item_max_size < length) {
1005 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,
1006 buffer_size, offset)) != 0) {
1010 item_length = tlv_length(&cursor);
1011 if (length < item_length) {
1015 memcpy(itemp, tlv_value(&cursor), item_length);
1017 *lengthp = item_length;
1026 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1031 __checkReturn efx_rc_t
1032 ef10_nvram_buffer_insert_item(
1033 __in_bcount(buffer_size)
1035 __in size_t buffer_size,
1036 __in uint32_t offset,
1037 __in_bcount(length) caddr_t keyp,
1038 __in uint32_t length,
1039 __out uint32_t *lengthp)
1042 tlv_cursor_t cursor;
1044 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,
1045 buffer_size, offset)) != 0) {
1049 rc = tlv_insert(&cursor, TLV_TAG_LICENSE, (uint8_t *)keyp, length);
1055 *lengthp = byte_offset(tlv_next_item_ptr(&cursor),
1063 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1068 __checkReturn efx_rc_t
1069 ef10_nvram_buffer_delete_item(
1070 __in_bcount(buffer_size)
1072 __in size_t buffer_size,
1073 __in uint32_t offset,
1074 __in uint32_t length,
1078 tlv_cursor_t cursor;
1080 _NOTE(ARGUNUSED(length, end))
1082 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,
1083 buffer_size, offset)) != 0) {
1087 if ((rc = tlv_delete(&cursor)) != 0)
1095 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1100 __checkReturn efx_rc_t
1101 ef10_nvram_buffer_finish(
1102 __in_bcount(buffer_size)
1104 __in size_t buffer_size)
1107 tlv_cursor_t cursor;
1109 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp,
1110 buffer_size)) != 0) {
1115 if ((rc = tlv_require_end(&cursor)) != 0)
1118 if ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0)
1128 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1136 * Read and validate a segment from a partition. A segment is a complete
1137 * tlv chain between PARTITION_HEADER and PARTITION_END tags. There may
1138 * be multiple segments in a partition, so seg_offset allows segments
1139 * beyond the first to be read.
1141 static __checkReturn efx_rc_t
1142 ef10_nvram_read_tlv_segment(
1143 __in efx_nic_t *enp,
1144 __in uint32_t partn,
1145 __in size_t seg_offset,
1146 __in_bcount(max_seg_size) caddr_t seg_data,
1147 __in size_t max_seg_size)
1149 tlv_cursor_t cursor;
1150 struct tlv_partition_header *header;
1151 struct tlv_partition_trailer *trailer;
1152 size_t total_length;
1157 EFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK);
1159 if ((seg_data == NULL) || (max_seg_size == 0)) {
1164 /* Read initial chunk of the segment, starting at offset */
1165 if ((rc = ef10_nvram_partn_read_mode(enp, partn, seg_offset, seg_data,
1167 MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0) {
1171 /* A PARTITION_HEADER tag must be the first item at the given offset */
1172 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data,
1173 max_seg_size)) != 0) {
1177 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
1181 header = (struct tlv_partition_header *)tlv_item(&cursor);
1183 /* Check TLV segment length (includes the END tag) */
1184 total_length = __LE_TO_CPU_32(header->total_length);
1185 if (total_length > max_seg_size) {
1190 /* Read the remaining segment content */
1191 if (total_length > EF10_NVRAM_CHUNK) {
1192 if ((rc = ef10_nvram_partn_read_mode(enp, partn,
1193 seg_offset + EF10_NVRAM_CHUNK,
1194 seg_data + EF10_NVRAM_CHUNK,
1195 total_length - EF10_NVRAM_CHUNK,
1196 MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0)
1200 /* Check segment ends with PARTITION_TRAILER and END tags */
1201 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {
1205 trailer = (struct tlv_partition_trailer *)tlv_item(&cursor);
1207 if ((rc = tlv_advance(&cursor)) != 0) {
1211 if (tlv_tag(&cursor) != TLV_TAG_END) {
1216 /* Check data read from segment is consistent */
1217 if (trailer->generation != header->generation) {
1219 * The partition data may have been modified between successive
1220 * MCDI NVRAM_READ requests by the MC or another PCI function.
1222 * The caller must retry to obtain consistent partition data.
1228 /* Verify segment checksum */
1230 for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) {
1231 cksum += *((uint32_t *)(seg_data + pos));
1241 EFSYS_PROBE(fail11);
1243 EFSYS_PROBE(fail10);
1261 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1267 * Read a single TLV item from a host memory
1268 * buffer containing a TLV formatted segment.
1270 __checkReturn efx_rc_t
1271 ef10_nvram_buf_read_tlv(
1272 __in efx_nic_t *enp,
1273 __in_bcount(max_seg_size) caddr_t seg_data,
1274 __in size_t max_seg_size,
1276 __deref_out_bcount_opt(*sizep) caddr_t *datap,
1277 __out size_t *sizep)
1279 tlv_cursor_t cursor;
1285 if ((seg_data == NULL) || (max_seg_size == 0)) {
1290 /* Find requested TLV tag in segment data */
1291 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data,
1292 max_seg_size)) != 0) {
1296 if ((rc = tlv_find(&cursor, tag)) != 0) {
1300 value = (caddr_t)tlv_value(&cursor);
1301 length = tlv_length(&cursor);
1306 /* Copy out data from TLV item */
1307 EFSYS_KMEM_ALLOC(enp->en_esip, length, data);
1312 memcpy(data, value, length);
1327 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1332 /* Read a single TLV item from the first segment in a TLV formatted partition */
1333 __checkReturn efx_rc_t
1334 ef10_nvram_partn_read_tlv(
1335 __in efx_nic_t *enp,
1336 __in uint32_t partn,
1338 __deref_out_bcount_opt(*seg_sizep) caddr_t *seg_datap,
1339 __out size_t *seg_sizep)
1341 caddr_t seg_data = NULL;
1342 size_t partn_size = 0;
1348 /* Allocate sufficient memory for the entire partition */
1349 if ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0)
1352 if (partn_size == 0) {
1357 EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, seg_data);
1358 if (seg_data == NULL) {
1364 * Read the first segment in a TLV partition. Retry until consistent
1365 * segment contents are returned. Inconsistent data may be read if:
1366 * a) the segment contents are invalid
1367 * b) the MC has rebooted while we were reading the partition
1368 * c) the partition has been modified while we were reading it
1369 * Limit retry attempts to ensure forward progress.
1373 rc = ef10_nvram_read_tlv_segment(enp, partn, 0,
1374 seg_data, partn_size);
1375 } while ((rc == EAGAIN) && (--retry > 0));
1378 /* Failed to obtain consistent segment data */
1382 if ((rc = ef10_nvram_buf_read_tlv(enp, seg_data, partn_size,
1383 tag, &data, &length)) != 0)
1386 EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data);
1389 *seg_sizep = length;
1398 EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data);
1404 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1409 /* Compute the size of a segment. */
1410 static __checkReturn efx_rc_t
1411 ef10_nvram_buf_segment_size(
1412 __in caddr_t seg_data,
1413 __in size_t max_seg_size,
1414 __out size_t *seg_sizep)
1417 tlv_cursor_t cursor;
1418 struct tlv_partition_header *header;
1421 uint32_t *end_tag_position;
1422 uint32_t segment_length;
1424 /* A PARTITION_HEADER tag must be the first item at the given offset */
1425 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data,
1426 max_seg_size)) != 0) {
1430 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
1434 header = (struct tlv_partition_header *)tlv_item(&cursor);
1436 /* Check TLV segment length (includes the END tag) */
1437 *seg_sizep = __LE_TO_CPU_32(header->total_length);
1438 if (*seg_sizep > max_seg_size) {
1443 /* Check segment ends with PARTITION_TRAILER and END tags */
1444 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {
1449 if ((rc = tlv_advance(&cursor)) != 0) {
1453 if (tlv_tag(&cursor) != TLV_TAG_END) {
1457 end_tag_position = cursor.current;
1459 /* Verify segment checksum */
1461 for (pos = 0; (size_t)pos < *seg_sizep; pos += sizeof (uint32_t)) {
1462 cksum += *((uint32_t *)(seg_data + pos));
1470 * Calculate total length from HEADER to END tags and compare to
1471 * max_seg_size and the total_length field in the HEADER tag.
1473 segment_length = tlv_block_length_used(&cursor);
1475 if (segment_length > max_seg_size) {
1480 if (segment_length != *seg_sizep) {
1485 /* Skip over the first HEADER tag. */
1486 rc = tlv_rewind(&cursor);
1487 rc = tlv_advance(&cursor);
1490 if (tlv_tag(&cursor) == TLV_TAG_END) {
1491 /* Check that the END tag is the one found earlier. */
1492 if (cursor.current != end_tag_position)
1496 /* Check for duplicate HEADER tags before the END tag. */
1497 if (tlv_tag(&cursor) == TLV_TAG_PARTITION_HEADER) {
1502 rc = tlv_advance(&cursor);
1510 EFSYS_PROBE(fail12);
1512 EFSYS_PROBE(fail11);
1514 EFSYS_PROBE(fail10);
1532 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1538 * Add or update a single TLV item in a host memory buffer containing a TLV
1539 * formatted segment. Historically partitions consisted of only one segment.
1541 __checkReturn efx_rc_t
1542 ef10_nvram_buf_write_tlv(
1543 __inout_bcount(max_seg_size) caddr_t seg_data,
1544 __in size_t max_seg_size,
1546 __in_bcount(tag_size) caddr_t tag_data,
1547 __in size_t tag_size,
1548 __out size_t *total_lengthp)
1550 tlv_cursor_t cursor;
1551 struct tlv_partition_header *header;
1552 struct tlv_partition_trailer *trailer;
1553 uint32_t generation;
1558 /* A PARTITION_HEADER tag must be the first item (at offset zero) */
1559 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data,
1560 max_seg_size)) != 0) {
1564 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
1568 header = (struct tlv_partition_header *)tlv_item(&cursor);
1570 /* Update the TLV chain to contain the new data */
1571 if ((rc = tlv_find(&cursor, tag)) == 0) {
1572 /* Modify existing TLV item */
1573 if ((rc = tlv_modify(&cursor, tag,
1574 (uint8_t *)tag_data, tag_size)) != 0)
1577 /* Insert a new TLV item before the PARTITION_TRAILER */
1578 rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER);
1583 if ((rc = tlv_insert(&cursor, tag,
1584 (uint8_t *)tag_data, tag_size)) != 0) {
1590 /* Find the trailer tag */
1591 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {
1595 trailer = (struct tlv_partition_trailer *)tlv_item(&cursor);
1597 /* Update PARTITION_HEADER and PARTITION_TRAILER fields */
1598 *total_lengthp = tlv_block_length_used(&cursor);
1599 if (*total_lengthp > max_seg_size) {
1603 generation = __LE_TO_CPU_32(header->generation) + 1;
1605 header->total_length = __CPU_TO_LE_32(*total_lengthp);
1606 header->generation = __CPU_TO_LE_32(generation);
1607 trailer->generation = __CPU_TO_LE_32(generation);
1609 /* Recompute PARTITION_TRAILER checksum */
1610 trailer->checksum = 0;
1612 for (pos = 0; (size_t)pos < *total_lengthp; pos += sizeof (uint32_t)) {
1613 cksum += *((uint32_t *)(seg_data + pos));
1615 trailer->checksum = ~cksum + 1;
1632 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1638 * Add or update a single TLV item in the first segment of a TLV formatted
1639 * dynamic config partition. The first segment is the current active
1642 __checkReturn efx_rc_t
1643 ef10_nvram_partn_write_tlv(
1644 __in efx_nic_t *enp,
1645 __in uint32_t partn,
1647 __in_bcount(size) caddr_t data,
1650 return ef10_nvram_partn_write_segment_tlv(enp, partn, tag, data,
1655 * Read a segment from nvram at the given offset into a buffer (segment_data)
1656 * and optionally write a new tag to it.
1658 static __checkReturn efx_rc_t
1659 ef10_nvram_segment_write_tlv(
1660 __in efx_nic_t *enp,
1661 __in uint32_t partn,
1663 __in_bcount(size) caddr_t data,
1665 __inout caddr_t *seg_datap,
1666 __inout size_t *partn_offsetp,
1667 __inout size_t *src_remain_lenp,
1668 __inout size_t *dest_remain_lenp,
1669 __in boolean_t write)
1673 size_t original_segment_size;
1674 size_t modified_segment_size;
1677 * Read the segment from NVRAM into the segment_data buffer and validate
1678 * it, returning if it does not validate. This is not a failure unless
1679 * this is the first segment in a partition. In this case the caller
1680 * must propagate the error.
1682 status = ef10_nvram_read_tlv_segment(enp, partn, *partn_offsetp,
1683 *seg_datap, *src_remain_lenp);
1689 status = ef10_nvram_buf_segment_size(*seg_datap,
1690 *src_remain_lenp, &original_segment_size);
1697 /* Update the contents of the segment in the buffer */
1698 if ((rc = ef10_nvram_buf_write_tlv(*seg_datap,
1699 *dest_remain_lenp, tag, data, size,
1700 &modified_segment_size)) != 0) {
1703 *dest_remain_lenp -= modified_segment_size;
1704 *seg_datap += modified_segment_size;
1707 * We won't modify this segment, but still need to update the
1708 * remaining lengths and pointers.
1710 *dest_remain_lenp -= original_segment_size;
1711 *seg_datap += original_segment_size;
1714 *partn_offsetp += original_segment_size;
1715 *src_remain_lenp -= original_segment_size;
1724 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1730 * Add or update a single TLV item in either the first segment or in all
1731 * segments in a TLV formatted dynamic config partition. Dynamic config
1732 * partitions on boards that support RFID are divided into a number of segments,
1733 * each formatted like a partition, with header, trailer and end tags. The first
1734 * segment is the current active configuration.
1736 * The segments are initialised by manftest and each contain a different
1737 * configuration e.g. firmware variant. The firmware can be instructed
1738 * via RFID to copy a segment to replace the first segment, hence changing the
1739 * active configuration. This allows ops to change the configuration of a board
1740 * prior to shipment using RFID.
1742 * Changes to the dynamic config may need to be written to all segments (e.g.
1743 * firmware versions) or just the first segment (changes to the active
1744 * configuration). See SF-111324-SW "The use of RFID in Solarflare Products".
1745 * If only the first segment is written the code still needs to be aware of the
1746 * possible presence of subsequent segments as writing to a segment may cause
1747 * its size to increase, which would overwrite the subsequent segments and
1750 __checkReturn efx_rc_t
1751 ef10_nvram_partn_write_segment_tlv(
1752 __in efx_nic_t *enp,
1753 __in uint32_t partn,
1755 __in_bcount(size) caddr_t data,
1757 __in boolean_t all_segments)
1759 size_t partn_size = 0;
1761 size_t total_length = 0;
1763 size_t current_offset = 0;
1764 size_t remaining_original_length;
1765 size_t remaining_modified_length;
1766 caddr_t segment_data;
1768 EFSYS_ASSERT3U(partn, ==, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG);
1770 /* Allocate sufficient memory for the entire partition */
1771 if ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0)
1774 EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, partn_data);
1775 if (partn_data == NULL) {
1780 remaining_original_length = partn_size;
1781 remaining_modified_length = partn_size;
1782 segment_data = partn_data;
1784 /* Lock the partition */
1785 if ((rc = ef10_nvram_partn_lock(enp, partn)) != 0)
1788 /* Iterate over each (potential) segment to update it. */
1790 boolean_t write = all_segments || current_offset == 0;
1792 rc = ef10_nvram_segment_write_tlv(enp, partn, tag, data, size,
1793 &segment_data, ¤t_offset, &remaining_original_length,
1794 &remaining_modified_length, write);
1796 if (current_offset == 0) {
1798 * If no data has been read then the first
1799 * segment is invalid, which is an error.
1805 } while (current_offset < partn_size);
1807 total_length = segment_data - partn_data;
1810 * We've run out of space. This should actually be dealt with by
1811 * ef10_nvram_buf_write_tlv returning ENOSPC.
1813 if (total_length > partn_size) {
1818 /* Erase the whole partition in NVRAM */
1819 if ((rc = ef10_nvram_partn_erase(enp, partn, 0, partn_size)) != 0)
1822 /* Write new partition contents from the buffer to NVRAM */
1823 if ((rc = ef10_nvram_partn_write(enp, partn, 0, partn_data,
1824 total_length)) != 0)
1827 /* Unlock the partition */
1828 ef10_nvram_partn_unlock(enp, partn, NULL);
1830 EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data);
1843 ef10_nvram_partn_unlock(enp, partn, NULL);
1847 EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data);
1851 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1857 * Get the size of a NVRAM partition. This is the total size allocated in nvram,
1858 * not the data used by the segments in the partition.
1860 __checkReturn efx_rc_t
1861 ef10_nvram_partn_size(
1862 __in efx_nic_t *enp,
1863 __in uint32_t partn,
1864 __out size_t *sizep)
1868 if ((rc = efx_mcdi_nvram_info(enp, partn, sizep,
1869 NULL, NULL, NULL)) != 0)
1875 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1880 __checkReturn efx_rc_t
1881 ef10_nvram_partn_lock(
1882 __in efx_nic_t *enp,
1883 __in uint32_t partn)
1887 if ((rc = efx_mcdi_nvram_update_start(enp, partn)) != 0)
1893 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1898 __checkReturn efx_rc_t
1899 ef10_nvram_partn_read_mode(
1900 __in efx_nic_t *enp,
1901 __in uint32_t partn,
1902 __in unsigned int offset,
1903 __out_bcount(size) caddr_t data,
1911 chunk = MIN(size, EF10_NVRAM_CHUNK);
1913 if ((rc = efx_mcdi_nvram_read(enp, partn, offset,
1914 data, chunk, mode)) != 0) {
1926 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1931 __checkReturn efx_rc_t
1932 ef10_nvram_partn_read(
1933 __in efx_nic_t *enp,
1934 __in uint32_t partn,
1935 __in unsigned int offset,
1936 __out_bcount(size) caddr_t data,
1940 * Read requests which come in through the EFX API expect to
1941 * read the current, active partition.
1943 return ef10_nvram_partn_read_mode(enp, partn, offset, data, size,
1944 MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT);
1947 __checkReturn efx_rc_t
1948 ef10_nvram_partn_erase(
1949 __in efx_nic_t *enp,
1950 __in uint32_t partn,
1951 __in unsigned int offset,
1955 uint32_t erase_size;
1957 if ((rc = efx_mcdi_nvram_info(enp, partn, NULL, NULL,
1958 &erase_size, NULL)) != 0)
1961 if (erase_size == 0) {
1962 if ((rc = efx_mcdi_nvram_erase(enp, partn, offset, size)) != 0)
1965 if (size % erase_size != 0) {
1970 if ((rc = efx_mcdi_nvram_erase(enp, partn, offset,
1973 offset += erase_size;
1987 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1992 __checkReturn efx_rc_t
1993 ef10_nvram_partn_write(
1994 __in efx_nic_t *enp,
1995 __in uint32_t partn,
1996 __in unsigned int offset,
1997 __out_bcount(size) caddr_t data,
2001 uint32_t write_size;
2004 if ((rc = efx_mcdi_nvram_info(enp, partn, NULL, NULL,
2005 NULL, &write_size)) != 0)
2008 if (write_size != 0) {
2010 * Check that the size is a multiple of the write chunk size if
2011 * the write chunk size is available.
2013 if (size % write_size != 0) {
2018 write_size = EF10_NVRAM_CHUNK;
2022 chunk = MIN(size, write_size);
2024 if ((rc = efx_mcdi_nvram_write(enp, partn, offset,
2025 data, chunk)) != 0) {
2041 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2046 __checkReturn efx_rc_t
2047 ef10_nvram_partn_unlock(
2048 __in efx_nic_t *enp,
2049 __in uint32_t partn,
2050 __out_opt uint32_t *resultp)
2052 boolean_t reboot = B_FALSE;
2055 if (resultp != NULL)
2056 *resultp = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN;
2058 rc = efx_mcdi_nvram_update_finish(enp, partn, reboot, resultp);
2065 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2070 __checkReturn efx_rc_t
2071 ef10_nvram_partn_set_version(
2072 __in efx_nic_t *enp,
2073 __in uint32_t partn,
2074 __in_ecount(4) uint16_t version[4])
2076 struct tlv_partition_version partn_version;
2080 /* Add or modify partition version TLV item */
2081 partn_version.version_w = __CPU_TO_LE_16(version[0]);
2082 partn_version.version_x = __CPU_TO_LE_16(version[1]);
2083 partn_version.version_y = __CPU_TO_LE_16(version[2]);
2084 partn_version.version_z = __CPU_TO_LE_16(version[3]);
2086 size = sizeof (partn_version) - (2 * sizeof (uint32_t));
2088 /* Write the version number to all segments in the partition */
2089 if ((rc = ef10_nvram_partn_write_segment_tlv(enp,
2090 NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
2091 TLV_TAG_PARTITION_VERSION(partn),
2092 (caddr_t)&partn_version.version_w, size, B_TRUE)) != 0)
2098 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2103 #endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */
2107 typedef struct ef10_parttbl_entry_s {
2110 efx_nvram_type_t nvtype;
2111 } ef10_parttbl_entry_t;
2113 /* Translate EFX NVRAM types to firmware partition types */
2114 static ef10_parttbl_entry_t hunt_parttbl[] = {
2115 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 1, EFX_NVRAM_MC_FIRMWARE},
2116 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 2, EFX_NVRAM_MC_FIRMWARE},
2117 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 3, EFX_NVRAM_MC_FIRMWARE},
2118 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 4, EFX_NVRAM_MC_FIRMWARE},
2119 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 1, EFX_NVRAM_MC_GOLDEN},
2120 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 2, EFX_NVRAM_MC_GOLDEN},
2121 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 3, EFX_NVRAM_MC_GOLDEN},
2122 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 4, EFX_NVRAM_MC_GOLDEN},
2123 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 1, EFX_NVRAM_BOOTROM},
2124 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 2, EFX_NVRAM_BOOTROM},
2125 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 3, EFX_NVRAM_BOOTROM},
2126 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 4, EFX_NVRAM_BOOTROM},
2127 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 1, EFX_NVRAM_BOOTROM_CFG},
2128 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT1, 2, EFX_NVRAM_BOOTROM_CFG},
2129 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT2, 3, EFX_NVRAM_BOOTROM_CFG},
2130 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT3, 4, EFX_NVRAM_BOOTROM_CFG},
2131 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 1, EFX_NVRAM_DYNAMIC_CFG},
2132 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 2, EFX_NVRAM_DYNAMIC_CFG},
2133 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 3, EFX_NVRAM_DYNAMIC_CFG},
2134 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 4, EFX_NVRAM_DYNAMIC_CFG},
2135 {NVRAM_PARTITION_TYPE_FPGA, 1, EFX_NVRAM_FPGA},
2136 {NVRAM_PARTITION_TYPE_FPGA, 2, EFX_NVRAM_FPGA},
2137 {NVRAM_PARTITION_TYPE_FPGA, 3, EFX_NVRAM_FPGA},
2138 {NVRAM_PARTITION_TYPE_FPGA, 4, EFX_NVRAM_FPGA},
2139 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 1, EFX_NVRAM_FPGA_BACKUP},
2140 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 2, EFX_NVRAM_FPGA_BACKUP},
2141 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 3, EFX_NVRAM_FPGA_BACKUP},
2142 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 4, EFX_NVRAM_FPGA_BACKUP},
2143 {NVRAM_PARTITION_TYPE_LICENSE, 1, EFX_NVRAM_LICENSE},
2144 {NVRAM_PARTITION_TYPE_LICENSE, 2, EFX_NVRAM_LICENSE},
2145 {NVRAM_PARTITION_TYPE_LICENSE, 3, EFX_NVRAM_LICENSE},
2146 {NVRAM_PARTITION_TYPE_LICENSE, 4, EFX_NVRAM_LICENSE}
2149 static ef10_parttbl_entry_t medford_parttbl[] = {
2150 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 1, EFX_NVRAM_MC_FIRMWARE},
2151 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 2, EFX_NVRAM_MC_FIRMWARE},
2152 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 3, EFX_NVRAM_MC_FIRMWARE},
2153 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 4, EFX_NVRAM_MC_FIRMWARE},
2154 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 1, EFX_NVRAM_MC_GOLDEN},
2155 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 2, EFX_NVRAM_MC_GOLDEN},
2156 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 3, EFX_NVRAM_MC_GOLDEN},
2157 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 4, EFX_NVRAM_MC_GOLDEN},
2158 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 1, EFX_NVRAM_BOOTROM},
2159 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 2, EFX_NVRAM_BOOTROM},
2160 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 3, EFX_NVRAM_BOOTROM},
2161 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 4, EFX_NVRAM_BOOTROM},
2162 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 1, EFX_NVRAM_BOOTROM_CFG},
2163 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 2, EFX_NVRAM_BOOTROM_CFG},
2164 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 3, EFX_NVRAM_BOOTROM_CFG},
2165 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 4, EFX_NVRAM_BOOTROM_CFG},
2166 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 1, EFX_NVRAM_DYNAMIC_CFG},
2167 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 2, EFX_NVRAM_DYNAMIC_CFG},
2168 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 3, EFX_NVRAM_DYNAMIC_CFG},
2169 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 4, EFX_NVRAM_DYNAMIC_CFG},
2170 {NVRAM_PARTITION_TYPE_FPGA, 1, EFX_NVRAM_FPGA},
2171 {NVRAM_PARTITION_TYPE_FPGA, 2, EFX_NVRAM_FPGA},
2172 {NVRAM_PARTITION_TYPE_FPGA, 3, EFX_NVRAM_FPGA},
2173 {NVRAM_PARTITION_TYPE_FPGA, 4, EFX_NVRAM_FPGA},
2174 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 1, EFX_NVRAM_FPGA_BACKUP},
2175 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 2, EFX_NVRAM_FPGA_BACKUP},
2176 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 3, EFX_NVRAM_FPGA_BACKUP},
2177 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 4, EFX_NVRAM_FPGA_BACKUP},
2178 {NVRAM_PARTITION_TYPE_LICENSE, 1, EFX_NVRAM_LICENSE},
2179 {NVRAM_PARTITION_TYPE_LICENSE, 2, EFX_NVRAM_LICENSE},
2180 {NVRAM_PARTITION_TYPE_LICENSE, 3, EFX_NVRAM_LICENSE},
2181 {NVRAM_PARTITION_TYPE_LICENSE, 4, EFX_NVRAM_LICENSE},
2182 {NVRAM_PARTITION_TYPE_EXPANSION_UEFI, 1, EFX_NVRAM_UEFIROM},
2183 {NVRAM_PARTITION_TYPE_EXPANSION_UEFI, 2, EFX_NVRAM_UEFIROM},
2184 {NVRAM_PARTITION_TYPE_EXPANSION_UEFI, 3, EFX_NVRAM_UEFIROM},
2185 {NVRAM_PARTITION_TYPE_EXPANSION_UEFI, 4, EFX_NVRAM_UEFIROM}
2188 static __checkReturn efx_rc_t
2190 __in efx_nic_t *enp,
2191 __out ef10_parttbl_entry_t **parttblp,
2192 __out size_t *parttbl_rowsp)
2194 switch (enp->en_family) {
2195 case EFX_FAMILY_HUNTINGTON:
2196 *parttblp = hunt_parttbl;
2197 *parttbl_rowsp = EFX_ARRAY_SIZE(hunt_parttbl);
2200 case EFX_FAMILY_MEDFORD:
2201 *parttblp = medford_parttbl;
2202 *parttbl_rowsp = EFX_ARRAY_SIZE(medford_parttbl);
2206 EFSYS_ASSERT(B_FALSE);
2212 __checkReturn efx_rc_t
2213 ef10_nvram_type_to_partn(
2214 __in efx_nic_t *enp,
2215 __in efx_nvram_type_t type,
2216 __out uint32_t *partnp)
2218 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
2219 ef10_parttbl_entry_t *parttbl = NULL;
2220 size_t parttbl_rows = 0;
2223 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
2224 EFSYS_ASSERT(partnp != NULL);
2226 if (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) {
2227 for (i = 0; i < parttbl_rows; i++) {
2228 ef10_parttbl_entry_t *entry = &parttbl[i];
2230 if (entry->nvtype == type &&
2231 entry->port == emip->emi_port) {
2232 *partnp = entry->partn;
2243 static __checkReturn efx_rc_t
2244 ef10_nvram_partn_to_type(
2245 __in efx_nic_t *enp,
2246 __in uint32_t partn,
2247 __out efx_nvram_type_t *typep)
2249 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
2250 ef10_parttbl_entry_t *parttbl = NULL;
2251 size_t parttbl_rows = 0;
2254 EFSYS_ASSERT(typep != NULL);
2256 if (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) {
2257 for (i = 0; i < parttbl_rows; i++) {
2258 ef10_parttbl_entry_t *entry = &parttbl[i];
2260 if (entry->partn == partn &&
2261 entry->port == emip->emi_port) {
2262 *typep = entry->nvtype;
2271 __checkReturn efx_rc_t
2273 __in efx_nic_t *enp)
2275 efx_nvram_type_t type;
2276 unsigned int npartns = 0;
2277 uint32_t *partns = NULL;
2282 /* Read available partitions from NVRAM partition map */
2283 size = MC_CMD_NVRAM_PARTITIONS_OUT_TYPE_ID_MAXNUM * sizeof (uint32_t);
2284 EFSYS_KMEM_ALLOC(enp->en_esip, size, partns);
2285 if (partns == NULL) {
2290 if ((rc = efx_mcdi_nvram_partitions(enp, (caddr_t)partns, size,
2295 for (i = 0; i < npartns; i++) {
2296 /* Check if the partition is supported for this port */
2297 if ((rc = ef10_nvram_partn_to_type(enp, partns[i], &type)) != 0)
2300 if ((rc = efx_mcdi_nvram_test(enp, partns[i])) != 0)
2304 EFSYS_KMEM_FREE(enp->en_esip, size, partns);
2311 EFSYS_KMEM_FREE(enp->en_esip, size, partns);
2313 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2317 #endif /* EFSYS_OPT_DIAG */
2319 __checkReturn efx_rc_t
2320 ef10_nvram_partn_get_version(
2321 __in efx_nic_t *enp,
2322 __in uint32_t partn,
2323 __out uint32_t *subtypep,
2324 __out_ecount(4) uint16_t version[4])
2328 /* FIXME: get highest partn version from all ports */
2329 /* FIXME: return partn description if available */
2331 if ((rc = efx_mcdi_nvram_metadata(enp, partn, subtypep,
2332 version, NULL, 0)) != 0)
2338 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2343 __checkReturn efx_rc_t
2344 ef10_nvram_partn_rw_start(
2345 __in efx_nic_t *enp,
2346 __in uint32_t partn,
2347 __out size_t *chunk_sizep)
2351 if ((rc = ef10_nvram_partn_lock(enp, partn)) != 0)
2354 if (chunk_sizep != NULL)
2355 *chunk_sizep = EF10_NVRAM_CHUNK;
2360 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2365 __checkReturn efx_rc_t
2366 ef10_nvram_partn_rw_finish(
2367 __in efx_nic_t *enp,
2368 __in uint32_t partn)
2372 if ((rc = ef10_nvram_partn_unlock(enp, partn, NULL)) != 0)
2378 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2383 #endif /* EFSYS_OPT_NVRAM */
2385 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */