efx_mcdi.c revision 310920
1/*-
2 * Copyright (c) 2008-2016 Solarflare Communications Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 *    this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 *    this list of conditions and the following disclaimer in the documentation
12 *    and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * The views and conclusions contained in the software and documentation are
27 * those of the authors and should not be interpreted as representing official
28 * policies, either expressed or implied, of the FreeBSD Project.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: stable/11/sys/dev/sfxge/common/efx_mcdi.c 310920 2016-12-31 11:02:33Z arybchik $");
33
34#include "efx.h"
35#include "efx_impl.h"
36
37#if EFSYS_OPT_MCDI
38
39/*
40 * There are three versions of the MCDI interface:
41 *  - MCDIv0: Siena BootROM. Transport uses MCDIv1 headers.
42 *  - MCDIv1: Siena firmware and Huntington BootROM.
43 *  - MCDIv2: EF10 firmware (Huntington/Medford) and Medford BootROM.
44 *            Transport uses MCDIv2 headers.
45 *
46 * MCDIv2 Header NOT_EPOCH flag
47 * ----------------------------
48 * A new epoch begins at initial startup or after an MC reboot, and defines when
49 * the MC should reject stale MCDI requests.
50 *
51 * The first MCDI request sent by the host should contain NOT_EPOCH=0, and all
52 * subsequent requests (until the next MC reboot) should contain NOT_EPOCH=1.
53 *
54 * After rebooting the MC will fail all requests with NOT_EPOCH=1 by writing a
55 * response with ERROR=1 and DATALEN=0 until a request is seen with NOT_EPOCH=0.
56 */
57
58
59
60#if EFSYS_OPT_SIENA
61
62static const efx_mcdi_ops_t	__efx_mcdi_siena_ops = {
63	siena_mcdi_init,		/* emco_init */
64	siena_mcdi_send_request,	/* emco_send_request */
65	siena_mcdi_poll_reboot,		/* emco_poll_reboot */
66	siena_mcdi_poll_response,	/* emco_poll_response */
67	siena_mcdi_read_response,	/* emco_read_response */
68	siena_mcdi_fini,		/* emco_fini */
69	siena_mcdi_feature_supported,	/* emco_feature_supported */
70};
71
72#endif	/* EFSYS_OPT_SIENA */
73
74#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
75
76static const efx_mcdi_ops_t	__efx_mcdi_ef10_ops = {
77	ef10_mcdi_init,			/* emco_init */
78	ef10_mcdi_send_request,		/* emco_send_request */
79	ef10_mcdi_poll_reboot,		/* emco_poll_reboot */
80	ef10_mcdi_poll_response,	/* emco_poll_response */
81	ef10_mcdi_read_response,	/* emco_read_response */
82	ef10_mcdi_fini,			/* emco_fini */
83	ef10_mcdi_feature_supported,	/* emco_feature_supported */
84};
85
86#endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
87
88
89
90	__checkReturn	efx_rc_t
91efx_mcdi_init(
92	__in		efx_nic_t *enp,
93	__in		const efx_mcdi_transport_t *emtp)
94{
95	const efx_mcdi_ops_t *emcop;
96	efx_rc_t rc;
97
98	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
99	EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
100
101	switch (enp->en_family) {
102#if EFSYS_OPT_SIENA
103	case EFX_FAMILY_SIENA:
104		emcop = &__efx_mcdi_siena_ops;
105		break;
106#endif	/* EFSYS_OPT_SIENA */
107
108#if EFSYS_OPT_HUNTINGTON
109	case EFX_FAMILY_HUNTINGTON:
110		emcop = &__efx_mcdi_ef10_ops;
111		break;
112#endif	/* EFSYS_OPT_HUNTINGTON */
113
114#if EFSYS_OPT_MEDFORD
115	case EFX_FAMILY_MEDFORD:
116		emcop = &__efx_mcdi_ef10_ops;
117		break;
118#endif	/* EFSYS_OPT_MEDFORD */
119
120	default:
121		EFSYS_ASSERT(0);
122		rc = ENOTSUP;
123		goto fail1;
124	}
125
126	if (enp->en_features & EFX_FEATURE_MCDI_DMA) {
127		/* MCDI requires a DMA buffer in host memory */
128		if ((emtp == NULL) || (emtp->emt_dma_mem) == NULL) {
129			rc = EINVAL;
130			goto fail2;
131		}
132	}
133	enp->en_mcdi.em_emtp = emtp;
134
135	if (emcop != NULL && emcop->emco_init != NULL) {
136		if ((rc = emcop->emco_init(enp, emtp)) != 0)
137			goto fail3;
138	}
139
140	enp->en_mcdi.em_emcop = emcop;
141	enp->en_mod_flags |= EFX_MOD_MCDI;
142
143	return (0);
144
145fail3:
146	EFSYS_PROBE(fail3);
147fail2:
148	EFSYS_PROBE(fail2);
149fail1:
150	EFSYS_PROBE1(fail1, efx_rc_t, rc);
151
152	enp->en_mcdi.em_emcop = NULL;
153	enp->en_mcdi.em_emtp = NULL;
154	enp->en_mod_flags &= ~EFX_MOD_MCDI;
155
156	return (rc);
157}
158
159			void
160efx_mcdi_fini(
161	__in		efx_nic_t *enp)
162{
163	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
164	const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
165
166	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
167	EFSYS_ASSERT3U(enp->en_mod_flags, ==, EFX_MOD_MCDI);
168
169	if (emcop != NULL && emcop->emco_fini != NULL)
170		emcop->emco_fini(enp);
171
172	emip->emi_port = 0;
173	emip->emi_aborted = 0;
174
175	enp->en_mcdi.em_emcop = NULL;
176	enp->en_mod_flags &= ~EFX_MOD_MCDI;
177}
178
179			void
180efx_mcdi_new_epoch(
181	__in		efx_nic_t *enp)
182{
183	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
184	int state;
185
186	/* Start a new epoch (allow fresh MCDI requests to succeed) */
187	EFSYS_LOCK(enp->en_eslp, state);
188	emip->emi_new_epoch = B_TRUE;
189	EFSYS_UNLOCK(enp->en_eslp, state);
190}
191
192static			void
193efx_mcdi_send_request(
194	__in		efx_nic_t *enp,
195	__in		void *hdrp,
196	__in		size_t hdr_len,
197	__in		void *sdup,
198	__in		size_t sdu_len)
199{
200	const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
201
202	emcop->emco_send_request(enp, hdrp, hdr_len, sdup, sdu_len);
203}
204
205static			efx_rc_t
206efx_mcdi_poll_reboot(
207	__in		efx_nic_t *enp)
208{
209	const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
210	efx_rc_t rc;
211
212	rc = emcop->emco_poll_reboot(enp);
213	return (rc);
214}
215
216static			boolean_t
217efx_mcdi_poll_response(
218	__in		efx_nic_t *enp)
219{
220	const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
221	boolean_t available;
222
223	available = emcop->emco_poll_response(enp);
224	return (available);
225}
226
227static			void
228efx_mcdi_read_response(
229	__in		efx_nic_t *enp,
230	__out		void *bufferp,
231	__in		size_t offset,
232	__in		size_t length)
233{
234	const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
235
236	emcop->emco_read_response(enp, bufferp, offset, length);
237}
238
239			void
240efx_mcdi_request_start(
241	__in		efx_nic_t *enp,
242	__in		efx_mcdi_req_t *emrp,
243	__in		boolean_t ev_cpl)
244{
245#if EFSYS_OPT_MCDI_LOGGING
246	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
247#endif
248	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
249	efx_dword_t hdr[2];
250	size_t hdr_len;
251	unsigned int max_version;
252	unsigned int seq;
253	unsigned int xflags;
254	boolean_t new_epoch;
255	int state;
256
257	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
258	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
259	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
260
261	/*
262	 * efx_mcdi_request_start() is naturally serialised against both
263	 * efx_mcdi_request_poll() and efx_mcdi_ev_cpl()/efx_mcdi_ev_death(),
264	 * by virtue of there only being one outstanding MCDI request.
265	 * Unfortunately, upper layers may also call efx_mcdi_request_abort()
266	 * at any time, to timeout a pending mcdi request, That request may
267	 * then subsequently complete, meaning efx_mcdi_ev_cpl() or
268	 * efx_mcdi_ev_death() may end up running in parallel with
269	 * efx_mcdi_request_start(). This race is handled by ensuring that
270	 * %emi_pending_req, %emi_ev_cpl and %emi_seq are protected by the
271	 * en_eslp lock.
272	 */
273	EFSYS_LOCK(enp->en_eslp, state);
274	EFSYS_ASSERT(emip->emi_pending_req == NULL);
275	emip->emi_pending_req = emrp;
276	emip->emi_ev_cpl = ev_cpl;
277	emip->emi_poll_cnt = 0;
278	seq = emip->emi_seq++ & EFX_MASK32(MCDI_HEADER_SEQ);
279	new_epoch = emip->emi_new_epoch;
280	max_version = emip->emi_max_version;
281	EFSYS_UNLOCK(enp->en_eslp, state);
282
283	xflags = 0;
284	if (ev_cpl)
285		xflags |= MCDI_HEADER_XFLAGS_EVREQ;
286
287	/*
288	 * Huntington firmware supports MCDIv2, but the Huntington BootROM only
289	 * supports MCDIv1. Use MCDIv1 headers for MCDIv1 commands where
290	 * possible to support this.
291	 */
292	if ((max_version >= 2) &&
293	    ((emrp->emr_cmd > MC_CMD_CMD_SPACE_ESCAPE_7) ||
294	    (emrp->emr_in_length > MCDI_CTL_SDU_LEN_MAX_V1))) {
295		/* Construct MCDI v2 header */
296		hdr_len = sizeof (hdr);
297		EFX_POPULATE_DWORD_8(hdr[0],
298		    MCDI_HEADER_CODE, MC_CMD_V2_EXTN,
299		    MCDI_HEADER_RESYNC, 1,
300		    MCDI_HEADER_DATALEN, 0,
301		    MCDI_HEADER_SEQ, seq,
302		    MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
303		    MCDI_HEADER_ERROR, 0,
304		    MCDI_HEADER_RESPONSE, 0,
305		    MCDI_HEADER_XFLAGS, xflags);
306
307		EFX_POPULATE_DWORD_2(hdr[1],
308		    MC_CMD_V2_EXTN_IN_EXTENDED_CMD, emrp->emr_cmd,
309		    MC_CMD_V2_EXTN_IN_ACTUAL_LEN, emrp->emr_in_length);
310	} else {
311		/* Construct MCDI v1 header */
312		hdr_len = sizeof (hdr[0]);
313		EFX_POPULATE_DWORD_8(hdr[0],
314		    MCDI_HEADER_CODE, emrp->emr_cmd,
315		    MCDI_HEADER_RESYNC, 1,
316		    MCDI_HEADER_DATALEN, emrp->emr_in_length,
317		    MCDI_HEADER_SEQ, seq,
318		    MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
319		    MCDI_HEADER_ERROR, 0,
320		    MCDI_HEADER_RESPONSE, 0,
321		    MCDI_HEADER_XFLAGS, xflags);
322	}
323
324#if EFSYS_OPT_MCDI_LOGGING
325	if (emtp->emt_logger != NULL) {
326		emtp->emt_logger(emtp->emt_context, EFX_LOG_MCDI_REQUEST,
327		    &hdr, hdr_len,
328		    emrp->emr_in_buf, emrp->emr_in_length);
329	}
330#endif /* EFSYS_OPT_MCDI_LOGGING */
331
332	efx_mcdi_send_request(enp, &hdr[0], hdr_len,
333	    emrp->emr_in_buf, emrp->emr_in_length);
334}
335
336
337static			void
338efx_mcdi_read_response_header(
339	__in		efx_nic_t *enp,
340	__inout		efx_mcdi_req_t *emrp)
341{
342#if EFSYS_OPT_MCDI_LOGGING
343	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
344#endif /* EFSYS_OPT_MCDI_LOGGING */
345	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
346	efx_dword_t hdr[2];
347	unsigned int hdr_len;
348	unsigned int data_len;
349	unsigned int seq;
350	unsigned int cmd;
351	unsigned int error;
352	efx_rc_t rc;
353
354	EFSYS_ASSERT(emrp != NULL);
355
356	efx_mcdi_read_response(enp, &hdr[0], 0, sizeof (hdr[0]));
357	hdr_len = sizeof (hdr[0]);
358
359	cmd = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE);
360	seq = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_SEQ);
361	error = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_ERROR);
362
363	if (cmd != MC_CMD_V2_EXTN) {
364		data_len = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_DATALEN);
365	} else {
366		efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1]));
367		hdr_len += sizeof (hdr[1]);
368
369		cmd = EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_EXTENDED_CMD);
370		data_len =
371		    EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
372	}
373
374	if (error && (data_len == 0)) {
375		/* The MC has rebooted since the request was sent. */
376		EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
377		efx_mcdi_poll_reboot(enp);
378		rc = EIO;
379		goto fail1;
380	}
381	if ((cmd != emrp->emr_cmd) ||
382	    (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
383		/* Response is for a different request */
384		rc = EIO;
385		goto fail2;
386	}
387	if (error) {
388		efx_dword_t err[2];
389		unsigned int err_len = MIN(data_len, sizeof (err));
390		int err_code = MC_CMD_ERR_EPROTO;
391		int err_arg = 0;
392
393		/* Read error code (and arg num for MCDI v2 commands) */
394		efx_mcdi_read_response(enp, &err, hdr_len, err_len);
395
396		if (err_len >= (MC_CMD_ERR_CODE_OFST + sizeof (efx_dword_t)))
397			err_code = EFX_DWORD_FIELD(err[0], EFX_DWORD_0);
398#ifdef WITH_MCDI_V2
399		if (err_len >= (MC_CMD_ERR_ARG_OFST + sizeof (efx_dword_t)))
400			err_arg = EFX_DWORD_FIELD(err[1], EFX_DWORD_0);
401#endif
402		emrp->emr_err_code = err_code;
403		emrp->emr_err_arg = err_arg;
404
405#if EFSYS_OPT_MCDI_PROXY_AUTH
406		if ((err_code == MC_CMD_ERR_PROXY_PENDING) &&
407		    (err_len == sizeof (err))) {
408			/*
409			 * The MCDI request would normally fail with EPERM, but
410			 * firmware has forwarded it to an authorization agent
411			 * attached to a privileged PF.
412			 *
413			 * Save the authorization request handle. The client
414			 * must wait for a PROXY_RESPONSE event, or timeout.
415			 */
416			emrp->emr_proxy_handle = err_arg;
417		}
418#endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
419
420#if EFSYS_OPT_MCDI_LOGGING
421		if (emtp->emt_logger != NULL) {
422			emtp->emt_logger(emtp->emt_context,
423			    EFX_LOG_MCDI_RESPONSE,
424			    &hdr, hdr_len,
425			    &err, err_len);
426		}
427#endif /* EFSYS_OPT_MCDI_LOGGING */
428
429		if (!emrp->emr_quiet) {
430			EFSYS_PROBE3(mcdi_err_arg, int, emrp->emr_cmd,
431			    int, err_code, int, err_arg);
432		}
433
434		rc = efx_mcdi_request_errcode(err_code);
435		goto fail3;
436	}
437
438	emrp->emr_rc = 0;
439	emrp->emr_out_length_used = data_len;
440#if EFSYS_OPT_MCDI_PROXY_AUTH
441	emrp->emr_proxy_handle = 0;
442#endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
443	return;
444
445fail3:
446fail2:
447fail1:
448	emrp->emr_rc = rc;
449	emrp->emr_out_length_used = 0;
450}
451
452static			void
453efx_mcdi_finish_response(
454	__in		efx_nic_t *enp,
455	__in		efx_mcdi_req_t *emrp)
456{
457#if EFSYS_OPT_MCDI_LOGGING
458	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
459#endif /* EFSYS_OPT_MCDI_LOGGING */
460	efx_dword_t hdr[2];
461	unsigned int hdr_len;
462	size_t bytes;
463
464	if (emrp->emr_out_buf == NULL)
465		return;
466
467	/* Read the command header to detect MCDI response format */
468	hdr_len = sizeof (hdr[0]);
469	efx_mcdi_read_response(enp, &hdr[0], 0, hdr_len);
470	if (EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) {
471		/*
472		 * Read the actual payload length. The length given in the event
473		 * is only correct for responses with the V1 format.
474		 */
475		efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1]));
476		hdr_len += sizeof (hdr[1]);
477
478		emrp->emr_out_length_used = EFX_DWORD_FIELD(hdr[1],
479					    MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
480	}
481
482	/* Copy payload out into caller supplied buffer */
483	bytes = MIN(emrp->emr_out_length_used, emrp->emr_out_length);
484	efx_mcdi_read_response(enp, emrp->emr_out_buf, hdr_len, bytes);
485
486#if EFSYS_OPT_MCDI_LOGGING
487	if (emtp->emt_logger != NULL) {
488		emtp->emt_logger(emtp->emt_context,
489		    EFX_LOG_MCDI_RESPONSE,
490		    &hdr, hdr_len,
491		    emrp->emr_out_buf, bytes);
492	}
493#endif /* EFSYS_OPT_MCDI_LOGGING */
494}
495
496
497	__checkReturn	boolean_t
498efx_mcdi_request_poll(
499	__in		efx_nic_t *enp)
500{
501	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
502	efx_mcdi_req_t *emrp;
503	int state;
504	efx_rc_t rc;
505
506	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
507	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
508	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
509
510	/* Serialise against post-watchdog efx_mcdi_ev* */
511	EFSYS_LOCK(enp->en_eslp, state);
512
513	EFSYS_ASSERT(emip->emi_pending_req != NULL);
514	EFSYS_ASSERT(!emip->emi_ev_cpl);
515	emrp = emip->emi_pending_req;
516
517	/* Check for reboot atomically w.r.t efx_mcdi_request_start */
518	if (emip->emi_poll_cnt++ == 0) {
519		if ((rc = efx_mcdi_poll_reboot(enp)) != 0) {
520			emip->emi_pending_req = NULL;
521			EFSYS_UNLOCK(enp->en_eslp, state);
522
523			/* Reboot/Assertion */
524			if (rc == EIO || rc == EINTR)
525				efx_mcdi_raise_exception(enp, emrp, rc);
526
527			goto fail1;
528		}
529	}
530
531	/* Check if a response is available */
532	if (efx_mcdi_poll_response(enp) == B_FALSE) {
533		EFSYS_UNLOCK(enp->en_eslp, state);
534		return (B_FALSE);
535	}
536
537	/* Read the response header */
538	efx_mcdi_read_response_header(enp, emrp);
539
540	/* Request complete */
541	emip->emi_pending_req = NULL;
542
543	/* Ensure stale MCDI requests fail after an MC reboot. */
544	emip->emi_new_epoch = B_FALSE;
545
546	EFSYS_UNLOCK(enp->en_eslp, state);
547
548	if ((rc = emrp->emr_rc) != 0)
549		goto fail2;
550
551	efx_mcdi_finish_response(enp, emrp);
552	return (B_TRUE);
553
554fail2:
555	if (!emrp->emr_quiet)
556		EFSYS_PROBE(fail2);
557fail1:
558	if (!emrp->emr_quiet)
559		EFSYS_PROBE1(fail1, efx_rc_t, rc);
560
561	return (B_TRUE);
562}
563
564	__checkReturn	boolean_t
565efx_mcdi_request_abort(
566	__in		efx_nic_t *enp)
567{
568	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
569	efx_mcdi_req_t *emrp;
570	boolean_t aborted;
571	int state;
572
573	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
574	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
575	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
576
577	/*
578	 * efx_mcdi_ev_* may have already completed this event, and be
579	 * spinning/blocked on the upper layer lock. So it *is* legitimate
580	 * to for emi_pending_req to be NULL. If there is a pending event
581	 * completed request, then provide a "credit" to allow
582	 * efx_mcdi_ev_cpl() to accept a single spurious completion.
583	 */
584	EFSYS_LOCK(enp->en_eslp, state);
585	emrp = emip->emi_pending_req;
586	aborted = (emrp != NULL);
587	if (aborted) {
588		emip->emi_pending_req = NULL;
589
590		/* Error the request */
591		emrp->emr_out_length_used = 0;
592		emrp->emr_rc = ETIMEDOUT;
593
594		/* Provide a credit for seqno/emr_pending_req mismatches */
595		if (emip->emi_ev_cpl)
596			++emip->emi_aborted;
597
598		/*
599		 * The upper layer has called us, so we don't
600		 * need to complete the request.
601		 */
602	}
603	EFSYS_UNLOCK(enp->en_eslp, state);
604
605	return (aborted);
606}
607
608	__checkReturn	efx_rc_t
609efx_mcdi_request_errcode(
610	__in		unsigned int err)
611{
612
613	switch (err) {
614		/* MCDI v1 */
615	case MC_CMD_ERR_EPERM:
616		return (EACCES);
617	case MC_CMD_ERR_ENOENT:
618		return (ENOENT);
619	case MC_CMD_ERR_EINTR:
620		return (EINTR);
621	case MC_CMD_ERR_EACCES:
622		return (EACCES);
623	case MC_CMD_ERR_EBUSY:
624		return (EBUSY);
625	case MC_CMD_ERR_EINVAL:
626		return (EINVAL);
627	case MC_CMD_ERR_EDEADLK:
628		return (EDEADLK);
629	case MC_CMD_ERR_ENOSYS:
630		return (ENOTSUP);
631	case MC_CMD_ERR_ETIME:
632		return (ETIMEDOUT);
633	case MC_CMD_ERR_ENOTSUP:
634		return (ENOTSUP);
635	case MC_CMD_ERR_EALREADY:
636		return (EALREADY);
637
638		/* MCDI v2 */
639	case MC_CMD_ERR_EEXIST:
640		return (EEXIST);
641#ifdef MC_CMD_ERR_EAGAIN
642	case MC_CMD_ERR_EAGAIN:
643		return (EAGAIN);
644#endif
645#ifdef MC_CMD_ERR_ENOSPC
646	case MC_CMD_ERR_ENOSPC:
647		return (ENOSPC);
648#endif
649
650	case MC_CMD_ERR_ALLOC_FAIL:
651		return (ENOMEM);
652	case MC_CMD_ERR_NO_VADAPTOR:
653		return (ENOENT);
654	case MC_CMD_ERR_NO_EVB_PORT:
655		return (ENOENT);
656	case MC_CMD_ERR_NO_VSWITCH:
657		return (ENODEV);
658	case MC_CMD_ERR_VLAN_LIMIT:
659		return (EINVAL);
660	case MC_CMD_ERR_BAD_PCI_FUNC:
661		return (ENODEV);
662	case MC_CMD_ERR_BAD_VLAN_MODE:
663		return (EINVAL);
664	case MC_CMD_ERR_BAD_VSWITCH_TYPE:
665		return (EINVAL);
666	case MC_CMD_ERR_BAD_VPORT_TYPE:
667		return (EINVAL);
668	case MC_CMD_ERR_MAC_EXIST:
669		return (EEXIST);
670
671	case MC_CMD_ERR_PROXY_PENDING:
672		return (EAGAIN);
673
674	default:
675		EFSYS_PROBE1(mc_pcol_error, int, err);
676		return (EIO);
677	}
678}
679
680			void
681efx_mcdi_raise_exception(
682	__in		efx_nic_t *enp,
683	__in_opt	efx_mcdi_req_t *emrp,
684	__in		int rc)
685{
686	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
687	efx_mcdi_exception_t exception;
688
689	/* Reboot or Assertion failure only */
690	EFSYS_ASSERT(rc == EIO || rc == EINTR);
691
692	/*
693	 * If MC_CMD_REBOOT causes a reboot (dependent on parameters),
694	 * then the EIO is not worthy of an exception.
695	 */
696	if (emrp != NULL && emrp->emr_cmd == MC_CMD_REBOOT && rc == EIO)
697		return;
698
699	exception = (rc == EIO)
700		? EFX_MCDI_EXCEPTION_MC_REBOOT
701		: EFX_MCDI_EXCEPTION_MC_BADASSERT;
702
703	emtp->emt_exception(emtp->emt_context, exception);
704}
705
706			void
707efx_mcdi_execute(
708	__in		efx_nic_t *enp,
709	__inout		efx_mcdi_req_t *emrp)
710{
711	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
712
713	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
714	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
715
716	emrp->emr_quiet = B_FALSE;
717	emtp->emt_execute(emtp->emt_context, emrp);
718}
719
720			void
721efx_mcdi_execute_quiet(
722	__in		efx_nic_t *enp,
723	__inout		efx_mcdi_req_t *emrp)
724{
725	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
726
727	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
728	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
729
730	emrp->emr_quiet = B_TRUE;
731	emtp->emt_execute(emtp->emt_context, emrp);
732}
733
734			void
735efx_mcdi_ev_cpl(
736	__in		efx_nic_t *enp,
737	__in		unsigned int seq,
738	__in		unsigned int outlen,
739	__in		int errcode)
740{
741	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
742	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
743	efx_mcdi_req_t *emrp;
744	int state;
745
746	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
747	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
748
749	/*
750	 * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start()
751	 * when we're completing an aborted request.
752	 */
753	EFSYS_LOCK(enp->en_eslp, state);
754	if (emip->emi_pending_req == NULL || !emip->emi_ev_cpl ||
755	    (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
756		EFSYS_ASSERT(emip->emi_aborted > 0);
757		if (emip->emi_aborted > 0)
758			--emip->emi_aborted;
759		EFSYS_UNLOCK(enp->en_eslp, state);
760		return;
761	}
762
763	emrp = emip->emi_pending_req;
764	emip->emi_pending_req = NULL;
765	EFSYS_UNLOCK(enp->en_eslp, state);
766
767	if (emip->emi_max_version >= 2) {
768		/* MCDIv2 response details do not fit into an event. */
769		efx_mcdi_read_response_header(enp, emrp);
770	} else {
771		if (errcode != 0) {
772			if (!emrp->emr_quiet) {
773				EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd,
774				    int, errcode);
775			}
776			emrp->emr_out_length_used = 0;
777			emrp->emr_rc = efx_mcdi_request_errcode(errcode);
778		} else {
779			emrp->emr_out_length_used = outlen;
780			emrp->emr_rc = 0;
781		}
782	}
783	if (errcode == 0) {
784		efx_mcdi_finish_response(enp, emrp);
785	}
786
787	emtp->emt_ev_cpl(emtp->emt_context);
788}
789
790#if EFSYS_OPT_MCDI_PROXY_AUTH
791
792	__checkReturn	efx_rc_t
793efx_mcdi_get_proxy_handle(
794	__in		efx_nic_t *enp,
795	__in		efx_mcdi_req_t *emrp,
796	__out		uint32_t *handlep)
797{
798	efx_rc_t rc;
799
800	/*
801	 * Return proxy handle from MCDI request that returned with error
802	 * MC_MCD_ERR_PROXY_PENDING. This handle is used to wait for a matching
803	 * PROXY_RESPONSE event.
804	 */
805	if ((emrp == NULL) || (handlep == NULL)) {
806		rc = EINVAL;
807		goto fail1;
808	}
809	if ((emrp->emr_rc != 0) &&
810	    (emrp->emr_err_code == MC_CMD_ERR_PROXY_PENDING)) {
811		*handlep = emrp->emr_proxy_handle;
812		rc = 0;
813	} else {
814		*handlep = 0;
815		rc = ENOENT;
816	}
817	return (rc);
818
819fail1:
820	EFSYS_PROBE1(fail1, efx_rc_t, rc);
821	return (rc);
822}
823
824			void
825efx_mcdi_ev_proxy_response(
826	__in		efx_nic_t *enp,
827	__in		unsigned int handle,
828	__in		unsigned int status)
829{
830	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
831	efx_rc_t rc;
832
833	/*
834	 * Handle results of an authorization request for a privileged MCDI
835	 * command. If authorization was granted then we must re-issue the
836	 * original MCDI request. If authorization failed or timed out,
837	 * then the original MCDI request should be completed with the
838	 * result code from this event.
839	 */
840	rc = (status == 0) ? 0 : efx_mcdi_request_errcode(status);
841
842	emtp->emt_ev_proxy_response(emtp->emt_context, handle, rc);
843}
844#endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
845
846			void
847efx_mcdi_ev_death(
848	__in		efx_nic_t *enp,
849	__in		int rc)
850{
851	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
852	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
853	efx_mcdi_req_t *emrp = NULL;
854	boolean_t ev_cpl;
855	int state;
856
857	/*
858	 * The MCDI request (if there is one) has been terminated, either
859	 * by a BADASSERT or REBOOT event.
860	 *
861	 * If there is an outstanding event-completed MCDI operation, then we
862	 * will never receive the completion event (because both MCDI
863	 * completions and BADASSERT events are sent to the same evq). So
864	 * complete this MCDI op.
865	 *
866	 * This function might run in parallel with efx_mcdi_request_poll()
867	 * for poll completed mcdi requests, and also with
868	 * efx_mcdi_request_start() for post-watchdog completions.
869	 */
870	EFSYS_LOCK(enp->en_eslp, state);
871	emrp = emip->emi_pending_req;
872	ev_cpl = emip->emi_ev_cpl;
873	if (emrp != NULL && emip->emi_ev_cpl) {
874		emip->emi_pending_req = NULL;
875
876		emrp->emr_out_length_used = 0;
877		emrp->emr_rc = rc;
878		++emip->emi_aborted;
879	}
880
881	/*
882	 * Since we're running in parallel with a request, consume the
883	 * status word before dropping the lock.
884	 */
885	if (rc == EIO || rc == EINTR) {
886		EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
887		(void) efx_mcdi_poll_reboot(enp);
888		emip->emi_new_epoch = B_TRUE;
889	}
890
891	EFSYS_UNLOCK(enp->en_eslp, state);
892
893	efx_mcdi_raise_exception(enp, emrp, rc);
894
895	if (emrp != NULL && ev_cpl)
896		emtp->emt_ev_cpl(emtp->emt_context);
897}
898
899	__checkReturn		efx_rc_t
900efx_mcdi_version(
901	__in			efx_nic_t *enp,
902	__out_ecount_opt(4)	uint16_t versionp[4],
903	__out_opt		uint32_t *buildp,
904	__out_opt		efx_mcdi_boot_t *statusp)
905{
906	efx_mcdi_req_t req;
907	uint8_t payload[MAX(MAX(MC_CMD_GET_VERSION_IN_LEN,
908				MC_CMD_GET_VERSION_OUT_LEN),
909			    MAX(MC_CMD_GET_BOOT_STATUS_IN_LEN,
910				MC_CMD_GET_BOOT_STATUS_OUT_LEN))];
911	efx_word_t *ver_words;
912	uint16_t version[4];
913	uint32_t build;
914	efx_mcdi_boot_t status;
915	efx_rc_t rc;
916
917	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
918
919	(void) memset(payload, 0, sizeof (payload));
920	req.emr_cmd = MC_CMD_GET_VERSION;
921	req.emr_in_buf = payload;
922	req.emr_in_length = MC_CMD_GET_VERSION_IN_LEN;
923	req.emr_out_buf = payload;
924	req.emr_out_length = MC_CMD_GET_VERSION_OUT_LEN;
925
926	efx_mcdi_execute(enp, &req);
927
928	if (req.emr_rc != 0) {
929		rc = req.emr_rc;
930		goto fail1;
931	}
932
933	/* bootrom support */
934	if (req.emr_out_length_used == MC_CMD_GET_VERSION_V0_OUT_LEN) {
935		version[0] = version[1] = version[2] = version[3] = 0;
936		build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
937
938		goto version;
939	}
940
941	if (req.emr_out_length_used < MC_CMD_GET_VERSION_OUT_LEN) {
942		rc = EMSGSIZE;
943		goto fail2;
944	}
945
946	ver_words = MCDI_OUT2(req, efx_word_t, GET_VERSION_OUT_VERSION);
947	version[0] = EFX_WORD_FIELD(ver_words[0], EFX_WORD_0);
948	version[1] = EFX_WORD_FIELD(ver_words[1], EFX_WORD_0);
949	version[2] = EFX_WORD_FIELD(ver_words[2], EFX_WORD_0);
950	version[3] = EFX_WORD_FIELD(ver_words[3], EFX_WORD_0);
951	build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
952
953version:
954	/* The bootrom doesn't understand BOOT_STATUS */
955	if (MC_FW_VERSION_IS_BOOTLOADER(build)) {
956		status = EFX_MCDI_BOOT_ROM;
957		goto out;
958	}
959
960	(void) memset(payload, 0, sizeof (payload));
961	req.emr_cmd = MC_CMD_GET_BOOT_STATUS;
962	req.emr_in_buf = payload;
963	req.emr_in_length = MC_CMD_GET_BOOT_STATUS_IN_LEN;
964	req.emr_out_buf = payload;
965	req.emr_out_length = MC_CMD_GET_BOOT_STATUS_OUT_LEN;
966
967	efx_mcdi_execute_quiet(enp, &req);
968
969	if (req.emr_rc == EACCES) {
970		/* Unprivileged functions cannot access BOOT_STATUS */
971		status = EFX_MCDI_BOOT_PRIMARY;
972		version[0] = version[1] = version[2] = version[3] = 0;
973		build = 0;
974		goto out;
975	}
976
977	if (req.emr_rc != 0) {
978		rc = req.emr_rc;
979		goto fail3;
980	}
981
982	if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) {
983		rc = EMSGSIZE;
984		goto fail4;
985	}
986
987	if (MCDI_OUT_DWORD_FIELD(req, GET_BOOT_STATUS_OUT_FLAGS,
988	    GET_BOOT_STATUS_OUT_FLAGS_PRIMARY))
989		status = EFX_MCDI_BOOT_PRIMARY;
990	else
991		status = EFX_MCDI_BOOT_SECONDARY;
992
993out:
994	if (versionp != NULL)
995		memcpy(versionp, version, sizeof (version));
996	if (buildp != NULL)
997		*buildp = build;
998	if (statusp != NULL)
999		*statusp = status;
1000
1001	return (0);
1002
1003fail4:
1004	EFSYS_PROBE(fail4);
1005fail3:
1006	EFSYS_PROBE(fail3);
1007fail2:
1008	EFSYS_PROBE(fail2);
1009fail1:
1010	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1011
1012	return (rc);
1013}
1014
1015static	__checkReturn	efx_rc_t
1016efx_mcdi_do_reboot(
1017	__in		efx_nic_t *enp,
1018	__in		boolean_t after_assertion)
1019{
1020	uint8_t payload[MAX(MC_CMD_REBOOT_IN_LEN, MC_CMD_REBOOT_OUT_LEN)];
1021	efx_mcdi_req_t req;
1022	efx_rc_t rc;
1023
1024	/*
1025	 * We could require the caller to have caused en_mod_flags=0 to
1026	 * call this function. This doesn't help the other port though,
1027	 * who's about to get the MC ripped out from underneath them.
1028	 * Since they have to cope with the subsequent fallout of MCDI
1029	 * failures, we should as well.
1030	 */
1031	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1032
1033	(void) memset(payload, 0, sizeof (payload));
1034	req.emr_cmd = MC_CMD_REBOOT;
1035	req.emr_in_buf = payload;
1036	req.emr_in_length = MC_CMD_REBOOT_IN_LEN;
1037	req.emr_out_buf = payload;
1038	req.emr_out_length = MC_CMD_REBOOT_OUT_LEN;
1039
1040	MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS,
1041	    (after_assertion ? MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION : 0));
1042
1043	efx_mcdi_execute_quiet(enp, &req);
1044
1045	if (req.emr_rc == EACCES) {
1046		/* Unprivileged functions cannot reboot the MC. */
1047		goto out;
1048	}
1049
1050	/* A successful reboot request returns EIO. */
1051	if (req.emr_rc != 0 && req.emr_rc != EIO) {
1052		rc = req.emr_rc;
1053		goto fail1;
1054	}
1055
1056out:
1057	return (0);
1058
1059fail1:
1060	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1061
1062	return (rc);
1063}
1064
1065	__checkReturn	efx_rc_t
1066efx_mcdi_reboot(
1067	__in		efx_nic_t *enp)
1068{
1069	return (efx_mcdi_do_reboot(enp, B_FALSE));
1070}
1071
1072	__checkReturn	efx_rc_t
1073efx_mcdi_exit_assertion_handler(
1074	__in		efx_nic_t *enp)
1075{
1076	return (efx_mcdi_do_reboot(enp, B_TRUE));
1077}
1078
1079	__checkReturn	efx_rc_t
1080efx_mcdi_read_assertion(
1081	__in		efx_nic_t *enp)
1082{
1083	efx_mcdi_req_t req;
1084	uint8_t payload[MAX(MC_CMD_GET_ASSERTS_IN_LEN,
1085			    MC_CMD_GET_ASSERTS_OUT_LEN)];
1086	const char *reason;
1087	unsigned int flags;
1088	unsigned int index;
1089	unsigned int ofst;
1090	int retry;
1091	efx_rc_t rc;
1092
1093	/*
1094	 * Before we attempt to chat to the MC, we should verify that the MC
1095	 * isn't in it's assertion handler, either due to a previous reboot,
1096	 * or because we're reinitializing due to an eec_exception().
1097	 *
1098	 * Use GET_ASSERTS to read any assertion state that may be present.
1099	 * Retry this command twice. Once because a boot-time assertion failure
1100	 * might cause the 1st MCDI request to fail. And once again because
1101	 * we might race with efx_mcdi_exit_assertion_handler() running on
1102	 * partner port(s) on the same NIC.
1103	 */
1104	retry = 2;
1105	do {
1106		(void) memset(payload, 0, sizeof (payload));
1107		req.emr_cmd = MC_CMD_GET_ASSERTS;
1108		req.emr_in_buf = payload;
1109		req.emr_in_length = MC_CMD_GET_ASSERTS_IN_LEN;
1110		req.emr_out_buf = payload;
1111		req.emr_out_length = MC_CMD_GET_ASSERTS_OUT_LEN;
1112
1113		MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1);
1114		efx_mcdi_execute_quiet(enp, &req);
1115
1116	} while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0);
1117
1118	if (req.emr_rc != 0) {
1119		if (req.emr_rc == EACCES) {
1120			/* Unprivileged functions cannot clear assertions. */
1121			goto out;
1122		}
1123		rc = req.emr_rc;
1124		goto fail1;
1125	}
1126
1127	if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) {
1128		rc = EMSGSIZE;
1129		goto fail2;
1130	}
1131
1132	/* Print out any assertion state recorded */
1133	flags = MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_GLOBAL_FLAGS);
1134	if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
1135		return (0);
1136
1137	reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
1138		? "system-level assertion"
1139		: (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
1140		? "thread-level assertion"
1141		: (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
1142		? "watchdog reset"
1143		: (flags == MC_CMD_GET_ASSERTS_FLAGS_ADDR_TRAP)
1144		? "illegal address trap"
1145		: "unknown assertion";
1146	EFSYS_PROBE3(mcpu_assertion,
1147	    const char *, reason, unsigned int,
1148	    MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_SAVED_PC_OFFS),
1149	    unsigned int,
1150	    MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS));
1151
1152	/* Print out the registers (r1 ... r31) */
1153	ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST;
1154	for (index = 1;
1155		index < 1 + MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM;
1156		index++) {
1157		EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int,
1158			    EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst),
1159					    EFX_DWORD_0));
1160		ofst += sizeof (efx_dword_t);
1161	}
1162	EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN);
1163
1164out:
1165	return (0);
1166
1167fail2:
1168	EFSYS_PROBE(fail2);
1169fail1:
1170	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1171
1172	return (rc);
1173}
1174
1175
1176/*
1177 * Internal routines for for specific MCDI requests.
1178 */
1179
1180	__checkReturn	efx_rc_t
1181efx_mcdi_drv_attach(
1182	__in		efx_nic_t *enp,
1183	__in		boolean_t attach)
1184{
1185	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1186	efx_mcdi_req_t req;
1187	uint8_t payload[MAX(MC_CMD_DRV_ATTACH_IN_LEN,
1188			    MC_CMD_DRV_ATTACH_EXT_OUT_LEN)];
1189	uint32_t flags;
1190	efx_rc_t rc;
1191
1192	(void) memset(payload, 0, sizeof (payload));
1193	req.emr_cmd = MC_CMD_DRV_ATTACH;
1194	req.emr_in_buf = payload;
1195	req.emr_in_length = MC_CMD_DRV_ATTACH_IN_LEN;
1196	req.emr_out_buf = payload;
1197	req.emr_out_length = MC_CMD_DRV_ATTACH_EXT_OUT_LEN;
1198
1199	/*
1200	 * Use DONT_CARE for the datapath firmware type to ensure that the
1201	 * driver can attach to an unprivileged function. The datapath firmware
1202	 * type to use is controlled by the 'sfboot' utility.
1203	 */
1204	MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_NEW_STATE, attach ? 1 : 0);
1205	MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_UPDATE, 1);
1206	MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_FIRMWARE_ID, MC_CMD_FW_DONT_CARE);
1207
1208	efx_mcdi_execute(enp, &req);
1209
1210	if (req.emr_rc != 0) {
1211		rc = req.emr_rc;
1212		goto fail1;
1213	}
1214
1215	if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) {
1216		rc = EMSGSIZE;
1217		goto fail2;
1218	}
1219
1220	if (attach == B_FALSE) {
1221		flags = 0;
1222	} else if (enp->en_family == EFX_FAMILY_SIENA) {
1223		efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
1224
1225		/* Create synthetic privileges for Siena functions */
1226		flags = EFX_NIC_FUNC_LINKCTRL | EFX_NIC_FUNC_TRUSTED;
1227		if (emip->emi_port == 1)
1228			flags |= EFX_NIC_FUNC_PRIMARY;
1229	} else {
1230		EFX_STATIC_ASSERT(EFX_NIC_FUNC_PRIMARY ==
1231		    (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_PRIMARY));
1232		EFX_STATIC_ASSERT(EFX_NIC_FUNC_LINKCTRL ==
1233		    (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL));
1234		EFX_STATIC_ASSERT(EFX_NIC_FUNC_TRUSTED ==
1235		    (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED));
1236
1237		/* Save function privilege flags (EF10 and later) */
1238		if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_EXT_OUT_LEN) {
1239			rc = EMSGSIZE;
1240			goto fail3;
1241		}
1242		flags = MCDI_OUT_DWORD(req, DRV_ATTACH_EXT_OUT_FUNC_FLAGS);
1243	}
1244	encp->enc_func_flags = flags;
1245
1246	return (0);
1247
1248fail3:
1249	EFSYS_PROBE(fail3);
1250fail2:
1251	EFSYS_PROBE(fail2);
1252fail1:
1253	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1254
1255	return (rc);
1256}
1257
1258	__checkReturn		efx_rc_t
1259efx_mcdi_get_board_cfg(
1260	__in			efx_nic_t *enp,
1261	__out_opt		uint32_t *board_typep,
1262	__out_opt		efx_dword_t *capabilitiesp,
1263	__out_ecount_opt(6)	uint8_t mac_addrp[6])
1264{
1265	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
1266	efx_mcdi_req_t req;
1267	uint8_t payload[MAX(MC_CMD_GET_BOARD_CFG_IN_LEN,
1268			    MC_CMD_GET_BOARD_CFG_OUT_LENMIN)];
1269	efx_rc_t rc;
1270
1271	(void) memset(payload, 0, sizeof (payload));
1272	req.emr_cmd = MC_CMD_GET_BOARD_CFG;
1273	req.emr_in_buf = payload;
1274	req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN;
1275	req.emr_out_buf = payload;
1276	req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMIN;
1277
1278	efx_mcdi_execute(enp, &req);
1279
1280	if (req.emr_rc != 0) {
1281		rc = req.emr_rc;
1282		goto fail1;
1283	}
1284
1285	if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
1286		rc = EMSGSIZE;
1287		goto fail2;
1288	}
1289
1290	if (mac_addrp != NULL) {
1291		uint8_t *addrp;
1292
1293		if (emip->emi_port == 1) {
1294			addrp = MCDI_OUT2(req, uint8_t,
1295			    GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0);
1296		} else if (emip->emi_port == 2) {
1297			addrp = MCDI_OUT2(req, uint8_t,
1298			    GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1);
1299		} else {
1300			rc = EINVAL;
1301			goto fail3;
1302		}
1303
1304		EFX_MAC_ADDR_COPY(mac_addrp, addrp);
1305	}
1306
1307	if (capabilitiesp != NULL) {
1308		if (emip->emi_port == 1) {
1309			*capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
1310			    GET_BOARD_CFG_OUT_CAPABILITIES_PORT0);
1311		} else if (emip->emi_port == 2) {
1312			*capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
1313			    GET_BOARD_CFG_OUT_CAPABILITIES_PORT1);
1314		} else {
1315			rc = EINVAL;
1316			goto fail4;
1317		}
1318	}
1319
1320	if (board_typep != NULL) {
1321		*board_typep = MCDI_OUT_DWORD(req,
1322		    GET_BOARD_CFG_OUT_BOARD_TYPE);
1323	}
1324
1325	return (0);
1326
1327fail4:
1328	EFSYS_PROBE(fail4);
1329fail3:
1330	EFSYS_PROBE(fail3);
1331fail2:
1332	EFSYS_PROBE(fail2);
1333fail1:
1334	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1335
1336	return (rc);
1337}
1338
1339	__checkReturn	efx_rc_t
1340efx_mcdi_get_resource_limits(
1341	__in		efx_nic_t *enp,
1342	__out_opt	uint32_t *nevqp,
1343	__out_opt	uint32_t *nrxqp,
1344	__out_opt	uint32_t *ntxqp)
1345{
1346	efx_mcdi_req_t req;
1347	uint8_t payload[MAX(MC_CMD_GET_RESOURCE_LIMITS_IN_LEN,
1348			    MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN)];
1349	efx_rc_t rc;
1350
1351	(void) memset(payload, 0, sizeof (payload));
1352	req.emr_cmd = MC_CMD_GET_RESOURCE_LIMITS;
1353	req.emr_in_buf = payload;
1354	req.emr_in_length = MC_CMD_GET_RESOURCE_LIMITS_IN_LEN;
1355	req.emr_out_buf = payload;
1356	req.emr_out_length = MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN;
1357
1358	efx_mcdi_execute(enp, &req);
1359
1360	if (req.emr_rc != 0) {
1361		rc = req.emr_rc;
1362		goto fail1;
1363	}
1364
1365	if (req.emr_out_length_used < MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) {
1366		rc = EMSGSIZE;
1367		goto fail2;
1368	}
1369
1370	if (nevqp != NULL)
1371		*nevqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_EVQ);
1372	if (nrxqp != NULL)
1373		*nrxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ);
1374	if (ntxqp != NULL)
1375		*ntxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ);
1376
1377	return (0);
1378
1379fail2:
1380	EFSYS_PROBE(fail2);
1381fail1:
1382	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1383
1384	return (rc);
1385}
1386
1387	__checkReturn	efx_rc_t
1388efx_mcdi_get_phy_cfg(
1389	__in		efx_nic_t *enp)
1390{
1391	efx_port_t *epp = &(enp->en_port);
1392	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1393	efx_mcdi_req_t req;
1394	uint8_t payload[MAX(MC_CMD_GET_PHY_CFG_IN_LEN,
1395			    MC_CMD_GET_PHY_CFG_OUT_LEN)];
1396	efx_rc_t rc;
1397
1398	(void) memset(payload, 0, sizeof (payload));
1399	req.emr_cmd = MC_CMD_GET_PHY_CFG;
1400	req.emr_in_buf = payload;
1401	req.emr_in_length = MC_CMD_GET_PHY_CFG_IN_LEN;
1402	req.emr_out_buf = payload;
1403	req.emr_out_length = MC_CMD_GET_PHY_CFG_OUT_LEN;
1404
1405	efx_mcdi_execute(enp, &req);
1406
1407	if (req.emr_rc != 0) {
1408		rc = req.emr_rc;
1409		goto fail1;
1410	}
1411
1412	if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) {
1413		rc = EMSGSIZE;
1414		goto fail2;
1415	}
1416
1417	encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE);
1418#if EFSYS_OPT_NAMES
1419	(void) strncpy(encp->enc_phy_name,
1420		MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME),
1421		MIN(sizeof (encp->enc_phy_name) - 1,
1422		    MC_CMD_GET_PHY_CFG_OUT_NAME_LEN));
1423#endif	/* EFSYS_OPT_NAMES */
1424	(void) memset(encp->enc_phy_revision, 0,
1425	    sizeof (encp->enc_phy_revision));
1426	memcpy(encp->enc_phy_revision,
1427		MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION),
1428		MIN(sizeof (encp->enc_phy_revision) - 1,
1429		    MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN));
1430#if EFSYS_OPT_PHY_LED_CONTROL
1431	encp->enc_led_mask = ((1 << EFX_PHY_LED_DEFAULT) |
1432			    (1 << EFX_PHY_LED_OFF) |
1433			    (1 << EFX_PHY_LED_ON));
1434#endif	/* EFSYS_OPT_PHY_LED_CONTROL */
1435
1436	/* Get the media type of the fixed port, if recognised. */
1437	EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI);
1438	EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4);
1439	EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4);
1440	EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP);
1441	EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS);
1442	EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T);
1443	EFX_STATIC_ASSERT(MC_CMD_MEDIA_QSFP_PLUS == EFX_PHY_MEDIA_QSFP_PLUS);
1444	epp->ep_fixed_port_type =
1445		MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE);
1446	if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES)
1447		epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID;
1448
1449	epp->ep_phy_cap_mask =
1450		MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP);
1451#if EFSYS_OPT_PHY_FLAGS
1452	encp->enc_phy_flags_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_FLAGS);
1453#endif	/* EFSYS_OPT_PHY_FLAGS */
1454
1455	encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT);
1456
1457	/* Populate internal state */
1458	encp->enc_mcdi_mdio_channel =
1459		(uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL);
1460
1461#if EFSYS_OPT_PHY_STATS
1462	encp->enc_mcdi_phy_stat_mask =
1463		MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_STATS_MASK);
1464#endif	/* EFSYS_OPT_PHY_STATS */
1465
1466#if EFSYS_OPT_BIST
1467	encp->enc_bist_mask = 0;
1468	if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1469	    GET_PHY_CFG_OUT_BIST_CABLE_SHORT))
1470		encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_SHORT);
1471	if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1472	    GET_PHY_CFG_OUT_BIST_CABLE_LONG))
1473		encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_LONG);
1474	if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1475	    GET_PHY_CFG_OUT_BIST))
1476		encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_NORMAL);
1477#endif  /* EFSYS_OPT_BIST */
1478
1479	return (0);
1480
1481fail2:
1482	EFSYS_PROBE(fail2);
1483fail1:
1484	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1485
1486	return (rc);
1487}
1488
1489	__checkReturn		efx_rc_t
1490efx_mcdi_firmware_update_supported(
1491	__in			efx_nic_t *enp,
1492	__out			boolean_t *supportedp)
1493{
1494	const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1495	efx_rc_t rc;
1496
1497	if (emcop != NULL) {
1498		if ((rc = emcop->emco_feature_supported(enp,
1499			    EFX_MCDI_FEATURE_FW_UPDATE, supportedp)) != 0)
1500			goto fail1;
1501	} else {
1502		/* Earlier devices always supported updates */
1503		*supportedp = B_TRUE;
1504	}
1505
1506	return (0);
1507
1508fail1:
1509	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1510
1511	return (rc);
1512}
1513
1514	__checkReturn		efx_rc_t
1515efx_mcdi_macaddr_change_supported(
1516	__in			efx_nic_t *enp,
1517	__out			boolean_t *supportedp)
1518{
1519	const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1520	efx_rc_t rc;
1521
1522	if (emcop != NULL) {
1523		if ((rc = emcop->emco_feature_supported(enp,
1524			    EFX_MCDI_FEATURE_MACADDR_CHANGE, supportedp)) != 0)
1525			goto fail1;
1526	} else {
1527		/* Earlier devices always supported MAC changes */
1528		*supportedp = B_TRUE;
1529	}
1530
1531	return (0);
1532
1533fail1:
1534	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1535
1536	return (rc);
1537}
1538
1539	__checkReturn		efx_rc_t
1540efx_mcdi_link_control_supported(
1541	__in			efx_nic_t *enp,
1542	__out			boolean_t *supportedp)
1543{
1544	const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1545	efx_rc_t rc;
1546
1547	if (emcop != NULL) {
1548		if ((rc = emcop->emco_feature_supported(enp,
1549			    EFX_MCDI_FEATURE_LINK_CONTROL, supportedp)) != 0)
1550			goto fail1;
1551	} else {
1552		/* Earlier devices always supported link control */
1553		*supportedp = B_TRUE;
1554	}
1555
1556	return (0);
1557
1558fail1:
1559	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1560
1561	return (rc);
1562}
1563
1564	__checkReturn		efx_rc_t
1565efx_mcdi_mac_spoofing_supported(
1566	__in			efx_nic_t *enp,
1567	__out			boolean_t *supportedp)
1568{
1569	const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1570	efx_rc_t rc;
1571
1572	if (emcop != NULL) {
1573		if ((rc = emcop->emco_feature_supported(enp,
1574			    EFX_MCDI_FEATURE_MAC_SPOOFING, supportedp)) != 0)
1575			goto fail1;
1576	} else {
1577		/* Earlier devices always supported MAC spoofing */
1578		*supportedp = B_TRUE;
1579	}
1580
1581	return (0);
1582
1583fail1:
1584	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1585
1586	return (rc);
1587}
1588
1589#if EFSYS_OPT_BIST
1590
1591#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
1592/*
1593 * Enter bist offline mode. This is a fw mode which puts the NIC into a state
1594 * where memory BIST tests can be run and not much else can interfere or happen.
1595 * A reboot is required to exit this mode.
1596 */
1597	__checkReturn		efx_rc_t
1598efx_mcdi_bist_enable_offline(
1599	__in			efx_nic_t *enp)
1600{
1601	efx_mcdi_req_t req;
1602	efx_rc_t rc;
1603
1604	EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_IN_LEN == 0);
1605	EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_OUT_LEN == 0);
1606
1607	req.emr_cmd = MC_CMD_ENABLE_OFFLINE_BIST;
1608	req.emr_in_buf = NULL;
1609	req.emr_in_length = 0;
1610	req.emr_out_buf = NULL;
1611	req.emr_out_length = 0;
1612
1613	efx_mcdi_execute(enp, &req);
1614
1615	if (req.emr_rc != 0) {
1616		rc = req.emr_rc;
1617		goto fail1;
1618	}
1619
1620	return (0);
1621
1622fail1:
1623	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1624
1625	return (rc);
1626}
1627#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
1628
1629	__checkReturn		efx_rc_t
1630efx_mcdi_bist_start(
1631	__in			efx_nic_t *enp,
1632	__in			efx_bist_type_t type)
1633{
1634	efx_mcdi_req_t req;
1635	uint8_t payload[MAX(MC_CMD_START_BIST_IN_LEN,
1636			    MC_CMD_START_BIST_OUT_LEN)];
1637	efx_rc_t rc;
1638
1639	(void) memset(payload, 0, sizeof (payload));
1640	req.emr_cmd = MC_CMD_START_BIST;
1641	req.emr_in_buf = payload;
1642	req.emr_in_length = MC_CMD_START_BIST_IN_LEN;
1643	req.emr_out_buf = payload;
1644	req.emr_out_length = MC_CMD_START_BIST_OUT_LEN;
1645
1646	switch (type) {
1647	case EFX_BIST_TYPE_PHY_NORMAL:
1648		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST);
1649		break;
1650	case EFX_BIST_TYPE_PHY_CABLE_SHORT:
1651		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1652		    MC_CMD_PHY_BIST_CABLE_SHORT);
1653		break;
1654	case EFX_BIST_TYPE_PHY_CABLE_LONG:
1655		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1656		    MC_CMD_PHY_BIST_CABLE_LONG);
1657		break;
1658	case EFX_BIST_TYPE_MC_MEM:
1659		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1660		    MC_CMD_MC_MEM_BIST);
1661		break;
1662	case EFX_BIST_TYPE_SAT_MEM:
1663		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1664		    MC_CMD_PORT_MEM_BIST);
1665		break;
1666	case EFX_BIST_TYPE_REG:
1667		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1668		    MC_CMD_REG_BIST);
1669		break;
1670	default:
1671		EFSYS_ASSERT(0);
1672	}
1673
1674	efx_mcdi_execute(enp, &req);
1675
1676	if (req.emr_rc != 0) {
1677		rc = req.emr_rc;
1678		goto fail1;
1679	}
1680
1681	return (0);
1682
1683fail1:
1684	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1685
1686	return (rc);
1687}
1688
1689#endif /* EFSYS_OPT_BIST */
1690
1691
1692/* Enable logging of some events (e.g. link state changes) */
1693	__checkReturn	efx_rc_t
1694efx_mcdi_log_ctrl(
1695	__in		efx_nic_t *enp)
1696{
1697	efx_mcdi_req_t req;
1698	uint8_t payload[MAX(MC_CMD_LOG_CTRL_IN_LEN,
1699			    MC_CMD_LOG_CTRL_OUT_LEN)];
1700	efx_rc_t rc;
1701
1702	(void) memset(payload, 0, sizeof (payload));
1703	req.emr_cmd = MC_CMD_LOG_CTRL;
1704	req.emr_in_buf = payload;
1705	req.emr_in_length = MC_CMD_LOG_CTRL_IN_LEN;
1706	req.emr_out_buf = payload;
1707	req.emr_out_length = MC_CMD_LOG_CTRL_OUT_LEN;
1708
1709	MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST,
1710		    MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ);
1711	MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST_EVQ, 0);
1712
1713	efx_mcdi_execute(enp, &req);
1714
1715	if (req.emr_rc != 0) {
1716		rc = req.emr_rc;
1717		goto fail1;
1718	}
1719
1720	return (0);
1721
1722fail1:
1723	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1724
1725	return (rc);
1726}
1727
1728
1729#if EFSYS_OPT_MAC_STATS
1730
1731typedef enum efx_stats_action_e {
1732	EFX_STATS_CLEAR,
1733	EFX_STATS_UPLOAD,
1734	EFX_STATS_ENABLE_NOEVENTS,
1735	EFX_STATS_ENABLE_EVENTS,
1736	EFX_STATS_DISABLE,
1737} efx_stats_action_t;
1738
1739static	__checkReturn	efx_rc_t
1740efx_mcdi_mac_stats(
1741	__in		efx_nic_t *enp,
1742	__in_opt	efsys_mem_t *esmp,
1743	__in		efx_stats_action_t action)
1744{
1745	efx_mcdi_req_t req;
1746	uint8_t payload[MAX(MC_CMD_MAC_STATS_IN_LEN,
1747			    MC_CMD_MAC_STATS_OUT_DMA_LEN)];
1748	int clear = (action == EFX_STATS_CLEAR);
1749	int upload = (action == EFX_STATS_UPLOAD);
1750	int enable = (action == EFX_STATS_ENABLE_NOEVENTS);
1751	int events = (action == EFX_STATS_ENABLE_EVENTS);
1752	int disable = (action == EFX_STATS_DISABLE);
1753	efx_rc_t rc;
1754
1755	(void) memset(payload, 0, sizeof (payload));
1756	req.emr_cmd = MC_CMD_MAC_STATS;
1757	req.emr_in_buf = payload;
1758	req.emr_in_length = MC_CMD_MAC_STATS_IN_LEN;
1759	req.emr_out_buf = payload;
1760	req.emr_out_length = MC_CMD_MAC_STATS_OUT_DMA_LEN;
1761
1762	MCDI_IN_POPULATE_DWORD_6(req, MAC_STATS_IN_CMD,
1763	    MAC_STATS_IN_DMA, upload,
1764	    MAC_STATS_IN_CLEAR, clear,
1765	    MAC_STATS_IN_PERIODIC_CHANGE, enable | events | disable,
1766	    MAC_STATS_IN_PERIODIC_ENABLE, enable | events,
1767	    MAC_STATS_IN_PERIODIC_NOEVENT, !events,
1768	    MAC_STATS_IN_PERIOD_MS, (enable | events) ? 1000: 0);
1769
1770	if (esmp != NULL) {
1771		int bytes = MC_CMD_MAC_NSTATS * sizeof (uint64_t);
1772
1773		EFX_STATIC_ASSERT(MC_CMD_MAC_NSTATS * sizeof (uint64_t) <=
1774		    EFX_MAC_STATS_SIZE);
1775
1776		MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_LO,
1777			    EFSYS_MEM_ADDR(esmp) & 0xffffffff);
1778		MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_HI,
1779			    EFSYS_MEM_ADDR(esmp) >> 32);
1780		MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_LEN, bytes);
1781	} else {
1782		EFSYS_ASSERT(!upload && !enable && !events);
1783	}
1784
1785	/*
1786	 * NOTE: Do not use EVB_PORT_ID_ASSIGNED when disabling periodic stats,
1787	 *	 as this may fail (and leave periodic DMA enabled) if the
1788	 *	 vadapter has already been deleted.
1789	 */
1790	MCDI_IN_SET_DWORD(req, MAC_STATS_IN_PORT_ID,
1791	    (disable ? EVB_PORT_ID_NULL : enp->en_vport_id));
1792
1793	efx_mcdi_execute(enp, &req);
1794
1795	if (req.emr_rc != 0) {
1796		/* EF10: Expect ENOENT if no DMA queues are initialised */
1797		if ((req.emr_rc != ENOENT) ||
1798		    (enp->en_rx_qcount + enp->en_tx_qcount != 0)) {
1799			rc = req.emr_rc;
1800			goto fail1;
1801		}
1802	}
1803
1804	return (0);
1805
1806fail1:
1807	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1808
1809	return (rc);
1810}
1811
1812	__checkReturn	efx_rc_t
1813efx_mcdi_mac_stats_clear(
1814	__in		efx_nic_t *enp)
1815{
1816	efx_rc_t rc;
1817
1818	if ((rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_CLEAR)) != 0)
1819		goto fail1;
1820
1821	return (0);
1822
1823fail1:
1824	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1825
1826	return (rc);
1827}
1828
1829	__checkReturn	efx_rc_t
1830efx_mcdi_mac_stats_upload(
1831	__in		efx_nic_t *enp,
1832	__in		efsys_mem_t *esmp)
1833{
1834	efx_rc_t rc;
1835
1836	/*
1837	 * The MC DMAs aggregate statistics for our convenience, so we can
1838	 * avoid having to pull the statistics buffer into the cache to
1839	 * maintain cumulative statistics.
1840	 */
1841	if ((rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_UPLOAD)) != 0)
1842		goto fail1;
1843
1844	return (0);
1845
1846fail1:
1847	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1848
1849	return (rc);
1850}
1851
1852	__checkReturn	efx_rc_t
1853efx_mcdi_mac_stats_periodic(
1854	__in		efx_nic_t *enp,
1855	__in		efsys_mem_t *esmp,
1856	__in		uint16_t period,
1857	__in		boolean_t events)
1858{
1859	efx_rc_t rc;
1860
1861	/*
1862	 * The MC DMAs aggregate statistics for our convenience, so we can
1863	 * avoid having to pull the statistics buffer into the cache to
1864	 * maintain cumulative statistics.
1865	 * Huntington uses a fixed 1sec period, so use that on Siena too.
1866	 */
1867	if (period == 0)
1868		rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_DISABLE);
1869	else if (events)
1870		rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_EVENTS);
1871	else
1872		rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_NOEVENTS);
1873
1874	if (rc != 0)
1875		goto fail1;
1876
1877	return (0);
1878
1879fail1:
1880	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1881
1882	return (rc);
1883}
1884
1885#endif	/* EFSYS_OPT_MAC_STATS */
1886
1887#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
1888
1889/*
1890 * This function returns the pf and vf number of a function.  If it is a pf the
1891 * vf number is 0xffff.  The vf number is the index of the vf on that
1892 * function. So if you have 3 vfs on pf 0 the 3 vfs will return (pf=0,vf=0),
1893 * (pf=0,vf=1), (pf=0,vf=2) aand the pf will return (pf=0, vf=0xffff).
1894 */
1895	__checkReturn		efx_rc_t
1896efx_mcdi_get_function_info(
1897	__in			efx_nic_t *enp,
1898	__out			uint32_t *pfp,
1899	__out_opt		uint32_t *vfp)
1900{
1901	efx_mcdi_req_t req;
1902	uint8_t payload[MAX(MC_CMD_GET_FUNCTION_INFO_IN_LEN,
1903			    MC_CMD_GET_FUNCTION_INFO_OUT_LEN)];
1904	efx_rc_t rc;
1905
1906	(void) memset(payload, 0, sizeof (payload));
1907	req.emr_cmd = MC_CMD_GET_FUNCTION_INFO;
1908	req.emr_in_buf = payload;
1909	req.emr_in_length = MC_CMD_GET_FUNCTION_INFO_IN_LEN;
1910	req.emr_out_buf = payload;
1911	req.emr_out_length = MC_CMD_GET_FUNCTION_INFO_OUT_LEN;
1912
1913	efx_mcdi_execute(enp, &req);
1914
1915	if (req.emr_rc != 0) {
1916		rc = req.emr_rc;
1917		goto fail1;
1918	}
1919
1920	if (req.emr_out_length_used < MC_CMD_GET_FUNCTION_INFO_OUT_LEN) {
1921		rc = EMSGSIZE;
1922		goto fail2;
1923	}
1924
1925	*pfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_PF);
1926	if (vfp != NULL)
1927		*vfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_VF);
1928
1929	return (0);
1930
1931fail2:
1932	EFSYS_PROBE(fail2);
1933fail1:
1934	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1935
1936	return (rc);
1937}
1938
1939	__checkReturn		efx_rc_t
1940efx_mcdi_privilege_mask(
1941	__in			efx_nic_t *enp,
1942	__in			uint32_t pf,
1943	__in			uint32_t vf,
1944	__out			uint32_t *maskp)
1945{
1946	efx_mcdi_req_t req;
1947	uint8_t payload[MAX(MC_CMD_PRIVILEGE_MASK_IN_LEN,
1948			    MC_CMD_PRIVILEGE_MASK_OUT_LEN)];
1949	efx_rc_t rc;
1950
1951	(void) memset(payload, 0, sizeof (payload));
1952	req.emr_cmd = MC_CMD_PRIVILEGE_MASK;
1953	req.emr_in_buf = payload;
1954	req.emr_in_length = MC_CMD_PRIVILEGE_MASK_IN_LEN;
1955	req.emr_out_buf = payload;
1956	req.emr_out_length = MC_CMD_PRIVILEGE_MASK_OUT_LEN;
1957
1958	MCDI_IN_POPULATE_DWORD_2(req, PRIVILEGE_MASK_IN_FUNCTION,
1959	    PRIVILEGE_MASK_IN_FUNCTION_PF, pf,
1960	    PRIVILEGE_MASK_IN_FUNCTION_VF, vf);
1961
1962	efx_mcdi_execute(enp, &req);
1963
1964	if (req.emr_rc != 0) {
1965		rc = req.emr_rc;
1966		goto fail1;
1967	}
1968
1969	if (req.emr_out_length_used < MC_CMD_PRIVILEGE_MASK_OUT_LEN) {
1970		rc = EMSGSIZE;
1971		goto fail2;
1972	}
1973
1974	*maskp = MCDI_OUT_DWORD(req, PRIVILEGE_MASK_OUT_OLD_MASK);
1975
1976	return (0);
1977
1978fail2:
1979	EFSYS_PROBE(fail2);
1980fail1:
1981	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1982
1983	return (rc);
1984}
1985
1986#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
1987
1988	__checkReturn		efx_rc_t
1989efx_mcdi_set_workaround(
1990	__in			efx_nic_t *enp,
1991	__in			uint32_t type,
1992	__in			boolean_t enabled,
1993	__out_opt		uint32_t *flagsp)
1994{
1995	efx_mcdi_req_t req;
1996	uint8_t payload[MAX(MC_CMD_WORKAROUND_IN_LEN,
1997			    MC_CMD_WORKAROUND_EXT_OUT_LEN)];
1998	efx_rc_t rc;
1999
2000	(void) memset(payload, 0, sizeof (payload));
2001	req.emr_cmd = MC_CMD_WORKAROUND;
2002	req.emr_in_buf = payload;
2003	req.emr_in_length = MC_CMD_WORKAROUND_IN_LEN;
2004	req.emr_out_buf = payload;
2005	req.emr_out_length = MC_CMD_WORKAROUND_OUT_LEN;
2006
2007	MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, type);
2008	MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, enabled ? 1 : 0);
2009
2010	efx_mcdi_execute_quiet(enp, &req);
2011
2012	if (req.emr_rc != 0) {
2013		rc = req.emr_rc;
2014		goto fail1;
2015	}
2016
2017	if (flagsp != NULL) {
2018		if (req.emr_out_length_used >= MC_CMD_WORKAROUND_EXT_OUT_LEN)
2019			*flagsp = MCDI_OUT_DWORD(req, WORKAROUND_EXT_OUT_FLAGS);
2020		else
2021			*flagsp = 0;
2022	}
2023
2024	return (0);
2025
2026fail1:
2027	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2028
2029	return (rc);
2030}
2031
2032
2033	__checkReturn		efx_rc_t
2034efx_mcdi_get_workarounds(
2035	__in			efx_nic_t *enp,
2036	__out_opt		uint32_t *implementedp,
2037	__out_opt		uint32_t *enabledp)
2038{
2039	efx_mcdi_req_t req;
2040	uint8_t payload[MC_CMD_GET_WORKAROUNDS_OUT_LEN];
2041	efx_rc_t rc;
2042
2043	(void) memset(payload, 0, sizeof (payload));
2044	req.emr_cmd = MC_CMD_GET_WORKAROUNDS;
2045	req.emr_in_buf = NULL;
2046	req.emr_in_length = 0;
2047	req.emr_out_buf = payload;
2048	req.emr_out_length = MC_CMD_GET_WORKAROUNDS_OUT_LEN;
2049
2050	efx_mcdi_execute(enp, &req);
2051
2052	if (req.emr_rc != 0) {
2053		rc = req.emr_rc;
2054		goto fail1;
2055	}
2056
2057	if (implementedp != NULL) {
2058		*implementedp =
2059		    MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_IMPLEMENTED);
2060	}
2061
2062	if (enabledp != NULL) {
2063		*enabledp = MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_ENABLED);
2064	}
2065
2066	return (0);
2067
2068fail1:
2069	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2070
2071	return (rc);
2072}
2073
2074/*
2075 * Size of media information page in accordance with SFF-8472 and SFF-8436.
2076 * It is used in MCDI interface as well.
2077 */
2078#define	EFX_PHY_MEDIA_INFO_PAGE_SIZE		0x80
2079
2080static	__checkReturn		efx_rc_t
2081efx_mcdi_get_phy_media_info(
2082	__in			efx_nic_t *enp,
2083	__in			uint32_t mcdi_page,
2084	__in			uint8_t offset,
2085	__in			uint8_t len,
2086	__out_bcount(len)	uint8_t *data)
2087{
2088	efx_mcdi_req_t req;
2089	uint8_t payload[MAX(MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN,
2090			    MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(
2091				EFX_PHY_MEDIA_INFO_PAGE_SIZE))];
2092	efx_rc_t rc;
2093
2094	EFSYS_ASSERT((uint32_t)offset + len <= EFX_PHY_MEDIA_INFO_PAGE_SIZE);
2095
2096	(void) memset(payload, 0, sizeof (payload));
2097	req.emr_cmd = MC_CMD_GET_PHY_MEDIA_INFO;
2098	req.emr_in_buf = payload;
2099	req.emr_in_length = MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN;
2100	req.emr_out_buf = payload;
2101	req.emr_out_length =
2102	    MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE);
2103
2104	MCDI_IN_SET_DWORD(req, GET_PHY_MEDIA_INFO_IN_PAGE, mcdi_page);
2105
2106	efx_mcdi_execute(enp, &req);
2107
2108	if (req.emr_rc != 0) {
2109		rc = req.emr_rc;
2110		goto fail1;
2111	}
2112
2113	if (req.emr_out_length_used !=
2114	    MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE)) {
2115		rc = EMSGSIZE;
2116		goto fail2;
2117	}
2118
2119	if (MCDI_OUT_DWORD(req, GET_PHY_MEDIA_INFO_OUT_DATALEN) !=
2120	    EFX_PHY_MEDIA_INFO_PAGE_SIZE) {
2121		rc = EIO;
2122		goto fail3;
2123	}
2124
2125	memcpy(data,
2126	    MCDI_OUT2(req, uint8_t, GET_PHY_MEDIA_INFO_OUT_DATA) + offset,
2127	    len);
2128
2129	return (0);
2130
2131fail3:
2132	EFSYS_PROBE(fail3);
2133fail2:
2134	EFSYS_PROBE(fail2);
2135fail1:
2136	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2137
2138	return (rc);
2139}
2140
2141/*
2142 * 2-wire device address of the base information in accordance with SFF-8472
2143 * Diagnostic Monitoring Interface for Optical Transceivers section
2144 * 4 Memory Organization.
2145 */
2146#define	EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE	0xA0
2147
2148/*
2149 * 2-wire device address of the digital diagnostics monitoring interface
2150 * in accordance with SFF-8472 Diagnostic Monitoring Interface for Optical
2151 * Transceivers section 4 Memory Organization.
2152 */
2153#define	EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM	0xA2
2154
2155/*
2156 * Hard wired 2-wire device address for QSFP+ in accordance with SFF-8436
2157 * QSFP+ 10 Gbs 4X PLUGGABLE TRANSCEIVER section 7.4 Device Addressing and
2158 * Operation.
2159 */
2160#define	EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP	0xA0
2161
2162	__checkReturn		efx_rc_t
2163efx_mcdi_phy_module_get_info(
2164	__in			efx_nic_t *enp,
2165	__in			uint8_t dev_addr,
2166	__in			uint8_t offset,
2167	__in			uint8_t len,
2168	__out_bcount(len)	uint8_t *data)
2169{
2170	efx_port_t *epp = &(enp->en_port);
2171	efx_rc_t rc;
2172	uint32_t mcdi_lower_page;
2173	uint32_t mcdi_upper_page;
2174
2175	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
2176
2177	/*
2178	 * Map device address to MC_CMD_GET_PHY_MEDIA_INFO pages.
2179	 * Offset plus length interface allows to access page 0 only.
2180	 * I.e. non-zero upper pages are not accessible.
2181	 * See SFF-8472 section 4 Memory Organization and SFF-8436 section 7.6
2182	 * QSFP+ Memory Map for details on how information is structured
2183	 * and accessible.
2184	 */
2185	switch (epp->ep_fixed_port_type) {
2186	case EFX_PHY_MEDIA_SFP_PLUS:
2187		/*
2188		 * In accordance with SFF-8472 Diagnostic Monitoring
2189		 * Interface for Optical Transceivers section 4 Memory
2190		 * Organization two 2-wire addresses are defined.
2191		 */
2192		switch (dev_addr) {
2193		/* Base information */
2194		case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE:
2195			/*
2196			 * MCDI page 0 should be used to access lower
2197			 * page 0 (0x00 - 0x7f) at the device address 0xA0.
2198			 */
2199			mcdi_lower_page = 0;
2200			/*
2201			 * MCDI page 1 should be used to access  upper
2202			 * page 0 (0x80 - 0xff) at the device address 0xA0.
2203			 */
2204			mcdi_upper_page = 1;
2205			break;
2206		/* Diagnostics */
2207		case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM:
2208			/*
2209			 * MCDI page 2 should be used to access lower
2210			 * page 0 (0x00 - 0x7f) at the device address 0xA2.
2211			 */
2212			mcdi_lower_page = 2;
2213			/*
2214			 * MCDI page 3 should be used to access upper
2215			 * page 0 (0x80 - 0xff) at the device address 0xA2.
2216			 */
2217			mcdi_upper_page = 3;
2218			break;
2219		default:
2220			rc = ENOTSUP;
2221			goto fail1;
2222		}
2223		break;
2224	case EFX_PHY_MEDIA_QSFP_PLUS:
2225		switch (dev_addr) {
2226		case EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP:
2227			/*
2228			 * MCDI page -1 should be used to access lower page 0
2229			 * (0x00 - 0x7f).
2230			 */
2231			mcdi_lower_page = (uint32_t)-1;
2232			/*
2233			 * MCDI page 0 should be used to access upper page 0
2234			 * (0x80h - 0xff).
2235			 */
2236			mcdi_upper_page = 0;
2237			break;
2238		default:
2239			rc = ENOTSUP;
2240			goto fail1;
2241		}
2242		break;
2243	default:
2244		rc = ENOTSUP;
2245		goto fail1;
2246	}
2247
2248	if (offset < EFX_PHY_MEDIA_INFO_PAGE_SIZE) {
2249		uint8_t read_len =
2250		    MIN(len, EFX_PHY_MEDIA_INFO_PAGE_SIZE - offset);
2251
2252		rc = efx_mcdi_get_phy_media_info(enp,
2253		    mcdi_lower_page, offset, read_len, data);
2254		if (rc != 0)
2255			goto fail2;
2256
2257		data += read_len;
2258		len -= read_len;
2259
2260		offset = 0;
2261	} else {
2262		offset -= EFX_PHY_MEDIA_INFO_PAGE_SIZE;
2263	}
2264
2265	if (len > 0) {
2266		EFSYS_ASSERT3U(len, <=, EFX_PHY_MEDIA_INFO_PAGE_SIZE);
2267		EFSYS_ASSERT3U(offset, <, EFX_PHY_MEDIA_INFO_PAGE_SIZE);
2268
2269		rc = efx_mcdi_get_phy_media_info(enp,
2270		    mcdi_upper_page, offset, len, data);
2271		if (rc != 0)
2272			goto fail3;
2273	}
2274
2275	return (0);
2276
2277fail3:
2278	EFSYS_PROBE(fail3);
2279fail2:
2280	EFSYS_PROBE(fail2);
2281fail1:
2282	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2283
2284	return (rc);
2285}
2286
2287#endif	/* EFSYS_OPT_MCDI */
2288