2 * Copyright (c) 2008-2016 Solarflare Communications Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
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.
37 * There are three versions of the MCDI interface:
38 * - MCDIv0: Siena BootROM. Transport uses MCDIv1 headers.
39 * - MCDIv1: Siena firmware and Huntington BootROM.
40 * - MCDIv2: EF10 firmware (Huntington/Medford) and Medford BootROM.
41 * Transport uses MCDIv2 headers.
43 * MCDIv2 Header NOT_EPOCH flag
44 * ----------------------------
45 * A new epoch begins at initial startup or after an MC reboot, and defines when
46 * the MC should reject stale MCDI requests.
48 * The first MCDI request sent by the host should contain NOT_EPOCH=0, and all
49 * subsequent requests (until the next MC reboot) should contain NOT_EPOCH=1.
51 * After rebooting the MC will fail all requests with NOT_EPOCH=1 by writing a
52 * response with ERROR=1 and DATALEN=0 until a request is seen with NOT_EPOCH=0.
57 __checkReturn efx_rc_t
60 __in const efx_mcdi_transport_t *emtp)
62 const efx_mcdi_ops_t *emcop;
65 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
66 EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
68 switch (enp->en_family) {
76 if (enp->en_features & EFX_FEATURE_MCDI_DMA) {
77 /* MCDI requires a DMA buffer in host memory */
78 if ((emtp == NULL) || (emtp->emt_dma_mem) == NULL) {
83 enp->en_mcdi.em_emtp = emtp;
85 if (emcop != NULL && emcop->emco_init != NULL) {
86 if ((rc = emcop->emco_init(enp, emtp)) != 0)
90 enp->en_mcdi.em_emcop = emcop;
91 enp->en_mod_flags |= EFX_MOD_MCDI;
100 EFSYS_PROBE1(fail1, efx_rc_t, rc);
102 enp->en_mcdi.em_emcop = NULL;
103 enp->en_mcdi.em_emtp = NULL;
104 enp->en_mod_flags &= ~EFX_MOD_MCDI;
113 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
114 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
116 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
117 EFSYS_ASSERT3U(enp->en_mod_flags, ==, EFX_MOD_MCDI);
119 if (emcop != NULL && emcop->emco_fini != NULL)
120 emcop->emco_fini(enp);
123 emip->emi_aborted = 0;
125 enp->en_mcdi.em_emcop = NULL;
126 enp->en_mod_flags &= ~EFX_MOD_MCDI;
133 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
134 efsys_lock_state_t state;
136 /* Start a new epoch (allow fresh MCDI requests to succeed) */
137 EFSYS_LOCK(enp->en_eslp, state);
138 emip->emi_new_epoch = B_TRUE;
139 EFSYS_UNLOCK(enp->en_eslp, state);
143 efx_mcdi_send_request(
150 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
152 emcop->emco_send_request(enp, hdrp, hdr_len, sdup, sdu_len);
156 efx_mcdi_poll_reboot(
159 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
162 rc = emcop->emco_poll_reboot(enp);
167 efx_mcdi_poll_response(
170 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
173 available = emcop->emco_poll_response(enp);
178 efx_mcdi_read_response(
184 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
186 emcop->emco_read_response(enp, bufferp, offset, length);
190 efx_mcdi_request_start(
192 __in efx_mcdi_req_t *emrp,
193 __in boolean_t ev_cpl)
195 #if EFSYS_OPT_MCDI_LOGGING
196 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
198 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
201 unsigned int max_version;
205 efsys_lock_state_t state;
207 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
208 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
209 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
212 * efx_mcdi_request_start() is naturally serialised against both
213 * efx_mcdi_request_poll() and efx_mcdi_ev_cpl()/efx_mcdi_ev_death(),
214 * by virtue of there only being one outstanding MCDI request.
215 * Unfortunately, upper layers may also call efx_mcdi_request_abort()
216 * at any time, to timeout a pending mcdi request, That request may
217 * then subsequently complete, meaning efx_mcdi_ev_cpl() or
218 * efx_mcdi_ev_death() may end up running in parallel with
219 * efx_mcdi_request_start(). This race is handled by ensuring that
220 * %emi_pending_req, %emi_ev_cpl and %emi_seq are protected by the
223 EFSYS_LOCK(enp->en_eslp, state);
224 EFSYS_ASSERT(emip->emi_pending_req == NULL);
225 emip->emi_pending_req = emrp;
226 emip->emi_ev_cpl = ev_cpl;
227 emip->emi_poll_cnt = 0;
228 seq = emip->emi_seq++ & EFX_MASK32(MCDI_HEADER_SEQ);
229 new_epoch = emip->emi_new_epoch;
230 max_version = emip->emi_max_version;
231 EFSYS_UNLOCK(enp->en_eslp, state);
235 xflags |= MCDI_HEADER_XFLAGS_EVREQ;
238 * Huntington firmware supports MCDIv2, but the Huntington BootROM only
239 * supports MCDIv1. Use MCDIv1 headers for MCDIv1 commands where
240 * possible to support this.
242 if ((max_version >= 2) &&
243 ((emrp->emr_cmd > MC_CMD_CMD_SPACE_ESCAPE_7) ||
244 (emrp->emr_in_length > MCDI_CTL_SDU_LEN_MAX_V1))) {
245 /* Construct MCDI v2 header */
246 hdr_len = sizeof (hdr);
247 EFX_POPULATE_DWORD_8(hdr[0],
248 MCDI_HEADER_CODE, MC_CMD_V2_EXTN,
249 MCDI_HEADER_RESYNC, 1,
250 MCDI_HEADER_DATALEN, 0,
251 MCDI_HEADER_SEQ, seq,
252 MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
253 MCDI_HEADER_ERROR, 0,
254 MCDI_HEADER_RESPONSE, 0,
255 MCDI_HEADER_XFLAGS, xflags);
257 EFX_POPULATE_DWORD_2(hdr[1],
258 MC_CMD_V2_EXTN_IN_EXTENDED_CMD, emrp->emr_cmd,
259 MC_CMD_V2_EXTN_IN_ACTUAL_LEN, emrp->emr_in_length);
261 /* Construct MCDI v1 header */
262 hdr_len = sizeof (hdr[0]);
263 EFX_POPULATE_DWORD_8(hdr[0],
264 MCDI_HEADER_CODE, emrp->emr_cmd,
265 MCDI_HEADER_RESYNC, 1,
266 MCDI_HEADER_DATALEN, emrp->emr_in_length,
267 MCDI_HEADER_SEQ, seq,
268 MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
269 MCDI_HEADER_ERROR, 0,
270 MCDI_HEADER_RESPONSE, 0,
271 MCDI_HEADER_XFLAGS, xflags);
274 #if EFSYS_OPT_MCDI_LOGGING
275 if (emtp->emt_logger != NULL) {
276 emtp->emt_logger(emtp->emt_context, EFX_LOG_MCDI_REQUEST,
278 emrp->emr_in_buf, emrp->emr_in_length);
280 #endif /* EFSYS_OPT_MCDI_LOGGING */
282 efx_mcdi_send_request(enp, &hdr[0], hdr_len,
283 emrp->emr_in_buf, emrp->emr_in_length);
288 efx_mcdi_read_response_header(
290 __inout efx_mcdi_req_t *emrp)
292 #if EFSYS_OPT_MCDI_LOGGING
293 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
294 #endif /* EFSYS_OPT_MCDI_LOGGING */
295 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
297 unsigned int hdr_len;
298 unsigned int data_len;
304 EFSYS_ASSERT(emrp != NULL);
306 efx_mcdi_read_response(enp, &hdr[0], 0, sizeof (hdr[0]));
307 hdr_len = sizeof (hdr[0]);
309 cmd = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE);
310 seq = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_SEQ);
311 error = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_ERROR);
313 if (cmd != MC_CMD_V2_EXTN) {
314 data_len = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_DATALEN);
316 efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1]));
317 hdr_len += sizeof (hdr[1]);
319 cmd = EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_EXTENDED_CMD);
321 EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
324 if (error && (data_len == 0)) {
325 /* The MC has rebooted since the request was sent. */
326 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
327 efx_mcdi_poll_reboot(enp);
331 if ((cmd != emrp->emr_cmd) ||
332 (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
333 /* Response is for a different request */
339 unsigned int err_len = MIN(data_len, sizeof (err));
340 int err_code = MC_CMD_ERR_EPROTO;
343 /* Read error code (and arg num for MCDI v2 commands) */
344 efx_mcdi_read_response(enp, &err, hdr_len, err_len);
346 if (err_len >= (MC_CMD_ERR_CODE_OFST + sizeof (efx_dword_t)))
347 err_code = EFX_DWORD_FIELD(err[0], EFX_DWORD_0);
349 if (err_len >= (MC_CMD_ERR_ARG_OFST + sizeof (efx_dword_t)))
350 err_arg = EFX_DWORD_FIELD(err[1], EFX_DWORD_0);
352 emrp->emr_err_code = err_code;
353 emrp->emr_err_arg = err_arg;
355 #if EFSYS_OPT_MCDI_PROXY_AUTH
356 if ((err_code == MC_CMD_ERR_PROXY_PENDING) &&
357 (err_len == sizeof (err))) {
359 * The MCDI request would normally fail with EPERM, but
360 * firmware has forwarded it to an authorization agent
361 * attached to a privileged PF.
363 * Save the authorization request handle. The client
364 * must wait for a PROXY_RESPONSE event, or timeout.
366 emrp->emr_proxy_handle = err_arg;
368 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
370 #if EFSYS_OPT_MCDI_LOGGING
371 if (emtp->emt_logger != NULL) {
372 emtp->emt_logger(emtp->emt_context,
373 EFX_LOG_MCDI_RESPONSE,
377 #endif /* EFSYS_OPT_MCDI_LOGGING */
379 if (!emrp->emr_quiet) {
380 EFSYS_PROBE3(mcdi_err_arg, int, emrp->emr_cmd,
381 int, err_code, int, err_arg);
384 rc = efx_mcdi_request_errcode(err_code);
389 emrp->emr_out_length_used = data_len;
390 #if EFSYS_OPT_MCDI_PROXY_AUTH
391 emrp->emr_proxy_handle = 0;
392 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
399 emrp->emr_out_length_used = 0;
403 efx_mcdi_finish_response(
405 __in efx_mcdi_req_t *emrp)
407 #if EFSYS_OPT_MCDI_LOGGING
408 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
409 #endif /* EFSYS_OPT_MCDI_LOGGING */
411 unsigned int hdr_len;
414 if (emrp->emr_out_buf == NULL)
417 /* Read the command header to detect MCDI response format */
418 hdr_len = sizeof (hdr[0]);
419 efx_mcdi_read_response(enp, &hdr[0], 0, hdr_len);
420 if (EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) {
422 * Read the actual payload length. The length given in the event
423 * is only correct for responses with the V1 format.
425 efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1]));
426 hdr_len += sizeof (hdr[1]);
428 emrp->emr_out_length_used = EFX_DWORD_FIELD(hdr[1],
429 MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
432 /* Copy payload out into caller supplied buffer */
433 bytes = MIN(emrp->emr_out_length_used, emrp->emr_out_length);
434 efx_mcdi_read_response(enp, emrp->emr_out_buf, hdr_len, bytes);
436 #if EFSYS_OPT_MCDI_LOGGING
437 if (emtp->emt_logger != NULL) {
438 emtp->emt_logger(emtp->emt_context,
439 EFX_LOG_MCDI_RESPONSE,
441 emrp->emr_out_buf, bytes);
443 #endif /* EFSYS_OPT_MCDI_LOGGING */
447 __checkReturn boolean_t
448 efx_mcdi_request_poll(
451 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
452 efx_mcdi_req_t *emrp;
453 efsys_lock_state_t state;
456 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
457 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
458 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
460 /* Serialise against post-watchdog efx_mcdi_ev* */
461 EFSYS_LOCK(enp->en_eslp, state);
463 EFSYS_ASSERT(emip->emi_pending_req != NULL);
464 EFSYS_ASSERT(!emip->emi_ev_cpl);
465 emrp = emip->emi_pending_req;
467 /* Check for reboot atomically w.r.t efx_mcdi_request_start */
468 if (emip->emi_poll_cnt++ == 0) {
469 if ((rc = efx_mcdi_poll_reboot(enp)) != 0) {
470 emip->emi_pending_req = NULL;
471 EFSYS_UNLOCK(enp->en_eslp, state);
473 /* Reboot/Assertion */
474 if (rc == EIO || rc == EINTR)
475 efx_mcdi_raise_exception(enp, emrp, rc);
481 /* Check if a response is available */
482 if (efx_mcdi_poll_response(enp) == B_FALSE) {
483 EFSYS_UNLOCK(enp->en_eslp, state);
487 /* Read the response header */
488 efx_mcdi_read_response_header(enp, emrp);
490 /* Request complete */
491 emip->emi_pending_req = NULL;
493 /* Ensure stale MCDI requests fail after an MC reboot. */
494 emip->emi_new_epoch = B_FALSE;
496 EFSYS_UNLOCK(enp->en_eslp, state);
498 if ((rc = emrp->emr_rc) != 0)
501 efx_mcdi_finish_response(enp, emrp);
505 if (!emrp->emr_quiet)
508 if (!emrp->emr_quiet)
509 EFSYS_PROBE1(fail1, efx_rc_t, rc);
514 __checkReturn boolean_t
515 efx_mcdi_request_abort(
518 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
519 efx_mcdi_req_t *emrp;
521 efsys_lock_state_t state;
523 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
524 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
525 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
528 * efx_mcdi_ev_* may have already completed this event, and be
529 * spinning/blocked on the upper layer lock. So it *is* legitimate
530 * to for emi_pending_req to be NULL. If there is a pending event
531 * completed request, then provide a "credit" to allow
532 * efx_mcdi_ev_cpl() to accept a single spurious completion.
534 EFSYS_LOCK(enp->en_eslp, state);
535 emrp = emip->emi_pending_req;
536 aborted = (emrp != NULL);
538 emip->emi_pending_req = NULL;
540 /* Error the request */
541 emrp->emr_out_length_used = 0;
542 emrp->emr_rc = ETIMEDOUT;
544 /* Provide a credit for seqno/emr_pending_req mismatches */
545 if (emip->emi_ev_cpl)
549 * The upper layer has called us, so we don't
550 * need to complete the request.
553 EFSYS_UNLOCK(enp->en_eslp, state);
559 efx_mcdi_get_timeout(
561 __in efx_mcdi_req_t *emrp,
562 __out uint32_t *timeoutp)
564 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
566 emcop->emco_get_timeout(enp, emrp, timeoutp);
569 __checkReturn efx_rc_t
570 efx_mcdi_request_errcode(
571 __in unsigned int err)
576 case MC_CMD_ERR_EPERM:
578 case MC_CMD_ERR_ENOENT:
580 case MC_CMD_ERR_EINTR:
582 case MC_CMD_ERR_EACCES:
584 case MC_CMD_ERR_EBUSY:
586 case MC_CMD_ERR_EINVAL:
588 case MC_CMD_ERR_EDEADLK:
590 case MC_CMD_ERR_ENOSYS:
592 case MC_CMD_ERR_ETIME:
594 case MC_CMD_ERR_ENOTSUP:
596 case MC_CMD_ERR_EALREADY:
600 case MC_CMD_ERR_EEXIST:
602 #ifdef MC_CMD_ERR_EAGAIN
603 case MC_CMD_ERR_EAGAIN:
606 #ifdef MC_CMD_ERR_ENOSPC
607 case MC_CMD_ERR_ENOSPC:
610 case MC_CMD_ERR_ERANGE:
613 case MC_CMD_ERR_ALLOC_FAIL:
615 case MC_CMD_ERR_NO_VADAPTOR:
617 case MC_CMD_ERR_NO_EVB_PORT:
619 case MC_CMD_ERR_NO_VSWITCH:
621 case MC_CMD_ERR_VLAN_LIMIT:
623 case MC_CMD_ERR_BAD_PCI_FUNC:
625 case MC_CMD_ERR_BAD_VLAN_MODE:
627 case MC_CMD_ERR_BAD_VSWITCH_TYPE:
629 case MC_CMD_ERR_BAD_VPORT_TYPE:
631 case MC_CMD_ERR_MAC_EXIST:
634 case MC_CMD_ERR_PROXY_PENDING:
638 EFSYS_PROBE1(mc_pcol_error, int, err);
644 efx_mcdi_raise_exception(
646 __in_opt efx_mcdi_req_t *emrp,
649 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
650 efx_mcdi_exception_t exception;
652 /* Reboot or Assertion failure only */
653 EFSYS_ASSERT(rc == EIO || rc == EINTR);
656 * If MC_CMD_REBOOT causes a reboot (dependent on parameters),
657 * then the EIO is not worthy of an exception.
659 if (emrp != NULL && emrp->emr_cmd == MC_CMD_REBOOT && rc == EIO)
662 exception = (rc == EIO)
663 ? EFX_MCDI_EXCEPTION_MC_REBOOT
664 : EFX_MCDI_EXCEPTION_MC_BADASSERT;
666 emtp->emt_exception(emtp->emt_context, exception);
672 __inout efx_mcdi_req_t *emrp)
674 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
676 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
677 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
679 emrp->emr_quiet = B_FALSE;
680 emtp->emt_execute(emtp->emt_context, emrp);
684 efx_mcdi_execute_quiet(
686 __inout efx_mcdi_req_t *emrp)
688 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
690 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
691 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
693 emrp->emr_quiet = B_TRUE;
694 emtp->emt_execute(emtp->emt_context, emrp);
700 __in unsigned int seq,
701 __in unsigned int outlen,
704 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
705 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
706 efx_mcdi_req_t *emrp;
707 efsys_lock_state_t state;
709 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
710 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
713 * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start()
714 * when we're completing an aborted request.
716 EFSYS_LOCK(enp->en_eslp, state);
717 if (emip->emi_pending_req == NULL || !emip->emi_ev_cpl ||
718 (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
719 EFSYS_ASSERT(emip->emi_aborted > 0);
720 if (emip->emi_aborted > 0)
722 EFSYS_UNLOCK(enp->en_eslp, state);
726 emrp = emip->emi_pending_req;
727 emip->emi_pending_req = NULL;
728 EFSYS_UNLOCK(enp->en_eslp, state);
730 if (emip->emi_max_version >= 2) {
731 /* MCDIv2 response details do not fit into an event. */
732 efx_mcdi_read_response_header(enp, emrp);
735 if (!emrp->emr_quiet) {
736 EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd,
739 emrp->emr_out_length_used = 0;
740 emrp->emr_rc = efx_mcdi_request_errcode(errcode);
742 emrp->emr_out_length_used = outlen;
747 efx_mcdi_finish_response(enp, emrp);
750 emtp->emt_ev_cpl(emtp->emt_context);
753 #if EFSYS_OPT_MCDI_PROXY_AUTH
755 __checkReturn efx_rc_t
756 efx_mcdi_get_proxy_handle(
758 __in efx_mcdi_req_t *emrp,
759 __out uint32_t *handlep)
764 * Return proxy handle from MCDI request that returned with error
765 * MC_MCD_ERR_PROXY_PENDING. This handle is used to wait for a matching
766 * PROXY_RESPONSE event.
768 if ((emrp == NULL) || (handlep == NULL)) {
772 if ((emrp->emr_rc != 0) &&
773 (emrp->emr_err_code == MC_CMD_ERR_PROXY_PENDING)) {
774 *handlep = emrp->emr_proxy_handle;
783 EFSYS_PROBE1(fail1, efx_rc_t, rc);
788 efx_mcdi_ev_proxy_response(
790 __in unsigned int handle,
791 __in unsigned int status)
793 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
797 * Handle results of an authorization request for a privileged MCDI
798 * command. If authorization was granted then we must re-issue the
799 * original MCDI request. If authorization failed or timed out,
800 * then the original MCDI request should be completed with the
801 * result code from this event.
803 rc = (status == 0) ? 0 : efx_mcdi_request_errcode(status);
805 emtp->emt_ev_proxy_response(emtp->emt_context, handle, rc);
807 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
814 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
815 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
816 efx_mcdi_req_t *emrp = NULL;
818 efsys_lock_state_t state;
821 * The MCDI request (if there is one) has been terminated, either
822 * by a BADASSERT or REBOOT event.
824 * If there is an outstanding event-completed MCDI operation, then we
825 * will never receive the completion event (because both MCDI
826 * completions and BADASSERT events are sent to the same evq). So
827 * complete this MCDI op.
829 * This function might run in parallel with efx_mcdi_request_poll()
830 * for poll completed mcdi requests, and also with
831 * efx_mcdi_request_start() for post-watchdog completions.
833 EFSYS_LOCK(enp->en_eslp, state);
834 emrp = emip->emi_pending_req;
835 ev_cpl = emip->emi_ev_cpl;
836 if (emrp != NULL && emip->emi_ev_cpl) {
837 emip->emi_pending_req = NULL;
839 emrp->emr_out_length_used = 0;
845 * Since we're running in parallel with a request, consume the
846 * status word before dropping the lock.
848 if (rc == EIO || rc == EINTR) {
849 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
850 (void) efx_mcdi_poll_reboot(enp);
851 emip->emi_new_epoch = B_TRUE;
854 EFSYS_UNLOCK(enp->en_eslp, state);
856 efx_mcdi_raise_exception(enp, emrp, rc);
858 if (emrp != NULL && ev_cpl)
859 emtp->emt_ev_cpl(emtp->emt_context);
862 __checkReturn efx_rc_t
865 __out_ecount_opt(4) uint16_t versionp[4],
866 __out_opt uint32_t *buildp,
867 __out_opt efx_mcdi_boot_t *statusp)
870 uint8_t payload[MAX(MAX(MC_CMD_GET_VERSION_IN_LEN,
871 MC_CMD_GET_VERSION_OUT_LEN),
872 MAX(MC_CMD_GET_BOOT_STATUS_IN_LEN,
873 MC_CMD_GET_BOOT_STATUS_OUT_LEN))];
874 efx_word_t *ver_words;
877 efx_mcdi_boot_t status;
880 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
882 (void) memset(payload, 0, sizeof (payload));
883 req.emr_cmd = MC_CMD_GET_VERSION;
884 req.emr_in_buf = payload;
885 req.emr_in_length = MC_CMD_GET_VERSION_IN_LEN;
886 req.emr_out_buf = payload;
887 req.emr_out_length = MC_CMD_GET_VERSION_OUT_LEN;
889 efx_mcdi_execute(enp, &req);
891 if (req.emr_rc != 0) {
896 /* bootrom support */
897 if (req.emr_out_length_used == MC_CMD_GET_VERSION_V0_OUT_LEN) {
898 version[0] = version[1] = version[2] = version[3] = 0;
899 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
904 if (req.emr_out_length_used < MC_CMD_GET_VERSION_OUT_LEN) {
909 ver_words = MCDI_OUT2(req, efx_word_t, GET_VERSION_OUT_VERSION);
910 version[0] = EFX_WORD_FIELD(ver_words[0], EFX_WORD_0);
911 version[1] = EFX_WORD_FIELD(ver_words[1], EFX_WORD_0);
912 version[2] = EFX_WORD_FIELD(ver_words[2], EFX_WORD_0);
913 version[3] = EFX_WORD_FIELD(ver_words[3], EFX_WORD_0);
914 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
917 /* The bootrom doesn't understand BOOT_STATUS */
918 if (MC_FW_VERSION_IS_BOOTLOADER(build)) {
919 status = EFX_MCDI_BOOT_ROM;
923 (void) memset(payload, 0, sizeof (payload));
924 req.emr_cmd = MC_CMD_GET_BOOT_STATUS;
925 req.emr_in_buf = payload;
926 req.emr_in_length = MC_CMD_GET_BOOT_STATUS_IN_LEN;
927 req.emr_out_buf = payload;
928 req.emr_out_length = MC_CMD_GET_BOOT_STATUS_OUT_LEN;
930 efx_mcdi_execute_quiet(enp, &req);
932 if (req.emr_rc == EACCES) {
933 /* Unprivileged functions cannot access BOOT_STATUS */
934 status = EFX_MCDI_BOOT_PRIMARY;
935 version[0] = version[1] = version[2] = version[3] = 0;
940 if (req.emr_rc != 0) {
945 if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) {
950 if (MCDI_OUT_DWORD_FIELD(req, GET_BOOT_STATUS_OUT_FLAGS,
951 GET_BOOT_STATUS_OUT_FLAGS_PRIMARY))
952 status = EFX_MCDI_BOOT_PRIMARY;
954 status = EFX_MCDI_BOOT_SECONDARY;
957 if (versionp != NULL)
958 memcpy(versionp, version, sizeof (version));
973 EFSYS_PROBE1(fail1, efx_rc_t, rc);
978 static __checkReturn efx_rc_t
981 __in boolean_t after_assertion)
983 uint8_t payload[MAX(MC_CMD_REBOOT_IN_LEN, MC_CMD_REBOOT_OUT_LEN)];
988 * We could require the caller to have caused en_mod_flags=0 to
989 * call this function. This doesn't help the other port though,
990 * who's about to get the MC ripped out from underneath them.
991 * Since they have to cope with the subsequent fallout of MCDI
992 * failures, we should as well.
994 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
996 (void) memset(payload, 0, sizeof (payload));
997 req.emr_cmd = MC_CMD_REBOOT;
998 req.emr_in_buf = payload;
999 req.emr_in_length = MC_CMD_REBOOT_IN_LEN;
1000 req.emr_out_buf = payload;
1001 req.emr_out_length = MC_CMD_REBOOT_OUT_LEN;
1003 MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS,
1004 (after_assertion ? MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION : 0));
1006 efx_mcdi_execute_quiet(enp, &req);
1008 if (req.emr_rc == EACCES) {
1009 /* Unprivileged functions cannot reboot the MC. */
1013 /* A successful reboot request returns EIO. */
1014 if (req.emr_rc != 0 && req.emr_rc != EIO) {
1023 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1028 __checkReturn efx_rc_t
1030 __in efx_nic_t *enp)
1032 return (efx_mcdi_do_reboot(enp, B_FALSE));
1035 __checkReturn efx_rc_t
1036 efx_mcdi_exit_assertion_handler(
1037 __in efx_nic_t *enp)
1039 return (efx_mcdi_do_reboot(enp, B_TRUE));
1042 __checkReturn efx_rc_t
1043 efx_mcdi_read_assertion(
1044 __in efx_nic_t *enp)
1047 uint8_t payload[MAX(MC_CMD_GET_ASSERTS_IN_LEN,
1048 MC_CMD_GET_ASSERTS_OUT_LEN)];
1057 * Before we attempt to chat to the MC, we should verify that the MC
1058 * isn't in it's assertion handler, either due to a previous reboot,
1059 * or because we're reinitializing due to an eec_exception().
1061 * Use GET_ASSERTS to read any assertion state that may be present.
1062 * Retry this command twice. Once because a boot-time assertion failure
1063 * might cause the 1st MCDI request to fail. And once again because
1064 * we might race with efx_mcdi_exit_assertion_handler() running on
1065 * partner port(s) on the same NIC.
1069 (void) memset(payload, 0, sizeof (payload));
1070 req.emr_cmd = MC_CMD_GET_ASSERTS;
1071 req.emr_in_buf = payload;
1072 req.emr_in_length = MC_CMD_GET_ASSERTS_IN_LEN;
1073 req.emr_out_buf = payload;
1074 req.emr_out_length = MC_CMD_GET_ASSERTS_OUT_LEN;
1076 MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1);
1077 efx_mcdi_execute_quiet(enp, &req);
1079 } while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0);
1081 if (req.emr_rc != 0) {
1082 if (req.emr_rc == EACCES) {
1083 /* Unprivileged functions cannot clear assertions. */
1090 if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) {
1095 /* Print out any assertion state recorded */
1096 flags = MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_GLOBAL_FLAGS);
1097 if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
1100 reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
1101 ? "system-level assertion"
1102 : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
1103 ? "thread-level assertion"
1104 : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
1106 : (flags == MC_CMD_GET_ASSERTS_FLAGS_ADDR_TRAP)
1107 ? "illegal address trap"
1108 : "unknown assertion";
1109 EFSYS_PROBE3(mcpu_assertion,
1110 const char *, reason, unsigned int,
1111 MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_SAVED_PC_OFFS),
1113 MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS));
1115 /* Print out the registers (r1 ... r31) */
1116 ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST;
1118 index < 1 + MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM;
1120 EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int,
1121 EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst),
1123 ofst += sizeof (efx_dword_t);
1125 EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN);
1133 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1140 * Internal routines for for specific MCDI requests.
1143 __checkReturn efx_rc_t
1144 efx_mcdi_drv_attach(
1145 __in efx_nic_t *enp,
1146 __in boolean_t attach)
1149 uint8_t payload[MAX(MC_CMD_DRV_ATTACH_IN_LEN,
1150 MC_CMD_DRV_ATTACH_EXT_OUT_LEN)];
1153 (void) memset(payload, 0, sizeof (payload));
1154 req.emr_cmd = MC_CMD_DRV_ATTACH;
1155 req.emr_in_buf = payload;
1156 req.emr_in_length = MC_CMD_DRV_ATTACH_IN_LEN;
1157 req.emr_out_buf = payload;
1158 req.emr_out_length = MC_CMD_DRV_ATTACH_EXT_OUT_LEN;
1161 * Use DONT_CARE for the datapath firmware type to ensure that the
1162 * driver can attach to an unprivileged function. The datapath firmware
1163 * type to use is controlled by the 'sfboot' utility.
1165 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_NEW_STATE, attach ? 1 : 0);
1166 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_UPDATE, 1);
1167 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_FIRMWARE_ID, MC_CMD_FW_DONT_CARE);
1169 efx_mcdi_execute(enp, &req);
1171 if (req.emr_rc != 0) {
1176 if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) {
1186 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1191 __checkReturn efx_rc_t
1192 efx_mcdi_get_board_cfg(
1193 __in efx_nic_t *enp,
1194 __out_opt uint32_t *board_typep,
1195 __out_opt efx_dword_t *capabilitiesp,
1196 __out_ecount_opt(6) uint8_t mac_addrp[6])
1198 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
1200 uint8_t payload[MAX(MC_CMD_GET_BOARD_CFG_IN_LEN,
1201 MC_CMD_GET_BOARD_CFG_OUT_LENMIN)];
1204 (void) memset(payload, 0, sizeof (payload));
1205 req.emr_cmd = MC_CMD_GET_BOARD_CFG;
1206 req.emr_in_buf = payload;
1207 req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN;
1208 req.emr_out_buf = payload;
1209 req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMIN;
1211 efx_mcdi_execute(enp, &req);
1213 if (req.emr_rc != 0) {
1218 if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
1223 if (mac_addrp != NULL) {
1226 if (emip->emi_port == 1) {
1227 addrp = MCDI_OUT2(req, uint8_t,
1228 GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0);
1229 } else if (emip->emi_port == 2) {
1230 addrp = MCDI_OUT2(req, uint8_t,
1231 GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1);
1237 EFX_MAC_ADDR_COPY(mac_addrp, addrp);
1240 if (capabilitiesp != NULL) {
1241 if (emip->emi_port == 1) {
1242 *capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
1243 GET_BOARD_CFG_OUT_CAPABILITIES_PORT0);
1244 } else if (emip->emi_port == 2) {
1245 *capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
1246 GET_BOARD_CFG_OUT_CAPABILITIES_PORT1);
1253 if (board_typep != NULL) {
1254 *board_typep = MCDI_OUT_DWORD(req,
1255 GET_BOARD_CFG_OUT_BOARD_TYPE);
1267 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1272 __checkReturn efx_rc_t
1273 efx_mcdi_get_resource_limits(
1274 __in efx_nic_t *enp,
1275 __out_opt uint32_t *nevqp,
1276 __out_opt uint32_t *nrxqp,
1277 __out_opt uint32_t *ntxqp)
1280 uint8_t payload[MAX(MC_CMD_GET_RESOURCE_LIMITS_IN_LEN,
1281 MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN)];
1284 (void) memset(payload, 0, sizeof (payload));
1285 req.emr_cmd = MC_CMD_GET_RESOURCE_LIMITS;
1286 req.emr_in_buf = payload;
1287 req.emr_in_length = MC_CMD_GET_RESOURCE_LIMITS_IN_LEN;
1288 req.emr_out_buf = payload;
1289 req.emr_out_length = MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN;
1291 efx_mcdi_execute(enp, &req);
1293 if (req.emr_rc != 0) {
1298 if (req.emr_out_length_used < MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) {
1304 *nevqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_EVQ);
1306 *nrxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ);
1308 *ntxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ);
1315 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1320 __checkReturn efx_rc_t
1321 efx_mcdi_get_phy_cfg(
1322 __in efx_nic_t *enp)
1324 efx_port_t *epp = &(enp->en_port);
1325 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1327 uint8_t payload[MAX(MC_CMD_GET_PHY_CFG_IN_LEN,
1328 MC_CMD_GET_PHY_CFG_OUT_LEN)];
1331 (void) memset(payload, 0, sizeof (payload));
1332 req.emr_cmd = MC_CMD_GET_PHY_CFG;
1333 req.emr_in_buf = payload;
1334 req.emr_in_length = MC_CMD_GET_PHY_CFG_IN_LEN;
1335 req.emr_out_buf = payload;
1336 req.emr_out_length = MC_CMD_GET_PHY_CFG_OUT_LEN;
1338 efx_mcdi_execute(enp, &req);
1340 if (req.emr_rc != 0) {
1345 if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) {
1350 encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE);
1352 (void) strncpy(encp->enc_phy_name,
1353 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME),
1354 MIN(sizeof (encp->enc_phy_name) - 1,
1355 MC_CMD_GET_PHY_CFG_OUT_NAME_LEN));
1356 #endif /* EFSYS_OPT_NAMES */
1357 (void) memset(encp->enc_phy_revision, 0,
1358 sizeof (encp->enc_phy_revision));
1359 memcpy(encp->enc_phy_revision,
1360 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION),
1361 MIN(sizeof (encp->enc_phy_revision) - 1,
1362 MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN));
1364 /* Get the media type of the fixed port, if recognised. */
1365 EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI);
1366 EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4);
1367 EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4);
1368 EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP);
1369 EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS);
1370 EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T);
1371 EFX_STATIC_ASSERT(MC_CMD_MEDIA_QSFP_PLUS == EFX_PHY_MEDIA_QSFP_PLUS);
1372 epp->ep_fixed_port_type =
1373 (efx_phy_media_type_t) MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE);
1374 if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES)
1375 epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID;
1377 epp->ep_phy_cap_mask =
1378 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP);
1380 encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT);
1382 /* Populate internal state */
1383 encp->enc_mcdi_mdio_channel =
1384 (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL);
1391 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1396 __checkReturn efx_rc_t
1397 efx_mcdi_firmware_update_supported(
1398 __in efx_nic_t *enp,
1399 __out boolean_t *supportedp)
1401 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1404 if (emcop != NULL) {
1405 if ((rc = emcop->emco_feature_supported(enp,
1406 EFX_MCDI_FEATURE_FW_UPDATE, supportedp)) != 0)
1409 /* Earlier devices always supported updates */
1410 *supportedp = B_TRUE;
1416 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1421 __checkReturn efx_rc_t
1422 efx_mcdi_macaddr_change_supported(
1423 __in efx_nic_t *enp,
1424 __out boolean_t *supportedp)
1426 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1429 if (emcop != NULL) {
1430 if ((rc = emcop->emco_feature_supported(enp,
1431 EFX_MCDI_FEATURE_MACADDR_CHANGE, supportedp)) != 0)
1434 /* Earlier devices always supported MAC changes */
1435 *supportedp = B_TRUE;
1441 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1446 __checkReturn efx_rc_t
1447 efx_mcdi_link_control_supported(
1448 __in efx_nic_t *enp,
1449 __out boolean_t *supportedp)
1451 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1454 if (emcop != NULL) {
1455 if ((rc = emcop->emco_feature_supported(enp,
1456 EFX_MCDI_FEATURE_LINK_CONTROL, supportedp)) != 0)
1459 /* Earlier devices always supported link control */
1460 *supportedp = B_TRUE;
1466 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1471 __checkReturn efx_rc_t
1472 efx_mcdi_mac_spoofing_supported(
1473 __in efx_nic_t *enp,
1474 __out boolean_t *supportedp)
1476 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1479 if (emcop != NULL) {
1480 if ((rc = emcop->emco_feature_supported(enp,
1481 EFX_MCDI_FEATURE_MAC_SPOOFING, supportedp)) != 0)
1484 /* Earlier devices always supported MAC spoofing */
1485 *supportedp = B_TRUE;
1491 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1497 /* Enable logging of some events (e.g. link state changes) */
1498 __checkReturn efx_rc_t
1500 __in efx_nic_t *enp)
1503 uint8_t payload[MAX(MC_CMD_LOG_CTRL_IN_LEN,
1504 MC_CMD_LOG_CTRL_OUT_LEN)];
1507 (void) memset(payload, 0, sizeof (payload));
1508 req.emr_cmd = MC_CMD_LOG_CTRL;
1509 req.emr_in_buf = payload;
1510 req.emr_in_length = MC_CMD_LOG_CTRL_IN_LEN;
1511 req.emr_out_buf = payload;
1512 req.emr_out_length = MC_CMD_LOG_CTRL_OUT_LEN;
1514 MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST,
1515 MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ);
1516 MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST_EVQ, 0);
1518 efx_mcdi_execute(enp, &req);
1520 if (req.emr_rc != 0) {
1528 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1534 __checkReturn efx_rc_t
1535 efx_mcdi_set_workaround(
1536 __in efx_nic_t *enp,
1538 __in boolean_t enabled,
1539 __out_opt uint32_t *flagsp)
1542 uint8_t payload[MAX(MC_CMD_WORKAROUND_IN_LEN,
1543 MC_CMD_WORKAROUND_EXT_OUT_LEN)];
1546 (void) memset(payload, 0, sizeof (payload));
1547 req.emr_cmd = MC_CMD_WORKAROUND;
1548 req.emr_in_buf = payload;
1549 req.emr_in_length = MC_CMD_WORKAROUND_IN_LEN;
1550 req.emr_out_buf = payload;
1551 req.emr_out_length = MC_CMD_WORKAROUND_OUT_LEN;
1553 MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, type);
1554 MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, enabled ? 1 : 0);
1556 efx_mcdi_execute_quiet(enp, &req);
1558 if (req.emr_rc != 0) {
1563 if (flagsp != NULL) {
1564 if (req.emr_out_length_used >= MC_CMD_WORKAROUND_EXT_OUT_LEN)
1565 *flagsp = MCDI_OUT_DWORD(req, WORKAROUND_EXT_OUT_FLAGS);
1573 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1579 __checkReturn efx_rc_t
1580 efx_mcdi_get_workarounds(
1581 __in efx_nic_t *enp,
1582 __out_opt uint32_t *implementedp,
1583 __out_opt uint32_t *enabledp)
1586 uint8_t payload[MC_CMD_GET_WORKAROUNDS_OUT_LEN];
1589 (void) memset(payload, 0, sizeof (payload));
1590 req.emr_cmd = MC_CMD_GET_WORKAROUNDS;
1591 req.emr_in_buf = NULL;
1592 req.emr_in_length = 0;
1593 req.emr_out_buf = payload;
1594 req.emr_out_length = MC_CMD_GET_WORKAROUNDS_OUT_LEN;
1596 efx_mcdi_execute(enp, &req);
1598 if (req.emr_rc != 0) {
1603 if (implementedp != NULL) {
1605 MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_IMPLEMENTED);
1608 if (enabledp != NULL) {
1609 *enabledp = MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_ENABLED);
1615 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1621 * Size of media information page in accordance with SFF-8472 and SFF-8436.
1622 * It is used in MCDI interface as well.
1624 #define EFX_PHY_MEDIA_INFO_PAGE_SIZE 0x80
1626 static __checkReturn efx_rc_t
1627 efx_mcdi_get_phy_media_info(
1628 __in efx_nic_t *enp,
1629 __in uint32_t mcdi_page,
1630 __in uint8_t offset,
1632 __out_bcount(len) uint8_t *data)
1635 uint8_t payload[MAX(MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN,
1636 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(
1637 EFX_PHY_MEDIA_INFO_PAGE_SIZE))];
1640 EFSYS_ASSERT((uint32_t)offset + len <= EFX_PHY_MEDIA_INFO_PAGE_SIZE);
1642 (void) memset(payload, 0, sizeof (payload));
1643 req.emr_cmd = MC_CMD_GET_PHY_MEDIA_INFO;
1644 req.emr_in_buf = payload;
1645 req.emr_in_length = MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN;
1646 req.emr_out_buf = payload;
1647 req.emr_out_length =
1648 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE);
1650 MCDI_IN_SET_DWORD(req, GET_PHY_MEDIA_INFO_IN_PAGE, mcdi_page);
1652 efx_mcdi_execute(enp, &req);
1654 if (req.emr_rc != 0) {
1659 if (req.emr_out_length_used !=
1660 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE)) {
1665 if (MCDI_OUT_DWORD(req, GET_PHY_MEDIA_INFO_OUT_DATALEN) !=
1666 EFX_PHY_MEDIA_INFO_PAGE_SIZE) {
1672 MCDI_OUT2(req, uint8_t, GET_PHY_MEDIA_INFO_OUT_DATA) + offset,
1682 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1688 * 2-wire device address of the base information in accordance with SFF-8472
1689 * Diagnostic Monitoring Interface for Optical Transceivers section
1690 * 4 Memory Organization.
1692 #define EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE 0xA0
1695 * 2-wire device address of the digital diagnostics monitoring interface
1696 * in accordance with SFF-8472 Diagnostic Monitoring Interface for Optical
1697 * Transceivers section 4 Memory Organization.
1699 #define EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM 0xA2
1702 * Hard wired 2-wire device address for QSFP+ in accordance with SFF-8436
1703 * QSFP+ 10 Gbs 4X PLUGGABLE TRANSCEIVER section 7.4 Device Addressing and
1706 #define EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP 0xA0
1708 __checkReturn efx_rc_t
1709 efx_mcdi_phy_module_get_info(
1710 __in efx_nic_t *enp,
1711 __in uint8_t dev_addr,
1712 __in uint8_t offset,
1714 __out_bcount(len) uint8_t *data)
1716 efx_port_t *epp = &(enp->en_port);
1718 uint32_t mcdi_lower_page;
1719 uint32_t mcdi_upper_page;
1721 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1724 * Map device address to MC_CMD_GET_PHY_MEDIA_INFO pages.
1725 * Offset plus length interface allows to access page 0 only.
1726 * I.e. non-zero upper pages are not accessible.
1727 * See SFF-8472 section 4 Memory Organization and SFF-8436 section 7.6
1728 * QSFP+ Memory Map for details on how information is structured
1731 switch (epp->ep_fixed_port_type) {
1732 case EFX_PHY_MEDIA_SFP_PLUS:
1734 * In accordance with SFF-8472 Diagnostic Monitoring
1735 * Interface for Optical Transceivers section 4 Memory
1736 * Organization two 2-wire addresses are defined.
1739 /* Base information */
1740 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE:
1742 * MCDI page 0 should be used to access lower
1743 * page 0 (0x00 - 0x7f) at the device address 0xA0.
1745 mcdi_lower_page = 0;
1747 * MCDI page 1 should be used to access upper
1748 * page 0 (0x80 - 0xff) at the device address 0xA0.
1750 mcdi_upper_page = 1;
1753 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM:
1755 * MCDI page 2 should be used to access lower
1756 * page 0 (0x00 - 0x7f) at the device address 0xA2.
1758 mcdi_lower_page = 2;
1760 * MCDI page 3 should be used to access upper
1761 * page 0 (0x80 - 0xff) at the device address 0xA2.
1763 mcdi_upper_page = 3;
1770 case EFX_PHY_MEDIA_QSFP_PLUS:
1772 case EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP:
1774 * MCDI page -1 should be used to access lower page 0
1777 mcdi_lower_page = (uint32_t)-1;
1779 * MCDI page 0 should be used to access upper page 0
1782 mcdi_upper_page = 0;
1794 if (offset < EFX_PHY_MEDIA_INFO_PAGE_SIZE) {
1796 MIN(len, EFX_PHY_MEDIA_INFO_PAGE_SIZE - offset);
1798 rc = efx_mcdi_get_phy_media_info(enp,
1799 mcdi_lower_page, offset, read_len, data);
1808 offset -= EFX_PHY_MEDIA_INFO_PAGE_SIZE;
1812 EFSYS_ASSERT3U(len, <=, EFX_PHY_MEDIA_INFO_PAGE_SIZE);
1813 EFSYS_ASSERT3U(offset, <, EFX_PHY_MEDIA_INFO_PAGE_SIZE);
1815 rc = efx_mcdi_get_phy_media_info(enp,
1816 mcdi_upper_page, offset, len, data);
1828 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1833 #endif /* EFSYS_OPT_MCDI */