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