15e111ed8SAndrew Rybchenko /* SPDX-License-Identifier: BSD-3-Clause
25e111ed8SAndrew Rybchenko *
3672386c1SAndrew Rybchenko * Copyright(c) 2019-2021 Xilinx, Inc.
45e111ed8SAndrew Rybchenko * Copyright(c) 2008-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_MCDI
115e111ed8SAndrew Rybchenko
125e111ed8SAndrew Rybchenko /*
135e111ed8SAndrew Rybchenko * There are three versions of the MCDI interface:
145e111ed8SAndrew Rybchenko * - MCDIv0: Siena BootROM. Transport uses MCDIv1 headers.
155e111ed8SAndrew Rybchenko * - MCDIv1: Siena firmware and Huntington BootROM.
165e111ed8SAndrew Rybchenko * - MCDIv2: EF10 firmware (Huntington/Medford) and Medford BootROM.
175e111ed8SAndrew Rybchenko * Transport uses MCDIv2 headers.
185e111ed8SAndrew Rybchenko *
195e111ed8SAndrew Rybchenko * MCDIv2 Header NOT_EPOCH flag
205e111ed8SAndrew Rybchenko * ----------------------------
215e111ed8SAndrew Rybchenko * A new epoch begins at initial startup or after an MC reboot, and defines when
225e111ed8SAndrew Rybchenko * the MC should reject stale MCDI requests.
235e111ed8SAndrew Rybchenko *
245e111ed8SAndrew Rybchenko * The first MCDI request sent by the host should contain NOT_EPOCH=0, and all
255e111ed8SAndrew Rybchenko * subsequent requests (until the next MC reboot) should contain NOT_EPOCH=1.
265e111ed8SAndrew Rybchenko *
275e111ed8SAndrew Rybchenko * After rebooting the MC will fail all requests with NOT_EPOCH=1 by writing a
285e111ed8SAndrew Rybchenko * response with ERROR=1 and DATALEN=0 until a request is seen with NOT_EPOCH=0.
295e111ed8SAndrew Rybchenko */
305e111ed8SAndrew Rybchenko
315e111ed8SAndrew Rybchenko
325e111ed8SAndrew Rybchenko
335e111ed8SAndrew Rybchenko #if EFSYS_OPT_SIENA
345e111ed8SAndrew Rybchenko
355e111ed8SAndrew Rybchenko static const efx_mcdi_ops_t __efx_mcdi_siena_ops = {
365e111ed8SAndrew Rybchenko siena_mcdi_init, /* emco_init */
375e111ed8SAndrew Rybchenko siena_mcdi_send_request, /* emco_send_request */
385e111ed8SAndrew Rybchenko siena_mcdi_poll_reboot, /* emco_poll_reboot */
395e111ed8SAndrew Rybchenko siena_mcdi_poll_response, /* emco_poll_response */
405e111ed8SAndrew Rybchenko siena_mcdi_read_response, /* emco_read_response */
415e111ed8SAndrew Rybchenko siena_mcdi_fini, /* emco_fini */
425e111ed8SAndrew Rybchenko siena_mcdi_feature_supported, /* emco_feature_supported */
435e111ed8SAndrew Rybchenko siena_mcdi_get_timeout, /* emco_get_timeout */
445e111ed8SAndrew Rybchenko };
455e111ed8SAndrew Rybchenko
465e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */
475e111ed8SAndrew Rybchenko
485e111ed8SAndrew Rybchenko #if EFX_OPTS_EF10()
495e111ed8SAndrew Rybchenko
505e111ed8SAndrew Rybchenko static const efx_mcdi_ops_t __efx_mcdi_ef10_ops = {
515e111ed8SAndrew Rybchenko ef10_mcdi_init, /* emco_init */
525e111ed8SAndrew Rybchenko ef10_mcdi_send_request, /* emco_send_request */
535e111ed8SAndrew Rybchenko ef10_mcdi_poll_reboot, /* emco_poll_reboot */
545e111ed8SAndrew Rybchenko ef10_mcdi_poll_response, /* emco_poll_response */
555e111ed8SAndrew Rybchenko ef10_mcdi_read_response, /* emco_read_response */
565e111ed8SAndrew Rybchenko ef10_mcdi_fini, /* emco_fini */
575e111ed8SAndrew Rybchenko ef10_mcdi_feature_supported, /* emco_feature_supported */
585e111ed8SAndrew Rybchenko ef10_mcdi_get_timeout, /* emco_get_timeout */
595e111ed8SAndrew Rybchenko };
605e111ed8SAndrew Rybchenko
615e111ed8SAndrew Rybchenko #endif /* EFX_OPTS_EF10() */
625e111ed8SAndrew Rybchenko
639b5b182dSAndrew Rybchenko #if EFSYS_OPT_RIVERHEAD
649b5b182dSAndrew Rybchenko
659b5b182dSAndrew Rybchenko static const efx_mcdi_ops_t __efx_mcdi_rhead_ops = {
669b5b182dSAndrew Rybchenko ef10_mcdi_init, /* emco_init */
679b5b182dSAndrew Rybchenko ef10_mcdi_send_request, /* emco_send_request */
689b5b182dSAndrew Rybchenko ef10_mcdi_poll_reboot, /* emco_poll_reboot */
699b5b182dSAndrew Rybchenko ef10_mcdi_poll_response, /* emco_poll_response */
709b5b182dSAndrew Rybchenko ef10_mcdi_read_response, /* emco_read_response */
719b5b182dSAndrew Rybchenko ef10_mcdi_fini, /* emco_fini */
729b5b182dSAndrew Rybchenko ef10_mcdi_feature_supported, /* emco_feature_supported */
739b5b182dSAndrew Rybchenko ef10_mcdi_get_timeout, /* emco_get_timeout */
749b5b182dSAndrew Rybchenko };
759b5b182dSAndrew Rybchenko
769b5b182dSAndrew Rybchenko #endif /* EFSYS_OPT_RIVERHEAD */
779b5b182dSAndrew Rybchenko
785e111ed8SAndrew Rybchenko
795e111ed8SAndrew Rybchenko
805e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_init(__in efx_nic_t * enp,__in const efx_mcdi_transport_t * emtp)815e111ed8SAndrew Rybchenko efx_mcdi_init(
825e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
835e111ed8SAndrew Rybchenko __in const efx_mcdi_transport_t *emtp)
845e111ed8SAndrew Rybchenko {
855e111ed8SAndrew Rybchenko const efx_mcdi_ops_t *emcop;
865e111ed8SAndrew Rybchenko efx_rc_t rc;
875e111ed8SAndrew Rybchenko
885e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
895e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
905e111ed8SAndrew Rybchenko
915e111ed8SAndrew Rybchenko switch (enp->en_family) {
925e111ed8SAndrew Rybchenko #if EFSYS_OPT_SIENA
935e111ed8SAndrew Rybchenko case EFX_FAMILY_SIENA:
945e111ed8SAndrew Rybchenko emcop = &__efx_mcdi_siena_ops;
955e111ed8SAndrew Rybchenko break;
965e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */
975e111ed8SAndrew Rybchenko
985e111ed8SAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON
995e111ed8SAndrew Rybchenko case EFX_FAMILY_HUNTINGTON:
1005e111ed8SAndrew Rybchenko emcop = &__efx_mcdi_ef10_ops;
1015e111ed8SAndrew Rybchenko break;
1025e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_HUNTINGTON */
1035e111ed8SAndrew Rybchenko
1045e111ed8SAndrew Rybchenko #if EFSYS_OPT_MEDFORD
1055e111ed8SAndrew Rybchenko case EFX_FAMILY_MEDFORD:
1065e111ed8SAndrew Rybchenko emcop = &__efx_mcdi_ef10_ops;
1075e111ed8SAndrew Rybchenko break;
1085e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD */
1095e111ed8SAndrew Rybchenko
1105e111ed8SAndrew Rybchenko #if EFSYS_OPT_MEDFORD2
1115e111ed8SAndrew Rybchenko case EFX_FAMILY_MEDFORD2:
1125e111ed8SAndrew Rybchenko emcop = &__efx_mcdi_ef10_ops;
1135e111ed8SAndrew Rybchenko break;
1145e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD2 */
1155e111ed8SAndrew Rybchenko
1169b5b182dSAndrew Rybchenko #if EFSYS_OPT_RIVERHEAD
1179b5b182dSAndrew Rybchenko case EFX_FAMILY_RIVERHEAD:
1189b5b182dSAndrew Rybchenko emcop = &__efx_mcdi_rhead_ops;
1199b5b182dSAndrew Rybchenko break;
1209b5b182dSAndrew Rybchenko #endif /* EFSYS_OPT_RIVERHEAD */
1219b5b182dSAndrew Rybchenko
1225e111ed8SAndrew Rybchenko default:
1235e111ed8SAndrew Rybchenko EFSYS_ASSERT(0);
1245e111ed8SAndrew Rybchenko rc = ENOTSUP;
1255e111ed8SAndrew Rybchenko goto fail1;
1265e111ed8SAndrew Rybchenko }
1275e111ed8SAndrew Rybchenko
1285e111ed8SAndrew Rybchenko if (enp->en_features & EFX_FEATURE_MCDI_DMA) {
1295e111ed8SAndrew Rybchenko /* MCDI requires a DMA buffer in host memory */
1305e111ed8SAndrew Rybchenko if ((emtp == NULL) || (emtp->emt_dma_mem) == NULL) {
1315e111ed8SAndrew Rybchenko rc = EINVAL;
1325e111ed8SAndrew Rybchenko goto fail2;
1335e111ed8SAndrew Rybchenko }
1345e111ed8SAndrew Rybchenko }
1355e111ed8SAndrew Rybchenko enp->en_mcdi.em_emtp = emtp;
1365e111ed8SAndrew Rybchenko
1375e111ed8SAndrew Rybchenko if (emcop != NULL && emcop->emco_init != NULL) {
1385e111ed8SAndrew Rybchenko if ((rc = emcop->emco_init(enp, emtp)) != 0)
1395e111ed8SAndrew Rybchenko goto fail3;
1405e111ed8SAndrew Rybchenko }
1415e111ed8SAndrew Rybchenko
1425e111ed8SAndrew Rybchenko enp->en_mcdi.em_emcop = emcop;
1435e111ed8SAndrew Rybchenko enp->en_mod_flags |= EFX_MOD_MCDI;
1445e111ed8SAndrew Rybchenko
1455e111ed8SAndrew Rybchenko return (0);
1465e111ed8SAndrew Rybchenko
1475e111ed8SAndrew Rybchenko fail3:
1485e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3);
1495e111ed8SAndrew Rybchenko fail2:
1505e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
1515e111ed8SAndrew Rybchenko fail1:
1525e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
1535e111ed8SAndrew Rybchenko
1545e111ed8SAndrew Rybchenko enp->en_mcdi.em_emcop = NULL;
1555e111ed8SAndrew Rybchenko enp->en_mcdi.em_emtp = NULL;
1565e111ed8SAndrew Rybchenko enp->en_mod_flags &= ~EFX_MOD_MCDI;
1575e111ed8SAndrew Rybchenko
1585e111ed8SAndrew Rybchenko return (rc);
1595e111ed8SAndrew Rybchenko }
1605e111ed8SAndrew Rybchenko
1615e111ed8SAndrew Rybchenko void
efx_mcdi_fini(__in efx_nic_t * enp)1625e111ed8SAndrew Rybchenko efx_mcdi_fini(
1635e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
1645e111ed8SAndrew Rybchenko {
1655e111ed8SAndrew Rybchenko efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
1665e111ed8SAndrew Rybchenko const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1675e111ed8SAndrew Rybchenko
1685e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1695e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, ==, EFX_MOD_MCDI);
1705e111ed8SAndrew Rybchenko
1715e111ed8SAndrew Rybchenko if (emcop != NULL && emcop->emco_fini != NULL)
1725e111ed8SAndrew Rybchenko emcop->emco_fini(enp);
1735e111ed8SAndrew Rybchenko
1745e111ed8SAndrew Rybchenko emip->emi_port = 0;
1755e111ed8SAndrew Rybchenko emip->emi_aborted = 0;
1765e111ed8SAndrew Rybchenko
1775e111ed8SAndrew Rybchenko enp->en_mcdi.em_emcop = NULL;
1785e111ed8SAndrew Rybchenko enp->en_mod_flags &= ~EFX_MOD_MCDI;
1795e111ed8SAndrew Rybchenko }
1805e111ed8SAndrew Rybchenko
1815e111ed8SAndrew Rybchenko void
efx_mcdi_new_epoch(__in efx_nic_t * enp)1825e111ed8SAndrew Rybchenko efx_mcdi_new_epoch(
1835e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
1845e111ed8SAndrew Rybchenko {
1855e111ed8SAndrew Rybchenko efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
1865e111ed8SAndrew Rybchenko efsys_lock_state_t state;
1875e111ed8SAndrew Rybchenko
1885e111ed8SAndrew Rybchenko /* Start a new epoch (allow fresh MCDI requests to succeed) */
1895e111ed8SAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state);
1905e111ed8SAndrew Rybchenko emip->emi_new_epoch = B_TRUE;
1915e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state);
1925e111ed8SAndrew Rybchenko }
1935e111ed8SAndrew Rybchenko
1945e111ed8SAndrew Rybchenko static void
efx_mcdi_send_request(__in efx_nic_t * enp,__in void * hdrp,__in size_t hdr_len,__in void * sdup,__in size_t sdu_len)1955e111ed8SAndrew Rybchenko efx_mcdi_send_request(
1965e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
1975e111ed8SAndrew Rybchenko __in void *hdrp,
1985e111ed8SAndrew Rybchenko __in size_t hdr_len,
1995e111ed8SAndrew Rybchenko __in void *sdup,
2005e111ed8SAndrew Rybchenko __in size_t sdu_len)
2015e111ed8SAndrew Rybchenko {
2025e111ed8SAndrew Rybchenko const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
2035e111ed8SAndrew Rybchenko
2045e111ed8SAndrew Rybchenko emcop->emco_send_request(enp, hdrp, hdr_len, sdup, sdu_len);
2055e111ed8SAndrew Rybchenko }
2065e111ed8SAndrew Rybchenko
2075e111ed8SAndrew Rybchenko static efx_rc_t
efx_mcdi_poll_reboot(__in efx_nic_t * enp)2085e111ed8SAndrew Rybchenko efx_mcdi_poll_reboot(
2095e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
2105e111ed8SAndrew Rybchenko {
2115e111ed8SAndrew Rybchenko const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
2125e111ed8SAndrew Rybchenko efx_rc_t rc;
2135e111ed8SAndrew Rybchenko
2145e111ed8SAndrew Rybchenko rc = emcop->emco_poll_reboot(enp);
2155e111ed8SAndrew Rybchenko return (rc);
2165e111ed8SAndrew Rybchenko }
2175e111ed8SAndrew Rybchenko
2185e111ed8SAndrew Rybchenko static boolean_t
efx_mcdi_poll_response(__in efx_nic_t * enp)2195e111ed8SAndrew Rybchenko efx_mcdi_poll_response(
2205e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
2215e111ed8SAndrew Rybchenko {
2225e111ed8SAndrew Rybchenko const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
2235e111ed8SAndrew Rybchenko boolean_t available;
2245e111ed8SAndrew Rybchenko
2255e111ed8SAndrew Rybchenko available = emcop->emco_poll_response(enp);
2265e111ed8SAndrew Rybchenko return (available);
2275e111ed8SAndrew Rybchenko }
2285e111ed8SAndrew Rybchenko
2295e111ed8SAndrew Rybchenko static void
efx_mcdi_read_response(__in efx_nic_t * enp,__out void * bufferp,__in size_t offset,__in size_t length)2305e111ed8SAndrew Rybchenko efx_mcdi_read_response(
2315e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
2325e111ed8SAndrew Rybchenko __out void *bufferp,
2335e111ed8SAndrew Rybchenko __in size_t offset,
2345e111ed8SAndrew Rybchenko __in size_t length)
2355e111ed8SAndrew Rybchenko {
2365e111ed8SAndrew Rybchenko const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
2375e111ed8SAndrew Rybchenko
2385e111ed8SAndrew Rybchenko emcop->emco_read_response(enp, bufferp, offset, length);
2395e111ed8SAndrew Rybchenko }
2405e111ed8SAndrew Rybchenko
2415e111ed8SAndrew Rybchenko void
efx_mcdi_request_start(__in efx_nic_t * enp,__in efx_mcdi_req_t * emrp,__in boolean_t ev_cpl)2425e111ed8SAndrew Rybchenko efx_mcdi_request_start(
2435e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
2445e111ed8SAndrew Rybchenko __in efx_mcdi_req_t *emrp,
2455e111ed8SAndrew Rybchenko __in boolean_t ev_cpl)
2465e111ed8SAndrew Rybchenko {
2475e111ed8SAndrew Rybchenko #if EFSYS_OPT_MCDI_LOGGING
2485e111ed8SAndrew Rybchenko const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
2495e111ed8SAndrew Rybchenko #endif
2505e111ed8SAndrew Rybchenko efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
2515e111ed8SAndrew Rybchenko efx_dword_t hdr[2];
2525e111ed8SAndrew Rybchenko size_t hdr_len;
2535e111ed8SAndrew Rybchenko unsigned int max_version;
2545e111ed8SAndrew Rybchenko unsigned int seq;
2555e111ed8SAndrew Rybchenko unsigned int xflags;
2565e111ed8SAndrew Rybchenko boolean_t new_epoch;
2575e111ed8SAndrew Rybchenko efsys_lock_state_t state;
2585e111ed8SAndrew Rybchenko
2595e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
2605e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
2615e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
2625e111ed8SAndrew Rybchenko
2635e111ed8SAndrew Rybchenko /*
2645e111ed8SAndrew Rybchenko * efx_mcdi_request_start() is naturally serialised against both
2655e111ed8SAndrew Rybchenko * efx_mcdi_request_poll() and efx_mcdi_ev_cpl()/efx_mcdi_ev_death(),
2665e111ed8SAndrew Rybchenko * by virtue of there only being one outstanding MCDI request.
2675e111ed8SAndrew Rybchenko * Unfortunately, upper layers may also call efx_mcdi_request_abort()
2685e111ed8SAndrew Rybchenko * at any time, to timeout a pending mcdi request, That request may
2695e111ed8SAndrew Rybchenko * then subsequently complete, meaning efx_mcdi_ev_cpl() or
2705e111ed8SAndrew Rybchenko * efx_mcdi_ev_death() may end up running in parallel with
2715e111ed8SAndrew Rybchenko * efx_mcdi_request_start(). This race is handled by ensuring that
2725e111ed8SAndrew Rybchenko * %emi_pending_req, %emi_ev_cpl and %emi_seq are protected by the
2735e111ed8SAndrew Rybchenko * en_eslp lock.
2745e111ed8SAndrew Rybchenko */
2755e111ed8SAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state);
2765e111ed8SAndrew Rybchenko EFSYS_ASSERT(emip->emi_pending_req == NULL);
2775e111ed8SAndrew Rybchenko emip->emi_pending_req = emrp;
2785e111ed8SAndrew Rybchenko emip->emi_ev_cpl = ev_cpl;
2795e111ed8SAndrew Rybchenko emip->emi_poll_cnt = 0;
2805e111ed8SAndrew Rybchenko seq = emip->emi_seq++ & EFX_MASK32(MCDI_HEADER_SEQ);
2815e111ed8SAndrew Rybchenko new_epoch = emip->emi_new_epoch;
2825e111ed8SAndrew Rybchenko max_version = emip->emi_max_version;
2835e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state);
2845e111ed8SAndrew Rybchenko
2855e111ed8SAndrew Rybchenko xflags = 0;
2865e111ed8SAndrew Rybchenko if (ev_cpl)
2875e111ed8SAndrew Rybchenko xflags |= MCDI_HEADER_XFLAGS_EVREQ;
2885e111ed8SAndrew Rybchenko
2895e111ed8SAndrew Rybchenko /*
2905e111ed8SAndrew Rybchenko * Huntington firmware supports MCDIv2, but the Huntington BootROM only
2915e111ed8SAndrew Rybchenko * supports MCDIv1. Use MCDIv1 headers for MCDIv1 commands where
2925e111ed8SAndrew Rybchenko * possible to support this.
2935e111ed8SAndrew Rybchenko */
2945e111ed8SAndrew Rybchenko if ((max_version >= 2) &&
2955e111ed8SAndrew Rybchenko ((emrp->emr_cmd > MC_CMD_CMD_SPACE_ESCAPE_7) ||
2965e111ed8SAndrew Rybchenko (emrp->emr_in_length > MCDI_CTL_SDU_LEN_MAX_V1) ||
2975e111ed8SAndrew Rybchenko (emrp->emr_out_length > MCDI_CTL_SDU_LEN_MAX_V1))) {
2985e111ed8SAndrew Rybchenko /* Construct MCDI v2 header */
2995e111ed8SAndrew Rybchenko hdr_len = sizeof (hdr);
3005e111ed8SAndrew Rybchenko EFX_POPULATE_DWORD_8(hdr[0],
3015e111ed8SAndrew Rybchenko MCDI_HEADER_CODE, MC_CMD_V2_EXTN,
3025e111ed8SAndrew Rybchenko MCDI_HEADER_RESYNC, 1,
3035e111ed8SAndrew Rybchenko MCDI_HEADER_DATALEN, 0,
3045e111ed8SAndrew Rybchenko MCDI_HEADER_SEQ, seq,
3055e111ed8SAndrew Rybchenko MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
3065e111ed8SAndrew Rybchenko MCDI_HEADER_ERROR, 0,
3075e111ed8SAndrew Rybchenko MCDI_HEADER_RESPONSE, 0,
3085e111ed8SAndrew Rybchenko MCDI_HEADER_XFLAGS, xflags);
3095e111ed8SAndrew Rybchenko
3105e111ed8SAndrew Rybchenko EFX_POPULATE_DWORD_2(hdr[1],
3115e111ed8SAndrew Rybchenko MC_CMD_V2_EXTN_IN_EXTENDED_CMD, emrp->emr_cmd,
3125e111ed8SAndrew Rybchenko MC_CMD_V2_EXTN_IN_ACTUAL_LEN, emrp->emr_in_length);
3135e111ed8SAndrew Rybchenko } else {
3145e111ed8SAndrew Rybchenko /* Construct MCDI v1 header */
3155e111ed8SAndrew Rybchenko hdr_len = sizeof (hdr[0]);
3165e111ed8SAndrew Rybchenko EFX_POPULATE_DWORD_8(hdr[0],
3175e111ed8SAndrew Rybchenko MCDI_HEADER_CODE, emrp->emr_cmd,
3185e111ed8SAndrew Rybchenko MCDI_HEADER_RESYNC, 1,
3195e111ed8SAndrew Rybchenko MCDI_HEADER_DATALEN, emrp->emr_in_length,
3205e111ed8SAndrew Rybchenko MCDI_HEADER_SEQ, seq,
3215e111ed8SAndrew Rybchenko MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
3225e111ed8SAndrew Rybchenko MCDI_HEADER_ERROR, 0,
3235e111ed8SAndrew Rybchenko MCDI_HEADER_RESPONSE, 0,
3245e111ed8SAndrew Rybchenko MCDI_HEADER_XFLAGS, xflags);
3255e111ed8SAndrew Rybchenko }
3265e111ed8SAndrew Rybchenko
3275e111ed8SAndrew Rybchenko #if EFSYS_OPT_MCDI_LOGGING
3285e111ed8SAndrew Rybchenko if (emtp->emt_logger != NULL) {
3295e111ed8SAndrew Rybchenko emtp->emt_logger(emtp->emt_context, EFX_LOG_MCDI_REQUEST,
3305e111ed8SAndrew Rybchenko &hdr[0], hdr_len,
3315e111ed8SAndrew Rybchenko emrp->emr_in_buf, emrp->emr_in_length);
3325e111ed8SAndrew Rybchenko }
3335e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MCDI_LOGGING */
3345e111ed8SAndrew Rybchenko
3355e111ed8SAndrew Rybchenko efx_mcdi_send_request(enp, &hdr[0], hdr_len,
3365e111ed8SAndrew Rybchenko emrp->emr_in_buf, emrp->emr_in_length);
3375e111ed8SAndrew Rybchenko }
3385e111ed8SAndrew Rybchenko
3395e111ed8SAndrew Rybchenko
3405e111ed8SAndrew Rybchenko static void
efx_mcdi_read_response_header(__in efx_nic_t * enp,__inout efx_mcdi_req_t * emrp)3415e111ed8SAndrew Rybchenko efx_mcdi_read_response_header(
3425e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
3435e111ed8SAndrew Rybchenko __inout efx_mcdi_req_t *emrp)
3445e111ed8SAndrew Rybchenko {
3455e111ed8SAndrew Rybchenko #if EFSYS_OPT_MCDI_LOGGING
3465e111ed8SAndrew Rybchenko const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
3475e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MCDI_LOGGING */
3485e111ed8SAndrew Rybchenko efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
3495e111ed8SAndrew Rybchenko efx_dword_t hdr[2];
3505e111ed8SAndrew Rybchenko unsigned int hdr_len;
3515e111ed8SAndrew Rybchenko unsigned int data_len;
3525e111ed8SAndrew Rybchenko unsigned int seq;
3535e111ed8SAndrew Rybchenko unsigned int cmd;
3545e111ed8SAndrew Rybchenko unsigned int error;
3555e111ed8SAndrew Rybchenko efx_rc_t rc;
3565e111ed8SAndrew Rybchenko
3575e111ed8SAndrew Rybchenko EFSYS_ASSERT(emrp != NULL);
3585e111ed8SAndrew Rybchenko
3595e111ed8SAndrew Rybchenko efx_mcdi_read_response(enp, &hdr[0], 0, sizeof (hdr[0]));
3605e111ed8SAndrew Rybchenko hdr_len = sizeof (hdr[0]);
3615e111ed8SAndrew Rybchenko
3625e111ed8SAndrew Rybchenko cmd = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE);
3635e111ed8SAndrew Rybchenko seq = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_SEQ);
3645e111ed8SAndrew Rybchenko error = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_ERROR);
3655e111ed8SAndrew Rybchenko
3665e111ed8SAndrew Rybchenko if (cmd != MC_CMD_V2_EXTN) {
3675e111ed8SAndrew Rybchenko data_len = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_DATALEN);
3685e111ed8SAndrew Rybchenko } else {
3695e111ed8SAndrew Rybchenko efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1]));
3705e111ed8SAndrew Rybchenko hdr_len += sizeof (hdr[1]);
3715e111ed8SAndrew Rybchenko
3725e111ed8SAndrew Rybchenko cmd = EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_EXTENDED_CMD);
3735e111ed8SAndrew Rybchenko data_len =
3745e111ed8SAndrew Rybchenko EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
3755e111ed8SAndrew Rybchenko }
3765e111ed8SAndrew Rybchenko
3775e111ed8SAndrew Rybchenko if (error && (data_len == 0)) {
3785e111ed8SAndrew Rybchenko /* The MC has rebooted since the request was sent. */
3795e111ed8SAndrew Rybchenko EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
3805e111ed8SAndrew Rybchenko efx_mcdi_poll_reboot(enp);
3815e111ed8SAndrew Rybchenko rc = EIO;
3825e111ed8SAndrew Rybchenko goto fail1;
3835e111ed8SAndrew Rybchenko }
3845e111ed8SAndrew Rybchenko #if EFSYS_OPT_MCDI_PROXY_AUTH_SERVER
3855e111ed8SAndrew Rybchenko if (((cmd != emrp->emr_cmd) && (emrp->emr_cmd != MC_CMD_PROXY_CMD)) ||
3865e111ed8SAndrew Rybchenko #else
3875e111ed8SAndrew Rybchenko if ((cmd != emrp->emr_cmd) ||
3885e111ed8SAndrew Rybchenko #endif
3895e111ed8SAndrew Rybchenko (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
3905e111ed8SAndrew Rybchenko /* Response is for a different request */
3915e111ed8SAndrew Rybchenko rc = EIO;
3925e111ed8SAndrew Rybchenko goto fail2;
3935e111ed8SAndrew Rybchenko }
3945e111ed8SAndrew Rybchenko if (error) {
3955e111ed8SAndrew Rybchenko efx_dword_t err[2];
3965e111ed8SAndrew Rybchenko unsigned int err_len = MIN(data_len, sizeof (err));
3975e111ed8SAndrew Rybchenko int err_code = MC_CMD_ERR_EPROTO;
3985e111ed8SAndrew Rybchenko int err_arg = 0;
3995e111ed8SAndrew Rybchenko
4005e111ed8SAndrew Rybchenko /* Read error code (and arg num for MCDI v2 commands) */
4015e111ed8SAndrew Rybchenko efx_mcdi_read_response(enp, &err, hdr_len, err_len);
4025e111ed8SAndrew Rybchenko
4035e111ed8SAndrew Rybchenko if (err_len >= (MC_CMD_ERR_CODE_OFST + sizeof (efx_dword_t)))
4045e111ed8SAndrew Rybchenko err_code = EFX_DWORD_FIELD(err[0], EFX_DWORD_0);
4055e111ed8SAndrew Rybchenko #ifdef WITH_MCDI_V2
4065e111ed8SAndrew Rybchenko if (err_len >= (MC_CMD_ERR_ARG_OFST + sizeof (efx_dword_t)))
4075e111ed8SAndrew Rybchenko err_arg = EFX_DWORD_FIELD(err[1], EFX_DWORD_0);
4085e111ed8SAndrew Rybchenko #endif
4095e111ed8SAndrew Rybchenko emrp->emr_err_code = err_code;
4105e111ed8SAndrew Rybchenko emrp->emr_err_arg = err_arg;
4115e111ed8SAndrew Rybchenko
4125e111ed8SAndrew Rybchenko #if EFSYS_OPT_MCDI_PROXY_AUTH
4135e111ed8SAndrew Rybchenko if ((err_code == MC_CMD_ERR_PROXY_PENDING) &&
4145e111ed8SAndrew Rybchenko (err_len == sizeof (err))) {
4155e111ed8SAndrew Rybchenko /*
4165e111ed8SAndrew Rybchenko * The MCDI request would normally fail with EPERM, but
4175e111ed8SAndrew Rybchenko * firmware has forwarded it to an authorization agent
4185e111ed8SAndrew Rybchenko * attached to a privileged PF.
4195e111ed8SAndrew Rybchenko *
4205e111ed8SAndrew Rybchenko * Save the authorization request handle. The client
4215e111ed8SAndrew Rybchenko * must wait for a PROXY_RESPONSE event, or timeout.
4225e111ed8SAndrew Rybchenko */
4235e111ed8SAndrew Rybchenko emrp->emr_proxy_handle = err_arg;
4245e111ed8SAndrew Rybchenko }
4255e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
4265e111ed8SAndrew Rybchenko
4275e111ed8SAndrew Rybchenko #if EFSYS_OPT_MCDI_LOGGING
4285e111ed8SAndrew Rybchenko if (emtp->emt_logger != NULL) {
4295e111ed8SAndrew Rybchenko emtp->emt_logger(emtp->emt_context,
4305e111ed8SAndrew Rybchenko EFX_LOG_MCDI_RESPONSE,
4315e111ed8SAndrew Rybchenko &hdr[0], hdr_len,
4325e111ed8SAndrew Rybchenko &err[0], err_len);
4335e111ed8SAndrew Rybchenko }
4345e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MCDI_LOGGING */
4355e111ed8SAndrew Rybchenko
4365e111ed8SAndrew Rybchenko if (!emrp->emr_quiet) {
4375e111ed8SAndrew Rybchenko EFSYS_PROBE3(mcdi_err_arg, int, emrp->emr_cmd,
4385e111ed8SAndrew Rybchenko int, err_code, int, err_arg);
4395e111ed8SAndrew Rybchenko }
4405e111ed8SAndrew Rybchenko
4415e111ed8SAndrew Rybchenko rc = efx_mcdi_request_errcode(err_code);
4425e111ed8SAndrew Rybchenko goto fail3;
4435e111ed8SAndrew Rybchenko }
4445e111ed8SAndrew Rybchenko
4455e111ed8SAndrew Rybchenko emrp->emr_rc = 0;
4465e111ed8SAndrew Rybchenko emrp->emr_out_length_used = data_len;
4475e111ed8SAndrew Rybchenko #if EFSYS_OPT_MCDI_PROXY_AUTH
4485e111ed8SAndrew Rybchenko emrp->emr_proxy_handle = 0;
4495e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
4505e111ed8SAndrew Rybchenko return;
4515e111ed8SAndrew Rybchenko
4525e111ed8SAndrew Rybchenko fail3:
4535e111ed8SAndrew Rybchenko fail2:
4545e111ed8SAndrew Rybchenko fail1:
4555e111ed8SAndrew Rybchenko emrp->emr_rc = rc;
4565e111ed8SAndrew Rybchenko emrp->emr_out_length_used = 0;
4575e111ed8SAndrew Rybchenko }
4585e111ed8SAndrew Rybchenko
4595e111ed8SAndrew Rybchenko static void
efx_mcdi_finish_response(__in efx_nic_t * enp,__in efx_mcdi_req_t * emrp)4605e111ed8SAndrew Rybchenko efx_mcdi_finish_response(
4615e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
4625e111ed8SAndrew Rybchenko __in efx_mcdi_req_t *emrp)
4635e111ed8SAndrew Rybchenko {
4645e111ed8SAndrew Rybchenko #if EFSYS_OPT_MCDI_LOGGING
4655e111ed8SAndrew Rybchenko const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
4665e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MCDI_LOGGING */
4675e111ed8SAndrew Rybchenko efx_dword_t hdr[2];
4685e111ed8SAndrew Rybchenko unsigned int hdr_len;
4695e111ed8SAndrew Rybchenko size_t bytes;
4705e111ed8SAndrew Rybchenko unsigned int resp_off;
4715e111ed8SAndrew Rybchenko #if EFSYS_OPT_MCDI_PROXY_AUTH_SERVER
4725e111ed8SAndrew Rybchenko unsigned int resp_cmd;
4735e111ed8SAndrew Rybchenko boolean_t proxied_cmd_resp = B_FALSE;
4745e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MCDI_PROXY_AUTH_SERVER */
4755e111ed8SAndrew Rybchenko
4765e111ed8SAndrew Rybchenko if (emrp->emr_out_buf == NULL)
4775e111ed8SAndrew Rybchenko return;
4785e111ed8SAndrew Rybchenko
4795e111ed8SAndrew Rybchenko /* Read the command header to detect MCDI response format */
4805e111ed8SAndrew Rybchenko hdr_len = sizeof (hdr[0]);
4815e111ed8SAndrew Rybchenko efx_mcdi_read_response(enp, &hdr[0], 0, hdr_len);
4825e111ed8SAndrew Rybchenko if (EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) {
4835e111ed8SAndrew Rybchenko /*
4845e111ed8SAndrew Rybchenko * Read the actual payload length. The length given in the event
4855e111ed8SAndrew Rybchenko * is only correct for responses with the V1 format.
4865e111ed8SAndrew Rybchenko */
4875e111ed8SAndrew Rybchenko efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1]));
4885e111ed8SAndrew Rybchenko hdr_len += sizeof (hdr[1]);
4895e111ed8SAndrew Rybchenko resp_off = hdr_len;
4905e111ed8SAndrew Rybchenko
4915e111ed8SAndrew Rybchenko emrp->emr_out_length_used = EFX_DWORD_FIELD(hdr[1],
4925e111ed8SAndrew Rybchenko MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
4935e111ed8SAndrew Rybchenko #if EFSYS_OPT_MCDI_PROXY_AUTH_SERVER
4945e111ed8SAndrew Rybchenko /*
4955e111ed8SAndrew Rybchenko * A proxy MCDI command is executed by PF on behalf of
4965e111ed8SAndrew Rybchenko * one of its VFs. The command to be proxied follows
4975e111ed8SAndrew Rybchenko * immediately afterward in the host buffer.
4985e111ed8SAndrew Rybchenko * PROXY_CMD inner call complete response should be copied to
4995e111ed8SAndrew Rybchenko * output buffer so that it can be returned to the requesting
5005e111ed8SAndrew Rybchenko * function in MC_CMD_PROXY_COMPLETE payload.
5015e111ed8SAndrew Rybchenko */
5025e111ed8SAndrew Rybchenko resp_cmd =
5035e111ed8SAndrew Rybchenko EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_EXTENDED_CMD);
5045e111ed8SAndrew Rybchenko proxied_cmd_resp = ((emrp->emr_cmd == MC_CMD_PROXY_CMD) &&
5055e111ed8SAndrew Rybchenko (resp_cmd != MC_CMD_PROXY_CMD));
5065e111ed8SAndrew Rybchenko if (proxied_cmd_resp) {
5075e111ed8SAndrew Rybchenko resp_off = 0;
5085e111ed8SAndrew Rybchenko emrp->emr_out_length_used += hdr_len;
5095e111ed8SAndrew Rybchenko }
5105e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MCDI_PROXY_AUTH_SERVER */
5115e111ed8SAndrew Rybchenko } else {
5125e111ed8SAndrew Rybchenko resp_off = hdr_len;
5135e111ed8SAndrew Rybchenko }
5145e111ed8SAndrew Rybchenko
5155e111ed8SAndrew Rybchenko /* Copy payload out into caller supplied buffer */
5165e111ed8SAndrew Rybchenko bytes = MIN(emrp->emr_out_length_used, emrp->emr_out_length);
5175e111ed8SAndrew Rybchenko efx_mcdi_read_response(enp, emrp->emr_out_buf, resp_off, bytes);
5185e111ed8SAndrew Rybchenko
519e1c9fcabSAndy Moreton /* Report bytes copied to caller (response message may be larger) */
520e1c9fcabSAndy Moreton emrp->emr_out_length_used = bytes;
521e1c9fcabSAndy Moreton
5225e111ed8SAndrew Rybchenko #if EFSYS_OPT_MCDI_LOGGING
5235e111ed8SAndrew Rybchenko if (emtp->emt_logger != NULL) {
5245e111ed8SAndrew Rybchenko emtp->emt_logger(emtp->emt_context,
5255e111ed8SAndrew Rybchenko EFX_LOG_MCDI_RESPONSE,
5265e111ed8SAndrew Rybchenko &hdr[0], hdr_len,
5275e111ed8SAndrew Rybchenko emrp->emr_out_buf, bytes);
5285e111ed8SAndrew Rybchenko }
5295e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MCDI_LOGGING */
5305e111ed8SAndrew Rybchenko }
5315e111ed8SAndrew Rybchenko
5325e111ed8SAndrew Rybchenko
5335e111ed8SAndrew Rybchenko __checkReturn boolean_t
efx_mcdi_request_poll(__in efx_nic_t * enp)5345e111ed8SAndrew Rybchenko efx_mcdi_request_poll(
5355e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
5365e111ed8SAndrew Rybchenko {
5375e111ed8SAndrew Rybchenko efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
5385e111ed8SAndrew Rybchenko efx_mcdi_req_t *emrp;
5395e111ed8SAndrew Rybchenko efsys_lock_state_t state;
5405e111ed8SAndrew Rybchenko efx_rc_t rc;
5415e111ed8SAndrew Rybchenko
5425e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
5435e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
5445e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
5455e111ed8SAndrew Rybchenko
5465e111ed8SAndrew Rybchenko /* Serialise against post-watchdog efx_mcdi_ev* */
5475e111ed8SAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state);
5485e111ed8SAndrew Rybchenko
5495e111ed8SAndrew Rybchenko EFSYS_ASSERT(emip->emi_pending_req != NULL);
5505e111ed8SAndrew Rybchenko EFSYS_ASSERT(!emip->emi_ev_cpl);
5515e111ed8SAndrew Rybchenko emrp = emip->emi_pending_req;
5525e111ed8SAndrew Rybchenko
5535e111ed8SAndrew Rybchenko /* Check if hardware is unavailable */
5545e111ed8SAndrew Rybchenko if (efx_nic_hw_unavailable(enp)) {
5555e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state);
5565e111ed8SAndrew Rybchenko return (B_FALSE);
5575e111ed8SAndrew Rybchenko }
5585e111ed8SAndrew Rybchenko
5595e111ed8SAndrew Rybchenko /* Check for reboot atomically w.r.t efx_mcdi_request_start */
5605e111ed8SAndrew Rybchenko if (emip->emi_poll_cnt++ == 0) {
5615e111ed8SAndrew Rybchenko if ((rc = efx_mcdi_poll_reboot(enp)) != 0) {
5625e111ed8SAndrew Rybchenko emip->emi_pending_req = NULL;
5635e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state);
5645e111ed8SAndrew Rybchenko
5655e111ed8SAndrew Rybchenko /* Reboot/Assertion */
5665e111ed8SAndrew Rybchenko if (rc == EIO || rc == EINTR)
5675e111ed8SAndrew Rybchenko efx_mcdi_raise_exception(enp, emrp, rc);
5685e111ed8SAndrew Rybchenko
5695e111ed8SAndrew Rybchenko goto fail1;
5705e111ed8SAndrew Rybchenko }
5715e111ed8SAndrew Rybchenko }
5725e111ed8SAndrew Rybchenko
5735e111ed8SAndrew Rybchenko /* Check if a response is available */
5745e111ed8SAndrew Rybchenko if (efx_mcdi_poll_response(enp) == B_FALSE) {
5755e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state);
5765e111ed8SAndrew Rybchenko return (B_FALSE);
5775e111ed8SAndrew Rybchenko }
5785e111ed8SAndrew Rybchenko
5795e111ed8SAndrew Rybchenko /* Read the response header */
5805e111ed8SAndrew Rybchenko efx_mcdi_read_response_header(enp, emrp);
5815e111ed8SAndrew Rybchenko
5825e111ed8SAndrew Rybchenko /* Request complete */
5835e111ed8SAndrew Rybchenko emip->emi_pending_req = NULL;
5845e111ed8SAndrew Rybchenko
5855e111ed8SAndrew Rybchenko /* Ensure stale MCDI requests fail after an MC reboot. */
5865e111ed8SAndrew Rybchenko emip->emi_new_epoch = B_FALSE;
5875e111ed8SAndrew Rybchenko
5885e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state);
5895e111ed8SAndrew Rybchenko
5905e111ed8SAndrew Rybchenko if ((rc = emrp->emr_rc) != 0)
5915e111ed8SAndrew Rybchenko goto fail2;
5925e111ed8SAndrew Rybchenko
5935e111ed8SAndrew Rybchenko efx_mcdi_finish_response(enp, emrp);
5945e111ed8SAndrew Rybchenko return (B_TRUE);
5955e111ed8SAndrew Rybchenko
5965e111ed8SAndrew Rybchenko fail2:
5975e111ed8SAndrew Rybchenko if (!emrp->emr_quiet)
5985e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
5995e111ed8SAndrew Rybchenko fail1:
6005e111ed8SAndrew Rybchenko if (!emrp->emr_quiet)
6015e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
6025e111ed8SAndrew Rybchenko
6035e111ed8SAndrew Rybchenko return (B_TRUE);
6045e111ed8SAndrew Rybchenko }
6055e111ed8SAndrew Rybchenko
6065e111ed8SAndrew Rybchenko __checkReturn boolean_t
efx_mcdi_request_abort(__in efx_nic_t * enp)6075e111ed8SAndrew Rybchenko efx_mcdi_request_abort(
6085e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
6095e111ed8SAndrew Rybchenko {
6105e111ed8SAndrew Rybchenko efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
6115e111ed8SAndrew Rybchenko efx_mcdi_req_t *emrp;
6125e111ed8SAndrew Rybchenko boolean_t aborted;
6135e111ed8SAndrew Rybchenko efsys_lock_state_t state;
6145e111ed8SAndrew Rybchenko
6155e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
6165e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
6175e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
6185e111ed8SAndrew Rybchenko
6195e111ed8SAndrew Rybchenko /*
6205e111ed8SAndrew Rybchenko * efx_mcdi_ev_* may have already completed this event, and be
6215e111ed8SAndrew Rybchenko * spinning/blocked on the upper layer lock. So it *is* legitimate
6225e111ed8SAndrew Rybchenko * to for emi_pending_req to be NULL. If there is a pending event
6235e111ed8SAndrew Rybchenko * completed request, then provide a "credit" to allow
6245e111ed8SAndrew Rybchenko * efx_mcdi_ev_cpl() to accept a single spurious completion.
6255e111ed8SAndrew Rybchenko */
6265e111ed8SAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state);
6275e111ed8SAndrew Rybchenko emrp = emip->emi_pending_req;
6285e111ed8SAndrew Rybchenko aborted = (emrp != NULL);
6295e111ed8SAndrew Rybchenko if (aborted) {
6305e111ed8SAndrew Rybchenko emip->emi_pending_req = NULL;
6315e111ed8SAndrew Rybchenko
6325e111ed8SAndrew Rybchenko /* Error the request */
6335e111ed8SAndrew Rybchenko emrp->emr_out_length_used = 0;
6345e111ed8SAndrew Rybchenko emrp->emr_rc = ETIMEDOUT;
6355e111ed8SAndrew Rybchenko
6365e111ed8SAndrew Rybchenko /* Provide a credit for seqno/emr_pending_req mismatches */
6375e111ed8SAndrew Rybchenko if (emip->emi_ev_cpl)
6385e111ed8SAndrew Rybchenko ++emip->emi_aborted;
6395e111ed8SAndrew Rybchenko
6405e111ed8SAndrew Rybchenko /*
6415e111ed8SAndrew Rybchenko * The upper layer has called us, so we don't
6425e111ed8SAndrew Rybchenko * need to complete the request.
6435e111ed8SAndrew Rybchenko */
6445e111ed8SAndrew Rybchenko }
6455e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state);
6465e111ed8SAndrew Rybchenko
6475e111ed8SAndrew Rybchenko return (aborted);
6485e111ed8SAndrew Rybchenko }
6495e111ed8SAndrew Rybchenko
6501bf9ff57SViacheslav Galaktionov __checkReturn efx_rc_t
efx_mcdi_get_client_handle(__in efx_nic_t * enp,__in efx_pcie_interface_t intf,__in uint16_t pf,__in uint16_t vf,__out uint32_t * handle)6511bf9ff57SViacheslav Galaktionov efx_mcdi_get_client_handle(
6521bf9ff57SViacheslav Galaktionov __in efx_nic_t *enp,
6531bf9ff57SViacheslav Galaktionov __in efx_pcie_interface_t intf,
6541bf9ff57SViacheslav Galaktionov __in uint16_t pf,
6551bf9ff57SViacheslav Galaktionov __in uint16_t vf,
6561bf9ff57SViacheslav Galaktionov __out uint32_t *handle)
6571bf9ff57SViacheslav Galaktionov {
6581bf9ff57SViacheslav Galaktionov efx_mcdi_req_t req;
6591bf9ff57SViacheslav Galaktionov EFX_MCDI_DECLARE_BUF(payload,
6601bf9ff57SViacheslav Galaktionov MC_CMD_GET_CLIENT_HANDLE_IN_LEN,
6611bf9ff57SViacheslav Galaktionov MC_CMD_GET_CLIENT_HANDLE_OUT_LEN);
662b85f5048SIvan Malov uint32_t pcie_intf;
6631bf9ff57SViacheslav Galaktionov efx_rc_t rc;
6641bf9ff57SViacheslav Galaktionov
6651bf9ff57SViacheslav Galaktionov if (handle == NULL) {
6661bf9ff57SViacheslav Galaktionov rc = EINVAL;
6671bf9ff57SViacheslav Galaktionov goto fail1;
6681bf9ff57SViacheslav Galaktionov }
6691bf9ff57SViacheslav Galaktionov
670b85f5048SIvan Malov rc = efx_mcdi_intf_to_pcie(intf, &pcie_intf);
671b85f5048SIvan Malov if (rc != 0)
672b85f5048SIvan Malov goto fail2;
673b85f5048SIvan Malov
6741bf9ff57SViacheslav Galaktionov req.emr_cmd = MC_CMD_GET_CLIENT_HANDLE;
6751bf9ff57SViacheslav Galaktionov req.emr_in_buf = payload;
6761bf9ff57SViacheslav Galaktionov req.emr_in_length = MC_CMD_GET_CLIENT_HANDLE_IN_LEN;
6771bf9ff57SViacheslav Galaktionov req.emr_out_buf = payload;
6781bf9ff57SViacheslav Galaktionov req.emr_out_length = MC_CMD_GET_CLIENT_HANDLE_OUT_LEN;
6791bf9ff57SViacheslav Galaktionov
6801bf9ff57SViacheslav Galaktionov MCDI_IN_SET_DWORD(req, GET_CLIENT_HANDLE_IN_TYPE,
6811bf9ff57SViacheslav Galaktionov MC_CMD_GET_CLIENT_HANDLE_IN_TYPE_FUNC);
6821bf9ff57SViacheslav Galaktionov MCDI_IN_SET_WORD(req, GET_CLIENT_HANDLE_IN_FUNC_PF, pf);
6831bf9ff57SViacheslav Galaktionov MCDI_IN_SET_WORD(req, GET_CLIENT_HANDLE_IN_FUNC_VF, vf);
684b85f5048SIvan Malov MCDI_IN_SET_DWORD(req, GET_CLIENT_HANDLE_IN_FUNC_INTF, pcie_intf);
6851bf9ff57SViacheslav Galaktionov
6861bf9ff57SViacheslav Galaktionov efx_mcdi_execute(enp, &req);
6871bf9ff57SViacheslav Galaktionov
6881bf9ff57SViacheslav Galaktionov if (req.emr_rc != 0) {
6891bf9ff57SViacheslav Galaktionov rc = req.emr_rc;
690b85f5048SIvan Malov goto fail3;
6911bf9ff57SViacheslav Galaktionov }
6921bf9ff57SViacheslav Galaktionov
6931bf9ff57SViacheslav Galaktionov if (req.emr_out_length_used < MC_CMD_GET_CLIENT_HANDLE_OUT_LEN) {
6941bf9ff57SViacheslav Galaktionov rc = EMSGSIZE;
695b85f5048SIvan Malov goto fail4;
6961bf9ff57SViacheslav Galaktionov }
6971bf9ff57SViacheslav Galaktionov
6981bf9ff57SViacheslav Galaktionov *handle = MCDI_OUT_DWORD(req, GET_CLIENT_HANDLE_OUT_HANDLE);
6991bf9ff57SViacheslav Galaktionov
7001bf9ff57SViacheslav Galaktionov return 0;
701b85f5048SIvan Malov fail4:
702b85f5048SIvan Malov EFSYS_PROBE(fail4);
7031bf9ff57SViacheslav Galaktionov fail3:
7041bf9ff57SViacheslav Galaktionov EFSYS_PROBE(fail3);
7051bf9ff57SViacheslav Galaktionov fail2:
7061bf9ff57SViacheslav Galaktionov EFSYS_PROBE(fail2);
7071bf9ff57SViacheslav Galaktionov fail1:
7081bf9ff57SViacheslav Galaktionov EFSYS_PROBE1(fail1, efx_rc_t, rc);
7091bf9ff57SViacheslav Galaktionov return (rc);
7101bf9ff57SViacheslav Galaktionov }
7111bf9ff57SViacheslav Galaktionov
7121bf9ff57SViacheslav Galaktionov __checkReturn efx_rc_t
efx_mcdi_get_own_client_handle(__in efx_nic_t * enp,__out uint32_t * handle)7131bf9ff57SViacheslav Galaktionov efx_mcdi_get_own_client_handle(
7141bf9ff57SViacheslav Galaktionov __in efx_nic_t *enp,
7151bf9ff57SViacheslav Galaktionov __out uint32_t *handle)
7161bf9ff57SViacheslav Galaktionov {
7171bf9ff57SViacheslav Galaktionov efx_rc_t rc;
7181bf9ff57SViacheslav Galaktionov
719b85f5048SIvan Malov rc = efx_mcdi_get_client_handle(enp, EFX_PCIE_INTERFACE_CALLER,
7201bf9ff57SViacheslav Galaktionov PCIE_FUNCTION_PF_NULL, PCIE_FUNCTION_VF_NULL, handle);
7211bf9ff57SViacheslav Galaktionov if (rc != 0)
7221bf9ff57SViacheslav Galaktionov goto fail1;
7231bf9ff57SViacheslav Galaktionov
7241bf9ff57SViacheslav Galaktionov return (0);
7251bf9ff57SViacheslav Galaktionov fail1:
7261bf9ff57SViacheslav Galaktionov EFSYS_PROBE1(fail1, efx_rc_t, rc);
7271bf9ff57SViacheslav Galaktionov return (rc);
7281bf9ff57SViacheslav Galaktionov }
7291bf9ff57SViacheslav Galaktionov
73078b82063SIvan Malov __checkReturn efx_rc_t
efx_mcdi_client_mac_addr_get(__in efx_nic_t * enp,__in uint32_t client_handle,__out uint8_t addr_bytes[EFX_MAC_ADDR_LEN])73178b82063SIvan Malov efx_mcdi_client_mac_addr_get(
73278b82063SIvan Malov __in efx_nic_t *enp,
73378b82063SIvan Malov __in uint32_t client_handle,
73478b82063SIvan Malov __out uint8_t addr_bytes[EFX_MAC_ADDR_LEN])
73578b82063SIvan Malov {
73678b82063SIvan Malov efx_mcdi_req_t req;
73778b82063SIvan Malov EFX_MCDI_DECLARE_BUF(payload,
73878b82063SIvan Malov MC_CMD_GET_CLIENT_MAC_ADDRESSES_IN_LEN,
73978b82063SIvan Malov MC_CMD_GET_CLIENT_MAC_ADDRESSES_OUT_LEN(1));
74078b82063SIvan Malov efx_rc_t rc;
74178b82063SIvan Malov
74278b82063SIvan Malov req.emr_cmd = MC_CMD_GET_CLIENT_MAC_ADDRESSES;
74378b82063SIvan Malov req.emr_in_buf = payload;
74478b82063SIvan Malov req.emr_in_length = MC_CMD_GET_CLIENT_MAC_ADDRESSES_IN_LEN;
74578b82063SIvan Malov req.emr_out_buf = payload;
74678b82063SIvan Malov req.emr_out_length = MC_CMD_GET_CLIENT_MAC_ADDRESSES_OUT_LEN(1);
74778b82063SIvan Malov
74878b82063SIvan Malov MCDI_IN_SET_DWORD(req, GET_CLIENT_MAC_ADDRESSES_IN_CLIENT_HANDLE,
74978b82063SIvan Malov client_handle);
75078b82063SIvan Malov
75178b82063SIvan Malov efx_mcdi_execute(enp, &req);
75278b82063SIvan Malov
75378b82063SIvan Malov if (req.emr_rc != 0) {
75478b82063SIvan Malov rc = req.emr_rc;
75578b82063SIvan Malov goto fail1;
75678b82063SIvan Malov }
75778b82063SIvan Malov
75878b82063SIvan Malov if (req.emr_out_length_used <
75978b82063SIvan Malov MC_CMD_GET_CLIENT_MAC_ADDRESSES_OUT_LEN(1)) {
76078b82063SIvan Malov rc = EMSGSIZE;
76178b82063SIvan Malov goto fail2;
76278b82063SIvan Malov }
76378b82063SIvan Malov
76478b82063SIvan Malov memcpy(addr_bytes,
76578b82063SIvan Malov MCDI_OUT2(req, uint8_t, GET_CLIENT_MAC_ADDRESSES_OUT_MAC_ADDRS),
76678b82063SIvan Malov EFX_MAC_ADDR_LEN);
76778b82063SIvan Malov
76878b82063SIvan Malov return (0);
76978b82063SIvan Malov
77078b82063SIvan Malov fail2:
77178b82063SIvan Malov EFSYS_PROBE(fail2);
77278b82063SIvan Malov fail1:
77378b82063SIvan Malov EFSYS_PROBE1(fail1, efx_rc_t, rc);
77478b82063SIvan Malov return (rc);
77578b82063SIvan Malov }
77678b82063SIvan Malov
77778b82063SIvan Malov __checkReturn efx_rc_t
efx_mcdi_client_mac_addr_set(__in efx_nic_t * enp,__in uint32_t client_handle,__in const uint8_t addr_bytes[EFX_MAC_ADDR_LEN])77878b82063SIvan Malov efx_mcdi_client_mac_addr_set(
77978b82063SIvan Malov __in efx_nic_t *enp,
78078b82063SIvan Malov __in uint32_t client_handle,
78178b82063SIvan Malov __in const uint8_t addr_bytes[EFX_MAC_ADDR_LEN])
78278b82063SIvan Malov {
78378b82063SIvan Malov efx_mcdi_req_t req;
78478b82063SIvan Malov EFX_MCDI_DECLARE_BUF(payload,
78578b82063SIvan Malov MC_CMD_SET_CLIENT_MAC_ADDRESSES_IN_LEN(1),
78678b82063SIvan Malov MC_CMD_SET_CLIENT_MAC_ADDRESSES_OUT_LEN);
78778b82063SIvan Malov uint32_t oui;
78878b82063SIvan Malov efx_rc_t rc;
78978b82063SIvan Malov
79078b82063SIvan Malov if (EFX_MAC_ADDR_IS_MULTICAST(addr_bytes)) {
79178b82063SIvan Malov rc = EINVAL;
79278b82063SIvan Malov goto fail1;
79378b82063SIvan Malov }
79478b82063SIvan Malov
79578b82063SIvan Malov oui = addr_bytes[0] << 16 | addr_bytes[1] << 8 | addr_bytes[2];
79678b82063SIvan Malov if (oui == 0x000000) {
79778b82063SIvan Malov rc = EINVAL;
79878b82063SIvan Malov goto fail2;
79978b82063SIvan Malov }
80078b82063SIvan Malov
80178b82063SIvan Malov req.emr_cmd = MC_CMD_SET_CLIENT_MAC_ADDRESSES;
80278b82063SIvan Malov req.emr_in_buf = payload;
80378b82063SIvan Malov req.emr_in_length = MC_CMD_SET_CLIENT_MAC_ADDRESSES_IN_LEN(1);
80478b82063SIvan Malov req.emr_out_buf = payload;
80578b82063SIvan Malov req.emr_out_length = MC_CMD_SET_CLIENT_MAC_ADDRESSES_OUT_LEN;
80678b82063SIvan Malov
80778b82063SIvan Malov MCDI_IN_SET_DWORD(req, SET_CLIENT_MAC_ADDRESSES_IN_CLIENT_HANDLE,
80878b82063SIvan Malov client_handle);
80978b82063SIvan Malov
81078b82063SIvan Malov memcpy(MCDI_IN2(req, uint8_t, SET_CLIENT_MAC_ADDRESSES_IN_MAC_ADDRS),
81178b82063SIvan Malov addr_bytes, EFX_MAC_ADDR_LEN);
81278b82063SIvan Malov
81378b82063SIvan Malov efx_mcdi_execute(enp, &req);
81478b82063SIvan Malov
81578b82063SIvan Malov if (req.emr_rc != 0) {
81678b82063SIvan Malov rc = req.emr_rc;
81778b82063SIvan Malov goto fail3;
81878b82063SIvan Malov }
81978b82063SIvan Malov
82078b82063SIvan Malov return (0);
82178b82063SIvan Malov
82278b82063SIvan Malov fail3:
82378b82063SIvan Malov EFSYS_PROBE(fail3);
82478b82063SIvan Malov fail2:
82578b82063SIvan Malov EFSYS_PROBE(fail2);
82678b82063SIvan Malov fail1:
82778b82063SIvan Malov EFSYS_PROBE1(fail1, efx_rc_t, rc);
82878b82063SIvan Malov return (rc);
82978b82063SIvan Malov }
83078b82063SIvan Malov
8315e111ed8SAndrew Rybchenko void
efx_mcdi_get_timeout(__in efx_nic_t * enp,__in efx_mcdi_req_t * emrp,__out uint32_t * timeoutp)8325e111ed8SAndrew Rybchenko efx_mcdi_get_timeout(
8335e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
8345e111ed8SAndrew Rybchenko __in efx_mcdi_req_t *emrp,
8355e111ed8SAndrew Rybchenko __out uint32_t *timeoutp)
8365e111ed8SAndrew Rybchenko {
8375e111ed8SAndrew Rybchenko const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
8385e111ed8SAndrew Rybchenko
8395e111ed8SAndrew Rybchenko emcop->emco_get_timeout(enp, emrp, timeoutp);
8405e111ed8SAndrew Rybchenko }
8415e111ed8SAndrew Rybchenko
8425e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_request_errcode(__in unsigned int err)8435e111ed8SAndrew Rybchenko efx_mcdi_request_errcode(
8445e111ed8SAndrew Rybchenko __in unsigned int err)
8455e111ed8SAndrew Rybchenko {
8465e111ed8SAndrew Rybchenko
8475e111ed8SAndrew Rybchenko switch (err) {
8485e111ed8SAndrew Rybchenko /* MCDI v1 */
8495e111ed8SAndrew Rybchenko case MC_CMD_ERR_EPERM:
8505e111ed8SAndrew Rybchenko return (EACCES);
8515e111ed8SAndrew Rybchenko case MC_CMD_ERR_ENOENT:
8525e111ed8SAndrew Rybchenko return (ENOENT);
8535e111ed8SAndrew Rybchenko case MC_CMD_ERR_EINTR:
8545e111ed8SAndrew Rybchenko return (EINTR);
8555e111ed8SAndrew Rybchenko case MC_CMD_ERR_EACCES:
8565e111ed8SAndrew Rybchenko return (EACCES);
8575e111ed8SAndrew Rybchenko case MC_CMD_ERR_EBUSY:
8585e111ed8SAndrew Rybchenko return (EBUSY);
8595e111ed8SAndrew Rybchenko case MC_CMD_ERR_EINVAL:
8605e111ed8SAndrew Rybchenko return (EINVAL);
8615e111ed8SAndrew Rybchenko case MC_CMD_ERR_EDEADLK:
8625e111ed8SAndrew Rybchenko return (EDEADLK);
8635e111ed8SAndrew Rybchenko case MC_CMD_ERR_ENOSYS:
8645e111ed8SAndrew Rybchenko return (ENOTSUP);
8655e111ed8SAndrew Rybchenko case MC_CMD_ERR_ETIME:
8665e111ed8SAndrew Rybchenko return (ETIMEDOUT);
8675e111ed8SAndrew Rybchenko case MC_CMD_ERR_ENOTSUP:
8685e111ed8SAndrew Rybchenko return (ENOTSUP);
8695e111ed8SAndrew Rybchenko case MC_CMD_ERR_EALREADY:
8705e111ed8SAndrew Rybchenko return (EALREADY);
8715e111ed8SAndrew Rybchenko
8725e111ed8SAndrew Rybchenko /* MCDI v2 */
8735e111ed8SAndrew Rybchenko case MC_CMD_ERR_EEXIST:
8745e111ed8SAndrew Rybchenko return (EEXIST);
8755e111ed8SAndrew Rybchenko #ifdef MC_CMD_ERR_EAGAIN
8765e111ed8SAndrew Rybchenko case MC_CMD_ERR_EAGAIN:
8775e111ed8SAndrew Rybchenko return (EAGAIN);
8785e111ed8SAndrew Rybchenko #endif
8795e111ed8SAndrew Rybchenko #ifdef MC_CMD_ERR_ENOSPC
8805e111ed8SAndrew Rybchenko case MC_CMD_ERR_ENOSPC:
8815e111ed8SAndrew Rybchenko return (ENOSPC);
8825e111ed8SAndrew Rybchenko #endif
8835e111ed8SAndrew Rybchenko case MC_CMD_ERR_ERANGE:
8845e111ed8SAndrew Rybchenko return (ERANGE);
8855e111ed8SAndrew Rybchenko
8865e111ed8SAndrew Rybchenko case MC_CMD_ERR_ALLOC_FAIL:
8875e111ed8SAndrew Rybchenko return (ENOMEM);
8885e111ed8SAndrew Rybchenko case MC_CMD_ERR_NO_VADAPTOR:
8895e111ed8SAndrew Rybchenko return (ENOENT);
8905e111ed8SAndrew Rybchenko case MC_CMD_ERR_NO_EVB_PORT:
8915e111ed8SAndrew Rybchenko return (ENOENT);
8925e111ed8SAndrew Rybchenko case MC_CMD_ERR_NO_VSWITCH:
8935e111ed8SAndrew Rybchenko return (ENODEV);
8945e111ed8SAndrew Rybchenko case MC_CMD_ERR_VLAN_LIMIT:
8955e111ed8SAndrew Rybchenko return (EINVAL);
8965e111ed8SAndrew Rybchenko case MC_CMD_ERR_BAD_PCI_FUNC:
8975e111ed8SAndrew Rybchenko return (ENODEV);
8985e111ed8SAndrew Rybchenko case MC_CMD_ERR_BAD_VLAN_MODE:
8995e111ed8SAndrew Rybchenko return (EINVAL);
9005e111ed8SAndrew Rybchenko case MC_CMD_ERR_BAD_VSWITCH_TYPE:
9015e111ed8SAndrew Rybchenko return (EINVAL);
9025e111ed8SAndrew Rybchenko case MC_CMD_ERR_BAD_VPORT_TYPE:
9035e111ed8SAndrew Rybchenko return (EINVAL);
9045e111ed8SAndrew Rybchenko case MC_CMD_ERR_MAC_EXIST:
9055e111ed8SAndrew Rybchenko return (EEXIST);
9065e111ed8SAndrew Rybchenko
9075e111ed8SAndrew Rybchenko case MC_CMD_ERR_PROXY_PENDING:
9085e111ed8SAndrew Rybchenko return (EAGAIN);
9095e111ed8SAndrew Rybchenko
9105e111ed8SAndrew Rybchenko default:
9115e111ed8SAndrew Rybchenko EFSYS_PROBE1(mc_pcol_error, int, err);
9125e111ed8SAndrew Rybchenko return (EIO);
9135e111ed8SAndrew Rybchenko }
9145e111ed8SAndrew Rybchenko }
9155e111ed8SAndrew Rybchenko
9165e111ed8SAndrew Rybchenko void
efx_mcdi_raise_exception(__in efx_nic_t * enp,__in_opt efx_mcdi_req_t * emrp,__in int rc)9175e111ed8SAndrew Rybchenko efx_mcdi_raise_exception(
9185e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
9195e111ed8SAndrew Rybchenko __in_opt efx_mcdi_req_t *emrp,
9205e111ed8SAndrew Rybchenko __in int rc)
9215e111ed8SAndrew Rybchenko {
9225e111ed8SAndrew Rybchenko const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
9235e111ed8SAndrew Rybchenko efx_mcdi_exception_t exception;
9245e111ed8SAndrew Rybchenko
9255e111ed8SAndrew Rybchenko /* Reboot or Assertion failure only */
9265e111ed8SAndrew Rybchenko EFSYS_ASSERT(rc == EIO || rc == EINTR);
9275e111ed8SAndrew Rybchenko
9285e111ed8SAndrew Rybchenko /*
9295e111ed8SAndrew Rybchenko * If MC_CMD_REBOOT causes a reboot (dependent on parameters),
9305e111ed8SAndrew Rybchenko * then the EIO is not worthy of an exception.
9315e111ed8SAndrew Rybchenko */
9325e111ed8SAndrew Rybchenko if (emrp != NULL && emrp->emr_cmd == MC_CMD_REBOOT && rc == EIO)
9335e111ed8SAndrew Rybchenko return;
9345e111ed8SAndrew Rybchenko
9355e111ed8SAndrew Rybchenko exception = (rc == EIO)
9365e111ed8SAndrew Rybchenko ? EFX_MCDI_EXCEPTION_MC_REBOOT
9375e111ed8SAndrew Rybchenko : EFX_MCDI_EXCEPTION_MC_BADASSERT;
9385e111ed8SAndrew Rybchenko
9395e111ed8SAndrew Rybchenko emtp->emt_exception(emtp->emt_context, exception);
9405e111ed8SAndrew Rybchenko }
9415e111ed8SAndrew Rybchenko
9425e111ed8SAndrew Rybchenko void
efx_mcdi_execute(__in efx_nic_t * enp,__inout efx_mcdi_req_t * emrp)9435e111ed8SAndrew Rybchenko efx_mcdi_execute(
9445e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
9455e111ed8SAndrew Rybchenko __inout efx_mcdi_req_t *emrp)
9465e111ed8SAndrew Rybchenko {
9475e111ed8SAndrew Rybchenko const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
9485e111ed8SAndrew Rybchenko
9495e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
9505e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
9515e111ed8SAndrew Rybchenko
9525e111ed8SAndrew Rybchenko emrp->emr_quiet = B_FALSE;
9535e111ed8SAndrew Rybchenko emtp->emt_execute(emtp->emt_context, emrp);
9545e111ed8SAndrew Rybchenko }
9555e111ed8SAndrew Rybchenko
9565e111ed8SAndrew Rybchenko void
efx_mcdi_execute_quiet(__in efx_nic_t * enp,__inout efx_mcdi_req_t * emrp)9575e111ed8SAndrew Rybchenko efx_mcdi_execute_quiet(
9585e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
9595e111ed8SAndrew Rybchenko __inout efx_mcdi_req_t *emrp)
9605e111ed8SAndrew Rybchenko {
9615e111ed8SAndrew Rybchenko const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
9625e111ed8SAndrew Rybchenko
9635e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
9645e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
9655e111ed8SAndrew Rybchenko
9665e111ed8SAndrew Rybchenko emrp->emr_quiet = B_TRUE;
9675e111ed8SAndrew Rybchenko emtp->emt_execute(emtp->emt_context, emrp);
9685e111ed8SAndrew Rybchenko }
9695e111ed8SAndrew Rybchenko
9705e111ed8SAndrew Rybchenko void
efx_mcdi_ev_cpl(__in efx_nic_t * enp,__in unsigned int seq,__in unsigned int outlen,__in int errcode)9715e111ed8SAndrew Rybchenko efx_mcdi_ev_cpl(
9725e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
9735e111ed8SAndrew Rybchenko __in unsigned int seq,
9745e111ed8SAndrew Rybchenko __in unsigned int outlen,
9755e111ed8SAndrew Rybchenko __in int errcode)
9765e111ed8SAndrew Rybchenko {
9775e111ed8SAndrew Rybchenko efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
9785e111ed8SAndrew Rybchenko const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
9795e111ed8SAndrew Rybchenko efx_mcdi_req_t *emrp;
9805e111ed8SAndrew Rybchenko efsys_lock_state_t state;
9815e111ed8SAndrew Rybchenko
9825e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
9835e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
9845e111ed8SAndrew Rybchenko
9855e111ed8SAndrew Rybchenko /*
9865e111ed8SAndrew Rybchenko * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start()
9875e111ed8SAndrew Rybchenko * when we're completing an aborted request.
9885e111ed8SAndrew Rybchenko */
9895e111ed8SAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state);
9905e111ed8SAndrew Rybchenko if (emip->emi_pending_req == NULL || !emip->emi_ev_cpl ||
9915e111ed8SAndrew Rybchenko (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
9925e111ed8SAndrew Rybchenko EFSYS_ASSERT(emip->emi_aborted > 0);
9935e111ed8SAndrew Rybchenko if (emip->emi_aborted > 0)
9945e111ed8SAndrew Rybchenko --emip->emi_aborted;
9955e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state);
9965e111ed8SAndrew Rybchenko return;
9975e111ed8SAndrew Rybchenko }
9985e111ed8SAndrew Rybchenko
9995e111ed8SAndrew Rybchenko emrp = emip->emi_pending_req;
10005e111ed8SAndrew Rybchenko emip->emi_pending_req = NULL;
10015e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state);
10025e111ed8SAndrew Rybchenko
10035e111ed8SAndrew Rybchenko if (emip->emi_max_version >= 2) {
10045e111ed8SAndrew Rybchenko /* MCDIv2 response details do not fit into an event. */
10055e111ed8SAndrew Rybchenko efx_mcdi_read_response_header(enp, emrp);
10065e111ed8SAndrew Rybchenko } else {
10075e111ed8SAndrew Rybchenko if (errcode != 0) {
10085e111ed8SAndrew Rybchenko if (!emrp->emr_quiet) {
10095e111ed8SAndrew Rybchenko EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd,
10105e111ed8SAndrew Rybchenko int, errcode);
10115e111ed8SAndrew Rybchenko }
10125e111ed8SAndrew Rybchenko emrp->emr_out_length_used = 0;
10135e111ed8SAndrew Rybchenko emrp->emr_rc = efx_mcdi_request_errcode(errcode);
10145e111ed8SAndrew Rybchenko } else {
10155e111ed8SAndrew Rybchenko emrp->emr_out_length_used = outlen;
10165e111ed8SAndrew Rybchenko emrp->emr_rc = 0;
10175e111ed8SAndrew Rybchenko }
10185e111ed8SAndrew Rybchenko }
10195e111ed8SAndrew Rybchenko if (emrp->emr_rc == 0)
10205e111ed8SAndrew Rybchenko efx_mcdi_finish_response(enp, emrp);
10215e111ed8SAndrew Rybchenko
10225e111ed8SAndrew Rybchenko emtp->emt_ev_cpl(emtp->emt_context);
10235e111ed8SAndrew Rybchenko }
10245e111ed8SAndrew Rybchenko
10255e111ed8SAndrew Rybchenko #if EFSYS_OPT_MCDI_PROXY_AUTH
10265e111ed8SAndrew Rybchenko
10275e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_get_proxy_handle(__in efx_nic_t * enp,__in efx_mcdi_req_t * emrp,__out uint32_t * handlep)10285e111ed8SAndrew Rybchenko efx_mcdi_get_proxy_handle(
10295e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
10305e111ed8SAndrew Rybchenko __in efx_mcdi_req_t *emrp,
10315e111ed8SAndrew Rybchenko __out uint32_t *handlep)
10325e111ed8SAndrew Rybchenko {
10335e111ed8SAndrew Rybchenko efx_rc_t rc;
10345e111ed8SAndrew Rybchenko
10355e111ed8SAndrew Rybchenko _NOTE(ARGUNUSED(enp))
10365e111ed8SAndrew Rybchenko
10375e111ed8SAndrew Rybchenko /*
10385e111ed8SAndrew Rybchenko * Return proxy handle from MCDI request that returned with error
10395e111ed8SAndrew Rybchenko * MC_MCD_ERR_PROXY_PENDING. This handle is used to wait for a matching
10405e111ed8SAndrew Rybchenko * PROXY_RESPONSE event.
10415e111ed8SAndrew Rybchenko */
10425e111ed8SAndrew Rybchenko if ((emrp == NULL) || (handlep == NULL)) {
10435e111ed8SAndrew Rybchenko rc = EINVAL;
10445e111ed8SAndrew Rybchenko goto fail1;
10455e111ed8SAndrew Rybchenko }
10465e111ed8SAndrew Rybchenko if ((emrp->emr_rc != 0) &&
10475e111ed8SAndrew Rybchenko (emrp->emr_err_code == MC_CMD_ERR_PROXY_PENDING)) {
10485e111ed8SAndrew Rybchenko *handlep = emrp->emr_proxy_handle;
10495e111ed8SAndrew Rybchenko rc = 0;
10505e111ed8SAndrew Rybchenko } else {
10515e111ed8SAndrew Rybchenko *handlep = 0;
10525e111ed8SAndrew Rybchenko rc = ENOENT;
10535e111ed8SAndrew Rybchenko }
10545e111ed8SAndrew Rybchenko return (rc);
10555e111ed8SAndrew Rybchenko
10565e111ed8SAndrew Rybchenko fail1:
10575e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
10585e111ed8SAndrew Rybchenko return (rc);
10595e111ed8SAndrew Rybchenko }
10605e111ed8SAndrew Rybchenko
10615e111ed8SAndrew Rybchenko void
efx_mcdi_ev_proxy_response(__in efx_nic_t * enp,__in unsigned int handle,__in unsigned int status)10625e111ed8SAndrew Rybchenko efx_mcdi_ev_proxy_response(
10635e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
10645e111ed8SAndrew Rybchenko __in unsigned int handle,
10655e111ed8SAndrew Rybchenko __in unsigned int status)
10665e111ed8SAndrew Rybchenko {
10675e111ed8SAndrew Rybchenko const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
10685e111ed8SAndrew Rybchenko efx_rc_t rc;
10695e111ed8SAndrew Rybchenko
10705e111ed8SAndrew Rybchenko /*
10715e111ed8SAndrew Rybchenko * Handle results of an authorization request for a privileged MCDI
10725e111ed8SAndrew Rybchenko * command. If authorization was granted then we must re-issue the
10735e111ed8SAndrew Rybchenko * original MCDI request. If authorization failed or timed out,
10745e111ed8SAndrew Rybchenko * then the original MCDI request should be completed with the
10755e111ed8SAndrew Rybchenko * result code from this event.
10765e111ed8SAndrew Rybchenko */
10775e111ed8SAndrew Rybchenko rc = (status == 0) ? 0 : efx_mcdi_request_errcode(status);
10785e111ed8SAndrew Rybchenko
10795e111ed8SAndrew Rybchenko emtp->emt_ev_proxy_response(emtp->emt_context, handle, rc);
10805e111ed8SAndrew Rybchenko }
10815e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
10825e111ed8SAndrew Rybchenko
10835e111ed8SAndrew Rybchenko #if EFSYS_OPT_MCDI_PROXY_AUTH_SERVER
10845e111ed8SAndrew Rybchenko void
efx_mcdi_ev_proxy_request(__in efx_nic_t * enp,__in unsigned int index)10855e111ed8SAndrew Rybchenko efx_mcdi_ev_proxy_request(
10865e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
10875e111ed8SAndrew Rybchenko __in unsigned int index)
10885e111ed8SAndrew Rybchenko {
10895e111ed8SAndrew Rybchenko const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
10905e111ed8SAndrew Rybchenko
10915e111ed8SAndrew Rybchenko if (emtp->emt_ev_proxy_request != NULL)
10925e111ed8SAndrew Rybchenko emtp->emt_ev_proxy_request(emtp->emt_context, index);
10935e111ed8SAndrew Rybchenko }
10945e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MCDI_PROXY_AUTH_SERVER */
10955e111ed8SAndrew Rybchenko void
efx_mcdi_ev_death(__in efx_nic_t * enp,__in int rc)10965e111ed8SAndrew Rybchenko efx_mcdi_ev_death(
10975e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
10985e111ed8SAndrew Rybchenko __in int rc)
10995e111ed8SAndrew Rybchenko {
11005e111ed8SAndrew Rybchenko efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
11015e111ed8SAndrew Rybchenko const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
11025e111ed8SAndrew Rybchenko efx_mcdi_req_t *emrp = NULL;
11035e111ed8SAndrew Rybchenko boolean_t ev_cpl;
11045e111ed8SAndrew Rybchenko efsys_lock_state_t state;
11055e111ed8SAndrew Rybchenko
11065e111ed8SAndrew Rybchenko /*
11075e111ed8SAndrew Rybchenko * The MCDI request (if there is one) has been terminated, either
11085e111ed8SAndrew Rybchenko * by a BADASSERT or REBOOT event.
11095e111ed8SAndrew Rybchenko *
11105e111ed8SAndrew Rybchenko * If there is an outstanding event-completed MCDI operation, then we
11115e111ed8SAndrew Rybchenko * will never receive the completion event (because both MCDI
11125e111ed8SAndrew Rybchenko * completions and BADASSERT events are sent to the same evq). So
11135e111ed8SAndrew Rybchenko * complete this MCDI op.
11145e111ed8SAndrew Rybchenko *
11155e111ed8SAndrew Rybchenko * This function might run in parallel with efx_mcdi_request_poll()
11165e111ed8SAndrew Rybchenko * for poll completed mcdi requests, and also with
11175e111ed8SAndrew Rybchenko * efx_mcdi_request_start() for post-watchdog completions.
11185e111ed8SAndrew Rybchenko */
11195e111ed8SAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state);
11205e111ed8SAndrew Rybchenko emrp = emip->emi_pending_req;
11215e111ed8SAndrew Rybchenko ev_cpl = emip->emi_ev_cpl;
11225e111ed8SAndrew Rybchenko if (emrp != NULL && emip->emi_ev_cpl) {
11235e111ed8SAndrew Rybchenko emip->emi_pending_req = NULL;
11245e111ed8SAndrew Rybchenko
11255e111ed8SAndrew Rybchenko emrp->emr_out_length_used = 0;
11265e111ed8SAndrew Rybchenko emrp->emr_rc = rc;
11275e111ed8SAndrew Rybchenko ++emip->emi_aborted;
11285e111ed8SAndrew Rybchenko }
11295e111ed8SAndrew Rybchenko
11305e111ed8SAndrew Rybchenko /*
11315e111ed8SAndrew Rybchenko * Since we're running in parallel with a request, consume the
11325e111ed8SAndrew Rybchenko * status word before dropping the lock.
11335e111ed8SAndrew Rybchenko */
11345e111ed8SAndrew Rybchenko if (rc == EIO || rc == EINTR) {
11355e111ed8SAndrew Rybchenko EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
11365e111ed8SAndrew Rybchenko (void) efx_mcdi_poll_reboot(enp);
11375e111ed8SAndrew Rybchenko emip->emi_new_epoch = B_TRUE;
11385e111ed8SAndrew Rybchenko }
11395e111ed8SAndrew Rybchenko
11405e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state);
11415e111ed8SAndrew Rybchenko
11425e111ed8SAndrew Rybchenko efx_mcdi_raise_exception(enp, emrp, rc);
11435e111ed8SAndrew Rybchenko
11445e111ed8SAndrew Rybchenko if (emrp != NULL && ev_cpl)
11455e111ed8SAndrew Rybchenko emtp->emt_ev_cpl(emtp->emt_context);
11465e111ed8SAndrew Rybchenko }
11475e111ed8SAndrew Rybchenko
11485e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_get_version(__in efx_nic_t * enp,__in uint32_t flags,__out efx_mcdi_version_t * verp)1149312191e8SIvan Malov efx_mcdi_get_version(
11505e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
1151df78fe71SIvan Malov __in uint32_t flags,
1152312191e8SIvan Malov __out efx_mcdi_version_t *verp)
11535e111ed8SAndrew Rybchenko {
1154833cfcd5SIvan Malov efx_nic_board_info_t *board_infop = &verp->emv_board_info;
11555e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload,
1156833cfcd5SIvan Malov MC_CMD_GET_VERSION_EXT_IN_LEN,
1157833cfcd5SIvan Malov MC_CMD_GET_VERSION_V2_OUT_LEN);
1158df78fe71SIvan Malov efx_word_t *ver_words;
1159df78fe71SIvan Malov uint16_t version[4];
1160312191e8SIvan Malov efx_mcdi_req_t req;
1161df78fe71SIvan Malov uint32_t firmware;
11625e111ed8SAndrew Rybchenko efx_rc_t rc;
11635e111ed8SAndrew Rybchenko
1164312191e8SIvan Malov EFX_STATIC_ASSERT(sizeof (verp->emv_version) ==
1165312191e8SIvan Malov MC_CMD_GET_VERSION_OUT_VERSION_LEN);
1166312191e8SIvan Malov EFX_STATIC_ASSERT(sizeof (verp->emv_firmware) ==
1167312191e8SIvan Malov MC_CMD_GET_VERSION_OUT_FIRMWARE_LEN);
1168312191e8SIvan Malov
1169833cfcd5SIvan Malov EFX_STATIC_ASSERT(EFX_MCDI_VERSION_BOARD_INFO ==
1170833cfcd5SIvan Malov (1U << MC_CMD_GET_VERSION_V2_OUT_BOARD_EXT_INFO_PRESENT_LBN));
1171833cfcd5SIvan Malov
1172833cfcd5SIvan Malov EFX_STATIC_ASSERT(sizeof (board_infop->enbi_serial) ==
1173833cfcd5SIvan Malov MC_CMD_GET_VERSION_V2_OUT_BOARD_SERIAL_LEN);
1174833cfcd5SIvan Malov EFX_STATIC_ASSERT(sizeof (board_infop->enbi_name) ==
1175833cfcd5SIvan Malov MC_CMD_GET_VERSION_V2_OUT_BOARD_NAME_LEN);
1176833cfcd5SIvan Malov EFX_STATIC_ASSERT(sizeof (board_infop->enbi_revision) ==
1177833cfcd5SIvan Malov MC_CMD_GET_VERSION_V2_OUT_BOARD_REVISION_LEN);
1178833cfcd5SIvan Malov
11795e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
11805e111ed8SAndrew Rybchenko
11815e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_VERSION;
11825e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
11835e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
1184833cfcd5SIvan Malov
1185df78fe71SIvan Malov if ((flags & EFX_MCDI_VERSION_BOARD_INFO) != 0) {
1186833cfcd5SIvan Malov /* Request basic + extended version information. */
1187833cfcd5SIvan Malov req.emr_in_length = MC_CMD_GET_VERSION_EXT_IN_LEN;
1188833cfcd5SIvan Malov req.emr_out_length = MC_CMD_GET_VERSION_V2_OUT_LEN;
1189833cfcd5SIvan Malov } else {
1190833cfcd5SIvan Malov /* Request only basic version information. */
1191312191e8SIvan Malov req.emr_in_length = MC_CMD_GET_VERSION_IN_LEN;
11925e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_GET_VERSION_OUT_LEN;
1193833cfcd5SIvan Malov }
1194312191e8SIvan Malov
11955e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req);
11965e111ed8SAndrew Rybchenko
11975e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
11985e111ed8SAndrew Rybchenko rc = req.emr_rc;
11995e111ed8SAndrew Rybchenko goto fail1;
12005e111ed8SAndrew Rybchenko }
12015e111ed8SAndrew Rybchenko
1202df78fe71SIvan Malov /* bootrom support */
1203df78fe71SIvan Malov if (req.emr_out_length_used == MC_CMD_GET_VERSION_V0_OUT_LEN) {
1204df78fe71SIvan Malov version[0] = version[1] = version[2] = version[3] = 0;
1205df78fe71SIvan Malov firmware = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
1206df78fe71SIvan Malov goto out;
1207df78fe71SIvan Malov }
1208df78fe71SIvan Malov
1209df78fe71SIvan Malov if (req.emr_out_length_used < req.emr_out_length) {
12105e111ed8SAndrew Rybchenko rc = EMSGSIZE;
12115e111ed8SAndrew Rybchenko goto fail2;
12125e111ed8SAndrew Rybchenko }
12135e111ed8SAndrew Rybchenko
1214df78fe71SIvan Malov ver_words = MCDI_OUT2(req, efx_word_t, GET_VERSION_OUT_VERSION);
1215df78fe71SIvan Malov version[0] = EFX_WORD_FIELD(ver_words[0], EFX_WORD_0);
1216df78fe71SIvan Malov version[1] = EFX_WORD_FIELD(ver_words[1], EFX_WORD_0);
1217df78fe71SIvan Malov version[2] = EFX_WORD_FIELD(ver_words[2], EFX_WORD_0);
1218df78fe71SIvan Malov version[3] = EFX_WORD_FIELD(ver_words[3], EFX_WORD_0);
1219df78fe71SIvan Malov firmware = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
1220df78fe71SIvan Malov
1221df78fe71SIvan Malov out:
1222312191e8SIvan Malov memset(verp, 0, sizeof (*verp));
12235e111ed8SAndrew Rybchenko
1224df78fe71SIvan Malov verp->emv_version[0] = version[0];
1225df78fe71SIvan Malov verp->emv_version[1] = version[1];
1226df78fe71SIvan Malov verp->emv_version[2] = version[2];
1227df78fe71SIvan Malov verp->emv_version[3] = version[3];
1228df78fe71SIvan Malov verp->emv_firmware = firmware;
1229312191e8SIvan Malov
1230833cfcd5SIvan Malov verp->emv_flags = MCDI_OUT_DWORD(req, GET_VERSION_V2_OUT_FLAGS);
1231df78fe71SIvan Malov verp->emv_flags &= flags;
1232833cfcd5SIvan Malov
1233833cfcd5SIvan Malov if ((verp->emv_flags & EFX_MCDI_VERSION_BOARD_INFO) != 0) {
1234833cfcd5SIvan Malov memcpy(board_infop->enbi_serial,
1235833cfcd5SIvan Malov MCDI_OUT2(req, char, GET_VERSION_V2_OUT_BOARD_SERIAL),
1236833cfcd5SIvan Malov sizeof (board_infop->enbi_serial));
1237833cfcd5SIvan Malov memcpy(board_infop->enbi_name,
1238833cfcd5SIvan Malov MCDI_OUT2(req, char, GET_VERSION_V2_OUT_BOARD_NAME),
1239833cfcd5SIvan Malov sizeof (board_infop->enbi_name));
1240833cfcd5SIvan Malov board_infop->enbi_revision =
1241833cfcd5SIvan Malov MCDI_OUT_DWORD(req, GET_VERSION_V2_OUT_BOARD_REVISION);
1242833cfcd5SIvan Malov }
1243833cfcd5SIvan Malov
1244312191e8SIvan Malov return (0);
1245312191e8SIvan Malov
1246312191e8SIvan Malov fail2:
1247312191e8SIvan Malov EFSYS_PROBE(fail2);
1248312191e8SIvan Malov fail1:
1249312191e8SIvan Malov EFSYS_PROBE1(fail1, efx_rc_t, rc);
1250312191e8SIvan Malov
1251312191e8SIvan Malov return (rc);
1252312191e8SIvan Malov }
1253312191e8SIvan Malov
1254312191e8SIvan Malov static __checkReturn efx_rc_t
efx_mcdi_get_boot_status(__in efx_nic_t * enp,__out efx_mcdi_boot_t * statusp)1255312191e8SIvan Malov efx_mcdi_get_boot_status(
1256312191e8SIvan Malov __in efx_nic_t *enp,
1257312191e8SIvan Malov __out efx_mcdi_boot_t *statusp)
1258312191e8SIvan Malov {
1259312191e8SIvan Malov EFX_MCDI_DECLARE_BUF(payload,
1260312191e8SIvan Malov MC_CMD_GET_BOOT_STATUS_IN_LEN,
1261312191e8SIvan Malov MC_CMD_GET_BOOT_STATUS_OUT_LEN);
1262312191e8SIvan Malov efx_mcdi_req_t req;
1263312191e8SIvan Malov efx_rc_t rc;
1264312191e8SIvan Malov
1265312191e8SIvan Malov EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
1266312191e8SIvan Malov
12675e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_BOOT_STATUS;
12685e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
12695e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_GET_BOOT_STATUS_IN_LEN;
12705e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
12715e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_GET_BOOT_STATUS_OUT_LEN;
12725e111ed8SAndrew Rybchenko
12735e111ed8SAndrew Rybchenko efx_mcdi_execute_quiet(enp, &req);
12745e111ed8SAndrew Rybchenko
1275df78fe71SIvan Malov /*
1276df78fe71SIvan Malov * NOTE: Unprivileged functions cannot access boot status,
1277df78fe71SIvan Malov * so the MCDI request will return EACCES. This is
1278df78fe71SIvan Malov * also checked in efx_mcdi_version.
1279df78fe71SIvan Malov */
1280df78fe71SIvan Malov
12815e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
12825e111ed8SAndrew Rybchenko rc = req.emr_rc;
1283312191e8SIvan Malov goto fail1;
12845e111ed8SAndrew Rybchenko }
12855e111ed8SAndrew Rybchenko
12865e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) {
12875e111ed8SAndrew Rybchenko rc = EMSGSIZE;
1288312191e8SIvan Malov goto fail2;
12895e111ed8SAndrew Rybchenko }
12905e111ed8SAndrew Rybchenko
12915e111ed8SAndrew Rybchenko if (MCDI_OUT_DWORD_FIELD(req, GET_BOOT_STATUS_OUT_FLAGS,
12925e111ed8SAndrew Rybchenko GET_BOOT_STATUS_OUT_FLAGS_PRIMARY))
1293312191e8SIvan Malov *statusp = EFX_MCDI_BOOT_PRIMARY;
12945e111ed8SAndrew Rybchenko else
1295312191e8SIvan Malov *statusp = EFX_MCDI_BOOT_SECONDARY;
1296312191e8SIvan Malov
1297312191e8SIvan Malov return (0);
1298312191e8SIvan Malov
1299312191e8SIvan Malov fail2:
1300312191e8SIvan Malov EFSYS_PROBE(fail2);
1301312191e8SIvan Malov fail1:
1302312191e8SIvan Malov EFSYS_PROBE1(fail1, efx_rc_t, rc);
1303312191e8SIvan Malov
1304312191e8SIvan Malov return (rc);
1305312191e8SIvan Malov }
1306312191e8SIvan Malov
1307312191e8SIvan Malov __checkReturn efx_rc_t
1308312191e8SIvan Malov efx_mcdi_version(
1309312191e8SIvan Malov __in efx_nic_t *enp,
1310312191e8SIvan Malov __out_ecount_opt(4) uint16_t versionp[4],
1311312191e8SIvan Malov __out_opt uint32_t *buildp,
1312312191e8SIvan Malov __out_opt efx_mcdi_boot_t *statusp)
1313312191e8SIvan Malov {
1314312191e8SIvan Malov efx_mcdi_version_t ver;
1315312191e8SIvan Malov efx_mcdi_boot_t status;
1316312191e8SIvan Malov efx_rc_t rc;
1317312191e8SIvan Malov
1318833cfcd5SIvan Malov rc = efx_mcdi_get_version(enp, 0, &ver);
1319312191e8SIvan Malov if (rc != 0)
1320312191e8SIvan Malov goto fail1;
1321312191e8SIvan Malov
1322312191e8SIvan Malov /* The bootrom doesn't understand BOOT_STATUS */
1323312191e8SIvan Malov if (MC_FW_VERSION_IS_BOOTLOADER(ver.emv_firmware)) {
1324312191e8SIvan Malov status = EFX_MCDI_BOOT_ROM;
1325312191e8SIvan Malov goto out;
1326312191e8SIvan Malov }
1327312191e8SIvan Malov
1328312191e8SIvan Malov rc = efx_mcdi_get_boot_status(enp, &status);
1329312191e8SIvan Malov if (rc == EACCES) {
1330312191e8SIvan Malov /* Unprivileged functions cannot access BOOT_STATUS */
1331312191e8SIvan Malov status = EFX_MCDI_BOOT_PRIMARY;
1332312191e8SIvan Malov memset(ver.emv_version, 0, sizeof (ver.emv_version));
1333312191e8SIvan Malov ver.emv_firmware = 0;
1334312191e8SIvan Malov } else if (rc != 0) {
1335312191e8SIvan Malov goto fail2;
1336312191e8SIvan Malov }
13375e111ed8SAndrew Rybchenko
13385e111ed8SAndrew Rybchenko out:
13395e111ed8SAndrew Rybchenko if (versionp != NULL)
1340312191e8SIvan Malov memcpy(versionp, ver.emv_version, sizeof (ver.emv_version));
13415e111ed8SAndrew Rybchenko if (buildp != NULL)
1342312191e8SIvan Malov *buildp = ver.emv_firmware;
13435e111ed8SAndrew Rybchenko if (statusp != NULL)
13445e111ed8SAndrew Rybchenko *statusp = status;
13455e111ed8SAndrew Rybchenko
13465e111ed8SAndrew Rybchenko return (0);
13475e111ed8SAndrew Rybchenko
13485e111ed8SAndrew Rybchenko fail2:
13495e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
13505e111ed8SAndrew Rybchenko fail1:
13515e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
13525e111ed8SAndrew Rybchenko
13535e111ed8SAndrew Rybchenko return (rc);
13545e111ed8SAndrew Rybchenko }
13555e111ed8SAndrew Rybchenko
13565e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_get_capabilities(__in efx_nic_t * enp,__out_opt uint32_t * flagsp,__out_opt uint16_t * rx_dpcpu_fw_idp,__out_opt uint16_t * tx_dpcpu_fw_idp,__out_opt uint32_t * flags2p,__out_opt uint32_t * tso2ncp)13575e111ed8SAndrew Rybchenko efx_mcdi_get_capabilities(
13585e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
13595e111ed8SAndrew Rybchenko __out_opt uint32_t *flagsp,
13605e111ed8SAndrew Rybchenko __out_opt uint16_t *rx_dpcpu_fw_idp,
13615e111ed8SAndrew Rybchenko __out_opt uint16_t *tx_dpcpu_fw_idp,
13625e111ed8SAndrew Rybchenko __out_opt uint32_t *flags2p,
13635e111ed8SAndrew Rybchenko __out_opt uint32_t *tso2ncp)
13645e111ed8SAndrew Rybchenko {
13655e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
13665e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_CAPABILITIES_IN_LEN,
13675e111ed8SAndrew Rybchenko MC_CMD_GET_CAPABILITIES_V2_OUT_LEN);
13685e111ed8SAndrew Rybchenko boolean_t v2_capable;
13695e111ed8SAndrew Rybchenko efx_rc_t rc;
13705e111ed8SAndrew Rybchenko
13715e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_CAPABILITIES;
13725e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
13735e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN;
13745e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
13755e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_GET_CAPABILITIES_V2_OUT_LEN;
13765e111ed8SAndrew Rybchenko
13775e111ed8SAndrew Rybchenko efx_mcdi_execute_quiet(enp, &req);
13785e111ed8SAndrew Rybchenko
13795e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
13805e111ed8SAndrew Rybchenko rc = req.emr_rc;
13815e111ed8SAndrew Rybchenko goto fail1;
13825e111ed8SAndrew Rybchenko }
13835e111ed8SAndrew Rybchenko
13845e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_OUT_LEN) {
13855e111ed8SAndrew Rybchenko rc = EMSGSIZE;
13865e111ed8SAndrew Rybchenko goto fail2;
13875e111ed8SAndrew Rybchenko }
13885e111ed8SAndrew Rybchenko
13895e111ed8SAndrew Rybchenko if (flagsp != NULL)
13905e111ed8SAndrew Rybchenko *flagsp = MCDI_OUT_DWORD(req, GET_CAPABILITIES_OUT_FLAGS1);
13915e111ed8SAndrew Rybchenko
13925e111ed8SAndrew Rybchenko if (rx_dpcpu_fw_idp != NULL)
13935e111ed8SAndrew Rybchenko *rx_dpcpu_fw_idp = MCDI_OUT_WORD(req,
13945e111ed8SAndrew Rybchenko GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID);
13955e111ed8SAndrew Rybchenko
13965e111ed8SAndrew Rybchenko if (tx_dpcpu_fw_idp != NULL)
13975e111ed8SAndrew Rybchenko *tx_dpcpu_fw_idp = MCDI_OUT_WORD(req,
13985e111ed8SAndrew Rybchenko GET_CAPABILITIES_OUT_TX_DPCPU_FW_ID);
13995e111ed8SAndrew Rybchenko
14005e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_V2_OUT_LEN)
14015e111ed8SAndrew Rybchenko v2_capable = B_FALSE;
14025e111ed8SAndrew Rybchenko else
14035e111ed8SAndrew Rybchenko v2_capable = B_TRUE;
14045e111ed8SAndrew Rybchenko
14055e111ed8SAndrew Rybchenko if (flags2p != NULL) {
14065e111ed8SAndrew Rybchenko *flags2p = (v2_capable) ?
14075e111ed8SAndrew Rybchenko MCDI_OUT_DWORD(req, GET_CAPABILITIES_V2_OUT_FLAGS2) :
14085e111ed8SAndrew Rybchenko 0;
14095e111ed8SAndrew Rybchenko }
14105e111ed8SAndrew Rybchenko
14115e111ed8SAndrew Rybchenko if (tso2ncp != NULL) {
14125e111ed8SAndrew Rybchenko *tso2ncp = (v2_capable) ?
14135e111ed8SAndrew Rybchenko MCDI_OUT_WORD(req,
14145e111ed8SAndrew Rybchenko GET_CAPABILITIES_V2_OUT_TX_TSO_V2_N_CONTEXTS) :
14155e111ed8SAndrew Rybchenko 0;
14165e111ed8SAndrew Rybchenko }
14175e111ed8SAndrew Rybchenko
14185e111ed8SAndrew Rybchenko return (0);
14195e111ed8SAndrew Rybchenko
14205e111ed8SAndrew Rybchenko fail2:
14215e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
14225e111ed8SAndrew Rybchenko fail1:
14235e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
14245e111ed8SAndrew Rybchenko
14255e111ed8SAndrew Rybchenko return (rc);
14265e111ed8SAndrew Rybchenko }
14275e111ed8SAndrew Rybchenko
14285e111ed8SAndrew Rybchenko static __checkReturn efx_rc_t
efx_mcdi_do_reboot(__in efx_nic_t * enp,__in boolean_t after_assertion)14295e111ed8SAndrew Rybchenko efx_mcdi_do_reboot(
14305e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
14315e111ed8SAndrew Rybchenko __in boolean_t after_assertion)
14325e111ed8SAndrew Rybchenko {
14335e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_REBOOT_IN_LEN,
14345e111ed8SAndrew Rybchenko MC_CMD_REBOOT_OUT_LEN);
14355e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
14365e111ed8SAndrew Rybchenko efx_rc_t rc;
14375e111ed8SAndrew Rybchenko
14385e111ed8SAndrew Rybchenko /*
14395e111ed8SAndrew Rybchenko * We could require the caller to have caused en_mod_flags=0 to
14405e111ed8SAndrew Rybchenko * call this function. This doesn't help the other port though,
14415e111ed8SAndrew Rybchenko * who's about to get the MC ripped out from underneath them.
14425e111ed8SAndrew Rybchenko * Since they have to cope with the subsequent fallout of MCDI
14435e111ed8SAndrew Rybchenko * failures, we should as well.
14445e111ed8SAndrew Rybchenko */
14455e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
14465e111ed8SAndrew Rybchenko
14475e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_REBOOT;
14485e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
14495e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_REBOOT_IN_LEN;
14505e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
14515e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_REBOOT_OUT_LEN;
14525e111ed8SAndrew Rybchenko
14535e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS,
14545e111ed8SAndrew Rybchenko (after_assertion ? MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION : 0));
14555e111ed8SAndrew Rybchenko
14565e111ed8SAndrew Rybchenko efx_mcdi_execute_quiet(enp, &req);
14575e111ed8SAndrew Rybchenko
14585e111ed8SAndrew Rybchenko if (req.emr_rc == EACCES) {
14595e111ed8SAndrew Rybchenko /* Unprivileged functions cannot reboot the MC. */
14605e111ed8SAndrew Rybchenko goto out;
14615e111ed8SAndrew Rybchenko }
14625e111ed8SAndrew Rybchenko
14635e111ed8SAndrew Rybchenko /* A successful reboot request returns EIO. */
14645e111ed8SAndrew Rybchenko if (req.emr_rc != 0 && req.emr_rc != EIO) {
14655e111ed8SAndrew Rybchenko rc = req.emr_rc;
14665e111ed8SAndrew Rybchenko goto fail1;
14675e111ed8SAndrew Rybchenko }
14685e111ed8SAndrew Rybchenko
14695e111ed8SAndrew Rybchenko out:
14705e111ed8SAndrew Rybchenko return (0);
14715e111ed8SAndrew Rybchenko
14725e111ed8SAndrew Rybchenko fail1:
14735e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
14745e111ed8SAndrew Rybchenko
14755e111ed8SAndrew Rybchenko return (rc);
14765e111ed8SAndrew Rybchenko }
14775e111ed8SAndrew Rybchenko
14785e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_reboot(__in efx_nic_t * enp)14795e111ed8SAndrew Rybchenko efx_mcdi_reboot(
14805e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
14815e111ed8SAndrew Rybchenko {
14825e111ed8SAndrew Rybchenko return (efx_mcdi_do_reboot(enp, B_FALSE));
14835e111ed8SAndrew Rybchenko }
14845e111ed8SAndrew Rybchenko
14855e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_exit_assertion_handler(__in efx_nic_t * enp)14865e111ed8SAndrew Rybchenko efx_mcdi_exit_assertion_handler(
14875e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
14885e111ed8SAndrew Rybchenko {
14895e111ed8SAndrew Rybchenko return (efx_mcdi_do_reboot(enp, B_TRUE));
14905e111ed8SAndrew Rybchenko }
14915e111ed8SAndrew Rybchenko
14925e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_read_assertion(__in efx_nic_t * enp)14935e111ed8SAndrew Rybchenko efx_mcdi_read_assertion(
14945e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
14955e111ed8SAndrew Rybchenko {
14965e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
14975e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_ASSERTS_IN_LEN,
14985e111ed8SAndrew Rybchenko MC_CMD_GET_ASSERTS_OUT_LEN);
14995e111ed8SAndrew Rybchenko const char *reason;
15005e111ed8SAndrew Rybchenko unsigned int flags;
15015e111ed8SAndrew Rybchenko unsigned int index;
15025e111ed8SAndrew Rybchenko unsigned int ofst;
15035e111ed8SAndrew Rybchenko int retry;
15045e111ed8SAndrew Rybchenko efx_rc_t rc;
15055e111ed8SAndrew Rybchenko
15065e111ed8SAndrew Rybchenko /*
15075e111ed8SAndrew Rybchenko * Before we attempt to chat to the MC, we should verify that the MC
15085e111ed8SAndrew Rybchenko * isn't in it's assertion handler, either due to a previous reboot,
15095e111ed8SAndrew Rybchenko * or because we're reinitializing due to an eec_exception().
15105e111ed8SAndrew Rybchenko *
15115e111ed8SAndrew Rybchenko * Use GET_ASSERTS to read any assertion state that may be present.
15125e111ed8SAndrew Rybchenko * Retry this command twice. Once because a boot-time assertion failure
15135e111ed8SAndrew Rybchenko * might cause the 1st MCDI request to fail. And once again because
15145e111ed8SAndrew Rybchenko * we might race with efx_mcdi_exit_assertion_handler() running on
15155e111ed8SAndrew Rybchenko * partner port(s) on the same NIC.
15165e111ed8SAndrew Rybchenko */
15175e111ed8SAndrew Rybchenko retry = 2;
15185e111ed8SAndrew Rybchenko do {
15195e111ed8SAndrew Rybchenko (void) memset(payload, 0, sizeof (payload));
15205e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_ASSERTS;
15215e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
15225e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_GET_ASSERTS_IN_LEN;
15235e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
15245e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_GET_ASSERTS_OUT_LEN;
15255e111ed8SAndrew Rybchenko
15265e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1);
15275e111ed8SAndrew Rybchenko efx_mcdi_execute_quiet(enp, &req);
15285e111ed8SAndrew Rybchenko
15295e111ed8SAndrew Rybchenko } while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0);
15305e111ed8SAndrew Rybchenko
15315e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
15325e111ed8SAndrew Rybchenko if (req.emr_rc == EACCES) {
15335e111ed8SAndrew Rybchenko /* Unprivileged functions cannot clear assertions. */
15345e111ed8SAndrew Rybchenko goto out;
15355e111ed8SAndrew Rybchenko }
15365e111ed8SAndrew Rybchenko rc = req.emr_rc;
15375e111ed8SAndrew Rybchenko goto fail1;
15385e111ed8SAndrew Rybchenko }
15395e111ed8SAndrew Rybchenko
15405e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) {
15415e111ed8SAndrew Rybchenko rc = EMSGSIZE;
15425e111ed8SAndrew Rybchenko goto fail2;
15435e111ed8SAndrew Rybchenko }
15445e111ed8SAndrew Rybchenko
15455e111ed8SAndrew Rybchenko /* Print out any assertion state recorded */
15465e111ed8SAndrew Rybchenko flags = MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_GLOBAL_FLAGS);
15475e111ed8SAndrew Rybchenko if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
15485e111ed8SAndrew Rybchenko return (0);
15495e111ed8SAndrew Rybchenko
15505e111ed8SAndrew Rybchenko reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
15515e111ed8SAndrew Rybchenko ? "system-level assertion"
15525e111ed8SAndrew Rybchenko : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
15535e111ed8SAndrew Rybchenko ? "thread-level assertion"
15545e111ed8SAndrew Rybchenko : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
15555e111ed8SAndrew Rybchenko ? "watchdog reset"
15565e111ed8SAndrew Rybchenko : (flags == MC_CMD_GET_ASSERTS_FLAGS_ADDR_TRAP)
15575e111ed8SAndrew Rybchenko ? "illegal address trap"
15585e111ed8SAndrew Rybchenko : "unknown assertion";
15595e111ed8SAndrew Rybchenko EFSYS_PROBE3(mcpu_assertion,
15605e111ed8SAndrew Rybchenko const char *, reason, unsigned int,
15615e111ed8SAndrew Rybchenko MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_SAVED_PC_OFFS),
15625e111ed8SAndrew Rybchenko unsigned int,
15635e111ed8SAndrew Rybchenko MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS));
15645e111ed8SAndrew Rybchenko
15655e111ed8SAndrew Rybchenko /* Print out the registers (r1 ... r31) */
15665e111ed8SAndrew Rybchenko ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST;
15675e111ed8SAndrew Rybchenko for (index = 1;
15685e111ed8SAndrew Rybchenko index < 1 + MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM;
15695e111ed8SAndrew Rybchenko index++) {
15705e111ed8SAndrew Rybchenko EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int,
15715e111ed8SAndrew Rybchenko EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst),
15725e111ed8SAndrew Rybchenko EFX_DWORD_0));
15735e111ed8SAndrew Rybchenko ofst += sizeof (efx_dword_t);
15745e111ed8SAndrew Rybchenko }
15755e111ed8SAndrew Rybchenko EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN);
15765e111ed8SAndrew Rybchenko
15775e111ed8SAndrew Rybchenko out:
15785e111ed8SAndrew Rybchenko return (0);
15795e111ed8SAndrew Rybchenko
15805e111ed8SAndrew Rybchenko fail2:
15815e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
15825e111ed8SAndrew Rybchenko fail1:
15835e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
15845e111ed8SAndrew Rybchenko
15855e111ed8SAndrew Rybchenko return (rc);
15865e111ed8SAndrew Rybchenko }
15875e111ed8SAndrew Rybchenko
15885e111ed8SAndrew Rybchenko
15895e111ed8SAndrew Rybchenko /*
15905e111ed8SAndrew Rybchenko * Internal routines for for specific MCDI requests.
15915e111ed8SAndrew Rybchenko */
15925e111ed8SAndrew Rybchenko
15935e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_drv_attach(__in efx_nic_t * enp,__in boolean_t attach)15945e111ed8SAndrew Rybchenko efx_mcdi_drv_attach(
15955e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
15965e111ed8SAndrew Rybchenko __in boolean_t attach)
15975e111ed8SAndrew Rybchenko {
15985e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
15995e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_DRV_ATTACH_IN_V2_LEN,
16005e111ed8SAndrew Rybchenko MC_CMD_DRV_ATTACH_EXT_OUT_LEN);
16015e111ed8SAndrew Rybchenko efx_rc_t rc;
16025e111ed8SAndrew Rybchenko
16035e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_DRV_ATTACH;
16045e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
16055e111ed8SAndrew Rybchenko if (enp->en_drv_version[0] == '\0') {
16065e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_DRV_ATTACH_IN_LEN;
16075e111ed8SAndrew Rybchenko } else {
16085e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_DRV_ATTACH_IN_V2_LEN;
16095e111ed8SAndrew Rybchenko }
16105e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
16115e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_DRV_ATTACH_EXT_OUT_LEN;
16125e111ed8SAndrew Rybchenko
16135e111ed8SAndrew Rybchenko /*
16145e111ed8SAndrew Rybchenko * Typically, client drivers use DONT_CARE for the datapath firmware
16155e111ed8SAndrew Rybchenko * type to ensure that the driver can attach to an unprivileged
16165e111ed8SAndrew Rybchenko * function. The datapath firmware type to use is controlled by the
16175e111ed8SAndrew Rybchenko * 'sfboot' utility.
16185e111ed8SAndrew Rybchenko * If a client driver wishes to attach with a specific datapath firmware
16195e111ed8SAndrew Rybchenko * type, that can be passed in second argument of efx_nic_probe API. One
16205e111ed8SAndrew Rybchenko * such example is the ESXi native driver that attempts attaching with
16215e111ed8SAndrew Rybchenko * FULL_FEATURED datapath firmware type first and fall backs to
16225e111ed8SAndrew Rybchenko * DONT_CARE datapath firmware type if MC_CMD_DRV_ATTACH fails.
1623*80e33a28SIvan Malov *
1624*80e33a28SIvan Malov * Always set WANT_V2_LINKCHANGES to 1. Old firmware that only supports
1625*80e33a28SIvan Malov * v1 will ignore it, and for newer firmware it ensures that it always
1626*80e33a28SIvan Malov * sends v2 if possible. While EF100 always uses v2, there are some
1627*80e33a28SIvan Malov * older EF10 firmwares that only send v2 if it is requested.
16285e111ed8SAndrew Rybchenko */
1629*80e33a28SIvan Malov MCDI_IN_POPULATE_DWORD_3(req, DRV_ATTACH_IN_NEW_STATE,
16305e111ed8SAndrew Rybchenko DRV_ATTACH_IN_ATTACH, attach ? 1 : 0,
1631*80e33a28SIvan Malov DRV_ATTACH_IN_SUBVARIANT_AWARE, EFSYS_OPT_FW_SUBVARIANT_AWARE,
1632*80e33a28SIvan Malov DRV_ATTACH_IN_WANT_V2_LINKCHANGES, 1);
16335e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_UPDATE, 1);
16345e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_FIRMWARE_ID, enp->efv);
16355e111ed8SAndrew Rybchenko
16365e111ed8SAndrew Rybchenko if (req.emr_in_length >= MC_CMD_DRV_ATTACH_IN_V2_LEN) {
16375e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(sizeof (enp->en_drv_version) ==
16385e111ed8SAndrew Rybchenko MC_CMD_DRV_ATTACH_IN_V2_DRIVER_VERSION_LEN);
16395e111ed8SAndrew Rybchenko memcpy(MCDI_IN2(req, char, DRV_ATTACH_IN_V2_DRIVER_VERSION),
16405e111ed8SAndrew Rybchenko enp->en_drv_version,
16415e111ed8SAndrew Rybchenko MC_CMD_DRV_ATTACH_IN_V2_DRIVER_VERSION_LEN);
16425e111ed8SAndrew Rybchenko }
16435e111ed8SAndrew Rybchenko
16445e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req);
16455e111ed8SAndrew Rybchenko
16465e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
16475e111ed8SAndrew Rybchenko rc = req.emr_rc;
16485e111ed8SAndrew Rybchenko goto fail1;
16495e111ed8SAndrew Rybchenko }
16505e111ed8SAndrew Rybchenko
16515e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) {
16525e111ed8SAndrew Rybchenko rc = EMSGSIZE;
16535e111ed8SAndrew Rybchenko goto fail2;
16545e111ed8SAndrew Rybchenko }
16555e111ed8SAndrew Rybchenko
16565e111ed8SAndrew Rybchenko return (0);
16575e111ed8SAndrew Rybchenko
16585e111ed8SAndrew Rybchenko fail2:
16595e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
16605e111ed8SAndrew Rybchenko fail1:
16615e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
16625e111ed8SAndrew Rybchenko
16635e111ed8SAndrew Rybchenko return (rc);
16645e111ed8SAndrew Rybchenko }
16655e111ed8SAndrew Rybchenko
16665e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
16675e111ed8SAndrew Rybchenko efx_mcdi_get_board_cfg(
16685e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
16695e111ed8SAndrew Rybchenko __out_opt uint32_t *board_typep,
16705e111ed8SAndrew Rybchenko __out_opt efx_dword_t *capabilitiesp,
16715e111ed8SAndrew Rybchenko __out_ecount_opt(6) uint8_t mac_addrp[6])
16725e111ed8SAndrew Rybchenko {
16735e111ed8SAndrew Rybchenko efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
16745e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
16755e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_BOARD_CFG_IN_LEN,
16765e111ed8SAndrew Rybchenko MC_CMD_GET_BOARD_CFG_OUT_LENMIN);
16775e111ed8SAndrew Rybchenko efx_rc_t rc;
16785e111ed8SAndrew Rybchenko
16795e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_BOARD_CFG;
16805e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
16815e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN;
16825e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
16835e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMIN;
16845e111ed8SAndrew Rybchenko
16855e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req);
16865e111ed8SAndrew Rybchenko
16875e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
16885e111ed8SAndrew Rybchenko rc = req.emr_rc;
16895e111ed8SAndrew Rybchenko goto fail1;
16905e111ed8SAndrew Rybchenko }
16915e111ed8SAndrew Rybchenko
16925e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
16935e111ed8SAndrew Rybchenko rc = EMSGSIZE;
16945e111ed8SAndrew Rybchenko goto fail2;
16955e111ed8SAndrew Rybchenko }
16965e111ed8SAndrew Rybchenko
16975e111ed8SAndrew Rybchenko if (mac_addrp != NULL) {
16985e111ed8SAndrew Rybchenko uint8_t *addrp;
16995e111ed8SAndrew Rybchenko
17005e111ed8SAndrew Rybchenko if (emip->emi_port == 1) {
17015e111ed8SAndrew Rybchenko addrp = MCDI_OUT2(req, uint8_t,
17025e111ed8SAndrew Rybchenko GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0);
17035e111ed8SAndrew Rybchenko } else if (emip->emi_port == 2) {
17045e111ed8SAndrew Rybchenko addrp = MCDI_OUT2(req, uint8_t,
17055e111ed8SAndrew Rybchenko GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1);
17065e111ed8SAndrew Rybchenko } else {
17075e111ed8SAndrew Rybchenko rc = EINVAL;
17085e111ed8SAndrew Rybchenko goto fail3;
17095e111ed8SAndrew Rybchenko }
17105e111ed8SAndrew Rybchenko
17115e111ed8SAndrew Rybchenko EFX_MAC_ADDR_COPY(mac_addrp, addrp);
17125e111ed8SAndrew Rybchenko }
17135e111ed8SAndrew Rybchenko
17145e111ed8SAndrew Rybchenko if (capabilitiesp != NULL) {
17155e111ed8SAndrew Rybchenko if (emip->emi_port == 1) {
17165e111ed8SAndrew Rybchenko *capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
17175e111ed8SAndrew Rybchenko GET_BOARD_CFG_OUT_CAPABILITIES_PORT0);
17185e111ed8SAndrew Rybchenko } else if (emip->emi_port == 2) {
17195e111ed8SAndrew Rybchenko *capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
17205e111ed8SAndrew Rybchenko GET_BOARD_CFG_OUT_CAPABILITIES_PORT1);
17215e111ed8SAndrew Rybchenko } else {
17225e111ed8SAndrew Rybchenko rc = EINVAL;
17235e111ed8SAndrew Rybchenko goto fail4;
17245e111ed8SAndrew Rybchenko }
17255e111ed8SAndrew Rybchenko }
17265e111ed8SAndrew Rybchenko
17275e111ed8SAndrew Rybchenko if (board_typep != NULL) {
17285e111ed8SAndrew Rybchenko *board_typep = MCDI_OUT_DWORD(req,
17295e111ed8SAndrew Rybchenko GET_BOARD_CFG_OUT_BOARD_TYPE);
17305e111ed8SAndrew Rybchenko }
17315e111ed8SAndrew Rybchenko
17325e111ed8SAndrew Rybchenko return (0);
17335e111ed8SAndrew Rybchenko
17345e111ed8SAndrew Rybchenko fail4:
17355e111ed8SAndrew Rybchenko EFSYS_PROBE(fail4);
17365e111ed8SAndrew Rybchenko fail3:
17375e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3);
17385e111ed8SAndrew Rybchenko fail2:
17395e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
17405e111ed8SAndrew Rybchenko fail1:
17415e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
17425e111ed8SAndrew Rybchenko
17435e111ed8SAndrew Rybchenko return (rc);
17445e111ed8SAndrew Rybchenko }
17455e111ed8SAndrew Rybchenko
17465e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_get_resource_limits(__in efx_nic_t * enp,__out_opt uint32_t * nevqp,__out_opt uint32_t * nrxqp,__out_opt uint32_t * ntxqp)17475e111ed8SAndrew Rybchenko efx_mcdi_get_resource_limits(
17485e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
17495e111ed8SAndrew Rybchenko __out_opt uint32_t *nevqp,
17505e111ed8SAndrew Rybchenko __out_opt uint32_t *nrxqp,
17515e111ed8SAndrew Rybchenko __out_opt uint32_t *ntxqp)
17525e111ed8SAndrew Rybchenko {
17535e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
17545e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_RESOURCE_LIMITS_IN_LEN,
17555e111ed8SAndrew Rybchenko MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN);
17565e111ed8SAndrew Rybchenko efx_rc_t rc;
17575e111ed8SAndrew Rybchenko
17585e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_RESOURCE_LIMITS;
17595e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
17605e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_GET_RESOURCE_LIMITS_IN_LEN;
17615e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
17625e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN;
17635e111ed8SAndrew Rybchenko
17645e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req);
17655e111ed8SAndrew Rybchenko
17665e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
17675e111ed8SAndrew Rybchenko rc = req.emr_rc;
17685e111ed8SAndrew Rybchenko goto fail1;
17695e111ed8SAndrew Rybchenko }
17705e111ed8SAndrew Rybchenko
17715e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) {
17725e111ed8SAndrew Rybchenko rc = EMSGSIZE;
17735e111ed8SAndrew Rybchenko goto fail2;
17745e111ed8SAndrew Rybchenko }
17755e111ed8SAndrew Rybchenko
17765e111ed8SAndrew Rybchenko if (nevqp != NULL)
17775e111ed8SAndrew Rybchenko *nevqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_EVQ);
17785e111ed8SAndrew Rybchenko if (nrxqp != NULL)
17795e111ed8SAndrew Rybchenko *nrxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ);
17805e111ed8SAndrew Rybchenko if (ntxqp != NULL)
17815e111ed8SAndrew Rybchenko *ntxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ);
17825e111ed8SAndrew Rybchenko
17835e111ed8SAndrew Rybchenko return (0);
17845e111ed8SAndrew Rybchenko
17855e111ed8SAndrew Rybchenko fail2:
17865e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
17875e111ed8SAndrew Rybchenko fail1:
17885e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
17895e111ed8SAndrew Rybchenko
17905e111ed8SAndrew Rybchenko return (rc);
17915e111ed8SAndrew Rybchenko }
17925e111ed8SAndrew Rybchenko
17935e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_get_phy_cfg(__in efx_nic_t * enp)17945e111ed8SAndrew Rybchenko efx_mcdi_get_phy_cfg(
17955e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
17965e111ed8SAndrew Rybchenko {
17975e111ed8SAndrew Rybchenko efx_port_t *epp = &(enp->en_port);
17985e111ed8SAndrew Rybchenko efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
17995e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
18005e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PHY_CFG_IN_LEN,
18015e111ed8SAndrew Rybchenko MC_CMD_GET_PHY_CFG_OUT_LEN);
18025e111ed8SAndrew Rybchenko #if EFSYS_OPT_NAMES
18035e111ed8SAndrew Rybchenko const char *namep;
18045e111ed8SAndrew Rybchenko size_t namelen;
18055e111ed8SAndrew Rybchenko #endif
18065e111ed8SAndrew Rybchenko uint32_t phy_media_type;
18075e111ed8SAndrew Rybchenko efx_rc_t rc;
18085e111ed8SAndrew Rybchenko
18095e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_PHY_CFG;
18105e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
18115e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_GET_PHY_CFG_IN_LEN;
18125e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
18135e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_GET_PHY_CFG_OUT_LEN;
18145e111ed8SAndrew Rybchenko
18155e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req);
18165e111ed8SAndrew Rybchenko
18175e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
18185e111ed8SAndrew Rybchenko rc = req.emr_rc;
18195e111ed8SAndrew Rybchenko goto fail1;
18205e111ed8SAndrew Rybchenko }
18215e111ed8SAndrew Rybchenko
18225e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) {
18235e111ed8SAndrew Rybchenko rc = EMSGSIZE;
18245e111ed8SAndrew Rybchenko goto fail2;
18255e111ed8SAndrew Rybchenko }
18265e111ed8SAndrew Rybchenko
18275e111ed8SAndrew Rybchenko encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE);
18285e111ed8SAndrew Rybchenko #if EFSYS_OPT_NAMES
18295e111ed8SAndrew Rybchenko namep = MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME);
18305e111ed8SAndrew Rybchenko namelen = MIN(sizeof (encp->enc_phy_name) - 1,
18315e111ed8SAndrew Rybchenko strnlen(namep, MC_CMD_GET_PHY_CFG_OUT_NAME_LEN));
18325e111ed8SAndrew Rybchenko (void) memset(encp->enc_phy_name, 0,
18335e111ed8SAndrew Rybchenko sizeof (encp->enc_phy_name));
18345e111ed8SAndrew Rybchenko memcpy(encp->enc_phy_name, namep, namelen);
18355e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_NAMES */
18365e111ed8SAndrew Rybchenko (void) memset(encp->enc_phy_revision, 0,
18375e111ed8SAndrew Rybchenko sizeof (encp->enc_phy_revision));
18385e111ed8SAndrew Rybchenko memcpy(encp->enc_phy_revision,
18395e111ed8SAndrew Rybchenko MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION),
18405e111ed8SAndrew Rybchenko MIN(sizeof (encp->enc_phy_revision) - 1,
18415e111ed8SAndrew Rybchenko MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN));
18425e111ed8SAndrew Rybchenko #if EFSYS_OPT_PHY_LED_CONTROL
18435e111ed8SAndrew Rybchenko encp->enc_led_mask = ((1 << EFX_PHY_LED_DEFAULT) |
18445e111ed8SAndrew Rybchenko (1 << EFX_PHY_LED_OFF) |
18455e111ed8SAndrew Rybchenko (1 << EFX_PHY_LED_ON));
18465e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_PHY_LED_CONTROL */
18475e111ed8SAndrew Rybchenko
18485e111ed8SAndrew Rybchenko /* Get the media type of the fixed port, if recognised. */
18495e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI);
18505e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4);
18515e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4);
18525e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP);
18535e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS);
18545e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T);
18555e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_MEDIA_QSFP_PLUS == EFX_PHY_MEDIA_QSFP_PLUS);
18565e111ed8SAndrew Rybchenko phy_media_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE);
18575e111ed8SAndrew Rybchenko epp->ep_fixed_port_type = (efx_phy_media_type_t)phy_media_type;
18585e111ed8SAndrew Rybchenko if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES)
18595e111ed8SAndrew Rybchenko epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID;
18605e111ed8SAndrew Rybchenko
18615e111ed8SAndrew Rybchenko epp->ep_phy_cap_mask =
18625e111ed8SAndrew Rybchenko MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP);
18635e111ed8SAndrew Rybchenko #if EFSYS_OPT_PHY_FLAGS
18645e111ed8SAndrew Rybchenko encp->enc_phy_flags_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_FLAGS);
18655e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_PHY_FLAGS */
18665e111ed8SAndrew Rybchenko
18675e111ed8SAndrew Rybchenko encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT);
18685e111ed8SAndrew Rybchenko
18695e111ed8SAndrew Rybchenko /* Populate internal state */
18705e111ed8SAndrew Rybchenko encp->enc_mcdi_mdio_channel =
18715e111ed8SAndrew Rybchenko (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL);
18725e111ed8SAndrew Rybchenko
18735e111ed8SAndrew Rybchenko #if EFSYS_OPT_PHY_STATS
18745e111ed8SAndrew Rybchenko encp->enc_mcdi_phy_stat_mask =
18755e111ed8SAndrew Rybchenko MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_STATS_MASK);
18765e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_PHY_STATS */
18775e111ed8SAndrew Rybchenko
18785e111ed8SAndrew Rybchenko #if EFSYS_OPT_BIST
18795e111ed8SAndrew Rybchenko encp->enc_bist_mask = 0;
18805e111ed8SAndrew Rybchenko if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
18815e111ed8SAndrew Rybchenko GET_PHY_CFG_OUT_BIST_CABLE_SHORT))
18825e111ed8SAndrew Rybchenko encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_SHORT);
18835e111ed8SAndrew Rybchenko if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
18845e111ed8SAndrew Rybchenko GET_PHY_CFG_OUT_BIST_CABLE_LONG))
18855e111ed8SAndrew Rybchenko encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_LONG);
18865e111ed8SAndrew Rybchenko if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
18875e111ed8SAndrew Rybchenko GET_PHY_CFG_OUT_BIST))
18885e111ed8SAndrew Rybchenko encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_NORMAL);
18895e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_BIST */
18905e111ed8SAndrew Rybchenko
18915e111ed8SAndrew Rybchenko return (0);
18925e111ed8SAndrew Rybchenko
18935e111ed8SAndrew Rybchenko fail2:
18945e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
18955e111ed8SAndrew Rybchenko fail1:
18965e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
18975e111ed8SAndrew Rybchenko
18985e111ed8SAndrew Rybchenko return (rc);
18995e111ed8SAndrew Rybchenko }
19005e111ed8SAndrew Rybchenko
19015e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_firmware_update_supported(__in efx_nic_t * enp,__out boolean_t * supportedp)19025e111ed8SAndrew Rybchenko efx_mcdi_firmware_update_supported(
19035e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
19045e111ed8SAndrew Rybchenko __out boolean_t *supportedp)
19055e111ed8SAndrew Rybchenko {
19065e111ed8SAndrew Rybchenko const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
19075e111ed8SAndrew Rybchenko efx_rc_t rc;
19085e111ed8SAndrew Rybchenko
19095e111ed8SAndrew Rybchenko if (emcop != NULL) {
19105e111ed8SAndrew Rybchenko if ((rc = emcop->emco_feature_supported(enp,
19115e111ed8SAndrew Rybchenko EFX_MCDI_FEATURE_FW_UPDATE, supportedp)) != 0)
19125e111ed8SAndrew Rybchenko goto fail1;
19135e111ed8SAndrew Rybchenko } else {
19145e111ed8SAndrew Rybchenko /* Earlier devices always supported updates */
19155e111ed8SAndrew Rybchenko *supportedp = B_TRUE;
19165e111ed8SAndrew Rybchenko }
19175e111ed8SAndrew Rybchenko
19185e111ed8SAndrew Rybchenko return (0);
19195e111ed8SAndrew Rybchenko
19205e111ed8SAndrew Rybchenko fail1:
19215e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
19225e111ed8SAndrew Rybchenko
19235e111ed8SAndrew Rybchenko return (rc);
19245e111ed8SAndrew Rybchenko }
19255e111ed8SAndrew Rybchenko
19265e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_macaddr_change_supported(__in efx_nic_t * enp,__out boolean_t * supportedp)19275e111ed8SAndrew Rybchenko efx_mcdi_macaddr_change_supported(
19285e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
19295e111ed8SAndrew Rybchenko __out boolean_t *supportedp)
19305e111ed8SAndrew Rybchenko {
19315e111ed8SAndrew Rybchenko const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
19325e111ed8SAndrew Rybchenko efx_rc_t rc;
19335e111ed8SAndrew Rybchenko
19345e111ed8SAndrew Rybchenko if (emcop != NULL) {
19355e111ed8SAndrew Rybchenko if ((rc = emcop->emco_feature_supported(enp,
19365e111ed8SAndrew Rybchenko EFX_MCDI_FEATURE_MACADDR_CHANGE, supportedp)) != 0)
19375e111ed8SAndrew Rybchenko goto fail1;
19385e111ed8SAndrew Rybchenko } else {
19395e111ed8SAndrew Rybchenko /* Earlier devices always supported MAC changes */
19405e111ed8SAndrew Rybchenko *supportedp = B_TRUE;
19415e111ed8SAndrew Rybchenko }
19425e111ed8SAndrew Rybchenko
19435e111ed8SAndrew Rybchenko return (0);
19445e111ed8SAndrew Rybchenko
19455e111ed8SAndrew Rybchenko fail1:
19465e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
19475e111ed8SAndrew Rybchenko
19485e111ed8SAndrew Rybchenko return (rc);
19495e111ed8SAndrew Rybchenko }
19505e111ed8SAndrew Rybchenko
19515e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_link_control_supported(__in efx_nic_t * enp,__out boolean_t * supportedp)19525e111ed8SAndrew Rybchenko efx_mcdi_link_control_supported(
19535e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
19545e111ed8SAndrew Rybchenko __out boolean_t *supportedp)
19555e111ed8SAndrew Rybchenko {
19565e111ed8SAndrew Rybchenko const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
19575e111ed8SAndrew Rybchenko efx_rc_t rc;
19585e111ed8SAndrew Rybchenko
19595e111ed8SAndrew Rybchenko if (emcop != NULL) {
19605e111ed8SAndrew Rybchenko if ((rc = emcop->emco_feature_supported(enp,
19615e111ed8SAndrew Rybchenko EFX_MCDI_FEATURE_LINK_CONTROL, supportedp)) != 0)
19625e111ed8SAndrew Rybchenko goto fail1;
19635e111ed8SAndrew Rybchenko } else {
19645e111ed8SAndrew Rybchenko /* Earlier devices always supported link control */
19655e111ed8SAndrew Rybchenko *supportedp = B_TRUE;
19665e111ed8SAndrew Rybchenko }
19675e111ed8SAndrew Rybchenko
19685e111ed8SAndrew Rybchenko return (0);
19695e111ed8SAndrew Rybchenko
19705e111ed8SAndrew Rybchenko fail1:
19715e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
19725e111ed8SAndrew Rybchenko
19735e111ed8SAndrew Rybchenko return (rc);
19745e111ed8SAndrew Rybchenko }
19755e111ed8SAndrew Rybchenko
19765e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_mac_spoofing_supported(__in efx_nic_t * enp,__out boolean_t * supportedp)19775e111ed8SAndrew Rybchenko efx_mcdi_mac_spoofing_supported(
19785e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
19795e111ed8SAndrew Rybchenko __out boolean_t *supportedp)
19805e111ed8SAndrew Rybchenko {
19815e111ed8SAndrew Rybchenko const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
19825e111ed8SAndrew Rybchenko efx_rc_t rc;
19835e111ed8SAndrew Rybchenko
19845e111ed8SAndrew Rybchenko if (emcop != NULL) {
19855e111ed8SAndrew Rybchenko if ((rc = emcop->emco_feature_supported(enp,
19865e111ed8SAndrew Rybchenko EFX_MCDI_FEATURE_MAC_SPOOFING, supportedp)) != 0)
19875e111ed8SAndrew Rybchenko goto fail1;
19885e111ed8SAndrew Rybchenko } else {
19895e111ed8SAndrew Rybchenko /* Earlier devices always supported MAC spoofing */
19905e111ed8SAndrew Rybchenko *supportedp = B_TRUE;
19915e111ed8SAndrew Rybchenko }
19925e111ed8SAndrew Rybchenko
19935e111ed8SAndrew Rybchenko return (0);
19945e111ed8SAndrew Rybchenko
19955e111ed8SAndrew Rybchenko fail1:
19965e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
19975e111ed8SAndrew Rybchenko
19985e111ed8SAndrew Rybchenko return (rc);
19995e111ed8SAndrew Rybchenko }
20005e111ed8SAndrew Rybchenko
20015e111ed8SAndrew Rybchenko #if EFSYS_OPT_BIST
20025e111ed8SAndrew Rybchenko
20035e111ed8SAndrew Rybchenko #if EFX_OPTS_EF10()
20045e111ed8SAndrew Rybchenko /*
20055e111ed8SAndrew Rybchenko * Enter bist offline mode. This is a fw mode which puts the NIC into a state
20065e111ed8SAndrew Rybchenko * where memory BIST tests can be run and not much else can interfere or happen.
20075e111ed8SAndrew Rybchenko * A reboot is required to exit this mode.
20085e111ed8SAndrew Rybchenko */
20095e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_bist_enable_offline(__in efx_nic_t * enp)20105e111ed8SAndrew Rybchenko efx_mcdi_bist_enable_offline(
20115e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
20125e111ed8SAndrew Rybchenko {
20135e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
20145e111ed8SAndrew Rybchenko efx_rc_t rc;
20155e111ed8SAndrew Rybchenko
20165e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_IN_LEN == 0);
20175e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_OUT_LEN == 0);
20185e111ed8SAndrew Rybchenko
20195e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_ENABLE_OFFLINE_BIST;
20205e111ed8SAndrew Rybchenko req.emr_in_buf = NULL;
20215e111ed8SAndrew Rybchenko req.emr_in_length = 0;
20225e111ed8SAndrew Rybchenko req.emr_out_buf = NULL;
20235e111ed8SAndrew Rybchenko req.emr_out_length = 0;
20245e111ed8SAndrew Rybchenko
20255e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req);
20265e111ed8SAndrew Rybchenko
20275e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
20285e111ed8SAndrew Rybchenko rc = req.emr_rc;
20295e111ed8SAndrew Rybchenko goto fail1;
20305e111ed8SAndrew Rybchenko }
20315e111ed8SAndrew Rybchenko
20325e111ed8SAndrew Rybchenko return (0);
20335e111ed8SAndrew Rybchenko
20345e111ed8SAndrew Rybchenko fail1:
20355e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
20365e111ed8SAndrew Rybchenko
20375e111ed8SAndrew Rybchenko return (rc);
20385e111ed8SAndrew Rybchenko }
20395e111ed8SAndrew Rybchenko #endif /* EFX_OPTS_EF10() */
20405e111ed8SAndrew Rybchenko
20415e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_bist_start(__in efx_nic_t * enp,__in efx_bist_type_t type)20425e111ed8SAndrew Rybchenko efx_mcdi_bist_start(
20435e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
20445e111ed8SAndrew Rybchenko __in efx_bist_type_t type)
20455e111ed8SAndrew Rybchenko {
20465e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
20475e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_START_BIST_IN_LEN,
20485e111ed8SAndrew Rybchenko MC_CMD_START_BIST_OUT_LEN);
20495e111ed8SAndrew Rybchenko efx_rc_t rc;
20505e111ed8SAndrew Rybchenko
20515e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_START_BIST;
20525e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
20535e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_START_BIST_IN_LEN;
20545e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
20555e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_START_BIST_OUT_LEN;
20565e111ed8SAndrew Rybchenko
20575e111ed8SAndrew Rybchenko switch (type) {
20585e111ed8SAndrew Rybchenko case EFX_BIST_TYPE_PHY_NORMAL:
20595e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST);
20605e111ed8SAndrew Rybchenko break;
20615e111ed8SAndrew Rybchenko case EFX_BIST_TYPE_PHY_CABLE_SHORT:
20625e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
20635e111ed8SAndrew Rybchenko MC_CMD_PHY_BIST_CABLE_SHORT);
20645e111ed8SAndrew Rybchenko break;
20655e111ed8SAndrew Rybchenko case EFX_BIST_TYPE_PHY_CABLE_LONG:
20665e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
20675e111ed8SAndrew Rybchenko MC_CMD_PHY_BIST_CABLE_LONG);
20685e111ed8SAndrew Rybchenko break;
20695e111ed8SAndrew Rybchenko case EFX_BIST_TYPE_MC_MEM:
20705e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
20715e111ed8SAndrew Rybchenko MC_CMD_MC_MEM_BIST);
20725e111ed8SAndrew Rybchenko break;
20735e111ed8SAndrew Rybchenko case EFX_BIST_TYPE_SAT_MEM:
20745e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
20755e111ed8SAndrew Rybchenko MC_CMD_PORT_MEM_BIST);
20765e111ed8SAndrew Rybchenko break;
20775e111ed8SAndrew Rybchenko case EFX_BIST_TYPE_REG:
20785e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
20795e111ed8SAndrew Rybchenko MC_CMD_REG_BIST);
20805e111ed8SAndrew Rybchenko break;
20815e111ed8SAndrew Rybchenko default:
20825e111ed8SAndrew Rybchenko EFSYS_ASSERT(0);
20835e111ed8SAndrew Rybchenko }
20845e111ed8SAndrew Rybchenko
20855e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req);
20865e111ed8SAndrew Rybchenko
20875e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
20885e111ed8SAndrew Rybchenko rc = req.emr_rc;
20895e111ed8SAndrew Rybchenko goto fail1;
20905e111ed8SAndrew Rybchenko }
20915e111ed8SAndrew Rybchenko
20925e111ed8SAndrew Rybchenko return (0);
20935e111ed8SAndrew Rybchenko
20945e111ed8SAndrew Rybchenko fail1:
20955e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
20965e111ed8SAndrew Rybchenko
20975e111ed8SAndrew Rybchenko return (rc);
20985e111ed8SAndrew Rybchenko }
20995e111ed8SAndrew Rybchenko
21005e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_BIST */
21015e111ed8SAndrew Rybchenko
21025e111ed8SAndrew Rybchenko
21035e111ed8SAndrew Rybchenko /* Enable logging of some events (e.g. link state changes) */
21045e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_log_ctrl(__in efx_nic_t * enp)21055e111ed8SAndrew Rybchenko efx_mcdi_log_ctrl(
21065e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
21075e111ed8SAndrew Rybchenko {
21085e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
21095e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_LOG_CTRL_IN_LEN,
21105e111ed8SAndrew Rybchenko MC_CMD_LOG_CTRL_OUT_LEN);
21115e111ed8SAndrew Rybchenko efx_rc_t rc;
21125e111ed8SAndrew Rybchenko
21135e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_LOG_CTRL;
21145e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
21155e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_LOG_CTRL_IN_LEN;
21165e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
21175e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_LOG_CTRL_OUT_LEN;
21185e111ed8SAndrew Rybchenko
21195e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST,
21205e111ed8SAndrew Rybchenko MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ);
21215e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST_EVQ, 0);
21225e111ed8SAndrew Rybchenko
21235e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req);
21245e111ed8SAndrew Rybchenko
21255e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
21265e111ed8SAndrew Rybchenko rc = req.emr_rc;
21275e111ed8SAndrew Rybchenko goto fail1;
21285e111ed8SAndrew Rybchenko }
21295e111ed8SAndrew Rybchenko
21305e111ed8SAndrew Rybchenko return (0);
21315e111ed8SAndrew Rybchenko
21325e111ed8SAndrew Rybchenko fail1:
21335e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
21345e111ed8SAndrew Rybchenko
21355e111ed8SAndrew Rybchenko return (rc);
21365e111ed8SAndrew Rybchenko }
21375e111ed8SAndrew Rybchenko
21385e111ed8SAndrew Rybchenko
21395e111ed8SAndrew Rybchenko #if EFSYS_OPT_MAC_STATS
21405e111ed8SAndrew Rybchenko
21415e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_mac_stats(__in efx_nic_t * enp,__in uint32_t vport_id,__in_opt efsys_mem_t * esmp,__in efx_stats_action_t action,__in uint16_t period_ms)21425e111ed8SAndrew Rybchenko efx_mcdi_mac_stats(
21435e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
21445e111ed8SAndrew Rybchenko __in uint32_t vport_id,
21455e111ed8SAndrew Rybchenko __in_opt efsys_mem_t *esmp,
21465e111ed8SAndrew Rybchenko __in efx_stats_action_t action,
21475e111ed8SAndrew Rybchenko __in uint16_t period_ms)
21485e111ed8SAndrew Rybchenko {
21495e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
21505e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAC_STATS_IN_LEN,
21515e111ed8SAndrew Rybchenko MC_CMD_MAC_STATS_V2_OUT_DMA_LEN);
21525e111ed8SAndrew Rybchenko int clear = (action == EFX_STATS_CLEAR);
21535e111ed8SAndrew Rybchenko int upload = (action == EFX_STATS_UPLOAD);
21545e111ed8SAndrew Rybchenko int enable = (action == EFX_STATS_ENABLE_NOEVENTS);
21555e111ed8SAndrew Rybchenko int events = (action == EFX_STATS_ENABLE_EVENTS);
21565e111ed8SAndrew Rybchenko int disable = (action == EFX_STATS_DISABLE);
21575e111ed8SAndrew Rybchenko efx_rc_t rc;
21585e111ed8SAndrew Rybchenko
21595e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_MAC_STATS;
21605e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
21615e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_MAC_STATS_IN_LEN;
21625e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
21635e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_MAC_STATS_V2_OUT_DMA_LEN;
21645e111ed8SAndrew Rybchenko
21655e111ed8SAndrew Rybchenko MCDI_IN_POPULATE_DWORD_6(req, MAC_STATS_IN_CMD,
21665e111ed8SAndrew Rybchenko MAC_STATS_IN_DMA, upload,
21675e111ed8SAndrew Rybchenko MAC_STATS_IN_CLEAR, clear,
21685e111ed8SAndrew Rybchenko MAC_STATS_IN_PERIODIC_CHANGE, enable | events | disable,
21695e111ed8SAndrew Rybchenko MAC_STATS_IN_PERIODIC_ENABLE, enable | events,
21705e111ed8SAndrew Rybchenko MAC_STATS_IN_PERIODIC_NOEVENT, !events,
21715e111ed8SAndrew Rybchenko MAC_STATS_IN_PERIOD_MS, (enable | events) ? period_ms : 0);
21725e111ed8SAndrew Rybchenko
21735e111ed8SAndrew Rybchenko if (enable || events || upload) {
21745e111ed8SAndrew Rybchenko const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
21755e111ed8SAndrew Rybchenko uint32_t bytes;
21765e111ed8SAndrew Rybchenko
21775e111ed8SAndrew Rybchenko /* Periodic stats or stats upload require a DMA buffer */
21785e111ed8SAndrew Rybchenko if (esmp == NULL) {
21795e111ed8SAndrew Rybchenko rc = EINVAL;
21805e111ed8SAndrew Rybchenko goto fail1;
21815e111ed8SAndrew Rybchenko }
21825e111ed8SAndrew Rybchenko
21835e111ed8SAndrew Rybchenko if (encp->enc_mac_stats_nstats < MC_CMD_MAC_NSTATS) {
21845e111ed8SAndrew Rybchenko /* MAC stats count too small for legacy MAC stats */
21855e111ed8SAndrew Rybchenko rc = ENOSPC;
21865e111ed8SAndrew Rybchenko goto fail2;
21875e111ed8SAndrew Rybchenko }
21885e111ed8SAndrew Rybchenko
21895e111ed8SAndrew Rybchenko bytes = encp->enc_mac_stats_nstats * sizeof (efx_qword_t);
21905e111ed8SAndrew Rybchenko
21915e111ed8SAndrew Rybchenko if (EFSYS_MEM_SIZE(esmp) < bytes) {
21925e111ed8SAndrew Rybchenko /* DMA buffer too small */
21935e111ed8SAndrew Rybchenko rc = ENOSPC;
21945e111ed8SAndrew Rybchenko goto fail3;
21955e111ed8SAndrew Rybchenko }
21965e111ed8SAndrew Rybchenko
21975e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_LO,
21985e111ed8SAndrew Rybchenko EFSYS_MEM_ADDR(esmp) & 0xffffffff);
21995e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_HI,
22005e111ed8SAndrew Rybchenko EFSYS_MEM_ADDR(esmp) >> 32);
22015e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_LEN, bytes);
22025e111ed8SAndrew Rybchenko }
22035e111ed8SAndrew Rybchenko
22045e111ed8SAndrew Rybchenko /*
22055e111ed8SAndrew Rybchenko * NOTE: Do not use EVB_PORT_ID_ASSIGNED when disabling periodic stats,
22065e111ed8SAndrew Rybchenko * as this may fail (and leave periodic DMA enabled) if the
22075e111ed8SAndrew Rybchenko * vadapter has already been deleted.
22085e111ed8SAndrew Rybchenko */
22095e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, MAC_STATS_IN_PORT_ID,
22105e111ed8SAndrew Rybchenko (disable ? EVB_PORT_ID_NULL : vport_id));
22115e111ed8SAndrew Rybchenko
22125e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req);
22135e111ed8SAndrew Rybchenko
22145e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
22155e111ed8SAndrew Rybchenko /* EF10: Expect ENOENT if no DMA queues are initialised */
22165e111ed8SAndrew Rybchenko if ((req.emr_rc != ENOENT) ||
22175e111ed8SAndrew Rybchenko (enp->en_rx_qcount + enp->en_tx_qcount != 0)) {
22185e111ed8SAndrew Rybchenko rc = req.emr_rc;
22195e111ed8SAndrew Rybchenko goto fail4;
22205e111ed8SAndrew Rybchenko }
22215e111ed8SAndrew Rybchenko }
22225e111ed8SAndrew Rybchenko
22235e111ed8SAndrew Rybchenko return (0);
22245e111ed8SAndrew Rybchenko
22255e111ed8SAndrew Rybchenko fail4:
22265e111ed8SAndrew Rybchenko EFSYS_PROBE(fail4);
22275e111ed8SAndrew Rybchenko fail3:
22285e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3);
22295e111ed8SAndrew Rybchenko fail2:
22305e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
22315e111ed8SAndrew Rybchenko fail1:
22325e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
22335e111ed8SAndrew Rybchenko
22345e111ed8SAndrew Rybchenko return (rc);
22355e111ed8SAndrew Rybchenko }
22365e111ed8SAndrew Rybchenko
22375e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_mac_stats_clear(__in efx_nic_t * enp)22385e111ed8SAndrew Rybchenko efx_mcdi_mac_stats_clear(
22395e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
22405e111ed8SAndrew Rybchenko {
22415e111ed8SAndrew Rybchenko efx_rc_t rc;
22425e111ed8SAndrew Rybchenko
22435e111ed8SAndrew Rybchenko if ((rc = efx_mcdi_mac_stats(enp, enp->en_vport_id, NULL,
22445e111ed8SAndrew Rybchenko EFX_STATS_CLEAR, 0)) != 0)
22455e111ed8SAndrew Rybchenko goto fail1;
22465e111ed8SAndrew Rybchenko
22475e111ed8SAndrew Rybchenko return (0);
22485e111ed8SAndrew Rybchenko
22495e111ed8SAndrew Rybchenko fail1:
22505e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
22515e111ed8SAndrew Rybchenko
22525e111ed8SAndrew Rybchenko return (rc);
22535e111ed8SAndrew Rybchenko }
22545e111ed8SAndrew Rybchenko
22555e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_mac_stats_upload(__in efx_nic_t * enp,__in efsys_mem_t * esmp)22565e111ed8SAndrew Rybchenko efx_mcdi_mac_stats_upload(
22575e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
22585e111ed8SAndrew Rybchenko __in efsys_mem_t *esmp)
22595e111ed8SAndrew Rybchenko {
22605e111ed8SAndrew Rybchenko efx_rc_t rc;
22615e111ed8SAndrew Rybchenko
22625e111ed8SAndrew Rybchenko /*
22635e111ed8SAndrew Rybchenko * The MC DMAs aggregate statistics for our convenience, so we can
22645e111ed8SAndrew Rybchenko * avoid having to pull the statistics buffer into the cache to
22655e111ed8SAndrew Rybchenko * maintain cumulative statistics.
22665e111ed8SAndrew Rybchenko */
22675e111ed8SAndrew Rybchenko if ((rc = efx_mcdi_mac_stats(enp, enp->en_vport_id, esmp,
22685e111ed8SAndrew Rybchenko EFX_STATS_UPLOAD, 0)) != 0)
22695e111ed8SAndrew Rybchenko goto fail1;
22705e111ed8SAndrew Rybchenko
22715e111ed8SAndrew Rybchenko return (0);
22725e111ed8SAndrew Rybchenko
22735e111ed8SAndrew Rybchenko fail1:
22745e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
22755e111ed8SAndrew Rybchenko
22765e111ed8SAndrew Rybchenko return (rc);
22775e111ed8SAndrew Rybchenko }
22785e111ed8SAndrew Rybchenko
22795e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_mac_stats_periodic(__in efx_nic_t * enp,__in efsys_mem_t * esmp,__in uint16_t period_ms,__in boolean_t events)22805e111ed8SAndrew Rybchenko efx_mcdi_mac_stats_periodic(
22815e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
22825e111ed8SAndrew Rybchenko __in efsys_mem_t *esmp,
22835e111ed8SAndrew Rybchenko __in uint16_t period_ms,
22845e111ed8SAndrew Rybchenko __in boolean_t events)
22855e111ed8SAndrew Rybchenko {
22865e111ed8SAndrew Rybchenko efx_rc_t rc;
22875e111ed8SAndrew Rybchenko
22885e111ed8SAndrew Rybchenko /*
22895e111ed8SAndrew Rybchenko * The MC DMAs aggregate statistics for our convenience, so we can
22905e111ed8SAndrew Rybchenko * avoid having to pull the statistics buffer into the cache to
22915e111ed8SAndrew Rybchenko * maintain cumulative statistics.
22925e111ed8SAndrew Rybchenko * Huntington uses a fixed 1sec period.
22935e111ed8SAndrew Rybchenko * Medford uses a fixed 1sec period before v6.2.1.1033 firmware.
22945e111ed8SAndrew Rybchenko */
22955e111ed8SAndrew Rybchenko if (period_ms == 0)
22965e111ed8SAndrew Rybchenko rc = efx_mcdi_mac_stats(enp, enp->en_vport_id, NULL,
22975e111ed8SAndrew Rybchenko EFX_STATS_DISABLE, 0);
22985e111ed8SAndrew Rybchenko else if (events)
22995e111ed8SAndrew Rybchenko rc = efx_mcdi_mac_stats(enp, enp->en_vport_id, esmp,
23005e111ed8SAndrew Rybchenko EFX_STATS_ENABLE_EVENTS, period_ms);
23015e111ed8SAndrew Rybchenko else
23025e111ed8SAndrew Rybchenko rc = efx_mcdi_mac_stats(enp, enp->en_vport_id, esmp,
23035e111ed8SAndrew Rybchenko EFX_STATS_ENABLE_NOEVENTS, period_ms);
23045e111ed8SAndrew Rybchenko
23055e111ed8SAndrew Rybchenko if (rc != 0)
23065e111ed8SAndrew Rybchenko goto fail1;
23075e111ed8SAndrew Rybchenko
23085e111ed8SAndrew Rybchenko return (0);
23095e111ed8SAndrew Rybchenko
23105e111ed8SAndrew Rybchenko fail1:
23115e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
23125e111ed8SAndrew Rybchenko
23135e111ed8SAndrew Rybchenko return (rc);
23145e111ed8SAndrew Rybchenko }
23155e111ed8SAndrew Rybchenko
23165e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MAC_STATS */
23175e111ed8SAndrew Rybchenko
23183c1c5cc4SAndrew Rybchenko #if EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10()
23195e111ed8SAndrew Rybchenko
23207d104a8dSViacheslav Galaktionov __checkReturn efx_rc_t
efx_mcdi_intf_from_pcie(__in uint32_t pcie_intf,__out efx_pcie_interface_t * efx_intf)23217d104a8dSViacheslav Galaktionov efx_mcdi_intf_from_pcie(
23227d104a8dSViacheslav Galaktionov __in uint32_t pcie_intf,
23237d104a8dSViacheslav Galaktionov __out efx_pcie_interface_t *efx_intf)
23247d104a8dSViacheslav Galaktionov {
23257d104a8dSViacheslav Galaktionov efx_rc_t rc;
23267d104a8dSViacheslav Galaktionov
23277d104a8dSViacheslav Galaktionov switch (pcie_intf) {
23287d104a8dSViacheslav Galaktionov case PCIE_INTERFACE_CALLER:
23297d104a8dSViacheslav Galaktionov *efx_intf = EFX_PCIE_INTERFACE_CALLER;
23307d104a8dSViacheslav Galaktionov break;
23317d104a8dSViacheslav Galaktionov case PCIE_INTERFACE_HOST_PRIMARY:
23327d104a8dSViacheslav Galaktionov *efx_intf = EFX_PCIE_INTERFACE_HOST_PRIMARY;
23337d104a8dSViacheslav Galaktionov break;
23347d104a8dSViacheslav Galaktionov case PCIE_INTERFACE_NIC_EMBEDDED:
23357d104a8dSViacheslav Galaktionov *efx_intf = EFX_PCIE_INTERFACE_NIC_EMBEDDED;
23367d104a8dSViacheslav Galaktionov break;
23377d104a8dSViacheslav Galaktionov default:
23387d104a8dSViacheslav Galaktionov rc = EINVAL;
23397d104a8dSViacheslav Galaktionov goto fail1;
23407d104a8dSViacheslav Galaktionov }
23417d104a8dSViacheslav Galaktionov
23427d104a8dSViacheslav Galaktionov return (0);
23437d104a8dSViacheslav Galaktionov
23447d104a8dSViacheslav Galaktionov fail1:
23457d104a8dSViacheslav Galaktionov EFSYS_PROBE1(fail1, efx_rc_t, rc);
23467d104a8dSViacheslav Galaktionov
23477d104a8dSViacheslav Galaktionov return (rc);
23487d104a8dSViacheslav Galaktionov }
23497d104a8dSViacheslav Galaktionov
2350b85f5048SIvan Malov __checkReturn efx_rc_t
efx_mcdi_intf_to_pcie(__in efx_pcie_interface_t efx_intf,__out uint32_t * pcie_intf)2351b85f5048SIvan Malov efx_mcdi_intf_to_pcie(
2352b85f5048SIvan Malov __in efx_pcie_interface_t efx_intf,
2353b85f5048SIvan Malov __out uint32_t *pcie_intf)
2354b85f5048SIvan Malov {
2355b85f5048SIvan Malov efx_rc_t rc;
2356b85f5048SIvan Malov
2357b85f5048SIvan Malov switch (efx_intf) {
2358b85f5048SIvan Malov case EFX_PCIE_INTERFACE_CALLER:
2359b85f5048SIvan Malov *pcie_intf = PCIE_INTERFACE_CALLER;
2360b85f5048SIvan Malov break;
2361b85f5048SIvan Malov case EFX_PCIE_INTERFACE_HOST_PRIMARY:
2362b85f5048SIvan Malov *pcie_intf = PCIE_INTERFACE_HOST_PRIMARY;
2363b85f5048SIvan Malov break;
2364b85f5048SIvan Malov case EFX_PCIE_INTERFACE_NIC_EMBEDDED:
2365b85f5048SIvan Malov *pcie_intf = PCIE_INTERFACE_NIC_EMBEDDED;
2366b85f5048SIvan Malov break;
2367b85f5048SIvan Malov default:
2368b85f5048SIvan Malov rc = EINVAL;
2369b85f5048SIvan Malov goto fail1;
2370b85f5048SIvan Malov }
2371b85f5048SIvan Malov
2372b85f5048SIvan Malov return (0);
2373b85f5048SIvan Malov
2374b85f5048SIvan Malov fail1:
2375b85f5048SIvan Malov EFSYS_PROBE1(fail1, efx_rc_t, rc);
2376b85f5048SIvan Malov return (rc);
2377b85f5048SIvan Malov }
2378b85f5048SIvan Malov
23795e111ed8SAndrew Rybchenko /*
23805e111ed8SAndrew Rybchenko * This function returns the pf and vf number of a function. If it is a pf the
23815e111ed8SAndrew Rybchenko * vf number is 0xffff. The vf number is the index of the vf on that
23825e111ed8SAndrew Rybchenko * function. So if you have 3 vfs on pf 0 the 3 vfs will return (pf=0,vf=0),
23835e111ed8SAndrew Rybchenko * (pf=0,vf=1), (pf=0,vf=2) aand the pf will return (pf=0, vf=0xffff).
23845e111ed8SAndrew Rybchenko */
23855e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_get_function_info(__in efx_nic_t * enp,__out uint32_t * pfp,__out_opt uint32_t * vfp,__out_opt efx_pcie_interface_t * intfp)23865e111ed8SAndrew Rybchenko efx_mcdi_get_function_info(
23875e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
23885e111ed8SAndrew Rybchenko __out uint32_t *pfp,
23897d104a8dSViacheslav Galaktionov __out_opt uint32_t *vfp,
23907d104a8dSViacheslav Galaktionov __out_opt efx_pcie_interface_t *intfp)
23915e111ed8SAndrew Rybchenko {
23927d104a8dSViacheslav Galaktionov efx_pcie_interface_t intf;
23935e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
23945e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_FUNCTION_INFO_IN_LEN,
23957d104a8dSViacheslav Galaktionov MC_CMD_GET_FUNCTION_INFO_OUT_V2_LEN);
23967d104a8dSViacheslav Galaktionov uint32_t pcie_intf;
23975e111ed8SAndrew Rybchenko efx_rc_t rc;
23985e111ed8SAndrew Rybchenko
23995e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_FUNCTION_INFO;
24005e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
24015e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_GET_FUNCTION_INFO_IN_LEN;
24025e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
24037d104a8dSViacheslav Galaktionov req.emr_out_length = MC_CMD_GET_FUNCTION_INFO_OUT_V2_LEN;
24045e111ed8SAndrew Rybchenko
24055e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req);
24065e111ed8SAndrew Rybchenko
24075e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
24085e111ed8SAndrew Rybchenko rc = req.emr_rc;
24095e111ed8SAndrew Rybchenko goto fail1;
24105e111ed8SAndrew Rybchenko }
24115e111ed8SAndrew Rybchenko
24125e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_FUNCTION_INFO_OUT_LEN) {
24135e111ed8SAndrew Rybchenko rc = EMSGSIZE;
24145e111ed8SAndrew Rybchenko goto fail2;
24155e111ed8SAndrew Rybchenko }
24165e111ed8SAndrew Rybchenko
24175e111ed8SAndrew Rybchenko *pfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_PF);
24185e111ed8SAndrew Rybchenko if (vfp != NULL)
24195e111ed8SAndrew Rybchenko *vfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_VF);
24205e111ed8SAndrew Rybchenko
24217d104a8dSViacheslav Galaktionov if (req.emr_out_length < MC_CMD_GET_FUNCTION_INFO_OUT_V2_LEN) {
24227d104a8dSViacheslav Galaktionov intf = EFX_PCIE_INTERFACE_HOST_PRIMARY;
24237d104a8dSViacheslav Galaktionov } else {
24247d104a8dSViacheslav Galaktionov pcie_intf = MCDI_OUT_DWORD(req,
24257d104a8dSViacheslav Galaktionov GET_FUNCTION_INFO_OUT_V2_INTF);
24267d104a8dSViacheslav Galaktionov
24277d104a8dSViacheslav Galaktionov rc = efx_mcdi_intf_from_pcie(pcie_intf, &intf);
24287d104a8dSViacheslav Galaktionov if (rc != 0)
24297d104a8dSViacheslav Galaktionov goto fail3;
24307d104a8dSViacheslav Galaktionov }
24317d104a8dSViacheslav Galaktionov
24327d104a8dSViacheslav Galaktionov if (intfp != NULL)
24337d104a8dSViacheslav Galaktionov *intfp = intf;
24347d104a8dSViacheslav Galaktionov
24355e111ed8SAndrew Rybchenko return (0);
24365e111ed8SAndrew Rybchenko
24377d104a8dSViacheslav Galaktionov fail3:
24387d104a8dSViacheslav Galaktionov EFSYS_PROBE(fail3);
24395e111ed8SAndrew Rybchenko fail2:
24405e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
24415e111ed8SAndrew Rybchenko fail1:
24425e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
24435e111ed8SAndrew Rybchenko
24445e111ed8SAndrew Rybchenko return (rc);
24455e111ed8SAndrew Rybchenko }
24465e111ed8SAndrew Rybchenko
24475e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_privilege_mask(__in efx_nic_t * enp,__in uint32_t pf,__in uint32_t vf,__out uint32_t * maskp)24485e111ed8SAndrew Rybchenko efx_mcdi_privilege_mask(
24495e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
24505e111ed8SAndrew Rybchenko __in uint32_t pf,
24515e111ed8SAndrew Rybchenko __in uint32_t vf,
24525e111ed8SAndrew Rybchenko __out uint32_t *maskp)
24535e111ed8SAndrew Rybchenko {
24545e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
24555e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_PRIVILEGE_MASK_IN_LEN,
24565e111ed8SAndrew Rybchenko MC_CMD_PRIVILEGE_MASK_OUT_LEN);
24575e111ed8SAndrew Rybchenko efx_rc_t rc;
24585e111ed8SAndrew Rybchenko
24595e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_PRIVILEGE_MASK;
24605e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
24615e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_PRIVILEGE_MASK_IN_LEN;
24625e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
24635e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_PRIVILEGE_MASK_OUT_LEN;
24645e111ed8SAndrew Rybchenko
24655e111ed8SAndrew Rybchenko MCDI_IN_POPULATE_DWORD_2(req, PRIVILEGE_MASK_IN_FUNCTION,
24665e111ed8SAndrew Rybchenko PRIVILEGE_MASK_IN_FUNCTION_PF, pf,
24675e111ed8SAndrew Rybchenko PRIVILEGE_MASK_IN_FUNCTION_VF, vf);
24685e111ed8SAndrew Rybchenko
24695e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req);
24705e111ed8SAndrew Rybchenko
24715e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
24725e111ed8SAndrew Rybchenko rc = req.emr_rc;
24735e111ed8SAndrew Rybchenko goto fail1;
24745e111ed8SAndrew Rybchenko }
24755e111ed8SAndrew Rybchenko
24765e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_PRIVILEGE_MASK_OUT_LEN) {
24775e111ed8SAndrew Rybchenko rc = EMSGSIZE;
24785e111ed8SAndrew Rybchenko goto fail2;
24795e111ed8SAndrew Rybchenko }
24805e111ed8SAndrew Rybchenko
24815e111ed8SAndrew Rybchenko *maskp = MCDI_OUT_DWORD(req, PRIVILEGE_MASK_OUT_OLD_MASK);
24825e111ed8SAndrew Rybchenko
24835e111ed8SAndrew Rybchenko return (0);
24845e111ed8SAndrew Rybchenko
24855e111ed8SAndrew Rybchenko fail2:
24865e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
24875e111ed8SAndrew Rybchenko fail1:
24885e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
24895e111ed8SAndrew Rybchenko
24905e111ed8SAndrew Rybchenko return (rc);
24915e111ed8SAndrew Rybchenko }
24925e111ed8SAndrew Rybchenko
24933c1c5cc4SAndrew Rybchenko #endif /* EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10() */
24945e111ed8SAndrew Rybchenko
24955e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_set_workaround(__in efx_nic_t * enp,__in uint32_t type,__in boolean_t enabled,__out_opt uint32_t * flagsp)24965e111ed8SAndrew Rybchenko efx_mcdi_set_workaround(
24975e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
24985e111ed8SAndrew Rybchenko __in uint32_t type,
24995e111ed8SAndrew Rybchenko __in boolean_t enabled,
25005e111ed8SAndrew Rybchenko __out_opt uint32_t *flagsp)
25015e111ed8SAndrew Rybchenko {
25025e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
25035e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_WORKAROUND_IN_LEN,
25045e111ed8SAndrew Rybchenko MC_CMD_WORKAROUND_EXT_OUT_LEN);
25055e111ed8SAndrew Rybchenko efx_rc_t rc;
25065e111ed8SAndrew Rybchenko
25075e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_WORKAROUND;
25085e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
25095e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_WORKAROUND_IN_LEN;
25105e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
25115e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_WORKAROUND_OUT_LEN;
25125e111ed8SAndrew Rybchenko
25135e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, type);
25145e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, enabled ? 1 : 0);
25155e111ed8SAndrew Rybchenko
25165e111ed8SAndrew Rybchenko efx_mcdi_execute_quiet(enp, &req);
25175e111ed8SAndrew Rybchenko
25185e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
25195e111ed8SAndrew Rybchenko rc = req.emr_rc;
25205e111ed8SAndrew Rybchenko goto fail1;
25215e111ed8SAndrew Rybchenko }
25225e111ed8SAndrew Rybchenko
25235e111ed8SAndrew Rybchenko if (flagsp != NULL) {
25245e111ed8SAndrew Rybchenko if (req.emr_out_length_used >= MC_CMD_WORKAROUND_EXT_OUT_LEN)
25255e111ed8SAndrew Rybchenko *flagsp = MCDI_OUT_DWORD(req, WORKAROUND_EXT_OUT_FLAGS);
25265e111ed8SAndrew Rybchenko else
25275e111ed8SAndrew Rybchenko *flagsp = 0;
25285e111ed8SAndrew Rybchenko }
25295e111ed8SAndrew Rybchenko
25305e111ed8SAndrew Rybchenko return (0);
25315e111ed8SAndrew Rybchenko
25325e111ed8SAndrew Rybchenko fail1:
25335e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
25345e111ed8SAndrew Rybchenko
25355e111ed8SAndrew Rybchenko return (rc);
25365e111ed8SAndrew Rybchenko }
25375e111ed8SAndrew Rybchenko
25385e111ed8SAndrew Rybchenko
25395e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_get_workarounds(__in efx_nic_t * enp,__out_opt uint32_t * implementedp,__out_opt uint32_t * enabledp)25405e111ed8SAndrew Rybchenko efx_mcdi_get_workarounds(
25415e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
25425e111ed8SAndrew Rybchenko __out_opt uint32_t *implementedp,
25435e111ed8SAndrew Rybchenko __out_opt uint32_t *enabledp)
25445e111ed8SAndrew Rybchenko {
25455e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
25465e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, 0, MC_CMD_GET_WORKAROUNDS_OUT_LEN);
25475e111ed8SAndrew Rybchenko efx_rc_t rc;
25485e111ed8SAndrew Rybchenko
25495e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_WORKAROUNDS;
25505e111ed8SAndrew Rybchenko req.emr_in_buf = NULL;
25515e111ed8SAndrew Rybchenko req.emr_in_length = 0;
25525e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
25535e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_GET_WORKAROUNDS_OUT_LEN;
25545e111ed8SAndrew Rybchenko
25555e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req);
25565e111ed8SAndrew Rybchenko
25575e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
25585e111ed8SAndrew Rybchenko rc = req.emr_rc;
25595e111ed8SAndrew Rybchenko goto fail1;
25605e111ed8SAndrew Rybchenko }
25615e111ed8SAndrew Rybchenko
2562e27950a0SAndy Moreton if (req.emr_out_length_used < MC_CMD_GET_WORKAROUNDS_OUT_LEN) {
2563e27950a0SAndy Moreton rc = EMSGSIZE;
2564e27950a0SAndy Moreton goto fail2;
2565e27950a0SAndy Moreton }
2566e27950a0SAndy Moreton
25675e111ed8SAndrew Rybchenko if (implementedp != NULL) {
25685e111ed8SAndrew Rybchenko *implementedp =
25695e111ed8SAndrew Rybchenko MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_IMPLEMENTED);
25705e111ed8SAndrew Rybchenko }
25715e111ed8SAndrew Rybchenko
25725e111ed8SAndrew Rybchenko if (enabledp != NULL) {
25735e111ed8SAndrew Rybchenko *enabledp = MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_ENABLED);
25745e111ed8SAndrew Rybchenko }
25755e111ed8SAndrew Rybchenko
25765e111ed8SAndrew Rybchenko return (0);
25775e111ed8SAndrew Rybchenko
2578e27950a0SAndy Moreton fail2:
2579e27950a0SAndy Moreton EFSYS_PROBE(fail2);
25805e111ed8SAndrew Rybchenko fail1:
25815e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
25825e111ed8SAndrew Rybchenko
25835e111ed8SAndrew Rybchenko return (rc);
25845e111ed8SAndrew Rybchenko }
25855e111ed8SAndrew Rybchenko
25865e111ed8SAndrew Rybchenko /*
25875e111ed8SAndrew Rybchenko * Size of media information page in accordance with SFF-8472 and SFF-8436.
25885e111ed8SAndrew Rybchenko * It is used in MCDI interface as well.
25895e111ed8SAndrew Rybchenko */
25905e111ed8SAndrew Rybchenko #define EFX_PHY_MEDIA_INFO_PAGE_SIZE 0x80
25915e111ed8SAndrew Rybchenko
25925e111ed8SAndrew Rybchenko /*
25935e111ed8SAndrew Rybchenko * Transceiver identifiers from SFF-8024 Table 4-1.
25945e111ed8SAndrew Rybchenko */
25955e111ed8SAndrew Rybchenko #define EFX_SFF_TRANSCEIVER_ID_SFP 0x03 /* SFP/SFP+/SFP28 */
25965e111ed8SAndrew Rybchenko #define EFX_SFF_TRANSCEIVER_ID_QSFP 0x0c /* QSFP */
25975e111ed8SAndrew Rybchenko #define EFX_SFF_TRANSCEIVER_ID_QSFP_PLUS 0x0d /* QSFP+ or later */
25985e111ed8SAndrew Rybchenko #define EFX_SFF_TRANSCEIVER_ID_QSFP28 0x11 /* QSFP28 or later */
25995e111ed8SAndrew Rybchenko
26005e111ed8SAndrew Rybchenko static __checkReturn efx_rc_t
efx_mcdi_get_phy_media_info(__in efx_nic_t * enp,__in uint32_t mcdi_page,__in uint8_t offset,__in uint8_t len,__out_bcount (len)uint8_t * data)26015e111ed8SAndrew Rybchenko efx_mcdi_get_phy_media_info(
26025e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
26035e111ed8SAndrew Rybchenko __in uint32_t mcdi_page,
26045e111ed8SAndrew Rybchenko __in uint8_t offset,
26055e111ed8SAndrew Rybchenko __in uint8_t len,
26065e111ed8SAndrew Rybchenko __out_bcount(len) uint8_t *data)
26075e111ed8SAndrew Rybchenko {
26085e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
26095e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN,
26105e111ed8SAndrew Rybchenko MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(
26115e111ed8SAndrew Rybchenko EFX_PHY_MEDIA_INFO_PAGE_SIZE));
26125e111ed8SAndrew Rybchenko efx_rc_t rc;
26135e111ed8SAndrew Rybchenko
26145e111ed8SAndrew Rybchenko EFSYS_ASSERT((uint32_t)offset + len <= EFX_PHY_MEDIA_INFO_PAGE_SIZE);
26155e111ed8SAndrew Rybchenko
26165e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_PHY_MEDIA_INFO;
26175e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
26185e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN;
26195e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
26205e111ed8SAndrew Rybchenko req.emr_out_length =
26215e111ed8SAndrew Rybchenko MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE);
26225e111ed8SAndrew Rybchenko
26235e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, GET_PHY_MEDIA_INFO_IN_PAGE, mcdi_page);
26245e111ed8SAndrew Rybchenko
26255e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req);
26265e111ed8SAndrew Rybchenko
26275e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
26285e111ed8SAndrew Rybchenko rc = req.emr_rc;
26295e111ed8SAndrew Rybchenko goto fail1;
26305e111ed8SAndrew Rybchenko }
26315e111ed8SAndrew Rybchenko
26325e111ed8SAndrew Rybchenko if (req.emr_out_length_used !=
26335e111ed8SAndrew Rybchenko MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE)) {
26345e111ed8SAndrew Rybchenko rc = EMSGSIZE;
26355e111ed8SAndrew Rybchenko goto fail2;
26365e111ed8SAndrew Rybchenko }
26375e111ed8SAndrew Rybchenko
26385e111ed8SAndrew Rybchenko if (MCDI_OUT_DWORD(req, GET_PHY_MEDIA_INFO_OUT_DATALEN) !=
26395e111ed8SAndrew Rybchenko EFX_PHY_MEDIA_INFO_PAGE_SIZE) {
26405e111ed8SAndrew Rybchenko rc = EIO;
26415e111ed8SAndrew Rybchenko goto fail3;
26425e111ed8SAndrew Rybchenko }
26435e111ed8SAndrew Rybchenko
26445e111ed8SAndrew Rybchenko memcpy(data,
26455e111ed8SAndrew Rybchenko MCDI_OUT2(req, uint8_t, GET_PHY_MEDIA_INFO_OUT_DATA) + offset,
26465e111ed8SAndrew Rybchenko len);
26475e111ed8SAndrew Rybchenko
26485e111ed8SAndrew Rybchenko return (0);
26495e111ed8SAndrew Rybchenko
26505e111ed8SAndrew Rybchenko fail3:
26515e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3);
26525e111ed8SAndrew Rybchenko fail2:
26535e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
26545e111ed8SAndrew Rybchenko fail1:
26555e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
26565e111ed8SAndrew Rybchenko
26575e111ed8SAndrew Rybchenko return (rc);
26585e111ed8SAndrew Rybchenko }
26595e111ed8SAndrew Rybchenko
26605e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_phy_module_get_info(__in efx_nic_t * enp,__in uint8_t dev_addr,__in size_t offset,__in size_t len,__out_bcount (len)uint8_t * data)26615e111ed8SAndrew Rybchenko efx_mcdi_phy_module_get_info(
26625e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
26635e111ed8SAndrew Rybchenko __in uint8_t dev_addr,
26645e111ed8SAndrew Rybchenko __in size_t offset,
26655e111ed8SAndrew Rybchenko __in size_t len,
26665e111ed8SAndrew Rybchenko __out_bcount(len) uint8_t *data)
26675e111ed8SAndrew Rybchenko {
26685e111ed8SAndrew Rybchenko efx_port_t *epp = &(enp->en_port);
26695e111ed8SAndrew Rybchenko efx_rc_t rc;
26705e111ed8SAndrew Rybchenko uint32_t mcdi_lower_page;
26715e111ed8SAndrew Rybchenko uint32_t mcdi_upper_page;
26725e111ed8SAndrew Rybchenko uint8_t id;
26735e111ed8SAndrew Rybchenko
26745e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
26755e111ed8SAndrew Rybchenko
26765e111ed8SAndrew Rybchenko /*
26775e111ed8SAndrew Rybchenko * Map device address to MC_CMD_GET_PHY_MEDIA_INFO pages.
26785e111ed8SAndrew Rybchenko * Offset plus length interface allows to access page 0 only.
26795e111ed8SAndrew Rybchenko * I.e. non-zero upper pages are not accessible.
26805e111ed8SAndrew Rybchenko * See SFF-8472 section 4 Memory Organization and SFF-8436 section 7.6
26815e111ed8SAndrew Rybchenko * QSFP+ Memory Map for details on how information is structured
26825e111ed8SAndrew Rybchenko * and accessible.
26835e111ed8SAndrew Rybchenko */
26845e111ed8SAndrew Rybchenko switch (epp->ep_fixed_port_type) {
26855e111ed8SAndrew Rybchenko case EFX_PHY_MEDIA_SFP_PLUS:
26865e111ed8SAndrew Rybchenko case EFX_PHY_MEDIA_QSFP_PLUS:
26875e111ed8SAndrew Rybchenko /* Port type supports modules */
26885e111ed8SAndrew Rybchenko break;
26895e111ed8SAndrew Rybchenko default:
26905e111ed8SAndrew Rybchenko rc = ENOTSUP;
26915e111ed8SAndrew Rybchenko goto fail1;
26925e111ed8SAndrew Rybchenko }
26935e111ed8SAndrew Rybchenko
26945e111ed8SAndrew Rybchenko /*
26955e111ed8SAndrew Rybchenko * For all supported port types, MCDI page 0 offset 0 holds the
26965e111ed8SAndrew Rybchenko * transceiver identifier. Probe to determine the data layout.
26975e111ed8SAndrew Rybchenko * Definitions from SFF-8024 Table 4-1.
26985e111ed8SAndrew Rybchenko */
26995e111ed8SAndrew Rybchenko rc = efx_mcdi_get_phy_media_info(enp,
27005e111ed8SAndrew Rybchenko 0, 0, sizeof(id), &id);
27015e111ed8SAndrew Rybchenko if (rc != 0)
27025e111ed8SAndrew Rybchenko goto fail2;
27035e111ed8SAndrew Rybchenko
27045e111ed8SAndrew Rybchenko switch (id) {
27055e111ed8SAndrew Rybchenko case EFX_SFF_TRANSCEIVER_ID_SFP:
27065e111ed8SAndrew Rybchenko /*
27075e111ed8SAndrew Rybchenko * In accordance with SFF-8472 Diagnostic Monitoring
27085e111ed8SAndrew Rybchenko * Interface for Optical Transceivers section 4 Memory
27095e111ed8SAndrew Rybchenko * Organization two 2-wire addresses are defined.
27105e111ed8SAndrew Rybchenko */
27115e111ed8SAndrew Rybchenko switch (dev_addr) {
27125e111ed8SAndrew Rybchenko /* Base information */
27135e111ed8SAndrew Rybchenko case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE:
27145e111ed8SAndrew Rybchenko /*
27155e111ed8SAndrew Rybchenko * MCDI page 0 should be used to access lower
27165e111ed8SAndrew Rybchenko * page 0 (0x00 - 0x7f) at the device address 0xA0.
27175e111ed8SAndrew Rybchenko */
27185e111ed8SAndrew Rybchenko mcdi_lower_page = 0;
27195e111ed8SAndrew Rybchenko /*
27205e111ed8SAndrew Rybchenko * MCDI page 1 should be used to access upper
27215e111ed8SAndrew Rybchenko * page 0 (0x80 - 0xff) at the device address 0xA0.
27225e111ed8SAndrew Rybchenko */
27235e111ed8SAndrew Rybchenko mcdi_upper_page = 1;
27245e111ed8SAndrew Rybchenko break;
27255e111ed8SAndrew Rybchenko /* Diagnostics */
27265e111ed8SAndrew Rybchenko case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM:
27275e111ed8SAndrew Rybchenko /*
27285e111ed8SAndrew Rybchenko * MCDI page 2 should be used to access lower
27295e111ed8SAndrew Rybchenko * page 0 (0x00 - 0x7f) at the device address 0xA2.
27305e111ed8SAndrew Rybchenko */
27315e111ed8SAndrew Rybchenko mcdi_lower_page = 2;
27325e111ed8SAndrew Rybchenko /*
27335e111ed8SAndrew Rybchenko * MCDI page 3 should be used to access upper
27345e111ed8SAndrew Rybchenko * page 0 (0x80 - 0xff) at the device address 0xA2.
27355e111ed8SAndrew Rybchenko */
27365e111ed8SAndrew Rybchenko mcdi_upper_page = 3;
27375e111ed8SAndrew Rybchenko break;
27385e111ed8SAndrew Rybchenko default:
27395e111ed8SAndrew Rybchenko rc = ENOTSUP;
27405e111ed8SAndrew Rybchenko goto fail3;
27415e111ed8SAndrew Rybchenko }
27425e111ed8SAndrew Rybchenko break;
27435e111ed8SAndrew Rybchenko case EFX_SFF_TRANSCEIVER_ID_QSFP:
27445e111ed8SAndrew Rybchenko case EFX_SFF_TRANSCEIVER_ID_QSFP_PLUS:
27455e111ed8SAndrew Rybchenko case EFX_SFF_TRANSCEIVER_ID_QSFP28:
27465e111ed8SAndrew Rybchenko switch (dev_addr) {
27475e111ed8SAndrew Rybchenko case EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP:
27485e111ed8SAndrew Rybchenko /*
27495e111ed8SAndrew Rybchenko * MCDI page -1 should be used to access lower page 0
27505e111ed8SAndrew Rybchenko * (0x00 - 0x7f).
27515e111ed8SAndrew Rybchenko */
27525e111ed8SAndrew Rybchenko mcdi_lower_page = (uint32_t)-1;
27535e111ed8SAndrew Rybchenko /*
27545e111ed8SAndrew Rybchenko * MCDI page 0 should be used to access upper page 0
27555e111ed8SAndrew Rybchenko * (0x80h - 0xff).
27565e111ed8SAndrew Rybchenko */
27575e111ed8SAndrew Rybchenko mcdi_upper_page = 0;
27585e111ed8SAndrew Rybchenko break;
27595e111ed8SAndrew Rybchenko default:
27605e111ed8SAndrew Rybchenko rc = ENOTSUP;
27615e111ed8SAndrew Rybchenko goto fail3;
27625e111ed8SAndrew Rybchenko }
27635e111ed8SAndrew Rybchenko break;
27645e111ed8SAndrew Rybchenko default:
27655e111ed8SAndrew Rybchenko rc = ENOTSUP;
27665e111ed8SAndrew Rybchenko goto fail3;
27675e111ed8SAndrew Rybchenko }
27685e111ed8SAndrew Rybchenko
27695e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(EFX_PHY_MEDIA_INFO_PAGE_SIZE <= 0xFF);
27705e111ed8SAndrew Rybchenko
27715e111ed8SAndrew Rybchenko if (offset < EFX_PHY_MEDIA_INFO_PAGE_SIZE) {
27725e111ed8SAndrew Rybchenko size_t read_len =
27735e111ed8SAndrew Rybchenko MIN(len, EFX_PHY_MEDIA_INFO_PAGE_SIZE - offset);
27745e111ed8SAndrew Rybchenko
27755e111ed8SAndrew Rybchenko rc = efx_mcdi_get_phy_media_info(enp,
27765e111ed8SAndrew Rybchenko mcdi_lower_page, (uint8_t)offset, (uint8_t)read_len, data);
27775e111ed8SAndrew Rybchenko if (rc != 0)
27785e111ed8SAndrew Rybchenko goto fail4;
27795e111ed8SAndrew Rybchenko
27805e111ed8SAndrew Rybchenko data += read_len;
27815e111ed8SAndrew Rybchenko len -= read_len;
27825e111ed8SAndrew Rybchenko
27835e111ed8SAndrew Rybchenko offset = 0;
27845e111ed8SAndrew Rybchenko } else {
27855e111ed8SAndrew Rybchenko offset -= EFX_PHY_MEDIA_INFO_PAGE_SIZE;
27865e111ed8SAndrew Rybchenko }
27875e111ed8SAndrew Rybchenko
27885e111ed8SAndrew Rybchenko if (len > 0) {
27895e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(len, <=, EFX_PHY_MEDIA_INFO_PAGE_SIZE);
27905e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(offset, <, EFX_PHY_MEDIA_INFO_PAGE_SIZE);
27915e111ed8SAndrew Rybchenko
27925e111ed8SAndrew Rybchenko rc = efx_mcdi_get_phy_media_info(enp,
27935e111ed8SAndrew Rybchenko mcdi_upper_page, (uint8_t)offset, (uint8_t)len, data);
27945e111ed8SAndrew Rybchenko if (rc != 0)
27955e111ed8SAndrew Rybchenko goto fail5;
27965e111ed8SAndrew Rybchenko }
27975e111ed8SAndrew Rybchenko
27985e111ed8SAndrew Rybchenko return (0);
27995e111ed8SAndrew Rybchenko
28005e111ed8SAndrew Rybchenko fail5:
28015e111ed8SAndrew Rybchenko EFSYS_PROBE(fail5);
28025e111ed8SAndrew Rybchenko fail4:
28035e111ed8SAndrew Rybchenko EFSYS_PROBE(fail4);
28045e111ed8SAndrew Rybchenko fail3:
28055e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3);
28065e111ed8SAndrew Rybchenko fail2:
28075e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
28085e111ed8SAndrew Rybchenko fail1:
28095e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
28105e111ed8SAndrew Rybchenko
28115e111ed8SAndrew Rybchenko return (rc);
28125e111ed8SAndrew Rybchenko }
28135e111ed8SAndrew Rybchenko
2814b97bf1caSAndrew Rybchenko #if EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10()
2815b97bf1caSAndrew Rybchenko
2816b97bf1caSAndrew Rybchenko #define INIT_EVQ_MAXNBUFS MC_CMD_INIT_EVQ_V2_IN_DMA_ADDR_MAXNUM
2817b97bf1caSAndrew Rybchenko
281885270581SAndrew Rybchenko #if EFX_OPTS_EF10()
2819b97bf1caSAndrew Rybchenko # if (INIT_EVQ_MAXNBUFS < EF10_EVQ_MAXNBUFS)
2820b97bf1caSAndrew Rybchenko # error "INIT_EVQ_MAXNBUFS too small"
2821b97bf1caSAndrew Rybchenko # endif
2822b97bf1caSAndrew Rybchenko #endif /* EFX_OPTS_EF10 */
2823b97bf1caSAndrew Rybchenko #if EFSYS_OPT_RIVERHEAD
2824b97bf1caSAndrew Rybchenko # if (INIT_EVQ_MAXNBUFS < RHEAD_EVQ_MAXNBUFS)
2825b97bf1caSAndrew Rybchenko # error "INIT_EVQ_MAXNBUFS too small"
2826b97bf1caSAndrew Rybchenko # endif
2827b97bf1caSAndrew Rybchenko #endif /* EFSYS_OPT_RIVERHEAD */
282885270581SAndrew Rybchenko
282985270581SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_init_evq(__in efx_nic_t * enp,__in unsigned int instance,__in efsys_mem_t * esmp,__in size_t nevs,__in uint32_t irq,__in uint32_t target_evq,__in uint32_t us,__in uint32_t flags,__in boolean_t low_latency)283085270581SAndrew Rybchenko efx_mcdi_init_evq(
283185270581SAndrew Rybchenko __in efx_nic_t *enp,
283285270581SAndrew Rybchenko __in unsigned int instance,
283385270581SAndrew Rybchenko __in efsys_mem_t *esmp,
283485270581SAndrew Rybchenko __in size_t nevs,
283585270581SAndrew Rybchenko __in uint32_t irq,
28363dee345aSAndrew Rybchenko __in uint32_t target_evq,
283785270581SAndrew Rybchenko __in uint32_t us,
283885270581SAndrew Rybchenko __in uint32_t flags,
283985270581SAndrew Rybchenko __in boolean_t low_latency)
284085270581SAndrew Rybchenko {
28418aad1149SAndrew Rybchenko const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
284285270581SAndrew Rybchenko efx_mcdi_req_t req;
284385270581SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload,
2844b97bf1caSAndrew Rybchenko MC_CMD_INIT_EVQ_V2_IN_LEN(INIT_EVQ_MAXNBUFS),
284513a300a5SAndrew Rybchenko MC_CMD_INIT_EVQ_V2_OUT_LEN);
284685270581SAndrew Rybchenko boolean_t interrupting;
2847f8a60f76SAndy Moreton int ev_extended_width;
284885270581SAndrew Rybchenko int ev_cut_through;
28498aad1149SAndrew Rybchenko int ev_merge;
285085270581SAndrew Rybchenko unsigned int evq_type;
285185270581SAndrew Rybchenko efx_qword_t *dma_addr;
285285270581SAndrew Rybchenko uint64_t addr;
285385270581SAndrew Rybchenko int npages;
285485270581SAndrew Rybchenko int i;
285585270581SAndrew Rybchenko efx_rc_t rc;
285685270581SAndrew Rybchenko
2857f8a60f76SAndy Moreton npages = efx_evq_nbufs(enp, nevs, flags);
2858b97bf1caSAndrew Rybchenko if (npages > INIT_EVQ_MAXNBUFS) {
285985270581SAndrew Rybchenko rc = EINVAL;
286085270581SAndrew Rybchenko goto fail1;
286185270581SAndrew Rybchenko }
286285270581SAndrew Rybchenko
286385270581SAndrew Rybchenko req.emr_cmd = MC_CMD_INIT_EVQ;
286485270581SAndrew Rybchenko req.emr_in_buf = payload;
286585270581SAndrew Rybchenko req.emr_in_length = MC_CMD_INIT_EVQ_V2_IN_LEN(npages);
286685270581SAndrew Rybchenko req.emr_out_buf = payload;
286785270581SAndrew Rybchenko req.emr_out_length = MC_CMD_INIT_EVQ_V2_OUT_LEN;
286885270581SAndrew Rybchenko
286985270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_SIZE, nevs);
287085270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_INSTANCE, instance);
287185270581SAndrew Rybchenko
287285270581SAndrew Rybchenko interrupting = ((flags & EFX_EVQ_FLAGS_NOTIFY_MASK) ==
287385270581SAndrew Rybchenko EFX_EVQ_FLAGS_NOTIFY_INTERRUPT);
287485270581SAndrew Rybchenko
28753dee345aSAndrew Rybchenko if (interrupting)
28763dee345aSAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_IRQ_NUM, irq);
28773dee345aSAndrew Rybchenko else
28783dee345aSAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TARGET_EVQ, target_evq);
28793dee345aSAndrew Rybchenko
28808aad1149SAndrew Rybchenko if (encp->enc_init_evq_v2_supported) {
28818aad1149SAndrew Rybchenko /*
28828aad1149SAndrew Rybchenko * On Medford the low latency license is required to enable RX
28838aad1149SAndrew Rybchenko * and event cut through and to disable RX batching. If event
28848aad1149SAndrew Rybchenko * queue type in flags is auto, we let the firmware decide the
28858aad1149SAndrew Rybchenko * settings to use. If the adapter has a low latency license,
28868aad1149SAndrew Rybchenko * it will choose the best settings for low latency, otherwise
28878aad1149SAndrew Rybchenko * it will choose the best settings for throughput.
28888aad1149SAndrew Rybchenko */
288985270581SAndrew Rybchenko switch (flags & EFX_EVQ_FLAGS_TYPE_MASK) {
289085270581SAndrew Rybchenko case EFX_EVQ_FLAGS_TYPE_AUTO:
289185270581SAndrew Rybchenko evq_type = MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_AUTO;
289285270581SAndrew Rybchenko break;
289385270581SAndrew Rybchenko case EFX_EVQ_FLAGS_TYPE_THROUGHPUT:
289485270581SAndrew Rybchenko evq_type = MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_THROUGHPUT;
289585270581SAndrew Rybchenko break;
289685270581SAndrew Rybchenko case EFX_EVQ_FLAGS_TYPE_LOW_LATENCY:
289785270581SAndrew Rybchenko evq_type = MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_LOW_LATENCY;
289885270581SAndrew Rybchenko break;
289985270581SAndrew Rybchenko default:
290085270581SAndrew Rybchenko rc = EINVAL;
290185270581SAndrew Rybchenko goto fail2;
290285270581SAndrew Rybchenko }
29038aad1149SAndrew Rybchenko /* EvQ type controls merging, no manual settings */
29048aad1149SAndrew Rybchenko ev_merge = 0;
29058aad1149SAndrew Rybchenko ev_cut_through = 0;
29068aad1149SAndrew Rybchenko } else {
29078aad1149SAndrew Rybchenko /* EvQ types other than manual are not supported */
29088aad1149SAndrew Rybchenko evq_type = MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_MANUAL;
29098aad1149SAndrew Rybchenko /*
29108aad1149SAndrew Rybchenko * On Huntington RX and TX event batching can only be requested
29118aad1149SAndrew Rybchenko * together (even if the datapath firmware doesn't actually
29128aad1149SAndrew Rybchenko * support RX batching). If event cut through is enabled no RX
29138aad1149SAndrew Rybchenko * batching will occur.
29148aad1149SAndrew Rybchenko *
29158aad1149SAndrew Rybchenko * So always enable RX and TX event batching, and enable event
29168aad1149SAndrew Rybchenko * cut through if we want low latency operation.
29178aad1149SAndrew Rybchenko */
29188aad1149SAndrew Rybchenko ev_merge = 1;
29198aad1149SAndrew Rybchenko switch (flags & EFX_EVQ_FLAGS_TYPE_MASK) {
29208aad1149SAndrew Rybchenko case EFX_EVQ_FLAGS_TYPE_AUTO:
29218aad1149SAndrew Rybchenko ev_cut_through = low_latency ? 1 : 0;
29228aad1149SAndrew Rybchenko break;
29238aad1149SAndrew Rybchenko case EFX_EVQ_FLAGS_TYPE_THROUGHPUT:
29248aad1149SAndrew Rybchenko ev_cut_through = 0;
29258aad1149SAndrew Rybchenko break;
29268aad1149SAndrew Rybchenko case EFX_EVQ_FLAGS_TYPE_LOW_LATENCY:
29278aad1149SAndrew Rybchenko ev_cut_through = 1;
29288aad1149SAndrew Rybchenko break;
29298aad1149SAndrew Rybchenko default:
29308aad1149SAndrew Rybchenko rc = EINVAL;
29318aad1149SAndrew Rybchenko goto fail2;
29328aad1149SAndrew Rybchenko }
29338aad1149SAndrew Rybchenko }
29348aad1149SAndrew Rybchenko
2935f8a60f76SAndy Moreton /*
2936f8a60f76SAndy Moreton * On EF100, extended width event queues have a different event
2937f8a60f76SAndy Moreton * descriptor layout and are used to support descriptor proxy queues.
2938f8a60f76SAndy Moreton */
2939f8a60f76SAndy Moreton ev_extended_width = 0;
2940f8a60f76SAndy Moreton #if EFSYS_OPT_EV_EXTENDED_WIDTH
2941f8a60f76SAndy Moreton if (encp->enc_init_evq_extended_width_supported) {
2942f8a60f76SAndy Moreton if (flags & EFX_EVQ_FLAGS_EXTENDED_WIDTH)
2943f8a60f76SAndy Moreton ev_extended_width = 1;
2944f8a60f76SAndy Moreton }
2945f8a60f76SAndy Moreton #endif
2946f8a60f76SAndy Moreton
2947f8a60f76SAndy Moreton MCDI_IN_POPULATE_DWORD_8(req, INIT_EVQ_V2_IN_FLAGS,
294885270581SAndrew Rybchenko INIT_EVQ_V2_IN_FLAG_INTERRUPTING, interrupting,
294985270581SAndrew Rybchenko INIT_EVQ_V2_IN_FLAG_RPTR_DOS, 0,
295085270581SAndrew Rybchenko INIT_EVQ_V2_IN_FLAG_INT_ARMD, 0,
29518aad1149SAndrew Rybchenko INIT_EVQ_V2_IN_FLAG_CUT_THRU, ev_cut_through,
29528aad1149SAndrew Rybchenko INIT_EVQ_V2_IN_FLAG_RX_MERGE, ev_merge,
29538aad1149SAndrew Rybchenko INIT_EVQ_V2_IN_FLAG_TX_MERGE, ev_merge,
2954f8a60f76SAndy Moreton INIT_EVQ_V2_IN_FLAG_TYPE, evq_type,
2955f8a60f76SAndy Moreton INIT_EVQ_V2_IN_FLAG_EXT_WIDTH, ev_extended_width);
295685270581SAndrew Rybchenko
295785270581SAndrew Rybchenko /* If the value is zero then disable the timer */
295885270581SAndrew Rybchenko if (us == 0) {
295985270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_MODE,
296085270581SAndrew Rybchenko MC_CMD_INIT_EVQ_V2_IN_TMR_MODE_DIS);
296185270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_LOAD, 0);
296285270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_RELOAD, 0);
296385270581SAndrew Rybchenko } else {
296485270581SAndrew Rybchenko unsigned int ticks;
296585270581SAndrew Rybchenko
296685270581SAndrew Rybchenko if ((rc = efx_ev_usecs_to_ticks(enp, us, &ticks)) != 0)
296785270581SAndrew Rybchenko goto fail3;
296885270581SAndrew Rybchenko
296985270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_MODE,
297085270581SAndrew Rybchenko MC_CMD_INIT_EVQ_V2_IN_TMR_INT_HLDOFF);
297185270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_LOAD, ticks);
297285270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_RELOAD, ticks);
297385270581SAndrew Rybchenko }
297485270581SAndrew Rybchenko
297585270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_COUNT_MODE,
297685270581SAndrew Rybchenko MC_CMD_INIT_EVQ_V2_IN_COUNT_MODE_DIS);
297785270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_COUNT_THRSHLD, 0);
297885270581SAndrew Rybchenko
297985270581SAndrew Rybchenko dma_addr = MCDI_IN2(req, efx_qword_t, INIT_EVQ_V2_IN_DMA_ADDR);
298085270581SAndrew Rybchenko addr = EFSYS_MEM_ADDR(esmp);
298185270581SAndrew Rybchenko
298285270581SAndrew Rybchenko for (i = 0; i < npages; i++) {
298385270581SAndrew Rybchenko EFX_POPULATE_QWORD_2(*dma_addr,
298485270581SAndrew Rybchenko EFX_DWORD_1, (uint32_t)(addr >> 32),
298585270581SAndrew Rybchenko EFX_DWORD_0, (uint32_t)(addr & 0xffffffff));
298685270581SAndrew Rybchenko
298785270581SAndrew Rybchenko dma_addr++;
298885270581SAndrew Rybchenko addr += EFX_BUF_SIZE;
298985270581SAndrew Rybchenko }
299085270581SAndrew Rybchenko
299185270581SAndrew Rybchenko efx_mcdi_execute(enp, &req);
299285270581SAndrew Rybchenko
299385270581SAndrew Rybchenko if (req.emr_rc != 0) {
299485270581SAndrew Rybchenko rc = req.emr_rc;
299585270581SAndrew Rybchenko goto fail4;
299685270581SAndrew Rybchenko }
299785270581SAndrew Rybchenko
29988aad1149SAndrew Rybchenko if (encp->enc_init_evq_v2_supported) {
299985270581SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_INIT_EVQ_V2_OUT_LEN) {
300085270581SAndrew Rybchenko rc = EMSGSIZE;
300185270581SAndrew Rybchenko goto fail5;
300285270581SAndrew Rybchenko }
30038aad1149SAndrew Rybchenko EFSYS_PROBE1(mcdi_evq_flags, uint32_t,
30048aad1149SAndrew Rybchenko MCDI_OUT_DWORD(req, INIT_EVQ_V2_OUT_FLAGS));
30058aad1149SAndrew Rybchenko } else {
30068aad1149SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_INIT_EVQ_OUT_LEN) {
30078aad1149SAndrew Rybchenko rc = EMSGSIZE;
30088aad1149SAndrew Rybchenko goto fail6;
30098aad1149SAndrew Rybchenko }
30108aad1149SAndrew Rybchenko }
301185270581SAndrew Rybchenko
301285270581SAndrew Rybchenko /* NOTE: ignore the returned IRQ param as firmware does not set it. */
301385270581SAndrew Rybchenko
301485270581SAndrew Rybchenko return (0);
301585270581SAndrew Rybchenko
30168aad1149SAndrew Rybchenko fail6:
30178aad1149SAndrew Rybchenko EFSYS_PROBE(fail6);
301885270581SAndrew Rybchenko fail5:
301985270581SAndrew Rybchenko EFSYS_PROBE(fail5);
302085270581SAndrew Rybchenko fail4:
302185270581SAndrew Rybchenko EFSYS_PROBE(fail4);
302285270581SAndrew Rybchenko fail3:
302385270581SAndrew Rybchenko EFSYS_PROBE(fail3);
302485270581SAndrew Rybchenko fail2:
302585270581SAndrew Rybchenko EFSYS_PROBE(fail2);
302685270581SAndrew Rybchenko fail1:
302785270581SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
302885270581SAndrew Rybchenko
302985270581SAndrew Rybchenko return (rc);
303085270581SAndrew Rybchenko }
303185270581SAndrew Rybchenko
303285270581SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_fini_evq(__in efx_nic_t * enp,__in uint32_t instance)303385270581SAndrew Rybchenko efx_mcdi_fini_evq(
303485270581SAndrew Rybchenko __in efx_nic_t *enp,
303585270581SAndrew Rybchenko __in uint32_t instance)
303685270581SAndrew Rybchenko {
303785270581SAndrew Rybchenko efx_mcdi_req_t req;
303885270581SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FINI_EVQ_IN_LEN,
303985270581SAndrew Rybchenko MC_CMD_FINI_EVQ_OUT_LEN);
304085270581SAndrew Rybchenko efx_rc_t rc;
304185270581SAndrew Rybchenko
304285270581SAndrew Rybchenko req.emr_cmd = MC_CMD_FINI_EVQ;
304385270581SAndrew Rybchenko req.emr_in_buf = payload;
304485270581SAndrew Rybchenko req.emr_in_length = MC_CMD_FINI_EVQ_IN_LEN;
304585270581SAndrew Rybchenko req.emr_out_buf = payload;
304685270581SAndrew Rybchenko req.emr_out_length = MC_CMD_FINI_EVQ_OUT_LEN;
304785270581SAndrew Rybchenko
304885270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, FINI_EVQ_IN_INSTANCE, instance);
304985270581SAndrew Rybchenko
305085270581SAndrew Rybchenko efx_mcdi_execute_quiet(enp, &req);
305185270581SAndrew Rybchenko
305285270581SAndrew Rybchenko if (req.emr_rc != 0) {
305385270581SAndrew Rybchenko rc = req.emr_rc;
305485270581SAndrew Rybchenko goto fail1;
305585270581SAndrew Rybchenko }
305685270581SAndrew Rybchenko
305785270581SAndrew Rybchenko return (0);
305885270581SAndrew Rybchenko
305985270581SAndrew Rybchenko fail1:
306085270581SAndrew Rybchenko /*
306185270581SAndrew Rybchenko * EALREADY is not an error, but indicates that the MC has rebooted and
306285270581SAndrew Rybchenko * that the EVQ has already been destroyed.
306385270581SAndrew Rybchenko */
306485270581SAndrew Rybchenko if (rc != EALREADY)
306585270581SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
306685270581SAndrew Rybchenko
306785270581SAndrew Rybchenko return (rc);
306885270581SAndrew Rybchenko }
306985270581SAndrew Rybchenko
307009b59c7dSAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_init_rxq(__in efx_nic_t * enp,__in uint32_t ndescs,__in efx_evq_t * eep,__in uint32_t label,__in uint32_t instance,__in efsys_mem_t * esmp,__in const efx_mcdi_init_rxq_params_t * params)307109b59c7dSAndrew Rybchenko efx_mcdi_init_rxq(
307209b59c7dSAndrew Rybchenko __in efx_nic_t *enp,
307309b59c7dSAndrew Rybchenko __in uint32_t ndescs,
307409b59c7dSAndrew Rybchenko __in efx_evq_t *eep,
307509b59c7dSAndrew Rybchenko __in uint32_t label,
307609b59c7dSAndrew Rybchenko __in uint32_t instance,
307709b59c7dSAndrew Rybchenko __in efsys_mem_t *esmp,
30787640543fSAndrew Rybchenko __in const efx_mcdi_init_rxq_params_t *params)
307909b59c7dSAndrew Rybchenko {
308009b59c7dSAndrew Rybchenko efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
308109b59c7dSAndrew Rybchenko efx_mcdi_req_t req;
3082c1f02189SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_INIT_RXQ_V5_IN_LEN,
3083c1f02189SAndrew Rybchenko MC_CMD_INIT_RXQ_V5_OUT_LEN);
308409b59c7dSAndrew Rybchenko int npages = efx_rxq_nbufs(enp, ndescs);
308509b59c7dSAndrew Rybchenko int i;
308609b59c7dSAndrew Rybchenko efx_qword_t *dma_addr;
308709b59c7dSAndrew Rybchenko uint64_t addr;
308809b59c7dSAndrew Rybchenko efx_rc_t rc;
308909b59c7dSAndrew Rybchenko uint32_t dma_mode;
309009b59c7dSAndrew Rybchenko boolean_t want_outer_classes;
309109b59c7dSAndrew Rybchenko boolean_t no_cont_ev;
309209b59c7dSAndrew Rybchenko
309309b59c7dSAndrew Rybchenko EFSYS_ASSERT3U(ndescs, <=, encp->enc_rxq_max_ndescs);
309409b59c7dSAndrew Rybchenko
309509b59c7dSAndrew Rybchenko if ((esmp == NULL) ||
309609b59c7dSAndrew Rybchenko (EFSYS_MEM_SIZE(esmp) < efx_rxq_size(enp, ndescs))) {
309709b59c7dSAndrew Rybchenko rc = EINVAL;
309809b59c7dSAndrew Rybchenko goto fail1;
309909b59c7dSAndrew Rybchenko }
310009b59c7dSAndrew Rybchenko
310109b59c7dSAndrew Rybchenko no_cont_ev = (eep->ee_flags & EFX_EVQ_FLAGS_NO_CONT_EV);
31027640543fSAndrew Rybchenko if ((no_cont_ev == B_TRUE) && (params->disable_scatter == B_FALSE)) {
310309b59c7dSAndrew Rybchenko /* TODO: Support scatter in NO_CONT_EV mode */
310409b59c7dSAndrew Rybchenko rc = EINVAL;
310509b59c7dSAndrew Rybchenko goto fail2;
310609b59c7dSAndrew Rybchenko }
310709b59c7dSAndrew Rybchenko
31087640543fSAndrew Rybchenko if (params->ps_buf_size > 0)
310909b59c7dSAndrew Rybchenko dma_mode = MC_CMD_INIT_RXQ_EXT_IN_PACKED_STREAM;
31107640543fSAndrew Rybchenko else if (params->es_bufs_per_desc > 0)
311109b59c7dSAndrew Rybchenko dma_mode = MC_CMD_INIT_RXQ_V3_IN_EQUAL_STRIDE_SUPER_BUFFER;
311209b59c7dSAndrew Rybchenko else
311309b59c7dSAndrew Rybchenko dma_mode = MC_CMD_INIT_RXQ_EXT_IN_SINGLE_PACKET;
311409b59c7dSAndrew Rybchenko
311509b59c7dSAndrew Rybchenko if (encp->enc_tunnel_encapsulations_supported != 0 &&
31167640543fSAndrew Rybchenko !params->want_inner_classes) {
311709b59c7dSAndrew Rybchenko /*
311809b59c7dSAndrew Rybchenko * WANT_OUTER_CLASSES can only be specified on hardware which
311909b59c7dSAndrew Rybchenko * supports tunnel encapsulation offloads, even though it is
312009b59c7dSAndrew Rybchenko * effectively the behaviour the hardware gives.
312109b59c7dSAndrew Rybchenko *
312209b59c7dSAndrew Rybchenko * Also, on hardware which does support such offloads, older
312309b59c7dSAndrew Rybchenko * firmware rejects the flag if the offloads are not supported
312409b59c7dSAndrew Rybchenko * by the current firmware variant, which means this may fail if
312509b59c7dSAndrew Rybchenko * the capabilities are not updated when the firmware variant
312609b59c7dSAndrew Rybchenko * changes. This is not an issue on newer firmware, as it was
312709b59c7dSAndrew Rybchenko * changed in bug 69842 (v6.4.2.1007) to permit this flag to be
312809b59c7dSAndrew Rybchenko * specified on all firmware variants.
312909b59c7dSAndrew Rybchenko */
313009b59c7dSAndrew Rybchenko want_outer_classes = B_TRUE;
313109b59c7dSAndrew Rybchenko } else {
313209b59c7dSAndrew Rybchenko want_outer_classes = B_FALSE;
313309b59c7dSAndrew Rybchenko }
313409b59c7dSAndrew Rybchenko
313509b59c7dSAndrew Rybchenko req.emr_cmd = MC_CMD_INIT_RXQ;
313609b59c7dSAndrew Rybchenko req.emr_in_buf = payload;
3137c1f02189SAndrew Rybchenko req.emr_in_length = MC_CMD_INIT_RXQ_V5_IN_LEN;
313809b59c7dSAndrew Rybchenko req.emr_out_buf = payload;
3139c1f02189SAndrew Rybchenko req.emr_out_length = MC_CMD_INIT_RXQ_V5_OUT_LEN;
314009b59c7dSAndrew Rybchenko
314109b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_SIZE, ndescs);
314209b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_TARGET_EVQ, eep->ee_index);
314309b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_LABEL, label);
314409b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_INSTANCE, instance);
314509b59c7dSAndrew Rybchenko MCDI_IN_POPULATE_DWORD_10(req, INIT_RXQ_EXT_IN_FLAGS,
314609b59c7dSAndrew Rybchenko INIT_RXQ_EXT_IN_FLAG_BUFF_MODE, 0,
314709b59c7dSAndrew Rybchenko INIT_RXQ_EXT_IN_FLAG_HDR_SPLIT, 0,
314809b59c7dSAndrew Rybchenko INIT_RXQ_EXT_IN_FLAG_TIMESTAMP, 0,
314909b59c7dSAndrew Rybchenko INIT_RXQ_EXT_IN_CRC_MODE, 0,
315009b59c7dSAndrew Rybchenko INIT_RXQ_EXT_IN_FLAG_PREFIX, 1,
31517640543fSAndrew Rybchenko INIT_RXQ_EXT_IN_FLAG_DISABLE_SCATTER, params->disable_scatter,
315209b59c7dSAndrew Rybchenko INIT_RXQ_EXT_IN_DMA_MODE,
315309b59c7dSAndrew Rybchenko dma_mode,
31547640543fSAndrew Rybchenko INIT_RXQ_EXT_IN_PACKED_STREAM_BUFF_SIZE, params->ps_buf_size,
315509b59c7dSAndrew Rybchenko INIT_RXQ_EXT_IN_FLAG_WANT_OUTER_CLASSES, want_outer_classes,
315609b59c7dSAndrew Rybchenko INIT_RXQ_EXT_IN_FLAG_NO_CONT_EV, no_cont_ev);
315709b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_OWNER_ID, 0);
315809b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_PORT_ID, enp->en_vport_id);
315909b59c7dSAndrew Rybchenko
31607640543fSAndrew Rybchenko if (params->es_bufs_per_desc > 0) {
316109b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req,
316209b59c7dSAndrew Rybchenko INIT_RXQ_V3_IN_ES_PACKET_BUFFERS_PER_BUCKET,
31637640543fSAndrew Rybchenko params->es_bufs_per_desc);
316409b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req,
31657640543fSAndrew Rybchenko INIT_RXQ_V3_IN_ES_MAX_DMA_LEN, params->es_max_dma_len);
316609b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req,
31677640543fSAndrew Rybchenko INIT_RXQ_V3_IN_ES_PACKET_STRIDE, params->es_buf_stride);
316809b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req,
316909b59c7dSAndrew Rybchenko INIT_RXQ_V3_IN_ES_HEAD_OF_LINE_BLOCK_TIMEOUT,
31707640543fSAndrew Rybchenko params->hol_block_timeout);
317109b59c7dSAndrew Rybchenko }
317209b59c7dSAndrew Rybchenko
317309b59c7dSAndrew Rybchenko if (encp->enc_init_rxq_with_buffer_size)
317409b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_RXQ_V4_IN_BUFFER_SIZE_BYTES,
31757640543fSAndrew Rybchenko params->buf_size);
317609b59c7dSAndrew Rybchenko
3177c1f02189SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_RXQ_V5_IN_RX_PREFIX_ID, params->prefix_id);
3178c1f02189SAndrew Rybchenko
317909b59c7dSAndrew Rybchenko dma_addr = MCDI_IN2(req, efx_qword_t, INIT_RXQ_IN_DMA_ADDR);
318009b59c7dSAndrew Rybchenko addr = EFSYS_MEM_ADDR(esmp);
318109b59c7dSAndrew Rybchenko
318209b59c7dSAndrew Rybchenko for (i = 0; i < npages; i++) {
318309b59c7dSAndrew Rybchenko EFX_POPULATE_QWORD_2(*dma_addr,
318409b59c7dSAndrew Rybchenko EFX_DWORD_1, (uint32_t)(addr >> 32),
318509b59c7dSAndrew Rybchenko EFX_DWORD_0, (uint32_t)(addr & 0xffffffff));
318609b59c7dSAndrew Rybchenko
318709b59c7dSAndrew Rybchenko dma_addr++;
318809b59c7dSAndrew Rybchenko addr += EFX_BUF_SIZE;
318909b59c7dSAndrew Rybchenko }
319009b59c7dSAndrew Rybchenko
319109b59c7dSAndrew Rybchenko efx_mcdi_execute(enp, &req);
319209b59c7dSAndrew Rybchenko
319309b59c7dSAndrew Rybchenko if (req.emr_rc != 0) {
319409b59c7dSAndrew Rybchenko rc = req.emr_rc;
319509b59c7dSAndrew Rybchenko goto fail3;
319609b59c7dSAndrew Rybchenko }
319709b59c7dSAndrew Rybchenko
319809b59c7dSAndrew Rybchenko return (0);
319909b59c7dSAndrew Rybchenko
320009b59c7dSAndrew Rybchenko fail3:
320109b59c7dSAndrew Rybchenko EFSYS_PROBE(fail3);
320209b59c7dSAndrew Rybchenko fail2:
320309b59c7dSAndrew Rybchenko EFSYS_PROBE(fail2);
320409b59c7dSAndrew Rybchenko fail1:
320509b59c7dSAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
320609b59c7dSAndrew Rybchenko
320709b59c7dSAndrew Rybchenko return (rc);
320809b59c7dSAndrew Rybchenko }
320909b59c7dSAndrew Rybchenko
321009b59c7dSAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_fini_rxq(__in efx_nic_t * enp,__in uint32_t instance)321109b59c7dSAndrew Rybchenko efx_mcdi_fini_rxq(
321209b59c7dSAndrew Rybchenko __in efx_nic_t *enp,
321309b59c7dSAndrew Rybchenko __in uint32_t instance)
321409b59c7dSAndrew Rybchenko {
321509b59c7dSAndrew Rybchenko efx_mcdi_req_t req;
321609b59c7dSAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FINI_RXQ_IN_LEN,
321709b59c7dSAndrew Rybchenko MC_CMD_FINI_RXQ_OUT_LEN);
321809b59c7dSAndrew Rybchenko efx_rc_t rc;
321909b59c7dSAndrew Rybchenko
322009b59c7dSAndrew Rybchenko req.emr_cmd = MC_CMD_FINI_RXQ;
322109b59c7dSAndrew Rybchenko req.emr_in_buf = payload;
322209b59c7dSAndrew Rybchenko req.emr_in_length = MC_CMD_FINI_RXQ_IN_LEN;
322309b59c7dSAndrew Rybchenko req.emr_out_buf = payload;
322409b59c7dSAndrew Rybchenko req.emr_out_length = MC_CMD_FINI_RXQ_OUT_LEN;
322509b59c7dSAndrew Rybchenko
322609b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req, FINI_RXQ_IN_INSTANCE, instance);
322709b59c7dSAndrew Rybchenko
322809b59c7dSAndrew Rybchenko efx_mcdi_execute_quiet(enp, &req);
322909b59c7dSAndrew Rybchenko
323009b59c7dSAndrew Rybchenko if (req.emr_rc != 0) {
323109b59c7dSAndrew Rybchenko rc = req.emr_rc;
323209b59c7dSAndrew Rybchenko goto fail1;
323309b59c7dSAndrew Rybchenko }
323409b59c7dSAndrew Rybchenko
323509b59c7dSAndrew Rybchenko return (0);
323609b59c7dSAndrew Rybchenko
323709b59c7dSAndrew Rybchenko fail1:
323809b59c7dSAndrew Rybchenko /*
323909b59c7dSAndrew Rybchenko * EALREADY is not an error, but indicates that the MC has rebooted and
324009b59c7dSAndrew Rybchenko * that the RXQ has already been destroyed.
324109b59c7dSAndrew Rybchenko */
324209b59c7dSAndrew Rybchenko if (rc != EALREADY)
324309b59c7dSAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
324409b59c7dSAndrew Rybchenko
324509b59c7dSAndrew Rybchenko return (rc);
324609b59c7dSAndrew Rybchenko }
324709b59c7dSAndrew Rybchenko
324870dc9c54SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_init_txq(__in efx_nic_t * enp,__in uint32_t ndescs,__in uint32_t target_evq,__in uint32_t label,__in uint32_t instance,__in uint16_t flags,__in efsys_mem_t * esmp)324970dc9c54SAndrew Rybchenko efx_mcdi_init_txq(
325070dc9c54SAndrew Rybchenko __in efx_nic_t *enp,
325170dc9c54SAndrew Rybchenko __in uint32_t ndescs,
325270dc9c54SAndrew Rybchenko __in uint32_t target_evq,
325370dc9c54SAndrew Rybchenko __in uint32_t label,
325470dc9c54SAndrew Rybchenko __in uint32_t instance,
325570dc9c54SAndrew Rybchenko __in uint16_t flags,
325670dc9c54SAndrew Rybchenko __in efsys_mem_t *esmp)
325770dc9c54SAndrew Rybchenko {
325870dc9c54SAndrew Rybchenko efx_mcdi_req_t req;
32594664935aSAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_INIT_TXQ_EXT_IN_LEN,
326070dc9c54SAndrew Rybchenko MC_CMD_INIT_TXQ_OUT_LEN);
326170dc9c54SAndrew Rybchenko efx_qword_t *dma_addr;
326270dc9c54SAndrew Rybchenko uint64_t addr;
326370dc9c54SAndrew Rybchenko int npages;
326470dc9c54SAndrew Rybchenko int i;
326570dc9c54SAndrew Rybchenko efx_rc_t rc;
326670dc9c54SAndrew Rybchenko
32674664935aSAndrew Rybchenko EFSYS_ASSERT(MC_CMD_INIT_TXQ_EXT_IN_DMA_ADDR_MAXNUM >=
326870dc9c54SAndrew Rybchenko efx_txq_nbufs(enp, enp->en_nic_cfg.enc_txq_max_ndescs));
326970dc9c54SAndrew Rybchenko
327070dc9c54SAndrew Rybchenko if ((esmp == NULL) ||
327170dc9c54SAndrew Rybchenko (EFSYS_MEM_SIZE(esmp) < efx_txq_size(enp, ndescs))) {
327270dc9c54SAndrew Rybchenko rc = EINVAL;
327370dc9c54SAndrew Rybchenko goto fail1;
327470dc9c54SAndrew Rybchenko }
327570dc9c54SAndrew Rybchenko
327670dc9c54SAndrew Rybchenko npages = efx_txq_nbufs(enp, ndescs);
327770dc9c54SAndrew Rybchenko if (MC_CMD_INIT_TXQ_IN_LEN(npages) > sizeof (payload)) {
327870dc9c54SAndrew Rybchenko rc = EINVAL;
327970dc9c54SAndrew Rybchenko goto fail2;
328070dc9c54SAndrew Rybchenko }
328170dc9c54SAndrew Rybchenko
328270dc9c54SAndrew Rybchenko req.emr_cmd = MC_CMD_INIT_TXQ;
328370dc9c54SAndrew Rybchenko req.emr_in_buf = payload;
328470dc9c54SAndrew Rybchenko req.emr_in_length = MC_CMD_INIT_TXQ_IN_LEN(npages);
328570dc9c54SAndrew Rybchenko req.emr_out_buf = payload;
328670dc9c54SAndrew Rybchenko req.emr_out_length = MC_CMD_INIT_TXQ_OUT_LEN;
328770dc9c54SAndrew Rybchenko
328870dc9c54SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_SIZE, ndescs);
328970dc9c54SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_TARGET_EVQ, target_evq);
329070dc9c54SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_LABEL, label);
329170dc9c54SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_INSTANCE, instance);
329270dc9c54SAndrew Rybchenko
329370dc9c54SAndrew Rybchenko MCDI_IN_POPULATE_DWORD_9(req, INIT_TXQ_IN_FLAGS,
329470dc9c54SAndrew Rybchenko INIT_TXQ_IN_FLAG_BUFF_MODE, 0,
329570dc9c54SAndrew Rybchenko INIT_TXQ_IN_FLAG_IP_CSUM_DIS,
329670dc9c54SAndrew Rybchenko (flags & EFX_TXQ_CKSUM_IPV4) ? 0 : 1,
329770dc9c54SAndrew Rybchenko INIT_TXQ_IN_FLAG_TCP_CSUM_DIS,
329870dc9c54SAndrew Rybchenko (flags & EFX_TXQ_CKSUM_TCPUDP) ? 0 : 1,
329970dc9c54SAndrew Rybchenko INIT_TXQ_EXT_IN_FLAG_INNER_IP_CSUM_EN,
330070dc9c54SAndrew Rybchenko (flags & EFX_TXQ_CKSUM_INNER_IPV4) ? 1 : 0,
330170dc9c54SAndrew Rybchenko INIT_TXQ_EXT_IN_FLAG_INNER_TCP_CSUM_EN,
330270dc9c54SAndrew Rybchenko (flags & EFX_TXQ_CKSUM_INNER_TCPUDP) ? 1 : 0,
330370dc9c54SAndrew Rybchenko INIT_TXQ_EXT_IN_FLAG_TSOV2_EN, (flags & EFX_TXQ_FATSOV2) ? 1 : 0,
330470dc9c54SAndrew Rybchenko INIT_TXQ_IN_FLAG_TCP_UDP_ONLY, 0,
330570dc9c54SAndrew Rybchenko INIT_TXQ_IN_CRC_MODE, 0,
330670dc9c54SAndrew Rybchenko INIT_TXQ_IN_FLAG_TIMESTAMP, 0);
330770dc9c54SAndrew Rybchenko
330870dc9c54SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_OWNER_ID, 0);
330970dc9c54SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_PORT_ID, enp->en_vport_id);
331070dc9c54SAndrew Rybchenko
331170dc9c54SAndrew Rybchenko dma_addr = MCDI_IN2(req, efx_qword_t, INIT_TXQ_IN_DMA_ADDR);
331270dc9c54SAndrew Rybchenko addr = EFSYS_MEM_ADDR(esmp);
331370dc9c54SAndrew Rybchenko
331470dc9c54SAndrew Rybchenko for (i = 0; i < npages; i++) {
331570dc9c54SAndrew Rybchenko EFX_POPULATE_QWORD_2(*dma_addr,
331670dc9c54SAndrew Rybchenko EFX_DWORD_1, (uint32_t)(addr >> 32),
331770dc9c54SAndrew Rybchenko EFX_DWORD_0, (uint32_t)(addr & 0xffffffff));
331870dc9c54SAndrew Rybchenko
331970dc9c54SAndrew Rybchenko dma_addr++;
332070dc9c54SAndrew Rybchenko addr += EFX_BUF_SIZE;
332170dc9c54SAndrew Rybchenko }
332270dc9c54SAndrew Rybchenko
332370dc9c54SAndrew Rybchenko efx_mcdi_execute(enp, &req);
332470dc9c54SAndrew Rybchenko
332570dc9c54SAndrew Rybchenko if (req.emr_rc != 0) {
332670dc9c54SAndrew Rybchenko rc = req.emr_rc;
332770dc9c54SAndrew Rybchenko goto fail3;
332870dc9c54SAndrew Rybchenko }
332970dc9c54SAndrew Rybchenko
333070dc9c54SAndrew Rybchenko return (0);
333170dc9c54SAndrew Rybchenko
333270dc9c54SAndrew Rybchenko fail3:
333370dc9c54SAndrew Rybchenko EFSYS_PROBE(fail3);
333470dc9c54SAndrew Rybchenko fail2:
333570dc9c54SAndrew Rybchenko EFSYS_PROBE(fail2);
333670dc9c54SAndrew Rybchenko fail1:
333770dc9c54SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
333870dc9c54SAndrew Rybchenko
333970dc9c54SAndrew Rybchenko return (rc);
334070dc9c54SAndrew Rybchenko }
334170dc9c54SAndrew Rybchenko
334270dc9c54SAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_fini_txq(__in efx_nic_t * enp,__in uint32_t instance)334370dc9c54SAndrew Rybchenko efx_mcdi_fini_txq(
334470dc9c54SAndrew Rybchenko __in efx_nic_t *enp,
334570dc9c54SAndrew Rybchenko __in uint32_t instance)
334670dc9c54SAndrew Rybchenko {
334770dc9c54SAndrew Rybchenko efx_mcdi_req_t req;
334870dc9c54SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FINI_TXQ_IN_LEN,
334970dc9c54SAndrew Rybchenko MC_CMD_FINI_TXQ_OUT_LEN);
335070dc9c54SAndrew Rybchenko efx_rc_t rc;
335170dc9c54SAndrew Rybchenko
335270dc9c54SAndrew Rybchenko req.emr_cmd = MC_CMD_FINI_TXQ;
335370dc9c54SAndrew Rybchenko req.emr_in_buf = payload;
335470dc9c54SAndrew Rybchenko req.emr_in_length = MC_CMD_FINI_TXQ_IN_LEN;
335570dc9c54SAndrew Rybchenko req.emr_out_buf = payload;
335670dc9c54SAndrew Rybchenko req.emr_out_length = MC_CMD_FINI_TXQ_OUT_LEN;
335770dc9c54SAndrew Rybchenko
335870dc9c54SAndrew Rybchenko MCDI_IN_SET_DWORD(req, FINI_TXQ_IN_INSTANCE, instance);
335970dc9c54SAndrew Rybchenko
336070dc9c54SAndrew Rybchenko efx_mcdi_execute_quiet(enp, &req);
336170dc9c54SAndrew Rybchenko
336270dc9c54SAndrew Rybchenko if (req.emr_rc != 0) {
336370dc9c54SAndrew Rybchenko rc = req.emr_rc;
336470dc9c54SAndrew Rybchenko goto fail1;
336570dc9c54SAndrew Rybchenko }
336670dc9c54SAndrew Rybchenko
336770dc9c54SAndrew Rybchenko return (0);
336870dc9c54SAndrew Rybchenko
336970dc9c54SAndrew Rybchenko fail1:
337070dc9c54SAndrew Rybchenko /*
337170dc9c54SAndrew Rybchenko * EALREADY is not an error, but indicates that the MC has rebooted and
337270dc9c54SAndrew Rybchenko * that the TXQ has already been destroyed.
337370dc9c54SAndrew Rybchenko */
337470dc9c54SAndrew Rybchenko if (rc != EALREADY)
337570dc9c54SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
337670dc9c54SAndrew Rybchenko
337770dc9c54SAndrew Rybchenko return (rc);
337870dc9c54SAndrew Rybchenko }
337970dc9c54SAndrew Rybchenko
33804fd0181fSAndrew Rybchenko #endif /* EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10() */
338109b59c7dSAndrew Rybchenko
338260fb370cSAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_get_nic_addr_info(__in efx_nic_t * enp,__out uint32_t * mapping_typep)338360fb370cSAndrew Rybchenko efx_mcdi_get_nic_addr_info(
338460fb370cSAndrew Rybchenko __in efx_nic_t *enp,
338560fb370cSAndrew Rybchenko __out uint32_t *mapping_typep)
338660fb370cSAndrew Rybchenko {
338760fb370cSAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_DESC_ADDR_INFO_IN_LEN,
338860fb370cSAndrew Rybchenko MC_CMD_GET_DESC_ADDR_INFO_OUT_LEN);
338960fb370cSAndrew Rybchenko efx_mcdi_req_t req;
339060fb370cSAndrew Rybchenko efx_rc_t rc;
339160fb370cSAndrew Rybchenko
339260fb370cSAndrew Rybchenko req.emr_cmd = MC_CMD_GET_DESC_ADDR_INFO;
339360fb370cSAndrew Rybchenko req.emr_in_buf = payload;
339460fb370cSAndrew Rybchenko req.emr_in_length = MC_CMD_GET_DESC_ADDR_INFO_IN_LEN;
339560fb370cSAndrew Rybchenko req.emr_out_buf = payload;
339660fb370cSAndrew Rybchenko req.emr_out_length = MC_CMD_GET_DESC_ADDR_INFO_OUT_LEN;
339760fb370cSAndrew Rybchenko
339860fb370cSAndrew Rybchenko efx_mcdi_execute_quiet(enp, &req);
339960fb370cSAndrew Rybchenko
340060fb370cSAndrew Rybchenko if (req.emr_rc != 0) {
340160fb370cSAndrew Rybchenko rc = req.emr_rc;
340260fb370cSAndrew Rybchenko goto fail1;
340360fb370cSAndrew Rybchenko }
340460fb370cSAndrew Rybchenko
340560fb370cSAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_DESC_ADDR_INFO_OUT_LEN) {
340660fb370cSAndrew Rybchenko rc = EMSGSIZE;
340760fb370cSAndrew Rybchenko goto fail2;
340860fb370cSAndrew Rybchenko }
340960fb370cSAndrew Rybchenko
341060fb370cSAndrew Rybchenko *mapping_typep =
341160fb370cSAndrew Rybchenko MCDI_OUT_DWORD(req, GET_DESC_ADDR_INFO_OUT_MAPPING_TYPE);
341260fb370cSAndrew Rybchenko
341360fb370cSAndrew Rybchenko return (0);
341460fb370cSAndrew Rybchenko
341560fb370cSAndrew Rybchenko fail2:
341660fb370cSAndrew Rybchenko EFSYS_PROBE(fail2);
341760fb370cSAndrew Rybchenko fail1:
341860fb370cSAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
341960fb370cSAndrew Rybchenko
342060fb370cSAndrew Rybchenko return (rc);
342160fb370cSAndrew Rybchenko }
342260fb370cSAndrew Rybchenko
342360fb370cSAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_get_nic_addr_regions(__in efx_nic_t * enp,__out efx_nic_dma_region_info_t * endrip)342460fb370cSAndrew Rybchenko efx_mcdi_get_nic_addr_regions(
342560fb370cSAndrew Rybchenko __in efx_nic_t *enp,
342660fb370cSAndrew Rybchenko __out efx_nic_dma_region_info_t *endrip)
342760fb370cSAndrew Rybchenko {
342860fb370cSAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_DESC_ADDR_REGIONS_IN_LEN,
342960fb370cSAndrew Rybchenko MC_CMD_GET_DESC_ADDR_REGIONS_OUT_LENMAX_MCDI2);
343060fb370cSAndrew Rybchenko efx_xword_t *regions;
343160fb370cSAndrew Rybchenko efx_mcdi_req_t req;
343260fb370cSAndrew Rybchenko efx_rc_t rc;
343360fb370cSAndrew Rybchenko size_t alloc_size;
343460fb370cSAndrew Rybchenko unsigned int nregions;
343560fb370cSAndrew Rybchenko unsigned int i;
343660fb370cSAndrew Rybchenko
343760fb370cSAndrew Rybchenko req.emr_cmd = MC_CMD_GET_DESC_ADDR_REGIONS;
343860fb370cSAndrew Rybchenko req.emr_in_buf = payload;
343960fb370cSAndrew Rybchenko req.emr_in_length = MC_CMD_GET_DESC_ADDR_REGIONS_IN_LEN;
344060fb370cSAndrew Rybchenko req.emr_out_buf = payload;
344160fb370cSAndrew Rybchenko req.emr_out_length = MC_CMD_GET_DESC_ADDR_REGIONS_OUT_LENMAX_MCDI2;
344260fb370cSAndrew Rybchenko
344360fb370cSAndrew Rybchenko efx_mcdi_execute_quiet(enp, &req);
344460fb370cSAndrew Rybchenko
344560fb370cSAndrew Rybchenko if (req.emr_rc != 0) {
344660fb370cSAndrew Rybchenko rc = req.emr_rc;
344760fb370cSAndrew Rybchenko goto fail1;
344860fb370cSAndrew Rybchenko }
344960fb370cSAndrew Rybchenko
345060fb370cSAndrew Rybchenko if (req.emr_out_length_used <
345160fb370cSAndrew Rybchenko MC_CMD_GET_DESC_ADDR_REGIONS_OUT_LENMIN) {
345260fb370cSAndrew Rybchenko rc = EMSGSIZE;
345360fb370cSAndrew Rybchenko goto fail2;
345460fb370cSAndrew Rybchenko }
345560fb370cSAndrew Rybchenko
345660fb370cSAndrew Rybchenko nregions = MC_CMD_GET_DESC_ADDR_REGIONS_OUT_REGIONS_NUM(
345760fb370cSAndrew Rybchenko req.emr_out_length_used);
345860fb370cSAndrew Rybchenko
345960fb370cSAndrew Rybchenko EFX_STATIC_ASSERT(sizeof (*regions) == DESC_ADDR_REGION_LEN);
346060fb370cSAndrew Rybchenko regions = MCDI_OUT2(req, efx_xword_t,
346160fb370cSAndrew Rybchenko GET_DESC_ADDR_REGIONS_OUT_REGIONS);
346260fb370cSAndrew Rybchenko
346360fb370cSAndrew Rybchenko alloc_size = nregions * sizeof(endrip->endri_regions[0]);
346460fb370cSAndrew Rybchenko if (alloc_size / sizeof (endrip->endri_regions[0]) != nregions) {
346560fb370cSAndrew Rybchenko rc = ENOMEM;
346660fb370cSAndrew Rybchenko goto fail3;
346760fb370cSAndrew Rybchenko }
346860fb370cSAndrew Rybchenko
346960fb370cSAndrew Rybchenko EFSYS_KMEM_ALLOC(enp->en_esip,
347060fb370cSAndrew Rybchenko alloc_size,
347160fb370cSAndrew Rybchenko endrip->endri_regions);
347260fb370cSAndrew Rybchenko if (endrip->endri_regions == NULL) {
347360fb370cSAndrew Rybchenko rc = ENOMEM;
347460fb370cSAndrew Rybchenko goto fail4;
347560fb370cSAndrew Rybchenko }
347660fb370cSAndrew Rybchenko
347760fb370cSAndrew Rybchenko endrip->endri_count = nregions;
347860fb370cSAndrew Rybchenko for (i = 0; i < nregions; ++i) {
347960fb370cSAndrew Rybchenko efx_nic_dma_region_t *region_info;
348060fb370cSAndrew Rybchenko
348160fb370cSAndrew Rybchenko region_info = &endrip->endri_regions[i];
348260fb370cSAndrew Rybchenko
348360fb370cSAndrew Rybchenko region_info->endr_inuse = B_FALSE;
348460fb370cSAndrew Rybchenko
348560fb370cSAndrew Rybchenko region_info->endr_nic_base =
348660fb370cSAndrew Rybchenko MCDI_OUT_INDEXED_MEMBER_QWORD(req,
348760fb370cSAndrew Rybchenko GET_DESC_ADDR_REGIONS_OUT_REGIONS, i,
348860fb370cSAndrew Rybchenko DESC_ADDR_REGION_DESC_ADDR_BASE);
348960fb370cSAndrew Rybchenko
349060fb370cSAndrew Rybchenko region_info->endr_trgt_base =
349160fb370cSAndrew Rybchenko MCDI_OUT_INDEXED_MEMBER_QWORD(req,
349260fb370cSAndrew Rybchenko GET_DESC_ADDR_REGIONS_OUT_REGIONS, i,
349360fb370cSAndrew Rybchenko DESC_ADDR_REGION_TRGT_ADDR_BASE);
349460fb370cSAndrew Rybchenko
349560fb370cSAndrew Rybchenko region_info->endr_window_log2 =
349660fb370cSAndrew Rybchenko MCDI_OUT_INDEXED_MEMBER_DWORD(req,
349760fb370cSAndrew Rybchenko GET_DESC_ADDR_REGIONS_OUT_REGIONS, i,
349860fb370cSAndrew Rybchenko DESC_ADDR_REGION_WINDOW_SIZE_LOG2);
349960fb370cSAndrew Rybchenko
350060fb370cSAndrew Rybchenko region_info->endr_align_log2 =
350160fb370cSAndrew Rybchenko MCDI_OUT_INDEXED_MEMBER_DWORD(req,
350260fb370cSAndrew Rybchenko GET_DESC_ADDR_REGIONS_OUT_REGIONS, i,
350360fb370cSAndrew Rybchenko DESC_ADDR_REGION_TRGT_ADDR_ALIGN_LOG2);
350460fb370cSAndrew Rybchenko }
350560fb370cSAndrew Rybchenko
350660fb370cSAndrew Rybchenko return (0);
350760fb370cSAndrew Rybchenko
350860fb370cSAndrew Rybchenko fail4:
350960fb370cSAndrew Rybchenko EFSYS_PROBE(fail4);
351060fb370cSAndrew Rybchenko fail3:
351160fb370cSAndrew Rybchenko EFSYS_PROBE(fail3);
351260fb370cSAndrew Rybchenko fail2:
351360fb370cSAndrew Rybchenko EFSYS_PROBE(fail2);
351460fb370cSAndrew Rybchenko fail1:
351560fb370cSAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
351660fb370cSAndrew Rybchenko
351760fb370cSAndrew Rybchenko return (rc);
351860fb370cSAndrew Rybchenko }
351960fb370cSAndrew Rybchenko
352060fb370cSAndrew Rybchenko __checkReturn efx_rc_t
efx_mcdi_set_nic_addr_regions(__in efx_nic_t * enp,__in const efx_nic_dma_region_info_t * endrip)352160fb370cSAndrew Rybchenko efx_mcdi_set_nic_addr_regions(
352260fb370cSAndrew Rybchenko __in efx_nic_t *enp,
352360fb370cSAndrew Rybchenko __in const efx_nic_dma_region_info_t *endrip)
352460fb370cSAndrew Rybchenko {
352560fb370cSAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload,
352660fb370cSAndrew Rybchenko MC_CMD_SET_DESC_ADDR_REGIONS_IN_LENMAX_MCDI2,
352760fb370cSAndrew Rybchenko MC_CMD_SET_DESC_ADDR_REGIONS_OUT_LEN);
352860fb370cSAndrew Rybchenko efx_qword_t *trgt_addr_base;
352960fb370cSAndrew Rybchenko efx_mcdi_req_t req;
353060fb370cSAndrew Rybchenko unsigned int i;
353160fb370cSAndrew Rybchenko efx_rc_t rc;
353260fb370cSAndrew Rybchenko
353360fb370cSAndrew Rybchenko if (endrip->endri_count >
353460fb370cSAndrew Rybchenko MC_CMD_SET_DESC_ADDR_REGIONS_IN_TRGT_ADDR_BASE_MAXNUM) {
353560fb370cSAndrew Rybchenko rc = EINVAL;
353660fb370cSAndrew Rybchenko goto fail1;
353760fb370cSAndrew Rybchenko }
353860fb370cSAndrew Rybchenko
353960fb370cSAndrew Rybchenko req.emr_cmd = MC_CMD_SET_DESC_ADDR_REGIONS;
354060fb370cSAndrew Rybchenko req.emr_in_buf = payload;
354160fb370cSAndrew Rybchenko req.emr_in_length =
354260fb370cSAndrew Rybchenko MC_CMD_SET_DESC_ADDR_REGIONS_IN_LEN(endrip->endri_count);
354360fb370cSAndrew Rybchenko req.emr_out_buf = payload;
354460fb370cSAndrew Rybchenko req.emr_out_length = MC_CMD_SET_DESC_ADDR_REGIONS_OUT_LEN;
354560fb370cSAndrew Rybchenko
354660fb370cSAndrew Rybchenko EFX_STATIC_ASSERT(sizeof (*trgt_addr_base) ==
354760fb370cSAndrew Rybchenko MC_CMD_SET_DESC_ADDR_REGIONS_IN_TRGT_ADDR_BASE_LEN);
354860fb370cSAndrew Rybchenko trgt_addr_base = MCDI_OUT2(req, efx_qword_t,
354960fb370cSAndrew Rybchenko SET_DESC_ADDR_REGIONS_IN_TRGT_ADDR_BASE);
355060fb370cSAndrew Rybchenko
355160fb370cSAndrew Rybchenko for (i = 0; i < endrip->endri_count; ++i) {
355260fb370cSAndrew Rybchenko const efx_nic_dma_region_t *region_info;
355360fb370cSAndrew Rybchenko
355460fb370cSAndrew Rybchenko region_info = &endrip->endri_regions[i];
355560fb370cSAndrew Rybchenko
355660fb370cSAndrew Rybchenko if (region_info->endr_inuse != B_TRUE)
355760fb370cSAndrew Rybchenko continue;
355860fb370cSAndrew Rybchenko
355960fb370cSAndrew Rybchenko EFX_STATIC_ASSERT(sizeof (1U) * 8 >=
356060fb370cSAndrew Rybchenko MC_CMD_SET_DESC_ADDR_REGIONS_IN_TRGT_ADDR_BASE_MAXNUM);
356160fb370cSAndrew Rybchenko MCDI_IN_SET_DWORD(req,
356260fb370cSAndrew Rybchenko SET_DESC_ADDR_REGIONS_IN_SET_REGION_MASK, 1U << i);
356360fb370cSAndrew Rybchenko
356460fb370cSAndrew Rybchenko MCDI_IN_SET_INDEXED_QWORD(req,
356560fb370cSAndrew Rybchenko SET_DESC_ADDR_REGIONS_IN_TRGT_ADDR_BASE, i,
356660fb370cSAndrew Rybchenko region_info->endr_trgt_base);
356760fb370cSAndrew Rybchenko }
356860fb370cSAndrew Rybchenko
356960fb370cSAndrew Rybchenko efx_mcdi_execute_quiet(enp, &req);
357060fb370cSAndrew Rybchenko
357160fb370cSAndrew Rybchenko if (req.emr_rc != 0) {
357260fb370cSAndrew Rybchenko rc = req.emr_rc;
357360fb370cSAndrew Rybchenko goto fail2;
357460fb370cSAndrew Rybchenko }
357560fb370cSAndrew Rybchenko
357660fb370cSAndrew Rybchenko return (0);
357760fb370cSAndrew Rybchenko
357860fb370cSAndrew Rybchenko fail2:
357960fb370cSAndrew Rybchenko EFSYS_PROBE(fail2);
358060fb370cSAndrew Rybchenko fail1:
358160fb370cSAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
358260fb370cSAndrew Rybchenko
358360fb370cSAndrew Rybchenko return (rc);
358460fb370cSAndrew Rybchenko }
358560fb370cSAndrew Rybchenko
35865e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MCDI */
3587