2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2009-2016 Solarflare Communications Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * The views and conclusions contained in the software and documentation are
29 * those of the authors and should not be interpreted as representing official
30 * policies, either expressed or implied, of the FreeBSD Project.
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
43 static __checkReturn efx_rc_t
47 __deref_out_bcount_opt(*sizep) caddr_t *svpdp,
50 siena_mc_static_config_hdr_t *scfg;
54 unsigned int vpd_offset;
55 unsigned int vpd_length;
56 unsigned int hdr_length;
61 EFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0 ||
62 partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1);
64 /* Allocate sufficient memory for the entire static cfg area */
65 if ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0)
68 if (size < SIENA_NVRAM_CHUNK) {
73 EFSYS_KMEM_ALLOC(enp->en_esip, size, scfg);
79 if ((rc = siena_nvram_partn_read(enp, partn, 0,
80 (caddr_t)scfg, SIENA_NVRAM_CHUNK)) != 0)
83 /* Verify the magic number */
84 if (EFX_DWORD_FIELD(scfg->magic, EFX_DWORD_0) !=
85 SIENA_MC_STATIC_CONFIG_MAGIC) {
90 /* All future versions of the structure must be backwards compatible */
91 EFX_STATIC_ASSERT(SIENA_MC_STATIC_CONFIG_VERSION == 0);
93 hdr_length = EFX_WORD_FIELD(scfg->length, EFX_WORD_0);
94 vpd_offset = EFX_DWORD_FIELD(scfg->static_vpd_offset, EFX_DWORD_0);
95 vpd_length = EFX_DWORD_FIELD(scfg->static_vpd_length, EFX_DWORD_0);
97 /* Verify the hdr doesn't overflow the sector size */
98 if (hdr_length > size || vpd_offset > size || vpd_length > size ||
99 vpd_length + vpd_offset > size) {
104 /* Read the remainder of scfg + static vpd */
105 region = vpd_offset + vpd_length;
106 if (region > SIENA_NVRAM_CHUNK) {
107 if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK,
108 (caddr_t)scfg + SIENA_NVRAM_CHUNK,
109 region - SIENA_NVRAM_CHUNK)) != 0)
113 /* Verify checksum */
115 for (pos = 0; pos < hdr_length; pos++)
116 cksum += ((uint8_t *)scfg)[pos];
125 /* Copy the vpd data out */
126 EFSYS_KMEM_ALLOC(enp->en_esip, vpd_length, svpd);
131 memcpy(svpd, (caddr_t)scfg + vpd_offset, vpd_length);
134 EFSYS_KMEM_FREE(enp->en_esip, size, scfg);
154 EFSYS_KMEM_FREE(enp->en_esip, size, scfg);
161 EFSYS_PROBE1(fail1, efx_rc_t, rc);
166 __checkReturn efx_rc_t
170 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
176 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
178 partn = (emip->emi_port == 1)
179 ? MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0
180 : MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1;
183 * We need the static VPD sector to present a unified static+dynamic
184 * VPD, that is, basically on every read, write, verify cycle. Since
185 * it should *never* change we can just cache it here.
187 if ((rc = siena_vpd_get_static(enp, partn, &svpd, &size)) != 0)
190 if (svpd != NULL && size > 0) {
191 if ((rc = efx_vpd_hunk_verify(svpd, size, NULL)) != 0)
195 enp->en_u.siena.enu_svpd = svpd;
196 enp->en_u.siena.enu_svpd_length = size;
203 EFSYS_KMEM_FREE(enp->en_esip, size, svpd);
205 EFSYS_PROBE1(fail1, efx_rc_t, rc);
210 __checkReturn efx_rc_t
215 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
219 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
222 * This function returns the total size the user should allocate
223 * for all VPD operations. We've already cached the static vpd,
224 * so we just need to return an upper bound on the dynamic vpd.
225 * Since the dynamic_config structure can change under our feet,
226 * (as version numbers are inserted), just be safe and return the
227 * total size of the dynamic_config *sector*
229 partn = (emip->emi_port == 1)
230 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
231 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
233 if ((rc = siena_nvram_partn_size(enp, partn, sizep)) != 0)
239 EFSYS_PROBE1(fail1, efx_rc_t, rc);
244 __checkReturn efx_rc_t
247 __out_bcount(size) caddr_t data,
250 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
251 siena_mc_dynamic_config_hdr_t *dcfg = NULL;
252 unsigned int vpd_length;
253 unsigned int vpd_offset;
254 unsigned int dcfg_partn;
258 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
260 dcfg_partn = (emip->emi_port == 1)
261 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
262 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
264 if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
265 B_TRUE, &dcfg, &dcfg_size)) != 0)
268 vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0);
269 vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0);
271 if (vpd_length > size) {
272 rc = EFAULT; /* Invalid dcfg: header bigger than sector */
276 EFSYS_ASSERT3U(vpd_length, <=, size);
277 memcpy(data, (caddr_t)dcfg + vpd_offset, vpd_length);
279 /* Pad data with all-1s, consistent with update operations */
280 memset(data + vpd_length, 0xff, size - vpd_length);
282 EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
289 EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
291 EFSYS_PROBE1(fail1, efx_rc_t, rc);
296 __checkReturn efx_rc_t
299 __in_bcount(size) caddr_t data,
304 efx_vpd_keyword_t skey;
305 efx_vpd_keyword_t dkey;
311 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
314 * Strictly you could take the view that dynamic vpd is optional.
315 * Instead, to conform more closely to the read/verify/reinit()
316 * paradigm, we require dynamic vpd. siena_vpd_reinit() will
317 * reinitialize it as required.
319 if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0)
323 * Verify that there is no duplication between the static and
324 * dynamic cfg sectors.
326 if (enp->en_u.siena.enu_svpd_length == 0)
330 _NOTE(CONSTANTCONDITION)
332 if ((rc = efx_vpd_hunk_next(data, size, &dtag,
333 &dkey, NULL, NULL, &dcont)) != 0)
339 * Skip the RV keyword. It should be present in both the static
340 * and dynamic cfg sectors.
342 if (dtag == EFX_VPD_RO && dkey == EFX_VPD_KEYWORD('R', 'V'))
346 _NOTE(CONSTANTCONDITION)
348 if ((rc = efx_vpd_hunk_next(
349 enp->en_u.siena.enu_svpd,
350 enp->en_u.siena.enu_svpd_length, &stag, &skey,
351 NULL, NULL, &scont)) != 0)
356 if (stag == dtag && skey == dkey) {
373 EFSYS_PROBE1(fail1, efx_rc_t, rc);
378 __checkReturn efx_rc_t
381 __in_bcount(size) caddr_t data,
388 * Only create a PID if the dynamic cfg doesn't have one
390 if (enp->en_u.siena.enu_svpd_length == 0)
396 rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
397 enp->en_u.siena.enu_svpd_length,
398 EFX_VPD_ID, 0, &offset, &length);
401 else if (rc == ENOENT)
407 if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0)
415 EFSYS_PROBE1(fail1, efx_rc_t, rc);
420 __checkReturn efx_rc_t
423 __in_bcount(size) caddr_t data,
425 __inout efx_vpd_value_t *evvp)
431 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
433 /* Attempt to satisfy the request from svpd first */
434 if (enp->en_u.siena.enu_svpd_length > 0) {
435 if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
436 enp->en_u.siena.enu_svpd_length, evvp->evv_tag,
437 evvp->evv_keyword, &offset, &length)) == 0) {
438 evvp->evv_length = length;
439 memcpy(evvp->evv_value,
440 enp->en_u.siena.enu_svpd + offset, length);
442 } else if (rc != ENOENT)
446 /* And then from the provided data buffer */
447 if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag,
448 evvp->evv_keyword, &offset, &length)) != 0) {
455 evvp->evv_length = length;
456 memcpy(evvp->evv_value, data + offset, length);
463 EFSYS_PROBE1(fail1, efx_rc_t, rc);
468 __checkReturn efx_rc_t
471 __in_bcount(size) caddr_t data,
473 __in efx_vpd_value_t *evvp)
477 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
479 /* If the provided (tag,keyword) exists in svpd, then it is readonly */
480 if (enp->en_u.siena.enu_svpd_length > 0) {
484 if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
485 enp->en_u.siena.enu_svpd_length, evvp->evv_tag,
486 evvp->evv_keyword, &offset, &length)) == 0) {
492 if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0)
500 EFSYS_PROBE1(fail1, efx_rc_t, rc);
505 __checkReturn efx_rc_t
508 __in_bcount(size) caddr_t data,
510 __out efx_vpd_value_t *evvp,
511 __inout unsigned int *contp)
513 _NOTE(ARGUNUSED(enp, data, size, evvp, contp))
518 __checkReturn efx_rc_t
521 __in_bcount(size) caddr_t data,
524 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
525 siena_mc_dynamic_config_hdr_t *dcfg = NULL;
526 unsigned int vpd_offset;
527 unsigned int dcfg_partn;
528 unsigned int hdr_length;
531 size_t partn_size, dcfg_size;
535 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
537 /* Determine total length of all tags */
538 if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0)
541 /* Lock dynamic config sector for write, and read structure only */
542 dcfg_partn = (emip->emi_port == 1)
543 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
544 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
546 if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &partn_size)) != 0)
549 if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0)
552 if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
553 B_FALSE, &dcfg, &dcfg_size)) != 0)
556 hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0);
558 /* Allocated memory should have room for the new VPD */
559 if (hdr_length + vpd_length > dcfg_size) {
564 /* Copy in new vpd and update header */
565 vpd_offset = dcfg_size - vpd_length;
566 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, EFX_DWORD_0, vpd_offset);
567 memcpy((caddr_t)dcfg + vpd_offset, data, vpd_length);
568 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length, EFX_DWORD_0, vpd_length);
570 /* Update the checksum */
572 for (pos = 0; pos < hdr_length; pos++)
573 cksum += ((uint8_t *)dcfg)[pos];
574 dcfg->csum.eb_u8[0] -= cksum;
576 /* Erase and write the new sector */
577 if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0)
580 /* Write out the new structure to nvram */
581 if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, (caddr_t)dcfg,
582 vpd_offset + vpd_length)) != 0)
585 EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
587 siena_nvram_partn_unlock(enp, dcfg_partn, NULL);
598 EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
602 siena_nvram_partn_unlock(enp, dcfg_partn, NULL);
608 EFSYS_PROBE1(fail1, efx_rc_t, rc);
617 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
619 if (enp->en_u.siena.enu_svpd_length > 0) {
620 EFSYS_KMEM_FREE(enp->en_esip, enp->en_u.siena.enu_svpd_length,
621 enp->en_u.siena.enu_svpd);
623 enp->en_u.siena.enu_svpd = NULL;
624 enp->en_u.siena.enu_svpd_length = 0;
628 #endif /* EFSYS_OPT_SIENA */
630 #endif /* EFSYS_OPT_VPD */