15e111ed8SAndrew Rybchenko /* SPDX-License-Identifier: BSD-3-Clause
25e111ed8SAndrew Rybchenko *
3*672386c1SAndrew Rybchenko * Copyright(c) 2019-2021 Xilinx, Inc.
45e111ed8SAndrew Rybchenko * Copyright(c) 2009-2019 Solarflare Communications Inc.
55e111ed8SAndrew Rybchenko */
65e111ed8SAndrew Rybchenko
75e111ed8SAndrew Rybchenko #include "efx.h"
85e111ed8SAndrew Rybchenko #include "efx_impl.h"
95e111ed8SAndrew Rybchenko
105e111ed8SAndrew Rybchenko #if EFSYS_OPT_NVRAM
115e111ed8SAndrew Rybchenko
125e111ed8SAndrew Rybchenko #if EFSYS_OPT_SIENA
135e111ed8SAndrew Rybchenko
145e111ed8SAndrew Rybchenko static const efx_nvram_ops_t __efx_nvram_siena_ops = {
155e111ed8SAndrew Rybchenko #if EFSYS_OPT_DIAG
165e111ed8SAndrew Rybchenko siena_nvram_test, /* envo_test */
175e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_DIAG */
185e111ed8SAndrew Rybchenko siena_nvram_type_to_partn, /* envo_type_to_partn */
195e111ed8SAndrew Rybchenko siena_nvram_partn_info, /* envo_partn_info */
205e111ed8SAndrew Rybchenko siena_nvram_partn_rw_start, /* envo_partn_rw_start */
215e111ed8SAndrew Rybchenko siena_nvram_partn_read, /* envo_partn_read */
225e111ed8SAndrew Rybchenko siena_nvram_partn_read, /* envo_partn_read_backup */
235e111ed8SAndrew Rybchenko siena_nvram_partn_erase, /* envo_partn_erase */
245e111ed8SAndrew Rybchenko siena_nvram_partn_write, /* envo_partn_write */
255e111ed8SAndrew Rybchenko siena_nvram_partn_rw_finish, /* envo_partn_rw_finish */
265e111ed8SAndrew Rybchenko siena_nvram_partn_get_version, /* envo_partn_get_version */
275e111ed8SAndrew Rybchenko siena_nvram_partn_set_version, /* envo_partn_set_version */
285e111ed8SAndrew Rybchenko NULL, /* envo_partn_validate */
295e111ed8SAndrew Rybchenko };
305e111ed8SAndrew Rybchenko
315e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */
325e111ed8SAndrew Rybchenko
335e111ed8SAndrew Rybchenko #if EFX_OPTS_EF10()
345e111ed8SAndrew Rybchenko
355e111ed8SAndrew Rybchenko static const efx_nvram_ops_t __efx_nvram_ef10_ops = {
365e111ed8SAndrew Rybchenko #if EFSYS_OPT_DIAG
375e111ed8SAndrew Rybchenko ef10_nvram_test, /* envo_test */
385e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_DIAG */
395e111ed8SAndrew Rybchenko ef10_nvram_type_to_partn, /* envo_type_to_partn */
405e111ed8SAndrew Rybchenko ef10_nvram_partn_info, /* envo_partn_info */
415e111ed8SAndrew Rybchenko ef10_nvram_partn_rw_start, /* envo_partn_rw_start */
425e111ed8SAndrew Rybchenko ef10_nvram_partn_read, /* envo_partn_read */
435e111ed8SAndrew Rybchenko ef10_nvram_partn_read_backup, /* envo_partn_read_backup */
445e111ed8SAndrew Rybchenko ef10_nvram_partn_erase, /* envo_partn_erase */
455e111ed8SAndrew Rybchenko ef10_nvram_partn_write, /* envo_partn_write */
465e111ed8SAndrew Rybchenko ef10_nvram_partn_rw_finish, /* envo_partn_rw_finish */
475e111ed8SAndrew Rybchenko ef10_nvram_partn_get_version, /* envo_partn_get_version */
485e111ed8SAndrew Rybchenko ef10_nvram_partn_set_version, /* envo_partn_set_version */
495e111ed8SAndrew Rybchenko ef10_nvram_buffer_validate, /* envo_buffer_validate */
505e111ed8SAndrew Rybchenko };
515e111ed8SAndrew Rybchenko
525e111ed8SAndrew Rybchenko #endif /* EFX_OPTS_EF10() */
535e111ed8SAndrew Rybchenko
545e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_nvram_init(__in efx_nic_t * enp)555e111ed8SAndrew Rybchenko efx_nvram_init(
565e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
575e111ed8SAndrew Rybchenko {
585e111ed8SAndrew Rybchenko const efx_nvram_ops_t *envop;
595e111ed8SAndrew Rybchenko efx_rc_t rc;
605e111ed8SAndrew Rybchenko
615e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
625e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
635e111ed8SAndrew Rybchenko EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NVRAM));
645e111ed8SAndrew Rybchenko
655e111ed8SAndrew Rybchenko switch (enp->en_family) {
665e111ed8SAndrew Rybchenko #if EFSYS_OPT_SIENA
675e111ed8SAndrew Rybchenko case EFX_FAMILY_SIENA:
685e111ed8SAndrew Rybchenko envop = &__efx_nvram_siena_ops;
695e111ed8SAndrew Rybchenko break;
705e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */
715e111ed8SAndrew Rybchenko
725e111ed8SAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON
735e111ed8SAndrew Rybchenko case EFX_FAMILY_HUNTINGTON:
745e111ed8SAndrew Rybchenko envop = &__efx_nvram_ef10_ops;
755e111ed8SAndrew Rybchenko break;
765e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_HUNTINGTON */
775e111ed8SAndrew Rybchenko
785e111ed8SAndrew Rybchenko #if EFSYS_OPT_MEDFORD
795e111ed8SAndrew Rybchenko case EFX_FAMILY_MEDFORD:
805e111ed8SAndrew Rybchenko envop = &__efx_nvram_ef10_ops;
815e111ed8SAndrew Rybchenko break;
825e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD */
835e111ed8SAndrew Rybchenko
845e111ed8SAndrew Rybchenko #if EFSYS_OPT_MEDFORD2
855e111ed8SAndrew Rybchenko case EFX_FAMILY_MEDFORD2:
865e111ed8SAndrew Rybchenko envop = &__efx_nvram_ef10_ops;
875e111ed8SAndrew Rybchenko break;
885e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD2 */
895e111ed8SAndrew Rybchenko
905e111ed8SAndrew Rybchenko default:
915e111ed8SAndrew Rybchenko EFSYS_ASSERT(0);
925e111ed8SAndrew Rybchenko rc = ENOTSUP;
935e111ed8SAndrew Rybchenko goto fail1;
945e111ed8SAndrew Rybchenko }
955e111ed8SAndrew Rybchenko
965e111ed8SAndrew Rybchenko enp->en_envop = envop;
975e111ed8SAndrew Rybchenko enp->en_mod_flags |= EFX_MOD_NVRAM;
985e111ed8SAndrew Rybchenko
995e111ed8SAndrew Rybchenko enp->en_nvram_partn_locked = EFX_NVRAM_PARTN_INVALID;
1005e111ed8SAndrew Rybchenko
1015e111ed8SAndrew Rybchenko return (0);
1025e111ed8SAndrew Rybchenko
1035e111ed8SAndrew Rybchenko fail1:
1045e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
1055e111ed8SAndrew Rybchenko
1065e111ed8SAndrew Rybchenko return (rc);
1075e111ed8SAndrew Rybchenko }
1085e111ed8SAndrew Rybchenko
1095e111ed8SAndrew Rybchenko #if EFSYS_OPT_DIAG
1105e111ed8SAndrew Rybchenko
1115e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_nvram_test(__in efx_nic_t * enp)1125e111ed8SAndrew Rybchenko efx_nvram_test(
1135e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
1145e111ed8SAndrew Rybchenko {
1155e111ed8SAndrew Rybchenko const efx_nvram_ops_t *envop = enp->en_envop;
1165e111ed8SAndrew Rybchenko efx_rc_t rc;
1175e111ed8SAndrew Rybchenko
1185e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1195e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
1205e111ed8SAndrew Rybchenko
1215e111ed8SAndrew Rybchenko if ((rc = envop->envo_test(enp)) != 0)
1225e111ed8SAndrew Rybchenko goto fail1;
1235e111ed8SAndrew Rybchenko
1245e111ed8SAndrew Rybchenko return (0);
1255e111ed8SAndrew Rybchenko
1265e111ed8SAndrew Rybchenko fail1:
1275e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
1285e111ed8SAndrew Rybchenko
1295e111ed8SAndrew Rybchenko return (rc);
1305e111ed8SAndrew Rybchenko }
1315e111ed8SAndrew Rybchenko
1325e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_DIAG */
1335e111ed8SAndrew Rybchenko
1345e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_nvram_size(__in efx_nic_t * enp,__in efx_nvram_type_t type,__out size_t * sizep)1355e111ed8SAndrew Rybchenko efx_nvram_size(
1365e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
1375e111ed8SAndrew Rybchenko __in efx_nvram_type_t type,
1385e111ed8SAndrew Rybchenko __out size_t *sizep)
1395e111ed8SAndrew Rybchenko {
1405e111ed8SAndrew Rybchenko const efx_nvram_ops_t *envop = enp->en_envop;
1415e111ed8SAndrew Rybchenko efx_nvram_info_t eni = { 0 };
1425e111ed8SAndrew Rybchenko uint32_t partn;
1435e111ed8SAndrew Rybchenko efx_rc_t rc;
1445e111ed8SAndrew Rybchenko
1455e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1465e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
1475e111ed8SAndrew Rybchenko
1485e111ed8SAndrew Rybchenko if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
1495e111ed8SAndrew Rybchenko goto fail1;
1505e111ed8SAndrew Rybchenko
1515e111ed8SAndrew Rybchenko if ((rc = envop->envo_partn_info(enp, partn, &eni)) != 0)
1525e111ed8SAndrew Rybchenko goto fail2;
1535e111ed8SAndrew Rybchenko
1545e111ed8SAndrew Rybchenko *sizep = eni.eni_partn_size;
1555e111ed8SAndrew Rybchenko
1565e111ed8SAndrew Rybchenko return (0);
1575e111ed8SAndrew Rybchenko
1585e111ed8SAndrew Rybchenko fail2:
1595e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
1605e111ed8SAndrew Rybchenko fail1:
1615e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
1625e111ed8SAndrew Rybchenko *sizep = 0;
1635e111ed8SAndrew Rybchenko
1645e111ed8SAndrew Rybchenko return (rc);
1655e111ed8SAndrew Rybchenko }
1665e111ed8SAndrew Rybchenko
1675e111ed8SAndrew Rybchenko extern __checkReturn efx_rc_t
efx_nvram_info(__in efx_nic_t * enp,__in efx_nvram_type_t type,__out efx_nvram_info_t * enip)1685e111ed8SAndrew Rybchenko efx_nvram_info(
1695e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
1705e111ed8SAndrew Rybchenko __in efx_nvram_type_t type,
1715e111ed8SAndrew Rybchenko __out efx_nvram_info_t *enip)
1725e111ed8SAndrew Rybchenko {
1735e111ed8SAndrew Rybchenko const efx_nvram_ops_t *envop = enp->en_envop;
1745e111ed8SAndrew Rybchenko uint32_t partn;
1755e111ed8SAndrew Rybchenko efx_rc_t rc;
1765e111ed8SAndrew Rybchenko
1775e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1785e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
1795e111ed8SAndrew Rybchenko
1805e111ed8SAndrew Rybchenko if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
1815e111ed8SAndrew Rybchenko goto fail1;
1825e111ed8SAndrew Rybchenko
1835e111ed8SAndrew Rybchenko if ((rc = envop->envo_partn_info(enp, partn, enip)) != 0)
1845e111ed8SAndrew Rybchenko goto fail2;
1855e111ed8SAndrew Rybchenko
1865e111ed8SAndrew Rybchenko return (0);
1875e111ed8SAndrew Rybchenko
1885e111ed8SAndrew Rybchenko fail2:
1895e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
1905e111ed8SAndrew Rybchenko fail1:
1915e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
1925e111ed8SAndrew Rybchenko
1935e111ed8SAndrew Rybchenko return (rc);
1945e111ed8SAndrew Rybchenko }
1955e111ed8SAndrew Rybchenko
1965e111ed8SAndrew Rybchenko
1975e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
1985e111ed8SAndrew Rybchenko efx_nvram_get_version(
1995e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
2005e111ed8SAndrew Rybchenko __in efx_nvram_type_t type,
2015e111ed8SAndrew Rybchenko __out uint32_t *subtypep,
2025e111ed8SAndrew Rybchenko __out_ecount(4) uint16_t version[4])
2035e111ed8SAndrew Rybchenko {
2045e111ed8SAndrew Rybchenko const efx_nvram_ops_t *envop = enp->en_envop;
2055e111ed8SAndrew Rybchenko uint32_t partn;
2065e111ed8SAndrew Rybchenko efx_rc_t rc;
2075e111ed8SAndrew Rybchenko
2085e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
2095e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
2105e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
2115e111ed8SAndrew Rybchenko
2125e111ed8SAndrew Rybchenko if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
2135e111ed8SAndrew Rybchenko goto fail1;
2145e111ed8SAndrew Rybchenko
2155e111ed8SAndrew Rybchenko if ((rc = envop->envo_partn_get_version(enp, partn,
2165e111ed8SAndrew Rybchenko subtypep, version)) != 0)
2175e111ed8SAndrew Rybchenko goto fail2;
2185e111ed8SAndrew Rybchenko
2195e111ed8SAndrew Rybchenko return (0);
2205e111ed8SAndrew Rybchenko
2215e111ed8SAndrew Rybchenko fail2:
2225e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
2235e111ed8SAndrew Rybchenko fail1:
2245e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
2255e111ed8SAndrew Rybchenko
2265e111ed8SAndrew Rybchenko return (rc);
2275e111ed8SAndrew Rybchenko }
2285e111ed8SAndrew Rybchenko
2295e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_nvram_rw_start(__in efx_nic_t * enp,__in efx_nvram_type_t type,__out_opt size_t * chunk_sizep)2305e111ed8SAndrew Rybchenko efx_nvram_rw_start(
2315e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
2325e111ed8SAndrew Rybchenko __in efx_nvram_type_t type,
2335e111ed8SAndrew Rybchenko __out_opt size_t *chunk_sizep)
2345e111ed8SAndrew Rybchenko {
2355e111ed8SAndrew Rybchenko const efx_nvram_ops_t *envop = enp->en_envop;
2365e111ed8SAndrew Rybchenko uint32_t partn;
2375e111ed8SAndrew Rybchenko efx_rc_t rc;
2385e111ed8SAndrew Rybchenko
2395e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
2405e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
2415e111ed8SAndrew Rybchenko
2425e111ed8SAndrew Rybchenko if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
2435e111ed8SAndrew Rybchenko goto fail1;
2445e111ed8SAndrew Rybchenko
2455e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, EFX_NVRAM_PARTN_INVALID);
2465e111ed8SAndrew Rybchenko
2475e111ed8SAndrew Rybchenko if ((rc = envop->envo_partn_rw_start(enp, partn, chunk_sizep)) != 0)
2485e111ed8SAndrew Rybchenko goto fail2;
2495e111ed8SAndrew Rybchenko
2505e111ed8SAndrew Rybchenko enp->en_nvram_partn_locked = partn;
2515e111ed8SAndrew Rybchenko
2525e111ed8SAndrew Rybchenko return (0);
2535e111ed8SAndrew Rybchenko
2545e111ed8SAndrew Rybchenko fail2:
2555e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
2565e111ed8SAndrew Rybchenko fail1:
2575e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
2585e111ed8SAndrew Rybchenko
2595e111ed8SAndrew Rybchenko return (rc);
2605e111ed8SAndrew Rybchenko }
2615e111ed8SAndrew Rybchenko
2625e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_nvram_read_chunk(__in efx_nic_t * enp,__in efx_nvram_type_t type,__in unsigned int offset,__out_bcount (size)caddr_t data,__in size_t size)2635e111ed8SAndrew Rybchenko efx_nvram_read_chunk(
2645e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
2655e111ed8SAndrew Rybchenko __in efx_nvram_type_t type,
2665e111ed8SAndrew Rybchenko __in unsigned int offset,
2675e111ed8SAndrew Rybchenko __out_bcount(size) caddr_t data,
2685e111ed8SAndrew Rybchenko __in size_t size)
2695e111ed8SAndrew Rybchenko {
2705e111ed8SAndrew Rybchenko const efx_nvram_ops_t *envop = enp->en_envop;
2715e111ed8SAndrew Rybchenko uint32_t partn;
2725e111ed8SAndrew Rybchenko efx_rc_t rc;
2735e111ed8SAndrew Rybchenko
2745e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
2755e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
2765e111ed8SAndrew Rybchenko
2775e111ed8SAndrew Rybchenko if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
2785e111ed8SAndrew Rybchenko goto fail1;
2795e111ed8SAndrew Rybchenko
2805e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn);
2815e111ed8SAndrew Rybchenko
2825e111ed8SAndrew Rybchenko if ((rc = envop->envo_partn_read(enp, partn, offset, data, size)) != 0)
2835e111ed8SAndrew Rybchenko goto fail2;
2845e111ed8SAndrew Rybchenko
2855e111ed8SAndrew Rybchenko return (0);
2865e111ed8SAndrew Rybchenko
2875e111ed8SAndrew Rybchenko fail2:
2885e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
2895e111ed8SAndrew Rybchenko fail1:
2905e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
2915e111ed8SAndrew Rybchenko
2925e111ed8SAndrew Rybchenko return (rc);
2935e111ed8SAndrew Rybchenko }
2945e111ed8SAndrew Rybchenko
2955e111ed8SAndrew Rybchenko /*
2965e111ed8SAndrew Rybchenko * Read from the backup (writeable) store of an A/B partition.
2975e111ed8SAndrew Rybchenko * For non A/B partitions, there is only a single store, and so this
2985e111ed8SAndrew Rybchenko * function has the same behaviour as efx_nvram_read_chunk().
2995e111ed8SAndrew Rybchenko */
3005e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_nvram_read_backup(__in efx_nic_t * enp,__in efx_nvram_type_t type,__in unsigned int offset,__out_bcount (size)caddr_t data,__in size_t size)3015e111ed8SAndrew Rybchenko efx_nvram_read_backup(
3025e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
3035e111ed8SAndrew Rybchenko __in efx_nvram_type_t type,
3045e111ed8SAndrew Rybchenko __in unsigned int offset,
3055e111ed8SAndrew Rybchenko __out_bcount(size) caddr_t data,
3065e111ed8SAndrew Rybchenko __in size_t size)
3075e111ed8SAndrew Rybchenko {
3085e111ed8SAndrew Rybchenko const efx_nvram_ops_t *envop = enp->en_envop;
3095e111ed8SAndrew Rybchenko uint32_t partn;
3105e111ed8SAndrew Rybchenko efx_rc_t rc;
3115e111ed8SAndrew Rybchenko
3125e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
3135e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
3145e111ed8SAndrew Rybchenko
3155e111ed8SAndrew Rybchenko if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
3165e111ed8SAndrew Rybchenko goto fail1;
3175e111ed8SAndrew Rybchenko
3185e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn);
3195e111ed8SAndrew Rybchenko
3205e111ed8SAndrew Rybchenko if ((rc = envop->envo_partn_read_backup(enp, partn, offset,
3215e111ed8SAndrew Rybchenko data, size)) != 0)
3225e111ed8SAndrew Rybchenko goto fail2;
3235e111ed8SAndrew Rybchenko
3245e111ed8SAndrew Rybchenko return (0);
3255e111ed8SAndrew Rybchenko
3265e111ed8SAndrew Rybchenko fail2:
3275e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
3285e111ed8SAndrew Rybchenko fail1:
3295e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
3305e111ed8SAndrew Rybchenko
3315e111ed8SAndrew Rybchenko return (rc);
3325e111ed8SAndrew Rybchenko }
3335e111ed8SAndrew Rybchenko
3345e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_nvram_erase(__in efx_nic_t * enp,__in efx_nvram_type_t type)3355e111ed8SAndrew Rybchenko efx_nvram_erase(
3365e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
3375e111ed8SAndrew Rybchenko __in efx_nvram_type_t type)
3385e111ed8SAndrew Rybchenko {
3395e111ed8SAndrew Rybchenko const efx_nvram_ops_t *envop = enp->en_envop;
3405e111ed8SAndrew Rybchenko unsigned int offset = 0;
3415e111ed8SAndrew Rybchenko efx_nvram_info_t eni = { 0 };
3425e111ed8SAndrew Rybchenko uint32_t partn;
3435e111ed8SAndrew Rybchenko efx_rc_t rc;
3445e111ed8SAndrew Rybchenko
3455e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
3465e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
3475e111ed8SAndrew Rybchenko
3485e111ed8SAndrew Rybchenko if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
3495e111ed8SAndrew Rybchenko goto fail1;
3505e111ed8SAndrew Rybchenko
3515e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn);
3525e111ed8SAndrew Rybchenko
3535e111ed8SAndrew Rybchenko if ((rc = envop->envo_partn_info(enp, partn, &eni)) != 0)
3545e111ed8SAndrew Rybchenko goto fail2;
3555e111ed8SAndrew Rybchenko
3565e111ed8SAndrew Rybchenko if ((rc = envop->envo_partn_erase(enp, partn, offset,
3575e111ed8SAndrew Rybchenko eni.eni_partn_size)) != 0)
3585e111ed8SAndrew Rybchenko goto fail3;
3595e111ed8SAndrew Rybchenko
3605e111ed8SAndrew Rybchenko return (0);
3615e111ed8SAndrew Rybchenko
3625e111ed8SAndrew Rybchenko fail3:
3635e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3);
3645e111ed8SAndrew Rybchenko fail2:
3655e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
3665e111ed8SAndrew Rybchenko fail1:
3675e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
3685e111ed8SAndrew Rybchenko
3695e111ed8SAndrew Rybchenko return (rc);
3705e111ed8SAndrew Rybchenko }
3715e111ed8SAndrew Rybchenko
3725e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_nvram_write_chunk(__in efx_nic_t * enp,__in efx_nvram_type_t type,__in unsigned int offset,__in_bcount (size)caddr_t data,__in size_t size)3735e111ed8SAndrew Rybchenko efx_nvram_write_chunk(
3745e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
3755e111ed8SAndrew Rybchenko __in efx_nvram_type_t type,
3765e111ed8SAndrew Rybchenko __in unsigned int offset,
3775e111ed8SAndrew Rybchenko __in_bcount(size) caddr_t data,
3785e111ed8SAndrew Rybchenko __in size_t size)
3795e111ed8SAndrew Rybchenko {
3805e111ed8SAndrew Rybchenko const efx_nvram_ops_t *envop = enp->en_envop;
3815e111ed8SAndrew Rybchenko uint32_t partn;
3825e111ed8SAndrew Rybchenko efx_rc_t rc;
3835e111ed8SAndrew Rybchenko
3845e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
3855e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
3865e111ed8SAndrew Rybchenko
3875e111ed8SAndrew Rybchenko if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
3885e111ed8SAndrew Rybchenko goto fail1;
3895e111ed8SAndrew Rybchenko
3905e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn);
3915e111ed8SAndrew Rybchenko
3925e111ed8SAndrew Rybchenko if ((rc = envop->envo_partn_write(enp, partn, offset, data, size)) != 0)
3935e111ed8SAndrew Rybchenko goto fail2;
3945e111ed8SAndrew Rybchenko
3955e111ed8SAndrew Rybchenko return (0);
3965e111ed8SAndrew Rybchenko
3975e111ed8SAndrew Rybchenko fail2:
3985e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
3995e111ed8SAndrew Rybchenko fail1:
4005e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
4015e111ed8SAndrew Rybchenko
4025e111ed8SAndrew Rybchenko return (rc);
4035e111ed8SAndrew Rybchenko }
4045e111ed8SAndrew Rybchenko
4055e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_nvram_rw_finish(__in efx_nic_t * enp,__in efx_nvram_type_t type,__out_opt uint32_t * verify_resultp)4065e111ed8SAndrew Rybchenko efx_nvram_rw_finish(
4075e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
4085e111ed8SAndrew Rybchenko __in efx_nvram_type_t type,
4095e111ed8SAndrew Rybchenko __out_opt uint32_t *verify_resultp)
4105e111ed8SAndrew Rybchenko {
4115e111ed8SAndrew Rybchenko const efx_nvram_ops_t *envop = enp->en_envop;
4125e111ed8SAndrew Rybchenko uint32_t partn;
4135e111ed8SAndrew Rybchenko uint32_t verify_result = 0;
4145e111ed8SAndrew Rybchenko efx_rc_t rc;
4155e111ed8SAndrew Rybchenko
4165e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
4175e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
4185e111ed8SAndrew Rybchenko
4195e111ed8SAndrew Rybchenko if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
4205e111ed8SAndrew Rybchenko goto fail1;
4215e111ed8SAndrew Rybchenko
4225e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, partn);
4235e111ed8SAndrew Rybchenko
4245e111ed8SAndrew Rybchenko if ((rc = envop->envo_partn_rw_finish(enp, partn, &verify_result)) != 0)
4255e111ed8SAndrew Rybchenko goto fail2;
4265e111ed8SAndrew Rybchenko
4275e111ed8SAndrew Rybchenko enp->en_nvram_partn_locked = EFX_NVRAM_PARTN_INVALID;
4285e111ed8SAndrew Rybchenko
4295e111ed8SAndrew Rybchenko if (verify_resultp != NULL)
4305e111ed8SAndrew Rybchenko *verify_resultp = verify_result;
4315e111ed8SAndrew Rybchenko
4325e111ed8SAndrew Rybchenko return (0);
4335e111ed8SAndrew Rybchenko
4345e111ed8SAndrew Rybchenko fail2:
4355e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
4365e111ed8SAndrew Rybchenko enp->en_nvram_partn_locked = EFX_NVRAM_PARTN_INVALID;
4375e111ed8SAndrew Rybchenko
4385e111ed8SAndrew Rybchenko fail1:
4395e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
4405e111ed8SAndrew Rybchenko
4415e111ed8SAndrew Rybchenko /* Always report verification result */
4425e111ed8SAndrew Rybchenko if (verify_resultp != NULL)
4435e111ed8SAndrew Rybchenko *verify_resultp = verify_result;
4445e111ed8SAndrew Rybchenko
4455e111ed8SAndrew Rybchenko return (rc);
4465e111ed8SAndrew Rybchenko }
4475e111ed8SAndrew Rybchenko
4485e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
4495e111ed8SAndrew Rybchenko efx_nvram_set_version(
4505e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
4515e111ed8SAndrew Rybchenko __in efx_nvram_type_t type,
4525e111ed8SAndrew Rybchenko __in_ecount(4) uint16_t version[4])
4535e111ed8SAndrew Rybchenko {
4545e111ed8SAndrew Rybchenko const efx_nvram_ops_t *envop = enp->en_envop;
4555e111ed8SAndrew Rybchenko uint32_t partn;
4565e111ed8SAndrew Rybchenko efx_rc_t rc;
4575e111ed8SAndrew Rybchenko
4585e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
4595e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
4605e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
4615e111ed8SAndrew Rybchenko
4625e111ed8SAndrew Rybchenko if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
4635e111ed8SAndrew Rybchenko goto fail1;
4645e111ed8SAndrew Rybchenko
4655e111ed8SAndrew Rybchenko /*
4665e111ed8SAndrew Rybchenko * The Siena implementation of envo_set_version() will attempt to
4675e111ed8SAndrew Rybchenko * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG partition.
4685e111ed8SAndrew Rybchenko * Therefore, you can't have already acquired the NVRAM_UPDATE lock.
4695e111ed8SAndrew Rybchenko */
4705e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, EFX_NVRAM_PARTN_INVALID);
4715e111ed8SAndrew Rybchenko
4725e111ed8SAndrew Rybchenko if ((rc = envop->envo_partn_set_version(enp, partn, version)) != 0)
4735e111ed8SAndrew Rybchenko goto fail2;
4745e111ed8SAndrew Rybchenko
4755e111ed8SAndrew Rybchenko return (0);
4765e111ed8SAndrew Rybchenko
4775e111ed8SAndrew Rybchenko fail2:
4785e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
4795e111ed8SAndrew Rybchenko fail1:
4805e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
4815e111ed8SAndrew Rybchenko
4825e111ed8SAndrew Rybchenko return (rc);
4835e111ed8SAndrew Rybchenko }
4845e111ed8SAndrew Rybchenko
4855e111ed8SAndrew Rybchenko /* Validate buffer contents (before writing to flash) */
4865e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_nvram_validate(__in efx_nic_t * enp,__in efx_nvram_type_t type,__in_bcount (partn_size)caddr_t partn_data,__in size_t partn_size)4875e111ed8SAndrew Rybchenko efx_nvram_validate(
4885e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
4895e111ed8SAndrew Rybchenko __in efx_nvram_type_t type,
4905e111ed8SAndrew Rybchenko __in_bcount(partn_size) caddr_t partn_data,
4915e111ed8SAndrew Rybchenko __in size_t partn_size)
4925e111ed8SAndrew Rybchenko {
4935e111ed8SAndrew Rybchenko const efx_nvram_ops_t *envop = enp->en_envop;
4945e111ed8SAndrew Rybchenko uint32_t partn;
4955e111ed8SAndrew Rybchenko efx_rc_t rc;
4965e111ed8SAndrew Rybchenko
4975e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
4985e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
4995e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
5005e111ed8SAndrew Rybchenko
5015e111ed8SAndrew Rybchenko if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
5025e111ed8SAndrew Rybchenko goto fail1;
5035e111ed8SAndrew Rybchenko
5045e111ed8SAndrew Rybchenko if (envop->envo_buffer_validate != NULL) {
5055e111ed8SAndrew Rybchenko if ((rc = envop->envo_buffer_validate(partn,
5065e111ed8SAndrew Rybchenko partn_data, partn_size)) != 0)
5075e111ed8SAndrew Rybchenko goto fail2;
5085e111ed8SAndrew Rybchenko }
5095e111ed8SAndrew Rybchenko
5105e111ed8SAndrew Rybchenko return (0);
5115e111ed8SAndrew Rybchenko
5125e111ed8SAndrew Rybchenko fail2:
5135e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
5145e111ed8SAndrew Rybchenko fail1:
5155e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
5165e111ed8SAndrew Rybchenko
5175e111ed8SAndrew Rybchenko return (rc);
5185e111ed8SAndrew Rybchenko }
5195e111ed8SAndrew Rybchenko
5205e111ed8SAndrew Rybchenko
5215e111ed8SAndrew Rybchenko void
efx_nvram_fini(__in efx_nic_t * enp)5225e111ed8SAndrew Rybchenko efx_nvram_fini(
5235e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
5245e111ed8SAndrew Rybchenko {
5255e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
5265e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
5275e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
5285e111ed8SAndrew Rybchenko
5295e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_nvram_partn_locked, ==, EFX_NVRAM_PARTN_INVALID);
5305e111ed8SAndrew Rybchenko
5315e111ed8SAndrew Rybchenko enp->en_envop = NULL;
5325e111ed8SAndrew Rybchenko enp->en_mod_flags &= ~EFX_MOD_NVRAM;
5335e111ed8SAndrew Rybchenko }
5345e111ed8SAndrew Rybchenko
5355e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_NVRAM */
5365e111ed8SAndrew Rybchenko
5375e111ed8SAndrew Rybchenko #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD
5385e111ed8SAndrew Rybchenko
5395e111ed8SAndrew Rybchenko /*
5405e111ed8SAndrew Rybchenko * Internal MCDI request handling
5415e111ed8SAndrew Rybchenko */
5425e111ed8SAndrew Rybchenko
5435e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_nvram_partitions(__in efx_nic_t * enp,__out_bcount (size)caddr_t data,__in size_t size,__out unsigned int * npartnp)5445e111ed8SAndrew Rybchenko efx_mcdi_nvram_partitions(
5455e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
5465e111ed8SAndrew Rybchenko __out_bcount(size) caddr_t data,
5475e111ed8SAndrew Rybchenko __in size_t size,
5485e111ed8SAndrew Rybchenko __out unsigned int *npartnp)
5495e111ed8SAndrew Rybchenko {
5505e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
5515e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_PARTITIONS_IN_LEN,
5525e111ed8SAndrew Rybchenko MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX);
5535e111ed8SAndrew Rybchenko unsigned int npartn;
5545e111ed8SAndrew Rybchenko efx_rc_t rc;
5555e111ed8SAndrew Rybchenko
5565e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_NVRAM_PARTITIONS;
5575e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
5585e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN;
5595e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
5605e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX;
5615e111ed8SAndrew Rybchenko
5625e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req);
5635e111ed8SAndrew Rybchenko
5645e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
5655e111ed8SAndrew Rybchenko rc = req.emr_rc;
5665e111ed8SAndrew Rybchenko goto fail1;
5675e111ed8SAndrew Rybchenko }
5685e111ed8SAndrew Rybchenko
5695e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) {
5705e111ed8SAndrew Rybchenko rc = EMSGSIZE;
5715e111ed8SAndrew Rybchenko goto fail2;
5725e111ed8SAndrew Rybchenko }
5735e111ed8SAndrew Rybchenko npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS);
5745e111ed8SAndrew Rybchenko
5755e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) {
5765e111ed8SAndrew Rybchenko rc = ENOENT;
5775e111ed8SAndrew Rybchenko goto fail3;
5785e111ed8SAndrew Rybchenko }
5795e111ed8SAndrew Rybchenko
5805e111ed8SAndrew Rybchenko if (size < npartn * sizeof (uint32_t)) {
5815e111ed8SAndrew Rybchenko rc = ENOSPC;
5825e111ed8SAndrew Rybchenko goto fail3;
5835e111ed8SAndrew Rybchenko }
5845e111ed8SAndrew Rybchenko
5855e111ed8SAndrew Rybchenko *npartnp = npartn;
5865e111ed8SAndrew Rybchenko
5875e111ed8SAndrew Rybchenko memcpy(data,
5885e111ed8SAndrew Rybchenko MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID),
5895e111ed8SAndrew Rybchenko (npartn * sizeof (uint32_t)));
5905e111ed8SAndrew Rybchenko
5915e111ed8SAndrew Rybchenko return (0);
5925e111ed8SAndrew Rybchenko
5935e111ed8SAndrew Rybchenko fail3:
5945e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3);
5955e111ed8SAndrew Rybchenko fail2:
5965e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
5975e111ed8SAndrew Rybchenko fail1:
5985e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
5995e111ed8SAndrew Rybchenko
6005e111ed8SAndrew Rybchenko return (rc);
6015e111ed8SAndrew Rybchenko }
6025e111ed8SAndrew Rybchenko
6035e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
6045e111ed8SAndrew Rybchenko efx_mcdi_nvram_metadata(
6055e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
6065e111ed8SAndrew Rybchenko __in uint32_t partn,
6075e111ed8SAndrew Rybchenko __out uint32_t *subtypep,
6085e111ed8SAndrew Rybchenko __out_ecount(4) uint16_t version[4],
6095e111ed8SAndrew Rybchenko __out_bcount_opt(size) char *descp,
6105e111ed8SAndrew Rybchenko __in size_t size)
6115e111ed8SAndrew Rybchenko {
6125e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
6135e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_METADATA_IN_LEN,
6145e111ed8SAndrew Rybchenko MC_CMD_NVRAM_METADATA_OUT_LENMAX);
6155e111ed8SAndrew Rybchenko efx_rc_t rc;
6165e111ed8SAndrew Rybchenko
6175e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_NVRAM_METADATA;
6185e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
6195e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN;
6205e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
6215e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX;
6225e111ed8SAndrew Rybchenko
6235e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn);
6245e111ed8SAndrew Rybchenko
6255e111ed8SAndrew Rybchenko efx_mcdi_execute_quiet(enp, &req);
6265e111ed8SAndrew Rybchenko
6275e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
6285e111ed8SAndrew Rybchenko rc = req.emr_rc;
6295e111ed8SAndrew Rybchenko goto fail1;
6305e111ed8SAndrew Rybchenko }
6315e111ed8SAndrew Rybchenko
6325e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
6335e111ed8SAndrew Rybchenko rc = EMSGSIZE;
6345e111ed8SAndrew Rybchenko goto fail2;
6355e111ed8SAndrew Rybchenko }
6365e111ed8SAndrew Rybchenko
6375e111ed8SAndrew Rybchenko if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
6385e111ed8SAndrew Rybchenko NVRAM_METADATA_OUT_SUBTYPE_VALID)) {
6395e111ed8SAndrew Rybchenko *subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE);
6405e111ed8SAndrew Rybchenko } else {
6415e111ed8SAndrew Rybchenko *subtypep = 0;
6425e111ed8SAndrew Rybchenko }
6435e111ed8SAndrew Rybchenko
6445e111ed8SAndrew Rybchenko if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
6455e111ed8SAndrew Rybchenko NVRAM_METADATA_OUT_VERSION_VALID)) {
6465e111ed8SAndrew Rybchenko version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W);
6475e111ed8SAndrew Rybchenko version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X);
6485e111ed8SAndrew Rybchenko version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y);
6495e111ed8SAndrew Rybchenko version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z);
6505e111ed8SAndrew Rybchenko } else {
6515e111ed8SAndrew Rybchenko version[0] = version[1] = version[2] = version[3] = 0;
6525e111ed8SAndrew Rybchenko }
6535e111ed8SAndrew Rybchenko
6545e111ed8SAndrew Rybchenko if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
6555e111ed8SAndrew Rybchenko NVRAM_METADATA_OUT_DESCRIPTION_VALID)) {
6565e111ed8SAndrew Rybchenko /* Return optional descrition string */
6575e111ed8SAndrew Rybchenko if ((descp != NULL) && (size > 0)) {
6585e111ed8SAndrew Rybchenko size_t desclen;
6595e111ed8SAndrew Rybchenko
6605e111ed8SAndrew Rybchenko descp[0] = '\0';
6615e111ed8SAndrew Rybchenko desclen = (req.emr_out_length_used
6625e111ed8SAndrew Rybchenko - MC_CMD_NVRAM_METADATA_OUT_LEN(0));
6635e111ed8SAndrew Rybchenko
6645e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(desclen, <=,
6655e111ed8SAndrew Rybchenko MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM);
6665e111ed8SAndrew Rybchenko
6675e111ed8SAndrew Rybchenko if (size < desclen) {
6685e111ed8SAndrew Rybchenko rc = ENOSPC;
6695e111ed8SAndrew Rybchenko goto fail3;
6705e111ed8SAndrew Rybchenko }
6715e111ed8SAndrew Rybchenko
6725e111ed8SAndrew Rybchenko memcpy(descp, MCDI_OUT2(req, char,
6735e111ed8SAndrew Rybchenko NVRAM_METADATA_OUT_DESCRIPTION),
6745e111ed8SAndrew Rybchenko desclen);
6755e111ed8SAndrew Rybchenko
6765e111ed8SAndrew Rybchenko /* Ensure string is NUL terminated */
6775e111ed8SAndrew Rybchenko descp[desclen] = '\0';
6785e111ed8SAndrew Rybchenko }
6795e111ed8SAndrew Rybchenko }
6805e111ed8SAndrew Rybchenko
6815e111ed8SAndrew Rybchenko return (0);
6825e111ed8SAndrew Rybchenko
6835e111ed8SAndrew Rybchenko fail3:
6845e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3);
6855e111ed8SAndrew Rybchenko fail2:
6865e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
6875e111ed8SAndrew Rybchenko fail1:
6885e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
6895e111ed8SAndrew Rybchenko
6905e111ed8SAndrew Rybchenko return (rc);
6915e111ed8SAndrew Rybchenko }
6925e111ed8SAndrew Rybchenko
6935e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_nvram_info(__in efx_nic_t * enp,__in uint32_t partn,__out efx_nvram_info_t * enip)6945e111ed8SAndrew Rybchenko efx_mcdi_nvram_info(
6955e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
6965e111ed8SAndrew Rybchenko __in uint32_t partn,
6975e111ed8SAndrew Rybchenko __out efx_nvram_info_t *enip)
6985e111ed8SAndrew Rybchenko {
6995e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_INFO_IN_LEN,
7005e111ed8SAndrew Rybchenko MC_CMD_NVRAM_INFO_V2_OUT_LEN);
7015e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
7025e111ed8SAndrew Rybchenko efx_rc_t rc;
7035e111ed8SAndrew Rybchenko
7045e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_NVRAM_INFO;
7055e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
7065e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
7075e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
7085e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN;
7095e111ed8SAndrew Rybchenko
7105e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
7115e111ed8SAndrew Rybchenko
7125e111ed8SAndrew Rybchenko efx_mcdi_execute_quiet(enp, &req);
7135e111ed8SAndrew Rybchenko
7145e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
7155e111ed8SAndrew Rybchenko rc = req.emr_rc;
7165e111ed8SAndrew Rybchenko goto fail1;
7175e111ed8SAndrew Rybchenko }
7185e111ed8SAndrew Rybchenko
7195e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {
7205e111ed8SAndrew Rybchenko rc = EMSGSIZE;
7215e111ed8SAndrew Rybchenko goto fail2;
7225e111ed8SAndrew Rybchenko }
7235e111ed8SAndrew Rybchenko
7245e111ed8SAndrew Rybchenko enip->eni_partn_size = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
7255e111ed8SAndrew Rybchenko
7265e111ed8SAndrew Rybchenko enip->eni_address = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR);
7275e111ed8SAndrew Rybchenko
7285e111ed8SAndrew Rybchenko enip->eni_erase_size = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE);
7295e111ed8SAndrew Rybchenko
7305e111ed8SAndrew Rybchenko enip->eni_write_size =
7315e111ed8SAndrew Rybchenko (req.emr_out_length_used <
7325e111ed8SAndrew Rybchenko MC_CMD_NVRAM_INFO_V2_OUT_LEN) ?
7335e111ed8SAndrew Rybchenko 0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE);
7345e111ed8SAndrew Rybchenko
7355e111ed8SAndrew Rybchenko enip->eni_flags = 0;
7365e111ed8SAndrew Rybchenko
7375e111ed8SAndrew Rybchenko if (MCDI_OUT_DWORD_FIELD(req, NVRAM_INFO_OUT_FLAGS,
7385e111ed8SAndrew Rybchenko NVRAM_INFO_OUT_PROTECTED))
7395e111ed8SAndrew Rybchenko enip->eni_flags |= EFX_NVRAM_FLAG_READ_ONLY;
7405e111ed8SAndrew Rybchenko
7415e111ed8SAndrew Rybchenko if (MCDI_OUT_DWORD_FIELD(req, NVRAM_INFO_OUT_FLAGS,
7425e111ed8SAndrew Rybchenko NVRAM_INFO_OUT_READ_ONLY))
7435e111ed8SAndrew Rybchenko enip->eni_flags |= EFX_NVRAM_FLAG_READ_ONLY;
7445e111ed8SAndrew Rybchenko
7455e111ed8SAndrew Rybchenko return (0);
7465e111ed8SAndrew Rybchenko
7475e111ed8SAndrew Rybchenko fail2:
7485e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
7495e111ed8SAndrew Rybchenko fail1:
7505e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
7515e111ed8SAndrew Rybchenko
7525e111ed8SAndrew Rybchenko return (rc);
7535e111ed8SAndrew Rybchenko }
7545e111ed8SAndrew Rybchenko
7555e111ed8SAndrew Rybchenko /*
7565e111ed8SAndrew Rybchenko * MC_CMD_NVRAM_UPDATE_START_V2 must be used to support firmware-verified
7575e111ed8SAndrew Rybchenko * NVRAM updates. Older firmware will ignore the flags field in the request.
7585e111ed8SAndrew Rybchenko */
7595e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_nvram_update_start(__in efx_nic_t * enp,__in uint32_t partn)7605e111ed8SAndrew Rybchenko efx_mcdi_nvram_update_start(
7615e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
7625e111ed8SAndrew Rybchenko __in uint32_t partn)
7635e111ed8SAndrew Rybchenko {
7645e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN,
7655e111ed8SAndrew Rybchenko MC_CMD_NVRAM_UPDATE_START_OUT_LEN);
7665e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
7675e111ed8SAndrew Rybchenko efx_rc_t rc;
7685e111ed8SAndrew Rybchenko
7695e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
7705e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
7715e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN;
7725e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
7735e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN;
7745e111ed8SAndrew Rybchenko
7755e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_V2_IN_TYPE, partn);
7765e111ed8SAndrew Rybchenko
7775e111ed8SAndrew Rybchenko MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_START_V2_IN_FLAGS,
7785e111ed8SAndrew Rybchenko NVRAM_UPDATE_START_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1);
7795e111ed8SAndrew Rybchenko
7805e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req);
7815e111ed8SAndrew Rybchenko
7825e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
7835e111ed8SAndrew Rybchenko rc = req.emr_rc;
7845e111ed8SAndrew Rybchenko goto fail1;
7855e111ed8SAndrew Rybchenko }
7865e111ed8SAndrew Rybchenko
7875e111ed8SAndrew Rybchenko return (0);
7885e111ed8SAndrew Rybchenko
7895e111ed8SAndrew Rybchenko fail1:
7905e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
7915e111ed8SAndrew Rybchenko
7925e111ed8SAndrew Rybchenko return (rc);
7935e111ed8SAndrew Rybchenko }
7945e111ed8SAndrew Rybchenko
7955e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_nvram_read(__in efx_nic_t * enp,__in uint32_t partn,__in uint32_t offset,__out_bcount (size)caddr_t data,__in size_t size,__in uint32_t mode)7965e111ed8SAndrew Rybchenko efx_mcdi_nvram_read(
7975e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
7985e111ed8SAndrew Rybchenko __in uint32_t partn,
7995e111ed8SAndrew Rybchenko __in uint32_t offset,
8005e111ed8SAndrew Rybchenko __out_bcount(size) caddr_t data,
8015e111ed8SAndrew Rybchenko __in size_t size,
8025e111ed8SAndrew Rybchenko __in uint32_t mode)
8035e111ed8SAndrew Rybchenko {
8045e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
8055e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_READ_IN_V2_LEN,
8065e111ed8SAndrew Rybchenko MC_CMD_NVRAM_READ_OUT_LENMAX);
8075e111ed8SAndrew Rybchenko efx_rc_t rc;
8085e111ed8SAndrew Rybchenko
8095e111ed8SAndrew Rybchenko if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) {
8105e111ed8SAndrew Rybchenko rc = EINVAL;
8115e111ed8SAndrew Rybchenko goto fail1;
8125e111ed8SAndrew Rybchenko }
8135e111ed8SAndrew Rybchenko
8145e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_NVRAM_READ;
8155e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
8165e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_NVRAM_READ_IN_V2_LEN;
8175e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
8185e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX;
8195e111ed8SAndrew Rybchenko
8205e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_TYPE, partn);
8215e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_OFFSET, offset);
8225e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_LENGTH, size);
8235e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_MODE, mode);
8245e111ed8SAndrew Rybchenko
8255e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req);
8265e111ed8SAndrew Rybchenko
8275e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
8285e111ed8SAndrew Rybchenko rc = req.emr_rc;
8295e111ed8SAndrew Rybchenko goto fail1;
8305e111ed8SAndrew Rybchenko }
8315e111ed8SAndrew Rybchenko
8325e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) {
8335e111ed8SAndrew Rybchenko rc = EMSGSIZE;
8345e111ed8SAndrew Rybchenko goto fail2;
8355e111ed8SAndrew Rybchenko }
8365e111ed8SAndrew Rybchenko
8375e111ed8SAndrew Rybchenko memcpy(data,
8385e111ed8SAndrew Rybchenko MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
8395e111ed8SAndrew Rybchenko size);
8405e111ed8SAndrew Rybchenko
8415e111ed8SAndrew Rybchenko return (0);
8425e111ed8SAndrew Rybchenko
8435e111ed8SAndrew Rybchenko fail2:
8445e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
8455e111ed8SAndrew Rybchenko fail1:
8465e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
8475e111ed8SAndrew Rybchenko
8485e111ed8SAndrew Rybchenko return (rc);
8495e111ed8SAndrew Rybchenko }
8505e111ed8SAndrew Rybchenko
8515e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_nvram_erase(__in efx_nic_t * enp,__in uint32_t partn,__in uint32_t offset,__in size_t size)8525e111ed8SAndrew Rybchenko efx_mcdi_nvram_erase(
8535e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
8545e111ed8SAndrew Rybchenko __in uint32_t partn,
8555e111ed8SAndrew Rybchenko __in uint32_t offset,
8565e111ed8SAndrew Rybchenko __in size_t size)
8575e111ed8SAndrew Rybchenko {
8585e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
8595e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_ERASE_IN_LEN,
8605e111ed8SAndrew Rybchenko MC_CMD_NVRAM_ERASE_OUT_LEN);
8615e111ed8SAndrew Rybchenko efx_rc_t rc;
8625e111ed8SAndrew Rybchenko
8635e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_NVRAM_ERASE;
8645e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
8655e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
8665e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
8675e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN;
8685e111ed8SAndrew Rybchenko
8695e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
8705e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
8715e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
8725e111ed8SAndrew Rybchenko
8735e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req);
8745e111ed8SAndrew Rybchenko
8755e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
8765e111ed8SAndrew Rybchenko rc = req.emr_rc;
8775e111ed8SAndrew Rybchenko goto fail1;
8785e111ed8SAndrew Rybchenko }
8795e111ed8SAndrew Rybchenko
8805e111ed8SAndrew Rybchenko return (0);
8815e111ed8SAndrew Rybchenko
8825e111ed8SAndrew Rybchenko fail1:
8835e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
8845e111ed8SAndrew Rybchenko
8855e111ed8SAndrew Rybchenko return (rc);
8865e111ed8SAndrew Rybchenko }
8875e111ed8SAndrew Rybchenko
8885e111ed8SAndrew Rybchenko /*
8895e111ed8SAndrew Rybchenko * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both
8905e111ed8SAndrew Rybchenko * Sienna and EF10 based boards. However EF10 based boards support the use
8915e111ed8SAndrew Rybchenko * of this command with payloads up to the maximum MCDI V2 payload length.
8925e111ed8SAndrew Rybchenko */
8935e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_nvram_write(__in efx_nic_t * enp,__in uint32_t partn,__in uint32_t offset,__in_bcount (size)caddr_t data,__in size_t size)8945e111ed8SAndrew Rybchenko efx_mcdi_nvram_write(
8955e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
8965e111ed8SAndrew Rybchenko __in uint32_t partn,
8975e111ed8SAndrew Rybchenko __in uint32_t offset,
8985e111ed8SAndrew Rybchenko __in_bcount(size) caddr_t data,
8995e111ed8SAndrew Rybchenko __in size_t size)
9005e111ed8SAndrew Rybchenko {
9015e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
9025e111ed8SAndrew Rybchenko uint8_t *payload;
9035e111ed8SAndrew Rybchenko efx_rc_t rc;
9045e111ed8SAndrew Rybchenko size_t max_data_size;
9055e111ed8SAndrew Rybchenko size_t payload_len = enp->en_nic_cfg.enc_mcdi_max_payload_length;
9065e111ed8SAndrew Rybchenko
9075e111ed8SAndrew Rybchenko max_data_size = payload_len - MC_CMD_NVRAM_WRITE_IN_LEN(0);
9085e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(payload_len, >, 0);
9095e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(max_data_size, <, payload_len);
9105e111ed8SAndrew Rybchenko
9115e111ed8SAndrew Rybchenko if (size > max_data_size) {
9125e111ed8SAndrew Rybchenko rc = EINVAL;
9135e111ed8SAndrew Rybchenko goto fail1;
9145e111ed8SAndrew Rybchenko }
9155e111ed8SAndrew Rybchenko
9165e111ed8SAndrew Rybchenko EFSYS_KMEM_ALLOC(enp->en_esip, payload_len, payload);
9175e111ed8SAndrew Rybchenko if (payload == NULL) {
9185e111ed8SAndrew Rybchenko rc = ENOMEM;
9195e111ed8SAndrew Rybchenko goto fail2;
9205e111ed8SAndrew Rybchenko }
9215e111ed8SAndrew Rybchenko
9225e111ed8SAndrew Rybchenko (void) memset(payload, 0, payload_len);
9235e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_NVRAM_WRITE;
9245e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
9255e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size);
9265e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
9275e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN;
9285e111ed8SAndrew Rybchenko
9295e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
9305e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
9315e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size);
9325e111ed8SAndrew Rybchenko
9335e111ed8SAndrew Rybchenko memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
9345e111ed8SAndrew Rybchenko data, size);
9355e111ed8SAndrew Rybchenko
9365e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req);
9375e111ed8SAndrew Rybchenko
9385e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
9395e111ed8SAndrew Rybchenko rc = req.emr_rc;
9405e111ed8SAndrew Rybchenko goto fail3;
9415e111ed8SAndrew Rybchenko }
9425e111ed8SAndrew Rybchenko
9435e111ed8SAndrew Rybchenko EFSYS_KMEM_FREE(enp->en_esip, payload_len, payload);
9445e111ed8SAndrew Rybchenko
9455e111ed8SAndrew Rybchenko return (0);
9465e111ed8SAndrew Rybchenko
9475e111ed8SAndrew Rybchenko fail3:
9485e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3);
9495e111ed8SAndrew Rybchenko EFSYS_KMEM_FREE(enp->en_esip, payload_len, payload);
9505e111ed8SAndrew Rybchenko fail2:
9515e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
9525e111ed8SAndrew Rybchenko fail1:
9535e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
9545e111ed8SAndrew Rybchenko
9555e111ed8SAndrew Rybchenko return (rc);
9565e111ed8SAndrew Rybchenko }
9575e111ed8SAndrew Rybchenko
9585e111ed8SAndrew Rybchenko
9595e111ed8SAndrew Rybchenko /*
9605e111ed8SAndrew Rybchenko * MC_CMD_NVRAM_UPDATE_FINISH_V2 must be used to support firmware-verified
9615e111ed8SAndrew Rybchenko * NVRAM updates. Older firmware will ignore the flags field in the request.
9625e111ed8SAndrew Rybchenko */
9635e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_nvram_update_finish(__in efx_nic_t * enp,__in uint32_t partn,__in boolean_t reboot,__in uint32_t flags,__out_opt uint32_t * verify_resultp)9645e111ed8SAndrew Rybchenko efx_mcdi_nvram_update_finish(
9655e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
9665e111ed8SAndrew Rybchenko __in uint32_t partn,
9675e111ed8SAndrew Rybchenko __in boolean_t reboot,
9685e111ed8SAndrew Rybchenko __in uint32_t flags,
9695e111ed8SAndrew Rybchenko __out_opt uint32_t *verify_resultp)
9705e111ed8SAndrew Rybchenko {
9715e111ed8SAndrew Rybchenko const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
9725e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
9735e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN,
9745e111ed8SAndrew Rybchenko MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN);
9755e111ed8SAndrew Rybchenko uint32_t verify_result = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN;
9765e111ed8SAndrew Rybchenko efx_rc_t rc = 0;
9775e111ed8SAndrew Rybchenko
9785e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
9795e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
9805e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN;
9815e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
9825e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN;
9835e111ed8SAndrew Rybchenko
9845e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_TYPE, partn);
9855e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_REBOOT, reboot);
9865e111ed8SAndrew Rybchenko
9875e111ed8SAndrew Rybchenko if (!encp->enc_nvram_update_poll_verify_result_supported) {
9885e111ed8SAndrew Rybchenko flags &= ~EFX_NVRAM_UPDATE_FLAGS_BACKGROUND;
9895e111ed8SAndrew Rybchenko flags &= ~EFX_NVRAM_UPDATE_FLAGS_POLL;
9905e111ed8SAndrew Rybchenko }
9915e111ed8SAndrew Rybchenko
9925e111ed8SAndrew Rybchenko MCDI_IN_POPULATE_DWORD_3(req, NVRAM_UPDATE_FINISH_V2_IN_FLAGS,
9935e111ed8SAndrew Rybchenko NVRAM_UPDATE_FINISH_V2_IN_FLAG_REPORT_VERIFY_RESULT,
9945e111ed8SAndrew Rybchenko 1,
9955e111ed8SAndrew Rybchenko NVRAM_UPDATE_FINISH_V2_IN_FLAG_RUN_IN_BACKGROUND,
9965e111ed8SAndrew Rybchenko (flags & EFX_NVRAM_UPDATE_FLAGS_BACKGROUND) ? 1 : 0,
9975e111ed8SAndrew Rybchenko NVRAM_UPDATE_FINISH_V2_IN_FLAG_POLL_VERIFY_RESULT,
9985e111ed8SAndrew Rybchenko (flags & EFX_NVRAM_UPDATE_FLAGS_POLL) ? 1 : 0
9995e111ed8SAndrew Rybchenko );
10005e111ed8SAndrew Rybchenko
10015e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req);
10025e111ed8SAndrew Rybchenko
10035e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
10045e111ed8SAndrew Rybchenko rc = req.emr_rc;
10055e111ed8SAndrew Rybchenko goto fail1;
10065e111ed8SAndrew Rybchenko }
10075e111ed8SAndrew Rybchenko
10085e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN) {
10095e111ed8SAndrew Rybchenko verify_result = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN;
10105e111ed8SAndrew Rybchenko if (encp->enc_nvram_update_verify_result_supported) {
10115e111ed8SAndrew Rybchenko /* Result of update verification is missing */
10125e111ed8SAndrew Rybchenko rc = EMSGSIZE;
10135e111ed8SAndrew Rybchenko goto fail2;
10145e111ed8SAndrew Rybchenko }
10155e111ed8SAndrew Rybchenko } else {
10165e111ed8SAndrew Rybchenko verify_result =
10175e111ed8SAndrew Rybchenko MCDI_OUT_DWORD(req, NVRAM_UPDATE_FINISH_V2_OUT_RESULT_CODE);
10185e111ed8SAndrew Rybchenko }
10195e111ed8SAndrew Rybchenko
10205e111ed8SAndrew Rybchenko if (encp->enc_nvram_update_verify_result_supported) {
10215e111ed8SAndrew Rybchenko if ((verify_result != MC_CMD_NVRAM_VERIFY_RC_SUCCESS) &&
10225e111ed8SAndrew Rybchenko (verify_result != MC_CMD_NVRAM_VERIFY_RC_PENDING)) {
10235e111ed8SAndrew Rybchenko /* Update verification failed */
10245e111ed8SAndrew Rybchenko rc = EINVAL;
10255e111ed8SAndrew Rybchenko goto fail3;
10265e111ed8SAndrew Rybchenko }
10275e111ed8SAndrew Rybchenko }
10285e111ed8SAndrew Rybchenko
10295e111ed8SAndrew Rybchenko if (verify_resultp != NULL)
10305e111ed8SAndrew Rybchenko *verify_resultp = verify_result;
10315e111ed8SAndrew Rybchenko
10325e111ed8SAndrew Rybchenko return (0);
10335e111ed8SAndrew Rybchenko
10345e111ed8SAndrew Rybchenko fail3:
10355e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3);
10365e111ed8SAndrew Rybchenko fail2:
10375e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
10385e111ed8SAndrew Rybchenko fail1:
10395e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
10405e111ed8SAndrew Rybchenko
10415e111ed8SAndrew Rybchenko /* Always report verification result */
10425e111ed8SAndrew Rybchenko if (verify_resultp != NULL)
10435e111ed8SAndrew Rybchenko *verify_resultp = verify_result;
10445e111ed8SAndrew Rybchenko
10455e111ed8SAndrew Rybchenko return (rc);
10465e111ed8SAndrew Rybchenko }
10475e111ed8SAndrew Rybchenko
10485e111ed8SAndrew Rybchenko #if EFSYS_OPT_DIAG
10495e111ed8SAndrew Rybchenko
10505e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_nvram_test(__in efx_nic_t * enp,__in uint32_t partn)10515e111ed8SAndrew Rybchenko efx_mcdi_nvram_test(
10525e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
10535e111ed8SAndrew Rybchenko __in uint32_t partn)
10545e111ed8SAndrew Rybchenko {
10555e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
10565e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_TEST_IN_LEN,
10575e111ed8SAndrew Rybchenko MC_CMD_NVRAM_TEST_OUT_LEN);
10585e111ed8SAndrew Rybchenko int result;
10595e111ed8SAndrew Rybchenko efx_rc_t rc;
10605e111ed8SAndrew Rybchenko
10615e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_NVRAM_TEST;
10625e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
10635e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
10645e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
10655e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
10665e111ed8SAndrew Rybchenko
10675e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn);
10685e111ed8SAndrew Rybchenko
10695e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req);
10705e111ed8SAndrew Rybchenko
10715e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
10725e111ed8SAndrew Rybchenko rc = req.emr_rc;
10735e111ed8SAndrew Rybchenko goto fail1;
10745e111ed8SAndrew Rybchenko }
10755e111ed8SAndrew Rybchenko
10765e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
10775e111ed8SAndrew Rybchenko rc = EMSGSIZE;
10785e111ed8SAndrew Rybchenko goto fail2;
10795e111ed8SAndrew Rybchenko }
10805e111ed8SAndrew Rybchenko
10815e111ed8SAndrew Rybchenko result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
10825e111ed8SAndrew Rybchenko if (result == MC_CMD_NVRAM_TEST_FAIL) {
10835e111ed8SAndrew Rybchenko
10845e111ed8SAndrew Rybchenko EFSYS_PROBE1(nvram_test_failure, int, partn);
10855e111ed8SAndrew Rybchenko
10865e111ed8SAndrew Rybchenko rc = (EINVAL);
10875e111ed8SAndrew Rybchenko goto fail3;
10885e111ed8SAndrew Rybchenko }
10895e111ed8SAndrew Rybchenko
10905e111ed8SAndrew Rybchenko return (0);
10915e111ed8SAndrew Rybchenko
10925e111ed8SAndrew Rybchenko fail3:
10935e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3);
10945e111ed8SAndrew Rybchenko fail2:
10955e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
10965e111ed8SAndrew Rybchenko fail1:
10975e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
10985e111ed8SAndrew Rybchenko
10995e111ed8SAndrew Rybchenko return (rc);
11005e111ed8SAndrew Rybchenko }
11015e111ed8SAndrew Rybchenko
11025e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_DIAG */
11035e111ed8SAndrew Rybchenko
11045e111ed8SAndrew Rybchenko
11055e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */
1106