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.
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
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.
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.
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.
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.
62 static const efx_mcdi_ops_t __efx_mcdi_siena_ops = {
63 siena_mcdi_init, /* emco_init */
64 siena_mcdi_send_request, /* emco_send_request */
65 siena_mcdi_poll_reboot, /* emco_poll_reboot */
66 siena_mcdi_poll_response, /* emco_poll_response */
67 siena_mcdi_read_response, /* emco_read_response */
68 siena_mcdi_fini, /* emco_fini */
69 siena_mcdi_feature_supported, /* emco_feature_supported */
70 siena_mcdi_get_timeout, /* emco_get_timeout */
73 #endif /* EFSYS_OPT_SIENA */
75 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
77 static const efx_mcdi_ops_t __efx_mcdi_ef10_ops = {
78 ef10_mcdi_init, /* emco_init */
79 ef10_mcdi_send_request, /* emco_send_request */
80 ef10_mcdi_poll_reboot, /* emco_poll_reboot */
81 ef10_mcdi_poll_response, /* emco_poll_response */
82 ef10_mcdi_read_response, /* emco_read_response */
83 ef10_mcdi_fini, /* emco_fini */
84 ef10_mcdi_feature_supported, /* emco_feature_supported */
85 ef10_mcdi_get_timeout, /* emco_get_timeout */
88 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
92 __checkReturn efx_rc_t
95 __in const efx_mcdi_transport_t *emtp)
97 const efx_mcdi_ops_t *emcop;
100 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
101 EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
103 switch (enp->en_family) {
105 case EFX_FAMILY_SIENA:
106 emcop = &__efx_mcdi_siena_ops;
108 #endif /* EFSYS_OPT_SIENA */
110 #if EFSYS_OPT_HUNTINGTON
111 case EFX_FAMILY_HUNTINGTON:
112 emcop = &__efx_mcdi_ef10_ops;
114 #endif /* EFSYS_OPT_HUNTINGTON */
116 #if EFSYS_OPT_MEDFORD
117 case EFX_FAMILY_MEDFORD:
118 emcop = &__efx_mcdi_ef10_ops;
120 #endif /* EFSYS_OPT_MEDFORD */
128 if (enp->en_features & EFX_FEATURE_MCDI_DMA) {
129 /* MCDI requires a DMA buffer in host memory */
130 if ((emtp == NULL) || (emtp->emt_dma_mem) == NULL) {
135 enp->en_mcdi.em_emtp = emtp;
137 if (emcop != NULL && emcop->emco_init != NULL) {
138 if ((rc = emcop->emco_init(enp, emtp)) != 0)
142 enp->en_mcdi.em_emcop = emcop;
143 enp->en_mod_flags |= EFX_MOD_MCDI;
152 EFSYS_PROBE1(fail1, efx_rc_t, rc);
154 enp->en_mcdi.em_emcop = NULL;
155 enp->en_mcdi.em_emtp = NULL;
156 enp->en_mod_flags &= ~EFX_MOD_MCDI;
165 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
166 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
168 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
169 EFSYS_ASSERT3U(enp->en_mod_flags, ==, EFX_MOD_MCDI);
171 if (emcop != NULL && emcop->emco_fini != NULL)
172 emcop->emco_fini(enp);
175 emip->emi_aborted = 0;
177 enp->en_mcdi.em_emcop = NULL;
178 enp->en_mod_flags &= ~EFX_MOD_MCDI;
185 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
186 efsys_lock_state_t state;
188 /* Start a new epoch (allow fresh MCDI requests to succeed) */
189 EFSYS_LOCK(enp->en_eslp, state);
190 emip->emi_new_epoch = B_TRUE;
191 EFSYS_UNLOCK(enp->en_eslp, state);
195 efx_mcdi_send_request(
202 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
204 emcop->emco_send_request(enp, hdrp, hdr_len, sdup, sdu_len);
208 efx_mcdi_poll_reboot(
211 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
214 rc = emcop->emco_poll_reboot(enp);
219 efx_mcdi_poll_response(
222 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
225 available = emcop->emco_poll_response(enp);
230 efx_mcdi_read_response(
236 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
238 emcop->emco_read_response(enp, bufferp, offset, length);
242 efx_mcdi_request_start(
244 __in efx_mcdi_req_t *emrp,
245 __in boolean_t ev_cpl)
247 #if EFSYS_OPT_MCDI_LOGGING
248 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
250 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
253 unsigned int max_version;
257 efsys_lock_state_t state;
259 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
260 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
261 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
264 * efx_mcdi_request_start() is naturally serialised against both
265 * efx_mcdi_request_poll() and efx_mcdi_ev_cpl()/efx_mcdi_ev_death(),
266 * by virtue of there only being one outstanding MCDI request.
267 * Unfortunately, upper layers may also call efx_mcdi_request_abort()
268 * at any time, to timeout a pending mcdi request, That request may
269 * then subsequently complete, meaning efx_mcdi_ev_cpl() or
270 * efx_mcdi_ev_death() may end up running in parallel with
271 * efx_mcdi_request_start(). This race is handled by ensuring that
272 * %emi_pending_req, %emi_ev_cpl and %emi_seq are protected by the
275 EFSYS_LOCK(enp->en_eslp, state);
276 EFSYS_ASSERT(emip->emi_pending_req == NULL);
277 emip->emi_pending_req = emrp;
278 emip->emi_ev_cpl = ev_cpl;
279 emip->emi_poll_cnt = 0;
280 seq = emip->emi_seq++ & EFX_MASK32(MCDI_HEADER_SEQ);
281 new_epoch = emip->emi_new_epoch;
282 max_version = emip->emi_max_version;
283 EFSYS_UNLOCK(enp->en_eslp, state);
287 xflags |= MCDI_HEADER_XFLAGS_EVREQ;
290 * Huntington firmware supports MCDIv2, but the Huntington BootROM only
291 * supports MCDIv1. Use MCDIv1 headers for MCDIv1 commands where
292 * possible to support this.
294 if ((max_version >= 2) &&
295 ((emrp->emr_cmd > MC_CMD_CMD_SPACE_ESCAPE_7) ||
296 (emrp->emr_in_length > MCDI_CTL_SDU_LEN_MAX_V1))) {
297 /* Construct MCDI v2 header */
298 hdr_len = sizeof (hdr);
299 EFX_POPULATE_DWORD_8(hdr[0],
300 MCDI_HEADER_CODE, MC_CMD_V2_EXTN,
301 MCDI_HEADER_RESYNC, 1,
302 MCDI_HEADER_DATALEN, 0,
303 MCDI_HEADER_SEQ, seq,
304 MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
305 MCDI_HEADER_ERROR, 0,
306 MCDI_HEADER_RESPONSE, 0,
307 MCDI_HEADER_XFLAGS, xflags);
309 EFX_POPULATE_DWORD_2(hdr[1],
310 MC_CMD_V2_EXTN_IN_EXTENDED_CMD, emrp->emr_cmd,
311 MC_CMD_V2_EXTN_IN_ACTUAL_LEN, emrp->emr_in_length);
313 /* Construct MCDI v1 header */
314 hdr_len = sizeof (hdr[0]);
315 EFX_POPULATE_DWORD_8(hdr[0],
316 MCDI_HEADER_CODE, emrp->emr_cmd,
317 MCDI_HEADER_RESYNC, 1,
318 MCDI_HEADER_DATALEN, emrp->emr_in_length,
319 MCDI_HEADER_SEQ, seq,
320 MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
321 MCDI_HEADER_ERROR, 0,
322 MCDI_HEADER_RESPONSE, 0,
323 MCDI_HEADER_XFLAGS, xflags);
326 #if EFSYS_OPT_MCDI_LOGGING
327 if (emtp->emt_logger != NULL) {
328 emtp->emt_logger(emtp->emt_context, EFX_LOG_MCDI_REQUEST,
330 emrp->emr_in_buf, emrp->emr_in_length);
332 #endif /* EFSYS_OPT_MCDI_LOGGING */
334 efx_mcdi_send_request(enp, &hdr[0], hdr_len,
335 emrp->emr_in_buf, emrp->emr_in_length);
340 efx_mcdi_read_response_header(
342 __inout efx_mcdi_req_t *emrp)
344 #if EFSYS_OPT_MCDI_LOGGING
345 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
346 #endif /* EFSYS_OPT_MCDI_LOGGING */
347 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
349 unsigned int hdr_len;
350 unsigned int data_len;
356 EFSYS_ASSERT(emrp != NULL);
358 efx_mcdi_read_response(enp, &hdr[0], 0, sizeof (hdr[0]));
359 hdr_len = sizeof (hdr[0]);
361 cmd = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE);
362 seq = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_SEQ);
363 error = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_ERROR);
365 if (cmd != MC_CMD_V2_EXTN) {
366 data_len = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_DATALEN);
368 efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1]));
369 hdr_len += sizeof (hdr[1]);
371 cmd = EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_EXTENDED_CMD);
373 EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
376 if (error && (data_len == 0)) {
377 /* The MC has rebooted since the request was sent. */
378 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
379 efx_mcdi_poll_reboot(enp);
383 if ((cmd != emrp->emr_cmd) ||
384 (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
385 /* Response is for a different request */
391 unsigned int err_len = MIN(data_len, sizeof (err));
392 int err_code = MC_CMD_ERR_EPROTO;
395 /* Read error code (and arg num for MCDI v2 commands) */
396 efx_mcdi_read_response(enp, &err, hdr_len, err_len);
398 if (err_len >= (MC_CMD_ERR_CODE_OFST + sizeof (efx_dword_t)))
399 err_code = EFX_DWORD_FIELD(err[0], EFX_DWORD_0);
401 if (err_len >= (MC_CMD_ERR_ARG_OFST + sizeof (efx_dword_t)))
402 err_arg = EFX_DWORD_FIELD(err[1], EFX_DWORD_0);
404 emrp->emr_err_code = err_code;
405 emrp->emr_err_arg = err_arg;
407 #if EFSYS_OPT_MCDI_PROXY_AUTH
408 if ((err_code == MC_CMD_ERR_PROXY_PENDING) &&
409 (err_len == sizeof (err))) {
411 * The MCDI request would normally fail with EPERM, but
412 * firmware has forwarded it to an authorization agent
413 * attached to a privileged PF.
415 * Save the authorization request handle. The client
416 * must wait for a PROXY_RESPONSE event, or timeout.
418 emrp->emr_proxy_handle = err_arg;
420 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
422 #if EFSYS_OPT_MCDI_LOGGING
423 if (emtp->emt_logger != NULL) {
424 emtp->emt_logger(emtp->emt_context,
425 EFX_LOG_MCDI_RESPONSE,
429 #endif /* EFSYS_OPT_MCDI_LOGGING */
431 if (!emrp->emr_quiet) {
432 EFSYS_PROBE3(mcdi_err_arg, int, emrp->emr_cmd,
433 int, err_code, int, err_arg);
436 rc = efx_mcdi_request_errcode(err_code);
441 emrp->emr_out_length_used = data_len;
442 #if EFSYS_OPT_MCDI_PROXY_AUTH
443 emrp->emr_proxy_handle = 0;
444 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
451 emrp->emr_out_length_used = 0;
455 efx_mcdi_finish_response(
457 __in efx_mcdi_req_t *emrp)
459 #if EFSYS_OPT_MCDI_LOGGING
460 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
461 #endif /* EFSYS_OPT_MCDI_LOGGING */
463 unsigned int hdr_len;
466 if (emrp->emr_out_buf == NULL)
469 /* Read the command header to detect MCDI response format */
470 hdr_len = sizeof (hdr[0]);
471 efx_mcdi_read_response(enp, &hdr[0], 0, hdr_len);
472 if (EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) {
474 * Read the actual payload length. The length given in the event
475 * is only correct for responses with the V1 format.
477 efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1]));
478 hdr_len += sizeof (hdr[1]);
480 emrp->emr_out_length_used = EFX_DWORD_FIELD(hdr[1],
481 MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
484 /* Copy payload out into caller supplied buffer */
485 bytes = MIN(emrp->emr_out_length_used, emrp->emr_out_length);
486 efx_mcdi_read_response(enp, emrp->emr_out_buf, hdr_len, bytes);
488 #if EFSYS_OPT_MCDI_LOGGING
489 if (emtp->emt_logger != NULL) {
490 emtp->emt_logger(emtp->emt_context,
491 EFX_LOG_MCDI_RESPONSE,
493 emrp->emr_out_buf, bytes);
495 #endif /* EFSYS_OPT_MCDI_LOGGING */
499 __checkReturn boolean_t
500 efx_mcdi_request_poll(
503 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
504 efx_mcdi_req_t *emrp;
505 efsys_lock_state_t state;
508 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
509 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
510 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
512 /* Serialise against post-watchdog efx_mcdi_ev* */
513 EFSYS_LOCK(enp->en_eslp, state);
515 EFSYS_ASSERT(emip->emi_pending_req != NULL);
516 EFSYS_ASSERT(!emip->emi_ev_cpl);
517 emrp = emip->emi_pending_req;
519 /* Check for reboot atomically w.r.t efx_mcdi_request_start */
520 if (emip->emi_poll_cnt++ == 0) {
521 if ((rc = efx_mcdi_poll_reboot(enp)) != 0) {
522 emip->emi_pending_req = NULL;
523 EFSYS_UNLOCK(enp->en_eslp, state);
525 /* Reboot/Assertion */
526 if (rc == EIO || rc == EINTR)
527 efx_mcdi_raise_exception(enp, emrp, rc);
533 /* Check if a response is available */
534 if (efx_mcdi_poll_response(enp) == B_FALSE) {
535 EFSYS_UNLOCK(enp->en_eslp, state);
539 /* Read the response header */
540 efx_mcdi_read_response_header(enp, emrp);
542 /* Request complete */
543 emip->emi_pending_req = NULL;
545 /* Ensure stale MCDI requests fail after an MC reboot. */
546 emip->emi_new_epoch = B_FALSE;
548 EFSYS_UNLOCK(enp->en_eslp, state);
550 if ((rc = emrp->emr_rc) != 0)
553 efx_mcdi_finish_response(enp, emrp);
557 if (!emrp->emr_quiet)
560 if (!emrp->emr_quiet)
561 EFSYS_PROBE1(fail1, efx_rc_t, rc);
566 __checkReturn boolean_t
567 efx_mcdi_request_abort(
570 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
571 efx_mcdi_req_t *emrp;
573 efsys_lock_state_t state;
575 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
576 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
577 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
580 * efx_mcdi_ev_* may have already completed this event, and be
581 * spinning/blocked on the upper layer lock. So it *is* legitimate
582 * to for emi_pending_req to be NULL. If there is a pending event
583 * completed request, then provide a "credit" to allow
584 * efx_mcdi_ev_cpl() to accept a single spurious completion.
586 EFSYS_LOCK(enp->en_eslp, state);
587 emrp = emip->emi_pending_req;
588 aborted = (emrp != NULL);
590 emip->emi_pending_req = NULL;
592 /* Error the request */
593 emrp->emr_out_length_used = 0;
594 emrp->emr_rc = ETIMEDOUT;
596 /* Provide a credit for seqno/emr_pending_req mismatches */
597 if (emip->emi_ev_cpl)
601 * The upper layer has called us, so we don't
602 * need to complete the request.
605 EFSYS_UNLOCK(enp->en_eslp, state);
611 efx_mcdi_get_timeout(
613 __in efx_mcdi_req_t *emrp,
614 __out uint32_t *timeoutp)
616 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
618 emcop->emco_get_timeout(enp, emrp, timeoutp);
621 __checkReturn efx_rc_t
622 efx_mcdi_request_errcode(
623 __in unsigned int err)
628 case MC_CMD_ERR_EPERM:
630 case MC_CMD_ERR_ENOENT:
632 case MC_CMD_ERR_EINTR:
634 case MC_CMD_ERR_EACCES:
636 case MC_CMD_ERR_EBUSY:
638 case MC_CMD_ERR_EINVAL:
640 case MC_CMD_ERR_EDEADLK:
642 case MC_CMD_ERR_ENOSYS:
644 case MC_CMD_ERR_ETIME:
646 case MC_CMD_ERR_ENOTSUP:
648 case MC_CMD_ERR_EALREADY:
652 case MC_CMD_ERR_EEXIST:
654 #ifdef MC_CMD_ERR_EAGAIN
655 case MC_CMD_ERR_EAGAIN:
658 #ifdef MC_CMD_ERR_ENOSPC
659 case MC_CMD_ERR_ENOSPC:
662 case MC_CMD_ERR_ERANGE:
665 case MC_CMD_ERR_ALLOC_FAIL:
667 case MC_CMD_ERR_NO_VADAPTOR:
669 case MC_CMD_ERR_NO_EVB_PORT:
671 case MC_CMD_ERR_NO_VSWITCH:
673 case MC_CMD_ERR_VLAN_LIMIT:
675 case MC_CMD_ERR_BAD_PCI_FUNC:
677 case MC_CMD_ERR_BAD_VLAN_MODE:
679 case MC_CMD_ERR_BAD_VSWITCH_TYPE:
681 case MC_CMD_ERR_BAD_VPORT_TYPE:
683 case MC_CMD_ERR_MAC_EXIST:
686 case MC_CMD_ERR_PROXY_PENDING:
690 EFSYS_PROBE1(mc_pcol_error, int, err);
696 efx_mcdi_raise_exception(
698 __in_opt efx_mcdi_req_t *emrp,
701 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
702 efx_mcdi_exception_t exception;
704 /* Reboot or Assertion failure only */
705 EFSYS_ASSERT(rc == EIO || rc == EINTR);
708 * If MC_CMD_REBOOT causes a reboot (dependent on parameters),
709 * then the EIO is not worthy of an exception.
711 if (emrp != NULL && emrp->emr_cmd == MC_CMD_REBOOT && rc == EIO)
714 exception = (rc == EIO)
715 ? EFX_MCDI_EXCEPTION_MC_REBOOT
716 : EFX_MCDI_EXCEPTION_MC_BADASSERT;
718 emtp->emt_exception(emtp->emt_context, exception);
724 __inout efx_mcdi_req_t *emrp)
726 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
728 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
729 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
731 emrp->emr_quiet = B_FALSE;
732 emtp->emt_execute(emtp->emt_context, emrp);
736 efx_mcdi_execute_quiet(
738 __inout efx_mcdi_req_t *emrp)
740 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
742 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
743 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
745 emrp->emr_quiet = B_TRUE;
746 emtp->emt_execute(emtp->emt_context, emrp);
752 __in unsigned int seq,
753 __in unsigned int outlen,
756 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
757 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
758 efx_mcdi_req_t *emrp;
759 efsys_lock_state_t state;
761 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
762 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
765 * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start()
766 * when we're completing an aborted request.
768 EFSYS_LOCK(enp->en_eslp, state);
769 if (emip->emi_pending_req == NULL || !emip->emi_ev_cpl ||
770 (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
771 EFSYS_ASSERT(emip->emi_aborted > 0);
772 if (emip->emi_aborted > 0)
774 EFSYS_UNLOCK(enp->en_eslp, state);
778 emrp = emip->emi_pending_req;
779 emip->emi_pending_req = NULL;
780 EFSYS_UNLOCK(enp->en_eslp, state);
782 if (emip->emi_max_version >= 2) {
783 /* MCDIv2 response details do not fit into an event. */
784 efx_mcdi_read_response_header(enp, emrp);
787 if (!emrp->emr_quiet) {
788 EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd,
791 emrp->emr_out_length_used = 0;
792 emrp->emr_rc = efx_mcdi_request_errcode(errcode);
794 emrp->emr_out_length_used = outlen;
799 efx_mcdi_finish_response(enp, emrp);
802 emtp->emt_ev_cpl(emtp->emt_context);
805 #if EFSYS_OPT_MCDI_PROXY_AUTH
807 __checkReturn efx_rc_t
808 efx_mcdi_get_proxy_handle(
810 __in efx_mcdi_req_t *emrp,
811 __out uint32_t *handlep)
816 * Return proxy handle from MCDI request that returned with error
817 * MC_MCD_ERR_PROXY_PENDING. This handle is used to wait for a matching
818 * PROXY_RESPONSE event.
820 if ((emrp == NULL) || (handlep == NULL)) {
824 if ((emrp->emr_rc != 0) &&
825 (emrp->emr_err_code == MC_CMD_ERR_PROXY_PENDING)) {
826 *handlep = emrp->emr_proxy_handle;
835 EFSYS_PROBE1(fail1, efx_rc_t, rc);
840 efx_mcdi_ev_proxy_response(
842 __in unsigned int handle,
843 __in unsigned int status)
845 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
849 * Handle results of an authorization request for a privileged MCDI
850 * command. If authorization was granted then we must re-issue the
851 * original MCDI request. If authorization failed or timed out,
852 * then the original MCDI request should be completed with the
853 * result code from this event.
855 rc = (status == 0) ? 0 : efx_mcdi_request_errcode(status);
857 emtp->emt_ev_proxy_response(emtp->emt_context, handle, rc);
859 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
866 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
867 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
868 efx_mcdi_req_t *emrp = NULL;
870 efsys_lock_state_t state;
873 * The MCDI request (if there is one) has been terminated, either
874 * by a BADASSERT or REBOOT event.
876 * If there is an outstanding event-completed MCDI operation, then we
877 * will never receive the completion event (because both MCDI
878 * completions and BADASSERT events are sent to the same evq). So
879 * complete this MCDI op.
881 * This function might run in parallel with efx_mcdi_request_poll()
882 * for poll completed mcdi requests, and also with
883 * efx_mcdi_request_start() for post-watchdog completions.
885 EFSYS_LOCK(enp->en_eslp, state);
886 emrp = emip->emi_pending_req;
887 ev_cpl = emip->emi_ev_cpl;
888 if (emrp != NULL && emip->emi_ev_cpl) {
889 emip->emi_pending_req = NULL;
891 emrp->emr_out_length_used = 0;
897 * Since we're running in parallel with a request, consume the
898 * status word before dropping the lock.
900 if (rc == EIO || rc == EINTR) {
901 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
902 (void) efx_mcdi_poll_reboot(enp);
903 emip->emi_new_epoch = B_TRUE;
906 EFSYS_UNLOCK(enp->en_eslp, state);
908 efx_mcdi_raise_exception(enp, emrp, rc);
910 if (emrp != NULL && ev_cpl)
911 emtp->emt_ev_cpl(emtp->emt_context);
914 __checkReturn efx_rc_t
917 __out_ecount_opt(4) uint16_t versionp[4],
918 __out_opt uint32_t *buildp,
919 __out_opt efx_mcdi_boot_t *statusp)
922 uint8_t payload[MAX(MAX(MC_CMD_GET_VERSION_IN_LEN,
923 MC_CMD_GET_VERSION_OUT_LEN),
924 MAX(MC_CMD_GET_BOOT_STATUS_IN_LEN,
925 MC_CMD_GET_BOOT_STATUS_OUT_LEN))];
926 efx_word_t *ver_words;
929 efx_mcdi_boot_t status;
932 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
934 (void) memset(payload, 0, sizeof (payload));
935 req.emr_cmd = MC_CMD_GET_VERSION;
936 req.emr_in_buf = payload;
937 req.emr_in_length = MC_CMD_GET_VERSION_IN_LEN;
938 req.emr_out_buf = payload;
939 req.emr_out_length = MC_CMD_GET_VERSION_OUT_LEN;
941 efx_mcdi_execute(enp, &req);
943 if (req.emr_rc != 0) {
948 /* bootrom support */
949 if (req.emr_out_length_used == MC_CMD_GET_VERSION_V0_OUT_LEN) {
950 version[0] = version[1] = version[2] = version[3] = 0;
951 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
956 if (req.emr_out_length_used < MC_CMD_GET_VERSION_OUT_LEN) {
961 ver_words = MCDI_OUT2(req, efx_word_t, GET_VERSION_OUT_VERSION);
962 version[0] = EFX_WORD_FIELD(ver_words[0], EFX_WORD_0);
963 version[1] = EFX_WORD_FIELD(ver_words[1], EFX_WORD_0);
964 version[2] = EFX_WORD_FIELD(ver_words[2], EFX_WORD_0);
965 version[3] = EFX_WORD_FIELD(ver_words[3], EFX_WORD_0);
966 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
969 /* The bootrom doesn't understand BOOT_STATUS */
970 if (MC_FW_VERSION_IS_BOOTLOADER(build)) {
971 status = EFX_MCDI_BOOT_ROM;
975 (void) memset(payload, 0, sizeof (payload));
976 req.emr_cmd = MC_CMD_GET_BOOT_STATUS;
977 req.emr_in_buf = payload;
978 req.emr_in_length = MC_CMD_GET_BOOT_STATUS_IN_LEN;
979 req.emr_out_buf = payload;
980 req.emr_out_length = MC_CMD_GET_BOOT_STATUS_OUT_LEN;
982 efx_mcdi_execute_quiet(enp, &req);
984 if (req.emr_rc == EACCES) {
985 /* Unprivileged functions cannot access BOOT_STATUS */
986 status = EFX_MCDI_BOOT_PRIMARY;
987 version[0] = version[1] = version[2] = version[3] = 0;
992 if (req.emr_rc != 0) {
997 if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) {
1002 if (MCDI_OUT_DWORD_FIELD(req, GET_BOOT_STATUS_OUT_FLAGS,
1003 GET_BOOT_STATUS_OUT_FLAGS_PRIMARY))
1004 status = EFX_MCDI_BOOT_PRIMARY;
1006 status = EFX_MCDI_BOOT_SECONDARY;
1009 if (versionp != NULL)
1010 memcpy(versionp, version, sizeof (version));
1013 if (statusp != NULL)
1025 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1030 static __checkReturn efx_rc_t
1032 __in efx_nic_t *enp,
1033 __in boolean_t after_assertion)
1035 uint8_t payload[MAX(MC_CMD_REBOOT_IN_LEN, MC_CMD_REBOOT_OUT_LEN)];
1040 * We could require the caller to have caused en_mod_flags=0 to
1041 * call this function. This doesn't help the other port though,
1042 * who's about to get the MC ripped out from underneath them.
1043 * Since they have to cope with the subsequent fallout of MCDI
1044 * failures, we should as well.
1046 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1048 (void) memset(payload, 0, sizeof (payload));
1049 req.emr_cmd = MC_CMD_REBOOT;
1050 req.emr_in_buf = payload;
1051 req.emr_in_length = MC_CMD_REBOOT_IN_LEN;
1052 req.emr_out_buf = payload;
1053 req.emr_out_length = MC_CMD_REBOOT_OUT_LEN;
1055 MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS,
1056 (after_assertion ? MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION : 0));
1058 efx_mcdi_execute_quiet(enp, &req);
1060 if (req.emr_rc == EACCES) {
1061 /* Unprivileged functions cannot reboot the MC. */
1065 /* A successful reboot request returns EIO. */
1066 if (req.emr_rc != 0 && req.emr_rc != EIO) {
1075 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1080 __checkReturn efx_rc_t
1082 __in efx_nic_t *enp)
1084 return (efx_mcdi_do_reboot(enp, B_FALSE));
1087 __checkReturn efx_rc_t
1088 efx_mcdi_exit_assertion_handler(
1089 __in efx_nic_t *enp)
1091 return (efx_mcdi_do_reboot(enp, B_TRUE));
1094 __checkReturn efx_rc_t
1095 efx_mcdi_read_assertion(
1096 __in efx_nic_t *enp)
1099 uint8_t payload[MAX(MC_CMD_GET_ASSERTS_IN_LEN,
1100 MC_CMD_GET_ASSERTS_OUT_LEN)];
1109 * Before we attempt to chat to the MC, we should verify that the MC
1110 * isn't in it's assertion handler, either due to a previous reboot,
1111 * or because we're reinitializing due to an eec_exception().
1113 * Use GET_ASSERTS to read any assertion state that may be present.
1114 * Retry this command twice. Once because a boot-time assertion failure
1115 * might cause the 1st MCDI request to fail. And once again because
1116 * we might race with efx_mcdi_exit_assertion_handler() running on
1117 * partner port(s) on the same NIC.
1121 (void) memset(payload, 0, sizeof (payload));
1122 req.emr_cmd = MC_CMD_GET_ASSERTS;
1123 req.emr_in_buf = payload;
1124 req.emr_in_length = MC_CMD_GET_ASSERTS_IN_LEN;
1125 req.emr_out_buf = payload;
1126 req.emr_out_length = MC_CMD_GET_ASSERTS_OUT_LEN;
1128 MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1);
1129 efx_mcdi_execute_quiet(enp, &req);
1131 } while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0);
1133 if (req.emr_rc != 0) {
1134 if (req.emr_rc == EACCES) {
1135 /* Unprivileged functions cannot clear assertions. */
1142 if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) {
1147 /* Print out any assertion state recorded */
1148 flags = MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_GLOBAL_FLAGS);
1149 if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
1152 reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
1153 ? "system-level assertion"
1154 : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
1155 ? "thread-level assertion"
1156 : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
1158 : (flags == MC_CMD_GET_ASSERTS_FLAGS_ADDR_TRAP)
1159 ? "illegal address trap"
1160 : "unknown assertion";
1161 EFSYS_PROBE3(mcpu_assertion,
1162 const char *, reason, unsigned int,
1163 MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_SAVED_PC_OFFS),
1165 MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS));
1167 /* Print out the registers (r1 ... r31) */
1168 ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST;
1170 index < 1 + MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM;
1172 EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int,
1173 EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst),
1175 ofst += sizeof (efx_dword_t);
1177 EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN);
1185 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1192 * Internal routines for for specific MCDI requests.
1195 __checkReturn efx_rc_t
1196 efx_mcdi_drv_attach(
1197 __in efx_nic_t *enp,
1198 __in boolean_t attach)
1201 uint8_t payload[MAX(MC_CMD_DRV_ATTACH_IN_LEN,
1202 MC_CMD_DRV_ATTACH_EXT_OUT_LEN)];
1205 (void) memset(payload, 0, sizeof (payload));
1206 req.emr_cmd = MC_CMD_DRV_ATTACH;
1207 req.emr_in_buf = payload;
1208 req.emr_in_length = MC_CMD_DRV_ATTACH_IN_LEN;
1209 req.emr_out_buf = payload;
1210 req.emr_out_length = MC_CMD_DRV_ATTACH_EXT_OUT_LEN;
1213 * Use DONT_CARE for the datapath firmware type to ensure that the
1214 * driver can attach to an unprivileged function. The datapath firmware
1215 * type to use is controlled by the 'sfboot' utility.
1217 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_NEW_STATE, attach ? 1 : 0);
1218 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_UPDATE, 1);
1219 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_FIRMWARE_ID, MC_CMD_FW_DONT_CARE);
1221 efx_mcdi_execute(enp, &req);
1223 if (req.emr_rc != 0) {
1228 if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) {
1238 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1243 __checkReturn efx_rc_t
1244 efx_mcdi_get_board_cfg(
1245 __in efx_nic_t *enp,
1246 __out_opt uint32_t *board_typep,
1247 __out_opt efx_dword_t *capabilitiesp,
1248 __out_ecount_opt(6) uint8_t mac_addrp[6])
1250 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
1252 uint8_t payload[MAX(MC_CMD_GET_BOARD_CFG_IN_LEN,
1253 MC_CMD_GET_BOARD_CFG_OUT_LENMIN)];
1256 (void) memset(payload, 0, sizeof (payload));
1257 req.emr_cmd = MC_CMD_GET_BOARD_CFG;
1258 req.emr_in_buf = payload;
1259 req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN;
1260 req.emr_out_buf = payload;
1261 req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMIN;
1263 efx_mcdi_execute(enp, &req);
1265 if (req.emr_rc != 0) {
1270 if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
1275 if (mac_addrp != NULL) {
1278 if (emip->emi_port == 1) {
1279 addrp = MCDI_OUT2(req, uint8_t,
1280 GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0);
1281 } else if (emip->emi_port == 2) {
1282 addrp = MCDI_OUT2(req, uint8_t,
1283 GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1);
1289 EFX_MAC_ADDR_COPY(mac_addrp, addrp);
1292 if (capabilitiesp != NULL) {
1293 if (emip->emi_port == 1) {
1294 *capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
1295 GET_BOARD_CFG_OUT_CAPABILITIES_PORT0);
1296 } else if (emip->emi_port == 2) {
1297 *capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
1298 GET_BOARD_CFG_OUT_CAPABILITIES_PORT1);
1305 if (board_typep != NULL) {
1306 *board_typep = MCDI_OUT_DWORD(req,
1307 GET_BOARD_CFG_OUT_BOARD_TYPE);
1319 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1324 __checkReturn efx_rc_t
1325 efx_mcdi_get_resource_limits(
1326 __in efx_nic_t *enp,
1327 __out_opt uint32_t *nevqp,
1328 __out_opt uint32_t *nrxqp,
1329 __out_opt uint32_t *ntxqp)
1332 uint8_t payload[MAX(MC_CMD_GET_RESOURCE_LIMITS_IN_LEN,
1333 MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN)];
1336 (void) memset(payload, 0, sizeof (payload));
1337 req.emr_cmd = MC_CMD_GET_RESOURCE_LIMITS;
1338 req.emr_in_buf = payload;
1339 req.emr_in_length = MC_CMD_GET_RESOURCE_LIMITS_IN_LEN;
1340 req.emr_out_buf = payload;
1341 req.emr_out_length = MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN;
1343 efx_mcdi_execute(enp, &req);
1345 if (req.emr_rc != 0) {
1350 if (req.emr_out_length_used < MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) {
1356 *nevqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_EVQ);
1358 *nrxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ);
1360 *ntxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ);
1367 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1372 __checkReturn efx_rc_t
1373 efx_mcdi_get_phy_cfg(
1374 __in efx_nic_t *enp)
1376 efx_port_t *epp = &(enp->en_port);
1377 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1379 uint8_t payload[MAX(MC_CMD_GET_PHY_CFG_IN_LEN,
1380 MC_CMD_GET_PHY_CFG_OUT_LEN)];
1383 (void) memset(payload, 0, sizeof (payload));
1384 req.emr_cmd = MC_CMD_GET_PHY_CFG;
1385 req.emr_in_buf = payload;
1386 req.emr_in_length = MC_CMD_GET_PHY_CFG_IN_LEN;
1387 req.emr_out_buf = payload;
1388 req.emr_out_length = MC_CMD_GET_PHY_CFG_OUT_LEN;
1390 efx_mcdi_execute(enp, &req);
1392 if (req.emr_rc != 0) {
1397 if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) {
1402 encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE);
1404 (void) strncpy(encp->enc_phy_name,
1405 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME),
1406 MIN(sizeof (encp->enc_phy_name) - 1,
1407 MC_CMD_GET_PHY_CFG_OUT_NAME_LEN));
1408 #endif /* EFSYS_OPT_NAMES */
1409 (void) memset(encp->enc_phy_revision, 0,
1410 sizeof (encp->enc_phy_revision));
1411 memcpy(encp->enc_phy_revision,
1412 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION),
1413 MIN(sizeof (encp->enc_phy_revision) - 1,
1414 MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN));
1415 #if EFSYS_OPT_PHY_LED_CONTROL
1416 encp->enc_led_mask = ((1 << EFX_PHY_LED_DEFAULT) |
1417 (1 << EFX_PHY_LED_OFF) |
1418 (1 << EFX_PHY_LED_ON));
1419 #endif /* EFSYS_OPT_PHY_LED_CONTROL */
1421 /* Get the media type of the fixed port, if recognised. */
1422 EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI);
1423 EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4);
1424 EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4);
1425 EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP);
1426 EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS);
1427 EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T);
1428 EFX_STATIC_ASSERT(MC_CMD_MEDIA_QSFP_PLUS == EFX_PHY_MEDIA_QSFP_PLUS);
1429 epp->ep_fixed_port_type =
1430 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE);
1431 if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES)
1432 epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID;
1434 epp->ep_phy_cap_mask =
1435 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP);
1436 #if EFSYS_OPT_PHY_FLAGS
1437 encp->enc_phy_flags_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_FLAGS);
1438 #endif /* EFSYS_OPT_PHY_FLAGS */
1440 encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT);
1442 /* Populate internal state */
1443 encp->enc_mcdi_mdio_channel =
1444 (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL);
1446 #if EFSYS_OPT_PHY_STATS
1447 encp->enc_mcdi_phy_stat_mask =
1448 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_STATS_MASK);
1449 #endif /* EFSYS_OPT_PHY_STATS */
1452 encp->enc_bist_mask = 0;
1453 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1454 GET_PHY_CFG_OUT_BIST_CABLE_SHORT))
1455 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_SHORT);
1456 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1457 GET_PHY_CFG_OUT_BIST_CABLE_LONG))
1458 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_LONG);
1459 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1460 GET_PHY_CFG_OUT_BIST))
1461 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_NORMAL);
1462 #endif /* EFSYS_OPT_BIST */
1469 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1474 __checkReturn efx_rc_t
1475 efx_mcdi_firmware_update_supported(
1476 __in efx_nic_t *enp,
1477 __out boolean_t *supportedp)
1479 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1482 if (emcop != NULL) {
1483 if ((rc = emcop->emco_feature_supported(enp,
1484 EFX_MCDI_FEATURE_FW_UPDATE, supportedp)) != 0)
1487 /* Earlier devices always supported updates */
1488 *supportedp = B_TRUE;
1494 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1499 __checkReturn efx_rc_t
1500 efx_mcdi_macaddr_change_supported(
1501 __in efx_nic_t *enp,
1502 __out boolean_t *supportedp)
1504 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1507 if (emcop != NULL) {
1508 if ((rc = emcop->emco_feature_supported(enp,
1509 EFX_MCDI_FEATURE_MACADDR_CHANGE, supportedp)) != 0)
1512 /* Earlier devices always supported MAC changes */
1513 *supportedp = B_TRUE;
1519 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1524 __checkReturn efx_rc_t
1525 efx_mcdi_link_control_supported(
1526 __in efx_nic_t *enp,
1527 __out boolean_t *supportedp)
1529 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1532 if (emcop != NULL) {
1533 if ((rc = emcop->emco_feature_supported(enp,
1534 EFX_MCDI_FEATURE_LINK_CONTROL, supportedp)) != 0)
1537 /* Earlier devices always supported link control */
1538 *supportedp = B_TRUE;
1544 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1549 __checkReturn efx_rc_t
1550 efx_mcdi_mac_spoofing_supported(
1551 __in efx_nic_t *enp,
1552 __out boolean_t *supportedp)
1554 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1557 if (emcop != NULL) {
1558 if ((rc = emcop->emco_feature_supported(enp,
1559 EFX_MCDI_FEATURE_MAC_SPOOFING, supportedp)) != 0)
1562 /* Earlier devices always supported MAC spoofing */
1563 *supportedp = B_TRUE;
1569 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1576 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
1578 * Enter bist offline mode. This is a fw mode which puts the NIC into a state
1579 * where memory BIST tests can be run and not much else can interfere or happen.
1580 * A reboot is required to exit this mode.
1582 __checkReturn efx_rc_t
1583 efx_mcdi_bist_enable_offline(
1584 __in efx_nic_t *enp)
1589 EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_IN_LEN == 0);
1590 EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_OUT_LEN == 0);
1592 req.emr_cmd = MC_CMD_ENABLE_OFFLINE_BIST;
1593 req.emr_in_buf = NULL;
1594 req.emr_in_length = 0;
1595 req.emr_out_buf = NULL;
1596 req.emr_out_length = 0;
1598 efx_mcdi_execute(enp, &req);
1600 if (req.emr_rc != 0) {
1608 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1612 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
1614 __checkReturn efx_rc_t
1615 efx_mcdi_bist_start(
1616 __in efx_nic_t *enp,
1617 __in efx_bist_type_t type)
1620 uint8_t payload[MAX(MC_CMD_START_BIST_IN_LEN,
1621 MC_CMD_START_BIST_OUT_LEN)];
1624 (void) memset(payload, 0, sizeof (payload));
1625 req.emr_cmd = MC_CMD_START_BIST;
1626 req.emr_in_buf = payload;
1627 req.emr_in_length = MC_CMD_START_BIST_IN_LEN;
1628 req.emr_out_buf = payload;
1629 req.emr_out_length = MC_CMD_START_BIST_OUT_LEN;
1632 case EFX_BIST_TYPE_PHY_NORMAL:
1633 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST);
1635 case EFX_BIST_TYPE_PHY_CABLE_SHORT:
1636 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1637 MC_CMD_PHY_BIST_CABLE_SHORT);
1639 case EFX_BIST_TYPE_PHY_CABLE_LONG:
1640 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1641 MC_CMD_PHY_BIST_CABLE_LONG);
1643 case EFX_BIST_TYPE_MC_MEM:
1644 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1645 MC_CMD_MC_MEM_BIST);
1647 case EFX_BIST_TYPE_SAT_MEM:
1648 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1649 MC_CMD_PORT_MEM_BIST);
1651 case EFX_BIST_TYPE_REG:
1652 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1659 efx_mcdi_execute(enp, &req);
1661 if (req.emr_rc != 0) {
1669 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1674 #endif /* EFSYS_OPT_BIST */
1677 /* Enable logging of some events (e.g. link state changes) */
1678 __checkReturn efx_rc_t
1680 __in efx_nic_t *enp)
1683 uint8_t payload[MAX(MC_CMD_LOG_CTRL_IN_LEN,
1684 MC_CMD_LOG_CTRL_OUT_LEN)];
1687 (void) memset(payload, 0, sizeof (payload));
1688 req.emr_cmd = MC_CMD_LOG_CTRL;
1689 req.emr_in_buf = payload;
1690 req.emr_in_length = MC_CMD_LOG_CTRL_IN_LEN;
1691 req.emr_out_buf = payload;
1692 req.emr_out_length = MC_CMD_LOG_CTRL_OUT_LEN;
1694 MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST,
1695 MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ);
1696 MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST_EVQ, 0);
1698 efx_mcdi_execute(enp, &req);
1700 if (req.emr_rc != 0) {
1708 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1714 #if EFSYS_OPT_MAC_STATS
1716 typedef enum efx_stats_action_e {
1719 EFX_STATS_ENABLE_NOEVENTS,
1720 EFX_STATS_ENABLE_EVENTS,
1722 } efx_stats_action_t;
1724 static __checkReturn efx_rc_t
1726 __in efx_nic_t *enp,
1727 __in_opt efsys_mem_t *esmp,
1728 __in efx_stats_action_t action,
1729 __in uint16_t period_ms)
1732 uint8_t payload[MAX(MC_CMD_MAC_STATS_IN_LEN,
1733 MC_CMD_MAC_STATS_OUT_DMA_LEN)];
1734 int clear = (action == EFX_STATS_CLEAR);
1735 int upload = (action == EFX_STATS_UPLOAD);
1736 int enable = (action == EFX_STATS_ENABLE_NOEVENTS);
1737 int events = (action == EFX_STATS_ENABLE_EVENTS);
1738 int disable = (action == EFX_STATS_DISABLE);
1741 (void) memset(payload, 0, sizeof (payload));
1742 req.emr_cmd = MC_CMD_MAC_STATS;
1743 req.emr_in_buf = payload;
1744 req.emr_in_length = MC_CMD_MAC_STATS_IN_LEN;
1745 req.emr_out_buf = payload;
1746 req.emr_out_length = MC_CMD_MAC_STATS_OUT_DMA_LEN;
1748 MCDI_IN_POPULATE_DWORD_6(req, MAC_STATS_IN_CMD,
1749 MAC_STATS_IN_DMA, upload,
1750 MAC_STATS_IN_CLEAR, clear,
1751 MAC_STATS_IN_PERIODIC_CHANGE, enable | events | disable,
1752 MAC_STATS_IN_PERIODIC_ENABLE, enable | events,
1753 MAC_STATS_IN_PERIODIC_NOEVENT, !events,
1754 MAC_STATS_IN_PERIOD_MS, (enable | events) ? period_ms : 0);
1757 int bytes = MC_CMD_MAC_NSTATS * sizeof (uint64_t);
1759 EFX_STATIC_ASSERT(MC_CMD_MAC_NSTATS * sizeof (uint64_t) <=
1760 EFX_MAC_STATS_SIZE);
1762 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_LO,
1763 EFSYS_MEM_ADDR(esmp) & 0xffffffff);
1764 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_HI,
1765 EFSYS_MEM_ADDR(esmp) >> 32);
1766 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_LEN, bytes);
1768 EFSYS_ASSERT(!upload && !enable && !events);
1772 * NOTE: Do not use EVB_PORT_ID_ASSIGNED when disabling periodic stats,
1773 * as this may fail (and leave periodic DMA enabled) if the
1774 * vadapter has already been deleted.
1776 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_PORT_ID,
1777 (disable ? EVB_PORT_ID_NULL : enp->en_vport_id));
1779 efx_mcdi_execute(enp, &req);
1781 if (req.emr_rc != 0) {
1782 /* EF10: Expect ENOENT if no DMA queues are initialised */
1783 if ((req.emr_rc != ENOENT) ||
1784 (enp->en_rx_qcount + enp->en_tx_qcount != 0)) {
1793 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1798 __checkReturn efx_rc_t
1799 efx_mcdi_mac_stats_clear(
1800 __in efx_nic_t *enp)
1804 if ((rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_CLEAR, 0)) != 0)
1810 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1815 __checkReturn efx_rc_t
1816 efx_mcdi_mac_stats_upload(
1817 __in efx_nic_t *enp,
1818 __in efsys_mem_t *esmp)
1823 * The MC DMAs aggregate statistics for our convenience, so we can
1824 * avoid having to pull the statistics buffer into the cache to
1825 * maintain cumulative statistics.
1827 if ((rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_UPLOAD, 0)) != 0)
1833 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1838 __checkReturn efx_rc_t
1839 efx_mcdi_mac_stats_periodic(
1840 __in efx_nic_t *enp,
1841 __in efsys_mem_t *esmp,
1842 __in uint16_t period_ms,
1843 __in boolean_t events)
1848 * The MC DMAs aggregate statistics for our convenience, so we can
1849 * avoid having to pull the statistics buffer into the cache to
1850 * maintain cumulative statistics.
1851 * Huntington uses a fixed 1sec period.
1852 * Medford uses a fixed 1sec period before v6.2.1.1033 firmware.
1855 rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_DISABLE, 0);
1857 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_EVENTS,
1860 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_NOEVENTS,
1869 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1874 #endif /* EFSYS_OPT_MAC_STATS */
1876 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
1879 * This function returns the pf and vf number of a function. If it is a pf the
1880 * vf number is 0xffff. The vf number is the index of the vf on that
1881 * function. So if you have 3 vfs on pf 0 the 3 vfs will return (pf=0,vf=0),
1882 * (pf=0,vf=1), (pf=0,vf=2) aand the pf will return (pf=0, vf=0xffff).
1884 __checkReturn efx_rc_t
1885 efx_mcdi_get_function_info(
1886 __in efx_nic_t *enp,
1887 __out uint32_t *pfp,
1888 __out_opt uint32_t *vfp)
1891 uint8_t payload[MAX(MC_CMD_GET_FUNCTION_INFO_IN_LEN,
1892 MC_CMD_GET_FUNCTION_INFO_OUT_LEN)];
1895 (void) memset(payload, 0, sizeof (payload));
1896 req.emr_cmd = MC_CMD_GET_FUNCTION_INFO;
1897 req.emr_in_buf = payload;
1898 req.emr_in_length = MC_CMD_GET_FUNCTION_INFO_IN_LEN;
1899 req.emr_out_buf = payload;
1900 req.emr_out_length = MC_CMD_GET_FUNCTION_INFO_OUT_LEN;
1902 efx_mcdi_execute(enp, &req);
1904 if (req.emr_rc != 0) {
1909 if (req.emr_out_length_used < MC_CMD_GET_FUNCTION_INFO_OUT_LEN) {
1914 *pfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_PF);
1916 *vfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_VF);
1923 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1928 __checkReturn efx_rc_t
1929 efx_mcdi_privilege_mask(
1930 __in efx_nic_t *enp,
1933 __out uint32_t *maskp)
1936 uint8_t payload[MAX(MC_CMD_PRIVILEGE_MASK_IN_LEN,
1937 MC_CMD_PRIVILEGE_MASK_OUT_LEN)];
1940 (void) memset(payload, 0, sizeof (payload));
1941 req.emr_cmd = MC_CMD_PRIVILEGE_MASK;
1942 req.emr_in_buf = payload;
1943 req.emr_in_length = MC_CMD_PRIVILEGE_MASK_IN_LEN;
1944 req.emr_out_buf = payload;
1945 req.emr_out_length = MC_CMD_PRIVILEGE_MASK_OUT_LEN;
1947 MCDI_IN_POPULATE_DWORD_2(req, PRIVILEGE_MASK_IN_FUNCTION,
1948 PRIVILEGE_MASK_IN_FUNCTION_PF, pf,
1949 PRIVILEGE_MASK_IN_FUNCTION_VF, vf);
1951 efx_mcdi_execute(enp, &req);
1953 if (req.emr_rc != 0) {
1958 if (req.emr_out_length_used < MC_CMD_PRIVILEGE_MASK_OUT_LEN) {
1963 *maskp = MCDI_OUT_DWORD(req, PRIVILEGE_MASK_OUT_OLD_MASK);
1970 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1975 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
1977 __checkReturn efx_rc_t
1978 efx_mcdi_set_workaround(
1979 __in efx_nic_t *enp,
1981 __in boolean_t enabled,
1982 __out_opt uint32_t *flagsp)
1985 uint8_t payload[MAX(MC_CMD_WORKAROUND_IN_LEN,
1986 MC_CMD_WORKAROUND_EXT_OUT_LEN)];
1989 (void) memset(payload, 0, sizeof (payload));
1990 req.emr_cmd = MC_CMD_WORKAROUND;
1991 req.emr_in_buf = payload;
1992 req.emr_in_length = MC_CMD_WORKAROUND_IN_LEN;
1993 req.emr_out_buf = payload;
1994 req.emr_out_length = MC_CMD_WORKAROUND_OUT_LEN;
1996 MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, type);
1997 MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, enabled ? 1 : 0);
1999 efx_mcdi_execute_quiet(enp, &req);
2001 if (req.emr_rc != 0) {
2006 if (flagsp != NULL) {
2007 if (req.emr_out_length_used >= MC_CMD_WORKAROUND_EXT_OUT_LEN)
2008 *flagsp = MCDI_OUT_DWORD(req, WORKAROUND_EXT_OUT_FLAGS);
2016 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2022 __checkReturn efx_rc_t
2023 efx_mcdi_get_workarounds(
2024 __in efx_nic_t *enp,
2025 __out_opt uint32_t *implementedp,
2026 __out_opt uint32_t *enabledp)
2029 uint8_t payload[MC_CMD_GET_WORKAROUNDS_OUT_LEN];
2032 (void) memset(payload, 0, sizeof (payload));
2033 req.emr_cmd = MC_CMD_GET_WORKAROUNDS;
2034 req.emr_in_buf = NULL;
2035 req.emr_in_length = 0;
2036 req.emr_out_buf = payload;
2037 req.emr_out_length = MC_CMD_GET_WORKAROUNDS_OUT_LEN;
2039 efx_mcdi_execute(enp, &req);
2041 if (req.emr_rc != 0) {
2046 if (implementedp != NULL) {
2048 MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_IMPLEMENTED);
2051 if (enabledp != NULL) {
2052 *enabledp = MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_ENABLED);
2058 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2064 * Size of media information page in accordance with SFF-8472 and SFF-8436.
2065 * It is used in MCDI interface as well.
2067 #define EFX_PHY_MEDIA_INFO_PAGE_SIZE 0x80
2069 static __checkReturn efx_rc_t
2070 efx_mcdi_get_phy_media_info(
2071 __in efx_nic_t *enp,
2072 __in uint32_t mcdi_page,
2073 __in uint8_t offset,
2075 __out_bcount(len) uint8_t *data)
2078 uint8_t payload[MAX(MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN,
2079 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(
2080 EFX_PHY_MEDIA_INFO_PAGE_SIZE))];
2083 EFSYS_ASSERT((uint32_t)offset + len <= EFX_PHY_MEDIA_INFO_PAGE_SIZE);
2085 (void) memset(payload, 0, sizeof (payload));
2086 req.emr_cmd = MC_CMD_GET_PHY_MEDIA_INFO;
2087 req.emr_in_buf = payload;
2088 req.emr_in_length = MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN;
2089 req.emr_out_buf = payload;
2090 req.emr_out_length =
2091 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE);
2093 MCDI_IN_SET_DWORD(req, GET_PHY_MEDIA_INFO_IN_PAGE, mcdi_page);
2095 efx_mcdi_execute(enp, &req);
2097 if (req.emr_rc != 0) {
2102 if (req.emr_out_length_used !=
2103 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE)) {
2108 if (MCDI_OUT_DWORD(req, GET_PHY_MEDIA_INFO_OUT_DATALEN) !=
2109 EFX_PHY_MEDIA_INFO_PAGE_SIZE) {
2115 MCDI_OUT2(req, uint8_t, GET_PHY_MEDIA_INFO_OUT_DATA) + offset,
2125 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2131 * 2-wire device address of the base information in accordance with SFF-8472
2132 * Diagnostic Monitoring Interface for Optical Transceivers section
2133 * 4 Memory Organization.
2135 #define EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE 0xA0
2138 * 2-wire device address of the digital diagnostics monitoring interface
2139 * in accordance with SFF-8472 Diagnostic Monitoring Interface for Optical
2140 * Transceivers section 4 Memory Organization.
2142 #define EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM 0xA2
2145 * Hard wired 2-wire device address for QSFP+ in accordance with SFF-8436
2146 * QSFP+ 10 Gbs 4X PLUGGABLE TRANSCEIVER section 7.4 Device Addressing and
2149 #define EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP 0xA0
2151 __checkReturn efx_rc_t
2152 efx_mcdi_phy_module_get_info(
2153 __in efx_nic_t *enp,
2154 __in uint8_t dev_addr,
2155 __in uint8_t offset,
2157 __out_bcount(len) uint8_t *data)
2159 efx_port_t *epp = &(enp->en_port);
2161 uint32_t mcdi_lower_page;
2162 uint32_t mcdi_upper_page;
2164 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
2167 * Map device address to MC_CMD_GET_PHY_MEDIA_INFO pages.
2168 * Offset plus length interface allows to access page 0 only.
2169 * I.e. non-zero upper pages are not accessible.
2170 * See SFF-8472 section 4 Memory Organization and SFF-8436 section 7.6
2171 * QSFP+ Memory Map for details on how information is structured
2174 switch (epp->ep_fixed_port_type) {
2175 case EFX_PHY_MEDIA_SFP_PLUS:
2177 * In accordance with SFF-8472 Diagnostic Monitoring
2178 * Interface for Optical Transceivers section 4 Memory
2179 * Organization two 2-wire addresses are defined.
2182 /* Base information */
2183 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE:
2185 * MCDI page 0 should be used to access lower
2186 * page 0 (0x00 - 0x7f) at the device address 0xA0.
2188 mcdi_lower_page = 0;
2190 * MCDI page 1 should be used to access upper
2191 * page 0 (0x80 - 0xff) at the device address 0xA0.
2193 mcdi_upper_page = 1;
2196 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM:
2198 * MCDI page 2 should be used to access lower
2199 * page 0 (0x00 - 0x7f) at the device address 0xA2.
2201 mcdi_lower_page = 2;
2203 * MCDI page 3 should be used to access upper
2204 * page 0 (0x80 - 0xff) at the device address 0xA2.
2206 mcdi_upper_page = 3;
2213 case EFX_PHY_MEDIA_QSFP_PLUS:
2215 case EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP:
2217 * MCDI page -1 should be used to access lower page 0
2220 mcdi_lower_page = (uint32_t)-1;
2222 * MCDI page 0 should be used to access upper page 0
2225 mcdi_upper_page = 0;
2237 if (offset < EFX_PHY_MEDIA_INFO_PAGE_SIZE) {
2239 MIN(len, EFX_PHY_MEDIA_INFO_PAGE_SIZE - offset);
2241 rc = efx_mcdi_get_phy_media_info(enp,
2242 mcdi_lower_page, offset, read_len, data);
2251 offset -= EFX_PHY_MEDIA_INFO_PAGE_SIZE;
2255 EFSYS_ASSERT3U(len, <=, EFX_PHY_MEDIA_INFO_PAGE_SIZE);
2256 EFSYS_ASSERT3U(offset, <, EFX_PHY_MEDIA_INFO_PAGE_SIZE);
2258 rc = efx_mcdi_get_phy_media_info(enp,
2259 mcdi_upper_page, offset, len, data);
2271 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2276 #endif /* EFSYS_OPT_MCDI */