1 /* SPDX-License-Identifier: BSD-3-Clause
3 * Copyright (c) 2012-2018 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
+= P2ROUNDUP(len
, sizeof (uint32_t)) / sizeof (*ptr
);
376 static __checkReturn efx_rc_t
378 __inout tlv_cursor_t
*cursor
,
385 uint32_t *last_segment_end
;
388 if ((rc
= tlv_validate_state(cursor
)) != 0)
391 if ((rc
= tlv_require_end(cursor
)) != 0)
394 if (tag
== TLV_TAG_END
) {
399 last_segment_end
= tlv_last_segment_end(cursor
);
401 delta
= TLV_DWORD_COUNT(size
);
402 if (last_segment_end
+ 1 + delta
> cursor
->limit
) {
407 /* Move data up: new space at cursor->current */
408 memmove(cursor
->current
+ delta
, cursor
->current
,
409 (last_segment_end
+ 1 - cursor
->current
) * sizeof (uint32_t));
411 /* Adjust the end pointer */
412 cursor
->end
+= delta
;
414 /* Write new TLV item */
415 tlv_write(cursor
, tag
, data
, size
);
426 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
431 static __checkReturn efx_rc_t
433 __inout tlv_cursor_t
*cursor
)
436 uint32_t *last_segment_end
;
439 if ((rc
= tlv_validate_state(cursor
)) != 0)
442 if (tlv_tag(cursor
) == TLV_TAG_END
) {
447 delta
= TLV_DWORD_COUNT(tlv_length(cursor
));
449 if ((rc
= tlv_require_end(cursor
)) != 0)
452 last_segment_end
= tlv_last_segment_end(cursor
);
454 /* Shuffle things down, destroying the item at cursor->current */
455 memmove(cursor
->current
, cursor
->current
+ delta
,
456 (last_segment_end
+ 1 - cursor
->current
) * sizeof (uint32_t));
457 /* Zero the new space at the end of the TLV chain */
458 memset(last_segment_end
+ 1 - delta
, 0, delta
* sizeof (uint32_t));
459 /* Adjust the end pointer */
460 cursor
->end
-= delta
;
469 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
474 static __checkReturn efx_rc_t
476 __inout tlv_cursor_t
*cursor
,
483 unsigned int old_ndwords
;
484 unsigned int new_ndwords
;
486 uint32_t *last_segment_end
;
489 if ((rc
= tlv_validate_state(cursor
)) != 0)
492 if (tlv_tag(cursor
) == TLV_TAG_END
) {
496 if (tlv_tag(cursor
) != tag
) {
501 old_ndwords
= TLV_DWORD_COUNT(tlv_length(cursor
));
502 new_ndwords
= TLV_DWORD_COUNT(size
);
504 if ((rc
= tlv_require_end(cursor
)) != 0)
507 last_segment_end
= tlv_last_segment_end(cursor
);
509 if (new_ndwords
> old_ndwords
) {
510 /* Expand space used for TLV item */
511 delta
= new_ndwords
- old_ndwords
;
512 pos
= cursor
->current
+ old_ndwords
;
514 if (last_segment_end
+ 1 + delta
> cursor
->limit
) {
519 /* Move up: new space at (cursor->current + old_ndwords) */
520 memmove(pos
+ delta
, pos
,
521 (last_segment_end
+ 1 - pos
) * sizeof (uint32_t));
523 /* Adjust the end pointer */
524 cursor
->end
+= delta
;
526 } else if (new_ndwords
< old_ndwords
) {
527 /* Shrink space used for TLV item */
528 delta
= old_ndwords
- new_ndwords
;
529 pos
= cursor
->current
+ new_ndwords
;
531 /* Move down: remove words at (cursor->current + new_ndwords) */
532 memmove(pos
, pos
+ delta
,
533 (last_segment_end
+ 1 - pos
) * sizeof (uint32_t));
535 /* Zero the new space at the end of the TLV chain */
536 memset(last_segment_end
+ 1 - delta
, 0,
537 delta
* sizeof (uint32_t));
539 /* Adjust the end pointer */
540 cursor
->end
-= delta
;
544 tlv_write(cursor
, tag
, data
, size
);
557 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
562 static uint32_t checksum_tlv_partition(
563 __in nvram_partition_t
*partition
)
565 tlv_cursor_t
*cursor
;
571 cursor
= &partition
->tlv_cursor
;
572 len
= tlv_block_length_used(cursor
);
573 EFSYS_ASSERT3U((len
& 3), ==, 0);
576 ptr
= partition
->data
;
577 end
= &ptr
[len
>> 2];
580 csum
+= __LE_TO_CPU_32(*ptr
++);
585 static __checkReturn efx_rc_t
586 tlv_update_partition_len_and_cks(
587 __in tlv_cursor_t
*cursor
)
590 nvram_partition_t partition
;
591 struct tlv_partition_header
*header
;
592 struct tlv_partition_trailer
*trailer
;
596 * We just modified the partition, so the total length may not be
597 * valid. Don't use tlv_find(), which performs some sanity checks
598 * that may fail here.
600 partition
.data
= cursor
->block
;
601 memcpy(&partition
.tlv_cursor
, cursor
, sizeof (*cursor
));
602 header
= (struct tlv_partition_header
*)partition
.data
;
604 if (__LE_TO_CPU_32(header
->tag
) != TLV_TAG_PARTITION_HEADER
) {
608 new_len
= tlv_block_length_used(&partition
.tlv_cursor
);
613 header
->total_length
= __CPU_TO_LE_32(new_len
);
614 /* Ensure the modified partition always has a new generation count. */
615 header
->generation
= __CPU_TO_LE_32(
616 __LE_TO_CPU_32(header
->generation
) + 1);
618 trailer
= (struct tlv_partition_trailer
*)((uint8_t *)header
+
619 new_len
- sizeof (*trailer
) - sizeof (uint32_t));
620 trailer
->generation
= header
->generation
;
621 trailer
->checksum
= __CPU_TO_LE_32(
622 __LE_TO_CPU_32(trailer
->checksum
) -
623 checksum_tlv_partition(&partition
));
630 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
635 /* Validate buffer contents (before writing to flash) */
636 __checkReturn efx_rc_t
637 ef10_nvram_buffer_validate(
639 __in_bcount(partn_size
) caddr_t partn_data
,
640 __in
size_t partn_size
)
643 struct tlv_partition_header
*header
;
644 struct tlv_partition_trailer
*trailer
;
650 EFX_STATIC_ASSERT(sizeof (*header
) <= EF10_NVRAM_CHUNK
);
652 if ((partn_data
== NULL
) || (partn_size
== 0)) {
657 /* The partition header must be the first item (at offset zero) */
658 if ((rc
= tlv_init_cursor_from_size(&cursor
, (uint8_t *)partn_data
,
663 if (tlv_tag(&cursor
) != TLV_TAG_PARTITION_HEADER
) {
667 header
= (struct tlv_partition_header
*)tlv_item(&cursor
);
669 /* Check TLV partition length (includes the END tag) */
670 total_length
= __LE_TO_CPU_32(header
->total_length
);
671 if (total_length
> partn_size
) {
676 /* Check partition header matches partn */
677 if (__LE_TO_CPU_16(header
->type_id
) != partn
) {
682 /* Check partition ends with PARTITION_TRAILER and END tags */
683 if ((rc
= tlv_find(&cursor
, TLV_TAG_PARTITION_TRAILER
)) != 0) {
687 trailer
= (struct tlv_partition_trailer
*)tlv_item(&cursor
);
689 if ((rc
= tlv_advance(&cursor
)) != 0) {
693 if (tlv_tag(&cursor
) != TLV_TAG_END
) {
698 /* Check generation counts are consistent */
699 if (trailer
->generation
!= header
->generation
) {
704 /* Verify partition checksum */
706 for (pos
= 0; (size_t)pos
< total_length
; pos
+= sizeof (uint32_t)) {
707 cksum
+= *((uint32_t *)(partn_data
+ pos
));
735 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
741 ef10_nvram_buffer_init(
742 __out_bcount(buffer_size
)
744 __in
size_t buffer_size
)
746 uint32_t *buf
= (uint32_t *)bufferp
;
748 memset(buf
, 0xff, buffer_size
);
753 __checkReturn efx_rc_t
754 ef10_nvram_buffer_create(
755 __in
uint32_t partn_type
,
756 __out_bcount(partn_size
)
758 __in
size_t partn_size
)
760 uint32_t *buf
= (uint32_t *)partn_data
;
763 struct tlv_partition_header header
;
764 struct tlv_partition_trailer trailer
;
766 unsigned int min_buf_size
= sizeof (struct tlv_partition_header
) +
767 sizeof (struct tlv_partition_trailer
);
768 if (partn_size
< min_buf_size
) {
773 ef10_nvram_buffer_init(partn_data
, partn_size
);
775 if ((rc
= tlv_init_cursor(&cursor
, buf
,
776 (uint32_t *)((uint8_t *)buf
+ partn_size
),
781 header
.tag
= __CPU_TO_LE_32(TLV_TAG_PARTITION_HEADER
);
782 header
.length
= __CPU_TO_LE_32(sizeof (header
) - 8);
783 header
.type_id
= __CPU_TO_LE_16(partn_type
);
785 header
.generation
= __CPU_TO_LE_32(1);
786 header
.total_length
= 0; /* This will be fixed below. */
787 if ((rc
= tlv_insert(
788 &cursor
, TLV_TAG_PARTITION_HEADER
,
789 (uint8_t *)&header
.type_id
, sizeof (header
) - 8)) != 0)
791 if ((rc
= tlv_advance(&cursor
)) != 0)
794 trailer
.tag
= __CPU_TO_LE_32(TLV_TAG_PARTITION_TRAILER
);
795 trailer
.length
= __CPU_TO_LE_32(sizeof (trailer
) - 8);
796 trailer
.generation
= header
.generation
;
797 trailer
.checksum
= 0; /* This will be fixed below. */
798 if ((rc
= tlv_insert(&cursor
, TLV_TAG_PARTITION_TRAILER
,
799 (uint8_t *)&trailer
.generation
, sizeof (trailer
) - 8)) != 0)
802 if ((rc
= tlv_update_partition_len_and_cks(&cursor
)) != 0)
805 /* Check that the partition is valid. */
806 if ((rc
= ef10_nvram_buffer_validate(partn_type
,
807 partn_data
, partn_size
)) != 0)
825 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
832 __in
uint32_t *position
,
835 return (uint32_t)((uint8_t *)position
- (uint8_t *)base
);
838 __checkReturn efx_rc_t
839 ef10_nvram_buffer_find_item_start(
840 __in_bcount(buffer_size
)
842 __in
size_t buffer_size
,
843 __out
uint32_t *startp
)
845 /* Read past partition header to find start address of the first key */
849 /* A PARTITION_HEADER tag must be the first item (at offset zero) */
850 if ((rc
= tlv_init_cursor_from_size(&cursor
, (uint8_t *)bufferp
,
851 buffer_size
)) != 0) {
855 if (tlv_tag(&cursor
) != TLV_TAG_PARTITION_HEADER
) {
860 if ((rc
= tlv_advance(&cursor
)) != 0) {
864 *startp
= byte_offset(cursor
.current
, cursor
.block
);
866 if ((rc
= tlv_require_end(&cursor
)) != 0)
878 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
883 __checkReturn efx_rc_t
884 ef10_nvram_buffer_find_end(
885 __in_bcount(buffer_size
)
887 __in
size_t buffer_size
,
888 __in
uint32_t offset
,
889 __out
uint32_t *endp
)
891 /* Read to end of partition */
894 uint32_t *segment_used
;
896 _NOTE(ARGUNUSED(offset
))
898 if ((rc
= tlv_init_cursor_from_size(&cursor
, (uint8_t *)bufferp
,
899 buffer_size
)) != 0) {
904 segment_used
= cursor
.block
;
907 * Go through each segment and check that it has an end tag. If there
908 * is no end tag then the previous segment was the last valid one,
909 * so return the used space including that end tag.
911 while (tlv_tag(&cursor
) == TLV_TAG_PARTITION_HEADER
) {
912 if (tlv_require_end(&cursor
) != 0) {
913 if (segment_used
== cursor
.block
) {
915 * First segment is corrupt, so there is
916 * no valid data in partition.
923 segment_used
= cursor
.end
+ 1;
925 cursor
.current
= segment_used
;
927 /* Return space used (including the END tag) */
928 *endp
= (segment_used
- cursor
.block
) * sizeof (uint32_t);
935 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
940 __checkReturn
__success(return != B_FALSE
) boolean_t
941 ef10_nvram_buffer_find_item(
942 __in_bcount(buffer_size
)
944 __in
size_t buffer_size
,
945 __in
uint32_t offset
,
946 __out
uint32_t *startp
,
947 __out
uint32_t *lengthp
)
949 /* Find TLV at offset and return key start and length */
954 if (tlv_init_cursor_at_offset(&cursor
, (uint8_t *)bufferp
,
955 buffer_size
, offset
) != 0) {
959 while ((key
= tlv_item(&cursor
)) != NULL
) {
960 tag
= tlv_tag(&cursor
);
961 if (tag
== TLV_TAG_PARTITION_HEADER
||
962 tag
== TLV_TAG_PARTITION_TRAILER
) {
963 if (tlv_advance(&cursor
) != 0) {
968 *startp
= byte_offset(cursor
.current
, cursor
.block
);
969 *lengthp
= byte_offset(tlv_next_item_ptr(&cursor
),
977 __checkReturn efx_rc_t
978 ef10_nvram_buffer_peek_item(
979 __in_bcount(buffer_size
)
981 __in
size_t buffer_size
,
982 __in
uint32_t offset
,
983 __out
uint32_t *tagp
,
984 __out
uint32_t *lengthp
,
985 __out
uint32_t *value_offsetp
)
991 if ((rc
= tlv_init_cursor_at_offset(&cursor
, (uint8_t *)bufferp
,
992 buffer_size
, offset
)) != 0) {
996 tag
= tlv_tag(&cursor
);
998 if (tag
== TLV_TAG_END
) {
1000 * To allow stepping over the END tag, report the full tag
1001 * length and a zero length value.
1003 *lengthp
= sizeof (tag
);
1004 *value_offsetp
= sizeof (tag
);
1006 *lengthp
= byte_offset(tlv_next_item_ptr(&cursor
),
1008 *value_offsetp
= byte_offset((uint32_t *)tlv_value(&cursor
),
1014 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1019 __checkReturn efx_rc_t
1020 ef10_nvram_buffer_get_item(
1021 __in_bcount(buffer_size
)
1023 __in
size_t buffer_size
,
1024 __in
uint32_t offset
,
1025 __in
uint32_t length
,
1026 __out
uint32_t *tagp
,
1027 __out_bcount_part(value_max_size
, *lengthp
)
1029 __in
size_t value_max_size
,
1030 __out
uint32_t *lengthp
)
1033 tlv_cursor_t cursor
;
1034 uint32_t value_length
;
1036 if (buffer_size
< (offset
+ length
)) {
1041 if ((rc
= tlv_init_cursor_at_offset(&cursor
, (uint8_t *)bufferp
,
1042 buffer_size
, offset
)) != 0) {
1046 value_length
= tlv_length(&cursor
);
1047 if (value_max_size
< value_length
) {
1051 memcpy(valuep
, tlv_value(&cursor
), value_length
);
1053 *tagp
= tlv_tag(&cursor
);
1054 *lengthp
= value_length
;
1063 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1068 __checkReturn efx_rc_t
1069 ef10_nvram_buffer_insert_item(
1070 __in_bcount(buffer_size
)
1072 __in
size_t buffer_size
,
1073 __in
uint32_t offset
,
1075 __in_bcount(length
) caddr_t valuep
,
1076 __in
uint32_t length
,
1077 __out
uint32_t *lengthp
)
1080 tlv_cursor_t cursor
;
1082 if ((rc
= tlv_init_cursor_at_offset(&cursor
, (uint8_t *)bufferp
,
1083 buffer_size
, offset
)) != 0) {
1087 rc
= tlv_insert(&cursor
, tag
, (uint8_t *)valuep
, length
);
1092 *lengthp
= byte_offset(tlv_next_item_ptr(&cursor
),
1100 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1105 __checkReturn efx_rc_t
1106 ef10_nvram_buffer_modify_item(
1107 __in_bcount(buffer_size
)
1109 __in
size_t buffer_size
,
1110 __in
uint32_t offset
,
1112 __in_bcount(length
) caddr_t valuep
,
1113 __in
uint32_t length
,
1114 __out
uint32_t *lengthp
)
1117 tlv_cursor_t cursor
;
1119 if ((rc
= tlv_init_cursor_at_offset(&cursor
, (uint8_t *)bufferp
,
1120 buffer_size
, offset
)) != 0) {
1124 rc
= tlv_modify(&cursor
, tag
, (uint8_t *)valuep
, length
);
1130 *lengthp
= byte_offset(tlv_next_item_ptr(&cursor
),
1138 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1144 __checkReturn efx_rc_t
1145 ef10_nvram_buffer_delete_item(
1146 __in_bcount(buffer_size
)
1148 __in
size_t buffer_size
,
1149 __in
uint32_t offset
,
1150 __in
uint32_t length
,
1154 tlv_cursor_t cursor
;
1156 _NOTE(ARGUNUSED(length
, end
))
1158 if ((rc
= tlv_init_cursor_at_offset(&cursor
, (uint8_t *)bufferp
,
1159 buffer_size
, offset
)) != 0) {
1163 if ((rc
= tlv_delete(&cursor
)) != 0)
1171 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1176 __checkReturn efx_rc_t
1177 ef10_nvram_buffer_finish(
1178 __in_bcount(buffer_size
)
1180 __in
size_t buffer_size
)
1183 tlv_cursor_t cursor
;
1185 if ((rc
= tlv_init_cursor_from_size(&cursor
, (uint8_t *)bufferp
,
1186 buffer_size
)) != 0) {
1191 if ((rc
= tlv_require_end(&cursor
)) != 0)
1194 if ((rc
= tlv_update_partition_len_and_cks(&cursor
)) != 0)
1204 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1212 * Read and validate a segment from a partition. A segment is a complete
1213 * tlv chain between PARTITION_HEADER and PARTITION_END tags. There may
1214 * be multiple segments in a partition, so seg_offset allows segments
1215 * beyond the first to be read.
1217 static __checkReturn efx_rc_t
1218 ef10_nvram_read_tlv_segment(
1219 __in efx_nic_t
*enp
,
1220 __in
uint32_t partn
,
1221 __in
size_t seg_offset
,
1222 __in_bcount(max_seg_size
) caddr_t seg_data
,
1223 __in
size_t max_seg_size
)
1225 tlv_cursor_t cursor
;
1226 struct tlv_partition_header
*header
;
1227 struct tlv_partition_trailer
*trailer
;
1228 size_t total_length
;
1233 EFX_STATIC_ASSERT(sizeof (*header
) <= EF10_NVRAM_CHUNK
);
1235 if ((seg_data
== NULL
) || (max_seg_size
== 0)) {
1240 /* Read initial chunk of the segment, starting at offset */
1241 if ((rc
= ef10_nvram_partn_read_mode(enp
, partn
, seg_offset
, seg_data
,
1243 MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT
)) != 0) {
1247 /* A PARTITION_HEADER tag must be the first item at the given offset */
1248 if ((rc
= tlv_init_cursor_from_size(&cursor
, (uint8_t *)seg_data
,
1249 max_seg_size
)) != 0) {
1253 if (tlv_tag(&cursor
) != TLV_TAG_PARTITION_HEADER
) {
1257 header
= (struct tlv_partition_header
*)tlv_item(&cursor
);
1259 /* Check TLV segment length (includes the END tag) */
1260 total_length
= __LE_TO_CPU_32(header
->total_length
);
1261 if (total_length
> max_seg_size
) {
1266 /* Read the remaining segment content */
1267 if (total_length
> EF10_NVRAM_CHUNK
) {
1268 if ((rc
= ef10_nvram_partn_read_mode(enp
, partn
,
1269 seg_offset
+ EF10_NVRAM_CHUNK
,
1270 seg_data
+ EF10_NVRAM_CHUNK
,
1271 total_length
- EF10_NVRAM_CHUNK
,
1272 MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT
)) != 0)
1276 /* Check segment ends with PARTITION_TRAILER and END tags */
1277 if ((rc
= tlv_find(&cursor
, TLV_TAG_PARTITION_TRAILER
)) != 0) {
1281 trailer
= (struct tlv_partition_trailer
*)tlv_item(&cursor
);
1283 if ((rc
= tlv_advance(&cursor
)) != 0) {
1287 if (tlv_tag(&cursor
) != TLV_TAG_END
) {
1292 /* Check data read from segment is consistent */
1293 if (trailer
->generation
!= header
->generation
) {
1295 * The partition data may have been modified between successive
1296 * MCDI NVRAM_READ requests by the MC or another PCI function.
1298 * The caller must retry to obtain consistent partition data.
1304 /* Verify segment checksum */
1306 for (pos
= 0; (size_t)pos
< total_length
; pos
+= sizeof (uint32_t)) {
1307 cksum
+= *((uint32_t *)(seg_data
+ pos
));
1317 EFSYS_PROBE(fail11
);
1319 EFSYS_PROBE(fail10
);
1337 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1343 * Read a single TLV item from a host memory
1344 * buffer containing a TLV formatted segment.
1346 __checkReturn efx_rc_t
1347 ef10_nvram_buf_read_tlv(
1348 __in efx_nic_t
*enp
,
1349 __in_bcount(max_seg_size
) caddr_t seg_data
,
1350 __in
size_t max_seg_size
,
1352 __deref_out_bcount_opt(*sizep
) caddr_t
*datap
,
1353 __out
size_t *sizep
)
1355 tlv_cursor_t cursor
;
1361 _NOTE(ARGUNUSED(enp
))
1363 if ((seg_data
== NULL
) || (max_seg_size
== 0)) {
1368 /* Find requested TLV tag in segment data */
1369 if ((rc
= tlv_init_cursor_from_size(&cursor
, (uint8_t *)seg_data
,
1370 max_seg_size
)) != 0) {
1374 if ((rc
= tlv_find(&cursor
, tag
)) != 0) {
1378 value
= (caddr_t
)tlv_value(&cursor
);
1379 length
= tlv_length(&cursor
);
1384 /* Copy out data from TLV item */
1385 EFSYS_KMEM_ALLOC(enp
->en_esip
, length
, data
);
1390 memcpy(data
, value
, length
);
1405 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1410 /* Read a single TLV item from the first segment in a TLV formatted partition */
1411 __checkReturn efx_rc_t
1412 ef10_nvram_partn_read_tlv(
1413 __in efx_nic_t
*enp
,
1414 __in
uint32_t partn
,
1416 __deref_out_bcount_opt(*seg_sizep
) caddr_t
*seg_datap
,
1417 __out
size_t *seg_sizep
)
1419 caddr_t seg_data
= NULL
;
1420 size_t partn_size
= 0;
1426 /* Allocate sufficient memory for the entire partition */
1427 if ((rc
= ef10_nvram_partn_size(enp
, partn
, &partn_size
)) != 0)
1430 if (partn_size
== 0) {
1435 EFSYS_KMEM_ALLOC(enp
->en_esip
, partn_size
, seg_data
);
1436 if (seg_data
== NULL
) {
1442 * Read the first segment in a TLV partition. Retry until consistent
1443 * segment contents are returned. Inconsistent data may be read if:
1444 * a) the segment contents are invalid
1445 * b) the MC has rebooted while we were reading the partition
1446 * c) the partition has been modified while we were reading it
1447 * Limit retry attempts to ensure forward progress.
1451 if ((rc
= ef10_nvram_read_tlv_segment(enp
, partn
, 0,
1452 seg_data
, partn_size
)) != 0)
1454 } while ((rc
== EAGAIN
) && (retry
> 0));
1457 /* Failed to obtain consistent segment data */
1464 if ((rc
= ef10_nvram_buf_read_tlv(enp
, seg_data
, partn_size
,
1465 tag
, &data
, &length
)) != 0)
1468 EFSYS_KMEM_FREE(enp
->en_esip
, partn_size
, seg_data
);
1471 *seg_sizep
= length
;
1480 EFSYS_KMEM_FREE(enp
->en_esip
, partn_size
, seg_data
);
1486 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1491 /* Compute the size of a segment. */
1492 static __checkReturn efx_rc_t
1493 ef10_nvram_buf_segment_size(
1494 __in caddr_t seg_data
,
1495 __in
size_t max_seg_size
,
1496 __out
size_t *seg_sizep
)
1499 tlv_cursor_t cursor
;
1500 struct tlv_partition_header
*header
;
1503 uint32_t *end_tag_position
;
1504 uint32_t segment_length
;
1506 /* A PARTITION_HEADER tag must be the first item at the given offset */
1507 if ((rc
= tlv_init_cursor_from_size(&cursor
, (uint8_t *)seg_data
,
1508 max_seg_size
)) != 0) {
1512 if (tlv_tag(&cursor
) != TLV_TAG_PARTITION_HEADER
) {
1516 header
= (struct tlv_partition_header
*)tlv_item(&cursor
);
1518 /* Check TLV segment length (includes the END tag) */
1519 *seg_sizep
= __LE_TO_CPU_32(header
->total_length
);
1520 if (*seg_sizep
> max_seg_size
) {
1525 /* Check segment ends with PARTITION_TRAILER and END tags */
1526 if ((rc
= tlv_find(&cursor
, TLV_TAG_PARTITION_TRAILER
)) != 0) {
1531 if ((rc
= tlv_advance(&cursor
)) != 0) {
1535 if (tlv_tag(&cursor
) != TLV_TAG_END
) {
1539 end_tag_position
= cursor
.current
;
1541 /* Verify segment checksum */
1543 for (pos
= 0; (size_t)pos
< *seg_sizep
; pos
+= sizeof (uint32_t)) {
1544 cksum
+= *((uint32_t *)(seg_data
+ pos
));
1552 * Calculate total length from HEADER to END tags and compare to
1553 * max_seg_size and the total_length field in the HEADER tag.
1555 segment_length
= tlv_block_length_used(&cursor
);
1557 if (segment_length
> max_seg_size
) {
1562 if (segment_length
!= *seg_sizep
) {
1567 /* Skip over the first HEADER tag. */
1568 rc
= tlv_rewind(&cursor
);
1569 rc
= tlv_advance(&cursor
);
1572 if (tlv_tag(&cursor
) == TLV_TAG_END
) {
1573 /* Check that the END tag is the one found earlier. */
1574 if (cursor
.current
!= end_tag_position
)
1578 /* Check for duplicate HEADER tags before the END tag. */
1579 if (tlv_tag(&cursor
) == TLV_TAG_PARTITION_HEADER
) {
1584 rc
= tlv_advance(&cursor
);
1592 EFSYS_PROBE(fail12
);
1594 EFSYS_PROBE(fail11
);
1596 EFSYS_PROBE(fail10
);
1614 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1620 * Add or update a single TLV item in a host memory buffer containing a TLV
1621 * formatted segment. Historically partitions consisted of only one segment.
1623 __checkReturn efx_rc_t
1624 ef10_nvram_buf_write_tlv(
1625 __inout_bcount(max_seg_size
) caddr_t seg_data
,
1626 __in
size_t max_seg_size
,
1628 __in_bcount(tag_size
) caddr_t tag_data
,
1629 __in
size_t tag_size
,
1630 __out
size_t *total_lengthp
)
1632 tlv_cursor_t cursor
;
1633 struct tlv_partition_header
*header
;
1634 struct tlv_partition_trailer
*trailer
;
1635 uint32_t generation
;
1640 /* A PARTITION_HEADER tag must be the first item (at offset zero) */
1641 if ((rc
= tlv_init_cursor_from_size(&cursor
, (uint8_t *)seg_data
,
1642 max_seg_size
)) != 0) {
1646 if (tlv_tag(&cursor
) != TLV_TAG_PARTITION_HEADER
) {
1650 header
= (struct tlv_partition_header
*)tlv_item(&cursor
);
1652 /* Update the TLV chain to contain the new data */
1653 if ((rc
= tlv_find(&cursor
, tag
)) == 0) {
1654 /* Modify existing TLV item */
1655 if ((rc
= tlv_modify(&cursor
, tag
,
1656 (uint8_t *)tag_data
, tag_size
)) != 0)
1659 /* Insert a new TLV item before the PARTITION_TRAILER */
1660 rc
= tlv_find(&cursor
, TLV_TAG_PARTITION_TRAILER
);
1665 if ((rc
= tlv_insert(&cursor
, tag
,
1666 (uint8_t *)tag_data
, tag_size
)) != 0) {
1672 /* Find the trailer tag */
1673 if ((rc
= tlv_find(&cursor
, TLV_TAG_PARTITION_TRAILER
)) != 0) {
1677 trailer
= (struct tlv_partition_trailer
*)tlv_item(&cursor
);
1679 /* Update PARTITION_HEADER and PARTITION_TRAILER fields */
1680 *total_lengthp
= tlv_block_length_used(&cursor
);
1681 if (*total_lengthp
> max_seg_size
) {
1685 generation
= __LE_TO_CPU_32(header
->generation
) + 1;
1687 header
->total_length
= __CPU_TO_LE_32(*total_lengthp
);
1688 header
->generation
= __CPU_TO_LE_32(generation
);
1689 trailer
->generation
= __CPU_TO_LE_32(generation
);
1691 /* Recompute PARTITION_TRAILER checksum */
1692 trailer
->checksum
= 0;
1694 for (pos
= 0; (size_t)pos
< *total_lengthp
; pos
+= sizeof (uint32_t)) {
1695 cksum
+= *((uint32_t *)(seg_data
+ pos
));
1697 trailer
->checksum
= ~cksum
+ 1;
1714 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1720 * Add or update a single TLV item in the first segment of a TLV formatted
1721 * dynamic config partition. The first segment is the current active
1724 __checkReturn efx_rc_t
1725 ef10_nvram_partn_write_tlv(
1726 __in efx_nic_t
*enp
,
1727 __in
uint32_t partn
,
1729 __in_bcount(size
) caddr_t data
,
1732 return ef10_nvram_partn_write_segment_tlv(enp
, partn
, tag
, data
,
1737 * Read a segment from nvram at the given offset into a buffer (segment_data)
1738 * and optionally write a new tag to it.
1740 static __checkReturn efx_rc_t
1741 ef10_nvram_segment_write_tlv(
1742 __in efx_nic_t
*enp
,
1743 __in
uint32_t partn
,
1745 __in_bcount(size
) caddr_t data
,
1747 __inout caddr_t
*seg_datap
,
1748 __inout
size_t *partn_offsetp
,
1749 __inout
size_t *src_remain_lenp
,
1750 __inout
size_t *dest_remain_lenp
,
1751 __in boolean_t write
)
1755 size_t original_segment_size
;
1756 size_t modified_segment_size
;
1759 * Read the segment from NVRAM into the segment_data buffer and validate
1760 * it, returning if it does not validate. This is not a failure unless
1761 * this is the first segment in a partition. In this case the caller
1762 * must propagate the error.
1764 status
= ef10_nvram_read_tlv_segment(enp
, partn
, *partn_offsetp
,
1765 *seg_datap
, *src_remain_lenp
);
1771 status
= ef10_nvram_buf_segment_size(*seg_datap
,
1772 *src_remain_lenp
, &original_segment_size
);
1779 /* Update the contents of the segment in the buffer */
1780 if ((rc
= ef10_nvram_buf_write_tlv(*seg_datap
,
1781 *dest_remain_lenp
, tag
, data
, size
,
1782 &modified_segment_size
)) != 0) {
1785 *dest_remain_lenp
-= modified_segment_size
;
1786 *seg_datap
+= modified_segment_size
;
1789 * We won't modify this segment, but still need to update the
1790 * remaining lengths and pointers.
1792 *dest_remain_lenp
-= original_segment_size
;
1793 *seg_datap
+= original_segment_size
;
1796 *partn_offsetp
+= original_segment_size
;
1797 *src_remain_lenp
-= original_segment_size
;
1806 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1812 * Add or update a single TLV item in either the first segment or in all
1813 * segments in a TLV formatted dynamic config partition. Dynamic config
1814 * partitions on boards that support RFID are divided into a number of segments,
1815 * each formatted like a partition, with header, trailer and end tags. The first
1816 * segment is the current active configuration.
1818 * The segments are initialised by manftest and each contain a different
1819 * configuration e.g. firmware variant. The firmware can be instructed
1820 * via RFID to copy a segment to replace the first segment, hence changing the
1821 * active configuration. This allows ops to change the configuration of a board
1822 * prior to shipment using RFID.
1824 * Changes to the dynamic config may need to be written to all segments (e.g.
1825 * firmware versions) or just the first segment (changes to the active
1826 * configuration). See SF-111324-SW "The use of RFID in Solarflare Products".
1827 * If only the first segment is written the code still needs to be aware of the
1828 * possible presence of subsequent segments as writing to a segment may cause
1829 * its size to increase, which would overwrite the subsequent segments and
1832 __checkReturn efx_rc_t
1833 ef10_nvram_partn_write_segment_tlv(
1834 __in efx_nic_t
*enp
,
1835 __in
uint32_t partn
,
1837 __in_bcount(size
) caddr_t data
,
1839 __in boolean_t all_segments
)
1841 size_t partn_size
= 0;
1843 size_t total_length
= 0;
1845 size_t current_offset
= 0;
1846 size_t remaining_original_length
;
1847 size_t remaining_modified_length
;
1848 caddr_t segment_data
;
1850 EFSYS_ASSERT3U(partn
, ==, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG
);
1852 /* Allocate sufficient memory for the entire partition */
1853 if ((rc
= ef10_nvram_partn_size(enp
, partn
, &partn_size
)) != 0)
1856 EFSYS_KMEM_ALLOC(enp
->en_esip
, partn_size
, partn_data
);
1857 if (partn_data
== NULL
) {
1862 remaining_original_length
= partn_size
;
1863 remaining_modified_length
= partn_size
;
1864 segment_data
= partn_data
;
1866 /* Lock the partition */
1867 if ((rc
= ef10_nvram_partn_lock(enp
, partn
)) != 0)
1870 /* Iterate over each (potential) segment to update it. */
1872 boolean_t write
= all_segments
|| current_offset
== 0;
1874 rc
= ef10_nvram_segment_write_tlv(enp
, partn
, tag
, data
, size
,
1875 &segment_data
, ¤t_offset
, &remaining_original_length
,
1876 &remaining_modified_length
, write
);
1878 if (current_offset
== 0) {
1880 * If no data has been read then the first
1881 * segment is invalid, which is an error.
1887 } while (current_offset
< partn_size
);
1889 total_length
= segment_data
- partn_data
;
1892 * We've run out of space. This should actually be dealt with by
1893 * ef10_nvram_buf_write_tlv returning ENOSPC.
1895 if (total_length
> partn_size
) {
1900 /* Erase the whole partition in NVRAM */
1901 if ((rc
= ef10_nvram_partn_erase(enp
, partn
, 0, partn_size
)) != 0)
1904 /* Write new partition contents from the buffer to NVRAM */
1905 if ((rc
= ef10_nvram_partn_write(enp
, partn
, 0, partn_data
,
1906 total_length
)) != 0)
1909 /* Unlock the partition */
1910 (void) ef10_nvram_partn_unlock(enp
, partn
, NULL
);
1912 EFSYS_KMEM_FREE(enp
->en_esip
, partn_size
, partn_data
);
1925 (void) ef10_nvram_partn_unlock(enp
, partn
, NULL
);
1929 EFSYS_KMEM_FREE(enp
->en_esip
, partn_size
, partn_data
);
1933 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1939 * Get the size of a NVRAM partition. This is the total size allocated in nvram,
1940 * not the data used by the segments in the partition.
1942 __checkReturn efx_rc_t
1943 ef10_nvram_partn_size(
1944 __in efx_nic_t
*enp
,
1945 __in
uint32_t partn
,
1946 __out
size_t *sizep
)
1950 if ((rc
= efx_mcdi_nvram_info(enp
, partn
, sizep
,
1951 NULL
, NULL
, NULL
)) != 0)
1957 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1962 __checkReturn efx_rc_t
1963 ef10_nvram_partn_lock(
1964 __in efx_nic_t
*enp
,
1965 __in
uint32_t partn
)
1969 if ((rc
= efx_mcdi_nvram_update_start(enp
, partn
)) != 0)
1975 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1980 __checkReturn efx_rc_t
1981 ef10_nvram_partn_read_mode(
1982 __in efx_nic_t
*enp
,
1983 __in
uint32_t partn
,
1984 __in
unsigned int offset
,
1985 __out_bcount(size
) caddr_t data
,
1993 chunk
= MIN(size
, EF10_NVRAM_CHUNK
);
1995 if ((rc
= efx_mcdi_nvram_read(enp
, partn
, offset
,
1996 data
, chunk
, mode
)) != 0) {
2008 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
2013 __checkReturn efx_rc_t
2014 ef10_nvram_partn_read(
2015 __in efx_nic_t
*enp
,
2016 __in
uint32_t partn
,
2017 __in
unsigned int offset
,
2018 __out_bcount(size
) caddr_t data
,
2022 * An A/B partition has two data stores (current and backup).
2023 * Read requests which come in through the EFX API expect to read the
2024 * current, active store of an A/B partition. For non A/B partitions,
2025 * there is only a single store and so the mode param is ignored.
2027 return ef10_nvram_partn_read_mode(enp
, partn
, offset
, data
, size
,
2028 MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT
);
2031 __checkReturn efx_rc_t
2032 ef10_nvram_partn_read_backup(
2033 __in efx_nic_t
*enp
,
2034 __in
uint32_t partn
,
2035 __in
unsigned int offset
,
2036 __out_bcount(size
) caddr_t data
,
2040 * An A/B partition has two data stores (current and backup).
2041 * Read the backup store of an A/B partition (i.e. the store currently
2042 * being written to if the partition is locked).
2044 * This is needed when comparing the existing partition content to avoid
2045 * unnecessary writes, or to read back what has been written to check
2046 * that the writes have succeeded.
2048 return ef10_nvram_partn_read_mode(enp
, partn
, offset
, data
, size
,
2049 MC_CMD_NVRAM_READ_IN_V2_TARGET_BACKUP
);
2052 __checkReturn efx_rc_t
2053 ef10_nvram_partn_erase(
2054 __in efx_nic_t
*enp
,
2055 __in
uint32_t partn
,
2056 __in
unsigned int offset
,
2060 uint32_t erase_size
;
2062 if ((rc
= efx_mcdi_nvram_info(enp
, partn
, NULL
, NULL
,
2063 &erase_size
, NULL
)) != 0)
2066 if (erase_size
== 0) {
2067 if ((rc
= efx_mcdi_nvram_erase(enp
, partn
, offset
, size
)) != 0)
2070 if (size
% erase_size
!= 0) {
2075 if ((rc
= efx_mcdi_nvram_erase(enp
, partn
, offset
,
2078 offset
+= erase_size
;
2092 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
2097 __checkReturn efx_rc_t
2098 ef10_nvram_partn_write(
2099 __in efx_nic_t
*enp
,
2100 __in
uint32_t partn
,
2101 __in
unsigned int offset
,
2102 __in_bcount(size
) caddr_t data
,
2106 uint32_t write_size
;
2109 if ((rc
= efx_mcdi_nvram_info(enp
, partn
, NULL
, NULL
,
2110 NULL
, &write_size
)) != 0)
2113 if (write_size
!= 0) {
2115 * Check that the size is a multiple of the write chunk size if
2116 * the write chunk size is available.
2118 if (size
% write_size
!= 0) {
2123 write_size
= EF10_NVRAM_CHUNK
;
2127 chunk
= MIN(size
, write_size
);
2129 if ((rc
= efx_mcdi_nvram_write(enp
, partn
, offset
,
2130 data
, chunk
)) != 0) {
2146 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
2151 __checkReturn efx_rc_t
2152 ef10_nvram_partn_unlock(
2153 __in efx_nic_t
*enp
,
2154 __in
uint32_t partn
,
2155 __out_opt
uint32_t *verify_resultp
)
2157 boolean_t reboot
= B_FALSE
;
2160 if (verify_resultp
!= NULL
)
2161 *verify_resultp
= MC_CMD_NVRAM_VERIFY_RC_UNKNOWN
;
2163 rc
= efx_mcdi_nvram_update_finish(enp
, partn
, reboot
, verify_resultp
);
2170 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
2175 __checkReturn efx_rc_t
2176 ef10_nvram_partn_set_version(
2177 __in efx_nic_t
*enp
,
2178 __in
uint32_t partn
,
2179 __in_ecount(4) uint16_t version
[4])
2181 struct tlv_partition_version partn_version
;
2185 /* Add or modify partition version TLV item */
2186 partn_version
.version_w
= __CPU_TO_LE_16(version
[0]);
2187 partn_version
.version_x
= __CPU_TO_LE_16(version
[1]);
2188 partn_version
.version_y
= __CPU_TO_LE_16(version
[2]);
2189 partn_version
.version_z
= __CPU_TO_LE_16(version
[3]);
2191 size
= sizeof (partn_version
) - (2 * sizeof (uint32_t));
2193 /* Write the version number to all segments in the partition */
2194 if ((rc
= ef10_nvram_partn_write_segment_tlv(enp
,
2195 NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG
,
2196 TLV_TAG_PARTITION_VERSION(partn
),
2197 (caddr_t
)&partn_version
.version_w
, size
, B_TRUE
)) != 0)
2203 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
2208 #endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */
2212 typedef struct ef10_parttbl_entry_s
{
2214 unsigned int port_mask
;
2215 efx_nvram_type_t nvtype
;
2216 } ef10_parttbl_entry_t
;
2218 /* Port mask values */
2219 #define PORT_1 (1u << 1)
2220 #define PORT_2 (1u << 2)
2221 #define PORT_3 (1u << 3)
2222 #define PORT_4 (1u << 4)
2223 #define PORT_ALL (0xffffffffu)
2225 #define PARTN_MAP_ENTRY(partn, port_mask, nvtype) \
2226 { (NVRAM_PARTITION_TYPE_##partn), (PORT_##port_mask), (EFX_NVRAM_##nvtype) }
2228 /* Translate EFX NVRAM types to firmware partition types */
2229 static ef10_parttbl_entry_t hunt_parttbl
[] = {
2230 /* partn ports nvtype */
2231 PARTN_MAP_ENTRY(MC_FIRMWARE
, ALL
, MC_FIRMWARE
),
2232 PARTN_MAP_ENTRY(MC_FIRMWARE_BACKUP
, ALL
, MC_GOLDEN
),
2233 PARTN_MAP_ENTRY(EXPANSION_ROM
, ALL
, BOOTROM
),
2234 PARTN_MAP_ENTRY(EXPROM_CONFIG_PORT0
, 1, BOOTROM_CFG
),
2235 PARTN_MAP_ENTRY(EXPROM_CONFIG_PORT1
, 2, BOOTROM_CFG
),
2236 PARTN_MAP_ENTRY(EXPROM_CONFIG_PORT2
, 3, BOOTROM_CFG
),
2237 PARTN_MAP_ENTRY(EXPROM_CONFIG_PORT3
, 4, BOOTROM_CFG
),
2238 PARTN_MAP_ENTRY(DYNAMIC_CONFIG
, ALL
, DYNAMIC_CFG
),
2239 PARTN_MAP_ENTRY(FPGA
, ALL
, FPGA
),
2240 PARTN_MAP_ENTRY(FPGA_BACKUP
, ALL
, FPGA_BACKUP
),
2241 PARTN_MAP_ENTRY(LICENSE
, ALL
, LICENSE
),
2244 static ef10_parttbl_entry_t medford_parttbl
[] = {
2245 /* partn ports nvtype */
2246 PARTN_MAP_ENTRY(MC_FIRMWARE
, ALL
, MC_FIRMWARE
),
2247 PARTN_MAP_ENTRY(MC_FIRMWARE_BACKUP
, ALL
, MC_GOLDEN
),
2248 PARTN_MAP_ENTRY(EXPANSION_ROM
, ALL
, BOOTROM
),
2249 PARTN_MAP_ENTRY(EXPROM_CONFIG
, ALL
, BOOTROM_CFG
),
2250 PARTN_MAP_ENTRY(DYNAMIC_CONFIG
, ALL
, DYNAMIC_CFG
),
2251 PARTN_MAP_ENTRY(FPGA
, ALL
, FPGA
),
2252 PARTN_MAP_ENTRY(FPGA_BACKUP
, ALL
, FPGA_BACKUP
),
2253 PARTN_MAP_ENTRY(LICENSE
, ALL
, LICENSE
),
2254 PARTN_MAP_ENTRY(EXPANSION_UEFI
, ALL
, UEFIROM
),
2255 PARTN_MAP_ENTRY(MUM_FIRMWARE
, ALL
, MUM_FIRMWARE
),
2258 static ef10_parttbl_entry_t medford2_parttbl
[] = {
2259 /* partn ports nvtype */
2260 PARTN_MAP_ENTRY(MC_FIRMWARE
, ALL
, MC_FIRMWARE
),
2261 PARTN_MAP_ENTRY(MC_FIRMWARE_BACKUP
, ALL
, MC_GOLDEN
),
2262 PARTN_MAP_ENTRY(EXPANSION_ROM
, ALL
, BOOTROM
),
2263 PARTN_MAP_ENTRY(EXPROM_CONFIG
, ALL
, BOOTROM_CFG
),
2264 PARTN_MAP_ENTRY(DYNAMIC_CONFIG
, ALL
, DYNAMIC_CFG
),
2265 PARTN_MAP_ENTRY(FPGA
, ALL
, FPGA
),
2266 PARTN_MAP_ENTRY(FPGA_BACKUP
, ALL
, FPGA_BACKUP
),
2267 PARTN_MAP_ENTRY(LICENSE
, ALL
, LICENSE
),
2268 PARTN_MAP_ENTRY(EXPANSION_UEFI
, ALL
, UEFIROM
),
2269 PARTN_MAP_ENTRY(MUM_FIRMWARE
, ALL
, MUM_FIRMWARE
),
2270 PARTN_MAP_ENTRY(DYNCONFIG_DEFAULTS
, ALL
, DYNCONFIG_DEFAULTS
),
2271 PARTN_MAP_ENTRY(ROMCONFIG_DEFAULTS
, ALL
, ROMCONFIG_DEFAULTS
),
2272 PARTN_MAP_ENTRY(BUNDLE
, ALL
, BUNDLE
),
2275 static __checkReturn efx_rc_t
2277 __in efx_nic_t
*enp
,
2278 __out ef10_parttbl_entry_t
**parttblp
,
2279 __out
size_t *parttbl_rowsp
)
2281 switch (enp
->en_family
) {
2282 case EFX_FAMILY_HUNTINGTON
:
2283 *parttblp
= hunt_parttbl
;
2284 *parttbl_rowsp
= EFX_ARRAY_SIZE(hunt_parttbl
);
2287 case EFX_FAMILY_MEDFORD
:
2288 *parttblp
= medford_parttbl
;
2289 *parttbl_rowsp
= EFX_ARRAY_SIZE(medford_parttbl
);
2292 case EFX_FAMILY_MEDFORD2
:
2293 *parttblp
= medford2_parttbl
;
2294 *parttbl_rowsp
= EFX_ARRAY_SIZE(medford2_parttbl
);
2298 EFSYS_ASSERT(B_FALSE
);
2304 __checkReturn efx_rc_t
2305 ef10_nvram_type_to_partn(
2306 __in efx_nic_t
*enp
,
2307 __in efx_nvram_type_t type
,
2308 __out
uint32_t *partnp
)
2310 efx_mcdi_iface_t
*emip
= &(enp
->en_mcdi
.em_emip
);
2311 ef10_parttbl_entry_t
*parttbl
= NULL
;
2312 size_t parttbl_rows
= 0;
2315 EFSYS_ASSERT3U(type
, !=, EFX_NVRAM_INVALID
);
2316 EFSYS_ASSERT3U(type
, <, EFX_NVRAM_NTYPES
);
2317 EFSYS_ASSERT(partnp
!= NULL
);
2319 if (ef10_parttbl_get(enp
, &parttbl
, &parttbl_rows
) == 0) {
2320 for (i
= 0; i
< parttbl_rows
; i
++) {
2321 ef10_parttbl_entry_t
*entry
= &parttbl
[i
];
2323 if ((entry
->nvtype
== type
) &&
2324 (entry
->port_mask
& (1u << emip
->emi_port
))) {
2325 *partnp
= entry
->partn
;
2336 static __checkReturn efx_rc_t
2337 ef10_nvram_partn_to_type(
2338 __in efx_nic_t
*enp
,
2339 __in
uint32_t partn
,
2340 __out efx_nvram_type_t
*typep
)
2342 efx_mcdi_iface_t
*emip
= &(enp
->en_mcdi
.em_emip
);
2343 ef10_parttbl_entry_t
*parttbl
= NULL
;
2344 size_t parttbl_rows
= 0;
2347 EFSYS_ASSERT(typep
!= NULL
);
2349 if (ef10_parttbl_get(enp
, &parttbl
, &parttbl_rows
) == 0) {
2350 for (i
= 0; i
< parttbl_rows
; i
++) {
2351 ef10_parttbl_entry_t
*entry
= &parttbl
[i
];
2353 if ((entry
->partn
== partn
) &&
2354 (entry
->port_mask
& (1u << emip
->emi_port
))) {
2355 *typep
= entry
->nvtype
;
2364 __checkReturn efx_rc_t
2366 __in efx_nic_t
*enp
)
2368 efx_nvram_type_t type
;
2369 unsigned int npartns
= 0;
2370 uint32_t *partns
= NULL
;
2375 /* Read available partitions from NVRAM partition map */
2376 size
= MC_CMD_NVRAM_PARTITIONS_OUT_TYPE_ID_MAXNUM
* sizeof (uint32_t);
2377 EFSYS_KMEM_ALLOC(enp
->en_esip
, size
, partns
);
2378 if (partns
== NULL
) {
2383 if ((rc
= efx_mcdi_nvram_partitions(enp
, (caddr_t
)partns
, size
,
2388 for (i
= 0; i
< npartns
; i
++) {
2389 /* Check if the partition is supported for this port */
2390 if ((rc
= ef10_nvram_partn_to_type(enp
, partns
[i
], &type
)) != 0)
2393 if ((rc
= efx_mcdi_nvram_test(enp
, partns
[i
])) != 0)
2397 EFSYS_KMEM_FREE(enp
->en_esip
, size
, partns
);
2404 EFSYS_KMEM_FREE(enp
->en_esip
, size
, partns
);
2406 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
2410 #endif /* EFSYS_OPT_DIAG */
2412 __checkReturn efx_rc_t
2413 ef10_nvram_partn_get_version(
2414 __in efx_nic_t
*enp
,
2415 __in
uint32_t partn
,
2416 __out
uint32_t *subtypep
,
2417 __out_ecount(4) uint16_t version
[4])
2421 /* FIXME: get highest partn version from all ports */
2422 /* FIXME: return partn description if available */
2424 if ((rc
= efx_mcdi_nvram_metadata(enp
, partn
, subtypep
,
2425 version
, NULL
, 0)) != 0)
2431 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
2436 __checkReturn efx_rc_t
2437 ef10_nvram_partn_rw_start(
2438 __in efx_nic_t
*enp
,
2439 __in
uint32_t partn
,
2440 __out
size_t *chunk_sizep
)
2442 uint32_t write_size
= 0;
2445 if ((rc
= efx_mcdi_nvram_info(enp
, partn
, NULL
, NULL
,
2446 NULL
, &write_size
)) != 0)
2449 if ((rc
= ef10_nvram_partn_lock(enp
, partn
)) != 0)
2452 if (chunk_sizep
!= NULL
) {
2453 if (write_size
== 0)
2454 *chunk_sizep
= EF10_NVRAM_CHUNK
;
2456 *chunk_sizep
= write_size
;
2464 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
2469 __checkReturn efx_rc_t
2470 ef10_nvram_partn_rw_finish(
2471 __in efx_nic_t
*enp
,
2472 __in
uint32_t partn
,
2473 __out_opt
uint32_t *verify_resultp
)
2477 if ((rc
= ef10_nvram_partn_unlock(enp
, partn
, verify_resultp
)) != 0)
2483 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
2488 #endif /* EFSYS_OPT_NVRAM */
2490 #endif /* EFX_OPTS_EF10() */