15e111ed8SAndrew Rybchenko /* SPDX-License-Identifier: BSD-3-Clause
25e111ed8SAndrew Rybchenko *
3*672386c1SAndrew Rybchenko * Copyright(c) 2019-2021 Xilinx, Inc.
45e111ed8SAndrew Rybchenko * Copyright(c) 2012-2019 Solarflare Communications Inc.
55e111ed8SAndrew Rybchenko */
65e111ed8SAndrew Rybchenko
75e111ed8SAndrew Rybchenko #include "efx.h"
85e111ed8SAndrew Rybchenko #include "efx_impl.h"
95e111ed8SAndrew Rybchenko
105e111ed8SAndrew Rybchenko
119b5b182dSAndrew Rybchenko #if EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10()
125e111ed8SAndrew Rybchenko
135e111ed8SAndrew Rybchenko #if EFSYS_OPT_MCDI
145e111ed8SAndrew Rybchenko
155e111ed8SAndrew Rybchenko #ifndef WITH_MCDI_V2
165e111ed8SAndrew Rybchenko #error "WITH_MCDI_V2 required for EF10 MCDIv2 commands."
175e111ed8SAndrew Rybchenko #endif
185e111ed8SAndrew Rybchenko
195e111ed8SAndrew Rybchenko
205e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
ef10_mcdi_init(__in efx_nic_t * enp,__in const efx_mcdi_transport_t * emtp)215e111ed8SAndrew Rybchenko ef10_mcdi_init(
225e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
235e111ed8SAndrew Rybchenko __in const efx_mcdi_transport_t *emtp)
245e111ed8SAndrew Rybchenko {
255e111ed8SAndrew Rybchenko efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
265e111ed8SAndrew Rybchenko efsys_mem_t *esmp = emtp->emt_dma_mem;
275e111ed8SAndrew Rybchenko efx_dword_t dword;
285e111ed8SAndrew Rybchenko efx_rc_t rc;
295e111ed8SAndrew Rybchenko
309b5b182dSAndrew Rybchenko EFSYS_ASSERT(EFX_FAMILY_IS_EF100(enp) || EFX_FAMILY_IS_EF10(enp));
315e111ed8SAndrew Rybchenko EFSYS_ASSERT(enp->en_features & EFX_FEATURE_MCDI_DMA);
325e111ed8SAndrew Rybchenko
335e111ed8SAndrew Rybchenko /*
345e111ed8SAndrew Rybchenko * All EF10 firmware supports MCDIv2 and MCDIv1.
355e111ed8SAndrew Rybchenko * Medford BootROM supports MCDIv2 and MCDIv1.
365e111ed8SAndrew Rybchenko * Huntington BootROM supports MCDIv1 only.
375e111ed8SAndrew Rybchenko */
385e111ed8SAndrew Rybchenko emip->emi_max_version = 2;
395e111ed8SAndrew Rybchenko
405e111ed8SAndrew Rybchenko /* A host DMA buffer is required for EF10 MCDI */
415e111ed8SAndrew Rybchenko if (esmp == NULL) {
425e111ed8SAndrew Rybchenko rc = EINVAL;
435e111ed8SAndrew Rybchenko goto fail1;
445e111ed8SAndrew Rybchenko }
455e111ed8SAndrew Rybchenko
465e111ed8SAndrew Rybchenko /*
475e111ed8SAndrew Rybchenko * Ensure that the MC doorbell is in a known state before issuing MCDI
485e111ed8SAndrew Rybchenko * commands. The recovery algorithm requires that the MC command buffer
495e111ed8SAndrew Rybchenko * must be 256 byte aligned. See bug24769.
505e111ed8SAndrew Rybchenko */
515e111ed8SAndrew Rybchenko if ((EFSYS_MEM_ADDR(esmp) & 0xFF) != 0) {
525e111ed8SAndrew Rybchenko rc = EINVAL;
535e111ed8SAndrew Rybchenko goto fail2;
545e111ed8SAndrew Rybchenko }
555e111ed8SAndrew Rybchenko EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 1);
569b5b182dSAndrew Rybchenko switch (enp->en_family) {
579b5b182dSAndrew Rybchenko #if EFSYS_OPT_RIVERHEAD
589b5b182dSAndrew Rybchenko case EFX_FAMILY_RIVERHEAD:
59341bd4e0SIgor Romanov EFX_BAR_FCW_WRITED(enp, ER_GZ_MC_DB_HWRD_REG, &dword);
609b5b182dSAndrew Rybchenko break;
619b5b182dSAndrew Rybchenko #endif /* EFSYS_OPT_RIVERHEAD */
629b5b182dSAndrew Rybchenko default:
635e111ed8SAndrew Rybchenko EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE);
649b5b182dSAndrew Rybchenko break;
659b5b182dSAndrew Rybchenko }
665e111ed8SAndrew Rybchenko
675e111ed8SAndrew Rybchenko /* Save initial MC reboot status */
685e111ed8SAndrew Rybchenko (void) ef10_mcdi_poll_reboot(enp);
695e111ed8SAndrew Rybchenko
705e111ed8SAndrew Rybchenko /* Start a new epoch (allow fresh MCDI requests to succeed) */
715e111ed8SAndrew Rybchenko efx_mcdi_new_epoch(enp);
725e111ed8SAndrew Rybchenko
735e111ed8SAndrew Rybchenko return (0);
745e111ed8SAndrew Rybchenko
755e111ed8SAndrew Rybchenko fail2:
765e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
775e111ed8SAndrew Rybchenko fail1:
785e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
795e111ed8SAndrew Rybchenko
805e111ed8SAndrew Rybchenko return (rc);
815e111ed8SAndrew Rybchenko }
825e111ed8SAndrew Rybchenko
835e111ed8SAndrew Rybchenko void
ef10_mcdi_fini(__in efx_nic_t * enp)845e111ed8SAndrew Rybchenko ef10_mcdi_fini(
855e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
865e111ed8SAndrew Rybchenko {
875e111ed8SAndrew Rybchenko efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
885e111ed8SAndrew Rybchenko
895e111ed8SAndrew Rybchenko emip->emi_new_epoch = B_FALSE;
905e111ed8SAndrew Rybchenko }
915e111ed8SAndrew Rybchenko
925e111ed8SAndrew Rybchenko /*
935e111ed8SAndrew Rybchenko * In older firmware all commands are processed in a single thread, so a long
945e111ed8SAndrew Rybchenko * running command for one PCIe function can block processing for another
955e111ed8SAndrew Rybchenko * function (see bug 61269).
965e111ed8SAndrew Rybchenko *
975e111ed8SAndrew Rybchenko * In newer firmware that supports multithreaded MCDI processing, we can extend
985e111ed8SAndrew Rybchenko * the timeout for long-running requests which we know firmware may choose to
995e111ed8SAndrew Rybchenko * process in a background thread.
1005e111ed8SAndrew Rybchenko */
1015e111ed8SAndrew Rybchenko #define EF10_MCDI_CMD_TIMEOUT_US (10 * 1000 * 1000)
1025e111ed8SAndrew Rybchenko #define EF10_MCDI_CMD_LONG_TIMEOUT_US (60 * 1000 * 1000)
1035e111ed8SAndrew Rybchenko
1045e111ed8SAndrew Rybchenko void
ef10_mcdi_get_timeout(__in efx_nic_t * enp,__in efx_mcdi_req_t * emrp,__out uint32_t * timeoutp)1055e111ed8SAndrew Rybchenko ef10_mcdi_get_timeout(
1065e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
1075e111ed8SAndrew Rybchenko __in efx_mcdi_req_t *emrp,
1085e111ed8SAndrew Rybchenko __out uint32_t *timeoutp)
1095e111ed8SAndrew Rybchenko {
1105e111ed8SAndrew Rybchenko efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1115e111ed8SAndrew Rybchenko
1125e111ed8SAndrew Rybchenko switch (emrp->emr_cmd) {
1135e111ed8SAndrew Rybchenko case MC_CMD_POLL_BIST:
1145e111ed8SAndrew Rybchenko case MC_CMD_NVRAM_ERASE:
1155e111ed8SAndrew Rybchenko case MC_CMD_LICENSING_V3:
1165e111ed8SAndrew Rybchenko case MC_CMD_NVRAM_UPDATE_FINISH:
1175e111ed8SAndrew Rybchenko if (encp->enc_nvram_update_verify_result_supported != B_FALSE) {
1185e111ed8SAndrew Rybchenko /*
1195e111ed8SAndrew Rybchenko * Potentially longer running commands, which firmware
1205e111ed8SAndrew Rybchenko * may choose to process in a background thread.
1215e111ed8SAndrew Rybchenko */
1225e111ed8SAndrew Rybchenko *timeoutp = EF10_MCDI_CMD_LONG_TIMEOUT_US;
1235e111ed8SAndrew Rybchenko break;
1245e111ed8SAndrew Rybchenko }
1255e111ed8SAndrew Rybchenko /* FALLTHRU */
1265e111ed8SAndrew Rybchenko default:
1275e111ed8SAndrew Rybchenko *timeoutp = EF10_MCDI_CMD_TIMEOUT_US;
1285e111ed8SAndrew Rybchenko break;
1295e111ed8SAndrew Rybchenko }
1305e111ed8SAndrew Rybchenko }
1315e111ed8SAndrew Rybchenko
1325e111ed8SAndrew Rybchenko void
ef10_mcdi_send_request(__in efx_nic_t * enp,__in_bcount (hdr_len)void * hdrp,__in size_t hdr_len,__in_bcount (sdu_len)void * sdup,__in size_t sdu_len)1335e111ed8SAndrew Rybchenko ef10_mcdi_send_request(
1345e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
1355e111ed8SAndrew Rybchenko __in_bcount(hdr_len) void *hdrp,
1365e111ed8SAndrew Rybchenko __in size_t hdr_len,
1375e111ed8SAndrew Rybchenko __in_bcount(sdu_len) void *sdup,
1385e111ed8SAndrew Rybchenko __in size_t sdu_len)
1395e111ed8SAndrew Rybchenko {
1405e111ed8SAndrew Rybchenko const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
1415e111ed8SAndrew Rybchenko efsys_mem_t *esmp = emtp->emt_dma_mem;
1425e111ed8SAndrew Rybchenko efx_dword_t dword;
1435e111ed8SAndrew Rybchenko unsigned int pos;
1445e111ed8SAndrew Rybchenko
1459b5b182dSAndrew Rybchenko EFSYS_ASSERT(EFX_FAMILY_IS_EF100(enp) || EFX_FAMILY_IS_EF10(enp));
1465e111ed8SAndrew Rybchenko
1475e111ed8SAndrew Rybchenko /* Write the header */
1485e111ed8SAndrew Rybchenko for (pos = 0; pos < hdr_len; pos += sizeof (efx_dword_t)) {
1495e111ed8SAndrew Rybchenko dword = *(efx_dword_t *)((uint8_t *)hdrp + pos);
1505e111ed8SAndrew Rybchenko EFSYS_MEM_WRITED(esmp, pos, &dword);
1515e111ed8SAndrew Rybchenko }
1525e111ed8SAndrew Rybchenko
1535e111ed8SAndrew Rybchenko /* Write the payload */
1545e111ed8SAndrew Rybchenko for (pos = 0; pos < sdu_len; pos += sizeof (efx_dword_t)) {
1555e111ed8SAndrew Rybchenko dword = *(efx_dword_t *)((uint8_t *)sdup + pos);
1565e111ed8SAndrew Rybchenko EFSYS_MEM_WRITED(esmp, hdr_len + pos, &dword);
1575e111ed8SAndrew Rybchenko }
1585e111ed8SAndrew Rybchenko
1595e111ed8SAndrew Rybchenko /* Guarantee ordering of memory (MCDI request) and PIO (MC doorbell) */
1605e111ed8SAndrew Rybchenko EFSYS_DMA_SYNC_FOR_DEVICE(esmp, 0, hdr_len + sdu_len);
1615e111ed8SAndrew Rybchenko EFSYS_PIO_WRITE_BARRIER();
1625e111ed8SAndrew Rybchenko
1635e111ed8SAndrew Rybchenko /* Ring the doorbell to post the command DMA address to the MC */
1645e111ed8SAndrew Rybchenko EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0,
1655e111ed8SAndrew Rybchenko EFSYS_MEM_ADDR(esmp) >> 32);
1669b5b182dSAndrew Rybchenko switch (enp->en_family) {
1679b5b182dSAndrew Rybchenko #if EFSYS_OPT_RIVERHEAD
1689b5b182dSAndrew Rybchenko case EFX_FAMILY_RIVERHEAD:
169341bd4e0SIgor Romanov EFX_BAR_FCW_WRITED(enp, ER_GZ_MC_DB_LWRD_REG, &dword);
1709b5b182dSAndrew Rybchenko break;
1719b5b182dSAndrew Rybchenko #endif /* EFSYS_OPT_RIVERHEAD */
1729b5b182dSAndrew Rybchenko default:
1735e111ed8SAndrew Rybchenko EFX_BAR_WRITED(enp, ER_DZ_MC_DB_LWRD_REG, &dword, B_FALSE);
1749b5b182dSAndrew Rybchenko break;
1759b5b182dSAndrew Rybchenko }
1765e111ed8SAndrew Rybchenko
1775e111ed8SAndrew Rybchenko EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0,
1785e111ed8SAndrew Rybchenko EFSYS_MEM_ADDR(esmp) & 0xffffffff);
1799b5b182dSAndrew Rybchenko switch (enp->en_family) {
1809b5b182dSAndrew Rybchenko #if EFSYS_OPT_RIVERHEAD
1819b5b182dSAndrew Rybchenko case EFX_FAMILY_RIVERHEAD:
182341bd4e0SIgor Romanov EFX_BAR_FCW_WRITED(enp, ER_GZ_MC_DB_HWRD_REG, &dword);
1839b5b182dSAndrew Rybchenko break;
1849b5b182dSAndrew Rybchenko #endif /* EFSYS_OPT_RIVERHEAD */
1859b5b182dSAndrew Rybchenko default:
1865e111ed8SAndrew Rybchenko EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE);
1879b5b182dSAndrew Rybchenko break;
1889b5b182dSAndrew Rybchenko }
1895e111ed8SAndrew Rybchenko }
1905e111ed8SAndrew Rybchenko
1915e111ed8SAndrew Rybchenko __checkReturn boolean_t
ef10_mcdi_poll_response(__in efx_nic_t * enp)1925e111ed8SAndrew Rybchenko ef10_mcdi_poll_response(
1935e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
1945e111ed8SAndrew Rybchenko {
1955e111ed8SAndrew Rybchenko const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
1965e111ed8SAndrew Rybchenko efsys_mem_t *esmp = emtp->emt_dma_mem;
1975e111ed8SAndrew Rybchenko efx_dword_t hdr;
1985e111ed8SAndrew Rybchenko
1995e111ed8SAndrew Rybchenko EFSYS_MEM_READD(esmp, 0, &hdr);
2005e111ed8SAndrew Rybchenko EFSYS_MEM_READ_BARRIER();
2015e111ed8SAndrew Rybchenko
2025e111ed8SAndrew Rybchenko return (EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE) ? B_TRUE : B_FALSE);
2035e111ed8SAndrew Rybchenko }
2045e111ed8SAndrew Rybchenko
2055e111ed8SAndrew Rybchenko void
ef10_mcdi_read_response(__in efx_nic_t * enp,__out_bcount (length)void * bufferp,__in size_t offset,__in size_t length)2065e111ed8SAndrew Rybchenko ef10_mcdi_read_response(
2075e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
2085e111ed8SAndrew Rybchenko __out_bcount(length) void *bufferp,
2095e111ed8SAndrew Rybchenko __in size_t offset,
2105e111ed8SAndrew Rybchenko __in size_t length)
2115e111ed8SAndrew Rybchenko {
2125e111ed8SAndrew Rybchenko const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
2135e111ed8SAndrew Rybchenko efsys_mem_t *esmp = emtp->emt_dma_mem;
2145e111ed8SAndrew Rybchenko unsigned int pos = 0;
2155e111ed8SAndrew Rybchenko efx_dword_t data;
2165e111ed8SAndrew Rybchenko size_t remaining = length;
2175e111ed8SAndrew Rybchenko
2185e111ed8SAndrew Rybchenko while (remaining > 0) {
2195e111ed8SAndrew Rybchenko size_t chunk = MIN(remaining, sizeof (data));
2205e111ed8SAndrew Rybchenko
2215e111ed8SAndrew Rybchenko EFSYS_MEM_READD(esmp, offset + pos, &data);
2225e111ed8SAndrew Rybchenko memcpy((uint8_t *)bufferp + pos, &data, chunk);
2235e111ed8SAndrew Rybchenko pos += chunk;
2245e111ed8SAndrew Rybchenko remaining -= chunk;
2255e111ed8SAndrew Rybchenko }
2265e111ed8SAndrew Rybchenko }
2275e111ed8SAndrew Rybchenko
2285e111ed8SAndrew Rybchenko efx_rc_t
ef10_mcdi_poll_reboot(__in efx_nic_t * enp)2295e111ed8SAndrew Rybchenko ef10_mcdi_poll_reboot(
2305e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
2315e111ed8SAndrew Rybchenko {
2325e111ed8SAndrew Rybchenko efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
2335e111ed8SAndrew Rybchenko efx_dword_t dword;
2345e111ed8SAndrew Rybchenko uint32_t old_status;
2355e111ed8SAndrew Rybchenko uint32_t new_status;
2365e111ed8SAndrew Rybchenko efx_rc_t rc;
2375e111ed8SAndrew Rybchenko
2385e111ed8SAndrew Rybchenko old_status = emip->emi_mc_reboot_status;
2395e111ed8SAndrew Rybchenko
2405e111ed8SAndrew Rybchenko /* Update MC reboot status word */
241341bd4e0SIgor Romanov switch (enp->en_family) {
242341bd4e0SIgor Romanov #if EFSYS_OPT_RIVERHEAD
243341bd4e0SIgor Romanov case EFX_FAMILY_RIVERHEAD:
244341bd4e0SIgor Romanov EFX_BAR_FCW_READD(enp, ER_GZ_MC_SFT_STATUS, &dword);
245341bd4e0SIgor Romanov break;
246341bd4e0SIgor Romanov #endif /* EFSYS_OPT_RIVERHEAD */
247341bd4e0SIgor Romanov default:
248341bd4e0SIgor Romanov EFX_BAR_READD(enp, ER_DZ_BIU_MC_SFT_STATUS_REG,
249341bd4e0SIgor Romanov &dword, B_FALSE);
250341bd4e0SIgor Romanov break;
251341bd4e0SIgor Romanov }
2525e111ed8SAndrew Rybchenko new_status = dword.ed_u32[0];
2535e111ed8SAndrew Rybchenko
2545e111ed8SAndrew Rybchenko /* MC has rebooted if the value has changed */
2555e111ed8SAndrew Rybchenko if (new_status != old_status) {
2565e111ed8SAndrew Rybchenko emip->emi_mc_reboot_status = new_status;
2575e111ed8SAndrew Rybchenko
2585e111ed8SAndrew Rybchenko /*
2595e111ed8SAndrew Rybchenko * FIXME: Ignore detected MC REBOOT for now.
2605e111ed8SAndrew Rybchenko *
2615e111ed8SAndrew Rybchenko * The Siena support for checking for MC reboot from status
2625e111ed8SAndrew Rybchenko * flags is broken - see comments in siena_mcdi_poll_reboot().
2635e111ed8SAndrew Rybchenko * As the generic MCDI code is shared the EF10 reboot
2645e111ed8SAndrew Rybchenko * detection suffers similar problems.
2655e111ed8SAndrew Rybchenko *
2665e111ed8SAndrew Rybchenko * Do not report an error when the boot status changes until
2675e111ed8SAndrew Rybchenko * this can be handled by common code drivers (and reworked to
2685e111ed8SAndrew Rybchenko * support Siena too).
2695e111ed8SAndrew Rybchenko */
2705e111ed8SAndrew Rybchenko _NOTE(CONSTANTCONDITION)
2715e111ed8SAndrew Rybchenko if (B_FALSE) {
2725e111ed8SAndrew Rybchenko rc = EIO;
2735e111ed8SAndrew Rybchenko goto fail1;
2745e111ed8SAndrew Rybchenko }
2755e111ed8SAndrew Rybchenko }
2765e111ed8SAndrew Rybchenko
2775e111ed8SAndrew Rybchenko return (0);
2785e111ed8SAndrew Rybchenko
2795e111ed8SAndrew Rybchenko fail1:
2805e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
2815e111ed8SAndrew Rybchenko
2825e111ed8SAndrew Rybchenko return (rc);
2835e111ed8SAndrew Rybchenko }
2845e111ed8SAndrew Rybchenko
2855e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
ef10_mcdi_feature_supported(__in efx_nic_t * enp,__in efx_mcdi_feature_id_t id,__out boolean_t * supportedp)2865e111ed8SAndrew Rybchenko ef10_mcdi_feature_supported(
2875e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
2885e111ed8SAndrew Rybchenko __in efx_mcdi_feature_id_t id,
2895e111ed8SAndrew Rybchenko __out boolean_t *supportedp)
2905e111ed8SAndrew Rybchenko {
2915e111ed8SAndrew Rybchenko efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
2925e111ed8SAndrew Rybchenko uint32_t privilege_mask = encp->enc_privilege_mask;
2935e111ed8SAndrew Rybchenko efx_rc_t rc;
2945e111ed8SAndrew Rybchenko
2959b5b182dSAndrew Rybchenko EFSYS_ASSERT(EFX_FAMILY_IS_EF100(enp) || EFX_FAMILY_IS_EF10(enp));
2965e111ed8SAndrew Rybchenko
2975e111ed8SAndrew Rybchenko /*
2985e111ed8SAndrew Rybchenko * Use privilege mask state at MCDI attach.
2995e111ed8SAndrew Rybchenko */
3005e111ed8SAndrew Rybchenko
3015e111ed8SAndrew Rybchenko switch (id) {
3025e111ed8SAndrew Rybchenko case EFX_MCDI_FEATURE_FW_UPDATE:
3035e111ed8SAndrew Rybchenko /*
3045e111ed8SAndrew Rybchenko * Admin privilege must be used prior to introduction of
3055e111ed8SAndrew Rybchenko * specific flag.
3065e111ed8SAndrew Rybchenko */
3075e111ed8SAndrew Rybchenko *supportedp =
3085e111ed8SAndrew Rybchenko EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
3095e111ed8SAndrew Rybchenko break;
3105e111ed8SAndrew Rybchenko case EFX_MCDI_FEATURE_LINK_CONTROL:
3115e111ed8SAndrew Rybchenko /*
3125e111ed8SAndrew Rybchenko * Admin privilege used prior to introduction of
3135e111ed8SAndrew Rybchenko * specific flag.
3145e111ed8SAndrew Rybchenko */
3155e111ed8SAndrew Rybchenko *supportedp =
3165e111ed8SAndrew Rybchenko EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, LINK) ||
3175e111ed8SAndrew Rybchenko EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
3185e111ed8SAndrew Rybchenko break;
3195e111ed8SAndrew Rybchenko case EFX_MCDI_FEATURE_MACADDR_CHANGE:
3205e111ed8SAndrew Rybchenko /*
3215e111ed8SAndrew Rybchenko * Admin privilege must be used prior to introduction of
3225e111ed8SAndrew Rybchenko * mac spoofing privilege (at v4.6), which is used up to
3235e111ed8SAndrew Rybchenko * introduction of change mac spoofing privilege (at v4.7)
3245e111ed8SAndrew Rybchenko */
3255e111ed8SAndrew Rybchenko *supportedp =
3265e111ed8SAndrew Rybchenko EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, CHANGE_MAC) ||
3275e111ed8SAndrew Rybchenko EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) ||
3285e111ed8SAndrew Rybchenko EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
3295e111ed8SAndrew Rybchenko break;
3305e111ed8SAndrew Rybchenko case EFX_MCDI_FEATURE_MAC_SPOOFING:
3315e111ed8SAndrew Rybchenko /*
3325e111ed8SAndrew Rybchenko * Admin privilege must be used prior to introduction of
3335e111ed8SAndrew Rybchenko * mac spoofing privilege (at v4.6), which is used up to
3345e111ed8SAndrew Rybchenko * introduction of mac spoofing TX privilege (at v4.7)
3355e111ed8SAndrew Rybchenko */
3365e111ed8SAndrew Rybchenko *supportedp =
3375e111ed8SAndrew Rybchenko EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING_TX) ||
3385e111ed8SAndrew Rybchenko EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) ||
3395e111ed8SAndrew Rybchenko EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
3405e111ed8SAndrew Rybchenko break;
3415e111ed8SAndrew Rybchenko default:
3425e111ed8SAndrew Rybchenko rc = ENOTSUP;
3435e111ed8SAndrew Rybchenko goto fail1;
3445e111ed8SAndrew Rybchenko }
3455e111ed8SAndrew Rybchenko
3465e111ed8SAndrew Rybchenko return (0);
3475e111ed8SAndrew Rybchenko
3485e111ed8SAndrew Rybchenko fail1:
3495e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
3505e111ed8SAndrew Rybchenko
3515e111ed8SAndrew Rybchenko return (rc);
3525e111ed8SAndrew Rybchenko }
3535e111ed8SAndrew Rybchenko
3545e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MCDI */
3555e111ed8SAndrew Rybchenko
3569b5b182dSAndrew Rybchenko #endif /* EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10() */
357