1 /* SPDX-License-Identifier: BSD-3-Clause
3 * Copyright(c) 2019-2021 Xilinx, Inc.
4 * Copyright(c) 2012-2019 Solarflare Communications Inc.
12 #if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
14 #include "ef10_tlv_layout.h"
16 /* Cursor for TLV partition format */
17 typedef struct tlv_cursor_s {
18 uint32_t *block; /* Base of data block */
19 uint32_t *current; /* Cursor position */
20 uint32_t *end; /* End tag position */
21 uint32_t *limit; /* Last dword of data block */
24 typedef struct nvram_partition_s {
29 * The full length of the NVRAM partition.
30 * This is different from tlv_partition_header.total_length,
31 * which can be smaller.
36 tlv_cursor_t tlv_cursor;
40 static __checkReturn efx_rc_t
42 __inout tlv_cursor_t *cursor);
47 __out uint32_t *block)
49 *block = __CPU_TO_LE_32(TLV_TAG_END);
54 __in tlv_cursor_t *cursor)
58 dword = cursor->current[0];
59 tag = __LE_TO_CPU_32(dword);
66 __in tlv_cursor_t *cursor)
68 uint32_t dword, length;
70 if (tlv_tag(cursor) == TLV_TAG_END)
73 dword = cursor->current[1];
74 length = __LE_TO_CPU_32(dword);
76 return ((size_t)length);
81 __in tlv_cursor_t *cursor)
83 if (tlv_tag(cursor) == TLV_TAG_END)
86 return ((uint8_t *)(&cursor->current[2]));
91 __in tlv_cursor_t *cursor)
93 if (tlv_tag(cursor) == TLV_TAG_END)
96 return ((uint8_t *)cursor->current);
100 * TLV item DWORD length is tag + length + value (rounded up to DWORD)
101 * equivalent to tlv_n_words_for_len in mc-comms tlv.c
103 #define TLV_DWORD_COUNT(length) \
104 (1 + 1 + (((length) + sizeof (uint32_t) - 1) / sizeof (uint32_t)))
109 __in tlv_cursor_t *cursor)
113 length = tlv_length(cursor);
115 return (cursor->current + TLV_DWORD_COUNT(length));
118 static __checkReturn efx_rc_t
120 __inout tlv_cursor_t *cursor)
124 if ((rc = tlv_validate_state(cursor)) != 0)
127 if (cursor->current == cursor->end) {
128 /* No more tags after END tag */
129 cursor->current = NULL;
134 /* Advance to next item and validate */
135 cursor->current = tlv_next_item_ptr(cursor);
137 if ((rc = tlv_validate_state(cursor)) != 0)
147 EFSYS_PROBE1(fail1, efx_rc_t, rc);
154 __in tlv_cursor_t *cursor)
158 cursor->current = cursor->block;
160 if ((rc = tlv_validate_state(cursor)) != 0)
166 EFSYS_PROBE1(fail1, efx_rc_t, rc);
173 __inout tlv_cursor_t *cursor,
178 rc = tlv_rewind(cursor);
180 if (tlv_tag(cursor) == tag)
183 rc = tlv_advance(cursor);
188 static __checkReturn efx_rc_t
190 __inout tlv_cursor_t *cursor)
194 /* Check cursor position */
195 if (cursor->current < cursor->block) {
199 if (cursor->current > cursor->limit) {
204 if (tlv_tag(cursor) != TLV_TAG_END) {
205 /* Check current item has space for tag and length */
206 if (cursor->current > (cursor->limit - 1)) {
207 cursor->current = NULL;
212 /* Check we have value data for current item and an END tag */
213 if (tlv_next_item_ptr(cursor) > cursor->limit) {
214 cursor->current = NULL;
229 EFSYS_PROBE1(fail1, efx_rc_t, rc);
236 __out tlv_cursor_t *cursor,
237 __in uint32_t *block,
238 __in uint32_t *limit,
239 __in uint32_t *current)
241 cursor->block = block;
242 cursor->limit = limit;
244 cursor->current = current;
247 return (tlv_validate_state(cursor));
250 static __checkReturn efx_rc_t
251 tlv_init_cursor_from_size(
252 __out tlv_cursor_t *cursor,
258 limit = (uint32_t *)(block + size - sizeof (uint32_t));
259 return (tlv_init_cursor(cursor, (uint32_t *)block,
260 limit, (uint32_t *)block));
263 static __checkReturn efx_rc_t
264 tlv_init_cursor_at_offset(
265 __out tlv_cursor_t *cursor,
273 limit = (uint32_t *)(block + size - sizeof (uint32_t));
274 current = (uint32_t *)(block + offset);
275 return (tlv_init_cursor(cursor, (uint32_t *)block, limit, current));
278 static __checkReturn efx_rc_t
280 __inout tlv_cursor_t *cursor)
285 if (cursor->end == NULL) {
286 pos = cursor->current;
287 if ((rc = tlv_find(cursor, TLV_TAG_END)) != 0)
290 cursor->end = cursor->current;
291 cursor->current = pos;
297 EFSYS_PROBE1(fail1, efx_rc_t, rc);
303 tlv_block_length_used(
304 __inout tlv_cursor_t *cursor)
308 if ((rc = tlv_validate_state(cursor)) != 0)
311 if ((rc = tlv_require_end(cursor)) != 0)
314 /* Return space used (including the END tag) */
315 return (cursor->end + 1 - cursor->block) * sizeof (uint32_t);
320 EFSYS_PROBE1(fail1, efx_rc_t, rc);
326 tlv_last_segment_end(
327 __in tlv_cursor_t *cursor)
329 tlv_cursor_t segment_cursor;
330 uint32_t *last_segment_end = cursor->block;
331 uint32_t *segment_start = cursor->block;
334 * Go through each segment and check that it has an end tag. If there
335 * is no end tag then the previous segment was the last valid one,
336 * so return the pointer to its end tag.
339 if (tlv_init_cursor(&segment_cursor, segment_start,
340 cursor->limit, segment_start) != 0)
342 if (tlv_require_end(&segment_cursor) != 0)
344 last_segment_end = segment_cursor.end;
345 segment_start = segment_cursor.end + 1;
348 return (last_segment_end);
354 __in tlv_cursor_t *cursor,
356 __in_bcount(size) uint8_t *data,
362 ptr = cursor->current;
364 *ptr++ = __CPU_TO_LE_32(tag);
365 *ptr++ = __CPU_TO_LE_32(len);
368 ptr[(len - 1) / sizeof (uint32_t)] = 0;
369 memcpy(ptr, data, len);
370 ptr += EFX_P2ROUNDUP(uint32_t, len,
371 sizeof (uint32_t)) / sizeof (*ptr);
377 static __checkReturn efx_rc_t
379 __inout tlv_cursor_t *cursor,
386 uint32_t *last_segment_end;
389 if ((rc = tlv_validate_state(cursor)) != 0)
392 if ((rc = tlv_require_end(cursor)) != 0)
395 if (tag == TLV_TAG_END) {
400 last_segment_end = tlv_last_segment_end(cursor);
402 delta = TLV_DWORD_COUNT(size);
403 if (last_segment_end + 1 + delta > cursor->limit) {
408 /* Move data up: new space at cursor->current */
409 memmove(cursor->current + delta, cursor->current,
410 (last_segment_end + 1 - cursor->current) * sizeof (uint32_t));
412 /* Adjust the end pointer */
413 cursor->end += delta;
415 /* Write new TLV item */
416 tlv_write(cursor, tag, data, size);
427 EFSYS_PROBE1(fail1, efx_rc_t, rc);
432 static __checkReturn efx_rc_t
434 __inout tlv_cursor_t *cursor)
437 uint32_t *last_segment_end;
440 if ((rc = tlv_validate_state(cursor)) != 0)
443 if (tlv_tag(cursor) == TLV_TAG_END) {
448 delta = TLV_DWORD_COUNT(tlv_length(cursor));
450 if ((rc = tlv_require_end(cursor)) != 0)
453 last_segment_end = tlv_last_segment_end(cursor);
455 /* Shuffle things down, destroying the item at cursor->current */
456 memmove(cursor->current, cursor->current + delta,
457 (last_segment_end + 1 - cursor->current) * sizeof (uint32_t));
458 /* Zero the new space at the end of the TLV chain */
459 memset(last_segment_end + 1 - delta, 0, delta * sizeof (uint32_t));
460 /* Adjust the end pointer */
461 cursor->end -= delta;
470 EFSYS_PROBE1(fail1, efx_rc_t, rc);
475 static __checkReturn efx_rc_t
477 __inout tlv_cursor_t *cursor,
484 unsigned int old_ndwords;
485 unsigned int new_ndwords;
487 uint32_t *last_segment_end;
490 if ((rc = tlv_validate_state(cursor)) != 0)
493 if (tlv_tag(cursor) == TLV_TAG_END) {
497 if (tlv_tag(cursor) != tag) {
502 old_ndwords = TLV_DWORD_COUNT(tlv_length(cursor));
503 new_ndwords = TLV_DWORD_COUNT(size);
505 if ((rc = tlv_require_end(cursor)) != 0)
508 last_segment_end = tlv_last_segment_end(cursor);
510 if (new_ndwords > old_ndwords) {
511 /* Expand space used for TLV item */
512 delta = new_ndwords - old_ndwords;
513 pos = cursor->current + old_ndwords;
515 if (last_segment_end + 1 + delta > cursor->limit) {
520 /* Move up: new space at (cursor->current + old_ndwords) */
521 memmove(pos + delta, pos,
522 (last_segment_end + 1 - pos) * sizeof (uint32_t));
524 /* Adjust the end pointer */
525 cursor->end += delta;
527 } else if (new_ndwords < old_ndwords) {
528 /* Shrink space used for TLV item */
529 delta = old_ndwords - new_ndwords;
530 pos = cursor->current + new_ndwords;
532 /* Move down: remove words at (cursor->current + new_ndwords) */
533 memmove(pos, pos + delta,
534 (last_segment_end + 1 - pos) * sizeof (uint32_t));
536 /* Zero the new space at the end of the TLV chain */
537 memset(last_segment_end + 1 - delta, 0,
538 delta * sizeof (uint32_t));
540 /* Adjust the end pointer */
541 cursor->end -= delta;
545 tlv_write(cursor, tag, data, size);
558 EFSYS_PROBE1(fail1, efx_rc_t, rc);
563 static uint32_t checksum_tlv_partition(
564 __in nvram_partition_t *partition)
566 tlv_cursor_t *cursor;
572 cursor = &partition->tlv_cursor;
573 len = tlv_block_length_used(cursor);
574 EFSYS_ASSERT3U((len & 3), ==, 0);
577 ptr = partition->data;
578 end = &ptr[len >> 2];
581 csum += __LE_TO_CPU_32(*ptr++);
586 static __checkReturn efx_rc_t
587 tlv_update_partition_len_and_cks(
588 __in tlv_cursor_t *cursor)
591 nvram_partition_t partition;
592 struct tlv_partition_header *header;
593 struct tlv_partition_trailer *trailer;
597 * We just modified the partition, so the total length may not be
598 * valid. Don't use tlv_find(), which performs some sanity checks
599 * that may fail here.
601 partition.data = cursor->block;
602 memcpy(&partition.tlv_cursor, cursor, sizeof (*cursor));
603 header = (struct tlv_partition_header *)partition.data;
605 if (__LE_TO_CPU_32(header->tag) != TLV_TAG_PARTITION_HEADER) {
609 new_len = tlv_block_length_used(&partition.tlv_cursor);
614 header->total_length = __CPU_TO_LE_32(new_len);
615 /* Ensure the modified partition always has a new generation count. */
616 header->generation = __CPU_TO_LE_32(
617 __LE_TO_CPU_32(header->generation) + 1);
619 trailer = (struct tlv_partition_trailer *)((uint8_t *)header +
620 new_len - sizeof (*trailer) - sizeof (uint32_t));
621 trailer->generation = header->generation;
622 trailer->checksum = __CPU_TO_LE_32(
623 __LE_TO_CPU_32(trailer->checksum) -
624 checksum_tlv_partition(&partition));
631 EFSYS_PROBE1(fail1, efx_rc_t, rc);
636 /* Validate buffer contents (before writing to flash) */
637 __checkReturn efx_rc_t
638 ef10_nvram_buffer_validate(
640 __in_bcount(partn_size) caddr_t partn_data,
641 __in size_t partn_size)
644 struct tlv_partition_header *header;
645 struct tlv_partition_trailer *trailer;
651 EFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK);
653 if ((partn_data == NULL) || (partn_size == 0)) {
658 /* The partition header must be the first item (at offset zero) */
659 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)partn_data,
664 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
668 header = (struct tlv_partition_header *)tlv_item(&cursor);
670 /* Check TLV partition length (includes the END tag) */
671 total_length = __LE_TO_CPU_32(header->total_length);
672 if (total_length > partn_size) {
677 /* Check partition header matches partn */
678 if (__LE_TO_CPU_16(header->type_id) != partn) {
683 /* Check partition ends with PARTITION_TRAILER and END tags */
684 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {
688 trailer = (struct tlv_partition_trailer *)tlv_item(&cursor);
690 if ((rc = tlv_advance(&cursor)) != 0) {
694 if (tlv_tag(&cursor) != TLV_TAG_END) {
699 /* Check generation counts are consistent */
700 if (trailer->generation != header->generation) {
705 /* Verify partition checksum */
707 for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) {
708 cksum += *((uint32_t *)(partn_data + pos));
736 EFSYS_PROBE1(fail1, efx_rc_t, rc);
742 ef10_nvram_buffer_init(
743 __out_bcount(buffer_size)
745 __in size_t buffer_size)
747 uint32_t *buf = (uint32_t *)bufferp;
749 memset(buf, 0xff, buffer_size);
754 __checkReturn efx_rc_t
755 ef10_nvram_buffer_create(
756 __in uint32_t partn_type,
757 __out_bcount(partn_size)
759 __in size_t partn_size)
761 uint32_t *buf = (uint32_t *)partn_data;
764 struct tlv_partition_header header;
765 struct tlv_partition_trailer trailer;
767 unsigned int min_buf_size = sizeof (struct tlv_partition_header) +
768 sizeof (struct tlv_partition_trailer);
769 if (partn_size < min_buf_size) {
774 ef10_nvram_buffer_init(partn_data, partn_size);
776 if ((rc = tlv_init_cursor(&cursor, buf,
777 (uint32_t *)((uint8_t *)buf + partn_size),
782 header.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_HEADER);
783 header.length = __CPU_TO_LE_32(sizeof (header) - 8);
784 header.type_id = __CPU_TO_LE_16(partn_type);
786 header.generation = __CPU_TO_LE_32(1);
787 header.total_length = 0; /* This will be fixed below. */
788 if ((rc = tlv_insert(
789 &cursor, TLV_TAG_PARTITION_HEADER,
790 (uint8_t *)&header.type_id, sizeof (header) - 8)) != 0)
792 if ((rc = tlv_advance(&cursor)) != 0)
795 trailer.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_TRAILER);
796 trailer.length = __CPU_TO_LE_32(sizeof (trailer) - 8);
797 trailer.generation = header.generation;
798 trailer.checksum = 0; /* This will be fixed below. */
799 if ((rc = tlv_insert(&cursor, TLV_TAG_PARTITION_TRAILER,
800 (uint8_t *)&trailer.generation, sizeof (trailer) - 8)) != 0)
803 if ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0)
806 /* Check that the partition is valid. */
807 if ((rc = ef10_nvram_buffer_validate(partn_type,
808 partn_data, partn_size)) != 0)
826 EFSYS_PROBE1(fail1, efx_rc_t, rc);
833 __in uint32_t *position,
836 return (uint32_t)((uint8_t *)position - (uint8_t *)base);
839 __checkReturn efx_rc_t
840 ef10_nvram_buffer_find_item_start(
841 __in_bcount(buffer_size)
843 __in size_t buffer_size,
844 __out uint32_t *startp)
846 /* Read past partition header to find start address of the first key */
850 /* A PARTITION_HEADER tag must be the first item (at offset zero) */
851 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp,
852 buffer_size)) != 0) {
856 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
861 if ((rc = tlv_advance(&cursor)) != 0) {
865 *startp = byte_offset(cursor.current, cursor.block);
867 if ((rc = tlv_require_end(&cursor)) != 0)
879 EFSYS_PROBE1(fail1, efx_rc_t, rc);
884 __checkReturn efx_rc_t
885 ef10_nvram_buffer_find_end(
886 __in_bcount(buffer_size)
888 __in size_t buffer_size,
889 __in uint32_t offset,
890 __out uint32_t *endp)
892 /* Read to end of partition */
895 uint32_t *segment_used;
897 _NOTE(ARGUNUSED(offset))
899 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp,
900 buffer_size)) != 0) {
905 segment_used = cursor.block;
908 * Go through each segment and check that it has an end tag. If there
909 * is no end tag then the previous segment was the last valid one,
910 * so return the used space including that end tag.
912 while (tlv_tag(&cursor) == TLV_TAG_PARTITION_HEADER) {
913 if (tlv_require_end(&cursor) != 0) {
914 if (segment_used == cursor.block) {
916 * First segment is corrupt, so there is
917 * no valid data in partition.
924 segment_used = cursor.end + 1;
926 cursor.current = segment_used;
928 /* Return space used (including the END tag) */
929 *endp = (segment_used - cursor.block) * sizeof (uint32_t);
936 EFSYS_PROBE1(fail1, efx_rc_t, rc);
941 __checkReturn __success(return != B_FALSE) boolean_t
942 ef10_nvram_buffer_find_item(
943 __in_bcount(buffer_size)
945 __in size_t buffer_size,
946 __in uint32_t offset,
947 __out uint32_t *startp,
948 __out uint32_t *lengthp)
950 /* Find TLV at offset and return key start and length */
955 if (tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,
956 buffer_size, offset) != 0) {
960 while ((key = tlv_item(&cursor)) != NULL) {
961 tag = tlv_tag(&cursor);
962 if (tag == TLV_TAG_PARTITION_HEADER ||
963 tag == TLV_TAG_PARTITION_TRAILER) {
964 if (tlv_advance(&cursor) != 0) {
969 *startp = byte_offset(cursor.current, cursor.block);
970 *lengthp = byte_offset(tlv_next_item_ptr(&cursor),
978 __checkReturn efx_rc_t
979 ef10_nvram_buffer_peek_item(
980 __in_bcount(buffer_size)
982 __in size_t buffer_size,
983 __in uint32_t offset,
984 __out uint32_t *tagp,
985 __out uint32_t *lengthp,
986 __out uint32_t *value_offsetp)
992 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,
993 buffer_size, offset)) != 0) {
997 tag = tlv_tag(&cursor);
999 if (tag == TLV_TAG_END) {
1001 * To allow stepping over the END tag, report the full tag
1002 * length and a zero length value.
1004 *lengthp = sizeof (tag);
1005 *value_offsetp = sizeof (tag);
1007 *lengthp = byte_offset(tlv_next_item_ptr(&cursor),
1009 *value_offsetp = byte_offset((uint32_t *)tlv_value(&cursor),
1015 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1020 __checkReturn efx_rc_t
1021 ef10_nvram_buffer_get_item(
1022 __in_bcount(buffer_size)
1024 __in size_t buffer_size,
1025 __in uint32_t offset,
1026 __in uint32_t length,
1027 __out uint32_t *tagp,
1028 __out_bcount_part(value_max_size, *lengthp)
1030 __in size_t value_max_size,
1031 __out uint32_t *lengthp)
1034 tlv_cursor_t cursor;
1035 uint32_t value_length;
1037 if (buffer_size < (offset + length)) {
1042 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,
1043 buffer_size, offset)) != 0) {
1047 value_length = tlv_length(&cursor);
1048 if (value_max_size < value_length) {
1052 memcpy(valuep, tlv_value(&cursor), value_length);
1054 *tagp = tlv_tag(&cursor);
1055 *lengthp = value_length;
1064 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1069 __checkReturn efx_rc_t
1070 ef10_nvram_buffer_insert_item(
1071 __in_bcount(buffer_size)
1073 __in size_t buffer_size,
1074 __in uint32_t offset,
1076 __in_bcount(length) caddr_t valuep,
1077 __in uint32_t length,
1078 __out uint32_t *lengthp)
1081 tlv_cursor_t cursor;
1083 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,
1084 buffer_size, offset)) != 0) {
1088 rc = tlv_insert(&cursor, tag, (uint8_t *)valuep, length);
1093 *lengthp = byte_offset(tlv_next_item_ptr(&cursor),
1101 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1106 __checkReturn efx_rc_t
1107 ef10_nvram_buffer_modify_item(
1108 __in_bcount(buffer_size)
1110 __in size_t buffer_size,
1111 __in uint32_t offset,
1113 __in_bcount(length) caddr_t valuep,
1114 __in uint32_t length,
1115 __out uint32_t *lengthp)
1118 tlv_cursor_t cursor;
1120 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,
1121 buffer_size, offset)) != 0) {
1125 rc = tlv_modify(&cursor, tag, (uint8_t *)valuep, length);
1131 *lengthp = byte_offset(tlv_next_item_ptr(&cursor),
1139 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1145 __checkReturn efx_rc_t
1146 ef10_nvram_buffer_delete_item(
1147 __in_bcount(buffer_size)
1149 __in size_t buffer_size,
1150 __in uint32_t offset,
1151 __in uint32_t length,
1155 tlv_cursor_t cursor;
1157 _NOTE(ARGUNUSED(length, end))
1159 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,
1160 buffer_size, offset)) != 0) {
1164 if ((rc = tlv_delete(&cursor)) != 0)
1172 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1177 __checkReturn efx_rc_t
1178 ef10_nvram_buffer_finish(
1179 __in_bcount(buffer_size)
1181 __in size_t buffer_size)
1184 tlv_cursor_t cursor;
1186 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp,
1187 buffer_size)) != 0) {
1192 if ((rc = tlv_require_end(&cursor)) != 0)
1195 if ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0)
1205 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1213 * Read and validate a segment from a partition. A segment is a complete
1214 * tlv chain between PARTITION_HEADER and PARTITION_END tags. There may
1215 * be multiple segments in a partition, so seg_offset allows segments
1216 * beyond the first to be read.
1218 static __checkReturn efx_rc_t
1219 ef10_nvram_read_tlv_segment(
1220 __in efx_nic_t *enp,
1221 __in uint32_t partn,
1222 __in size_t seg_offset,
1223 __in_bcount(max_seg_size) caddr_t seg_data,
1224 __in size_t max_seg_size)
1226 tlv_cursor_t cursor;
1227 struct tlv_partition_header *header;
1228 struct tlv_partition_trailer *trailer;
1229 size_t total_length;
1234 EFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK);
1236 if ((seg_data == NULL) || (max_seg_size == 0)) {
1241 /* Read initial chunk of the segment, starting at offset */
1242 if ((rc = ef10_nvram_partn_read_mode(enp, partn, seg_offset, seg_data,
1244 MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0) {
1248 /* A PARTITION_HEADER tag must be the first item at the given offset */
1249 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data,
1250 max_seg_size)) != 0) {
1254 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
1258 header = (struct tlv_partition_header *)tlv_item(&cursor);
1260 /* Check TLV segment length (includes the END tag) */
1261 total_length = __LE_TO_CPU_32(header->total_length);
1262 if (total_length > max_seg_size) {
1267 /* Read the remaining segment content */
1268 if (total_length > EF10_NVRAM_CHUNK) {
1269 if ((rc = ef10_nvram_partn_read_mode(enp, partn,
1270 seg_offset + EF10_NVRAM_CHUNK,
1271 seg_data + EF10_NVRAM_CHUNK,
1272 total_length - EF10_NVRAM_CHUNK,
1273 MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0)
1277 /* Check segment ends with PARTITION_TRAILER and END tags */
1278 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {
1282 trailer = (struct tlv_partition_trailer *)tlv_item(&cursor);
1284 if ((rc = tlv_advance(&cursor)) != 0) {
1288 if (tlv_tag(&cursor) != TLV_TAG_END) {
1293 /* Check data read from segment is consistent */
1294 if (trailer->generation != header->generation) {
1296 * The partition data may have been modified between successive
1297 * MCDI NVRAM_READ requests by the MC or another PCI function.
1299 * The caller must retry to obtain consistent partition data.
1305 /* Verify segment checksum */
1307 for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) {
1308 cksum += *((uint32_t *)(seg_data + pos));
1318 EFSYS_PROBE(fail11);
1320 EFSYS_PROBE(fail10);
1338 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1344 * Read a single TLV item from a host memory
1345 * buffer containing a TLV formatted segment.
1347 __checkReturn efx_rc_t
1348 ef10_nvram_buf_read_tlv(
1349 __in efx_nic_t *enp,
1350 __in_bcount(max_seg_size) caddr_t seg_data,
1351 __in size_t max_seg_size,
1353 __deref_out_bcount_opt(*sizep) caddr_t *datap,
1354 __out size_t *sizep)
1356 tlv_cursor_t cursor;
1362 _NOTE(ARGUNUSED(enp))
1364 if ((seg_data == NULL) || (max_seg_size == 0)) {
1369 /* Find requested TLV tag in segment data */
1370 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data,
1371 max_seg_size)) != 0) {
1375 if ((rc = tlv_find(&cursor, tag)) != 0) {
1379 value = (caddr_t)tlv_value(&cursor);
1380 length = tlv_length(&cursor);
1385 /* Copy out data from TLV item */
1386 EFSYS_KMEM_ALLOC(enp->en_esip, length, data);
1391 memcpy(data, value, length);
1406 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1411 /* Read a single TLV item from the first segment in a TLV formatted partition */
1412 __checkReturn efx_rc_t
1413 ef10_nvram_partn_read_tlv(
1414 __in efx_nic_t *enp,
1415 __in uint32_t partn,
1417 __deref_out_bcount_opt(*seg_sizep) caddr_t *seg_datap,
1418 __out size_t *seg_sizep)
1420 caddr_t seg_data = NULL;
1421 size_t partn_size = 0;
1427 /* Allocate sufficient memory for the entire partition */
1428 if ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0)
1431 if (partn_size == 0) {
1436 EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, seg_data);
1437 if (seg_data == NULL) {
1443 * Read the first segment in a TLV partition. Retry until consistent
1444 * segment contents are returned. Inconsistent data may be read if:
1445 * a) the segment contents are invalid
1446 * b) the MC has rebooted while we were reading the partition
1447 * c) the partition has been modified while we were reading it
1448 * Limit retry attempts to ensure forward progress.
1452 if ((rc = ef10_nvram_read_tlv_segment(enp, partn, 0,
1453 seg_data, partn_size)) != 0)
1455 } while ((rc == EAGAIN) && (retry > 0));
1458 /* Failed to obtain consistent segment data */
1465 if ((rc = ef10_nvram_buf_read_tlv(enp, seg_data, partn_size,
1466 tag, &data, &length)) != 0)
1469 EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data);
1472 *seg_sizep = length;
1481 EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data);
1487 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1492 /* Compute the size of a segment. */
1493 static __checkReturn efx_rc_t
1494 ef10_nvram_buf_segment_size(
1495 __in caddr_t seg_data,
1496 __in size_t max_seg_size,
1497 __out size_t *seg_sizep)
1500 tlv_cursor_t cursor;
1501 struct tlv_partition_header *header;
1504 uint32_t *end_tag_position;
1505 uint32_t segment_length;
1507 /* A PARTITION_HEADER tag must be the first item at the given offset */
1508 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data,
1509 max_seg_size)) != 0) {
1513 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
1517 header = (struct tlv_partition_header *)tlv_item(&cursor);
1519 /* Check TLV segment length (includes the END tag) */
1520 *seg_sizep = __LE_TO_CPU_32(header->total_length);
1521 if (*seg_sizep > max_seg_size) {
1526 /* Check segment ends with PARTITION_TRAILER and END tags */
1527 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {
1532 if ((rc = tlv_advance(&cursor)) != 0) {
1536 if (tlv_tag(&cursor) != TLV_TAG_END) {
1540 end_tag_position = cursor.current;
1542 /* Verify segment checksum */
1544 for (pos = 0; (size_t)pos < *seg_sizep; pos += sizeof (uint32_t)) {
1545 cksum += *((uint32_t *)(seg_data + pos));
1553 * Calculate total length from HEADER to END tags and compare to
1554 * max_seg_size and the total_length field in the HEADER tag.
1556 segment_length = tlv_block_length_used(&cursor);
1558 if (segment_length > max_seg_size) {
1563 if (segment_length != *seg_sizep) {
1568 /* Skip over the first HEADER tag. */
1569 rc = tlv_rewind(&cursor);
1570 rc = tlv_advance(&cursor);
1573 if (tlv_tag(&cursor) == TLV_TAG_END) {
1574 /* Check that the END tag is the one found earlier. */
1575 if (cursor.current != end_tag_position)
1579 /* Check for duplicate HEADER tags before the END tag. */
1580 if (tlv_tag(&cursor) == TLV_TAG_PARTITION_HEADER) {
1585 rc = tlv_advance(&cursor);
1593 EFSYS_PROBE(fail12);
1595 EFSYS_PROBE(fail11);
1597 EFSYS_PROBE(fail10);
1615 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1621 * Add or update a single TLV item in a host memory buffer containing a TLV
1622 * formatted segment. Historically partitions consisted of only one segment.
1624 __checkReturn efx_rc_t
1625 ef10_nvram_buf_write_tlv(
1626 __inout_bcount(max_seg_size) caddr_t seg_data,
1627 __in size_t max_seg_size,
1629 __in_bcount(tag_size) caddr_t tag_data,
1630 __in size_t tag_size,
1631 __out size_t *total_lengthp)
1633 tlv_cursor_t cursor;
1634 struct tlv_partition_header *header;
1635 struct tlv_partition_trailer *trailer;
1636 uint32_t generation;
1641 /* A PARTITION_HEADER tag must be the first item (at offset zero) */
1642 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data,
1643 max_seg_size)) != 0) {
1647 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
1651 header = (struct tlv_partition_header *)tlv_item(&cursor);
1653 /* Update the TLV chain to contain the new data */
1654 if ((rc = tlv_find(&cursor, tag)) == 0) {
1655 /* Modify existing TLV item */
1656 if ((rc = tlv_modify(&cursor, tag,
1657 (uint8_t *)tag_data, tag_size)) != 0)
1660 /* Insert a new TLV item before the PARTITION_TRAILER */
1661 rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER);
1666 if ((rc = tlv_insert(&cursor, tag,
1667 (uint8_t *)tag_data, tag_size)) != 0) {
1673 /* Find the trailer tag */
1674 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {
1678 trailer = (struct tlv_partition_trailer *)tlv_item(&cursor);
1680 /* Update PARTITION_HEADER and PARTITION_TRAILER fields */
1681 *total_lengthp = tlv_block_length_used(&cursor);
1682 if (*total_lengthp > max_seg_size) {
1686 generation = __LE_TO_CPU_32(header->generation) + 1;
1688 header->total_length = __CPU_TO_LE_32(*total_lengthp);
1689 header->generation = __CPU_TO_LE_32(generation);
1690 trailer->generation = __CPU_TO_LE_32(generation);
1692 /* Recompute PARTITION_TRAILER checksum */
1693 trailer->checksum = 0;
1695 for (pos = 0; (size_t)pos < *total_lengthp; pos += sizeof (uint32_t)) {
1696 cksum += *((uint32_t *)(seg_data + pos));
1698 trailer->checksum = ~cksum + 1;
1715 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1721 * Add or update a single TLV item in the first segment of a TLV formatted
1722 * dynamic config partition. The first segment is the current active
1725 __checkReturn efx_rc_t
1726 ef10_nvram_partn_write_tlv(
1727 __in efx_nic_t *enp,
1728 __in uint32_t partn,
1730 __in_bcount(size) caddr_t data,
1733 return ef10_nvram_partn_write_segment_tlv(enp, partn, tag, data,
1738 * Read a segment from nvram at the given offset into a buffer (segment_data)
1739 * and optionally write a new tag to it.
1741 static __checkReturn efx_rc_t
1742 ef10_nvram_segment_write_tlv(
1743 __in efx_nic_t *enp,
1744 __in uint32_t partn,
1746 __in_bcount(size) caddr_t data,
1748 __inout caddr_t *seg_datap,
1749 __inout size_t *partn_offsetp,
1750 __inout size_t *src_remain_lenp,
1751 __inout size_t *dest_remain_lenp,
1752 __in boolean_t write)
1756 size_t original_segment_size;
1757 size_t modified_segment_size;
1760 * Read the segment from NVRAM into the segment_data buffer and validate
1761 * it, returning if it does not validate. This is not a failure unless
1762 * this is the first segment in a partition. In this case the caller
1763 * must propagate the error.
1765 status = ef10_nvram_read_tlv_segment(enp, partn, *partn_offsetp,
1766 *seg_datap, *src_remain_lenp);
1772 status = ef10_nvram_buf_segment_size(*seg_datap,
1773 *src_remain_lenp, &original_segment_size);
1780 /* Update the contents of the segment in the buffer */
1781 if ((rc = ef10_nvram_buf_write_tlv(*seg_datap,
1782 *dest_remain_lenp, tag, data, size,
1783 &modified_segment_size)) != 0) {
1786 *dest_remain_lenp -= modified_segment_size;
1787 *seg_datap += modified_segment_size;
1790 * We won't modify this segment, but still need to update the
1791 * remaining lengths and pointers.
1793 *dest_remain_lenp -= original_segment_size;
1794 *seg_datap += original_segment_size;
1797 *partn_offsetp += original_segment_size;
1798 *src_remain_lenp -= original_segment_size;
1807 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1813 * Add or update a single TLV item in either the first segment or in all
1814 * segments in a TLV formatted dynamic config partition. Dynamic config
1815 * partitions on boards that support RFID are divided into a number of segments,
1816 * each formatted like a partition, with header, trailer and end tags. The first
1817 * segment is the current active configuration.
1819 * The segments are initialised by manftest and each contain a different
1820 * configuration e.g. firmware variant. The firmware can be instructed
1821 * via RFID to copy a segment to replace the first segment, hence changing the
1822 * active configuration. This allows ops to change the configuration of a board
1823 * prior to shipment using RFID.
1825 * Changes to the dynamic config may need to be written to all segments (e.g.
1826 * firmware versions) or just the first segment (changes to the active
1827 * configuration). See SF-111324-SW "The use of RFID in Solarflare Products".
1828 * If only the first segment is written the code still needs to be aware of the
1829 * possible presence of subsequent segments as writing to a segment may cause
1830 * its size to increase, which would overwrite the subsequent segments and
1833 __checkReturn efx_rc_t
1834 ef10_nvram_partn_write_segment_tlv(
1835 __in efx_nic_t *enp,
1836 __in uint32_t partn,
1838 __in_bcount(size) caddr_t data,
1840 __in boolean_t all_segments)
1842 size_t partn_size = 0;
1844 size_t total_length = 0;
1846 size_t current_offset = 0;
1847 size_t remaining_original_length;
1848 size_t remaining_modified_length;
1849 caddr_t segment_data;
1851 EFSYS_ASSERT3U(partn, ==, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG);
1853 /* Allocate sufficient memory for the entire partition */
1854 if ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0)
1857 EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, partn_data);
1858 if (partn_data == NULL) {
1863 remaining_original_length = partn_size;
1864 remaining_modified_length = partn_size;
1865 segment_data = partn_data;
1867 /* Lock the partition */
1868 if ((rc = ef10_nvram_partn_lock(enp, partn)) != 0)
1871 /* Iterate over each (potential) segment to update it. */
1873 boolean_t write = all_segments || current_offset == 0;
1875 rc = ef10_nvram_segment_write_tlv(enp, partn, tag, data, size,
1876 &segment_data, ¤t_offset, &remaining_original_length,
1877 &remaining_modified_length, write);
1879 if (current_offset == 0) {
1881 * If no data has been read then the first
1882 * segment is invalid, which is an error.
1888 } while (current_offset < partn_size);
1890 total_length = segment_data - partn_data;
1893 * We've run out of space. This should actually be dealt with by
1894 * ef10_nvram_buf_write_tlv returning ENOSPC.
1896 if (total_length > partn_size) {
1901 /* Erase the whole partition in NVRAM */
1902 if ((rc = ef10_nvram_partn_erase(enp, partn, 0, partn_size)) != 0)
1905 /* Write new partition contents from the buffer to NVRAM */
1906 if ((rc = ef10_nvram_partn_write(enp, partn, 0, partn_data,
1907 total_length)) != 0)
1910 /* Unlock the partition */
1911 (void) ef10_nvram_partn_unlock(enp, partn, NULL);
1913 EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data);
1926 (void) ef10_nvram_partn_unlock(enp, partn, NULL);
1930 EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data);
1934 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1940 * Get the size of a NVRAM partition. This is the total size allocated in nvram,
1941 * not the data used by the segments in the partition.
1943 __checkReturn efx_rc_t
1944 ef10_nvram_partn_size(
1945 __in efx_nic_t *enp,
1946 __in uint32_t partn,
1947 __out size_t *sizep)
1950 efx_nvram_info_t eni = { 0 };
1952 if ((rc = efx_mcdi_nvram_info(enp, partn, &eni)) != 0)
1955 *sizep = eni.eni_partn_size;
1960 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1965 __checkReturn efx_rc_t
1966 ef10_nvram_partn_info(
1967 __in efx_nic_t *enp,
1968 __in uint32_t partn,
1969 __out efx_nvram_info_t *enip)
1973 if ((rc = efx_mcdi_nvram_info(enp, partn, enip)) != 0)
1976 if (enip->eni_write_size == 0)
1977 enip->eni_write_size = EF10_NVRAM_CHUNK;
1982 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1988 __checkReturn efx_rc_t
1989 ef10_nvram_partn_lock(
1990 __in efx_nic_t *enp,
1991 __in uint32_t partn)
1995 if ((rc = efx_mcdi_nvram_update_start(enp, partn)) != 0)
2001 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2006 __checkReturn efx_rc_t
2007 ef10_nvram_partn_read_mode(
2008 __in efx_nic_t *enp,
2009 __in uint32_t partn,
2010 __in unsigned int offset,
2011 __out_bcount(size) caddr_t data,
2019 chunk = MIN(size, EF10_NVRAM_CHUNK);
2021 if ((rc = efx_mcdi_nvram_read(enp, partn, offset,
2022 data, chunk, mode)) != 0) {
2034 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2039 __checkReturn efx_rc_t
2040 ef10_nvram_partn_read(
2041 __in efx_nic_t *enp,
2042 __in uint32_t partn,
2043 __in unsigned int offset,
2044 __out_bcount(size) caddr_t data,
2048 * An A/B partition has two data stores (current and backup).
2049 * Read requests which come in through the EFX API expect to read the
2050 * current, active store of an A/B partition. For non A/B partitions,
2051 * there is only a single store and so the mode param is ignored.
2053 return ef10_nvram_partn_read_mode(enp, partn, offset, data, size,
2054 MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT);
2057 __checkReturn efx_rc_t
2058 ef10_nvram_partn_read_backup(
2059 __in efx_nic_t *enp,
2060 __in uint32_t partn,
2061 __in unsigned int offset,
2062 __out_bcount(size) caddr_t data,
2066 * An A/B partition has two data stores (current and backup).
2067 * Read the backup store of an A/B partition (i.e. the store currently
2068 * being written to if the partition is locked).
2070 * This is needed when comparing the existing partition content to avoid
2071 * unnecessary writes, or to read back what has been written to check
2072 * that the writes have succeeded.
2074 return ef10_nvram_partn_read_mode(enp, partn, offset, data, size,
2075 MC_CMD_NVRAM_READ_IN_V2_TARGET_BACKUP);
2078 __checkReturn efx_rc_t
2079 ef10_nvram_partn_erase(
2080 __in efx_nic_t *enp,
2081 __in uint32_t partn,
2082 __in unsigned int offset,
2086 efx_nvram_info_t eni = { 0 };
2087 uint32_t erase_size;
2089 if ((rc = efx_mcdi_nvram_info(enp, partn, &eni)) != 0)
2092 erase_size = eni.eni_erase_size;
2094 if (erase_size == 0) {
2095 if ((rc = efx_mcdi_nvram_erase(enp, partn, offset, size)) != 0)
2098 if (size % erase_size != 0) {
2103 if ((rc = efx_mcdi_nvram_erase(enp, partn, offset,
2106 offset += erase_size;
2120 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2125 __checkReturn efx_rc_t
2126 ef10_nvram_partn_write(
2127 __in efx_nic_t *enp,
2128 __in uint32_t partn,
2129 __in unsigned int offset,
2130 __in_bcount(size) caddr_t data,
2134 efx_nvram_info_t eni = { 0 };
2135 uint32_t write_size;
2138 if ((rc = efx_mcdi_nvram_info(enp, partn, &eni)) != 0)
2141 write_size = eni.eni_write_size;
2143 if (write_size != 0) {
2145 * Check that the size is a multiple of the write chunk size if
2146 * the write chunk size is available.
2148 if (size % write_size != 0) {
2153 write_size = EF10_NVRAM_CHUNK;
2157 chunk = MIN(size, write_size);
2159 if ((rc = efx_mcdi_nvram_write(enp, partn, offset,
2160 data, chunk)) != 0) {
2176 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2181 #define EF10_NVRAM_INITIAL_POLL_DELAY_US 10000
2182 #define EF10_NVRAM_MAX_POLL_DELAY_US 1000000
2183 #define EF10_NVRAM_POLL_RETRIES 100
2185 __checkReturn efx_rc_t
2186 ef10_nvram_partn_unlock(
2187 __in efx_nic_t *enp,
2188 __in uint32_t partn,
2189 __out_opt uint32_t *verify_resultp)
2191 boolean_t reboot = B_FALSE;
2192 uint32_t poll_delay_us = EF10_NVRAM_INITIAL_POLL_DELAY_US;
2193 uint32_t poll_retry = 0;
2194 uint32_t verify_result = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN;
2197 rc = efx_mcdi_nvram_update_finish(enp, partn, reboot,
2198 EFX_NVRAM_UPDATE_FLAGS_BACKGROUND, &verify_result);
2201 * NVRAM updates can take a long time (e.g. up to 1 minute for bundle
2202 * images). Polling for NVRAM update completion ensures that other MCDI
2203 * commands can be issued before the background NVRAM update completes.
2205 * Without polling, other MCDI commands can only be issued before the
2206 * NVRAM update completes if the MCDI transport and the firmware
2207 * support the Asynchronous MCDI protocol extensions in SF-116575-PS.
2209 * The initial call either completes the update synchronously, or
2210 * returns RC_PENDING to indicate processing is continuing. In the
2211 * latter case, we poll for at least 1 minute, at increasing intervals
2212 * (10ms, 100ms, 1s).
2214 while (verify_result == MC_CMD_NVRAM_VERIFY_RC_PENDING) {
2216 if (poll_retry > EF10_NVRAM_POLL_RETRIES) {
2222 EFSYS_SLEEP(poll_delay_us);
2223 if (poll_delay_us < EF10_NVRAM_MAX_POLL_DELAY_US)
2224 poll_delay_us *= 10;
2226 /* Poll for completion of background NVRAM update. */
2227 verify_result = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN;
2229 rc = efx_mcdi_nvram_update_finish(enp, partn, reboot,
2230 EFX_NVRAM_UPDATE_FLAGS_POLL, &verify_result);
2232 /* Poll failed, so assume NVRAM update failed. */
2237 if (verify_resultp != NULL)
2238 *verify_resultp = verify_result;
2245 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2250 __checkReturn efx_rc_t
2251 ef10_nvram_partn_set_version(
2252 __in efx_nic_t *enp,
2253 __in uint32_t partn,
2254 __in_ecount(4) uint16_t version[4])
2256 struct tlv_partition_version partn_version;
2260 /* Add or modify partition version TLV item */
2261 partn_version.version_w = __CPU_TO_LE_16(version[0]);
2262 partn_version.version_x = __CPU_TO_LE_16(version[1]);
2263 partn_version.version_y = __CPU_TO_LE_16(version[2]);
2264 partn_version.version_z = __CPU_TO_LE_16(version[3]);
2266 size = sizeof (partn_version) - (2 * sizeof (uint32_t));
2268 /* Write the version number to all segments in the partition */
2269 if ((rc = ef10_nvram_partn_write_segment_tlv(enp,
2270 NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
2271 TLV_TAG_PARTITION_VERSION(partn),
2272 (caddr_t)&partn_version.version_w, size, B_TRUE)) != 0)
2278 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2283 #endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */
2287 typedef struct ef10_parttbl_entry_s {
2289 unsigned int port_mask;
2290 efx_nvram_type_t nvtype;
2291 } ef10_parttbl_entry_t;
2293 /* Port mask values */
2294 #define PORT_1 (1u << 1)
2295 #define PORT_2 (1u << 2)
2296 #define PORT_3 (1u << 3)
2297 #define PORT_4 (1u << 4)
2298 #define PORT_ALL (0xffffffffu)
2300 #define PARTN_MAP_ENTRY(partn, port_mask, nvtype) \
2301 { (NVRAM_PARTITION_TYPE_##partn), (PORT_##port_mask), (EFX_NVRAM_##nvtype) }
2303 /* Translate EFX NVRAM types to firmware partition types */
2304 static ef10_parttbl_entry_t hunt_parttbl[] = {
2305 /* partn ports nvtype */
2306 PARTN_MAP_ENTRY(MC_FIRMWARE, ALL, MC_FIRMWARE),
2307 PARTN_MAP_ENTRY(MC_FIRMWARE_BACKUP, ALL, MC_GOLDEN),
2308 PARTN_MAP_ENTRY(EXPANSION_ROM, ALL, BOOTROM),
2309 PARTN_MAP_ENTRY(EXPROM_CONFIG_PORT0, 1, BOOTROM_CFG),
2310 PARTN_MAP_ENTRY(EXPROM_CONFIG_PORT1, 2, BOOTROM_CFG),
2311 PARTN_MAP_ENTRY(EXPROM_CONFIG_PORT2, 3, BOOTROM_CFG),
2312 PARTN_MAP_ENTRY(EXPROM_CONFIG_PORT3, 4, BOOTROM_CFG),
2313 PARTN_MAP_ENTRY(DYNAMIC_CONFIG, ALL, DYNAMIC_CFG),
2314 PARTN_MAP_ENTRY(FPGA, ALL, FPGA),
2315 PARTN_MAP_ENTRY(FPGA_BACKUP, ALL, FPGA_BACKUP),
2316 PARTN_MAP_ENTRY(LICENSE, ALL, LICENSE),
2319 static ef10_parttbl_entry_t medford_parttbl[] = {
2320 /* partn ports nvtype */
2321 PARTN_MAP_ENTRY(MC_FIRMWARE, ALL, MC_FIRMWARE),
2322 PARTN_MAP_ENTRY(MC_FIRMWARE_BACKUP, ALL, MC_GOLDEN),
2323 PARTN_MAP_ENTRY(EXPANSION_ROM, ALL, BOOTROM),
2324 PARTN_MAP_ENTRY(EXPROM_CONFIG, ALL, BOOTROM_CFG),
2325 PARTN_MAP_ENTRY(DYNAMIC_CONFIG, ALL, DYNAMIC_CFG),
2326 PARTN_MAP_ENTRY(FPGA, ALL, FPGA),
2327 PARTN_MAP_ENTRY(FPGA_BACKUP, ALL, FPGA_BACKUP),
2328 PARTN_MAP_ENTRY(LICENSE, ALL, LICENSE),
2329 PARTN_MAP_ENTRY(EXPANSION_UEFI, ALL, UEFIROM),
2330 PARTN_MAP_ENTRY(MUM_FIRMWARE, ALL, MUM_FIRMWARE),
2333 static ef10_parttbl_entry_t medford2_parttbl[] = {
2334 /* partn ports nvtype */
2335 PARTN_MAP_ENTRY(MC_FIRMWARE, ALL, MC_FIRMWARE),
2336 PARTN_MAP_ENTRY(MC_FIRMWARE_BACKUP, ALL, MC_GOLDEN),
2337 PARTN_MAP_ENTRY(EXPANSION_ROM, ALL, BOOTROM),
2338 PARTN_MAP_ENTRY(EXPROM_CONFIG, ALL, BOOTROM_CFG),
2339 PARTN_MAP_ENTRY(DYNAMIC_CONFIG, ALL, DYNAMIC_CFG),
2340 PARTN_MAP_ENTRY(FPGA, ALL, FPGA),
2341 PARTN_MAP_ENTRY(FPGA_BACKUP, ALL, FPGA_BACKUP),
2342 PARTN_MAP_ENTRY(LICENSE, ALL, LICENSE),
2343 PARTN_MAP_ENTRY(EXPANSION_UEFI, ALL, UEFIROM),
2344 PARTN_MAP_ENTRY(MUM_FIRMWARE, ALL, MUM_FIRMWARE),
2345 PARTN_MAP_ENTRY(DYNCONFIG_DEFAULTS, ALL, DYNCONFIG_DEFAULTS),
2346 PARTN_MAP_ENTRY(ROMCONFIG_DEFAULTS, ALL, ROMCONFIG_DEFAULTS),
2347 PARTN_MAP_ENTRY(BUNDLE, ALL, BUNDLE),
2348 PARTN_MAP_ENTRY(BUNDLE_METADATA, ALL, BUNDLE_METADATA),
2351 static __checkReturn efx_rc_t
2353 __in efx_nic_t *enp,
2354 __out ef10_parttbl_entry_t **parttblp,
2355 __out size_t *parttbl_rowsp)
2357 switch (enp->en_family) {
2358 case EFX_FAMILY_HUNTINGTON:
2359 *parttblp = hunt_parttbl;
2360 *parttbl_rowsp = EFX_ARRAY_SIZE(hunt_parttbl);
2363 case EFX_FAMILY_MEDFORD:
2364 *parttblp = medford_parttbl;
2365 *parttbl_rowsp = EFX_ARRAY_SIZE(medford_parttbl);
2368 case EFX_FAMILY_MEDFORD2:
2369 *parttblp = medford2_parttbl;
2370 *parttbl_rowsp = EFX_ARRAY_SIZE(medford2_parttbl);
2374 EFSYS_ASSERT(B_FALSE);
2380 __checkReturn efx_rc_t
2381 ef10_nvram_type_to_partn(
2382 __in efx_nic_t *enp,
2383 __in efx_nvram_type_t type,
2384 __out uint32_t *partnp)
2386 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
2387 ef10_parttbl_entry_t *parttbl = NULL;
2388 size_t parttbl_rows = 0;
2391 EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
2392 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
2393 EFSYS_ASSERT(partnp != NULL);
2395 if (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) {
2396 for (i = 0; i < parttbl_rows; i++) {
2397 ef10_parttbl_entry_t *entry = &parttbl[i];
2399 if ((entry->nvtype == type) &&
2400 (entry->port_mask & (1u << emip->emi_port))) {
2401 *partnp = entry->partn;
2412 static __checkReturn efx_rc_t
2413 ef10_nvram_partn_to_type(
2414 __in efx_nic_t *enp,
2415 __in uint32_t partn,
2416 __out efx_nvram_type_t *typep)
2418 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
2419 ef10_parttbl_entry_t *parttbl = NULL;
2420 size_t parttbl_rows = 0;
2423 EFSYS_ASSERT(typep != NULL);
2425 if (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) {
2426 for (i = 0; i < parttbl_rows; i++) {
2427 ef10_parttbl_entry_t *entry = &parttbl[i];
2429 if ((entry->partn == partn) &&
2430 (entry->port_mask & (1u << emip->emi_port))) {
2431 *typep = entry->nvtype;
2440 __checkReturn efx_rc_t
2442 __in efx_nic_t *enp)
2444 efx_nvram_type_t type;
2445 unsigned int npartns = 0;
2446 uint32_t *partns = NULL;
2451 /* Read available partitions from NVRAM partition map */
2452 size = MC_CMD_NVRAM_PARTITIONS_OUT_TYPE_ID_MAXNUM * sizeof (uint32_t);
2453 EFSYS_KMEM_ALLOC(enp->en_esip, size, partns);
2454 if (partns == NULL) {
2459 if ((rc = efx_mcdi_nvram_partitions(enp, (caddr_t)partns, size,
2464 for (i = 0; i < npartns; i++) {
2465 /* Check if the partition is supported for this port */
2466 if ((rc = ef10_nvram_partn_to_type(enp, partns[i], &type)) != 0)
2469 if ((rc = efx_mcdi_nvram_test(enp, partns[i])) != 0)
2473 EFSYS_KMEM_FREE(enp->en_esip, size, partns);
2480 EFSYS_KMEM_FREE(enp->en_esip, size, partns);
2482 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2486 #endif /* EFSYS_OPT_DIAG */
2488 __checkReturn efx_rc_t
2489 ef10_nvram_partn_get_version(
2490 __in efx_nic_t *enp,
2491 __in uint32_t partn,
2492 __out uint32_t *subtypep,
2493 __out_ecount(4) uint16_t version[4])
2497 /* FIXME: get highest partn version from all ports */
2498 /* FIXME: return partn description if available */
2500 if ((rc = efx_mcdi_nvram_metadata(enp, partn, subtypep,
2501 version, NULL, 0)) != 0)
2507 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2512 __checkReturn efx_rc_t
2513 ef10_nvram_partn_rw_start(
2514 __in efx_nic_t *enp,
2515 __in uint32_t partn,
2516 __out size_t *chunk_sizep)
2518 efx_nvram_info_t eni = { 0 };
2521 if ((rc = ef10_nvram_partn_info(enp, partn, &eni)) != 0)
2524 if ((rc = ef10_nvram_partn_lock(enp, partn)) != 0)
2527 if (chunk_sizep != NULL)
2528 *chunk_sizep = eni.eni_write_size;
2535 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2540 __checkReturn efx_rc_t
2541 ef10_nvram_partn_rw_finish(
2542 __in efx_nic_t *enp,
2543 __in uint32_t partn,
2544 __out_opt uint32_t *verify_resultp)
2548 if ((rc = ef10_nvram_partn_unlock(enp, partn, verify_resultp)) != 0)
2554 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2559 #endif /* EFSYS_OPT_NVRAM */
2561 #endif /* EFX_OPTS_EF10() */