xref: /dpdk/drivers/common/sfc_efx/base/ef10_mcdi.c (revision 672386c1e9e1f64f7aa3b1360ad22dc737ea8d72)
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