ef10_mcdi.c revision 293765
1283514Sarybchik/*-
2283514Sarybchik * Copyright (c) 2012-2015 Solarflare Communications Inc.
3283514Sarybchik * All rights reserved.
4283514Sarybchik *
5283514Sarybchik * Redistribution and use in source and binary forms, with or without
6283514Sarybchik * modification, are permitted provided that the following conditions are met:
7283514Sarybchik *
8283514Sarybchik * 1. Redistributions of source code must retain the above copyright notice,
9283514Sarybchik *    this list of conditions and the following disclaimer.
10283514Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice,
11283514Sarybchik *    this list of conditions and the following disclaimer in the documentation
12283514Sarybchik *    and/or other materials provided with the distribution.
13283514Sarybchik *
14283514Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15283514Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16283514Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17283514Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18283514Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19283514Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20283514Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21283514Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22283514Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23283514Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24283514Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25283514Sarybchik *
26283514Sarybchik * The views and conclusions contained in the software and documentation are
27283514Sarybchik * those of the authors and should not be interpreted as representing official
28283514Sarybchik * policies, either expressed or implied, of the FreeBSD Project.
29283514Sarybchik */
30283514Sarybchik
31283514Sarybchik#include <sys/cdefs.h>
32283514Sarybchik__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/hunt_mcdi.c 293765 2016-01-12 15:25:03Z arybchik $");
33283514Sarybchik
34283514Sarybchik#include "efsys.h"
35283514Sarybchik#include "efx.h"
36283514Sarybchik#include "efx_impl.h"
37283514Sarybchik
38283514Sarybchik
39293757Sarybchik#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
40283514Sarybchik
41283514Sarybchik#if EFSYS_OPT_MCDI
42283514Sarybchik
43283514Sarybchik#ifndef WITH_MCDI_V2
44293757Sarybchik#error "WITH_MCDI_V2 required for EF10 MCDIv2 commands."
45283514Sarybchik#endif
46283514Sarybchik
47283514Sarybchiktypedef enum efx_mcdi_header_type_e {
48283514Sarybchik	EFX_MCDI_HEADER_TYPE_V1, /* MCDIv0 (BootROM), MCDIv1 commands */
49283514Sarybchik	EFX_MCDI_HEADER_TYPE_V2, /* MCDIv2 commands */
50283514Sarybchik} efx_mcdi_header_type_t;
51283514Sarybchik
52283514Sarybchik/*
53283514Sarybchik * Return the header format to use for sending an MCDI request.
54283514Sarybchik *
55283514Sarybchik * An MCDIv1 (Siena compatible) command should use MCDIv2 encapsulation if the
56283514Sarybchik * request input buffer or response output buffer are too large for the MCDIv1
57283514Sarybchik * format. An MCDIv2 command must always be sent using MCDIv2 encapsulation.
58283514Sarybchik */
59283514Sarybchik#define	EFX_MCDI_HEADER_TYPE(_cmd, _length)				\
60283514Sarybchik	((((_cmd) & ~EFX_MASK32(MCDI_HEADER_CODE)) ||			\
61283514Sarybchik	((_length) & ~EFX_MASK32(MCDI_HEADER_DATALEN)))	?		\
62283514Sarybchik	EFX_MCDI_HEADER_TYPE_V2	: EFX_MCDI_HEADER_TYPE_V1)
63283514Sarybchik
64283514Sarybchik
65283514Sarybchik/*
66283514Sarybchik * MCDI Header NOT_EPOCH flag
67283514Sarybchik * ==========================
68283514Sarybchik * A new epoch begins at initial startup or after an MC reboot, and defines when
69283514Sarybchik * the MC should reject stale MCDI requests.
70283514Sarybchik *
71283514Sarybchik * The first MCDI request sent by the host should contain NOT_EPOCH=0, and all
72283514Sarybchik * subsequent requests (until the next MC reboot) should contain NOT_EPOCH=1.
73283514Sarybchik *
74283514Sarybchik * After rebooting the MC will fail all requests with NOT_EPOCH=1 by writing a
75283514Sarybchik * response with ERROR=1 and DATALEN=0 until a request is seen with NOT_EPOCH=0.
76283514Sarybchik */
77283514Sarybchik
78283514Sarybchik
79291436Sarybchik	__checkReturn	efx_rc_t
80293757Sarybchikef10_mcdi_init(
81283514Sarybchik	__in		efx_nic_t *enp,
82283514Sarybchik	__in		const efx_mcdi_transport_t *emtp)
83283514Sarybchik{
84293765Sarybchik	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
85283514Sarybchik	efsys_mem_t *esmp = emtp->emt_dma_mem;
86283514Sarybchik	efx_dword_t dword;
87291436Sarybchik	efx_rc_t rc;
88283514Sarybchik
89293757Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
90293757Sarybchik		    enp->en_family == EFX_FAMILY_MEDFORD);
91283514Sarybchik	EFSYS_ASSERT(enp->en_features & EFX_FEATURE_MCDI_DMA);
92283514Sarybchik
93293765Sarybchik	/*
94293765Sarybchik	 * All EF10 firmware supports MCDIv2 and MCDIv1.
95293765Sarybchik	 * Medford BootROM supports MCDIv2 and MCDIv1.
96293765Sarybchik	 * Huntington BootROM supports MCDIv1 only.
97293765Sarybchik	 */
98293765Sarybchik	emip->emi_max_version = 2;
99293765Sarybchik
100293757Sarybchik	/* A host DMA buffer is required for EF10 MCDI */
101283514Sarybchik	if (esmp == NULL) {
102283514Sarybchik		rc = EINVAL;
103283514Sarybchik		goto fail1;
104283514Sarybchik	}
105283514Sarybchik
106283514Sarybchik	/*
107283514Sarybchik	 * Ensure that the MC doorbell is in a known state before issuing MCDI
108283514Sarybchik	 * commands. The recovery algorithm requires that the MC command buffer
109283514Sarybchik	 * must be 256 byte aligned. See bug24769.
110283514Sarybchik	 */
111283514Sarybchik	if ((EFSYS_MEM_ADDR(esmp) & 0xFF) != 0) {
112283514Sarybchik		rc = EINVAL;
113283514Sarybchik		goto fail2;
114283514Sarybchik	}
115283514Sarybchik	EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 1);
116283514Sarybchik	EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE);
117283514Sarybchik
118283514Sarybchik	/* Save initial MC reboot status */
119293757Sarybchik	(void) ef10_mcdi_poll_reboot(enp);
120283514Sarybchik
121283514Sarybchik	/* Start a new epoch (allow fresh MCDI requests to succeed) */
122283514Sarybchik	efx_mcdi_new_epoch(enp);
123283514Sarybchik
124283514Sarybchik	return (0);
125283514Sarybchik
126283514Sarybchikfail2:
127283514Sarybchik	EFSYS_PROBE(fail2);
128283514Sarybchikfail1:
129291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
130283514Sarybchik
131283514Sarybchik	return (rc);
132283514Sarybchik}
133283514Sarybchik
134283514Sarybchik			void
135293757Sarybchikef10_mcdi_fini(
136283514Sarybchik	__in		efx_nic_t *enp)
137283514Sarybchik{
138283514Sarybchik	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
139283514Sarybchik
140283514Sarybchik	emip->emi_new_epoch = B_FALSE;
141283514Sarybchik}
142283514Sarybchik
143283514Sarybchik			void
144293757Sarybchikef10_mcdi_request_copyin(
145283514Sarybchik	__in		efx_nic_t *enp,
146283514Sarybchik	__in		efx_mcdi_req_t *emrp,
147283514Sarybchik	__in		unsigned int seq,
148283514Sarybchik	__in		boolean_t ev_cpl,
149283514Sarybchik	__in		boolean_t new_epoch)
150283514Sarybchik{
151283514Sarybchik	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
152283514Sarybchik	efsys_mem_t *esmp = emtp->emt_dma_mem;
153283514Sarybchik	efx_mcdi_header_type_t hdr_type;
154283514Sarybchik	efx_dword_t dword;
155291677Sarybchik	efx_dword_t hdr[2];
156283514Sarybchik	unsigned int xflags;
157283514Sarybchik	unsigned int pos;
158283514Sarybchik	size_t offset;
159283514Sarybchik
160293757Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
161293757Sarybchik		    enp->en_family == EFX_FAMILY_MEDFORD);
162283514Sarybchik
163283514Sarybchik	xflags = 0;
164283514Sarybchik	if (ev_cpl)
165283514Sarybchik		xflags |= MCDI_HEADER_XFLAGS_EVREQ;
166283514Sarybchik
167283514Sarybchik	offset = 0;
168283514Sarybchik
169283514Sarybchik	hdr_type = EFX_MCDI_HEADER_TYPE(emrp->emr_cmd,
170283514Sarybchik	    MAX(emrp->emr_in_length, emrp->emr_out_length));
171283514Sarybchik
172283514Sarybchik	if (hdr_type == EFX_MCDI_HEADER_TYPE_V2) {
173283514Sarybchik		/* Construct MCDI v2 header */
174291677Sarybchik		EFX_POPULATE_DWORD_8(hdr[0],
175283514Sarybchik		    MCDI_HEADER_CODE, MC_CMD_V2_EXTN,
176283514Sarybchik		    MCDI_HEADER_RESYNC, 1,
177283514Sarybchik		    MCDI_HEADER_DATALEN, 0,
178283514Sarybchik		    MCDI_HEADER_SEQ, seq,
179283514Sarybchik		    MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
180283514Sarybchik		    MCDI_HEADER_ERROR, 0,
181283514Sarybchik		    MCDI_HEADER_RESPONSE, 0,
182283514Sarybchik		    MCDI_HEADER_XFLAGS, xflags);
183291677Sarybchik		EFSYS_MEM_WRITED(esmp, offset, &hdr[0]);
184291677Sarybchik		offset += sizeof (efx_dword_t);
185283514Sarybchik
186291677Sarybchik		EFX_POPULATE_DWORD_2(hdr[1],
187283514Sarybchik		    MC_CMD_V2_EXTN_IN_EXTENDED_CMD, emrp->emr_cmd,
188283514Sarybchik		    MC_CMD_V2_EXTN_IN_ACTUAL_LEN, emrp->emr_in_length);
189291677Sarybchik		EFSYS_MEM_WRITED(esmp, offset, &hdr[1]);
190291677Sarybchik		offset += sizeof (efx_dword_t);
191283514Sarybchik	} else {
192283514Sarybchik		/* Construct MCDI v1 header */
193291677Sarybchik		EFX_POPULATE_DWORD_8(hdr[0],
194283514Sarybchik		    MCDI_HEADER_CODE, emrp->emr_cmd,
195283514Sarybchik		    MCDI_HEADER_RESYNC, 1,
196283514Sarybchik		    MCDI_HEADER_DATALEN, emrp->emr_in_length,
197283514Sarybchik		    MCDI_HEADER_SEQ, seq,
198283514Sarybchik		    MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
199283514Sarybchik		    MCDI_HEADER_ERROR, 0,
200283514Sarybchik		    MCDI_HEADER_RESPONSE, 0,
201283514Sarybchik		    MCDI_HEADER_XFLAGS, xflags);
202291677Sarybchik		EFSYS_MEM_WRITED(esmp, 0, &hdr[0]);
203291677Sarybchik		offset += sizeof (efx_dword_t);
204283514Sarybchik	}
205283514Sarybchik
206291677Sarybchik#if EFSYS_OPT_MCDI_LOGGING
207291677Sarybchik	if (emtp->emt_logger != NULL) {
208291677Sarybchik		emtp->emt_logger(emtp->emt_context, EFX_LOG_MCDI_REQUEST,
209291677Sarybchik		    &hdr, offset,
210291677Sarybchik		    emrp->emr_in_buf, emrp->emr_in_length);
211291677Sarybchik	}
212291677Sarybchik#endif /* EFSYS_OPT_MCDI_LOGGING */
213291677Sarybchik
214283514Sarybchik	/* Construct the payload */
215283514Sarybchik	for (pos = 0; pos < emrp->emr_in_length; pos += sizeof (efx_dword_t)) {
216283514Sarybchik		memcpy(&dword, MCDI_IN(*emrp, efx_dword_t, pos),
217283514Sarybchik		    MIN(sizeof (dword), emrp->emr_in_length - pos));
218283514Sarybchik		EFSYS_MEM_WRITED(esmp, offset + pos, &dword);
219283514Sarybchik	}
220283514Sarybchik
221283514Sarybchik	/* Ring the doorbell to post the command DMA address to the MC */
222283514Sarybchik	EFSYS_ASSERT((EFSYS_MEM_ADDR(esmp) & 0xFF) == 0);
223283514Sarybchik
224283514Sarybchik	/* Guarantee ordering of memory (MCDI request) and PIO (MC doorbell) */
225283514Sarybchik	EFSYS_DMA_SYNC_FOR_DEVICE(esmp, 0, offset + emrp->emr_in_length);
226283514Sarybchik	EFSYS_PIO_WRITE_BARRIER();
227283514Sarybchik
228283514Sarybchik	EFX_POPULATE_DWORD_1(dword,
229283514Sarybchik	    EFX_DWORD_0, EFSYS_MEM_ADDR(esmp) >> 32);
230283514Sarybchik	EFX_BAR_WRITED(enp, ER_DZ_MC_DB_LWRD_REG, &dword, B_FALSE);
231283514Sarybchik
232283514Sarybchik	EFX_POPULATE_DWORD_1(dword,
233283514Sarybchik	    EFX_DWORD_0, EFSYS_MEM_ADDR(esmp) & 0xffffffff);
234283514Sarybchik	EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE);
235283514Sarybchik}
236283514Sarybchik
237283514Sarybchik			void
238293757Sarybchikef10_mcdi_request_copyout(
239283514Sarybchik	__in		efx_nic_t *enp,
240283514Sarybchik	__in		efx_mcdi_req_t *emrp)
241283514Sarybchik{
242291985Sarybchik#if EFSYS_OPT_MCDI_LOGGING
243283514Sarybchik	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
244291985Sarybchik#endif /* EFSYS_OPT_MCDI_LOGGING */
245291677Sarybchik	efx_dword_t hdr[2];
246291985Sarybchik	unsigned int hdr_len;
247283514Sarybchik	size_t bytes;
248283514Sarybchik
249283514Sarybchik	if (emrp->emr_out_buf == NULL)
250283514Sarybchik		return;
251283514Sarybchik
252283514Sarybchik	/* Read the command header to detect MCDI response format */
253291985Sarybchik	hdr_len = sizeof (hdr[0]);
254293757Sarybchik	ef10_mcdi_read_response(enp, &hdr[0], 0, hdr_len);
255291677Sarybchik	if (EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) {
256283514Sarybchik		/*
257283514Sarybchik		 * Read the actual payload length. The length given in the event
258283514Sarybchik		 * is only correct for responses with the V1 format.
259283514Sarybchik		 */
260293757Sarybchik		ef10_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1]));
261291985Sarybchik		hdr_len += sizeof (hdr[1]);
262291985Sarybchik
263291677Sarybchik		emrp->emr_out_length_used = EFX_DWORD_FIELD(hdr[1],
264283514Sarybchik					    MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
265283514Sarybchik	}
266283514Sarybchik
267283514Sarybchik	/* Copy payload out into caller supplied buffer */
268283514Sarybchik	bytes = MIN(emrp->emr_out_length_used, emrp->emr_out_length);
269293757Sarybchik	ef10_mcdi_read_response(enp, emrp->emr_out_buf, hdr_len, bytes);
270291677Sarybchik
271291677Sarybchik#if EFSYS_OPT_MCDI_LOGGING
272291677Sarybchik	if (emtp->emt_logger != NULL) {
273291677Sarybchik		emtp->emt_logger(emtp->emt_context,
274291677Sarybchik		    EFX_LOG_MCDI_RESPONSE,
275291985Sarybchik		    &hdr, hdr_len,
276291985Sarybchik		    emrp->emr_out_buf, bytes);
277291677Sarybchik	}
278291677Sarybchik#endif /* EFSYS_OPT_MCDI_LOGGING */
279283514Sarybchik}
280283514Sarybchik
281292090Sarybchik	__checkReturn	boolean_t
282293757Sarybchikef10_mcdi_poll_response(
283291928Sarybchik	__in		efx_nic_t *enp)
284291928Sarybchik{
285291928Sarybchik	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
286291928Sarybchik	efsys_mem_t *esmp = emtp->emt_dma_mem;
287291928Sarybchik	efx_dword_t hdr;
288291928Sarybchik
289291928Sarybchik	EFSYS_MEM_READD(esmp, 0, &hdr);
290291928Sarybchik	return (EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE) ? B_TRUE : B_FALSE);
291291928Sarybchik}
292291928Sarybchik
293291985Sarybchik			void
294293757Sarybchikef10_mcdi_read_response(
295291985Sarybchik	__in		efx_nic_t *enp,
296291985Sarybchik	__out		void *bufferp,
297291985Sarybchik	__in		size_t offset,
298291985Sarybchik	__in		size_t length)
299291985Sarybchik{
300291985Sarybchik	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
301291985Sarybchik	efsys_mem_t *esmp = emtp->emt_dma_mem;
302291985Sarybchik	unsigned int pos;
303291985Sarybchik	efx_dword_t data;
304291985Sarybchik
305291985Sarybchik	for (pos = 0; pos < length; pos += sizeof (efx_dword_t)) {
306291985Sarybchik		EFSYS_MEM_READD(esmp, offset + pos, &data);
307291985Sarybchik		memcpy((uint8_t *)bufferp + pos, &data,
308291985Sarybchik		    MIN(sizeof (data), length - pos));
309291985Sarybchik	}
310291985Sarybchik}
311291985Sarybchik
312291436Sarybchik			efx_rc_t
313293757Sarybchikef10_mcdi_poll_reboot(
314283514Sarybchik	__in		efx_nic_t *enp)
315283514Sarybchik{
316283514Sarybchik	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
317283514Sarybchik	efx_dword_t dword;
318283514Sarybchik	uint32_t old_status;
319283514Sarybchik	uint32_t new_status;
320291436Sarybchik	efx_rc_t rc;
321283514Sarybchik
322283514Sarybchik	old_status = emip->emi_mc_reboot_status;
323283514Sarybchik
324283514Sarybchik	/* Update MC reboot status word */
325283514Sarybchik	EFX_BAR_TBL_READD(enp, ER_DZ_BIU_MC_SFT_STATUS_REG, 0, &dword, B_FALSE);
326283514Sarybchik	new_status = dword.ed_u32[0];
327283514Sarybchik
328283514Sarybchik	/* MC has rebooted if the value has changed */
329283514Sarybchik	if (new_status != old_status) {
330283514Sarybchik		emip->emi_mc_reboot_status = new_status;
331283514Sarybchik
332283514Sarybchik		/*
333283514Sarybchik		 * FIXME: Ignore detected MC REBOOT for now.
334283514Sarybchik		 *
335283514Sarybchik		 * The Siena support for checking for MC reboot from status
336283514Sarybchik		 * flags is broken - see comments in siena_mcdi_poll_reboot().
337293757Sarybchik		 * As the generic MCDI code is shared the EF10 reboot
338283514Sarybchik		 * detection suffers similar problems.
339283514Sarybchik		 *
340283514Sarybchik		 * Do not report an error when the boot status changes until
341283514Sarybchik		 * this can be handled by common code drivers (and reworked to
342283514Sarybchik		 * support Siena too).
343283514Sarybchik		 */
344283514Sarybchik		if (B_FALSE) {
345283514Sarybchik			rc = EIO;
346283514Sarybchik			goto fail1;
347283514Sarybchik		}
348283514Sarybchik	}
349283514Sarybchik
350283514Sarybchik	return (0);
351283514Sarybchik
352283514Sarybchikfail1:
353291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
354283514Sarybchik
355283514Sarybchik	return (rc);
356283514Sarybchik}
357283514Sarybchik
358291436Sarybchik	__checkReturn	efx_rc_t
359293757Sarybchikef10_mcdi_feature_supported(
360283514Sarybchik	__in		efx_nic_t *enp,
361292055Sarybchik	__in		efx_mcdi_feature_id_t id,
362283514Sarybchik	__out		boolean_t *supportedp)
363283514Sarybchik{
364283514Sarybchik	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
365291585Sarybchik	uint32_t privilege_mask = encp->enc_privilege_mask;
366292055Sarybchik	efx_rc_t rc;
367283514Sarybchik
368293757Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
369293757Sarybchik		    enp->en_family == EFX_FAMILY_MEDFORD);
370283514Sarybchik
371291585Sarybchik	/*
372291585Sarybchik	 * Use privilege mask state at MCDI attach.
373291585Sarybchik	 */
374283514Sarybchik
375292055Sarybchik	switch (id) {
376292055Sarybchik	case EFX_MCDI_FEATURE_FW_UPDATE:
377292055Sarybchik		/*
378292055Sarybchik		 * Admin privilege must be used prior to introduction of
379292055Sarybchik		 * specific flag.
380292055Sarybchik		 */
381292055Sarybchik		*supportedp =
382292055Sarybchik		    EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
383292055Sarybchik		break;
384292055Sarybchik	case EFX_MCDI_FEATURE_LINK_CONTROL:
385292055Sarybchik		/*
386292055Sarybchik		 * Admin privilege used prior to introduction of
387292055Sarybchik		 * specific flag.
388292055Sarybchik		 */
389292055Sarybchik		*supportedp =
390292055Sarybchik		    EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, LINK) ||
391292055Sarybchik		    EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
392292055Sarybchik		break;
393292055Sarybchik	case EFX_MCDI_FEATURE_MACADDR_CHANGE:
394292055Sarybchik		/*
395292055Sarybchik		 * Admin privilege must be used prior to introduction of
396292055Sarybchik		 * mac spoofing privilege (at v4.6), which is used up to
397292055Sarybchik		 * introduction of change mac spoofing privilege (at v4.7)
398292055Sarybchik		 */
399292055Sarybchik		*supportedp =
400292055Sarybchik		    EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, CHANGE_MAC) ||
401292055Sarybchik		    EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) ||
402292055Sarybchik		    EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
403292055Sarybchik		break;
404292055Sarybchik	case EFX_MCDI_FEATURE_MAC_SPOOFING:
405292055Sarybchik		/*
406292055Sarybchik		 * Admin privilege must be used prior to introduction of
407292055Sarybchik		 * mac spoofing privilege (at v4.6), which is used up to
408292055Sarybchik		 * introduction of mac spoofing TX privilege (at v4.7)
409292055Sarybchik		 */
410292055Sarybchik		*supportedp =
411292055Sarybchik		    EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING_TX) ||
412292055Sarybchik		    EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) ||
413292055Sarybchik		    EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
414292055Sarybchik		break;
415292055Sarybchik	default:
416292055Sarybchik		rc = ENOTSUP;
417292055Sarybchik		goto fail1;
418292055Sarybchik		break;
419292055Sarybchik	}
420283514Sarybchik
421292008Sarybchik	return (0);
422292008Sarybchik
423292055Sarybchikfail1:
424292055Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
425292008Sarybchik
426292055Sarybchik	return (rc);
427291588Sarybchik}
428291588Sarybchik
429283514Sarybchik#endif	/* EFSYS_OPT_MCDI */
430283514Sarybchik
431293757Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
432