2 * Copyright (c) 2009-2016 Solarflare Communications Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * The views and conclusions contained in the software and documentation are
27 * those of the authors and should not be interpreted as representing official
28 * policies, either expressed or implied, of the FreeBSD Project.
36 #if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
38 __checkReturn efx_rc_t
39 siena_nvram_partn_size(
46 if ((1 << partn
) & ~enp
->en_u
.siena
.enu_partn_mask
) {
51 if ((rc
= efx_mcdi_nvram_info(enp
, partn
, sizep
,
52 NULL
, NULL
, NULL
)) != 0) {
61 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
66 __checkReturn efx_rc_t
67 siena_nvram_partn_lock(
73 if ((rc
= efx_mcdi_nvram_update_start(enp
, partn
)) != 0) {
80 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
85 __checkReturn efx_rc_t
86 siena_nvram_partn_read(
89 __in
unsigned int offset
,
90 __out_bcount(size
) caddr_t data
,
97 chunk
= MIN(size
, SIENA_NVRAM_CHUNK
);
99 if ((rc
= efx_mcdi_nvram_read(enp
, partn
, offset
, data
, chunk
,
100 MC_CMD_NVRAM_READ_IN_V2_DEFAULT
)) != 0) {
112 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
117 __checkReturn efx_rc_t
118 siena_nvram_partn_erase(
121 __in
unsigned int offset
,
126 if ((rc
= efx_mcdi_nvram_erase(enp
, partn
, offset
, size
)) != 0) {
133 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
138 __checkReturn efx_rc_t
139 siena_nvram_partn_write(
142 __in
unsigned int offset
,
143 __out_bcount(size
) caddr_t data
,
150 chunk
= MIN(size
, SIENA_NVRAM_CHUNK
);
152 if ((rc
= efx_mcdi_nvram_write(enp
, partn
, offset
,
153 data
, chunk
)) != 0) {
165 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
170 __checkReturn efx_rc_t
171 siena_nvram_partn_unlock(
179 * Reboot into the new image only for PHYs. The driver has to
180 * explicitly cope with an MC reboot after a firmware update.
182 reboot
= (partn
== MC_CMD_NVRAM_TYPE_PHY_PORT0
||
183 partn
== MC_CMD_NVRAM_TYPE_PHY_PORT1
||
184 partn
== MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO
);
186 rc
= efx_mcdi_nvram_update_finish(enp
, partn
, reboot
, NULL
);
193 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
198 #endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */
202 typedef struct siena_parttbl_entry_s
{
205 efx_nvram_type_t nvtype
;
206 } siena_parttbl_entry_t
;
208 static siena_parttbl_entry_t siena_parttbl
[] = {
209 {MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO
, 1, EFX_NVRAM_NULLPHY
},
210 {MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO
, 2, EFX_NVRAM_NULLPHY
},
211 {MC_CMD_NVRAM_TYPE_MC_FW
, 1, EFX_NVRAM_MC_FIRMWARE
},
212 {MC_CMD_NVRAM_TYPE_MC_FW
, 2, EFX_NVRAM_MC_FIRMWARE
},
213 {MC_CMD_NVRAM_TYPE_MC_FW_BACKUP
, 1, EFX_NVRAM_MC_GOLDEN
},
214 {MC_CMD_NVRAM_TYPE_MC_FW_BACKUP
, 2, EFX_NVRAM_MC_GOLDEN
},
215 {MC_CMD_NVRAM_TYPE_EXP_ROM
, 1, EFX_NVRAM_BOOTROM
},
216 {MC_CMD_NVRAM_TYPE_EXP_ROM
, 2, EFX_NVRAM_BOOTROM
},
217 {MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0
, 1, EFX_NVRAM_BOOTROM_CFG
},
218 {MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1
, 2, EFX_NVRAM_BOOTROM_CFG
},
219 {MC_CMD_NVRAM_TYPE_PHY_PORT0
, 1, EFX_NVRAM_PHY
},
220 {MC_CMD_NVRAM_TYPE_PHY_PORT1
, 2, EFX_NVRAM_PHY
},
221 {MC_CMD_NVRAM_TYPE_FPGA
, 1, EFX_NVRAM_FPGA
},
222 {MC_CMD_NVRAM_TYPE_FPGA
, 2, EFX_NVRAM_FPGA
},
223 {MC_CMD_NVRAM_TYPE_FPGA_BACKUP
, 1, EFX_NVRAM_FPGA_BACKUP
},
224 {MC_CMD_NVRAM_TYPE_FPGA_BACKUP
, 2, EFX_NVRAM_FPGA_BACKUP
},
225 {MC_CMD_NVRAM_TYPE_FC_FW
, 1, EFX_NVRAM_FCFW
},
226 {MC_CMD_NVRAM_TYPE_FC_FW
, 2, EFX_NVRAM_FCFW
},
227 {MC_CMD_NVRAM_TYPE_CPLD
, 1, EFX_NVRAM_CPLD
},
228 {MC_CMD_NVRAM_TYPE_CPLD
, 2, EFX_NVRAM_CPLD
},
229 {MC_CMD_NVRAM_TYPE_LICENSE
, 1, EFX_NVRAM_LICENSE
},
230 {MC_CMD_NVRAM_TYPE_LICENSE
, 2, EFX_NVRAM_LICENSE
}
233 __checkReturn efx_rc_t
234 siena_nvram_type_to_partn(
236 __in efx_nvram_type_t type
,
237 __out
uint32_t *partnp
)
239 efx_mcdi_iface_t
*emip
= &(enp
->en_mcdi
.em_emip
);
242 EFSYS_ASSERT3U(type
, <, EFX_NVRAM_NTYPES
);
243 EFSYS_ASSERT(partnp
!= NULL
);
245 for (i
= 0; i
< EFX_ARRAY_SIZE(siena_parttbl
); i
++) {
246 siena_parttbl_entry_t
*entry
= &siena_parttbl
[i
];
248 if (entry
->port
== emip
->emi_port
&& entry
->nvtype
== type
) {
249 *partnp
= entry
->partn
;
260 __checkReturn efx_rc_t
264 efx_mcdi_iface_t
*emip
= &(enp
->en_mcdi
.em_emip
);
265 siena_parttbl_entry_t
*entry
;
270 * Iterate over the list of supported partition types
271 * applicable to *this* port
273 for (i
= 0; i
< EFX_ARRAY_SIZE(siena_parttbl
); i
++) {
274 entry
= &siena_parttbl
[i
];
276 if (entry
->port
!= emip
->emi_port
||
277 !(enp
->en_u
.siena
.enu_partn_mask
& (1 << entry
->partn
)))
280 if ((rc
= efx_mcdi_nvram_test(enp
, entry
->partn
)) != 0) {
288 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
293 #endif /* EFSYS_OPT_DIAG */
296 #define SIENA_DYNAMIC_CFG_SIZE(_nitems) \
297 (sizeof (siena_mc_dynamic_config_hdr_t) + ((_nitems) * \
298 sizeof (((siena_mc_dynamic_config_hdr_t *)NULL)->fw_version[0])))
300 __checkReturn efx_rc_t
301 siena_nvram_get_dynamic_cfg(
305 __out siena_mc_dynamic_config_hdr_t
**dcfgp
,
308 siena_mc_dynamic_config_hdr_t
*dcfg
= NULL
;
311 unsigned int vpd_offset
;
312 unsigned int vpd_length
;
313 unsigned int hdr_length
;
314 unsigned int nversions
;
319 EFSYS_ASSERT(partn
== MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
||
320 partn
== MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1
);
323 * Allocate sufficient memory for the entire dynamiccfg area, even
324 * if we're not actually going to read in the VPD.
326 if ((rc
= siena_nvram_partn_size(enp
, partn
, &size
)) != 0)
329 EFSYS_KMEM_ALLOC(enp
->en_esip
, size
, dcfg
);
335 if ((rc
= siena_nvram_partn_read(enp
, partn
, 0,
336 (caddr_t
)dcfg
, SIENA_NVRAM_CHUNK
)) != 0)
339 /* Verify the magic */
340 if (EFX_DWORD_FIELD(dcfg
->magic
, EFX_DWORD_0
)
341 != SIENA_MC_DYNAMIC_CONFIG_MAGIC
)
344 /* All future versions of the structure must be backwards compatible */
345 EFX_STATIC_ASSERT(SIENA_MC_DYNAMIC_CONFIG_VERSION
== 0);
347 hdr_length
= EFX_WORD_FIELD(dcfg
->length
, EFX_WORD_0
);
348 nversions
= EFX_DWORD_FIELD(dcfg
->num_fw_version_items
, EFX_DWORD_0
);
349 vpd_offset
= EFX_DWORD_FIELD(dcfg
->dynamic_vpd_offset
, EFX_DWORD_0
);
350 vpd_length
= EFX_DWORD_FIELD(dcfg
->dynamic_vpd_length
, EFX_DWORD_0
);
352 /* Verify the hdr doesn't overflow the partn size */
353 if (hdr_length
> size
|| vpd_offset
> size
|| vpd_length
> size
||
354 vpd_length
+ vpd_offset
> size
)
357 /* Verify the header has room for all it's versions */
358 if (hdr_length
< SIENA_DYNAMIC_CFG_SIZE(0) ||
359 hdr_length
< SIENA_DYNAMIC_CFG_SIZE(nversions
))
363 * Read the remaining portion of the dcfg, either including
364 * the whole of VPD (there is no vpd length in this structure,
365 * so we have to parse each tag), or just the dcfg header itself
367 region
= vpd
? vpd_offset
+ vpd_length
: hdr_length
;
368 if (region
> SIENA_NVRAM_CHUNK
) {
369 if ((rc
= siena_nvram_partn_read(enp
, partn
, SIENA_NVRAM_CHUNK
,
370 (caddr_t
)dcfg
+ SIENA_NVRAM_CHUNK
,
371 region
- SIENA_NVRAM_CHUNK
)) != 0)
375 /* Verify checksum */
377 for (pos
= 0; pos
< hdr_length
; pos
++)
378 cksum
+= ((uint8_t *)dcfg
)[pos
];
385 EFSYS_PROBE(invalid4
);
387 EFSYS_PROBE(invalid3
);
389 EFSYS_PROBE(invalid2
);
391 EFSYS_PROBE(invalid1
);
394 * Construct a new "null" dcfg, with an empty version vector,
395 * and an empty VPD chunk trailing. This has the neat side effect
396 * of testing the exception paths in the write path.
398 EFX_POPULATE_DWORD_1(dcfg
->magic
,
399 EFX_DWORD_0
, SIENA_MC_DYNAMIC_CONFIG_MAGIC
);
400 EFX_POPULATE_WORD_1(dcfg
->length
, EFX_WORD_0
, sizeof (*dcfg
));
401 EFX_POPULATE_BYTE_1(dcfg
->version
, EFX_BYTE_0
,
402 SIENA_MC_DYNAMIC_CONFIG_VERSION
);
403 EFX_POPULATE_DWORD_1(dcfg
->dynamic_vpd_offset
,
404 EFX_DWORD_0
, sizeof (*dcfg
));
405 EFX_POPULATE_DWORD_1(dcfg
->dynamic_vpd_length
, EFX_DWORD_0
, 0);
406 EFX_POPULATE_DWORD_1(dcfg
->num_fw_version_items
, EFX_DWORD_0
, 0);
419 EFSYS_KMEM_FREE(enp
->en_esip
, size
, dcfg
);
424 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
429 __checkReturn efx_rc_t
430 siena_nvram_get_subtype(
433 __out
uint32_t *subtypep
)
436 uint8_t payload
[MAX(MC_CMD_GET_BOARD_CFG_IN_LEN
,
437 MC_CMD_GET_BOARD_CFG_OUT_LENMAX
)];
441 (void) memset(payload
, 0, sizeof (payload
));
442 req
.emr_cmd
= MC_CMD_GET_BOARD_CFG
;
443 req
.emr_in_buf
= payload
;
444 req
.emr_in_length
= MC_CMD_GET_BOARD_CFG_IN_LEN
;
445 req
.emr_out_buf
= payload
;
446 req
.emr_out_length
= MC_CMD_GET_BOARD_CFG_OUT_LENMAX
;
448 efx_mcdi_execute(enp
, &req
);
450 if (req
.emr_rc
!= 0) {
455 if (req
.emr_out_length_used
< MC_CMD_GET_BOARD_CFG_OUT_LENMIN
) {
460 if (req
.emr_out_length_used
<
461 MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_OFST
+
462 (partn
+ 1) * sizeof (efx_word_t
)) {
467 fw_list
= MCDI_OUT2(req
, efx_word_t
,
468 GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST
);
469 *subtypep
= EFX_WORD_FIELD(fw_list
[partn
], EFX_WORD_0
);
478 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
483 __checkReturn efx_rc_t
484 siena_nvram_partn_get_version(
487 __out
uint32_t *subtypep
,
488 __out_ecount(4) uint16_t version
[4])
490 siena_mc_dynamic_config_hdr_t
*dcfg
;
491 siena_parttbl_entry_t
*entry
;
496 if ((1 << partn
) & ~enp
->en_u
.siena
.enu_partn_mask
) {
501 if ((rc
= siena_nvram_get_subtype(enp
, partn
, subtypep
)) != 0)
505 * Some partitions are accessible from both ports (for instance BOOTROM)
506 * Find the highest version reported by all dcfg structures on ports
507 * that have access to this partition.
509 version
[0] = version
[1] = version
[2] = version
[3] = 0;
510 for (i
= 0; i
< EFX_ARRAY_SIZE(siena_parttbl
); i
++) {
511 siena_mc_fw_version_t
*verp
;
516 entry
= &siena_parttbl
[i
];
517 if (entry
->partn
!= partn
)
520 dcfg_partn
= (entry
->port
== 1)
521 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
522 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1
;
524 * Ingore missing partitions on port 2, assuming they're due
525 * to to running on a single port part.
527 if ((1 << dcfg_partn
) & ~enp
->en_u
.siena
.enu_partn_mask
) {
528 if (entry
->port
== 2)
532 if ((rc
= siena_nvram_get_dynamic_cfg(enp
, dcfg_partn
,
533 B_FALSE
, &dcfg
, &length
)) != 0)
536 nitems
= EFX_DWORD_FIELD(dcfg
->num_fw_version_items
,
538 if (nitems
< entry
->partn
)
541 verp
= &dcfg
->fw_version
[partn
];
542 temp
[0] = EFX_WORD_FIELD(verp
->version_w
, EFX_WORD_0
);
543 temp
[1] = EFX_WORD_FIELD(verp
->version_x
, EFX_WORD_0
);
544 temp
[2] = EFX_WORD_FIELD(verp
->version_y
, EFX_WORD_0
);
545 temp
[3] = EFX_WORD_FIELD(verp
->version_z
, EFX_WORD_0
);
546 if (memcmp(version
, temp
, sizeof (temp
)) < 0)
547 memcpy(version
, temp
, sizeof (temp
));
550 EFSYS_KMEM_FREE(enp
->en_esip
, length
, dcfg
);
560 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
565 __checkReturn efx_rc_t
566 siena_nvram_partn_rw_start(
569 __out
size_t *chunk_sizep
)
573 if ((rc
= siena_nvram_partn_lock(enp
, partn
)) != 0)
576 if (chunk_sizep
!= NULL
)
577 *chunk_sizep
= SIENA_NVRAM_CHUNK
;
582 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
587 __checkReturn efx_rc_t
588 siena_nvram_partn_rw_finish(
594 if ((rc
= siena_nvram_partn_unlock(enp
, partn
)) != 0)
600 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
605 __checkReturn efx_rc_t
606 siena_nvram_partn_set_version(
609 __in_ecount(4) uint16_t version
[4])
611 efx_mcdi_iface_t
*emip
= &(enp
->en_mcdi
.em_emip
);
612 siena_mc_dynamic_config_hdr_t
*dcfg
= NULL
;
613 siena_mc_fw_version_t
*fwverp
;
616 unsigned int hdr_length
;
617 unsigned int vpd_length
;
618 unsigned int vpd_offset
;
620 unsigned int required_hdr_length
;
627 dcfg_partn
= (emip
->emi_port
== 1)
628 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
629 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1
;
631 if ((rc
= siena_nvram_partn_size(enp
, dcfg_partn
, &dcfg_size
)) != 0)
634 if ((rc
= siena_nvram_partn_lock(enp
, dcfg_partn
)) != 0)
637 if ((rc
= siena_nvram_get_dynamic_cfg(enp
, dcfg_partn
,
638 B_TRUE
, &dcfg
, &length
)) != 0)
641 hdr_length
= EFX_WORD_FIELD(dcfg
->length
, EFX_WORD_0
);
642 nitems
= EFX_DWORD_FIELD(dcfg
->num_fw_version_items
, EFX_DWORD_0
);
643 vpd_length
= EFX_DWORD_FIELD(dcfg
->dynamic_vpd_length
, EFX_DWORD_0
);
644 vpd_offset
= EFX_DWORD_FIELD(dcfg
->dynamic_vpd_offset
, EFX_DWORD_0
);
647 * NOTE: This function will blatt any fields trailing the version
648 * vector, or the VPD chunk.
650 required_hdr_length
= SIENA_DYNAMIC_CFG_SIZE(partn
+ 1);
651 if (required_hdr_length
+ vpd_length
> length
) {
656 if (vpd_offset
< required_hdr_length
) {
657 (void) memmove((caddr_t
)dcfg
+ required_hdr_length
,
658 (caddr_t
)dcfg
+ vpd_offset
, vpd_length
);
659 vpd_offset
= required_hdr_length
;
660 EFX_POPULATE_DWORD_1(dcfg
->dynamic_vpd_offset
,
661 EFX_DWORD_0
, vpd_offset
);
664 if (hdr_length
< required_hdr_length
) {
665 (void) memset((caddr_t
)dcfg
+ hdr_length
, 0,
666 required_hdr_length
- hdr_length
);
667 hdr_length
= required_hdr_length
;
668 EFX_POPULATE_WORD_1(dcfg
->length
,
669 EFX_WORD_0
, hdr_length
);
672 /* Get the subtype to insert into the fw_subtype array */
673 if ((rc
= siena_nvram_get_subtype(enp
, partn
, &subtype
)) != 0)
676 /* Fill out the new version */
677 fwverp
= &dcfg
->fw_version
[partn
];
678 EFX_POPULATE_DWORD_1(fwverp
->fw_subtype
, EFX_DWORD_0
, subtype
);
679 EFX_POPULATE_WORD_1(fwverp
->version_w
, EFX_WORD_0
, version
[0]);
680 EFX_POPULATE_WORD_1(fwverp
->version_x
, EFX_WORD_0
, version
[1]);
681 EFX_POPULATE_WORD_1(fwverp
->version_y
, EFX_WORD_0
, version
[2]);
682 EFX_POPULATE_WORD_1(fwverp
->version_z
, EFX_WORD_0
, version
[3]);
684 /* Update the version count */
685 if (nitems
< partn
+ 1) {
687 EFX_POPULATE_DWORD_1(dcfg
->num_fw_version_items
,
688 EFX_DWORD_0
, nitems
);
691 /* Update the checksum */
693 for (pos
= 0; pos
< hdr_length
; pos
++)
694 cksum
+= ((uint8_t *)dcfg
)[pos
];
695 dcfg
->csum
.eb_u8
[0] -= cksum
;
697 /* Erase and write the new partition */
698 if ((rc
= siena_nvram_partn_erase(enp
, dcfg_partn
, 0, dcfg_size
)) != 0)
701 /* Write out the new structure to nvram */
702 if ((rc
= siena_nvram_partn_write(enp
, dcfg_partn
, 0,
703 (caddr_t
)dcfg
, vpd_offset
+ vpd_length
)) != 0)
706 EFSYS_KMEM_FREE(enp
->en_esip
, length
, dcfg
);
708 siena_nvram_partn_unlock(enp
, dcfg_partn
);
721 EFSYS_KMEM_FREE(enp
->en_esip
, length
, dcfg
);
727 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
732 #endif /* EFSYS_OPT_NVRAM */
734 #endif /* EFSYS_OPT_SIENA */