1 /* SPDX-License-Identifier: BSD-3-Clause
3 * Copyright (c) 2009-2018 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
83 EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp
));
86 * This function returns the total size the user should allocate
87 * for all VPD operations. We've already cached the static vpd,
88 * so we just need to return an upper bound on the dynamic vpd,
89 * which is the size of the DYNAMIC_CONFIG partition.
91 if ((rc
= efx_mcdi_nvram_info(enp
, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG
,
92 sizep
, NULL
, NULL
, NULL
)) != 0)
98 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
103 __checkReturn efx_rc_t
106 __out_bcount(size
) caddr_t data
,
115 EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp
));
117 if (enp
->en_nic_cfg
.enc_vpd_is_global
) {
118 tag
= TLV_TAG_GLOBAL_DYNAMIC_VPD
;
120 pci_pf
= enp
->en_nic_cfg
.enc_pf
;
121 tag
= TLV_TAG_PF_DYNAMIC_VPD(pci_pf
);
124 if ((rc
= ef10_nvram_partn_read_tlv(enp
,
125 NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG
,
126 tag
, &dvpd
, &dvpd_size
)) != 0)
129 if (dvpd_size
> size
) {
134 memcpy(data
, dvpd
, dvpd_size
);
136 /* Pad data with all-1s, consistent with update operations */
137 memset(data
+ dvpd_size
, 0xff, size
- dvpd_size
);
140 EFSYS_KMEM_FREE(enp
->en_esip
, dvpd_size
, dvpd
);
148 EFSYS_KMEM_FREE(enp
->en_esip
, dvpd_size
, dvpd
);
150 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
155 __checkReturn efx_rc_t
158 __in_bcount(size
) caddr_t data
,
163 efx_vpd_keyword_t skey
;
164 efx_vpd_keyword_t dkey
;
169 EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp
));
172 * Strictly you could take the view that dynamic vpd is optional.
173 * Instead, to conform more closely to the read/verify/reinit()
174 * paradigm, we require dynamic vpd. ef10_vpd_reinit() will
175 * reinitialize it as required.
177 if ((rc
= efx_vpd_hunk_verify(data
, size
, NULL
)) != 0)
181 * Verify that there is no duplication between the static and
182 * dynamic cfg sectors.
184 if (enp
->en_arch
.ef10
.ena_svpd_length
== 0)
188 _NOTE(CONSTANTCONDITION
)
190 if ((rc
= efx_vpd_hunk_next(data
, size
, &dtag
,
191 &dkey
, NULL
, NULL
, &dcont
)) != 0)
197 * Skip the RV keyword. It should be present in both the static
198 * and dynamic cfg sectors.
200 if (dtag
== EFX_VPD_RO
&& dkey
== EFX_VPD_KEYWORD('R', 'V'))
204 _NOTE(CONSTANTCONDITION
)
206 if ((rc
= efx_vpd_hunk_next(
207 enp
->en_arch
.ef10
.ena_svpd
,
208 enp
->en_arch
.ef10
.ena_svpd_length
, &stag
, &skey
,
209 NULL
, NULL
, &scont
)) != 0)
214 if (stag
== dtag
&& skey
== dkey
) {
231 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
236 __checkReturn efx_rc_t
239 __in_bcount(size
) caddr_t data
,
246 * Only create an ID string if the dynamic cfg doesn't have one
248 if (enp
->en_arch
.ef10
.ena_svpd_length
== 0)
254 rc
= efx_vpd_hunk_get(enp
->en_arch
.ef10
.ena_svpd
,
255 enp
->en_arch
.ef10
.ena_svpd_length
,
256 EFX_VPD_ID
, 0, &offset
, &length
);
259 else if (rc
== ENOENT
)
265 if ((rc
= efx_vpd_hunk_reinit(data
, size
, wantpid
)) != 0)
273 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
278 __checkReturn efx_rc_t
281 __in_bcount(size
) caddr_t data
,
283 __inout efx_vpd_value_t
*evvp
)
289 EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp
));
291 /* Attempt to satisfy the request from svpd first */
292 if (enp
->en_arch
.ef10
.ena_svpd_length
> 0) {
293 if ((rc
= efx_vpd_hunk_get(enp
->en_arch
.ef10
.ena_svpd
,
294 enp
->en_arch
.ef10
.ena_svpd_length
, evvp
->evv_tag
,
295 evvp
->evv_keyword
, &offset
, &length
)) == 0) {
296 evvp
->evv_length
= length
;
297 memcpy(evvp
->evv_value
,
298 enp
->en_arch
.ef10
.ena_svpd
+ offset
, length
);
300 } else if (rc
!= ENOENT
)
304 /* And then from the provided data buffer */
305 if ((rc
= efx_vpd_hunk_get(data
, size
, evvp
->evv_tag
,
306 evvp
->evv_keyword
, &offset
, &length
)) != 0) {
312 evvp
->evv_length
= length
;
313 memcpy(evvp
->evv_value
, data
+ offset
, length
);
320 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
325 __checkReturn efx_rc_t
328 __in_bcount(size
) caddr_t data
,
330 __in efx_vpd_value_t
*evvp
)
334 EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp
));
336 /* If the provided (tag,keyword) exists in svpd, then it is readonly */
337 if (enp
->en_arch
.ef10
.ena_svpd_length
> 0) {
341 if ((rc
= efx_vpd_hunk_get(enp
->en_arch
.ef10
.ena_svpd
,
342 enp
->en_arch
.ef10
.ena_svpd_length
, evvp
->evv_tag
,
343 evvp
->evv_keyword
, &offset
, &length
)) == 0) {
349 if ((rc
= efx_vpd_hunk_set(data
, size
, evvp
)) != 0)
357 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
362 __checkReturn efx_rc_t
365 __in_bcount(size
) caddr_t data
,
367 __out efx_vpd_value_t
*evvp
,
368 __inout
unsigned int *contp
)
370 _NOTE(ARGUNUSED(enp
, data
, size
, evvp
, contp
))
375 __checkReturn efx_rc_t
378 __in_bcount(size
) caddr_t data
,
386 EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp
));
388 if (enp
->en_nic_cfg
.enc_vpd_is_global
) {
389 tag
= TLV_TAG_GLOBAL_DYNAMIC_VPD
;
391 pci_pf
= enp
->en_nic_cfg
.enc_pf
;
392 tag
= TLV_TAG_PF_DYNAMIC_VPD(pci_pf
);
395 /* Determine total length of new dynamic VPD */
396 if ((rc
= efx_vpd_hunk_length(data
, size
, &vpd_length
)) != 0)
399 /* Store new dynamic VPD in all segments in DYNAMIC_CONFIG partition */
400 if ((rc
= ef10_nvram_partn_write_segment_tlv(enp
,
401 NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG
,
402 tag
, data
, vpd_length
, B_TRUE
)) != 0) {
412 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
421 EFSYS_ASSERT(EFX_FAMILY_IS_EF10(enp
));
423 if (enp
->en_arch
.ef10
.ena_svpd_length
> 0) {
424 EFSYS_KMEM_FREE(enp
->en_esip
, enp
->en_arch
.ef10
.ena_svpd_length
,
425 enp
->en_arch
.ef10
.ena_svpd
);
427 enp
->en_arch
.ef10
.ena_svpd
= NULL
;
428 enp
->en_arch
.ef10
.ena_svpd_length
= 0;
432 #endif /* EFX_OPTS_EF10() */
434 #endif /* EFSYS_OPT_VPD */