15e111ed8SAndrew Rybchenko /* SPDX-License-Identifier: BSD-3-Clause 25e111ed8SAndrew Rybchenko * 35e111ed8SAndrew Rybchenko * Copyright(c) 2019-2020 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 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 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 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 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 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 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 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 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 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 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 5195e111ed8SAndrew Rybchenko #if EFSYS_OPT_MCDI_LOGGING 5205e111ed8SAndrew Rybchenko if (emtp->emt_logger != NULL) { 5215e111ed8SAndrew Rybchenko emtp->emt_logger(emtp->emt_context, 5225e111ed8SAndrew Rybchenko EFX_LOG_MCDI_RESPONSE, 5235e111ed8SAndrew Rybchenko &hdr[0], hdr_len, 5245e111ed8SAndrew Rybchenko emrp->emr_out_buf, bytes); 5255e111ed8SAndrew Rybchenko } 5265e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MCDI_LOGGING */ 5275e111ed8SAndrew Rybchenko } 5285e111ed8SAndrew Rybchenko 5295e111ed8SAndrew Rybchenko 5305e111ed8SAndrew Rybchenko __checkReturn boolean_t 5315e111ed8SAndrew Rybchenko efx_mcdi_request_poll( 5325e111ed8SAndrew Rybchenko __in efx_nic_t *enp) 5335e111ed8SAndrew Rybchenko { 5345e111ed8SAndrew Rybchenko efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 5355e111ed8SAndrew Rybchenko efx_mcdi_req_t *emrp; 5365e111ed8SAndrew Rybchenko efsys_lock_state_t state; 5375e111ed8SAndrew Rybchenko efx_rc_t rc; 5385e111ed8SAndrew Rybchenko 5395e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 5405e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 5415e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 5425e111ed8SAndrew Rybchenko 5435e111ed8SAndrew Rybchenko /* Serialise against post-watchdog efx_mcdi_ev* */ 5445e111ed8SAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state); 5455e111ed8SAndrew Rybchenko 5465e111ed8SAndrew Rybchenko EFSYS_ASSERT(emip->emi_pending_req != NULL); 5475e111ed8SAndrew Rybchenko EFSYS_ASSERT(!emip->emi_ev_cpl); 5485e111ed8SAndrew Rybchenko emrp = emip->emi_pending_req; 5495e111ed8SAndrew Rybchenko 5505e111ed8SAndrew Rybchenko /* Check if hardware is unavailable */ 5515e111ed8SAndrew Rybchenko if (efx_nic_hw_unavailable(enp)) { 5525e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state); 5535e111ed8SAndrew Rybchenko return (B_FALSE); 5545e111ed8SAndrew Rybchenko } 5555e111ed8SAndrew Rybchenko 5565e111ed8SAndrew Rybchenko /* Check for reboot atomically w.r.t efx_mcdi_request_start */ 5575e111ed8SAndrew Rybchenko if (emip->emi_poll_cnt++ == 0) { 5585e111ed8SAndrew Rybchenko if ((rc = efx_mcdi_poll_reboot(enp)) != 0) { 5595e111ed8SAndrew Rybchenko emip->emi_pending_req = NULL; 5605e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state); 5615e111ed8SAndrew Rybchenko 5625e111ed8SAndrew Rybchenko /* Reboot/Assertion */ 5635e111ed8SAndrew Rybchenko if (rc == EIO || rc == EINTR) 5645e111ed8SAndrew Rybchenko efx_mcdi_raise_exception(enp, emrp, rc); 5655e111ed8SAndrew Rybchenko 5665e111ed8SAndrew Rybchenko goto fail1; 5675e111ed8SAndrew Rybchenko } 5685e111ed8SAndrew Rybchenko } 5695e111ed8SAndrew Rybchenko 5705e111ed8SAndrew Rybchenko /* Check if a response is available */ 5715e111ed8SAndrew Rybchenko if (efx_mcdi_poll_response(enp) == B_FALSE) { 5725e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state); 5735e111ed8SAndrew Rybchenko return (B_FALSE); 5745e111ed8SAndrew Rybchenko } 5755e111ed8SAndrew Rybchenko 5765e111ed8SAndrew Rybchenko /* Read the response header */ 5775e111ed8SAndrew Rybchenko efx_mcdi_read_response_header(enp, emrp); 5785e111ed8SAndrew Rybchenko 5795e111ed8SAndrew Rybchenko /* Request complete */ 5805e111ed8SAndrew Rybchenko emip->emi_pending_req = NULL; 5815e111ed8SAndrew Rybchenko 5825e111ed8SAndrew Rybchenko /* Ensure stale MCDI requests fail after an MC reboot. */ 5835e111ed8SAndrew Rybchenko emip->emi_new_epoch = B_FALSE; 5845e111ed8SAndrew Rybchenko 5855e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state); 5865e111ed8SAndrew Rybchenko 5875e111ed8SAndrew Rybchenko if ((rc = emrp->emr_rc) != 0) 5885e111ed8SAndrew Rybchenko goto fail2; 5895e111ed8SAndrew Rybchenko 5905e111ed8SAndrew Rybchenko efx_mcdi_finish_response(enp, emrp); 5915e111ed8SAndrew Rybchenko return (B_TRUE); 5925e111ed8SAndrew Rybchenko 5935e111ed8SAndrew Rybchenko fail2: 5945e111ed8SAndrew Rybchenko if (!emrp->emr_quiet) 5955e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2); 5965e111ed8SAndrew Rybchenko fail1: 5975e111ed8SAndrew Rybchenko if (!emrp->emr_quiet) 5985e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 5995e111ed8SAndrew Rybchenko 6005e111ed8SAndrew Rybchenko return (B_TRUE); 6015e111ed8SAndrew Rybchenko } 6025e111ed8SAndrew Rybchenko 6035e111ed8SAndrew Rybchenko __checkReturn boolean_t 6045e111ed8SAndrew Rybchenko efx_mcdi_request_abort( 6055e111ed8SAndrew Rybchenko __in efx_nic_t *enp) 6065e111ed8SAndrew Rybchenko { 6075e111ed8SAndrew Rybchenko efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 6085e111ed8SAndrew Rybchenko efx_mcdi_req_t *emrp; 6095e111ed8SAndrew Rybchenko boolean_t aborted; 6105e111ed8SAndrew Rybchenko efsys_lock_state_t state; 6115e111ed8SAndrew Rybchenko 6125e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 6135e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 6145e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 6155e111ed8SAndrew Rybchenko 6165e111ed8SAndrew Rybchenko /* 6175e111ed8SAndrew Rybchenko * efx_mcdi_ev_* may have already completed this event, and be 6185e111ed8SAndrew Rybchenko * spinning/blocked on the upper layer lock. So it *is* legitimate 6195e111ed8SAndrew Rybchenko * to for emi_pending_req to be NULL. If there is a pending event 6205e111ed8SAndrew Rybchenko * completed request, then provide a "credit" to allow 6215e111ed8SAndrew Rybchenko * efx_mcdi_ev_cpl() to accept a single spurious completion. 6225e111ed8SAndrew Rybchenko */ 6235e111ed8SAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state); 6245e111ed8SAndrew Rybchenko emrp = emip->emi_pending_req; 6255e111ed8SAndrew Rybchenko aborted = (emrp != NULL); 6265e111ed8SAndrew Rybchenko if (aborted) { 6275e111ed8SAndrew Rybchenko emip->emi_pending_req = NULL; 6285e111ed8SAndrew Rybchenko 6295e111ed8SAndrew Rybchenko /* Error the request */ 6305e111ed8SAndrew Rybchenko emrp->emr_out_length_used = 0; 6315e111ed8SAndrew Rybchenko emrp->emr_rc = ETIMEDOUT; 6325e111ed8SAndrew Rybchenko 6335e111ed8SAndrew Rybchenko /* Provide a credit for seqno/emr_pending_req mismatches */ 6345e111ed8SAndrew Rybchenko if (emip->emi_ev_cpl) 6355e111ed8SAndrew Rybchenko ++emip->emi_aborted; 6365e111ed8SAndrew Rybchenko 6375e111ed8SAndrew Rybchenko /* 6385e111ed8SAndrew Rybchenko * The upper layer has called us, so we don't 6395e111ed8SAndrew Rybchenko * need to complete the request. 6405e111ed8SAndrew Rybchenko */ 6415e111ed8SAndrew Rybchenko } 6425e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state); 6435e111ed8SAndrew Rybchenko 6445e111ed8SAndrew Rybchenko return (aborted); 6455e111ed8SAndrew Rybchenko } 6465e111ed8SAndrew Rybchenko 6475e111ed8SAndrew Rybchenko void 6485e111ed8SAndrew Rybchenko efx_mcdi_get_timeout( 6495e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 6505e111ed8SAndrew Rybchenko __in efx_mcdi_req_t *emrp, 6515e111ed8SAndrew Rybchenko __out uint32_t *timeoutp) 6525e111ed8SAndrew Rybchenko { 6535e111ed8SAndrew Rybchenko const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 6545e111ed8SAndrew Rybchenko 6555e111ed8SAndrew Rybchenko emcop->emco_get_timeout(enp, emrp, timeoutp); 6565e111ed8SAndrew Rybchenko } 6575e111ed8SAndrew Rybchenko 6585e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 6595e111ed8SAndrew Rybchenko efx_mcdi_request_errcode( 6605e111ed8SAndrew Rybchenko __in unsigned int err) 6615e111ed8SAndrew Rybchenko { 6625e111ed8SAndrew Rybchenko 6635e111ed8SAndrew Rybchenko switch (err) { 6645e111ed8SAndrew Rybchenko /* MCDI v1 */ 6655e111ed8SAndrew Rybchenko case MC_CMD_ERR_EPERM: 6665e111ed8SAndrew Rybchenko return (EACCES); 6675e111ed8SAndrew Rybchenko case MC_CMD_ERR_ENOENT: 6685e111ed8SAndrew Rybchenko return (ENOENT); 6695e111ed8SAndrew Rybchenko case MC_CMD_ERR_EINTR: 6705e111ed8SAndrew Rybchenko return (EINTR); 6715e111ed8SAndrew Rybchenko case MC_CMD_ERR_EACCES: 6725e111ed8SAndrew Rybchenko return (EACCES); 6735e111ed8SAndrew Rybchenko case MC_CMD_ERR_EBUSY: 6745e111ed8SAndrew Rybchenko return (EBUSY); 6755e111ed8SAndrew Rybchenko case MC_CMD_ERR_EINVAL: 6765e111ed8SAndrew Rybchenko return (EINVAL); 6775e111ed8SAndrew Rybchenko case MC_CMD_ERR_EDEADLK: 6785e111ed8SAndrew Rybchenko return (EDEADLK); 6795e111ed8SAndrew Rybchenko case MC_CMD_ERR_ENOSYS: 6805e111ed8SAndrew Rybchenko return (ENOTSUP); 6815e111ed8SAndrew Rybchenko case MC_CMD_ERR_ETIME: 6825e111ed8SAndrew Rybchenko return (ETIMEDOUT); 6835e111ed8SAndrew Rybchenko case MC_CMD_ERR_ENOTSUP: 6845e111ed8SAndrew Rybchenko return (ENOTSUP); 6855e111ed8SAndrew Rybchenko case MC_CMD_ERR_EALREADY: 6865e111ed8SAndrew Rybchenko return (EALREADY); 6875e111ed8SAndrew Rybchenko 6885e111ed8SAndrew Rybchenko /* MCDI v2 */ 6895e111ed8SAndrew Rybchenko case MC_CMD_ERR_EEXIST: 6905e111ed8SAndrew Rybchenko return (EEXIST); 6915e111ed8SAndrew Rybchenko #ifdef MC_CMD_ERR_EAGAIN 6925e111ed8SAndrew Rybchenko case MC_CMD_ERR_EAGAIN: 6935e111ed8SAndrew Rybchenko return (EAGAIN); 6945e111ed8SAndrew Rybchenko #endif 6955e111ed8SAndrew Rybchenko #ifdef MC_CMD_ERR_ENOSPC 6965e111ed8SAndrew Rybchenko case MC_CMD_ERR_ENOSPC: 6975e111ed8SAndrew Rybchenko return (ENOSPC); 6985e111ed8SAndrew Rybchenko #endif 6995e111ed8SAndrew Rybchenko case MC_CMD_ERR_ERANGE: 7005e111ed8SAndrew Rybchenko return (ERANGE); 7015e111ed8SAndrew Rybchenko 7025e111ed8SAndrew Rybchenko case MC_CMD_ERR_ALLOC_FAIL: 7035e111ed8SAndrew Rybchenko return (ENOMEM); 7045e111ed8SAndrew Rybchenko case MC_CMD_ERR_NO_VADAPTOR: 7055e111ed8SAndrew Rybchenko return (ENOENT); 7065e111ed8SAndrew Rybchenko case MC_CMD_ERR_NO_EVB_PORT: 7075e111ed8SAndrew Rybchenko return (ENOENT); 7085e111ed8SAndrew Rybchenko case MC_CMD_ERR_NO_VSWITCH: 7095e111ed8SAndrew Rybchenko return (ENODEV); 7105e111ed8SAndrew Rybchenko case MC_CMD_ERR_VLAN_LIMIT: 7115e111ed8SAndrew Rybchenko return (EINVAL); 7125e111ed8SAndrew Rybchenko case MC_CMD_ERR_BAD_PCI_FUNC: 7135e111ed8SAndrew Rybchenko return (ENODEV); 7145e111ed8SAndrew Rybchenko case MC_CMD_ERR_BAD_VLAN_MODE: 7155e111ed8SAndrew Rybchenko return (EINVAL); 7165e111ed8SAndrew Rybchenko case MC_CMD_ERR_BAD_VSWITCH_TYPE: 7175e111ed8SAndrew Rybchenko return (EINVAL); 7185e111ed8SAndrew Rybchenko case MC_CMD_ERR_BAD_VPORT_TYPE: 7195e111ed8SAndrew Rybchenko return (EINVAL); 7205e111ed8SAndrew Rybchenko case MC_CMD_ERR_MAC_EXIST: 7215e111ed8SAndrew Rybchenko return (EEXIST); 7225e111ed8SAndrew Rybchenko 7235e111ed8SAndrew Rybchenko case MC_CMD_ERR_PROXY_PENDING: 7245e111ed8SAndrew Rybchenko return (EAGAIN); 7255e111ed8SAndrew Rybchenko 7265e111ed8SAndrew Rybchenko default: 7275e111ed8SAndrew Rybchenko EFSYS_PROBE1(mc_pcol_error, int, err); 7285e111ed8SAndrew Rybchenko return (EIO); 7295e111ed8SAndrew Rybchenko } 7305e111ed8SAndrew Rybchenko } 7315e111ed8SAndrew Rybchenko 7325e111ed8SAndrew Rybchenko void 7335e111ed8SAndrew Rybchenko efx_mcdi_raise_exception( 7345e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 7355e111ed8SAndrew Rybchenko __in_opt efx_mcdi_req_t *emrp, 7365e111ed8SAndrew Rybchenko __in int rc) 7375e111ed8SAndrew Rybchenko { 7385e111ed8SAndrew Rybchenko const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 7395e111ed8SAndrew Rybchenko efx_mcdi_exception_t exception; 7405e111ed8SAndrew Rybchenko 7415e111ed8SAndrew Rybchenko /* Reboot or Assertion failure only */ 7425e111ed8SAndrew Rybchenko EFSYS_ASSERT(rc == EIO || rc == EINTR); 7435e111ed8SAndrew Rybchenko 7445e111ed8SAndrew Rybchenko /* 7455e111ed8SAndrew Rybchenko * If MC_CMD_REBOOT causes a reboot (dependent on parameters), 7465e111ed8SAndrew Rybchenko * then the EIO is not worthy of an exception. 7475e111ed8SAndrew Rybchenko */ 7485e111ed8SAndrew Rybchenko if (emrp != NULL && emrp->emr_cmd == MC_CMD_REBOOT && rc == EIO) 7495e111ed8SAndrew Rybchenko return; 7505e111ed8SAndrew Rybchenko 7515e111ed8SAndrew Rybchenko exception = (rc == EIO) 7525e111ed8SAndrew Rybchenko ? EFX_MCDI_EXCEPTION_MC_REBOOT 7535e111ed8SAndrew Rybchenko : EFX_MCDI_EXCEPTION_MC_BADASSERT; 7545e111ed8SAndrew Rybchenko 7555e111ed8SAndrew Rybchenko emtp->emt_exception(emtp->emt_context, exception); 7565e111ed8SAndrew Rybchenko } 7575e111ed8SAndrew Rybchenko 7585e111ed8SAndrew Rybchenko void 7595e111ed8SAndrew Rybchenko efx_mcdi_execute( 7605e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 7615e111ed8SAndrew Rybchenko __inout efx_mcdi_req_t *emrp) 7625e111ed8SAndrew Rybchenko { 7635e111ed8SAndrew Rybchenko const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 7645e111ed8SAndrew Rybchenko 7655e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 7665e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 7675e111ed8SAndrew Rybchenko 7685e111ed8SAndrew Rybchenko emrp->emr_quiet = B_FALSE; 7695e111ed8SAndrew Rybchenko emtp->emt_execute(emtp->emt_context, emrp); 7705e111ed8SAndrew Rybchenko } 7715e111ed8SAndrew Rybchenko 7725e111ed8SAndrew Rybchenko void 7735e111ed8SAndrew Rybchenko efx_mcdi_execute_quiet( 7745e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 7755e111ed8SAndrew Rybchenko __inout efx_mcdi_req_t *emrp) 7765e111ed8SAndrew Rybchenko { 7775e111ed8SAndrew Rybchenko const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 7785e111ed8SAndrew Rybchenko 7795e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 7805e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 7815e111ed8SAndrew Rybchenko 7825e111ed8SAndrew Rybchenko emrp->emr_quiet = B_TRUE; 7835e111ed8SAndrew Rybchenko emtp->emt_execute(emtp->emt_context, emrp); 7845e111ed8SAndrew Rybchenko } 7855e111ed8SAndrew Rybchenko 7865e111ed8SAndrew Rybchenko void 7875e111ed8SAndrew Rybchenko efx_mcdi_ev_cpl( 7885e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 7895e111ed8SAndrew Rybchenko __in unsigned int seq, 7905e111ed8SAndrew Rybchenko __in unsigned int outlen, 7915e111ed8SAndrew Rybchenko __in int errcode) 7925e111ed8SAndrew Rybchenko { 7935e111ed8SAndrew Rybchenko efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 7945e111ed8SAndrew Rybchenko const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 7955e111ed8SAndrew Rybchenko efx_mcdi_req_t *emrp; 7965e111ed8SAndrew Rybchenko efsys_lock_state_t state; 7975e111ed8SAndrew Rybchenko 7985e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 7995e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 8005e111ed8SAndrew Rybchenko 8015e111ed8SAndrew Rybchenko /* 8025e111ed8SAndrew Rybchenko * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start() 8035e111ed8SAndrew Rybchenko * when we're completing an aborted request. 8045e111ed8SAndrew Rybchenko */ 8055e111ed8SAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state); 8065e111ed8SAndrew Rybchenko if (emip->emi_pending_req == NULL || !emip->emi_ev_cpl || 8075e111ed8SAndrew Rybchenko (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) { 8085e111ed8SAndrew Rybchenko EFSYS_ASSERT(emip->emi_aborted > 0); 8095e111ed8SAndrew Rybchenko if (emip->emi_aborted > 0) 8105e111ed8SAndrew Rybchenko --emip->emi_aborted; 8115e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state); 8125e111ed8SAndrew Rybchenko return; 8135e111ed8SAndrew Rybchenko } 8145e111ed8SAndrew Rybchenko 8155e111ed8SAndrew Rybchenko emrp = emip->emi_pending_req; 8165e111ed8SAndrew Rybchenko emip->emi_pending_req = NULL; 8175e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state); 8185e111ed8SAndrew Rybchenko 8195e111ed8SAndrew Rybchenko if (emip->emi_max_version >= 2) { 8205e111ed8SAndrew Rybchenko /* MCDIv2 response details do not fit into an event. */ 8215e111ed8SAndrew Rybchenko efx_mcdi_read_response_header(enp, emrp); 8225e111ed8SAndrew Rybchenko } else { 8235e111ed8SAndrew Rybchenko if (errcode != 0) { 8245e111ed8SAndrew Rybchenko if (!emrp->emr_quiet) { 8255e111ed8SAndrew Rybchenko EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd, 8265e111ed8SAndrew Rybchenko int, errcode); 8275e111ed8SAndrew Rybchenko } 8285e111ed8SAndrew Rybchenko emrp->emr_out_length_used = 0; 8295e111ed8SAndrew Rybchenko emrp->emr_rc = efx_mcdi_request_errcode(errcode); 8305e111ed8SAndrew Rybchenko } else { 8315e111ed8SAndrew Rybchenko emrp->emr_out_length_used = outlen; 8325e111ed8SAndrew Rybchenko emrp->emr_rc = 0; 8335e111ed8SAndrew Rybchenko } 8345e111ed8SAndrew Rybchenko } 8355e111ed8SAndrew Rybchenko if (emrp->emr_rc == 0) 8365e111ed8SAndrew Rybchenko efx_mcdi_finish_response(enp, emrp); 8375e111ed8SAndrew Rybchenko 8385e111ed8SAndrew Rybchenko emtp->emt_ev_cpl(emtp->emt_context); 8395e111ed8SAndrew Rybchenko } 8405e111ed8SAndrew Rybchenko 8415e111ed8SAndrew Rybchenko #if EFSYS_OPT_MCDI_PROXY_AUTH 8425e111ed8SAndrew Rybchenko 8435e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 8445e111ed8SAndrew Rybchenko efx_mcdi_get_proxy_handle( 8455e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 8465e111ed8SAndrew Rybchenko __in efx_mcdi_req_t *emrp, 8475e111ed8SAndrew Rybchenko __out uint32_t *handlep) 8485e111ed8SAndrew Rybchenko { 8495e111ed8SAndrew Rybchenko efx_rc_t rc; 8505e111ed8SAndrew Rybchenko 8515e111ed8SAndrew Rybchenko _NOTE(ARGUNUSED(enp)) 8525e111ed8SAndrew Rybchenko 8535e111ed8SAndrew Rybchenko /* 8545e111ed8SAndrew Rybchenko * Return proxy handle from MCDI request that returned with error 8555e111ed8SAndrew Rybchenko * MC_MCD_ERR_PROXY_PENDING. This handle is used to wait for a matching 8565e111ed8SAndrew Rybchenko * PROXY_RESPONSE event. 8575e111ed8SAndrew Rybchenko */ 8585e111ed8SAndrew Rybchenko if ((emrp == NULL) || (handlep == NULL)) { 8595e111ed8SAndrew Rybchenko rc = EINVAL; 8605e111ed8SAndrew Rybchenko goto fail1; 8615e111ed8SAndrew Rybchenko } 8625e111ed8SAndrew Rybchenko if ((emrp->emr_rc != 0) && 8635e111ed8SAndrew Rybchenko (emrp->emr_err_code == MC_CMD_ERR_PROXY_PENDING)) { 8645e111ed8SAndrew Rybchenko *handlep = emrp->emr_proxy_handle; 8655e111ed8SAndrew Rybchenko rc = 0; 8665e111ed8SAndrew Rybchenko } else { 8675e111ed8SAndrew Rybchenko *handlep = 0; 8685e111ed8SAndrew Rybchenko rc = ENOENT; 8695e111ed8SAndrew Rybchenko } 8705e111ed8SAndrew Rybchenko return (rc); 8715e111ed8SAndrew Rybchenko 8725e111ed8SAndrew Rybchenko fail1: 8735e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 8745e111ed8SAndrew Rybchenko return (rc); 8755e111ed8SAndrew Rybchenko } 8765e111ed8SAndrew Rybchenko 8775e111ed8SAndrew Rybchenko void 8785e111ed8SAndrew Rybchenko efx_mcdi_ev_proxy_response( 8795e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 8805e111ed8SAndrew Rybchenko __in unsigned int handle, 8815e111ed8SAndrew Rybchenko __in unsigned int status) 8825e111ed8SAndrew Rybchenko { 8835e111ed8SAndrew Rybchenko const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 8845e111ed8SAndrew Rybchenko efx_rc_t rc; 8855e111ed8SAndrew Rybchenko 8865e111ed8SAndrew Rybchenko /* 8875e111ed8SAndrew Rybchenko * Handle results of an authorization request for a privileged MCDI 8885e111ed8SAndrew Rybchenko * command. If authorization was granted then we must re-issue the 8895e111ed8SAndrew Rybchenko * original MCDI request. If authorization failed or timed out, 8905e111ed8SAndrew Rybchenko * then the original MCDI request should be completed with the 8915e111ed8SAndrew Rybchenko * result code from this event. 8925e111ed8SAndrew Rybchenko */ 8935e111ed8SAndrew Rybchenko rc = (status == 0) ? 0 : efx_mcdi_request_errcode(status); 8945e111ed8SAndrew Rybchenko 8955e111ed8SAndrew Rybchenko emtp->emt_ev_proxy_response(emtp->emt_context, handle, rc); 8965e111ed8SAndrew Rybchenko } 8975e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */ 8985e111ed8SAndrew Rybchenko 8995e111ed8SAndrew Rybchenko #if EFSYS_OPT_MCDI_PROXY_AUTH_SERVER 9005e111ed8SAndrew Rybchenko void 9015e111ed8SAndrew Rybchenko efx_mcdi_ev_proxy_request( 9025e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 9035e111ed8SAndrew Rybchenko __in unsigned int index) 9045e111ed8SAndrew Rybchenko { 9055e111ed8SAndrew Rybchenko const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 9065e111ed8SAndrew Rybchenko 9075e111ed8SAndrew Rybchenko if (emtp->emt_ev_proxy_request != NULL) 9085e111ed8SAndrew Rybchenko emtp->emt_ev_proxy_request(emtp->emt_context, index); 9095e111ed8SAndrew Rybchenko } 9105e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MCDI_PROXY_AUTH_SERVER */ 9115e111ed8SAndrew Rybchenko void 9125e111ed8SAndrew Rybchenko efx_mcdi_ev_death( 9135e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 9145e111ed8SAndrew Rybchenko __in int rc) 9155e111ed8SAndrew Rybchenko { 9165e111ed8SAndrew Rybchenko efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 9175e111ed8SAndrew Rybchenko const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 9185e111ed8SAndrew Rybchenko efx_mcdi_req_t *emrp = NULL; 9195e111ed8SAndrew Rybchenko boolean_t ev_cpl; 9205e111ed8SAndrew Rybchenko efsys_lock_state_t state; 9215e111ed8SAndrew Rybchenko 9225e111ed8SAndrew Rybchenko /* 9235e111ed8SAndrew Rybchenko * The MCDI request (if there is one) has been terminated, either 9245e111ed8SAndrew Rybchenko * by a BADASSERT or REBOOT event. 9255e111ed8SAndrew Rybchenko * 9265e111ed8SAndrew Rybchenko * If there is an outstanding event-completed MCDI operation, then we 9275e111ed8SAndrew Rybchenko * will never receive the completion event (because both MCDI 9285e111ed8SAndrew Rybchenko * completions and BADASSERT events are sent to the same evq). So 9295e111ed8SAndrew Rybchenko * complete this MCDI op. 9305e111ed8SAndrew Rybchenko * 9315e111ed8SAndrew Rybchenko * This function might run in parallel with efx_mcdi_request_poll() 9325e111ed8SAndrew Rybchenko * for poll completed mcdi requests, and also with 9335e111ed8SAndrew Rybchenko * efx_mcdi_request_start() for post-watchdog completions. 9345e111ed8SAndrew Rybchenko */ 9355e111ed8SAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state); 9365e111ed8SAndrew Rybchenko emrp = emip->emi_pending_req; 9375e111ed8SAndrew Rybchenko ev_cpl = emip->emi_ev_cpl; 9385e111ed8SAndrew Rybchenko if (emrp != NULL && emip->emi_ev_cpl) { 9395e111ed8SAndrew Rybchenko emip->emi_pending_req = NULL; 9405e111ed8SAndrew Rybchenko 9415e111ed8SAndrew Rybchenko emrp->emr_out_length_used = 0; 9425e111ed8SAndrew Rybchenko emrp->emr_rc = rc; 9435e111ed8SAndrew Rybchenko ++emip->emi_aborted; 9445e111ed8SAndrew Rybchenko } 9455e111ed8SAndrew Rybchenko 9465e111ed8SAndrew Rybchenko /* 9475e111ed8SAndrew Rybchenko * Since we're running in parallel with a request, consume the 9485e111ed8SAndrew Rybchenko * status word before dropping the lock. 9495e111ed8SAndrew Rybchenko */ 9505e111ed8SAndrew Rybchenko if (rc == EIO || rc == EINTR) { 9515e111ed8SAndrew Rybchenko EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US); 9525e111ed8SAndrew Rybchenko (void) efx_mcdi_poll_reboot(enp); 9535e111ed8SAndrew Rybchenko emip->emi_new_epoch = B_TRUE; 9545e111ed8SAndrew Rybchenko } 9555e111ed8SAndrew Rybchenko 9565e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state); 9575e111ed8SAndrew Rybchenko 9585e111ed8SAndrew Rybchenko efx_mcdi_raise_exception(enp, emrp, rc); 9595e111ed8SAndrew Rybchenko 9605e111ed8SAndrew Rybchenko if (emrp != NULL && ev_cpl) 9615e111ed8SAndrew Rybchenko emtp->emt_ev_cpl(emtp->emt_context); 9625e111ed8SAndrew Rybchenko } 9635e111ed8SAndrew Rybchenko 9645e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 9655e111ed8SAndrew Rybchenko efx_mcdi_version( 9665e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 9675e111ed8SAndrew Rybchenko __out_ecount_opt(4) uint16_t versionp[4], 9685e111ed8SAndrew Rybchenko __out_opt uint32_t *buildp, 9695e111ed8SAndrew Rybchenko __out_opt efx_mcdi_boot_t *statusp) 9705e111ed8SAndrew Rybchenko { 9715e111ed8SAndrew Rybchenko efx_mcdi_req_t req; 9725e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, 9735e111ed8SAndrew Rybchenko MAX(MC_CMD_GET_VERSION_IN_LEN, MC_CMD_GET_BOOT_STATUS_IN_LEN), 9745e111ed8SAndrew Rybchenko MAX(MC_CMD_GET_VERSION_OUT_LEN, 9755e111ed8SAndrew Rybchenko MC_CMD_GET_BOOT_STATUS_OUT_LEN)); 9765e111ed8SAndrew Rybchenko efx_word_t *ver_words; 9775e111ed8SAndrew Rybchenko uint16_t version[4]; 9785e111ed8SAndrew Rybchenko uint32_t build; 9795e111ed8SAndrew Rybchenko efx_mcdi_boot_t status; 9805e111ed8SAndrew Rybchenko efx_rc_t rc; 9815e111ed8SAndrew Rybchenko 9825e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 9835e111ed8SAndrew Rybchenko 9845e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_VERSION; 9855e111ed8SAndrew Rybchenko req.emr_in_buf = payload; 9865e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_GET_VERSION_IN_LEN; 9875e111ed8SAndrew Rybchenko req.emr_out_buf = payload; 9885e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_GET_VERSION_OUT_LEN; 9895e111ed8SAndrew Rybchenko 9905e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req); 9915e111ed8SAndrew Rybchenko 9925e111ed8SAndrew Rybchenko if (req.emr_rc != 0) { 9935e111ed8SAndrew Rybchenko rc = req.emr_rc; 9945e111ed8SAndrew Rybchenko goto fail1; 9955e111ed8SAndrew Rybchenko } 9965e111ed8SAndrew Rybchenko 9975e111ed8SAndrew Rybchenko /* bootrom support */ 9985e111ed8SAndrew Rybchenko if (req.emr_out_length_used == MC_CMD_GET_VERSION_V0_OUT_LEN) { 9995e111ed8SAndrew Rybchenko version[0] = version[1] = version[2] = version[3] = 0; 10005e111ed8SAndrew Rybchenko build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE); 10015e111ed8SAndrew Rybchenko 10025e111ed8SAndrew Rybchenko goto version; 10035e111ed8SAndrew Rybchenko } 10045e111ed8SAndrew Rybchenko 10055e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_VERSION_OUT_LEN) { 10065e111ed8SAndrew Rybchenko rc = EMSGSIZE; 10075e111ed8SAndrew Rybchenko goto fail2; 10085e111ed8SAndrew Rybchenko } 10095e111ed8SAndrew Rybchenko 10105e111ed8SAndrew Rybchenko ver_words = MCDI_OUT2(req, efx_word_t, GET_VERSION_OUT_VERSION); 10115e111ed8SAndrew Rybchenko version[0] = EFX_WORD_FIELD(ver_words[0], EFX_WORD_0); 10125e111ed8SAndrew Rybchenko version[1] = EFX_WORD_FIELD(ver_words[1], EFX_WORD_0); 10135e111ed8SAndrew Rybchenko version[2] = EFX_WORD_FIELD(ver_words[2], EFX_WORD_0); 10145e111ed8SAndrew Rybchenko version[3] = EFX_WORD_FIELD(ver_words[3], EFX_WORD_0); 10155e111ed8SAndrew Rybchenko build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE); 10165e111ed8SAndrew Rybchenko 10175e111ed8SAndrew Rybchenko version: 10185e111ed8SAndrew Rybchenko /* The bootrom doesn't understand BOOT_STATUS */ 10195e111ed8SAndrew Rybchenko if (MC_FW_VERSION_IS_BOOTLOADER(build)) { 10205e111ed8SAndrew Rybchenko status = EFX_MCDI_BOOT_ROM; 10215e111ed8SAndrew Rybchenko goto out; 10225e111ed8SAndrew Rybchenko } 10235e111ed8SAndrew Rybchenko 10245e111ed8SAndrew Rybchenko (void) memset(payload, 0, sizeof (payload)); 10255e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_BOOT_STATUS; 10265e111ed8SAndrew Rybchenko req.emr_in_buf = payload; 10275e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_GET_BOOT_STATUS_IN_LEN; 10285e111ed8SAndrew Rybchenko req.emr_out_buf = payload; 10295e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_GET_BOOT_STATUS_OUT_LEN; 10305e111ed8SAndrew Rybchenko 10315e111ed8SAndrew Rybchenko efx_mcdi_execute_quiet(enp, &req); 10325e111ed8SAndrew Rybchenko 10335e111ed8SAndrew Rybchenko if (req.emr_rc == EACCES) { 10345e111ed8SAndrew Rybchenko /* Unprivileged functions cannot access BOOT_STATUS */ 10355e111ed8SAndrew Rybchenko status = EFX_MCDI_BOOT_PRIMARY; 10365e111ed8SAndrew Rybchenko version[0] = version[1] = version[2] = version[3] = 0; 10375e111ed8SAndrew Rybchenko build = 0; 10385e111ed8SAndrew Rybchenko goto out; 10395e111ed8SAndrew Rybchenko } 10405e111ed8SAndrew Rybchenko 10415e111ed8SAndrew Rybchenko if (req.emr_rc != 0) { 10425e111ed8SAndrew Rybchenko rc = req.emr_rc; 10435e111ed8SAndrew Rybchenko goto fail3; 10445e111ed8SAndrew Rybchenko } 10455e111ed8SAndrew Rybchenko 10465e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) { 10475e111ed8SAndrew Rybchenko rc = EMSGSIZE; 10485e111ed8SAndrew Rybchenko goto fail4; 10495e111ed8SAndrew Rybchenko } 10505e111ed8SAndrew Rybchenko 10515e111ed8SAndrew Rybchenko if (MCDI_OUT_DWORD_FIELD(req, GET_BOOT_STATUS_OUT_FLAGS, 10525e111ed8SAndrew Rybchenko GET_BOOT_STATUS_OUT_FLAGS_PRIMARY)) 10535e111ed8SAndrew Rybchenko status = EFX_MCDI_BOOT_PRIMARY; 10545e111ed8SAndrew Rybchenko else 10555e111ed8SAndrew Rybchenko status = EFX_MCDI_BOOT_SECONDARY; 10565e111ed8SAndrew Rybchenko 10575e111ed8SAndrew Rybchenko out: 10585e111ed8SAndrew Rybchenko if (versionp != NULL) 10595e111ed8SAndrew Rybchenko memcpy(versionp, version, sizeof (version)); 10605e111ed8SAndrew Rybchenko if (buildp != NULL) 10615e111ed8SAndrew Rybchenko *buildp = build; 10625e111ed8SAndrew Rybchenko if (statusp != NULL) 10635e111ed8SAndrew Rybchenko *statusp = status; 10645e111ed8SAndrew Rybchenko 10655e111ed8SAndrew Rybchenko return (0); 10665e111ed8SAndrew Rybchenko 10675e111ed8SAndrew Rybchenko fail4: 10685e111ed8SAndrew Rybchenko EFSYS_PROBE(fail4); 10695e111ed8SAndrew Rybchenko fail3: 10705e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3); 10715e111ed8SAndrew Rybchenko fail2: 10725e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2); 10735e111ed8SAndrew Rybchenko fail1: 10745e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 10755e111ed8SAndrew Rybchenko 10765e111ed8SAndrew Rybchenko return (rc); 10775e111ed8SAndrew Rybchenko } 10785e111ed8SAndrew Rybchenko 10795e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 10805e111ed8SAndrew Rybchenko efx_mcdi_get_capabilities( 10815e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 10825e111ed8SAndrew Rybchenko __out_opt uint32_t *flagsp, 10835e111ed8SAndrew Rybchenko __out_opt uint16_t *rx_dpcpu_fw_idp, 10845e111ed8SAndrew Rybchenko __out_opt uint16_t *tx_dpcpu_fw_idp, 10855e111ed8SAndrew Rybchenko __out_opt uint32_t *flags2p, 10865e111ed8SAndrew Rybchenko __out_opt uint32_t *tso2ncp) 10875e111ed8SAndrew Rybchenko { 10885e111ed8SAndrew Rybchenko efx_mcdi_req_t req; 10895e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_CAPABILITIES_IN_LEN, 10905e111ed8SAndrew Rybchenko MC_CMD_GET_CAPABILITIES_V2_OUT_LEN); 10915e111ed8SAndrew Rybchenko boolean_t v2_capable; 10925e111ed8SAndrew Rybchenko efx_rc_t rc; 10935e111ed8SAndrew Rybchenko 10945e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_CAPABILITIES; 10955e111ed8SAndrew Rybchenko req.emr_in_buf = payload; 10965e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN; 10975e111ed8SAndrew Rybchenko req.emr_out_buf = payload; 10985e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_GET_CAPABILITIES_V2_OUT_LEN; 10995e111ed8SAndrew Rybchenko 11005e111ed8SAndrew Rybchenko efx_mcdi_execute_quiet(enp, &req); 11015e111ed8SAndrew Rybchenko 11025e111ed8SAndrew Rybchenko if (req.emr_rc != 0) { 11035e111ed8SAndrew Rybchenko rc = req.emr_rc; 11045e111ed8SAndrew Rybchenko goto fail1; 11055e111ed8SAndrew Rybchenko } 11065e111ed8SAndrew Rybchenko 11075e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_OUT_LEN) { 11085e111ed8SAndrew Rybchenko rc = EMSGSIZE; 11095e111ed8SAndrew Rybchenko goto fail2; 11105e111ed8SAndrew Rybchenko } 11115e111ed8SAndrew Rybchenko 11125e111ed8SAndrew Rybchenko if (flagsp != NULL) 11135e111ed8SAndrew Rybchenko *flagsp = MCDI_OUT_DWORD(req, GET_CAPABILITIES_OUT_FLAGS1); 11145e111ed8SAndrew Rybchenko 11155e111ed8SAndrew Rybchenko if (rx_dpcpu_fw_idp != NULL) 11165e111ed8SAndrew Rybchenko *rx_dpcpu_fw_idp = MCDI_OUT_WORD(req, 11175e111ed8SAndrew Rybchenko GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID); 11185e111ed8SAndrew Rybchenko 11195e111ed8SAndrew Rybchenko if (tx_dpcpu_fw_idp != NULL) 11205e111ed8SAndrew Rybchenko *tx_dpcpu_fw_idp = MCDI_OUT_WORD(req, 11215e111ed8SAndrew Rybchenko GET_CAPABILITIES_OUT_TX_DPCPU_FW_ID); 11225e111ed8SAndrew Rybchenko 11235e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_V2_OUT_LEN) 11245e111ed8SAndrew Rybchenko v2_capable = B_FALSE; 11255e111ed8SAndrew Rybchenko else 11265e111ed8SAndrew Rybchenko v2_capable = B_TRUE; 11275e111ed8SAndrew Rybchenko 11285e111ed8SAndrew Rybchenko if (flags2p != NULL) { 11295e111ed8SAndrew Rybchenko *flags2p = (v2_capable) ? 11305e111ed8SAndrew Rybchenko MCDI_OUT_DWORD(req, GET_CAPABILITIES_V2_OUT_FLAGS2) : 11315e111ed8SAndrew Rybchenko 0; 11325e111ed8SAndrew Rybchenko } 11335e111ed8SAndrew Rybchenko 11345e111ed8SAndrew Rybchenko if (tso2ncp != NULL) { 11355e111ed8SAndrew Rybchenko *tso2ncp = (v2_capable) ? 11365e111ed8SAndrew Rybchenko MCDI_OUT_WORD(req, 11375e111ed8SAndrew Rybchenko GET_CAPABILITIES_V2_OUT_TX_TSO_V2_N_CONTEXTS) : 11385e111ed8SAndrew Rybchenko 0; 11395e111ed8SAndrew Rybchenko } 11405e111ed8SAndrew Rybchenko 11415e111ed8SAndrew Rybchenko return (0); 11425e111ed8SAndrew Rybchenko 11435e111ed8SAndrew Rybchenko fail2: 11445e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2); 11455e111ed8SAndrew Rybchenko fail1: 11465e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 11475e111ed8SAndrew Rybchenko 11485e111ed8SAndrew Rybchenko return (rc); 11495e111ed8SAndrew Rybchenko } 11505e111ed8SAndrew Rybchenko 11515e111ed8SAndrew Rybchenko static __checkReturn efx_rc_t 11525e111ed8SAndrew Rybchenko efx_mcdi_do_reboot( 11535e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 11545e111ed8SAndrew Rybchenko __in boolean_t after_assertion) 11555e111ed8SAndrew Rybchenko { 11565e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_REBOOT_IN_LEN, 11575e111ed8SAndrew Rybchenko MC_CMD_REBOOT_OUT_LEN); 11585e111ed8SAndrew Rybchenko efx_mcdi_req_t req; 11595e111ed8SAndrew Rybchenko efx_rc_t rc; 11605e111ed8SAndrew Rybchenko 11615e111ed8SAndrew Rybchenko /* 11625e111ed8SAndrew Rybchenko * We could require the caller to have caused en_mod_flags=0 to 11635e111ed8SAndrew Rybchenko * call this function. This doesn't help the other port though, 11645e111ed8SAndrew Rybchenko * who's about to get the MC ripped out from underneath them. 11655e111ed8SAndrew Rybchenko * Since they have to cope with the subsequent fallout of MCDI 11665e111ed8SAndrew Rybchenko * failures, we should as well. 11675e111ed8SAndrew Rybchenko */ 11685e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 11695e111ed8SAndrew Rybchenko 11705e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_REBOOT; 11715e111ed8SAndrew Rybchenko req.emr_in_buf = payload; 11725e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_REBOOT_IN_LEN; 11735e111ed8SAndrew Rybchenko req.emr_out_buf = payload; 11745e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_REBOOT_OUT_LEN; 11755e111ed8SAndrew Rybchenko 11765e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS, 11775e111ed8SAndrew Rybchenko (after_assertion ? MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION : 0)); 11785e111ed8SAndrew Rybchenko 11795e111ed8SAndrew Rybchenko efx_mcdi_execute_quiet(enp, &req); 11805e111ed8SAndrew Rybchenko 11815e111ed8SAndrew Rybchenko if (req.emr_rc == EACCES) { 11825e111ed8SAndrew Rybchenko /* Unprivileged functions cannot reboot the MC. */ 11835e111ed8SAndrew Rybchenko goto out; 11845e111ed8SAndrew Rybchenko } 11855e111ed8SAndrew Rybchenko 11865e111ed8SAndrew Rybchenko /* A successful reboot request returns EIO. */ 11875e111ed8SAndrew Rybchenko if (req.emr_rc != 0 && req.emr_rc != EIO) { 11885e111ed8SAndrew Rybchenko rc = req.emr_rc; 11895e111ed8SAndrew Rybchenko goto fail1; 11905e111ed8SAndrew Rybchenko } 11915e111ed8SAndrew Rybchenko 11925e111ed8SAndrew Rybchenko out: 11935e111ed8SAndrew Rybchenko return (0); 11945e111ed8SAndrew Rybchenko 11955e111ed8SAndrew Rybchenko fail1: 11965e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 11975e111ed8SAndrew Rybchenko 11985e111ed8SAndrew Rybchenko return (rc); 11995e111ed8SAndrew Rybchenko } 12005e111ed8SAndrew Rybchenko 12015e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 12025e111ed8SAndrew Rybchenko efx_mcdi_reboot( 12035e111ed8SAndrew Rybchenko __in efx_nic_t *enp) 12045e111ed8SAndrew Rybchenko { 12055e111ed8SAndrew Rybchenko return (efx_mcdi_do_reboot(enp, B_FALSE)); 12065e111ed8SAndrew Rybchenko } 12075e111ed8SAndrew Rybchenko 12085e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 12095e111ed8SAndrew Rybchenko efx_mcdi_exit_assertion_handler( 12105e111ed8SAndrew Rybchenko __in efx_nic_t *enp) 12115e111ed8SAndrew Rybchenko { 12125e111ed8SAndrew Rybchenko return (efx_mcdi_do_reboot(enp, B_TRUE)); 12135e111ed8SAndrew Rybchenko } 12145e111ed8SAndrew Rybchenko 12155e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 12165e111ed8SAndrew Rybchenko efx_mcdi_read_assertion( 12175e111ed8SAndrew Rybchenko __in efx_nic_t *enp) 12185e111ed8SAndrew Rybchenko { 12195e111ed8SAndrew Rybchenko efx_mcdi_req_t req; 12205e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_ASSERTS_IN_LEN, 12215e111ed8SAndrew Rybchenko MC_CMD_GET_ASSERTS_OUT_LEN); 12225e111ed8SAndrew Rybchenko const char *reason; 12235e111ed8SAndrew Rybchenko unsigned int flags; 12245e111ed8SAndrew Rybchenko unsigned int index; 12255e111ed8SAndrew Rybchenko unsigned int ofst; 12265e111ed8SAndrew Rybchenko int retry; 12275e111ed8SAndrew Rybchenko efx_rc_t rc; 12285e111ed8SAndrew Rybchenko 12295e111ed8SAndrew Rybchenko /* 12305e111ed8SAndrew Rybchenko * Before we attempt to chat to the MC, we should verify that the MC 12315e111ed8SAndrew Rybchenko * isn't in it's assertion handler, either due to a previous reboot, 12325e111ed8SAndrew Rybchenko * or because we're reinitializing due to an eec_exception(). 12335e111ed8SAndrew Rybchenko * 12345e111ed8SAndrew Rybchenko * Use GET_ASSERTS to read any assertion state that may be present. 12355e111ed8SAndrew Rybchenko * Retry this command twice. Once because a boot-time assertion failure 12365e111ed8SAndrew Rybchenko * might cause the 1st MCDI request to fail. And once again because 12375e111ed8SAndrew Rybchenko * we might race with efx_mcdi_exit_assertion_handler() running on 12385e111ed8SAndrew Rybchenko * partner port(s) on the same NIC. 12395e111ed8SAndrew Rybchenko */ 12405e111ed8SAndrew Rybchenko retry = 2; 12415e111ed8SAndrew Rybchenko do { 12425e111ed8SAndrew Rybchenko (void) memset(payload, 0, sizeof (payload)); 12435e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_ASSERTS; 12445e111ed8SAndrew Rybchenko req.emr_in_buf = payload; 12455e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_GET_ASSERTS_IN_LEN; 12465e111ed8SAndrew Rybchenko req.emr_out_buf = payload; 12475e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_GET_ASSERTS_OUT_LEN; 12485e111ed8SAndrew Rybchenko 12495e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1); 12505e111ed8SAndrew Rybchenko efx_mcdi_execute_quiet(enp, &req); 12515e111ed8SAndrew Rybchenko 12525e111ed8SAndrew Rybchenko } while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0); 12535e111ed8SAndrew Rybchenko 12545e111ed8SAndrew Rybchenko if (req.emr_rc != 0) { 12555e111ed8SAndrew Rybchenko if (req.emr_rc == EACCES) { 12565e111ed8SAndrew Rybchenko /* Unprivileged functions cannot clear assertions. */ 12575e111ed8SAndrew Rybchenko goto out; 12585e111ed8SAndrew Rybchenko } 12595e111ed8SAndrew Rybchenko rc = req.emr_rc; 12605e111ed8SAndrew Rybchenko goto fail1; 12615e111ed8SAndrew Rybchenko } 12625e111ed8SAndrew Rybchenko 12635e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) { 12645e111ed8SAndrew Rybchenko rc = EMSGSIZE; 12655e111ed8SAndrew Rybchenko goto fail2; 12665e111ed8SAndrew Rybchenko } 12675e111ed8SAndrew Rybchenko 12685e111ed8SAndrew Rybchenko /* Print out any assertion state recorded */ 12695e111ed8SAndrew Rybchenko flags = MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_GLOBAL_FLAGS); 12705e111ed8SAndrew Rybchenko if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS) 12715e111ed8SAndrew Rybchenko return (0); 12725e111ed8SAndrew Rybchenko 12735e111ed8SAndrew Rybchenko reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL) 12745e111ed8SAndrew Rybchenko ? "system-level assertion" 12755e111ed8SAndrew Rybchenko : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL) 12765e111ed8SAndrew Rybchenko ? "thread-level assertion" 12775e111ed8SAndrew Rybchenko : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED) 12785e111ed8SAndrew Rybchenko ? "watchdog reset" 12795e111ed8SAndrew Rybchenko : (flags == MC_CMD_GET_ASSERTS_FLAGS_ADDR_TRAP) 12805e111ed8SAndrew Rybchenko ? "illegal address trap" 12815e111ed8SAndrew Rybchenko : "unknown assertion"; 12825e111ed8SAndrew Rybchenko EFSYS_PROBE3(mcpu_assertion, 12835e111ed8SAndrew Rybchenko const char *, reason, unsigned int, 12845e111ed8SAndrew Rybchenko MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_SAVED_PC_OFFS), 12855e111ed8SAndrew Rybchenko unsigned int, 12865e111ed8SAndrew Rybchenko MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS)); 12875e111ed8SAndrew Rybchenko 12885e111ed8SAndrew Rybchenko /* Print out the registers (r1 ... r31) */ 12895e111ed8SAndrew Rybchenko ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST; 12905e111ed8SAndrew Rybchenko for (index = 1; 12915e111ed8SAndrew Rybchenko index < 1 + MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM; 12925e111ed8SAndrew Rybchenko index++) { 12935e111ed8SAndrew Rybchenko EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int, 12945e111ed8SAndrew Rybchenko EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst), 12955e111ed8SAndrew Rybchenko EFX_DWORD_0)); 12965e111ed8SAndrew Rybchenko ofst += sizeof (efx_dword_t); 12975e111ed8SAndrew Rybchenko } 12985e111ed8SAndrew Rybchenko EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN); 12995e111ed8SAndrew Rybchenko 13005e111ed8SAndrew Rybchenko out: 13015e111ed8SAndrew Rybchenko return (0); 13025e111ed8SAndrew Rybchenko 13035e111ed8SAndrew Rybchenko fail2: 13045e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2); 13055e111ed8SAndrew Rybchenko fail1: 13065e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 13075e111ed8SAndrew Rybchenko 13085e111ed8SAndrew Rybchenko return (rc); 13095e111ed8SAndrew Rybchenko } 13105e111ed8SAndrew Rybchenko 13115e111ed8SAndrew Rybchenko 13125e111ed8SAndrew Rybchenko /* 13135e111ed8SAndrew Rybchenko * Internal routines for for specific MCDI requests. 13145e111ed8SAndrew Rybchenko */ 13155e111ed8SAndrew Rybchenko 13165e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 13175e111ed8SAndrew Rybchenko efx_mcdi_drv_attach( 13185e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 13195e111ed8SAndrew Rybchenko __in boolean_t attach) 13205e111ed8SAndrew Rybchenko { 13215e111ed8SAndrew Rybchenko efx_mcdi_req_t req; 13225e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_DRV_ATTACH_IN_V2_LEN, 13235e111ed8SAndrew Rybchenko MC_CMD_DRV_ATTACH_EXT_OUT_LEN); 13245e111ed8SAndrew Rybchenko efx_rc_t rc; 13255e111ed8SAndrew Rybchenko 13265e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_DRV_ATTACH; 13275e111ed8SAndrew Rybchenko req.emr_in_buf = payload; 13285e111ed8SAndrew Rybchenko if (enp->en_drv_version[0] == '\0') { 13295e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_DRV_ATTACH_IN_LEN; 13305e111ed8SAndrew Rybchenko } else { 13315e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_DRV_ATTACH_IN_V2_LEN; 13325e111ed8SAndrew Rybchenko } 13335e111ed8SAndrew Rybchenko req.emr_out_buf = payload; 13345e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_DRV_ATTACH_EXT_OUT_LEN; 13355e111ed8SAndrew Rybchenko 13365e111ed8SAndrew Rybchenko /* 13375e111ed8SAndrew Rybchenko * Typically, client drivers use DONT_CARE for the datapath firmware 13385e111ed8SAndrew Rybchenko * type to ensure that the driver can attach to an unprivileged 13395e111ed8SAndrew Rybchenko * function. The datapath firmware type to use is controlled by the 13405e111ed8SAndrew Rybchenko * 'sfboot' utility. 13415e111ed8SAndrew Rybchenko * If a client driver wishes to attach with a specific datapath firmware 13425e111ed8SAndrew Rybchenko * type, that can be passed in second argument of efx_nic_probe API. One 13435e111ed8SAndrew Rybchenko * such example is the ESXi native driver that attempts attaching with 13445e111ed8SAndrew Rybchenko * FULL_FEATURED datapath firmware type first and fall backs to 13455e111ed8SAndrew Rybchenko * DONT_CARE datapath firmware type if MC_CMD_DRV_ATTACH fails. 13465e111ed8SAndrew Rybchenko */ 13475e111ed8SAndrew Rybchenko MCDI_IN_POPULATE_DWORD_2(req, DRV_ATTACH_IN_NEW_STATE, 13485e111ed8SAndrew Rybchenko DRV_ATTACH_IN_ATTACH, attach ? 1 : 0, 13495e111ed8SAndrew Rybchenko DRV_ATTACH_IN_SUBVARIANT_AWARE, EFSYS_OPT_FW_SUBVARIANT_AWARE); 13505e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_UPDATE, 1); 13515e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_FIRMWARE_ID, enp->efv); 13525e111ed8SAndrew Rybchenko 13535e111ed8SAndrew Rybchenko if (req.emr_in_length >= MC_CMD_DRV_ATTACH_IN_V2_LEN) { 13545e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(sizeof (enp->en_drv_version) == 13555e111ed8SAndrew Rybchenko MC_CMD_DRV_ATTACH_IN_V2_DRIVER_VERSION_LEN); 13565e111ed8SAndrew Rybchenko memcpy(MCDI_IN2(req, char, DRV_ATTACH_IN_V2_DRIVER_VERSION), 13575e111ed8SAndrew Rybchenko enp->en_drv_version, 13585e111ed8SAndrew Rybchenko MC_CMD_DRV_ATTACH_IN_V2_DRIVER_VERSION_LEN); 13595e111ed8SAndrew Rybchenko } 13605e111ed8SAndrew Rybchenko 13615e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req); 13625e111ed8SAndrew Rybchenko 13635e111ed8SAndrew Rybchenko if (req.emr_rc != 0) { 13645e111ed8SAndrew Rybchenko rc = req.emr_rc; 13655e111ed8SAndrew Rybchenko goto fail1; 13665e111ed8SAndrew Rybchenko } 13675e111ed8SAndrew Rybchenko 13685e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) { 13695e111ed8SAndrew Rybchenko rc = EMSGSIZE; 13705e111ed8SAndrew Rybchenko goto fail2; 13715e111ed8SAndrew Rybchenko } 13725e111ed8SAndrew Rybchenko 13735e111ed8SAndrew Rybchenko return (0); 13745e111ed8SAndrew Rybchenko 13755e111ed8SAndrew Rybchenko fail2: 13765e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2); 13775e111ed8SAndrew Rybchenko fail1: 13785e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 13795e111ed8SAndrew Rybchenko 13805e111ed8SAndrew Rybchenko return (rc); 13815e111ed8SAndrew Rybchenko } 13825e111ed8SAndrew Rybchenko 13835e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 13845e111ed8SAndrew Rybchenko efx_mcdi_get_board_cfg( 13855e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 13865e111ed8SAndrew Rybchenko __out_opt uint32_t *board_typep, 13875e111ed8SAndrew Rybchenko __out_opt efx_dword_t *capabilitiesp, 13885e111ed8SAndrew Rybchenko __out_ecount_opt(6) uint8_t mac_addrp[6]) 13895e111ed8SAndrew Rybchenko { 13905e111ed8SAndrew Rybchenko efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 13915e111ed8SAndrew Rybchenko efx_mcdi_req_t req; 13925e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_BOARD_CFG_IN_LEN, 13935e111ed8SAndrew Rybchenko MC_CMD_GET_BOARD_CFG_OUT_LENMIN); 13945e111ed8SAndrew Rybchenko efx_rc_t rc; 13955e111ed8SAndrew Rybchenko 13965e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_BOARD_CFG; 13975e111ed8SAndrew Rybchenko req.emr_in_buf = payload; 13985e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN; 13995e111ed8SAndrew Rybchenko req.emr_out_buf = payload; 14005e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMIN; 14015e111ed8SAndrew Rybchenko 14025e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req); 14035e111ed8SAndrew Rybchenko 14045e111ed8SAndrew Rybchenko if (req.emr_rc != 0) { 14055e111ed8SAndrew Rybchenko rc = req.emr_rc; 14065e111ed8SAndrew Rybchenko goto fail1; 14075e111ed8SAndrew Rybchenko } 14085e111ed8SAndrew Rybchenko 14095e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) { 14105e111ed8SAndrew Rybchenko rc = EMSGSIZE; 14115e111ed8SAndrew Rybchenko goto fail2; 14125e111ed8SAndrew Rybchenko } 14135e111ed8SAndrew Rybchenko 14145e111ed8SAndrew Rybchenko if (mac_addrp != NULL) { 14155e111ed8SAndrew Rybchenko uint8_t *addrp; 14165e111ed8SAndrew Rybchenko 14175e111ed8SAndrew Rybchenko if (emip->emi_port == 1) { 14185e111ed8SAndrew Rybchenko addrp = MCDI_OUT2(req, uint8_t, 14195e111ed8SAndrew Rybchenko GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0); 14205e111ed8SAndrew Rybchenko } else if (emip->emi_port == 2) { 14215e111ed8SAndrew Rybchenko addrp = MCDI_OUT2(req, uint8_t, 14225e111ed8SAndrew Rybchenko GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1); 14235e111ed8SAndrew Rybchenko } else { 14245e111ed8SAndrew Rybchenko rc = EINVAL; 14255e111ed8SAndrew Rybchenko goto fail3; 14265e111ed8SAndrew Rybchenko } 14275e111ed8SAndrew Rybchenko 14285e111ed8SAndrew Rybchenko EFX_MAC_ADDR_COPY(mac_addrp, addrp); 14295e111ed8SAndrew Rybchenko } 14305e111ed8SAndrew Rybchenko 14315e111ed8SAndrew Rybchenko if (capabilitiesp != NULL) { 14325e111ed8SAndrew Rybchenko if (emip->emi_port == 1) { 14335e111ed8SAndrew Rybchenko *capabilitiesp = *MCDI_OUT2(req, efx_dword_t, 14345e111ed8SAndrew Rybchenko GET_BOARD_CFG_OUT_CAPABILITIES_PORT0); 14355e111ed8SAndrew Rybchenko } else if (emip->emi_port == 2) { 14365e111ed8SAndrew Rybchenko *capabilitiesp = *MCDI_OUT2(req, efx_dword_t, 14375e111ed8SAndrew Rybchenko GET_BOARD_CFG_OUT_CAPABILITIES_PORT1); 14385e111ed8SAndrew Rybchenko } else { 14395e111ed8SAndrew Rybchenko rc = EINVAL; 14405e111ed8SAndrew Rybchenko goto fail4; 14415e111ed8SAndrew Rybchenko } 14425e111ed8SAndrew Rybchenko } 14435e111ed8SAndrew Rybchenko 14445e111ed8SAndrew Rybchenko if (board_typep != NULL) { 14455e111ed8SAndrew Rybchenko *board_typep = MCDI_OUT_DWORD(req, 14465e111ed8SAndrew Rybchenko GET_BOARD_CFG_OUT_BOARD_TYPE); 14475e111ed8SAndrew Rybchenko } 14485e111ed8SAndrew Rybchenko 14495e111ed8SAndrew Rybchenko return (0); 14505e111ed8SAndrew Rybchenko 14515e111ed8SAndrew Rybchenko fail4: 14525e111ed8SAndrew Rybchenko EFSYS_PROBE(fail4); 14535e111ed8SAndrew Rybchenko fail3: 14545e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3); 14555e111ed8SAndrew Rybchenko fail2: 14565e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2); 14575e111ed8SAndrew Rybchenko fail1: 14585e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 14595e111ed8SAndrew Rybchenko 14605e111ed8SAndrew Rybchenko return (rc); 14615e111ed8SAndrew Rybchenko } 14625e111ed8SAndrew Rybchenko 14635e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 14645e111ed8SAndrew Rybchenko efx_mcdi_get_resource_limits( 14655e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 14665e111ed8SAndrew Rybchenko __out_opt uint32_t *nevqp, 14675e111ed8SAndrew Rybchenko __out_opt uint32_t *nrxqp, 14685e111ed8SAndrew Rybchenko __out_opt uint32_t *ntxqp) 14695e111ed8SAndrew Rybchenko { 14705e111ed8SAndrew Rybchenko efx_mcdi_req_t req; 14715e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_RESOURCE_LIMITS_IN_LEN, 14725e111ed8SAndrew Rybchenko MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN); 14735e111ed8SAndrew Rybchenko efx_rc_t rc; 14745e111ed8SAndrew Rybchenko 14755e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_RESOURCE_LIMITS; 14765e111ed8SAndrew Rybchenko req.emr_in_buf = payload; 14775e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_GET_RESOURCE_LIMITS_IN_LEN; 14785e111ed8SAndrew Rybchenko req.emr_out_buf = payload; 14795e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN; 14805e111ed8SAndrew Rybchenko 14815e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req); 14825e111ed8SAndrew Rybchenko 14835e111ed8SAndrew Rybchenko if (req.emr_rc != 0) { 14845e111ed8SAndrew Rybchenko rc = req.emr_rc; 14855e111ed8SAndrew Rybchenko goto fail1; 14865e111ed8SAndrew Rybchenko } 14875e111ed8SAndrew Rybchenko 14885e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) { 14895e111ed8SAndrew Rybchenko rc = EMSGSIZE; 14905e111ed8SAndrew Rybchenko goto fail2; 14915e111ed8SAndrew Rybchenko } 14925e111ed8SAndrew Rybchenko 14935e111ed8SAndrew Rybchenko if (nevqp != NULL) 14945e111ed8SAndrew Rybchenko *nevqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_EVQ); 14955e111ed8SAndrew Rybchenko if (nrxqp != NULL) 14965e111ed8SAndrew Rybchenko *nrxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ); 14975e111ed8SAndrew Rybchenko if (ntxqp != NULL) 14985e111ed8SAndrew Rybchenko *ntxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ); 14995e111ed8SAndrew Rybchenko 15005e111ed8SAndrew Rybchenko return (0); 15015e111ed8SAndrew Rybchenko 15025e111ed8SAndrew Rybchenko fail2: 15035e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2); 15045e111ed8SAndrew Rybchenko fail1: 15055e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 15065e111ed8SAndrew Rybchenko 15075e111ed8SAndrew Rybchenko return (rc); 15085e111ed8SAndrew Rybchenko } 15095e111ed8SAndrew Rybchenko 15105e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 15115e111ed8SAndrew Rybchenko efx_mcdi_get_phy_cfg( 15125e111ed8SAndrew Rybchenko __in efx_nic_t *enp) 15135e111ed8SAndrew Rybchenko { 15145e111ed8SAndrew Rybchenko efx_port_t *epp = &(enp->en_port); 15155e111ed8SAndrew Rybchenko efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 15165e111ed8SAndrew Rybchenko efx_mcdi_req_t req; 15175e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PHY_CFG_IN_LEN, 15185e111ed8SAndrew Rybchenko MC_CMD_GET_PHY_CFG_OUT_LEN); 15195e111ed8SAndrew Rybchenko #if EFSYS_OPT_NAMES 15205e111ed8SAndrew Rybchenko const char *namep; 15215e111ed8SAndrew Rybchenko size_t namelen; 15225e111ed8SAndrew Rybchenko #endif 15235e111ed8SAndrew Rybchenko uint32_t phy_media_type; 15245e111ed8SAndrew Rybchenko efx_rc_t rc; 15255e111ed8SAndrew Rybchenko 15265e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_PHY_CFG; 15275e111ed8SAndrew Rybchenko req.emr_in_buf = payload; 15285e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_GET_PHY_CFG_IN_LEN; 15295e111ed8SAndrew Rybchenko req.emr_out_buf = payload; 15305e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_GET_PHY_CFG_OUT_LEN; 15315e111ed8SAndrew Rybchenko 15325e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req); 15335e111ed8SAndrew Rybchenko 15345e111ed8SAndrew Rybchenko if (req.emr_rc != 0) { 15355e111ed8SAndrew Rybchenko rc = req.emr_rc; 15365e111ed8SAndrew Rybchenko goto fail1; 15375e111ed8SAndrew Rybchenko } 15385e111ed8SAndrew Rybchenko 15395e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) { 15405e111ed8SAndrew Rybchenko rc = EMSGSIZE; 15415e111ed8SAndrew Rybchenko goto fail2; 15425e111ed8SAndrew Rybchenko } 15435e111ed8SAndrew Rybchenko 15445e111ed8SAndrew Rybchenko encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE); 15455e111ed8SAndrew Rybchenko #if EFSYS_OPT_NAMES 15465e111ed8SAndrew Rybchenko namep = MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME); 15475e111ed8SAndrew Rybchenko namelen = MIN(sizeof (encp->enc_phy_name) - 1, 15485e111ed8SAndrew Rybchenko strnlen(namep, MC_CMD_GET_PHY_CFG_OUT_NAME_LEN)); 15495e111ed8SAndrew Rybchenko (void) memset(encp->enc_phy_name, 0, 15505e111ed8SAndrew Rybchenko sizeof (encp->enc_phy_name)); 15515e111ed8SAndrew Rybchenko memcpy(encp->enc_phy_name, namep, namelen); 15525e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_NAMES */ 15535e111ed8SAndrew Rybchenko (void) memset(encp->enc_phy_revision, 0, 15545e111ed8SAndrew Rybchenko sizeof (encp->enc_phy_revision)); 15555e111ed8SAndrew Rybchenko memcpy(encp->enc_phy_revision, 15565e111ed8SAndrew Rybchenko MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION), 15575e111ed8SAndrew Rybchenko MIN(sizeof (encp->enc_phy_revision) - 1, 15585e111ed8SAndrew Rybchenko MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN)); 15595e111ed8SAndrew Rybchenko #if EFSYS_OPT_PHY_LED_CONTROL 15605e111ed8SAndrew Rybchenko encp->enc_led_mask = ((1 << EFX_PHY_LED_DEFAULT) | 15615e111ed8SAndrew Rybchenko (1 << EFX_PHY_LED_OFF) | 15625e111ed8SAndrew Rybchenko (1 << EFX_PHY_LED_ON)); 15635e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_PHY_LED_CONTROL */ 15645e111ed8SAndrew Rybchenko 15655e111ed8SAndrew Rybchenko /* Get the media type of the fixed port, if recognised. */ 15665e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI); 15675e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4); 15685e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4); 15695e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP); 15705e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS); 15715e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T); 15725e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_MEDIA_QSFP_PLUS == EFX_PHY_MEDIA_QSFP_PLUS); 15735e111ed8SAndrew Rybchenko phy_media_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE); 15745e111ed8SAndrew Rybchenko epp->ep_fixed_port_type = (efx_phy_media_type_t)phy_media_type; 15755e111ed8SAndrew Rybchenko if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES) 15765e111ed8SAndrew Rybchenko epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID; 15775e111ed8SAndrew Rybchenko 15785e111ed8SAndrew Rybchenko epp->ep_phy_cap_mask = 15795e111ed8SAndrew Rybchenko MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP); 15805e111ed8SAndrew Rybchenko #if EFSYS_OPT_PHY_FLAGS 15815e111ed8SAndrew Rybchenko encp->enc_phy_flags_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_FLAGS); 15825e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_PHY_FLAGS */ 15835e111ed8SAndrew Rybchenko 15845e111ed8SAndrew Rybchenko encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT); 15855e111ed8SAndrew Rybchenko 15865e111ed8SAndrew Rybchenko /* Populate internal state */ 15875e111ed8SAndrew Rybchenko encp->enc_mcdi_mdio_channel = 15885e111ed8SAndrew Rybchenko (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL); 15895e111ed8SAndrew Rybchenko 15905e111ed8SAndrew Rybchenko #if EFSYS_OPT_PHY_STATS 15915e111ed8SAndrew Rybchenko encp->enc_mcdi_phy_stat_mask = 15925e111ed8SAndrew Rybchenko MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_STATS_MASK); 15935e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_PHY_STATS */ 15945e111ed8SAndrew Rybchenko 15955e111ed8SAndrew Rybchenko #if EFSYS_OPT_BIST 15965e111ed8SAndrew Rybchenko encp->enc_bist_mask = 0; 15975e111ed8SAndrew Rybchenko if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, 15985e111ed8SAndrew Rybchenko GET_PHY_CFG_OUT_BIST_CABLE_SHORT)) 15995e111ed8SAndrew Rybchenko encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_SHORT); 16005e111ed8SAndrew Rybchenko if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, 16015e111ed8SAndrew Rybchenko GET_PHY_CFG_OUT_BIST_CABLE_LONG)) 16025e111ed8SAndrew Rybchenko encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_LONG); 16035e111ed8SAndrew Rybchenko if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, 16045e111ed8SAndrew Rybchenko GET_PHY_CFG_OUT_BIST)) 16055e111ed8SAndrew Rybchenko encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_NORMAL); 16065e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_BIST */ 16075e111ed8SAndrew Rybchenko 16085e111ed8SAndrew Rybchenko return (0); 16095e111ed8SAndrew Rybchenko 16105e111ed8SAndrew Rybchenko fail2: 16115e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2); 16125e111ed8SAndrew Rybchenko fail1: 16135e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 16145e111ed8SAndrew Rybchenko 16155e111ed8SAndrew Rybchenko return (rc); 16165e111ed8SAndrew Rybchenko } 16175e111ed8SAndrew Rybchenko 16185e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 16195e111ed8SAndrew Rybchenko efx_mcdi_firmware_update_supported( 16205e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 16215e111ed8SAndrew Rybchenko __out boolean_t *supportedp) 16225e111ed8SAndrew Rybchenko { 16235e111ed8SAndrew Rybchenko const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 16245e111ed8SAndrew Rybchenko efx_rc_t rc; 16255e111ed8SAndrew Rybchenko 16265e111ed8SAndrew Rybchenko if (emcop != NULL) { 16275e111ed8SAndrew Rybchenko if ((rc = emcop->emco_feature_supported(enp, 16285e111ed8SAndrew Rybchenko EFX_MCDI_FEATURE_FW_UPDATE, supportedp)) != 0) 16295e111ed8SAndrew Rybchenko goto fail1; 16305e111ed8SAndrew Rybchenko } else { 16315e111ed8SAndrew Rybchenko /* Earlier devices always supported updates */ 16325e111ed8SAndrew Rybchenko *supportedp = B_TRUE; 16335e111ed8SAndrew Rybchenko } 16345e111ed8SAndrew Rybchenko 16355e111ed8SAndrew Rybchenko return (0); 16365e111ed8SAndrew Rybchenko 16375e111ed8SAndrew Rybchenko fail1: 16385e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 16395e111ed8SAndrew Rybchenko 16405e111ed8SAndrew Rybchenko return (rc); 16415e111ed8SAndrew Rybchenko } 16425e111ed8SAndrew Rybchenko 16435e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 16445e111ed8SAndrew Rybchenko efx_mcdi_macaddr_change_supported( 16455e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 16465e111ed8SAndrew Rybchenko __out boolean_t *supportedp) 16475e111ed8SAndrew Rybchenko { 16485e111ed8SAndrew Rybchenko const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 16495e111ed8SAndrew Rybchenko efx_rc_t rc; 16505e111ed8SAndrew Rybchenko 16515e111ed8SAndrew Rybchenko if (emcop != NULL) { 16525e111ed8SAndrew Rybchenko if ((rc = emcop->emco_feature_supported(enp, 16535e111ed8SAndrew Rybchenko EFX_MCDI_FEATURE_MACADDR_CHANGE, supportedp)) != 0) 16545e111ed8SAndrew Rybchenko goto fail1; 16555e111ed8SAndrew Rybchenko } else { 16565e111ed8SAndrew Rybchenko /* Earlier devices always supported MAC changes */ 16575e111ed8SAndrew Rybchenko *supportedp = B_TRUE; 16585e111ed8SAndrew Rybchenko } 16595e111ed8SAndrew Rybchenko 16605e111ed8SAndrew Rybchenko return (0); 16615e111ed8SAndrew Rybchenko 16625e111ed8SAndrew Rybchenko fail1: 16635e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 16645e111ed8SAndrew Rybchenko 16655e111ed8SAndrew Rybchenko return (rc); 16665e111ed8SAndrew Rybchenko } 16675e111ed8SAndrew Rybchenko 16685e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 16695e111ed8SAndrew Rybchenko efx_mcdi_link_control_supported( 16705e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 16715e111ed8SAndrew Rybchenko __out boolean_t *supportedp) 16725e111ed8SAndrew Rybchenko { 16735e111ed8SAndrew Rybchenko const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 16745e111ed8SAndrew Rybchenko efx_rc_t rc; 16755e111ed8SAndrew Rybchenko 16765e111ed8SAndrew Rybchenko if (emcop != NULL) { 16775e111ed8SAndrew Rybchenko if ((rc = emcop->emco_feature_supported(enp, 16785e111ed8SAndrew Rybchenko EFX_MCDI_FEATURE_LINK_CONTROL, supportedp)) != 0) 16795e111ed8SAndrew Rybchenko goto fail1; 16805e111ed8SAndrew Rybchenko } else { 16815e111ed8SAndrew Rybchenko /* Earlier devices always supported link control */ 16825e111ed8SAndrew Rybchenko *supportedp = B_TRUE; 16835e111ed8SAndrew Rybchenko } 16845e111ed8SAndrew Rybchenko 16855e111ed8SAndrew Rybchenko return (0); 16865e111ed8SAndrew Rybchenko 16875e111ed8SAndrew Rybchenko fail1: 16885e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 16895e111ed8SAndrew Rybchenko 16905e111ed8SAndrew Rybchenko return (rc); 16915e111ed8SAndrew Rybchenko } 16925e111ed8SAndrew Rybchenko 16935e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 16945e111ed8SAndrew Rybchenko efx_mcdi_mac_spoofing_supported( 16955e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 16965e111ed8SAndrew Rybchenko __out boolean_t *supportedp) 16975e111ed8SAndrew Rybchenko { 16985e111ed8SAndrew Rybchenko const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 16995e111ed8SAndrew Rybchenko efx_rc_t rc; 17005e111ed8SAndrew Rybchenko 17015e111ed8SAndrew Rybchenko if (emcop != NULL) { 17025e111ed8SAndrew Rybchenko if ((rc = emcop->emco_feature_supported(enp, 17035e111ed8SAndrew Rybchenko EFX_MCDI_FEATURE_MAC_SPOOFING, supportedp)) != 0) 17045e111ed8SAndrew Rybchenko goto fail1; 17055e111ed8SAndrew Rybchenko } else { 17065e111ed8SAndrew Rybchenko /* Earlier devices always supported MAC spoofing */ 17075e111ed8SAndrew Rybchenko *supportedp = B_TRUE; 17085e111ed8SAndrew Rybchenko } 17095e111ed8SAndrew Rybchenko 17105e111ed8SAndrew Rybchenko return (0); 17115e111ed8SAndrew Rybchenko 17125e111ed8SAndrew Rybchenko fail1: 17135e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 17145e111ed8SAndrew Rybchenko 17155e111ed8SAndrew Rybchenko return (rc); 17165e111ed8SAndrew Rybchenko } 17175e111ed8SAndrew Rybchenko 17185e111ed8SAndrew Rybchenko #if EFSYS_OPT_BIST 17195e111ed8SAndrew Rybchenko 17205e111ed8SAndrew Rybchenko #if EFX_OPTS_EF10() 17215e111ed8SAndrew Rybchenko /* 17225e111ed8SAndrew Rybchenko * Enter bist offline mode. This is a fw mode which puts the NIC into a state 17235e111ed8SAndrew Rybchenko * where memory BIST tests can be run and not much else can interfere or happen. 17245e111ed8SAndrew Rybchenko * A reboot is required to exit this mode. 17255e111ed8SAndrew Rybchenko */ 17265e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 17275e111ed8SAndrew Rybchenko efx_mcdi_bist_enable_offline( 17285e111ed8SAndrew Rybchenko __in efx_nic_t *enp) 17295e111ed8SAndrew Rybchenko { 17305e111ed8SAndrew Rybchenko efx_mcdi_req_t req; 17315e111ed8SAndrew Rybchenko efx_rc_t rc; 17325e111ed8SAndrew Rybchenko 17335e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_IN_LEN == 0); 17345e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_OUT_LEN == 0); 17355e111ed8SAndrew Rybchenko 17365e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_ENABLE_OFFLINE_BIST; 17375e111ed8SAndrew Rybchenko req.emr_in_buf = NULL; 17385e111ed8SAndrew Rybchenko req.emr_in_length = 0; 17395e111ed8SAndrew Rybchenko req.emr_out_buf = NULL; 17405e111ed8SAndrew Rybchenko req.emr_out_length = 0; 17415e111ed8SAndrew Rybchenko 17425e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req); 17435e111ed8SAndrew Rybchenko 17445e111ed8SAndrew Rybchenko if (req.emr_rc != 0) { 17455e111ed8SAndrew Rybchenko rc = req.emr_rc; 17465e111ed8SAndrew Rybchenko goto fail1; 17475e111ed8SAndrew Rybchenko } 17485e111ed8SAndrew Rybchenko 17495e111ed8SAndrew Rybchenko return (0); 17505e111ed8SAndrew Rybchenko 17515e111ed8SAndrew Rybchenko fail1: 17525e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 17535e111ed8SAndrew Rybchenko 17545e111ed8SAndrew Rybchenko return (rc); 17555e111ed8SAndrew Rybchenko } 17565e111ed8SAndrew Rybchenko #endif /* EFX_OPTS_EF10() */ 17575e111ed8SAndrew Rybchenko 17585e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 17595e111ed8SAndrew Rybchenko efx_mcdi_bist_start( 17605e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 17615e111ed8SAndrew Rybchenko __in efx_bist_type_t type) 17625e111ed8SAndrew Rybchenko { 17635e111ed8SAndrew Rybchenko efx_mcdi_req_t req; 17645e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_START_BIST_IN_LEN, 17655e111ed8SAndrew Rybchenko MC_CMD_START_BIST_OUT_LEN); 17665e111ed8SAndrew Rybchenko efx_rc_t rc; 17675e111ed8SAndrew Rybchenko 17685e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_START_BIST; 17695e111ed8SAndrew Rybchenko req.emr_in_buf = payload; 17705e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_START_BIST_IN_LEN; 17715e111ed8SAndrew Rybchenko req.emr_out_buf = payload; 17725e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_START_BIST_OUT_LEN; 17735e111ed8SAndrew Rybchenko 17745e111ed8SAndrew Rybchenko switch (type) { 17755e111ed8SAndrew Rybchenko case EFX_BIST_TYPE_PHY_NORMAL: 17765e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST); 17775e111ed8SAndrew Rybchenko break; 17785e111ed8SAndrew Rybchenko case EFX_BIST_TYPE_PHY_CABLE_SHORT: 17795e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 17805e111ed8SAndrew Rybchenko MC_CMD_PHY_BIST_CABLE_SHORT); 17815e111ed8SAndrew Rybchenko break; 17825e111ed8SAndrew Rybchenko case EFX_BIST_TYPE_PHY_CABLE_LONG: 17835e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 17845e111ed8SAndrew Rybchenko MC_CMD_PHY_BIST_CABLE_LONG); 17855e111ed8SAndrew Rybchenko break; 17865e111ed8SAndrew Rybchenko case EFX_BIST_TYPE_MC_MEM: 17875e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 17885e111ed8SAndrew Rybchenko MC_CMD_MC_MEM_BIST); 17895e111ed8SAndrew Rybchenko break; 17905e111ed8SAndrew Rybchenko case EFX_BIST_TYPE_SAT_MEM: 17915e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 17925e111ed8SAndrew Rybchenko MC_CMD_PORT_MEM_BIST); 17935e111ed8SAndrew Rybchenko break; 17945e111ed8SAndrew Rybchenko case EFX_BIST_TYPE_REG: 17955e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 17965e111ed8SAndrew Rybchenko MC_CMD_REG_BIST); 17975e111ed8SAndrew Rybchenko break; 17985e111ed8SAndrew Rybchenko default: 17995e111ed8SAndrew Rybchenko EFSYS_ASSERT(0); 18005e111ed8SAndrew Rybchenko } 18015e111ed8SAndrew Rybchenko 18025e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req); 18035e111ed8SAndrew Rybchenko 18045e111ed8SAndrew Rybchenko if (req.emr_rc != 0) { 18055e111ed8SAndrew Rybchenko rc = req.emr_rc; 18065e111ed8SAndrew Rybchenko goto fail1; 18075e111ed8SAndrew Rybchenko } 18085e111ed8SAndrew Rybchenko 18095e111ed8SAndrew Rybchenko return (0); 18105e111ed8SAndrew Rybchenko 18115e111ed8SAndrew Rybchenko fail1: 18125e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 18135e111ed8SAndrew Rybchenko 18145e111ed8SAndrew Rybchenko return (rc); 18155e111ed8SAndrew Rybchenko } 18165e111ed8SAndrew Rybchenko 18175e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_BIST */ 18185e111ed8SAndrew Rybchenko 18195e111ed8SAndrew Rybchenko 18205e111ed8SAndrew Rybchenko /* Enable logging of some events (e.g. link state changes) */ 18215e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 18225e111ed8SAndrew Rybchenko efx_mcdi_log_ctrl( 18235e111ed8SAndrew Rybchenko __in efx_nic_t *enp) 18245e111ed8SAndrew Rybchenko { 18255e111ed8SAndrew Rybchenko efx_mcdi_req_t req; 18265e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_LOG_CTRL_IN_LEN, 18275e111ed8SAndrew Rybchenko MC_CMD_LOG_CTRL_OUT_LEN); 18285e111ed8SAndrew Rybchenko efx_rc_t rc; 18295e111ed8SAndrew Rybchenko 18305e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_LOG_CTRL; 18315e111ed8SAndrew Rybchenko req.emr_in_buf = payload; 18325e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_LOG_CTRL_IN_LEN; 18335e111ed8SAndrew Rybchenko req.emr_out_buf = payload; 18345e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_LOG_CTRL_OUT_LEN; 18355e111ed8SAndrew Rybchenko 18365e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST, 18375e111ed8SAndrew Rybchenko MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ); 18385e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST_EVQ, 0); 18395e111ed8SAndrew Rybchenko 18405e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req); 18415e111ed8SAndrew Rybchenko 18425e111ed8SAndrew Rybchenko if (req.emr_rc != 0) { 18435e111ed8SAndrew Rybchenko rc = req.emr_rc; 18445e111ed8SAndrew Rybchenko goto fail1; 18455e111ed8SAndrew Rybchenko } 18465e111ed8SAndrew Rybchenko 18475e111ed8SAndrew Rybchenko return (0); 18485e111ed8SAndrew Rybchenko 18495e111ed8SAndrew Rybchenko fail1: 18505e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 18515e111ed8SAndrew Rybchenko 18525e111ed8SAndrew Rybchenko return (rc); 18535e111ed8SAndrew Rybchenko } 18545e111ed8SAndrew Rybchenko 18555e111ed8SAndrew Rybchenko 18565e111ed8SAndrew Rybchenko #if EFSYS_OPT_MAC_STATS 18575e111ed8SAndrew Rybchenko 18585e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 18595e111ed8SAndrew Rybchenko efx_mcdi_mac_stats( 18605e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 18615e111ed8SAndrew Rybchenko __in uint32_t vport_id, 18625e111ed8SAndrew Rybchenko __in_opt efsys_mem_t *esmp, 18635e111ed8SAndrew Rybchenko __in efx_stats_action_t action, 18645e111ed8SAndrew Rybchenko __in uint16_t period_ms) 18655e111ed8SAndrew Rybchenko { 18665e111ed8SAndrew Rybchenko efx_mcdi_req_t req; 18675e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAC_STATS_IN_LEN, 18685e111ed8SAndrew Rybchenko MC_CMD_MAC_STATS_V2_OUT_DMA_LEN); 18695e111ed8SAndrew Rybchenko int clear = (action == EFX_STATS_CLEAR); 18705e111ed8SAndrew Rybchenko int upload = (action == EFX_STATS_UPLOAD); 18715e111ed8SAndrew Rybchenko int enable = (action == EFX_STATS_ENABLE_NOEVENTS); 18725e111ed8SAndrew Rybchenko int events = (action == EFX_STATS_ENABLE_EVENTS); 18735e111ed8SAndrew Rybchenko int disable = (action == EFX_STATS_DISABLE); 18745e111ed8SAndrew Rybchenko efx_rc_t rc; 18755e111ed8SAndrew Rybchenko 18765e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_MAC_STATS; 18775e111ed8SAndrew Rybchenko req.emr_in_buf = payload; 18785e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_MAC_STATS_IN_LEN; 18795e111ed8SAndrew Rybchenko req.emr_out_buf = payload; 18805e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_MAC_STATS_V2_OUT_DMA_LEN; 18815e111ed8SAndrew Rybchenko 18825e111ed8SAndrew Rybchenko MCDI_IN_POPULATE_DWORD_6(req, MAC_STATS_IN_CMD, 18835e111ed8SAndrew Rybchenko MAC_STATS_IN_DMA, upload, 18845e111ed8SAndrew Rybchenko MAC_STATS_IN_CLEAR, clear, 18855e111ed8SAndrew Rybchenko MAC_STATS_IN_PERIODIC_CHANGE, enable | events | disable, 18865e111ed8SAndrew Rybchenko MAC_STATS_IN_PERIODIC_ENABLE, enable | events, 18875e111ed8SAndrew Rybchenko MAC_STATS_IN_PERIODIC_NOEVENT, !events, 18885e111ed8SAndrew Rybchenko MAC_STATS_IN_PERIOD_MS, (enable | events) ? period_ms : 0); 18895e111ed8SAndrew Rybchenko 18905e111ed8SAndrew Rybchenko if (enable || events || upload) { 18915e111ed8SAndrew Rybchenko const efx_nic_cfg_t *encp = &enp->en_nic_cfg; 18925e111ed8SAndrew Rybchenko uint32_t bytes; 18935e111ed8SAndrew Rybchenko 18945e111ed8SAndrew Rybchenko /* Periodic stats or stats upload require a DMA buffer */ 18955e111ed8SAndrew Rybchenko if (esmp == NULL) { 18965e111ed8SAndrew Rybchenko rc = EINVAL; 18975e111ed8SAndrew Rybchenko goto fail1; 18985e111ed8SAndrew Rybchenko } 18995e111ed8SAndrew Rybchenko 19005e111ed8SAndrew Rybchenko if (encp->enc_mac_stats_nstats < MC_CMD_MAC_NSTATS) { 19015e111ed8SAndrew Rybchenko /* MAC stats count too small for legacy MAC stats */ 19025e111ed8SAndrew Rybchenko rc = ENOSPC; 19035e111ed8SAndrew Rybchenko goto fail2; 19045e111ed8SAndrew Rybchenko } 19055e111ed8SAndrew Rybchenko 19065e111ed8SAndrew Rybchenko bytes = encp->enc_mac_stats_nstats * sizeof (efx_qword_t); 19075e111ed8SAndrew Rybchenko 19085e111ed8SAndrew Rybchenko if (EFSYS_MEM_SIZE(esmp) < bytes) { 19095e111ed8SAndrew Rybchenko /* DMA buffer too small */ 19105e111ed8SAndrew Rybchenko rc = ENOSPC; 19115e111ed8SAndrew Rybchenko goto fail3; 19125e111ed8SAndrew Rybchenko } 19135e111ed8SAndrew Rybchenko 19145e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_LO, 19155e111ed8SAndrew Rybchenko EFSYS_MEM_ADDR(esmp) & 0xffffffff); 19165e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_HI, 19175e111ed8SAndrew Rybchenko EFSYS_MEM_ADDR(esmp) >> 32); 19185e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_LEN, bytes); 19195e111ed8SAndrew Rybchenko } 19205e111ed8SAndrew Rybchenko 19215e111ed8SAndrew Rybchenko /* 19225e111ed8SAndrew Rybchenko * NOTE: Do not use EVB_PORT_ID_ASSIGNED when disabling periodic stats, 19235e111ed8SAndrew Rybchenko * as this may fail (and leave periodic DMA enabled) if the 19245e111ed8SAndrew Rybchenko * vadapter has already been deleted. 19255e111ed8SAndrew Rybchenko */ 19265e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, MAC_STATS_IN_PORT_ID, 19275e111ed8SAndrew Rybchenko (disable ? EVB_PORT_ID_NULL : vport_id)); 19285e111ed8SAndrew Rybchenko 19295e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req); 19305e111ed8SAndrew Rybchenko 19315e111ed8SAndrew Rybchenko if (req.emr_rc != 0) { 19325e111ed8SAndrew Rybchenko /* EF10: Expect ENOENT if no DMA queues are initialised */ 19335e111ed8SAndrew Rybchenko if ((req.emr_rc != ENOENT) || 19345e111ed8SAndrew Rybchenko (enp->en_rx_qcount + enp->en_tx_qcount != 0)) { 19355e111ed8SAndrew Rybchenko rc = req.emr_rc; 19365e111ed8SAndrew Rybchenko goto fail4; 19375e111ed8SAndrew Rybchenko } 19385e111ed8SAndrew Rybchenko } 19395e111ed8SAndrew Rybchenko 19405e111ed8SAndrew Rybchenko return (0); 19415e111ed8SAndrew Rybchenko 19425e111ed8SAndrew Rybchenko fail4: 19435e111ed8SAndrew Rybchenko EFSYS_PROBE(fail4); 19445e111ed8SAndrew Rybchenko fail3: 19455e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3); 19465e111ed8SAndrew Rybchenko fail2: 19475e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2); 19485e111ed8SAndrew Rybchenko fail1: 19495e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 19505e111ed8SAndrew Rybchenko 19515e111ed8SAndrew Rybchenko return (rc); 19525e111ed8SAndrew Rybchenko } 19535e111ed8SAndrew Rybchenko 19545e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 19555e111ed8SAndrew Rybchenko efx_mcdi_mac_stats_clear( 19565e111ed8SAndrew Rybchenko __in efx_nic_t *enp) 19575e111ed8SAndrew Rybchenko { 19585e111ed8SAndrew Rybchenko efx_rc_t rc; 19595e111ed8SAndrew Rybchenko 19605e111ed8SAndrew Rybchenko if ((rc = efx_mcdi_mac_stats(enp, enp->en_vport_id, NULL, 19615e111ed8SAndrew Rybchenko EFX_STATS_CLEAR, 0)) != 0) 19625e111ed8SAndrew Rybchenko goto fail1; 19635e111ed8SAndrew Rybchenko 19645e111ed8SAndrew Rybchenko return (0); 19655e111ed8SAndrew Rybchenko 19665e111ed8SAndrew Rybchenko fail1: 19675e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 19685e111ed8SAndrew Rybchenko 19695e111ed8SAndrew Rybchenko return (rc); 19705e111ed8SAndrew Rybchenko } 19715e111ed8SAndrew Rybchenko 19725e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 19735e111ed8SAndrew Rybchenko efx_mcdi_mac_stats_upload( 19745e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 19755e111ed8SAndrew Rybchenko __in efsys_mem_t *esmp) 19765e111ed8SAndrew Rybchenko { 19775e111ed8SAndrew Rybchenko efx_rc_t rc; 19785e111ed8SAndrew Rybchenko 19795e111ed8SAndrew Rybchenko /* 19805e111ed8SAndrew Rybchenko * The MC DMAs aggregate statistics for our convenience, so we can 19815e111ed8SAndrew Rybchenko * avoid having to pull the statistics buffer into the cache to 19825e111ed8SAndrew Rybchenko * maintain cumulative statistics. 19835e111ed8SAndrew Rybchenko */ 19845e111ed8SAndrew Rybchenko if ((rc = efx_mcdi_mac_stats(enp, enp->en_vport_id, esmp, 19855e111ed8SAndrew Rybchenko EFX_STATS_UPLOAD, 0)) != 0) 19865e111ed8SAndrew Rybchenko goto fail1; 19875e111ed8SAndrew Rybchenko 19885e111ed8SAndrew Rybchenko return (0); 19895e111ed8SAndrew Rybchenko 19905e111ed8SAndrew Rybchenko fail1: 19915e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 19925e111ed8SAndrew Rybchenko 19935e111ed8SAndrew Rybchenko return (rc); 19945e111ed8SAndrew Rybchenko } 19955e111ed8SAndrew Rybchenko 19965e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 19975e111ed8SAndrew Rybchenko efx_mcdi_mac_stats_periodic( 19985e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 19995e111ed8SAndrew Rybchenko __in efsys_mem_t *esmp, 20005e111ed8SAndrew Rybchenko __in uint16_t period_ms, 20015e111ed8SAndrew Rybchenko __in boolean_t events) 20025e111ed8SAndrew Rybchenko { 20035e111ed8SAndrew Rybchenko efx_rc_t rc; 20045e111ed8SAndrew Rybchenko 20055e111ed8SAndrew Rybchenko /* 20065e111ed8SAndrew Rybchenko * The MC DMAs aggregate statistics for our convenience, so we can 20075e111ed8SAndrew Rybchenko * avoid having to pull the statistics buffer into the cache to 20085e111ed8SAndrew Rybchenko * maintain cumulative statistics. 20095e111ed8SAndrew Rybchenko * Huntington uses a fixed 1sec period. 20105e111ed8SAndrew Rybchenko * Medford uses a fixed 1sec period before v6.2.1.1033 firmware. 20115e111ed8SAndrew Rybchenko */ 20125e111ed8SAndrew Rybchenko if (period_ms == 0) 20135e111ed8SAndrew Rybchenko rc = efx_mcdi_mac_stats(enp, enp->en_vport_id, NULL, 20145e111ed8SAndrew Rybchenko EFX_STATS_DISABLE, 0); 20155e111ed8SAndrew Rybchenko else if (events) 20165e111ed8SAndrew Rybchenko rc = efx_mcdi_mac_stats(enp, enp->en_vport_id, esmp, 20175e111ed8SAndrew Rybchenko EFX_STATS_ENABLE_EVENTS, period_ms); 20185e111ed8SAndrew Rybchenko else 20195e111ed8SAndrew Rybchenko rc = efx_mcdi_mac_stats(enp, enp->en_vport_id, esmp, 20205e111ed8SAndrew Rybchenko EFX_STATS_ENABLE_NOEVENTS, period_ms); 20215e111ed8SAndrew Rybchenko 20225e111ed8SAndrew Rybchenko if (rc != 0) 20235e111ed8SAndrew Rybchenko goto fail1; 20245e111ed8SAndrew Rybchenko 20255e111ed8SAndrew Rybchenko return (0); 20265e111ed8SAndrew Rybchenko 20275e111ed8SAndrew Rybchenko fail1: 20285e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 20295e111ed8SAndrew Rybchenko 20305e111ed8SAndrew Rybchenko return (rc); 20315e111ed8SAndrew Rybchenko } 20325e111ed8SAndrew Rybchenko 20335e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MAC_STATS */ 20345e111ed8SAndrew Rybchenko 20353c1c5cc4SAndrew Rybchenko #if EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10() 20365e111ed8SAndrew Rybchenko 20375e111ed8SAndrew Rybchenko /* 20385e111ed8SAndrew Rybchenko * This function returns the pf and vf number of a function. If it is a pf the 20395e111ed8SAndrew Rybchenko * vf number is 0xffff. The vf number is the index of the vf on that 20405e111ed8SAndrew Rybchenko * function. So if you have 3 vfs on pf 0 the 3 vfs will return (pf=0,vf=0), 20415e111ed8SAndrew Rybchenko * (pf=0,vf=1), (pf=0,vf=2) aand the pf will return (pf=0, vf=0xffff). 20425e111ed8SAndrew Rybchenko */ 20435e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 20445e111ed8SAndrew Rybchenko efx_mcdi_get_function_info( 20455e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 20465e111ed8SAndrew Rybchenko __out uint32_t *pfp, 20475e111ed8SAndrew Rybchenko __out_opt uint32_t *vfp) 20485e111ed8SAndrew Rybchenko { 20495e111ed8SAndrew Rybchenko efx_mcdi_req_t req; 20505e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_FUNCTION_INFO_IN_LEN, 20515e111ed8SAndrew Rybchenko MC_CMD_GET_FUNCTION_INFO_OUT_LEN); 20525e111ed8SAndrew Rybchenko efx_rc_t rc; 20535e111ed8SAndrew Rybchenko 20545e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_FUNCTION_INFO; 20555e111ed8SAndrew Rybchenko req.emr_in_buf = payload; 20565e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_GET_FUNCTION_INFO_IN_LEN; 20575e111ed8SAndrew Rybchenko req.emr_out_buf = payload; 20585e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_GET_FUNCTION_INFO_OUT_LEN; 20595e111ed8SAndrew Rybchenko 20605e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req); 20615e111ed8SAndrew Rybchenko 20625e111ed8SAndrew Rybchenko if (req.emr_rc != 0) { 20635e111ed8SAndrew Rybchenko rc = req.emr_rc; 20645e111ed8SAndrew Rybchenko goto fail1; 20655e111ed8SAndrew Rybchenko } 20665e111ed8SAndrew Rybchenko 20675e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_FUNCTION_INFO_OUT_LEN) { 20685e111ed8SAndrew Rybchenko rc = EMSGSIZE; 20695e111ed8SAndrew Rybchenko goto fail2; 20705e111ed8SAndrew Rybchenko } 20715e111ed8SAndrew Rybchenko 20725e111ed8SAndrew Rybchenko *pfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_PF); 20735e111ed8SAndrew Rybchenko if (vfp != NULL) 20745e111ed8SAndrew Rybchenko *vfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_VF); 20755e111ed8SAndrew Rybchenko 20765e111ed8SAndrew Rybchenko return (0); 20775e111ed8SAndrew Rybchenko 20785e111ed8SAndrew Rybchenko fail2: 20795e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2); 20805e111ed8SAndrew Rybchenko fail1: 20815e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 20825e111ed8SAndrew Rybchenko 20835e111ed8SAndrew Rybchenko return (rc); 20845e111ed8SAndrew Rybchenko } 20855e111ed8SAndrew Rybchenko 20865e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 20875e111ed8SAndrew Rybchenko efx_mcdi_privilege_mask( 20885e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 20895e111ed8SAndrew Rybchenko __in uint32_t pf, 20905e111ed8SAndrew Rybchenko __in uint32_t vf, 20915e111ed8SAndrew Rybchenko __out uint32_t *maskp) 20925e111ed8SAndrew Rybchenko { 20935e111ed8SAndrew Rybchenko efx_mcdi_req_t req; 20945e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_PRIVILEGE_MASK_IN_LEN, 20955e111ed8SAndrew Rybchenko MC_CMD_PRIVILEGE_MASK_OUT_LEN); 20965e111ed8SAndrew Rybchenko efx_rc_t rc; 20975e111ed8SAndrew Rybchenko 20985e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_PRIVILEGE_MASK; 20995e111ed8SAndrew Rybchenko req.emr_in_buf = payload; 21005e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_PRIVILEGE_MASK_IN_LEN; 21015e111ed8SAndrew Rybchenko req.emr_out_buf = payload; 21025e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_PRIVILEGE_MASK_OUT_LEN; 21035e111ed8SAndrew Rybchenko 21045e111ed8SAndrew Rybchenko MCDI_IN_POPULATE_DWORD_2(req, PRIVILEGE_MASK_IN_FUNCTION, 21055e111ed8SAndrew Rybchenko PRIVILEGE_MASK_IN_FUNCTION_PF, pf, 21065e111ed8SAndrew Rybchenko PRIVILEGE_MASK_IN_FUNCTION_VF, vf); 21075e111ed8SAndrew Rybchenko 21085e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req); 21095e111ed8SAndrew Rybchenko 21105e111ed8SAndrew Rybchenko if (req.emr_rc != 0) { 21115e111ed8SAndrew Rybchenko rc = req.emr_rc; 21125e111ed8SAndrew Rybchenko goto fail1; 21135e111ed8SAndrew Rybchenko } 21145e111ed8SAndrew Rybchenko 21155e111ed8SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_PRIVILEGE_MASK_OUT_LEN) { 21165e111ed8SAndrew Rybchenko rc = EMSGSIZE; 21175e111ed8SAndrew Rybchenko goto fail2; 21185e111ed8SAndrew Rybchenko } 21195e111ed8SAndrew Rybchenko 21205e111ed8SAndrew Rybchenko *maskp = MCDI_OUT_DWORD(req, PRIVILEGE_MASK_OUT_OLD_MASK); 21215e111ed8SAndrew Rybchenko 21225e111ed8SAndrew Rybchenko return (0); 21235e111ed8SAndrew Rybchenko 21245e111ed8SAndrew Rybchenko fail2: 21255e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2); 21265e111ed8SAndrew Rybchenko fail1: 21275e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 21285e111ed8SAndrew Rybchenko 21295e111ed8SAndrew Rybchenko return (rc); 21305e111ed8SAndrew Rybchenko } 21315e111ed8SAndrew Rybchenko 21323c1c5cc4SAndrew Rybchenko #endif /* EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10() */ 21335e111ed8SAndrew Rybchenko 21345e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 21355e111ed8SAndrew Rybchenko efx_mcdi_set_workaround( 21365e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 21375e111ed8SAndrew Rybchenko __in uint32_t type, 21385e111ed8SAndrew Rybchenko __in boolean_t enabled, 21395e111ed8SAndrew Rybchenko __out_opt uint32_t *flagsp) 21405e111ed8SAndrew Rybchenko { 21415e111ed8SAndrew Rybchenko efx_mcdi_req_t req; 21425e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_WORKAROUND_IN_LEN, 21435e111ed8SAndrew Rybchenko MC_CMD_WORKAROUND_EXT_OUT_LEN); 21445e111ed8SAndrew Rybchenko efx_rc_t rc; 21455e111ed8SAndrew Rybchenko 21465e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_WORKAROUND; 21475e111ed8SAndrew Rybchenko req.emr_in_buf = payload; 21485e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_WORKAROUND_IN_LEN; 21495e111ed8SAndrew Rybchenko req.emr_out_buf = payload; 21505e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_WORKAROUND_OUT_LEN; 21515e111ed8SAndrew Rybchenko 21525e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, type); 21535e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, enabled ? 1 : 0); 21545e111ed8SAndrew Rybchenko 21555e111ed8SAndrew Rybchenko efx_mcdi_execute_quiet(enp, &req); 21565e111ed8SAndrew Rybchenko 21575e111ed8SAndrew Rybchenko if (req.emr_rc != 0) { 21585e111ed8SAndrew Rybchenko rc = req.emr_rc; 21595e111ed8SAndrew Rybchenko goto fail1; 21605e111ed8SAndrew Rybchenko } 21615e111ed8SAndrew Rybchenko 21625e111ed8SAndrew Rybchenko if (flagsp != NULL) { 21635e111ed8SAndrew Rybchenko if (req.emr_out_length_used >= MC_CMD_WORKAROUND_EXT_OUT_LEN) 21645e111ed8SAndrew Rybchenko *flagsp = MCDI_OUT_DWORD(req, WORKAROUND_EXT_OUT_FLAGS); 21655e111ed8SAndrew Rybchenko else 21665e111ed8SAndrew Rybchenko *flagsp = 0; 21675e111ed8SAndrew Rybchenko } 21685e111ed8SAndrew Rybchenko 21695e111ed8SAndrew Rybchenko return (0); 21705e111ed8SAndrew Rybchenko 21715e111ed8SAndrew Rybchenko fail1: 21725e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 21735e111ed8SAndrew Rybchenko 21745e111ed8SAndrew Rybchenko return (rc); 21755e111ed8SAndrew Rybchenko } 21765e111ed8SAndrew Rybchenko 21775e111ed8SAndrew Rybchenko 21785e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 21795e111ed8SAndrew Rybchenko efx_mcdi_get_workarounds( 21805e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 21815e111ed8SAndrew Rybchenko __out_opt uint32_t *implementedp, 21825e111ed8SAndrew Rybchenko __out_opt uint32_t *enabledp) 21835e111ed8SAndrew Rybchenko { 21845e111ed8SAndrew Rybchenko efx_mcdi_req_t req; 21855e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, 0, MC_CMD_GET_WORKAROUNDS_OUT_LEN); 21865e111ed8SAndrew Rybchenko efx_rc_t rc; 21875e111ed8SAndrew Rybchenko 21885e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_WORKAROUNDS; 21895e111ed8SAndrew Rybchenko req.emr_in_buf = NULL; 21905e111ed8SAndrew Rybchenko req.emr_in_length = 0; 21915e111ed8SAndrew Rybchenko req.emr_out_buf = payload; 21925e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_GET_WORKAROUNDS_OUT_LEN; 21935e111ed8SAndrew Rybchenko 21945e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req); 21955e111ed8SAndrew Rybchenko 21965e111ed8SAndrew Rybchenko if (req.emr_rc != 0) { 21975e111ed8SAndrew Rybchenko rc = req.emr_rc; 21985e111ed8SAndrew Rybchenko goto fail1; 21995e111ed8SAndrew Rybchenko } 22005e111ed8SAndrew Rybchenko 22015e111ed8SAndrew Rybchenko if (implementedp != NULL) { 22025e111ed8SAndrew Rybchenko *implementedp = 22035e111ed8SAndrew Rybchenko MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_IMPLEMENTED); 22045e111ed8SAndrew Rybchenko } 22055e111ed8SAndrew Rybchenko 22065e111ed8SAndrew Rybchenko if (enabledp != NULL) { 22075e111ed8SAndrew Rybchenko *enabledp = MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_ENABLED); 22085e111ed8SAndrew Rybchenko } 22095e111ed8SAndrew Rybchenko 22105e111ed8SAndrew Rybchenko return (0); 22115e111ed8SAndrew Rybchenko 22125e111ed8SAndrew Rybchenko fail1: 22135e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 22145e111ed8SAndrew Rybchenko 22155e111ed8SAndrew Rybchenko return (rc); 22165e111ed8SAndrew Rybchenko } 22175e111ed8SAndrew Rybchenko 22185e111ed8SAndrew Rybchenko /* 22195e111ed8SAndrew Rybchenko * Size of media information page in accordance with SFF-8472 and SFF-8436. 22205e111ed8SAndrew Rybchenko * It is used in MCDI interface as well. 22215e111ed8SAndrew Rybchenko */ 22225e111ed8SAndrew Rybchenko #define EFX_PHY_MEDIA_INFO_PAGE_SIZE 0x80 22235e111ed8SAndrew Rybchenko 22245e111ed8SAndrew Rybchenko /* 22255e111ed8SAndrew Rybchenko * Transceiver identifiers from SFF-8024 Table 4-1. 22265e111ed8SAndrew Rybchenko */ 22275e111ed8SAndrew Rybchenko #define EFX_SFF_TRANSCEIVER_ID_SFP 0x03 /* SFP/SFP+/SFP28 */ 22285e111ed8SAndrew Rybchenko #define EFX_SFF_TRANSCEIVER_ID_QSFP 0x0c /* QSFP */ 22295e111ed8SAndrew Rybchenko #define EFX_SFF_TRANSCEIVER_ID_QSFP_PLUS 0x0d /* QSFP+ or later */ 22305e111ed8SAndrew Rybchenko #define EFX_SFF_TRANSCEIVER_ID_QSFP28 0x11 /* QSFP28 or later */ 22315e111ed8SAndrew Rybchenko 22325e111ed8SAndrew Rybchenko static __checkReturn efx_rc_t 22335e111ed8SAndrew Rybchenko efx_mcdi_get_phy_media_info( 22345e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 22355e111ed8SAndrew Rybchenko __in uint32_t mcdi_page, 22365e111ed8SAndrew Rybchenko __in uint8_t offset, 22375e111ed8SAndrew Rybchenko __in uint8_t len, 22385e111ed8SAndrew Rybchenko __out_bcount(len) uint8_t *data) 22395e111ed8SAndrew Rybchenko { 22405e111ed8SAndrew Rybchenko efx_mcdi_req_t req; 22415e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN, 22425e111ed8SAndrew Rybchenko MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN( 22435e111ed8SAndrew Rybchenko EFX_PHY_MEDIA_INFO_PAGE_SIZE)); 22445e111ed8SAndrew Rybchenko efx_rc_t rc; 22455e111ed8SAndrew Rybchenko 22465e111ed8SAndrew Rybchenko EFSYS_ASSERT((uint32_t)offset + len <= EFX_PHY_MEDIA_INFO_PAGE_SIZE); 22475e111ed8SAndrew Rybchenko 22485e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_PHY_MEDIA_INFO; 22495e111ed8SAndrew Rybchenko req.emr_in_buf = payload; 22505e111ed8SAndrew Rybchenko req.emr_in_length = MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN; 22515e111ed8SAndrew Rybchenko req.emr_out_buf = payload; 22525e111ed8SAndrew Rybchenko req.emr_out_length = 22535e111ed8SAndrew Rybchenko MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE); 22545e111ed8SAndrew Rybchenko 22555e111ed8SAndrew Rybchenko MCDI_IN_SET_DWORD(req, GET_PHY_MEDIA_INFO_IN_PAGE, mcdi_page); 22565e111ed8SAndrew Rybchenko 22575e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req); 22585e111ed8SAndrew Rybchenko 22595e111ed8SAndrew Rybchenko if (req.emr_rc != 0) { 22605e111ed8SAndrew Rybchenko rc = req.emr_rc; 22615e111ed8SAndrew Rybchenko goto fail1; 22625e111ed8SAndrew Rybchenko } 22635e111ed8SAndrew Rybchenko 22645e111ed8SAndrew Rybchenko if (req.emr_out_length_used != 22655e111ed8SAndrew Rybchenko MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE)) { 22665e111ed8SAndrew Rybchenko rc = EMSGSIZE; 22675e111ed8SAndrew Rybchenko goto fail2; 22685e111ed8SAndrew Rybchenko } 22695e111ed8SAndrew Rybchenko 22705e111ed8SAndrew Rybchenko if (MCDI_OUT_DWORD(req, GET_PHY_MEDIA_INFO_OUT_DATALEN) != 22715e111ed8SAndrew Rybchenko EFX_PHY_MEDIA_INFO_PAGE_SIZE) { 22725e111ed8SAndrew Rybchenko rc = EIO; 22735e111ed8SAndrew Rybchenko goto fail3; 22745e111ed8SAndrew Rybchenko } 22755e111ed8SAndrew Rybchenko 22765e111ed8SAndrew Rybchenko memcpy(data, 22775e111ed8SAndrew Rybchenko MCDI_OUT2(req, uint8_t, GET_PHY_MEDIA_INFO_OUT_DATA) + offset, 22785e111ed8SAndrew Rybchenko len); 22795e111ed8SAndrew Rybchenko 22805e111ed8SAndrew Rybchenko return (0); 22815e111ed8SAndrew Rybchenko 22825e111ed8SAndrew Rybchenko fail3: 22835e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3); 22845e111ed8SAndrew Rybchenko fail2: 22855e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2); 22865e111ed8SAndrew Rybchenko fail1: 22875e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 22885e111ed8SAndrew Rybchenko 22895e111ed8SAndrew Rybchenko return (rc); 22905e111ed8SAndrew Rybchenko } 22915e111ed8SAndrew Rybchenko 22925e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 22935e111ed8SAndrew Rybchenko efx_mcdi_phy_module_get_info( 22945e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 22955e111ed8SAndrew Rybchenko __in uint8_t dev_addr, 22965e111ed8SAndrew Rybchenko __in size_t offset, 22975e111ed8SAndrew Rybchenko __in size_t len, 22985e111ed8SAndrew Rybchenko __out_bcount(len) uint8_t *data) 22995e111ed8SAndrew Rybchenko { 23005e111ed8SAndrew Rybchenko efx_port_t *epp = &(enp->en_port); 23015e111ed8SAndrew Rybchenko efx_rc_t rc; 23025e111ed8SAndrew Rybchenko uint32_t mcdi_lower_page; 23035e111ed8SAndrew Rybchenko uint32_t mcdi_upper_page; 23045e111ed8SAndrew Rybchenko uint8_t id; 23055e111ed8SAndrew Rybchenko 23065e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 23075e111ed8SAndrew Rybchenko 23085e111ed8SAndrew Rybchenko /* 23095e111ed8SAndrew Rybchenko * Map device address to MC_CMD_GET_PHY_MEDIA_INFO pages. 23105e111ed8SAndrew Rybchenko * Offset plus length interface allows to access page 0 only. 23115e111ed8SAndrew Rybchenko * I.e. non-zero upper pages are not accessible. 23125e111ed8SAndrew Rybchenko * See SFF-8472 section 4 Memory Organization and SFF-8436 section 7.6 23135e111ed8SAndrew Rybchenko * QSFP+ Memory Map for details on how information is structured 23145e111ed8SAndrew Rybchenko * and accessible. 23155e111ed8SAndrew Rybchenko */ 23165e111ed8SAndrew Rybchenko switch (epp->ep_fixed_port_type) { 23175e111ed8SAndrew Rybchenko case EFX_PHY_MEDIA_SFP_PLUS: 23185e111ed8SAndrew Rybchenko case EFX_PHY_MEDIA_QSFP_PLUS: 23195e111ed8SAndrew Rybchenko /* Port type supports modules */ 23205e111ed8SAndrew Rybchenko break; 23215e111ed8SAndrew Rybchenko default: 23225e111ed8SAndrew Rybchenko rc = ENOTSUP; 23235e111ed8SAndrew Rybchenko goto fail1; 23245e111ed8SAndrew Rybchenko } 23255e111ed8SAndrew Rybchenko 23265e111ed8SAndrew Rybchenko /* 23275e111ed8SAndrew Rybchenko * For all supported port types, MCDI page 0 offset 0 holds the 23285e111ed8SAndrew Rybchenko * transceiver identifier. Probe to determine the data layout. 23295e111ed8SAndrew Rybchenko * Definitions from SFF-8024 Table 4-1. 23305e111ed8SAndrew Rybchenko */ 23315e111ed8SAndrew Rybchenko rc = efx_mcdi_get_phy_media_info(enp, 23325e111ed8SAndrew Rybchenko 0, 0, sizeof(id), &id); 23335e111ed8SAndrew Rybchenko if (rc != 0) 23345e111ed8SAndrew Rybchenko goto fail2; 23355e111ed8SAndrew Rybchenko 23365e111ed8SAndrew Rybchenko switch (id) { 23375e111ed8SAndrew Rybchenko case EFX_SFF_TRANSCEIVER_ID_SFP: 23385e111ed8SAndrew Rybchenko /* 23395e111ed8SAndrew Rybchenko * In accordance with SFF-8472 Diagnostic Monitoring 23405e111ed8SAndrew Rybchenko * Interface for Optical Transceivers section 4 Memory 23415e111ed8SAndrew Rybchenko * Organization two 2-wire addresses are defined. 23425e111ed8SAndrew Rybchenko */ 23435e111ed8SAndrew Rybchenko switch (dev_addr) { 23445e111ed8SAndrew Rybchenko /* Base information */ 23455e111ed8SAndrew Rybchenko case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE: 23465e111ed8SAndrew Rybchenko /* 23475e111ed8SAndrew Rybchenko * MCDI page 0 should be used to access lower 23485e111ed8SAndrew Rybchenko * page 0 (0x00 - 0x7f) at the device address 0xA0. 23495e111ed8SAndrew Rybchenko */ 23505e111ed8SAndrew Rybchenko mcdi_lower_page = 0; 23515e111ed8SAndrew Rybchenko /* 23525e111ed8SAndrew Rybchenko * MCDI page 1 should be used to access upper 23535e111ed8SAndrew Rybchenko * page 0 (0x80 - 0xff) at the device address 0xA0. 23545e111ed8SAndrew Rybchenko */ 23555e111ed8SAndrew Rybchenko mcdi_upper_page = 1; 23565e111ed8SAndrew Rybchenko break; 23575e111ed8SAndrew Rybchenko /* Diagnostics */ 23585e111ed8SAndrew Rybchenko case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM: 23595e111ed8SAndrew Rybchenko /* 23605e111ed8SAndrew Rybchenko * MCDI page 2 should be used to access lower 23615e111ed8SAndrew Rybchenko * page 0 (0x00 - 0x7f) at the device address 0xA2. 23625e111ed8SAndrew Rybchenko */ 23635e111ed8SAndrew Rybchenko mcdi_lower_page = 2; 23645e111ed8SAndrew Rybchenko /* 23655e111ed8SAndrew Rybchenko * MCDI page 3 should be used to access upper 23665e111ed8SAndrew Rybchenko * page 0 (0x80 - 0xff) at the device address 0xA2. 23675e111ed8SAndrew Rybchenko */ 23685e111ed8SAndrew Rybchenko mcdi_upper_page = 3; 23695e111ed8SAndrew Rybchenko break; 23705e111ed8SAndrew Rybchenko default: 23715e111ed8SAndrew Rybchenko rc = ENOTSUP; 23725e111ed8SAndrew Rybchenko goto fail3; 23735e111ed8SAndrew Rybchenko } 23745e111ed8SAndrew Rybchenko break; 23755e111ed8SAndrew Rybchenko case EFX_SFF_TRANSCEIVER_ID_QSFP: 23765e111ed8SAndrew Rybchenko case EFX_SFF_TRANSCEIVER_ID_QSFP_PLUS: 23775e111ed8SAndrew Rybchenko case EFX_SFF_TRANSCEIVER_ID_QSFP28: 23785e111ed8SAndrew Rybchenko switch (dev_addr) { 23795e111ed8SAndrew Rybchenko case EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP: 23805e111ed8SAndrew Rybchenko /* 23815e111ed8SAndrew Rybchenko * MCDI page -1 should be used to access lower page 0 23825e111ed8SAndrew Rybchenko * (0x00 - 0x7f). 23835e111ed8SAndrew Rybchenko */ 23845e111ed8SAndrew Rybchenko mcdi_lower_page = (uint32_t)-1; 23855e111ed8SAndrew Rybchenko /* 23865e111ed8SAndrew Rybchenko * MCDI page 0 should be used to access upper page 0 23875e111ed8SAndrew Rybchenko * (0x80h - 0xff). 23885e111ed8SAndrew Rybchenko */ 23895e111ed8SAndrew Rybchenko mcdi_upper_page = 0; 23905e111ed8SAndrew Rybchenko break; 23915e111ed8SAndrew Rybchenko default: 23925e111ed8SAndrew Rybchenko rc = ENOTSUP; 23935e111ed8SAndrew Rybchenko goto fail3; 23945e111ed8SAndrew Rybchenko } 23955e111ed8SAndrew Rybchenko break; 23965e111ed8SAndrew Rybchenko default: 23975e111ed8SAndrew Rybchenko rc = ENOTSUP; 23985e111ed8SAndrew Rybchenko goto fail3; 23995e111ed8SAndrew Rybchenko } 24005e111ed8SAndrew Rybchenko 24015e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(EFX_PHY_MEDIA_INFO_PAGE_SIZE <= 0xFF); 24025e111ed8SAndrew Rybchenko 24035e111ed8SAndrew Rybchenko if (offset < EFX_PHY_MEDIA_INFO_PAGE_SIZE) { 24045e111ed8SAndrew Rybchenko size_t read_len = 24055e111ed8SAndrew Rybchenko MIN(len, EFX_PHY_MEDIA_INFO_PAGE_SIZE - offset); 24065e111ed8SAndrew Rybchenko 24075e111ed8SAndrew Rybchenko rc = efx_mcdi_get_phy_media_info(enp, 24085e111ed8SAndrew Rybchenko mcdi_lower_page, (uint8_t)offset, (uint8_t)read_len, data); 24095e111ed8SAndrew Rybchenko if (rc != 0) 24105e111ed8SAndrew Rybchenko goto fail4; 24115e111ed8SAndrew Rybchenko 24125e111ed8SAndrew Rybchenko data += read_len; 24135e111ed8SAndrew Rybchenko len -= read_len; 24145e111ed8SAndrew Rybchenko 24155e111ed8SAndrew Rybchenko offset = 0; 24165e111ed8SAndrew Rybchenko } else { 24175e111ed8SAndrew Rybchenko offset -= EFX_PHY_MEDIA_INFO_PAGE_SIZE; 24185e111ed8SAndrew Rybchenko } 24195e111ed8SAndrew Rybchenko 24205e111ed8SAndrew Rybchenko if (len > 0) { 24215e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(len, <=, EFX_PHY_MEDIA_INFO_PAGE_SIZE); 24225e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(offset, <, EFX_PHY_MEDIA_INFO_PAGE_SIZE); 24235e111ed8SAndrew Rybchenko 24245e111ed8SAndrew Rybchenko rc = efx_mcdi_get_phy_media_info(enp, 24255e111ed8SAndrew Rybchenko mcdi_upper_page, (uint8_t)offset, (uint8_t)len, data); 24265e111ed8SAndrew Rybchenko if (rc != 0) 24275e111ed8SAndrew Rybchenko goto fail5; 24285e111ed8SAndrew Rybchenko } 24295e111ed8SAndrew Rybchenko 24305e111ed8SAndrew Rybchenko return (0); 24315e111ed8SAndrew Rybchenko 24325e111ed8SAndrew Rybchenko fail5: 24335e111ed8SAndrew Rybchenko EFSYS_PROBE(fail5); 24345e111ed8SAndrew Rybchenko fail4: 24355e111ed8SAndrew Rybchenko EFSYS_PROBE(fail4); 24365e111ed8SAndrew Rybchenko fail3: 24375e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3); 24385e111ed8SAndrew Rybchenko fail2: 24395e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2); 24405e111ed8SAndrew Rybchenko fail1: 24415e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 24425e111ed8SAndrew Rybchenko 24435e111ed8SAndrew Rybchenko return (rc); 24445e111ed8SAndrew Rybchenko } 24455e111ed8SAndrew Rybchenko 2446b97bf1caSAndrew Rybchenko #if EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10() 2447b97bf1caSAndrew Rybchenko 2448b97bf1caSAndrew Rybchenko #define INIT_EVQ_MAXNBUFS MC_CMD_INIT_EVQ_V2_IN_DMA_ADDR_MAXNUM 2449b97bf1caSAndrew Rybchenko 245085270581SAndrew Rybchenko #if EFX_OPTS_EF10() 2451b97bf1caSAndrew Rybchenko # if (INIT_EVQ_MAXNBUFS < EF10_EVQ_MAXNBUFS) 2452b97bf1caSAndrew Rybchenko # error "INIT_EVQ_MAXNBUFS too small" 2453b97bf1caSAndrew Rybchenko # endif 2454b97bf1caSAndrew Rybchenko #endif /* EFX_OPTS_EF10 */ 2455b97bf1caSAndrew Rybchenko #if EFSYS_OPT_RIVERHEAD 2456b97bf1caSAndrew Rybchenko # if (INIT_EVQ_MAXNBUFS < RHEAD_EVQ_MAXNBUFS) 2457b97bf1caSAndrew Rybchenko # error "INIT_EVQ_MAXNBUFS too small" 2458b97bf1caSAndrew Rybchenko # endif 2459b97bf1caSAndrew Rybchenko #endif /* EFSYS_OPT_RIVERHEAD */ 246085270581SAndrew Rybchenko 246185270581SAndrew Rybchenko __checkReturn efx_rc_t 246285270581SAndrew Rybchenko efx_mcdi_init_evq( 246385270581SAndrew Rybchenko __in efx_nic_t *enp, 246485270581SAndrew Rybchenko __in unsigned int instance, 246585270581SAndrew Rybchenko __in efsys_mem_t *esmp, 246685270581SAndrew Rybchenko __in size_t nevs, 246785270581SAndrew Rybchenko __in uint32_t irq, 246885270581SAndrew Rybchenko __in uint32_t us, 246985270581SAndrew Rybchenko __in uint32_t flags, 247085270581SAndrew Rybchenko __in boolean_t low_latency) 247185270581SAndrew Rybchenko { 24728aad1149SAndrew Rybchenko const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 247385270581SAndrew Rybchenko efx_mcdi_req_t req; 247485270581SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, 2475b97bf1caSAndrew Rybchenko MC_CMD_INIT_EVQ_V2_IN_LEN(INIT_EVQ_MAXNBUFS), 247613a300a5SAndrew Rybchenko MC_CMD_INIT_EVQ_V2_OUT_LEN); 247785270581SAndrew Rybchenko boolean_t interrupting; 247885270581SAndrew Rybchenko int ev_cut_through; 24798aad1149SAndrew Rybchenko int ev_merge; 248085270581SAndrew Rybchenko unsigned int evq_type; 248185270581SAndrew Rybchenko efx_qword_t *dma_addr; 248285270581SAndrew Rybchenko uint64_t addr; 248385270581SAndrew Rybchenko int npages; 248485270581SAndrew Rybchenko int i; 248585270581SAndrew Rybchenko efx_rc_t rc; 248685270581SAndrew Rybchenko 248785270581SAndrew Rybchenko npages = efx_evq_nbufs(enp, nevs); 2488b97bf1caSAndrew Rybchenko if (npages > INIT_EVQ_MAXNBUFS) { 248985270581SAndrew Rybchenko rc = EINVAL; 249085270581SAndrew Rybchenko goto fail1; 249185270581SAndrew Rybchenko } 249285270581SAndrew Rybchenko 249385270581SAndrew Rybchenko req.emr_cmd = MC_CMD_INIT_EVQ; 249485270581SAndrew Rybchenko req.emr_in_buf = payload; 249585270581SAndrew Rybchenko req.emr_in_length = MC_CMD_INIT_EVQ_V2_IN_LEN(npages); 249685270581SAndrew Rybchenko req.emr_out_buf = payload; 249785270581SAndrew Rybchenko req.emr_out_length = MC_CMD_INIT_EVQ_V2_OUT_LEN; 249885270581SAndrew Rybchenko 249985270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_SIZE, nevs); 250085270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_INSTANCE, instance); 250185270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_IRQ_NUM, irq); 250285270581SAndrew Rybchenko 250385270581SAndrew Rybchenko interrupting = ((flags & EFX_EVQ_FLAGS_NOTIFY_MASK) == 250485270581SAndrew Rybchenko EFX_EVQ_FLAGS_NOTIFY_INTERRUPT); 250585270581SAndrew Rybchenko 25068aad1149SAndrew Rybchenko if (encp->enc_init_evq_v2_supported) { 25078aad1149SAndrew Rybchenko /* 25088aad1149SAndrew Rybchenko * On Medford the low latency license is required to enable RX 25098aad1149SAndrew Rybchenko * and event cut through and to disable RX batching. If event 25108aad1149SAndrew Rybchenko * queue type in flags is auto, we let the firmware decide the 25118aad1149SAndrew Rybchenko * settings to use. If the adapter has a low latency license, 25128aad1149SAndrew Rybchenko * it will choose the best settings for low latency, otherwise 25138aad1149SAndrew Rybchenko * it will choose the best settings for throughput. 25148aad1149SAndrew Rybchenko */ 251585270581SAndrew Rybchenko switch (flags & EFX_EVQ_FLAGS_TYPE_MASK) { 251685270581SAndrew Rybchenko case EFX_EVQ_FLAGS_TYPE_AUTO: 251785270581SAndrew Rybchenko evq_type = MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_AUTO; 251885270581SAndrew Rybchenko break; 251985270581SAndrew Rybchenko case EFX_EVQ_FLAGS_TYPE_THROUGHPUT: 252085270581SAndrew Rybchenko evq_type = MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_THROUGHPUT; 252185270581SAndrew Rybchenko break; 252285270581SAndrew Rybchenko case EFX_EVQ_FLAGS_TYPE_LOW_LATENCY: 252385270581SAndrew Rybchenko evq_type = MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_LOW_LATENCY; 252485270581SAndrew Rybchenko break; 252585270581SAndrew Rybchenko default: 252685270581SAndrew Rybchenko rc = EINVAL; 252785270581SAndrew Rybchenko goto fail2; 252885270581SAndrew Rybchenko } 25298aad1149SAndrew Rybchenko /* EvQ type controls merging, no manual settings */ 25308aad1149SAndrew Rybchenko ev_merge = 0; 25318aad1149SAndrew Rybchenko ev_cut_through = 0; 25328aad1149SAndrew Rybchenko } else { 25338aad1149SAndrew Rybchenko /* EvQ types other than manual are not supported */ 25348aad1149SAndrew Rybchenko evq_type = MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_MANUAL; 25358aad1149SAndrew Rybchenko /* 25368aad1149SAndrew Rybchenko * On Huntington RX and TX event batching can only be requested 25378aad1149SAndrew Rybchenko * together (even if the datapath firmware doesn't actually 25388aad1149SAndrew Rybchenko * support RX batching). If event cut through is enabled no RX 25398aad1149SAndrew Rybchenko * batching will occur. 25408aad1149SAndrew Rybchenko * 25418aad1149SAndrew Rybchenko * So always enable RX and TX event batching, and enable event 25428aad1149SAndrew Rybchenko * cut through if we want low latency operation. 25438aad1149SAndrew Rybchenko */ 25448aad1149SAndrew Rybchenko ev_merge = 1; 25458aad1149SAndrew Rybchenko switch (flags & EFX_EVQ_FLAGS_TYPE_MASK) { 25468aad1149SAndrew Rybchenko case EFX_EVQ_FLAGS_TYPE_AUTO: 25478aad1149SAndrew Rybchenko ev_cut_through = low_latency ? 1 : 0; 25488aad1149SAndrew Rybchenko break; 25498aad1149SAndrew Rybchenko case EFX_EVQ_FLAGS_TYPE_THROUGHPUT: 25508aad1149SAndrew Rybchenko ev_cut_through = 0; 25518aad1149SAndrew Rybchenko break; 25528aad1149SAndrew Rybchenko case EFX_EVQ_FLAGS_TYPE_LOW_LATENCY: 25538aad1149SAndrew Rybchenko ev_cut_through = 1; 25548aad1149SAndrew Rybchenko break; 25558aad1149SAndrew Rybchenko default: 25568aad1149SAndrew Rybchenko rc = EINVAL; 25578aad1149SAndrew Rybchenko goto fail2; 25588aad1149SAndrew Rybchenko } 25598aad1149SAndrew Rybchenko } 25608aad1149SAndrew Rybchenko 25618aad1149SAndrew Rybchenko MCDI_IN_POPULATE_DWORD_7(req, INIT_EVQ_V2_IN_FLAGS, 256285270581SAndrew Rybchenko INIT_EVQ_V2_IN_FLAG_INTERRUPTING, interrupting, 256385270581SAndrew Rybchenko INIT_EVQ_V2_IN_FLAG_RPTR_DOS, 0, 256485270581SAndrew Rybchenko INIT_EVQ_V2_IN_FLAG_INT_ARMD, 0, 25658aad1149SAndrew Rybchenko INIT_EVQ_V2_IN_FLAG_CUT_THRU, ev_cut_through, 25668aad1149SAndrew Rybchenko INIT_EVQ_V2_IN_FLAG_RX_MERGE, ev_merge, 25678aad1149SAndrew Rybchenko INIT_EVQ_V2_IN_FLAG_TX_MERGE, ev_merge, 256885270581SAndrew Rybchenko INIT_EVQ_V2_IN_FLAG_TYPE, evq_type); 256985270581SAndrew Rybchenko 257085270581SAndrew Rybchenko /* If the value is zero then disable the timer */ 257185270581SAndrew Rybchenko if (us == 0) { 257285270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_MODE, 257385270581SAndrew Rybchenko MC_CMD_INIT_EVQ_V2_IN_TMR_MODE_DIS); 257485270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_LOAD, 0); 257585270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_RELOAD, 0); 257685270581SAndrew Rybchenko } else { 257785270581SAndrew Rybchenko unsigned int ticks; 257885270581SAndrew Rybchenko 257985270581SAndrew Rybchenko if ((rc = efx_ev_usecs_to_ticks(enp, us, &ticks)) != 0) 258085270581SAndrew Rybchenko goto fail3; 258185270581SAndrew Rybchenko 258285270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_MODE, 258385270581SAndrew Rybchenko MC_CMD_INIT_EVQ_V2_IN_TMR_INT_HLDOFF); 258485270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_LOAD, ticks); 258585270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_RELOAD, ticks); 258685270581SAndrew Rybchenko } 258785270581SAndrew Rybchenko 258885270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_COUNT_MODE, 258985270581SAndrew Rybchenko MC_CMD_INIT_EVQ_V2_IN_COUNT_MODE_DIS); 259085270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_COUNT_THRSHLD, 0); 259185270581SAndrew Rybchenko 259285270581SAndrew Rybchenko dma_addr = MCDI_IN2(req, efx_qword_t, INIT_EVQ_V2_IN_DMA_ADDR); 259385270581SAndrew Rybchenko addr = EFSYS_MEM_ADDR(esmp); 259485270581SAndrew Rybchenko 259585270581SAndrew Rybchenko for (i = 0; i < npages; i++) { 259685270581SAndrew Rybchenko EFX_POPULATE_QWORD_2(*dma_addr, 259785270581SAndrew Rybchenko EFX_DWORD_1, (uint32_t)(addr >> 32), 259885270581SAndrew Rybchenko EFX_DWORD_0, (uint32_t)(addr & 0xffffffff)); 259985270581SAndrew Rybchenko 260085270581SAndrew Rybchenko dma_addr++; 260185270581SAndrew Rybchenko addr += EFX_BUF_SIZE; 260285270581SAndrew Rybchenko } 260385270581SAndrew Rybchenko 260485270581SAndrew Rybchenko efx_mcdi_execute(enp, &req); 260585270581SAndrew Rybchenko 260685270581SAndrew Rybchenko if (req.emr_rc != 0) { 260785270581SAndrew Rybchenko rc = req.emr_rc; 260885270581SAndrew Rybchenko goto fail4; 260985270581SAndrew Rybchenko } 261085270581SAndrew Rybchenko 26118aad1149SAndrew Rybchenko if (encp->enc_init_evq_v2_supported) { 261285270581SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_INIT_EVQ_V2_OUT_LEN) { 261385270581SAndrew Rybchenko rc = EMSGSIZE; 261485270581SAndrew Rybchenko goto fail5; 261585270581SAndrew Rybchenko } 26168aad1149SAndrew Rybchenko EFSYS_PROBE1(mcdi_evq_flags, uint32_t, 26178aad1149SAndrew Rybchenko MCDI_OUT_DWORD(req, INIT_EVQ_V2_OUT_FLAGS)); 26188aad1149SAndrew Rybchenko } else { 26198aad1149SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_INIT_EVQ_OUT_LEN) { 26208aad1149SAndrew Rybchenko rc = EMSGSIZE; 26218aad1149SAndrew Rybchenko goto fail6; 26228aad1149SAndrew Rybchenko } 26238aad1149SAndrew Rybchenko } 262485270581SAndrew Rybchenko 262585270581SAndrew Rybchenko /* NOTE: ignore the returned IRQ param as firmware does not set it. */ 262685270581SAndrew Rybchenko 262785270581SAndrew Rybchenko return (0); 262885270581SAndrew Rybchenko 26298aad1149SAndrew Rybchenko fail6: 26308aad1149SAndrew Rybchenko EFSYS_PROBE(fail6); 263185270581SAndrew Rybchenko fail5: 263285270581SAndrew Rybchenko EFSYS_PROBE(fail5); 263385270581SAndrew Rybchenko fail4: 263485270581SAndrew Rybchenko EFSYS_PROBE(fail4); 263585270581SAndrew Rybchenko fail3: 263685270581SAndrew Rybchenko EFSYS_PROBE(fail3); 263785270581SAndrew Rybchenko fail2: 263885270581SAndrew Rybchenko EFSYS_PROBE(fail2); 263985270581SAndrew Rybchenko fail1: 264085270581SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 264185270581SAndrew Rybchenko 264285270581SAndrew Rybchenko return (rc); 264385270581SAndrew Rybchenko } 264485270581SAndrew Rybchenko 264585270581SAndrew Rybchenko __checkReturn efx_rc_t 264685270581SAndrew Rybchenko efx_mcdi_fini_evq( 264785270581SAndrew Rybchenko __in efx_nic_t *enp, 264885270581SAndrew Rybchenko __in uint32_t instance) 264985270581SAndrew Rybchenko { 265085270581SAndrew Rybchenko efx_mcdi_req_t req; 265185270581SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FINI_EVQ_IN_LEN, 265285270581SAndrew Rybchenko MC_CMD_FINI_EVQ_OUT_LEN); 265385270581SAndrew Rybchenko efx_rc_t rc; 265485270581SAndrew Rybchenko 265585270581SAndrew Rybchenko req.emr_cmd = MC_CMD_FINI_EVQ; 265685270581SAndrew Rybchenko req.emr_in_buf = payload; 265785270581SAndrew Rybchenko req.emr_in_length = MC_CMD_FINI_EVQ_IN_LEN; 265885270581SAndrew Rybchenko req.emr_out_buf = payload; 265985270581SAndrew Rybchenko req.emr_out_length = MC_CMD_FINI_EVQ_OUT_LEN; 266085270581SAndrew Rybchenko 266185270581SAndrew Rybchenko MCDI_IN_SET_DWORD(req, FINI_EVQ_IN_INSTANCE, instance); 266285270581SAndrew Rybchenko 266385270581SAndrew Rybchenko efx_mcdi_execute_quiet(enp, &req); 266485270581SAndrew Rybchenko 266585270581SAndrew Rybchenko if (req.emr_rc != 0) { 266685270581SAndrew Rybchenko rc = req.emr_rc; 266785270581SAndrew Rybchenko goto fail1; 266885270581SAndrew Rybchenko } 266985270581SAndrew Rybchenko 267085270581SAndrew Rybchenko return (0); 267185270581SAndrew Rybchenko 267285270581SAndrew Rybchenko fail1: 267385270581SAndrew Rybchenko /* 267485270581SAndrew Rybchenko * EALREADY is not an error, but indicates that the MC has rebooted and 267585270581SAndrew Rybchenko * that the EVQ has already been destroyed. 267685270581SAndrew Rybchenko */ 267785270581SAndrew Rybchenko if (rc != EALREADY) 267885270581SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 267985270581SAndrew Rybchenko 268085270581SAndrew Rybchenko return (rc); 268185270581SAndrew Rybchenko } 268285270581SAndrew Rybchenko 2683b97bf1caSAndrew Rybchenko #endif /* EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10() */ 268485270581SAndrew Rybchenko 2685*09b59c7dSAndrew Rybchenko #if EFX_OPTS_EF10() 2686*09b59c7dSAndrew Rybchenko 2687*09b59c7dSAndrew Rybchenko __checkReturn efx_rc_t 2688*09b59c7dSAndrew Rybchenko efx_mcdi_init_rxq( 2689*09b59c7dSAndrew Rybchenko __in efx_nic_t *enp, 2690*09b59c7dSAndrew Rybchenko __in uint32_t ndescs, 2691*09b59c7dSAndrew Rybchenko __in efx_evq_t *eep, 2692*09b59c7dSAndrew Rybchenko __in uint32_t label, 2693*09b59c7dSAndrew Rybchenko __in uint32_t instance, 2694*09b59c7dSAndrew Rybchenko __in efsys_mem_t *esmp, 2695*09b59c7dSAndrew Rybchenko __in boolean_t disable_scatter, 2696*09b59c7dSAndrew Rybchenko __in boolean_t want_inner_classes, 2697*09b59c7dSAndrew Rybchenko __in uint32_t buf_size, 2698*09b59c7dSAndrew Rybchenko __in uint32_t ps_bufsize, 2699*09b59c7dSAndrew Rybchenko __in uint32_t es_bufs_per_desc, 2700*09b59c7dSAndrew Rybchenko __in uint32_t es_max_dma_len, 2701*09b59c7dSAndrew Rybchenko __in uint32_t es_buf_stride, 2702*09b59c7dSAndrew Rybchenko __in uint32_t hol_block_timeout) 2703*09b59c7dSAndrew Rybchenko { 2704*09b59c7dSAndrew Rybchenko efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 2705*09b59c7dSAndrew Rybchenko efx_mcdi_req_t req; 2706*09b59c7dSAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_INIT_RXQ_V4_IN_LEN, 2707*09b59c7dSAndrew Rybchenko MC_CMD_INIT_RXQ_V4_OUT_LEN); 2708*09b59c7dSAndrew Rybchenko int npages = efx_rxq_nbufs(enp, ndescs); 2709*09b59c7dSAndrew Rybchenko int i; 2710*09b59c7dSAndrew Rybchenko efx_qword_t *dma_addr; 2711*09b59c7dSAndrew Rybchenko uint64_t addr; 2712*09b59c7dSAndrew Rybchenko efx_rc_t rc; 2713*09b59c7dSAndrew Rybchenko uint32_t dma_mode; 2714*09b59c7dSAndrew Rybchenko boolean_t want_outer_classes; 2715*09b59c7dSAndrew Rybchenko boolean_t no_cont_ev; 2716*09b59c7dSAndrew Rybchenko 2717*09b59c7dSAndrew Rybchenko EFSYS_ASSERT3U(ndescs, <=, encp->enc_rxq_max_ndescs); 2718*09b59c7dSAndrew Rybchenko 2719*09b59c7dSAndrew Rybchenko if ((esmp == NULL) || 2720*09b59c7dSAndrew Rybchenko (EFSYS_MEM_SIZE(esmp) < efx_rxq_size(enp, ndescs))) { 2721*09b59c7dSAndrew Rybchenko rc = EINVAL; 2722*09b59c7dSAndrew Rybchenko goto fail1; 2723*09b59c7dSAndrew Rybchenko } 2724*09b59c7dSAndrew Rybchenko 2725*09b59c7dSAndrew Rybchenko no_cont_ev = (eep->ee_flags & EFX_EVQ_FLAGS_NO_CONT_EV); 2726*09b59c7dSAndrew Rybchenko if ((no_cont_ev == B_TRUE) && (disable_scatter == B_FALSE)) { 2727*09b59c7dSAndrew Rybchenko /* TODO: Support scatter in NO_CONT_EV mode */ 2728*09b59c7dSAndrew Rybchenko rc = EINVAL; 2729*09b59c7dSAndrew Rybchenko goto fail2; 2730*09b59c7dSAndrew Rybchenko } 2731*09b59c7dSAndrew Rybchenko 2732*09b59c7dSAndrew Rybchenko if (ps_bufsize > 0) 2733*09b59c7dSAndrew Rybchenko dma_mode = MC_CMD_INIT_RXQ_EXT_IN_PACKED_STREAM; 2734*09b59c7dSAndrew Rybchenko else if (es_bufs_per_desc > 0) 2735*09b59c7dSAndrew Rybchenko dma_mode = MC_CMD_INIT_RXQ_V3_IN_EQUAL_STRIDE_SUPER_BUFFER; 2736*09b59c7dSAndrew Rybchenko else 2737*09b59c7dSAndrew Rybchenko dma_mode = MC_CMD_INIT_RXQ_EXT_IN_SINGLE_PACKET; 2738*09b59c7dSAndrew Rybchenko 2739*09b59c7dSAndrew Rybchenko if (encp->enc_tunnel_encapsulations_supported != 0 && 2740*09b59c7dSAndrew Rybchenko !want_inner_classes) { 2741*09b59c7dSAndrew Rybchenko /* 2742*09b59c7dSAndrew Rybchenko * WANT_OUTER_CLASSES can only be specified on hardware which 2743*09b59c7dSAndrew Rybchenko * supports tunnel encapsulation offloads, even though it is 2744*09b59c7dSAndrew Rybchenko * effectively the behaviour the hardware gives. 2745*09b59c7dSAndrew Rybchenko * 2746*09b59c7dSAndrew Rybchenko * Also, on hardware which does support such offloads, older 2747*09b59c7dSAndrew Rybchenko * firmware rejects the flag if the offloads are not supported 2748*09b59c7dSAndrew Rybchenko * by the current firmware variant, which means this may fail if 2749*09b59c7dSAndrew Rybchenko * the capabilities are not updated when the firmware variant 2750*09b59c7dSAndrew Rybchenko * changes. This is not an issue on newer firmware, as it was 2751*09b59c7dSAndrew Rybchenko * changed in bug 69842 (v6.4.2.1007) to permit this flag to be 2752*09b59c7dSAndrew Rybchenko * specified on all firmware variants. 2753*09b59c7dSAndrew Rybchenko */ 2754*09b59c7dSAndrew Rybchenko want_outer_classes = B_TRUE; 2755*09b59c7dSAndrew Rybchenko } else { 2756*09b59c7dSAndrew Rybchenko want_outer_classes = B_FALSE; 2757*09b59c7dSAndrew Rybchenko } 2758*09b59c7dSAndrew Rybchenko 2759*09b59c7dSAndrew Rybchenko req.emr_cmd = MC_CMD_INIT_RXQ; 2760*09b59c7dSAndrew Rybchenko req.emr_in_buf = payload; 2761*09b59c7dSAndrew Rybchenko req.emr_in_length = MC_CMD_INIT_RXQ_V4_IN_LEN; 2762*09b59c7dSAndrew Rybchenko req.emr_out_buf = payload; 2763*09b59c7dSAndrew Rybchenko req.emr_out_length = MC_CMD_INIT_RXQ_V4_OUT_LEN; 2764*09b59c7dSAndrew Rybchenko 2765*09b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_SIZE, ndescs); 2766*09b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_TARGET_EVQ, eep->ee_index); 2767*09b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_LABEL, label); 2768*09b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_INSTANCE, instance); 2769*09b59c7dSAndrew Rybchenko MCDI_IN_POPULATE_DWORD_10(req, INIT_RXQ_EXT_IN_FLAGS, 2770*09b59c7dSAndrew Rybchenko INIT_RXQ_EXT_IN_FLAG_BUFF_MODE, 0, 2771*09b59c7dSAndrew Rybchenko INIT_RXQ_EXT_IN_FLAG_HDR_SPLIT, 0, 2772*09b59c7dSAndrew Rybchenko INIT_RXQ_EXT_IN_FLAG_TIMESTAMP, 0, 2773*09b59c7dSAndrew Rybchenko INIT_RXQ_EXT_IN_CRC_MODE, 0, 2774*09b59c7dSAndrew Rybchenko INIT_RXQ_EXT_IN_FLAG_PREFIX, 1, 2775*09b59c7dSAndrew Rybchenko INIT_RXQ_EXT_IN_FLAG_DISABLE_SCATTER, disable_scatter, 2776*09b59c7dSAndrew Rybchenko INIT_RXQ_EXT_IN_DMA_MODE, 2777*09b59c7dSAndrew Rybchenko dma_mode, 2778*09b59c7dSAndrew Rybchenko INIT_RXQ_EXT_IN_PACKED_STREAM_BUFF_SIZE, ps_bufsize, 2779*09b59c7dSAndrew Rybchenko INIT_RXQ_EXT_IN_FLAG_WANT_OUTER_CLASSES, want_outer_classes, 2780*09b59c7dSAndrew Rybchenko INIT_RXQ_EXT_IN_FLAG_NO_CONT_EV, no_cont_ev); 2781*09b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_OWNER_ID, 0); 2782*09b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_PORT_ID, enp->en_vport_id); 2783*09b59c7dSAndrew Rybchenko 2784*09b59c7dSAndrew Rybchenko if (es_bufs_per_desc > 0) { 2785*09b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req, 2786*09b59c7dSAndrew Rybchenko INIT_RXQ_V3_IN_ES_PACKET_BUFFERS_PER_BUCKET, 2787*09b59c7dSAndrew Rybchenko es_bufs_per_desc); 2788*09b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req, 2789*09b59c7dSAndrew Rybchenko INIT_RXQ_V3_IN_ES_MAX_DMA_LEN, es_max_dma_len); 2790*09b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req, 2791*09b59c7dSAndrew Rybchenko INIT_RXQ_V3_IN_ES_PACKET_STRIDE, es_buf_stride); 2792*09b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req, 2793*09b59c7dSAndrew Rybchenko INIT_RXQ_V3_IN_ES_HEAD_OF_LINE_BLOCK_TIMEOUT, 2794*09b59c7dSAndrew Rybchenko hol_block_timeout); 2795*09b59c7dSAndrew Rybchenko } 2796*09b59c7dSAndrew Rybchenko 2797*09b59c7dSAndrew Rybchenko if (encp->enc_init_rxq_with_buffer_size) 2798*09b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req, INIT_RXQ_V4_IN_BUFFER_SIZE_BYTES, 2799*09b59c7dSAndrew Rybchenko buf_size); 2800*09b59c7dSAndrew Rybchenko 2801*09b59c7dSAndrew Rybchenko dma_addr = MCDI_IN2(req, efx_qword_t, INIT_RXQ_IN_DMA_ADDR); 2802*09b59c7dSAndrew Rybchenko addr = EFSYS_MEM_ADDR(esmp); 2803*09b59c7dSAndrew Rybchenko 2804*09b59c7dSAndrew Rybchenko for (i = 0; i < npages; i++) { 2805*09b59c7dSAndrew Rybchenko EFX_POPULATE_QWORD_2(*dma_addr, 2806*09b59c7dSAndrew Rybchenko EFX_DWORD_1, (uint32_t)(addr >> 32), 2807*09b59c7dSAndrew Rybchenko EFX_DWORD_0, (uint32_t)(addr & 0xffffffff)); 2808*09b59c7dSAndrew Rybchenko 2809*09b59c7dSAndrew Rybchenko dma_addr++; 2810*09b59c7dSAndrew Rybchenko addr += EFX_BUF_SIZE; 2811*09b59c7dSAndrew Rybchenko } 2812*09b59c7dSAndrew Rybchenko 2813*09b59c7dSAndrew Rybchenko efx_mcdi_execute(enp, &req); 2814*09b59c7dSAndrew Rybchenko 2815*09b59c7dSAndrew Rybchenko if (req.emr_rc != 0) { 2816*09b59c7dSAndrew Rybchenko rc = req.emr_rc; 2817*09b59c7dSAndrew Rybchenko goto fail3; 2818*09b59c7dSAndrew Rybchenko } 2819*09b59c7dSAndrew Rybchenko 2820*09b59c7dSAndrew Rybchenko return (0); 2821*09b59c7dSAndrew Rybchenko 2822*09b59c7dSAndrew Rybchenko fail3: 2823*09b59c7dSAndrew Rybchenko EFSYS_PROBE(fail3); 2824*09b59c7dSAndrew Rybchenko fail2: 2825*09b59c7dSAndrew Rybchenko EFSYS_PROBE(fail2); 2826*09b59c7dSAndrew Rybchenko fail1: 2827*09b59c7dSAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 2828*09b59c7dSAndrew Rybchenko 2829*09b59c7dSAndrew Rybchenko return (rc); 2830*09b59c7dSAndrew Rybchenko } 2831*09b59c7dSAndrew Rybchenko 2832*09b59c7dSAndrew Rybchenko __checkReturn efx_rc_t 2833*09b59c7dSAndrew Rybchenko efx_mcdi_fini_rxq( 2834*09b59c7dSAndrew Rybchenko __in efx_nic_t *enp, 2835*09b59c7dSAndrew Rybchenko __in uint32_t instance) 2836*09b59c7dSAndrew Rybchenko { 2837*09b59c7dSAndrew Rybchenko efx_mcdi_req_t req; 2838*09b59c7dSAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FINI_RXQ_IN_LEN, 2839*09b59c7dSAndrew Rybchenko MC_CMD_FINI_RXQ_OUT_LEN); 2840*09b59c7dSAndrew Rybchenko efx_rc_t rc; 2841*09b59c7dSAndrew Rybchenko 2842*09b59c7dSAndrew Rybchenko req.emr_cmd = MC_CMD_FINI_RXQ; 2843*09b59c7dSAndrew Rybchenko req.emr_in_buf = payload; 2844*09b59c7dSAndrew Rybchenko req.emr_in_length = MC_CMD_FINI_RXQ_IN_LEN; 2845*09b59c7dSAndrew Rybchenko req.emr_out_buf = payload; 2846*09b59c7dSAndrew Rybchenko req.emr_out_length = MC_CMD_FINI_RXQ_OUT_LEN; 2847*09b59c7dSAndrew Rybchenko 2848*09b59c7dSAndrew Rybchenko MCDI_IN_SET_DWORD(req, FINI_RXQ_IN_INSTANCE, instance); 2849*09b59c7dSAndrew Rybchenko 2850*09b59c7dSAndrew Rybchenko efx_mcdi_execute_quiet(enp, &req); 2851*09b59c7dSAndrew Rybchenko 2852*09b59c7dSAndrew Rybchenko if (req.emr_rc != 0) { 2853*09b59c7dSAndrew Rybchenko rc = req.emr_rc; 2854*09b59c7dSAndrew Rybchenko goto fail1; 2855*09b59c7dSAndrew Rybchenko } 2856*09b59c7dSAndrew Rybchenko 2857*09b59c7dSAndrew Rybchenko return (0); 2858*09b59c7dSAndrew Rybchenko 2859*09b59c7dSAndrew Rybchenko fail1: 2860*09b59c7dSAndrew Rybchenko /* 2861*09b59c7dSAndrew Rybchenko * EALREADY is not an error, but indicates that the MC has rebooted and 2862*09b59c7dSAndrew Rybchenko * that the RXQ has already been destroyed. 2863*09b59c7dSAndrew Rybchenko */ 2864*09b59c7dSAndrew Rybchenko if (rc != EALREADY) 2865*09b59c7dSAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 2866*09b59c7dSAndrew Rybchenko 2867*09b59c7dSAndrew Rybchenko return (rc); 2868*09b59c7dSAndrew Rybchenko } 2869*09b59c7dSAndrew Rybchenko 2870*09b59c7dSAndrew Rybchenko #endif /* EFX_OPTS_EF10() */ 2871*09b59c7dSAndrew Rybchenko 28725e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MCDI */ 2873