1 /* SPDX-License-Identifier: BSD-3-Clause
3 * Copyright(c) 2019-2020 Xilinx, Inc.
4 * Copyright(c) 2009-2019 Solarflare Communications Inc.
15 #include "ef10_tlv_layout.h"
17 __checkReturn efx_rc_t
27 EFSYS_ASSERT3U(enp
->en_mod_flags
, &, EFX_MOD_PROBE
);
28 EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp
));
30 if (enp
->en_nic_cfg
.enc_vpd_is_global
) {
31 tag
= TLV_TAG_GLOBAL_STATIC_VPD
;
33 pci_pf
= enp
->en_nic_cfg
.enc_pf
;
34 tag
= TLV_TAG_PF_STATIC_VPD(pci_pf
);
38 * The VPD interface exposes VPD resources from the combined static and
39 * dynamic VPD storage. As the static VPD configuration should *never*
40 * change, we can cache it.
44 rc
= ef10_nvram_partn_read_tlv(enp
,
45 NVRAM_PARTITION_TYPE_STATIC_CONFIG
,
46 tag
, &svpd
, &svpd_size
);
49 /* Unprivileged functions cannot access VPD */
55 if (svpd
!= NULL
&& svpd_size
> 0) {
56 if ((rc
= efx_vpd_hunk_verify(svpd
, svpd_size
, NULL
)) != 0)
60 enp
->en_arch
.ef10
.ena_svpd
= svpd
;
61 enp
->en_arch
.ef10
.ena_svpd_length
= svpd_size
;
69 EFSYS_KMEM_FREE(enp
->en_esip
, svpd_size
, svpd
);
71 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
76 __checkReturn efx_rc_t
82 efx_nvram_info_t eni
= { 0 };
84 EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp
));
87 * This function returns the total size the user should allocate
88 * for all VPD operations. We've already cached the static vpd,
89 * so we just need to return an upper bound on the dynamic vpd,
90 * which is the size of the DYNAMIC_CONFIG partition.
92 if ((rc
= efx_mcdi_nvram_info(enp
,
93 NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG
, &eni
)) != 0)
96 *sizep
= eni
.eni_partn_size
;
101 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
106 __checkReturn efx_rc_t
109 __out_bcount(size
) caddr_t data
,
118 EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp
));
120 if (enp
->en_nic_cfg
.enc_vpd_is_global
) {
121 tag
= TLV_TAG_GLOBAL_DYNAMIC_VPD
;
123 pci_pf
= enp
->en_nic_cfg
.enc_pf
;
124 tag
= TLV_TAG_PF_DYNAMIC_VPD(pci_pf
);
127 if ((rc
= ef10_nvram_partn_read_tlv(enp
,
128 NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG
,
129 tag
, &dvpd
, &dvpd_size
)) != 0)
132 if (dvpd_size
> size
) {
137 memcpy(data
, dvpd
, dvpd_size
);
139 /* Pad data with all-1s, consistent with update operations */
140 memset(data
+ dvpd_size
, 0xff, size
- dvpd_size
);
143 EFSYS_KMEM_FREE(enp
->en_esip
, dvpd_size
, dvpd
);
151 EFSYS_KMEM_FREE(enp
->en_esip
, dvpd_size
, dvpd
);
153 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
158 __checkReturn efx_rc_t
161 __in_bcount(size
) caddr_t data
,
166 efx_vpd_keyword_t skey
;
167 efx_vpd_keyword_t dkey
;
172 EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp
));
175 * Strictly you could take the view that dynamic vpd is optional.
176 * Instead, to conform more closely to the read/verify/reinit()
177 * paradigm, we require dynamic vpd. ef10_vpd_reinit() will
178 * reinitialize it as required.
180 if ((rc
= efx_vpd_hunk_verify(data
, size
, NULL
)) != 0)
184 * Verify that there is no duplication between the static and
185 * dynamic cfg sectors.
187 if (enp
->en_arch
.ef10
.ena_svpd_length
== 0)
191 _NOTE(CONSTANTCONDITION
)
193 if ((rc
= efx_vpd_hunk_next(data
, size
, &dtag
,
194 &dkey
, NULL
, NULL
, &dcont
)) != 0)
200 * Skip the RV keyword. It should be present in both the static
201 * and dynamic cfg sectors.
203 if (dtag
== EFX_VPD_RO
&& dkey
== EFX_VPD_KEYWORD('R', 'V'))
207 _NOTE(CONSTANTCONDITION
)
209 if ((rc
= efx_vpd_hunk_next(
210 enp
->en_arch
.ef10
.ena_svpd
,
211 enp
->en_arch
.ef10
.ena_svpd_length
, &stag
, &skey
,
212 NULL
, NULL
, &scont
)) != 0)
217 if (stag
== dtag
&& skey
== dkey
) {
234 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
239 __checkReturn efx_rc_t
242 __in_bcount(size
) caddr_t data
,
249 * Only create an ID string if the dynamic cfg doesn't have one
251 if (enp
->en_arch
.ef10
.ena_svpd_length
== 0)
257 rc
= efx_vpd_hunk_get(enp
->en_arch
.ef10
.ena_svpd
,
258 enp
->en_arch
.ef10
.ena_svpd_length
,
259 EFX_VPD_ID
, 0, &offset
, &length
);
262 else if (rc
== ENOENT
)
268 if ((rc
= efx_vpd_hunk_reinit(data
, size
, wantpid
)) != 0)
276 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
281 __checkReturn efx_rc_t
284 __in_bcount(size
) caddr_t data
,
286 __inout efx_vpd_value_t
*evvp
)
292 EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp
));
294 /* Attempt to satisfy the request from svpd first */
295 if (enp
->en_arch
.ef10
.ena_svpd_length
> 0) {
296 if ((rc
= efx_vpd_hunk_get(enp
->en_arch
.ef10
.ena_svpd
,
297 enp
->en_arch
.ef10
.ena_svpd_length
, evvp
->evv_tag
,
298 evvp
->evv_keyword
, &offset
, &length
)) == 0) {
299 evvp
->evv_length
= length
;
300 memcpy(evvp
->evv_value
,
301 enp
->en_arch
.ef10
.ena_svpd
+ offset
, length
);
303 } else if (rc
!= ENOENT
)
307 /* And then from the provided data buffer */
308 if ((rc
= efx_vpd_hunk_get(data
, size
, evvp
->evv_tag
,
309 evvp
->evv_keyword
, &offset
, &length
)) != 0) {
315 evvp
->evv_length
= length
;
316 memcpy(evvp
->evv_value
, data
+ offset
, length
);
323 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
328 __checkReturn efx_rc_t
331 __in_bcount(size
) caddr_t data
,
333 __in efx_vpd_value_t
*evvp
)
337 EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp
));
339 /* If the provided (tag,keyword) exists in svpd, then it is readonly */
340 if (enp
->en_arch
.ef10
.ena_svpd_length
> 0) {
344 if ((rc
= efx_vpd_hunk_get(enp
->en_arch
.ef10
.ena_svpd
,
345 enp
->en_arch
.ef10
.ena_svpd_length
, evvp
->evv_tag
,
346 evvp
->evv_keyword
, &offset
, &length
)) == 0) {
352 if ((rc
= efx_vpd_hunk_set(data
, size
, evvp
)) != 0)
360 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
365 __checkReturn efx_rc_t
368 __in_bcount(size
) caddr_t data
,
370 __out efx_vpd_value_t
*evvp
,
371 __inout
unsigned int *contp
)
373 _NOTE(ARGUNUSED(enp
, data
, size
, evvp
, contp
))
378 __checkReturn efx_rc_t
381 __in_bcount(size
) caddr_t data
,
389 EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp
));
391 if (enp
->en_nic_cfg
.enc_vpd_is_global
) {
392 tag
= TLV_TAG_GLOBAL_DYNAMIC_VPD
;
394 pci_pf
= enp
->en_nic_cfg
.enc_pf
;
395 tag
= TLV_TAG_PF_DYNAMIC_VPD(pci_pf
);
398 /* Determine total length of new dynamic VPD */
399 if ((rc
= efx_vpd_hunk_length(data
, size
, &vpd_length
)) != 0)
402 /* Store new dynamic VPD in all segments in DYNAMIC_CONFIG partition */
403 if ((rc
= ef10_nvram_partn_write_segment_tlv(enp
,
404 NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG
,
405 tag
, data
, vpd_length
, B_TRUE
)) != 0) {
415 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
424 EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp
));
426 if (enp
->en_arch
.ef10
.ena_svpd_length
> 0) {
427 EFSYS_KMEM_FREE(enp
->en_esip
, enp
->en_arch
.ef10
.ena_svpd_length
,
428 enp
->en_arch
.ef10
.ena_svpd
);
430 enp
->en_arch
.ef10
.ena_svpd
= NULL
;
431 enp
->en_arch
.ef10
.ena_svpd_length
= 0;
435 #endif /* EFX_OPTS_EF10() */
437 #endif /* EFSYS_OPT_VPD */