1 /* SPDX-License-Identifier: BSD-3-Clause
3 * Copyright(c) 2019-2021 Xilinx, Inc.
4 * Copyright(c) 2009-2019 Solarflare Communications Inc.
12 #define TAG_TYPE_LBN 7
13 #define TAG_TYPE_WIDTH 1
14 #define TAG_TYPE_LARGE_ITEM_DECODE 1
15 #define TAG_TYPE_SMALL_ITEM_DECODE 0
17 #define TAG_SMALL_ITEM_NAME_LBN 3
18 #define TAG_SMALL_ITEM_NAME_WIDTH 4
19 #define TAG_SMALL_ITEM_SIZE_LBN 0
20 #define TAG_SMALL_ITEM_SIZE_WIDTH 3
22 #define TAG_LARGE_ITEM_NAME_LBN 0
23 #define TAG_LARGE_ITEM_NAME_WIDTH 7
25 #define TAG_NAME_END_DECODE 0x0f
26 #define TAG_NAME_ID_STRING_DECODE 0x02
27 #define TAG_NAME_VPD_R_DECODE 0x10
28 #define TAG_NAME_VPD_W_DECODE 0x11
32 static const efx_vpd_ops_t __efx_vpd_siena_ops = {
33 siena_vpd_init, /* evpdo_init */
34 siena_vpd_size, /* evpdo_size */
35 siena_vpd_read, /* evpdo_read */
36 siena_vpd_verify, /* evpdo_verify */
37 siena_vpd_reinit, /* evpdo_reinit */
38 siena_vpd_get, /* evpdo_get */
39 siena_vpd_set, /* evpdo_set */
40 siena_vpd_next, /* evpdo_next */
41 siena_vpd_write, /* evpdo_write */
42 siena_vpd_fini, /* evpdo_fini */
45 #endif /* EFSYS_OPT_SIENA */
49 static const efx_vpd_ops_t __efx_vpd_ef10_ops = {
50 ef10_vpd_init, /* evpdo_init */
51 ef10_vpd_size, /* evpdo_size */
52 ef10_vpd_read, /* evpdo_read */
53 ef10_vpd_verify, /* evpdo_verify */
54 ef10_vpd_reinit, /* evpdo_reinit */
55 ef10_vpd_get, /* evpdo_get */
56 ef10_vpd_set, /* evpdo_set */
57 ef10_vpd_next, /* evpdo_next */
58 ef10_vpd_write, /* evpdo_write */
59 ef10_vpd_fini, /* evpdo_fini */
62 #endif /* EFX_OPTS_EF10() */
64 __checkReturn efx_rc_t
68 const efx_vpd_ops_t *evpdop;
71 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
72 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
73 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_VPD));
75 switch (enp->en_family) {
77 case EFX_FAMILY_SIENA:
78 evpdop = &__efx_vpd_siena_ops;
80 #endif /* EFSYS_OPT_SIENA */
82 #if EFSYS_OPT_HUNTINGTON
83 case EFX_FAMILY_HUNTINGTON:
84 evpdop = &__efx_vpd_ef10_ops;
86 #endif /* EFSYS_OPT_HUNTINGTON */
89 case EFX_FAMILY_MEDFORD:
90 evpdop = &__efx_vpd_ef10_ops;
92 #endif /* EFSYS_OPT_MEDFORD */
94 #if EFSYS_OPT_MEDFORD2
95 case EFX_FAMILY_MEDFORD2:
96 evpdop = &__efx_vpd_ef10_ops;
98 #endif /* EFSYS_OPT_MEDFORD2 */
106 if (evpdop->evpdo_init != NULL) {
107 if ((rc = evpdop->evpdo_init(enp)) != 0)
111 enp->en_evpdop = evpdop;
112 enp->en_mod_flags |= EFX_MOD_VPD;
119 EFSYS_PROBE1(fail1, efx_rc_t, rc);
124 __checkReturn efx_rc_t
129 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
132 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
133 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
135 if ((rc = evpdop->evpdo_size(enp, sizep)) != 0)
141 EFSYS_PROBE1(fail1, efx_rc_t, rc);
146 __checkReturn efx_rc_t
149 __out_bcount(size) caddr_t data,
152 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
155 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
156 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
158 if ((rc = evpdop->evpdo_read(enp, data, size)) != 0)
164 EFSYS_PROBE1(fail1, efx_rc_t, rc);
169 __checkReturn efx_rc_t
172 __in_bcount(size) caddr_t data,
175 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
178 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
179 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
181 if ((rc = evpdop->evpdo_verify(enp, data, size)) != 0)
187 EFSYS_PROBE1(fail1, efx_rc_t, rc);
192 __checkReturn efx_rc_t
195 __in_bcount(size) caddr_t data,
198 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
201 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
202 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
204 if (evpdop->evpdo_reinit == NULL) {
209 if ((rc = evpdop->evpdo_reinit(enp, data, size)) != 0)
217 EFSYS_PROBE1(fail1, efx_rc_t, rc);
222 __checkReturn efx_rc_t
225 __in_bcount(size) caddr_t data,
227 __inout efx_vpd_value_t *evvp)
229 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
232 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
233 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
235 if ((rc = evpdop->evpdo_get(enp, data, size, evvp)) != 0) {
245 EFSYS_PROBE1(fail1, efx_rc_t, rc);
250 __checkReturn efx_rc_t
253 __inout_bcount(size) caddr_t data,
255 __in efx_vpd_value_t *evvp)
257 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
260 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
261 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
263 if ((rc = evpdop->evpdo_set(enp, data, size, evvp)) != 0)
269 EFSYS_PROBE1(fail1, efx_rc_t, rc);
274 __checkReturn efx_rc_t
277 __inout_bcount(size) caddr_t data,
279 __out efx_vpd_value_t *evvp,
280 __inout unsigned int *contp)
282 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
285 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
286 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
288 if ((rc = evpdop->evpdo_next(enp, data, size, evvp, contp)) != 0)
294 EFSYS_PROBE1(fail1, efx_rc_t, rc);
299 __checkReturn efx_rc_t
302 __in_bcount(size) caddr_t data,
305 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
308 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
309 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
311 if ((rc = evpdop->evpdo_write(enp, data, size)) != 0)
317 EFSYS_PROBE1(fail1, efx_rc_t, rc);
322 static __checkReturn efx_rc_t
326 __inout unsigned int *offsetp,
327 __out efx_vpd_tag_t *tagp,
328 __out uint16_t *lengthp)
337 if (*offsetp >= size) {
342 EFX_POPULATE_BYTE_1(byte, EFX_BYTE_0, data[*offsetp]);
344 switch (EFX_BYTE_FIELD(byte, TAG_TYPE)) {
345 case TAG_TYPE_SMALL_ITEM_DECODE:
348 name = EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_NAME);
349 length = (uint16_t)EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_SIZE);
353 case TAG_TYPE_LARGE_ITEM_DECODE:
356 if (*offsetp + headlen > size) {
361 name = EFX_BYTE_FIELD(byte, TAG_LARGE_ITEM_NAME);
362 EFX_POPULATE_WORD_2(word,
363 EFX_BYTE_0, data[*offsetp + 1],
364 EFX_BYTE_1, data[*offsetp + 2]);
365 length = EFX_WORD_FIELD(word, EFX_WORD_0);
374 if (*offsetp + headlen + length > size) {
379 EFX_STATIC_ASSERT(TAG_NAME_END_DECODE == EFX_VPD_END);
380 EFX_STATIC_ASSERT(TAG_NAME_ID_STRING_DECODE == EFX_VPD_ID);
381 EFX_STATIC_ASSERT(TAG_NAME_VPD_R_DECODE == EFX_VPD_RO);
382 EFX_STATIC_ASSERT(TAG_NAME_VPD_W_DECODE == EFX_VPD_RW);
383 if (name != EFX_VPD_END && name != EFX_VPD_ID &&
384 name != EFX_VPD_RO) {
402 EFSYS_PROBE1(fail1, efx_rc_t, rc);
407 static __checkReturn efx_rc_t
408 efx_vpd_next_keyword(
409 __in_bcount(size) caddr_t tag,
411 __in unsigned int pos,
412 __out efx_vpd_keyword_t *keywordp,
413 __out uint8_t *lengthp)
415 efx_vpd_keyword_t keyword;
419 if (pos + 3U > size) {
424 keyword = EFX_VPD_KEYWORD(tag[pos], tag[pos + 1]);
425 length = tag[pos + 2];
427 if (length == 0 || pos + 3U + length > size) {
440 EFSYS_PROBE1(fail1, efx_rc_t, rc);
445 __checkReturn efx_rc_t
447 __in_bcount(size) caddr_t data,
449 __out size_t *lengthp)
457 _NOTE(CONSTANTCONDITION)
459 if ((rc = efx_vpd_next_tag(data, size, &offset,
460 &tag, &taglen)) != 0)
463 if (tag == EFX_VPD_END)
472 EFSYS_PROBE1(fail1, efx_rc_t, rc);
477 __checkReturn efx_rc_t
479 __in_bcount(size) caddr_t data,
481 __out_opt boolean_t *cksummedp)
484 efx_vpd_keyword_t keyword;
491 boolean_t cksummed = B_FALSE;
495 * Parse every tag,keyword in the existing VPD. If the csum is present,
496 * the assert it is correct, and is the final keyword in the RO block.
499 _NOTE(CONSTANTCONDITION)
501 if ((rc = efx_vpd_next_tag(data, size, &offset,
502 &tag, &taglen)) != 0)
504 if (tag == EFX_VPD_END)
506 else if (tag == EFX_VPD_ID)
509 for (pos = 0; pos != taglen; pos += 3 + keylen) {
510 /* RV keyword must be the last in the block */
516 if ((rc = efx_vpd_next_keyword(data + offset,
517 taglen, pos, &keyword, &keylen)) != 0)
520 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
522 for (i = 0; i < offset + pos + 4; i++)
543 if (cksummedp != NULL)
544 *cksummedp = cksummed;
557 EFSYS_PROBE1(fail1, efx_rc_t, rc);
562 static uint8_t __efx_vpd_blank_pid[] = {
563 /* Large resource type ID length 1 */
565 /* Product name ' ' */
569 static uint8_t __efx_vpd_blank_r[] = {
570 /* Large resource type VPD-R length 4 */
572 /* RV keyword length 1 */
574 /* RV payload checksum */
578 __checkReturn efx_rc_t
580 __in_bcount(size) caddr_t data,
582 __in boolean_t wantpid)
584 unsigned int offset = 0;
596 memcpy(data + offset, __efx_vpd_blank_pid,
597 sizeof (__efx_vpd_blank_pid));
598 offset += sizeof (__efx_vpd_blank_pid);
601 memcpy(data + offset, __efx_vpd_blank_r, sizeof (__efx_vpd_blank_r));
602 offset += sizeof (__efx_vpd_blank_r);
604 /* Update checksum */
606 for (pos = 0; pos < offset; pos++)
608 data[offset - 1] -= cksum;
610 /* Append trailing tag */
611 EFX_POPULATE_BYTE_3(byte,
612 TAG_TYPE, TAG_TYPE_SMALL_ITEM_DECODE,
613 TAG_SMALL_ITEM_NAME, TAG_NAME_END_DECODE,
614 TAG_SMALL_ITEM_SIZE, 0);
615 data[offset] = EFX_BYTE_FIELD(byte, EFX_BYTE_0);
621 EFSYS_PROBE1(fail1, efx_rc_t, rc);
626 __checkReturn efx_rc_t
628 __in_bcount(size) caddr_t data,
630 __out efx_vpd_tag_t *tagp,
631 __out efx_vpd_keyword_t *keywordp,
632 __out_opt unsigned int *payloadp,
633 __out_opt uint8_t *paylenp,
634 __inout unsigned int *contp)
637 efx_vpd_keyword_t keyword = 0;
647 _NOTE(CONSTANTCONDITION)
649 if ((rc = efx_vpd_next_tag(data, size, &offset,
650 &tag, &taglen)) != 0)
653 if (tag == EFX_VPD_END) {
660 if (tag == EFX_VPD_ID) {
661 if (index++ == *contp) {
662 EFSYS_ASSERT3U(taglen, <, 0x100);
664 paylen = (uint8_t)MIN(taglen, 0xff);
669 for (pos = 0; pos != taglen; pos += 3 + keylen) {
670 if ((rc = efx_vpd_next_keyword(data + offset,
671 taglen, pos, &keyword, &keylen)) != 0)
674 if (index++ == *contp) {
689 if (payloadp != NULL)
700 EFSYS_PROBE1(fail1, efx_rc_t, rc);
705 __checkReturn efx_rc_t
707 __in_bcount(size) caddr_t data,
709 __in efx_vpd_tag_t tag,
710 __in efx_vpd_keyword_t keyword,
711 __out unsigned int *payloadp,
712 __out uint8_t *paylenp)
715 efx_vpd_keyword_t ikeyword;
723 _NOTE(CONSTANTCONDITION)
725 if ((rc = efx_vpd_next_tag(data, size, &offset,
726 &itag, &taglen)) != 0)
728 if (itag == EFX_VPD_END)
732 if (itag == EFX_VPD_ID) {
733 EFSYS_ASSERT3U(taglen, <, 0x100);
735 *paylenp = (uint8_t)MIN(taglen, 0xff);
740 for (pos = 0; pos != taglen; pos += 3 + keylen) {
741 if ((rc = efx_vpd_next_keyword(data + offset,
742 taglen, pos, &ikeyword, &keylen)) != 0)
745 if (ikeyword == keyword) {
747 *payloadp = offset + pos + 3;
762 EFSYS_PROBE1(fail1, efx_rc_t, rc);
767 __checkReturn efx_rc_t
769 __in_bcount(size) caddr_t data,
771 __in efx_vpd_value_t *evvp)
775 efx_vpd_keyword_t keyword;
778 unsigned int taghead;
788 switch (evvp->evv_tag) {
790 if (evvp->evv_keyword != 0) {
795 /* Can't delete the ID keyword */
796 if (evvp->evv_length == 0) {
803 if (evvp->evv_keyword == EFX_VPD_KEYWORD('R', 'V')) {
814 /* Determine total size of all current tags */
815 if ((rc = efx_vpd_hunk_length(data, size, &used)) != 0)
819 _NOTE(CONSTANTCONDITION)
822 if ((rc = efx_vpd_next_tag(data, size, &offset,
823 &tag, &taglen)) != 0)
825 if (tag == EFX_VPD_END)
827 else if (tag != evvp->evv_tag) {
832 /* We only support modifying large resource tags */
833 if (offset - taghead != 3) {
839 * Work out the offset of the byte immediately after the
840 * old (=source) and new (=dest) new keyword/tag
843 if (tag == EFX_VPD_ID) {
844 source = offset + taglen;
845 dest = offset + evvp->evv_length;
849 EFSYS_ASSERT3U(tag, ==, EFX_VPD_RO);
851 for (pos = 0; pos != taglen; pos += 3 + keylen) {
852 if ((rc = efx_vpd_next_keyword(data + offset,
853 taglen, pos, &keyword, &keylen)) != 0)
856 if (keyword == evvp->evv_keyword &&
857 evvp->evv_length == 0) {
858 /* Deleting this keyword */
859 source = offset + pos + 3 + keylen;
863 } else if (keyword == evvp->evv_keyword) {
864 /* Adjusting this keyword */
865 source = offset + pos + 3 + keylen;
866 dest = offset + pos + 3 + evvp->evv_length;
869 } else if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
870 /* The RV keyword must be at the end */
871 EFSYS_ASSERT3U(pos + 3 + keylen, ==, taglen);
874 * The keyword doesn't already exist. If the
875 * user deleting a non-existant keyword then
878 if (evvp->evv_length == 0)
881 /* Insert this keyword before the RV keyword */
882 source = offset + pos;
883 dest = offset + pos + 3 + evvp->evv_length;
889 if (used + dest > size + source) {
894 /* Move trailing data */
895 (void) memmove(data + dest, data + source, used - source);
898 memcpy(data + dest - evvp->evv_length, evvp->evv_value,
901 /* Insert new keyword header if required */
902 if (tag != EFX_VPD_ID && evvp->evv_length > 0) {
903 EFX_POPULATE_WORD_1(word, EFX_WORD_0,
905 data[offset + pos + 0] =
906 EFX_WORD_FIELD(word, EFX_BYTE_0);
907 data[offset + pos + 1] =
908 EFX_WORD_FIELD(word, EFX_BYTE_1);
909 data[offset + pos + 2] = evvp->evv_length;
912 /* Modify tag length (large resource type) */
913 taglen += (uint16_t)(dest - source);
914 EFX_POPULATE_WORD_1(word, EFX_WORD_0, taglen);
915 data[offset - 2] = EFX_WORD_FIELD(word, EFX_BYTE_0);
916 data[offset - 1] = EFX_WORD_FIELD(word, EFX_BYTE_1);
921 /* Unable to find the matching tag */
926 /* Find the RV tag, and update the checksum */
928 _NOTE(CONSTANTCONDITION)
930 if ((rc = efx_vpd_next_tag(data, size, &offset,
931 &tag, &taglen)) != 0)
933 if (tag == EFX_VPD_END)
935 if (tag == EFX_VPD_RO) {
936 for (pos = 0; pos != taglen; pos += 3 + keylen) {
937 if ((rc = efx_vpd_next_keyword(data + offset,
938 taglen, pos, &keyword, &keylen)) != 0)
941 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
943 for (i = 0; i < offset + pos + 3; i++)
954 /* Zero out the unused portion */
955 (void) memset(data + offset + taglen, 0xff, size - offset - taglen);
976 EFSYS_PROBE1(fail1, efx_rc_t, rc);
985 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
987 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
988 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
989 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
991 if (evpdop->evpdo_fini != NULL)
992 evpdop->evpdo_fini(enp);
994 enp->en_evpdop = NULL;
995 enp->en_mod_flags &= ~EFX_MOD_VPD;
998 #endif /* EFSYS_OPT_VPD */