1 /* SPDX-License-Identifier: BSD-3-Clause
3 * Copyright (c) 2008-2018 Solarflare Communications Inc.
13 * There are three versions of the MCDI interface:
14 * - MCDIv0: Siena BootROM. Transport uses MCDIv1 headers.
15 * - MCDIv1: Siena firmware and Huntington BootROM.
16 * - MCDIv2: EF10 firmware (Huntington/Medford) and Medford BootROM.
17 * Transport uses MCDIv2 headers.
19 * MCDIv2 Header NOT_EPOCH flag
20 * ----------------------------
21 * A new epoch begins at initial startup or after an MC reboot, and defines when
22 * the MC should reject stale MCDI requests.
24 * The first MCDI request sent by the host should contain NOT_EPOCH=0, and all
25 * subsequent requests (until the next MC reboot) should contain NOT_EPOCH=1.
27 * After rebooting the MC will fail all requests with NOT_EPOCH=1 by writing a
28 * response with ERROR=1 and DATALEN=0 until a request is seen with NOT_EPOCH=0.
35 static const efx_mcdi_ops_t __efx_mcdi_siena_ops = {
36 siena_mcdi_init, /* emco_init */
37 siena_mcdi_send_request, /* emco_send_request */
38 siena_mcdi_poll_reboot, /* emco_poll_reboot */
39 siena_mcdi_poll_response, /* emco_poll_response */
40 siena_mcdi_read_response, /* emco_read_response */
41 siena_mcdi_fini, /* emco_fini */
42 siena_mcdi_feature_supported, /* emco_feature_supported */
43 siena_mcdi_get_timeout, /* emco_get_timeout */
46 #endif /* EFSYS_OPT_SIENA */
48 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
50 static const efx_mcdi_ops_t __efx_mcdi_ef10_ops = {
51 ef10_mcdi_init, /* emco_init */
52 ef10_mcdi_send_request, /* emco_send_request */
53 ef10_mcdi_poll_reboot, /* emco_poll_reboot */
54 ef10_mcdi_poll_response, /* emco_poll_response */
55 ef10_mcdi_read_response, /* emco_read_response */
56 ef10_mcdi_fini, /* emco_fini */
57 ef10_mcdi_feature_supported, /* emco_feature_supported */
58 ef10_mcdi_get_timeout, /* emco_get_timeout */
61 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
65 __checkReturn efx_rc_t
68 __in const efx_mcdi_transport_t *emtp)
70 const efx_mcdi_ops_t *emcop;
73 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
74 EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
76 switch (enp->en_family) {
78 case EFX_FAMILY_SIENA:
79 emcop = &__efx_mcdi_siena_ops;
81 #endif /* EFSYS_OPT_SIENA */
83 #if EFSYS_OPT_HUNTINGTON
84 case EFX_FAMILY_HUNTINGTON:
85 emcop = &__efx_mcdi_ef10_ops;
87 #endif /* EFSYS_OPT_HUNTINGTON */
90 case EFX_FAMILY_MEDFORD:
91 emcop = &__efx_mcdi_ef10_ops;
93 #endif /* EFSYS_OPT_MEDFORD */
101 if (enp->en_features & EFX_FEATURE_MCDI_DMA) {
102 /* MCDI requires a DMA buffer in host memory */
103 if ((emtp == NULL) || (emtp->emt_dma_mem) == NULL) {
108 enp->en_mcdi.em_emtp = emtp;
110 if (emcop != NULL && emcop->emco_init != NULL) {
111 if ((rc = emcop->emco_init(enp, emtp)) != 0)
115 enp->en_mcdi.em_emcop = emcop;
116 enp->en_mod_flags |= EFX_MOD_MCDI;
125 EFSYS_PROBE1(fail1, efx_rc_t, rc);
127 enp->en_mcdi.em_emcop = NULL;
128 enp->en_mcdi.em_emtp = NULL;
129 enp->en_mod_flags &= ~EFX_MOD_MCDI;
138 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
139 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
141 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
142 EFSYS_ASSERT3U(enp->en_mod_flags, ==, EFX_MOD_MCDI);
144 if (emcop != NULL && emcop->emco_fini != NULL)
145 emcop->emco_fini(enp);
148 emip->emi_aborted = 0;
150 enp->en_mcdi.em_emcop = NULL;
151 enp->en_mod_flags &= ~EFX_MOD_MCDI;
158 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
159 efsys_lock_state_t state;
161 /* Start a new epoch (allow fresh MCDI requests to succeed) */
162 EFSYS_LOCK(enp->en_eslp, state);
163 emip->emi_new_epoch = B_TRUE;
164 EFSYS_UNLOCK(enp->en_eslp, state);
168 efx_mcdi_send_request(
175 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
177 emcop->emco_send_request(enp, hdrp, hdr_len, sdup, sdu_len);
181 efx_mcdi_poll_reboot(
184 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
187 rc = emcop->emco_poll_reboot(enp);
192 efx_mcdi_poll_response(
195 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
198 available = emcop->emco_poll_response(enp);
203 efx_mcdi_read_response(
209 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
211 emcop->emco_read_response(enp, bufferp, offset, length);
215 efx_mcdi_request_start(
217 __in efx_mcdi_req_t *emrp,
218 __in boolean_t ev_cpl)
220 #if EFSYS_OPT_MCDI_LOGGING
221 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
223 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
226 unsigned int max_version;
230 efsys_lock_state_t state;
232 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
233 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
234 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
237 * efx_mcdi_request_start() is naturally serialised against both
238 * efx_mcdi_request_poll() and efx_mcdi_ev_cpl()/efx_mcdi_ev_death(),
239 * by virtue of there only being one outstanding MCDI request.
240 * Unfortunately, upper layers may also call efx_mcdi_request_abort()
241 * at any time, to timeout a pending mcdi request, That request may
242 * then subsequently complete, meaning efx_mcdi_ev_cpl() or
243 * efx_mcdi_ev_death() may end up running in parallel with
244 * efx_mcdi_request_start(). This race is handled by ensuring that
245 * %emi_pending_req, %emi_ev_cpl and %emi_seq are protected by the
248 EFSYS_LOCK(enp->en_eslp, state);
249 EFSYS_ASSERT(emip->emi_pending_req == NULL);
250 emip->emi_pending_req = emrp;
251 emip->emi_ev_cpl = ev_cpl;
252 emip->emi_poll_cnt = 0;
253 seq = emip->emi_seq++ & EFX_MASK32(MCDI_HEADER_SEQ);
254 new_epoch = emip->emi_new_epoch;
255 max_version = emip->emi_max_version;
256 EFSYS_UNLOCK(enp->en_eslp, state);
260 xflags |= MCDI_HEADER_XFLAGS_EVREQ;
263 * Huntington firmware supports MCDIv2, but the Huntington BootROM only
264 * supports MCDIv1. Use MCDIv1 headers for MCDIv1 commands where
265 * possible to support this.
267 if ((max_version >= 2) &&
268 ((emrp->emr_cmd > MC_CMD_CMD_SPACE_ESCAPE_7) ||
269 (emrp->emr_in_length > MCDI_CTL_SDU_LEN_MAX_V1) ||
270 (emrp->emr_out_length > MCDI_CTL_SDU_LEN_MAX_V1))) {
271 /* Construct MCDI v2 header */
272 hdr_len = sizeof (hdr);
273 EFX_POPULATE_DWORD_8(hdr[0],
274 MCDI_HEADER_CODE, MC_CMD_V2_EXTN,
275 MCDI_HEADER_RESYNC, 1,
276 MCDI_HEADER_DATALEN, 0,
277 MCDI_HEADER_SEQ, seq,
278 MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
279 MCDI_HEADER_ERROR, 0,
280 MCDI_HEADER_RESPONSE, 0,
281 MCDI_HEADER_XFLAGS, xflags);
283 EFX_POPULATE_DWORD_2(hdr[1],
284 MC_CMD_V2_EXTN_IN_EXTENDED_CMD, emrp->emr_cmd,
285 MC_CMD_V2_EXTN_IN_ACTUAL_LEN, emrp->emr_in_length);
287 /* Construct MCDI v1 header */
288 hdr_len = sizeof (hdr[0]);
289 EFX_POPULATE_DWORD_8(hdr[0],
290 MCDI_HEADER_CODE, emrp->emr_cmd,
291 MCDI_HEADER_RESYNC, 1,
292 MCDI_HEADER_DATALEN, emrp->emr_in_length,
293 MCDI_HEADER_SEQ, seq,
294 MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
295 MCDI_HEADER_ERROR, 0,
296 MCDI_HEADER_RESPONSE, 0,
297 MCDI_HEADER_XFLAGS, xflags);
300 #if EFSYS_OPT_MCDI_LOGGING
301 if (emtp->emt_logger != NULL) {
302 emtp->emt_logger(emtp->emt_context, EFX_LOG_MCDI_REQUEST,
304 emrp->emr_in_buf, emrp->emr_in_length);
306 #endif /* EFSYS_OPT_MCDI_LOGGING */
308 efx_mcdi_send_request(enp, &hdr[0], hdr_len,
309 emrp->emr_in_buf, emrp->emr_in_length);
314 efx_mcdi_read_response_header(
316 __inout efx_mcdi_req_t *emrp)
318 #if EFSYS_OPT_MCDI_LOGGING
319 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
320 #endif /* EFSYS_OPT_MCDI_LOGGING */
321 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
323 unsigned int hdr_len;
324 unsigned int data_len;
330 EFSYS_ASSERT(emrp != NULL);
332 efx_mcdi_read_response(enp, &hdr[0], 0, sizeof (hdr[0]));
333 hdr_len = sizeof (hdr[0]);
335 cmd = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE);
336 seq = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_SEQ);
337 error = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_ERROR);
339 if (cmd != MC_CMD_V2_EXTN) {
340 data_len = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_DATALEN);
342 efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1]));
343 hdr_len += sizeof (hdr[1]);
345 cmd = EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_EXTENDED_CMD);
347 EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
350 if (error && (data_len == 0)) {
351 /* The MC has rebooted since the request was sent. */
352 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
353 efx_mcdi_poll_reboot(enp);
357 if ((cmd != emrp->emr_cmd) ||
358 (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
359 /* Response is for a different request */
365 unsigned int err_len = MIN(data_len, sizeof (err));
366 int err_code = MC_CMD_ERR_EPROTO;
369 /* Read error code (and arg num for MCDI v2 commands) */
370 efx_mcdi_read_response(enp, &err, hdr_len, err_len);
372 if (err_len >= (MC_CMD_ERR_CODE_OFST + sizeof (efx_dword_t)))
373 err_code = EFX_DWORD_FIELD(err[0], EFX_DWORD_0);
375 if (err_len >= (MC_CMD_ERR_ARG_OFST + sizeof (efx_dword_t)))
376 err_arg = EFX_DWORD_FIELD(err[1], EFX_DWORD_0);
378 emrp->emr_err_code = err_code;
379 emrp->emr_err_arg = err_arg;
381 #if EFSYS_OPT_MCDI_PROXY_AUTH
382 if ((err_code == MC_CMD_ERR_PROXY_PENDING) &&
383 (err_len == sizeof (err))) {
385 * The MCDI request would normally fail with EPERM, but
386 * firmware has forwarded it to an authorization agent
387 * attached to a privileged PF.
389 * Save the authorization request handle. The client
390 * must wait for a PROXY_RESPONSE event, or timeout.
392 emrp->emr_proxy_handle = err_arg;
394 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
396 #if EFSYS_OPT_MCDI_LOGGING
397 if (emtp->emt_logger != NULL) {
398 emtp->emt_logger(emtp->emt_context,
399 EFX_LOG_MCDI_RESPONSE,
403 #endif /* EFSYS_OPT_MCDI_LOGGING */
405 if (!emrp->emr_quiet) {
406 EFSYS_PROBE3(mcdi_err_arg, int, emrp->emr_cmd,
407 int, err_code, int, err_arg);
410 rc = efx_mcdi_request_errcode(err_code);
415 emrp->emr_out_length_used = data_len;
416 #if EFSYS_OPT_MCDI_PROXY_AUTH
417 emrp->emr_proxy_handle = 0;
418 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
425 emrp->emr_out_length_used = 0;
429 efx_mcdi_finish_response(
431 __in efx_mcdi_req_t *emrp)
433 #if EFSYS_OPT_MCDI_LOGGING
434 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
435 #endif /* EFSYS_OPT_MCDI_LOGGING */
437 unsigned int hdr_len;
440 if (emrp->emr_out_buf == NULL)
443 /* Read the command header to detect MCDI response format */
444 hdr_len = sizeof (hdr[0]);
445 efx_mcdi_read_response(enp, &hdr[0], 0, hdr_len);
446 if (EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) {
448 * Read the actual payload length. The length given in the event
449 * is only correct for responses with the V1 format.
451 efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1]));
452 hdr_len += sizeof (hdr[1]);
454 emrp->emr_out_length_used = EFX_DWORD_FIELD(hdr[1],
455 MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
458 /* Copy payload out into caller supplied buffer */
459 bytes = MIN(emrp->emr_out_length_used, emrp->emr_out_length);
460 efx_mcdi_read_response(enp, emrp->emr_out_buf, hdr_len, bytes);
462 #if EFSYS_OPT_MCDI_LOGGING
463 if (emtp->emt_logger != NULL) {
464 emtp->emt_logger(emtp->emt_context,
465 EFX_LOG_MCDI_RESPONSE,
467 emrp->emr_out_buf, bytes);
469 #endif /* EFSYS_OPT_MCDI_LOGGING */
473 __checkReturn boolean_t
474 efx_mcdi_request_poll(
477 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
478 efx_mcdi_req_t *emrp;
479 efsys_lock_state_t state;
482 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
483 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
484 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
486 /* Serialise against post-watchdog efx_mcdi_ev* */
487 EFSYS_LOCK(enp->en_eslp, state);
489 EFSYS_ASSERT(emip->emi_pending_req != NULL);
490 EFSYS_ASSERT(!emip->emi_ev_cpl);
491 emrp = emip->emi_pending_req;
493 /* Check for reboot atomically w.r.t efx_mcdi_request_start */
494 if (emip->emi_poll_cnt++ == 0) {
495 if ((rc = efx_mcdi_poll_reboot(enp)) != 0) {
496 emip->emi_pending_req = NULL;
497 EFSYS_UNLOCK(enp->en_eslp, state);
499 /* Reboot/Assertion */
500 if (rc == EIO || rc == EINTR)
501 efx_mcdi_raise_exception(enp, emrp, rc);
507 /* Check if a response is available */
508 if (efx_mcdi_poll_response(enp) == B_FALSE) {
509 EFSYS_UNLOCK(enp->en_eslp, state);
513 /* Read the response header */
514 efx_mcdi_read_response_header(enp, emrp);
516 /* Request complete */
517 emip->emi_pending_req = NULL;
519 /* Ensure stale MCDI requests fail after an MC reboot. */
520 emip->emi_new_epoch = B_FALSE;
522 EFSYS_UNLOCK(enp->en_eslp, state);
524 if ((rc = emrp->emr_rc) != 0)
527 efx_mcdi_finish_response(enp, emrp);
531 if (!emrp->emr_quiet)
534 if (!emrp->emr_quiet)
535 EFSYS_PROBE1(fail1, efx_rc_t, rc);
540 __checkReturn boolean_t
541 efx_mcdi_request_abort(
544 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
545 efx_mcdi_req_t *emrp;
547 efsys_lock_state_t state;
549 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
550 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
551 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
554 * efx_mcdi_ev_* may have already completed this event, and be
555 * spinning/blocked on the upper layer lock. So it *is* legitimate
556 * to for emi_pending_req to be NULL. If there is a pending event
557 * completed request, then provide a "credit" to allow
558 * efx_mcdi_ev_cpl() to accept a single spurious completion.
560 EFSYS_LOCK(enp->en_eslp, state);
561 emrp = emip->emi_pending_req;
562 aborted = (emrp != NULL);
564 emip->emi_pending_req = NULL;
566 /* Error the request */
567 emrp->emr_out_length_used = 0;
568 emrp->emr_rc = ETIMEDOUT;
570 /* Provide a credit for seqno/emr_pending_req mismatches */
571 if (emip->emi_ev_cpl)
575 * The upper layer has called us, so we don't
576 * need to complete the request.
579 EFSYS_UNLOCK(enp->en_eslp, state);
585 efx_mcdi_get_timeout(
587 __in efx_mcdi_req_t *emrp,
588 __out uint32_t *timeoutp)
590 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
592 emcop->emco_get_timeout(enp, emrp, timeoutp);
595 __checkReturn efx_rc_t
596 efx_mcdi_request_errcode(
597 __in unsigned int err)
602 case MC_CMD_ERR_EPERM:
604 case MC_CMD_ERR_ENOENT:
606 case MC_CMD_ERR_EINTR:
608 case MC_CMD_ERR_EACCES:
610 case MC_CMD_ERR_EBUSY:
612 case MC_CMD_ERR_EINVAL:
614 case MC_CMD_ERR_EDEADLK:
616 case MC_CMD_ERR_ENOSYS:
618 case MC_CMD_ERR_ETIME:
620 case MC_CMD_ERR_ENOTSUP:
622 case MC_CMD_ERR_EALREADY:
626 case MC_CMD_ERR_EEXIST:
628 #ifdef MC_CMD_ERR_EAGAIN
629 case MC_CMD_ERR_EAGAIN:
632 #ifdef MC_CMD_ERR_ENOSPC
633 case MC_CMD_ERR_ENOSPC:
636 case MC_CMD_ERR_ERANGE:
639 case MC_CMD_ERR_ALLOC_FAIL:
641 case MC_CMD_ERR_NO_VADAPTOR:
643 case MC_CMD_ERR_NO_EVB_PORT:
645 case MC_CMD_ERR_NO_VSWITCH:
647 case MC_CMD_ERR_VLAN_LIMIT:
649 case MC_CMD_ERR_BAD_PCI_FUNC:
651 case MC_CMD_ERR_BAD_VLAN_MODE:
653 case MC_CMD_ERR_BAD_VSWITCH_TYPE:
655 case MC_CMD_ERR_BAD_VPORT_TYPE:
657 case MC_CMD_ERR_MAC_EXIST:
660 case MC_CMD_ERR_PROXY_PENDING:
664 EFSYS_PROBE1(mc_pcol_error, int, err);
670 efx_mcdi_raise_exception(
672 __in_opt efx_mcdi_req_t *emrp,
675 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
676 efx_mcdi_exception_t exception;
678 /* Reboot or Assertion failure only */
679 EFSYS_ASSERT(rc == EIO || rc == EINTR);
682 * If MC_CMD_REBOOT causes a reboot (dependent on parameters),
683 * then the EIO is not worthy of an exception.
685 if (emrp != NULL && emrp->emr_cmd == MC_CMD_REBOOT && rc == EIO)
688 exception = (rc == EIO)
689 ? EFX_MCDI_EXCEPTION_MC_REBOOT
690 : EFX_MCDI_EXCEPTION_MC_BADASSERT;
692 emtp->emt_exception(emtp->emt_context, exception);
698 __inout efx_mcdi_req_t *emrp)
700 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
702 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
703 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
705 emrp->emr_quiet = B_FALSE;
706 emtp->emt_execute(emtp->emt_context, emrp);
710 efx_mcdi_execute_quiet(
712 __inout efx_mcdi_req_t *emrp)
714 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
716 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
717 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
719 emrp->emr_quiet = B_TRUE;
720 emtp->emt_execute(emtp->emt_context, emrp);
726 __in unsigned int seq,
727 __in unsigned int outlen,
730 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
731 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
732 efx_mcdi_req_t *emrp;
733 efsys_lock_state_t state;
735 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
736 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
739 * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start()
740 * when we're completing an aborted request.
742 EFSYS_LOCK(enp->en_eslp, state);
743 if (emip->emi_pending_req == NULL || !emip->emi_ev_cpl ||
744 (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
745 EFSYS_ASSERT(emip->emi_aborted > 0);
746 if (emip->emi_aborted > 0)
748 EFSYS_UNLOCK(enp->en_eslp, state);
752 emrp = emip->emi_pending_req;
753 emip->emi_pending_req = NULL;
754 EFSYS_UNLOCK(enp->en_eslp, state);
756 if (emip->emi_max_version >= 2) {
757 /* MCDIv2 response details do not fit into an event. */
758 efx_mcdi_read_response_header(enp, emrp);
761 if (!emrp->emr_quiet) {
762 EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd,
765 emrp->emr_out_length_used = 0;
766 emrp->emr_rc = efx_mcdi_request_errcode(errcode);
768 emrp->emr_out_length_used = outlen;
772 if (emrp->emr_rc == 0)
773 efx_mcdi_finish_response(enp, emrp);
775 emtp->emt_ev_cpl(emtp->emt_context);
778 #if EFSYS_OPT_MCDI_PROXY_AUTH
780 __checkReturn efx_rc_t
781 efx_mcdi_get_proxy_handle(
783 __in efx_mcdi_req_t *emrp,
784 __out uint32_t *handlep)
788 _NOTE(ARGUNUSED(enp))
791 * Return proxy handle from MCDI request that returned with error
792 * MC_MCD_ERR_PROXY_PENDING. This handle is used to wait for a matching
793 * PROXY_RESPONSE event.
795 if ((emrp == NULL) || (handlep == NULL)) {
799 if ((emrp->emr_rc != 0) &&
800 (emrp->emr_err_code == MC_CMD_ERR_PROXY_PENDING)) {
801 *handlep = emrp->emr_proxy_handle;
810 EFSYS_PROBE1(fail1, efx_rc_t, rc);
815 efx_mcdi_ev_proxy_response(
817 __in unsigned int handle,
818 __in unsigned int status)
820 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
824 * Handle results of an authorization request for a privileged MCDI
825 * command. If authorization was granted then we must re-issue the
826 * original MCDI request. If authorization failed or timed out,
827 * then the original MCDI request should be completed with the
828 * result code from this event.
830 rc = (status == 0) ? 0 : efx_mcdi_request_errcode(status);
832 emtp->emt_ev_proxy_response(emtp->emt_context, handle, rc);
834 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
841 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
842 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
843 efx_mcdi_req_t *emrp = NULL;
845 efsys_lock_state_t state;
848 * The MCDI request (if there is one) has been terminated, either
849 * by a BADASSERT or REBOOT event.
851 * If there is an outstanding event-completed MCDI operation, then we
852 * will never receive the completion event (because both MCDI
853 * completions and BADASSERT events are sent to the same evq). So
854 * complete this MCDI op.
856 * This function might run in parallel with efx_mcdi_request_poll()
857 * for poll completed mcdi requests, and also with
858 * efx_mcdi_request_start() for post-watchdog completions.
860 EFSYS_LOCK(enp->en_eslp, state);
861 emrp = emip->emi_pending_req;
862 ev_cpl = emip->emi_ev_cpl;
863 if (emrp != NULL && emip->emi_ev_cpl) {
864 emip->emi_pending_req = NULL;
866 emrp->emr_out_length_used = 0;
872 * Since we're running in parallel with a request, consume the
873 * status word before dropping the lock.
875 if (rc == EIO || rc == EINTR) {
876 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
877 (void) efx_mcdi_poll_reboot(enp);
878 emip->emi_new_epoch = B_TRUE;
881 EFSYS_UNLOCK(enp->en_eslp, state);
883 efx_mcdi_raise_exception(enp, emrp, rc);
885 if (emrp != NULL && ev_cpl)
886 emtp->emt_ev_cpl(emtp->emt_context);
889 __checkReturn efx_rc_t
892 __out_ecount_opt(4) uint16_t versionp[4],
893 __out_opt uint32_t *buildp,
894 __out_opt efx_mcdi_boot_t *statusp)
897 uint8_t payload[MAX(MAX(MC_CMD_GET_VERSION_IN_LEN,
898 MC_CMD_GET_VERSION_OUT_LEN),
899 MAX(MC_CMD_GET_BOOT_STATUS_IN_LEN,
900 MC_CMD_GET_BOOT_STATUS_OUT_LEN))];
901 efx_word_t *ver_words;
904 efx_mcdi_boot_t status;
907 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
909 (void) memset(payload, 0, sizeof (payload));
910 req.emr_cmd = MC_CMD_GET_VERSION;
911 req.emr_in_buf = payload;
912 req.emr_in_length = MC_CMD_GET_VERSION_IN_LEN;
913 req.emr_out_buf = payload;
914 req.emr_out_length = MC_CMD_GET_VERSION_OUT_LEN;
916 efx_mcdi_execute(enp, &req);
918 if (req.emr_rc != 0) {
923 /* bootrom support */
924 if (req.emr_out_length_used == MC_CMD_GET_VERSION_V0_OUT_LEN) {
925 version[0] = version[1] = version[2] = version[3] = 0;
926 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
931 if (req.emr_out_length_used < MC_CMD_GET_VERSION_OUT_LEN) {
936 ver_words = MCDI_OUT2(req, efx_word_t, GET_VERSION_OUT_VERSION);
937 version[0] = EFX_WORD_FIELD(ver_words[0], EFX_WORD_0);
938 version[1] = EFX_WORD_FIELD(ver_words[1], EFX_WORD_0);
939 version[2] = EFX_WORD_FIELD(ver_words[2], EFX_WORD_0);
940 version[3] = EFX_WORD_FIELD(ver_words[3], EFX_WORD_0);
941 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
944 /* The bootrom doesn't understand BOOT_STATUS */
945 if (MC_FW_VERSION_IS_BOOTLOADER(build)) {
946 status = EFX_MCDI_BOOT_ROM;
950 (void) memset(payload, 0, sizeof (payload));
951 req.emr_cmd = MC_CMD_GET_BOOT_STATUS;
952 req.emr_in_buf = payload;
953 req.emr_in_length = MC_CMD_GET_BOOT_STATUS_IN_LEN;
954 req.emr_out_buf = payload;
955 req.emr_out_length = MC_CMD_GET_BOOT_STATUS_OUT_LEN;
957 efx_mcdi_execute_quiet(enp, &req);
959 if (req.emr_rc == EACCES) {
960 /* Unprivileged functions cannot access BOOT_STATUS */
961 status = EFX_MCDI_BOOT_PRIMARY;
962 version[0] = version[1] = version[2] = version[3] = 0;
967 if (req.emr_rc != 0) {
972 if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) {
977 if (MCDI_OUT_DWORD_FIELD(req, GET_BOOT_STATUS_OUT_FLAGS,
978 GET_BOOT_STATUS_OUT_FLAGS_PRIMARY))
979 status = EFX_MCDI_BOOT_PRIMARY;
981 status = EFX_MCDI_BOOT_SECONDARY;
984 if (versionp != NULL)
985 memcpy(versionp, version, sizeof (version));
1000 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1005 __checkReturn efx_rc_t
1006 efx_mcdi_get_capabilities(
1007 __in efx_nic_t *enp,
1008 __out_opt uint32_t *flagsp,
1009 __out_opt uint16_t *rx_dpcpu_fw_idp,
1010 __out_opt uint16_t *tx_dpcpu_fw_idp,
1011 __out_opt uint32_t *flags2p,
1012 __out_opt uint32_t *tso2ncp)
1015 uint8_t payload[MAX(MC_CMD_GET_CAPABILITIES_IN_LEN,
1016 MC_CMD_GET_CAPABILITIES_V2_OUT_LEN)];
1017 boolean_t v2_capable;
1020 (void) memset(payload, 0, sizeof (payload));
1021 req.emr_cmd = MC_CMD_GET_CAPABILITIES;
1022 req.emr_in_buf = payload;
1023 req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN;
1024 req.emr_out_buf = payload;
1025 req.emr_out_length = MC_CMD_GET_CAPABILITIES_V2_OUT_LEN;
1027 efx_mcdi_execute_quiet(enp, &req);
1029 if (req.emr_rc != 0) {
1034 if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_OUT_LEN) {
1040 *flagsp = MCDI_OUT_DWORD(req, GET_CAPABILITIES_OUT_FLAGS1);
1042 if (rx_dpcpu_fw_idp != NULL)
1043 *rx_dpcpu_fw_idp = MCDI_OUT_WORD(req,
1044 GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID);
1046 if (tx_dpcpu_fw_idp != NULL)
1047 *tx_dpcpu_fw_idp = MCDI_OUT_WORD(req,
1048 GET_CAPABILITIES_OUT_TX_DPCPU_FW_ID);
1050 if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_V2_OUT_LEN)
1051 v2_capable = B_FALSE;
1053 v2_capable = B_TRUE;
1055 if (flags2p != NULL) {
1056 *flags2p = (v2_capable) ?
1057 MCDI_OUT_DWORD(req, GET_CAPABILITIES_V2_OUT_FLAGS2) :
1061 if (tso2ncp != NULL) {
1062 *tso2ncp = (v2_capable) ?
1064 GET_CAPABILITIES_V2_OUT_TX_TSO_V2_N_CONTEXTS) :
1073 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1078 static __checkReturn efx_rc_t
1080 __in efx_nic_t *enp,
1081 __in boolean_t after_assertion)
1083 uint8_t payload[MAX(MC_CMD_REBOOT_IN_LEN, MC_CMD_REBOOT_OUT_LEN)];
1088 * We could require the caller to have caused en_mod_flags=0 to
1089 * call this function. This doesn't help the other port though,
1090 * who's about to get the MC ripped out from underneath them.
1091 * Since they have to cope with the subsequent fallout of MCDI
1092 * failures, we should as well.
1094 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1096 (void) memset(payload, 0, sizeof (payload));
1097 req.emr_cmd = MC_CMD_REBOOT;
1098 req.emr_in_buf = payload;
1099 req.emr_in_length = MC_CMD_REBOOT_IN_LEN;
1100 req.emr_out_buf = payload;
1101 req.emr_out_length = MC_CMD_REBOOT_OUT_LEN;
1103 MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS,
1104 (after_assertion ? MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION : 0));
1106 efx_mcdi_execute_quiet(enp, &req);
1108 if (req.emr_rc == EACCES) {
1109 /* Unprivileged functions cannot reboot the MC. */
1113 /* A successful reboot request returns EIO. */
1114 if (req.emr_rc != 0 && req.emr_rc != EIO) {
1123 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1128 __checkReturn efx_rc_t
1130 __in efx_nic_t *enp)
1132 return (efx_mcdi_do_reboot(enp, B_FALSE));
1135 __checkReturn efx_rc_t
1136 efx_mcdi_exit_assertion_handler(
1137 __in efx_nic_t *enp)
1139 return (efx_mcdi_do_reboot(enp, B_TRUE));
1142 __checkReturn efx_rc_t
1143 efx_mcdi_read_assertion(
1144 __in efx_nic_t *enp)
1147 uint8_t payload[MAX(MC_CMD_GET_ASSERTS_IN_LEN,
1148 MC_CMD_GET_ASSERTS_OUT_LEN)];
1157 * Before we attempt to chat to the MC, we should verify that the MC
1158 * isn't in it's assertion handler, either due to a previous reboot,
1159 * or because we're reinitializing due to an eec_exception().
1161 * Use GET_ASSERTS to read any assertion state that may be present.
1162 * Retry this command twice. Once because a boot-time assertion failure
1163 * might cause the 1st MCDI request to fail. And once again because
1164 * we might race with efx_mcdi_exit_assertion_handler() running on
1165 * partner port(s) on the same NIC.
1169 (void) memset(payload, 0, sizeof (payload));
1170 req.emr_cmd = MC_CMD_GET_ASSERTS;
1171 req.emr_in_buf = payload;
1172 req.emr_in_length = MC_CMD_GET_ASSERTS_IN_LEN;
1173 req.emr_out_buf = payload;
1174 req.emr_out_length = MC_CMD_GET_ASSERTS_OUT_LEN;
1176 MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1);
1177 efx_mcdi_execute_quiet(enp, &req);
1179 } while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0);
1181 if (req.emr_rc != 0) {
1182 if (req.emr_rc == EACCES) {
1183 /* Unprivileged functions cannot clear assertions. */
1190 if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) {
1195 /* Print out any assertion state recorded */
1196 flags = MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_GLOBAL_FLAGS);
1197 if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
1200 reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
1201 ? "system-level assertion"
1202 : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
1203 ? "thread-level assertion"
1204 : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
1206 : (flags == MC_CMD_GET_ASSERTS_FLAGS_ADDR_TRAP)
1207 ? "illegal address trap"
1208 : "unknown assertion";
1209 EFSYS_PROBE3(mcpu_assertion,
1210 const char *, reason, unsigned int,
1211 MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_SAVED_PC_OFFS),
1213 MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS));
1215 /* Print out the registers (r1 ... r31) */
1216 ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST;
1218 index < 1 + MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM;
1220 EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int,
1221 EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst),
1223 ofst += sizeof (efx_dword_t);
1225 EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN);
1233 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1240 * Internal routines for for specific MCDI requests.
1243 __checkReturn efx_rc_t
1244 efx_mcdi_drv_attach(
1245 __in efx_nic_t *enp,
1246 __in boolean_t attach)
1249 uint8_t payload[MAX(MC_CMD_DRV_ATTACH_IN_LEN,
1250 MC_CMD_DRV_ATTACH_EXT_OUT_LEN)];
1253 (void) memset(payload, 0, sizeof (payload));
1254 req.emr_cmd = MC_CMD_DRV_ATTACH;
1255 req.emr_in_buf = payload;
1256 req.emr_in_length = MC_CMD_DRV_ATTACH_IN_LEN;
1257 req.emr_out_buf = payload;
1258 req.emr_out_length = MC_CMD_DRV_ATTACH_EXT_OUT_LEN;
1261 * Use DONT_CARE for the datapath firmware type to ensure that the
1262 * driver can attach to an unprivileged function. The datapath firmware
1263 * type to use is controlled by the 'sfboot' utility.
1265 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_NEW_STATE, attach ? 1 : 0);
1266 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_UPDATE, 1);
1267 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_FIRMWARE_ID, MC_CMD_FW_DONT_CARE);
1269 efx_mcdi_execute(enp, &req);
1271 if (req.emr_rc != 0) {
1276 if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) {
1286 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1291 __checkReturn efx_rc_t
1292 efx_mcdi_get_board_cfg(
1293 __in efx_nic_t *enp,
1294 __out_opt uint32_t *board_typep,
1295 __out_opt efx_dword_t *capabilitiesp,
1296 __out_ecount_opt(6) uint8_t mac_addrp[6])
1298 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
1300 uint8_t payload[MAX(MC_CMD_GET_BOARD_CFG_IN_LEN,
1301 MC_CMD_GET_BOARD_CFG_OUT_LENMIN)];
1304 (void) memset(payload, 0, sizeof (payload));
1305 req.emr_cmd = MC_CMD_GET_BOARD_CFG;
1306 req.emr_in_buf = payload;
1307 req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN;
1308 req.emr_out_buf = payload;
1309 req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMIN;
1311 efx_mcdi_execute(enp, &req);
1313 if (req.emr_rc != 0) {
1318 if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
1323 if (mac_addrp != NULL) {
1326 if (emip->emi_port == 1) {
1327 addrp = MCDI_OUT2(req, uint8_t,
1328 GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0);
1329 } else if (emip->emi_port == 2) {
1330 addrp = MCDI_OUT2(req, uint8_t,
1331 GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1);
1337 EFX_MAC_ADDR_COPY(mac_addrp, addrp);
1340 if (capabilitiesp != NULL) {
1341 if (emip->emi_port == 1) {
1342 *capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
1343 GET_BOARD_CFG_OUT_CAPABILITIES_PORT0);
1344 } else if (emip->emi_port == 2) {
1345 *capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
1346 GET_BOARD_CFG_OUT_CAPABILITIES_PORT1);
1353 if (board_typep != NULL) {
1354 *board_typep = MCDI_OUT_DWORD(req,
1355 GET_BOARD_CFG_OUT_BOARD_TYPE);
1367 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1372 __checkReturn efx_rc_t
1373 efx_mcdi_get_resource_limits(
1374 __in efx_nic_t *enp,
1375 __out_opt uint32_t *nevqp,
1376 __out_opt uint32_t *nrxqp,
1377 __out_opt uint32_t *ntxqp)
1380 uint8_t payload[MAX(MC_CMD_GET_RESOURCE_LIMITS_IN_LEN,
1381 MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN)];
1384 (void) memset(payload, 0, sizeof (payload));
1385 req.emr_cmd = MC_CMD_GET_RESOURCE_LIMITS;
1386 req.emr_in_buf = payload;
1387 req.emr_in_length = MC_CMD_GET_RESOURCE_LIMITS_IN_LEN;
1388 req.emr_out_buf = payload;
1389 req.emr_out_length = MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN;
1391 efx_mcdi_execute(enp, &req);
1393 if (req.emr_rc != 0) {
1398 if (req.emr_out_length_used < MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) {
1404 *nevqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_EVQ);
1406 *nrxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ);
1408 *ntxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ);
1415 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1420 __checkReturn efx_rc_t
1421 efx_mcdi_get_phy_cfg(
1422 __in efx_nic_t *enp)
1424 efx_port_t *epp = &(enp->en_port);
1425 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1427 uint8_t payload[MAX(MC_CMD_GET_PHY_CFG_IN_LEN,
1428 MC_CMD_GET_PHY_CFG_OUT_LEN)];
1431 (void) memset(payload, 0, sizeof (payload));
1432 req.emr_cmd = MC_CMD_GET_PHY_CFG;
1433 req.emr_in_buf = payload;
1434 req.emr_in_length = MC_CMD_GET_PHY_CFG_IN_LEN;
1435 req.emr_out_buf = payload;
1436 req.emr_out_length = MC_CMD_GET_PHY_CFG_OUT_LEN;
1438 efx_mcdi_execute(enp, &req);
1440 if (req.emr_rc != 0) {
1445 if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) {
1450 encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE);
1452 (void) strncpy(encp->enc_phy_name,
1453 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME),
1454 MIN(sizeof (encp->enc_phy_name) - 1,
1455 MC_CMD_GET_PHY_CFG_OUT_NAME_LEN));
1456 #endif /* EFSYS_OPT_NAMES */
1457 (void) memset(encp->enc_phy_revision, 0,
1458 sizeof (encp->enc_phy_revision));
1459 memcpy(encp->enc_phy_revision,
1460 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION),
1461 MIN(sizeof (encp->enc_phy_revision) - 1,
1462 MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN));
1463 #if EFSYS_OPT_PHY_LED_CONTROL
1464 encp->enc_led_mask = ((1 << EFX_PHY_LED_DEFAULT) |
1465 (1 << EFX_PHY_LED_OFF) |
1466 (1 << EFX_PHY_LED_ON));
1467 #endif /* EFSYS_OPT_PHY_LED_CONTROL */
1469 /* Get the media type of the fixed port, if recognised. */
1470 EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI);
1471 EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4);
1472 EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4);
1473 EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP);
1474 EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS);
1475 EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T);
1476 EFX_STATIC_ASSERT(MC_CMD_MEDIA_QSFP_PLUS == EFX_PHY_MEDIA_QSFP_PLUS);
1477 epp->ep_fixed_port_type =
1478 (efx_phy_media_type_t) MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE);
1479 if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES)
1480 epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID;
1482 epp->ep_phy_cap_mask =
1483 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP);
1484 #if EFSYS_OPT_PHY_FLAGS
1485 encp->enc_phy_flags_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_FLAGS);
1486 #endif /* EFSYS_OPT_PHY_FLAGS */
1488 encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT);
1490 /* Populate internal state */
1491 encp->enc_mcdi_mdio_channel =
1492 (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL);
1494 #if EFSYS_OPT_PHY_STATS
1495 encp->enc_mcdi_phy_stat_mask =
1496 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_STATS_MASK);
1497 #endif /* EFSYS_OPT_PHY_STATS */
1500 encp->enc_bist_mask = 0;
1501 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1502 GET_PHY_CFG_OUT_BIST_CABLE_SHORT))
1503 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_SHORT);
1504 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1505 GET_PHY_CFG_OUT_BIST_CABLE_LONG))
1506 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_LONG);
1507 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1508 GET_PHY_CFG_OUT_BIST))
1509 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_NORMAL);
1510 #endif /* EFSYS_OPT_BIST */
1517 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1522 __checkReturn efx_rc_t
1523 efx_mcdi_firmware_update_supported(
1524 __in efx_nic_t *enp,
1525 __out boolean_t *supportedp)
1527 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1530 if (emcop != NULL) {
1531 if ((rc = emcop->emco_feature_supported(enp,
1532 EFX_MCDI_FEATURE_FW_UPDATE, supportedp)) != 0)
1535 /* Earlier devices always supported updates */
1536 *supportedp = B_TRUE;
1542 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1547 __checkReturn efx_rc_t
1548 efx_mcdi_macaddr_change_supported(
1549 __in efx_nic_t *enp,
1550 __out boolean_t *supportedp)
1552 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1555 if (emcop != NULL) {
1556 if ((rc = emcop->emco_feature_supported(enp,
1557 EFX_MCDI_FEATURE_MACADDR_CHANGE, supportedp)) != 0)
1560 /* Earlier devices always supported MAC changes */
1561 *supportedp = B_TRUE;
1567 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1572 __checkReturn efx_rc_t
1573 efx_mcdi_link_control_supported(
1574 __in efx_nic_t *enp,
1575 __out boolean_t *supportedp)
1577 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1580 if (emcop != NULL) {
1581 if ((rc = emcop->emco_feature_supported(enp,
1582 EFX_MCDI_FEATURE_LINK_CONTROL, supportedp)) != 0)
1585 /* Earlier devices always supported link control */
1586 *supportedp = B_TRUE;
1592 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1597 __checkReturn efx_rc_t
1598 efx_mcdi_mac_spoofing_supported(
1599 __in efx_nic_t *enp,
1600 __out boolean_t *supportedp)
1602 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1605 if (emcop != NULL) {
1606 if ((rc = emcop->emco_feature_supported(enp,
1607 EFX_MCDI_FEATURE_MAC_SPOOFING, supportedp)) != 0)
1610 /* Earlier devices always supported MAC spoofing */
1611 *supportedp = B_TRUE;
1617 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1624 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
1626 * Enter bist offline mode. This is a fw mode which puts the NIC into a state
1627 * where memory BIST tests can be run and not much else can interfere or happen.
1628 * A reboot is required to exit this mode.
1630 __checkReturn efx_rc_t
1631 efx_mcdi_bist_enable_offline(
1632 __in efx_nic_t *enp)
1637 EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_IN_LEN == 0);
1638 EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_OUT_LEN == 0);
1640 req.emr_cmd = MC_CMD_ENABLE_OFFLINE_BIST;
1641 req.emr_in_buf = NULL;
1642 req.emr_in_length = 0;
1643 req.emr_out_buf = NULL;
1644 req.emr_out_length = 0;
1646 efx_mcdi_execute(enp, &req);
1648 if (req.emr_rc != 0) {
1656 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1660 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
1662 __checkReturn efx_rc_t
1663 efx_mcdi_bist_start(
1664 __in efx_nic_t *enp,
1665 __in efx_bist_type_t type)
1668 uint8_t payload[MAX(MC_CMD_START_BIST_IN_LEN,
1669 MC_CMD_START_BIST_OUT_LEN)];
1672 (void) memset(payload, 0, sizeof (payload));
1673 req.emr_cmd = MC_CMD_START_BIST;
1674 req.emr_in_buf = payload;
1675 req.emr_in_length = MC_CMD_START_BIST_IN_LEN;
1676 req.emr_out_buf = payload;
1677 req.emr_out_length = MC_CMD_START_BIST_OUT_LEN;
1680 case EFX_BIST_TYPE_PHY_NORMAL:
1681 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST);
1683 case EFX_BIST_TYPE_PHY_CABLE_SHORT:
1684 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1685 MC_CMD_PHY_BIST_CABLE_SHORT);
1687 case EFX_BIST_TYPE_PHY_CABLE_LONG:
1688 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1689 MC_CMD_PHY_BIST_CABLE_LONG);
1691 case EFX_BIST_TYPE_MC_MEM:
1692 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1693 MC_CMD_MC_MEM_BIST);
1695 case EFX_BIST_TYPE_SAT_MEM:
1696 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1697 MC_CMD_PORT_MEM_BIST);
1699 case EFX_BIST_TYPE_REG:
1700 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1707 efx_mcdi_execute(enp, &req);
1709 if (req.emr_rc != 0) {
1717 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1722 #endif /* EFSYS_OPT_BIST */
1725 /* Enable logging of some events (e.g. link state changes) */
1726 __checkReturn efx_rc_t
1728 __in efx_nic_t *enp)
1731 uint8_t payload[MAX(MC_CMD_LOG_CTRL_IN_LEN,
1732 MC_CMD_LOG_CTRL_OUT_LEN)];
1735 (void) memset(payload, 0, sizeof (payload));
1736 req.emr_cmd = MC_CMD_LOG_CTRL;
1737 req.emr_in_buf = payload;
1738 req.emr_in_length = MC_CMD_LOG_CTRL_IN_LEN;
1739 req.emr_out_buf = payload;
1740 req.emr_out_length = MC_CMD_LOG_CTRL_OUT_LEN;
1742 MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST,
1743 MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ);
1744 MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST_EVQ, 0);
1746 efx_mcdi_execute(enp, &req);
1748 if (req.emr_rc != 0) {
1756 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1762 #if EFSYS_OPT_MAC_STATS
1764 typedef enum efx_stats_action_e {
1767 EFX_STATS_ENABLE_NOEVENTS,
1768 EFX_STATS_ENABLE_EVENTS,
1770 } efx_stats_action_t;
1772 static __checkReturn efx_rc_t
1774 __in efx_nic_t *enp,
1775 __in_opt efsys_mem_t *esmp,
1776 __in efx_stats_action_t action,
1777 __in uint16_t period_ms)
1780 uint8_t payload[MAX(MC_CMD_MAC_STATS_IN_LEN,
1781 MC_CMD_MAC_STATS_OUT_DMA_LEN)];
1782 int clear = (action == EFX_STATS_CLEAR);
1783 int upload = (action == EFX_STATS_UPLOAD);
1784 int enable = (action == EFX_STATS_ENABLE_NOEVENTS);
1785 int events = (action == EFX_STATS_ENABLE_EVENTS);
1786 int disable = (action == EFX_STATS_DISABLE);
1789 (void) memset(payload, 0, sizeof (payload));
1790 req.emr_cmd = MC_CMD_MAC_STATS;
1791 req.emr_in_buf = payload;
1792 req.emr_in_length = MC_CMD_MAC_STATS_IN_LEN;
1793 req.emr_out_buf = payload;
1794 req.emr_out_length = MC_CMD_MAC_STATS_OUT_DMA_LEN;
1796 MCDI_IN_POPULATE_DWORD_6(req, MAC_STATS_IN_CMD,
1797 MAC_STATS_IN_DMA, upload,
1798 MAC_STATS_IN_CLEAR, clear,
1799 MAC_STATS_IN_PERIODIC_CHANGE, enable | events | disable,
1800 MAC_STATS_IN_PERIODIC_ENABLE, enable | events,
1801 MAC_STATS_IN_PERIODIC_NOEVENT, !events,
1802 MAC_STATS_IN_PERIOD_MS, (enable | events) ? period_ms : 0);
1805 int bytes = MC_CMD_MAC_NSTATS * sizeof (uint64_t);
1807 EFX_STATIC_ASSERT(MC_CMD_MAC_NSTATS * sizeof (uint64_t) <=
1808 EFX_MAC_STATS_SIZE);
1810 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_LO,
1811 EFSYS_MEM_ADDR(esmp) & 0xffffffff);
1812 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_HI,
1813 EFSYS_MEM_ADDR(esmp) >> 32);
1814 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_LEN, bytes);
1816 EFSYS_ASSERT(!upload && !enable && !events);
1820 * NOTE: Do not use EVB_PORT_ID_ASSIGNED when disabling periodic stats,
1821 * as this may fail (and leave periodic DMA enabled) if the
1822 * vadapter has already been deleted.
1824 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_PORT_ID,
1825 (disable ? EVB_PORT_ID_NULL : enp->en_vport_id));
1827 efx_mcdi_execute(enp, &req);
1829 if (req.emr_rc != 0) {
1830 /* EF10: Expect ENOENT if no DMA queues are initialised */
1831 if ((req.emr_rc != ENOENT) ||
1832 (enp->en_rx_qcount + enp->en_tx_qcount != 0)) {
1841 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1846 __checkReturn efx_rc_t
1847 efx_mcdi_mac_stats_clear(
1848 __in efx_nic_t *enp)
1852 if ((rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_CLEAR, 0)) != 0)
1858 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1863 __checkReturn efx_rc_t
1864 efx_mcdi_mac_stats_upload(
1865 __in efx_nic_t *enp,
1866 __in efsys_mem_t *esmp)
1871 * The MC DMAs aggregate statistics for our convenience, so we can
1872 * avoid having to pull the statistics buffer into the cache to
1873 * maintain cumulative statistics.
1875 if ((rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_UPLOAD, 0)) != 0)
1881 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1886 __checkReturn efx_rc_t
1887 efx_mcdi_mac_stats_periodic(
1888 __in efx_nic_t *enp,
1889 __in efsys_mem_t *esmp,
1890 __in uint16_t period_ms,
1891 __in boolean_t events)
1896 * The MC DMAs aggregate statistics for our convenience, so we can
1897 * avoid having to pull the statistics buffer into the cache to
1898 * maintain cumulative statistics.
1899 * Huntington uses a fixed 1sec period.
1900 * Medford uses a fixed 1sec period before v6.2.1.1033 firmware.
1903 rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_DISABLE, 0);
1905 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_EVENTS,
1908 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_NOEVENTS,
1917 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1922 #endif /* EFSYS_OPT_MAC_STATS */
1924 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
1927 * This function returns the pf and vf number of a function. If it is a pf the
1928 * vf number is 0xffff. The vf number is the index of the vf on that
1929 * function. So if you have 3 vfs on pf 0 the 3 vfs will return (pf=0,vf=0),
1930 * (pf=0,vf=1), (pf=0,vf=2) aand the pf will return (pf=0, vf=0xffff).
1932 __checkReturn efx_rc_t
1933 efx_mcdi_get_function_info(
1934 __in efx_nic_t *enp,
1935 __out uint32_t *pfp,
1936 __out_opt uint32_t *vfp)
1939 uint8_t payload[MAX(MC_CMD_GET_FUNCTION_INFO_IN_LEN,
1940 MC_CMD_GET_FUNCTION_INFO_OUT_LEN)];
1943 (void) memset(payload, 0, sizeof (payload));
1944 req.emr_cmd = MC_CMD_GET_FUNCTION_INFO;
1945 req.emr_in_buf = payload;
1946 req.emr_in_length = MC_CMD_GET_FUNCTION_INFO_IN_LEN;
1947 req.emr_out_buf = payload;
1948 req.emr_out_length = MC_CMD_GET_FUNCTION_INFO_OUT_LEN;
1950 efx_mcdi_execute(enp, &req);
1952 if (req.emr_rc != 0) {
1957 if (req.emr_out_length_used < MC_CMD_GET_FUNCTION_INFO_OUT_LEN) {
1962 *pfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_PF);
1964 *vfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_VF);
1971 EFSYS_PROBE1(fail1, efx_rc_t, rc);
1976 __checkReturn efx_rc_t
1977 efx_mcdi_privilege_mask(
1978 __in efx_nic_t *enp,
1981 __out uint32_t *maskp)
1984 uint8_t payload[MAX(MC_CMD_PRIVILEGE_MASK_IN_LEN,
1985 MC_CMD_PRIVILEGE_MASK_OUT_LEN)];
1988 (void) memset(payload, 0, sizeof (payload));
1989 req.emr_cmd = MC_CMD_PRIVILEGE_MASK;
1990 req.emr_in_buf = payload;
1991 req.emr_in_length = MC_CMD_PRIVILEGE_MASK_IN_LEN;
1992 req.emr_out_buf = payload;
1993 req.emr_out_length = MC_CMD_PRIVILEGE_MASK_OUT_LEN;
1995 MCDI_IN_POPULATE_DWORD_2(req, PRIVILEGE_MASK_IN_FUNCTION,
1996 PRIVILEGE_MASK_IN_FUNCTION_PF, pf,
1997 PRIVILEGE_MASK_IN_FUNCTION_VF, vf);
1999 efx_mcdi_execute(enp, &req);
2001 if (req.emr_rc != 0) {
2006 if (req.emr_out_length_used < MC_CMD_PRIVILEGE_MASK_OUT_LEN) {
2011 *maskp = MCDI_OUT_DWORD(req, PRIVILEGE_MASK_OUT_OLD_MASK);
2018 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2023 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
2025 __checkReturn efx_rc_t
2026 efx_mcdi_set_workaround(
2027 __in efx_nic_t *enp,
2029 __in boolean_t enabled,
2030 __out_opt uint32_t *flagsp)
2033 uint8_t payload[MAX(MC_CMD_WORKAROUND_IN_LEN,
2034 MC_CMD_WORKAROUND_EXT_OUT_LEN)];
2037 (void) memset(payload, 0, sizeof (payload));
2038 req.emr_cmd = MC_CMD_WORKAROUND;
2039 req.emr_in_buf = payload;
2040 req.emr_in_length = MC_CMD_WORKAROUND_IN_LEN;
2041 req.emr_out_buf = payload;
2042 req.emr_out_length = MC_CMD_WORKAROUND_OUT_LEN;
2044 MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, type);
2045 MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, enabled ? 1 : 0);
2047 efx_mcdi_execute_quiet(enp, &req);
2049 if (req.emr_rc != 0) {
2054 if (flagsp != NULL) {
2055 if (req.emr_out_length_used >= MC_CMD_WORKAROUND_EXT_OUT_LEN)
2056 *flagsp = MCDI_OUT_DWORD(req, WORKAROUND_EXT_OUT_FLAGS);
2064 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2070 __checkReturn efx_rc_t
2071 efx_mcdi_get_workarounds(
2072 __in efx_nic_t *enp,
2073 __out_opt uint32_t *implementedp,
2074 __out_opt uint32_t *enabledp)
2077 uint8_t payload[MC_CMD_GET_WORKAROUNDS_OUT_LEN];
2080 (void) memset(payload, 0, sizeof (payload));
2081 req.emr_cmd = MC_CMD_GET_WORKAROUNDS;
2082 req.emr_in_buf = NULL;
2083 req.emr_in_length = 0;
2084 req.emr_out_buf = payload;
2085 req.emr_out_length = MC_CMD_GET_WORKAROUNDS_OUT_LEN;
2087 efx_mcdi_execute(enp, &req);
2089 if (req.emr_rc != 0) {
2094 if (implementedp != NULL) {
2096 MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_IMPLEMENTED);
2099 if (enabledp != NULL) {
2100 *enabledp = MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_ENABLED);
2106 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2112 * Size of media information page in accordance with SFF-8472 and SFF-8436.
2113 * It is used in MCDI interface as well.
2115 #define EFX_PHY_MEDIA_INFO_PAGE_SIZE 0x80
2117 static __checkReturn efx_rc_t
2118 efx_mcdi_get_phy_media_info(
2119 __in efx_nic_t *enp,
2120 __in uint32_t mcdi_page,
2121 __in uint8_t offset,
2123 __out_bcount(len) uint8_t *data)
2126 uint8_t payload[MAX(MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN,
2127 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(
2128 EFX_PHY_MEDIA_INFO_PAGE_SIZE))];
2131 EFSYS_ASSERT((uint32_t)offset + len <= EFX_PHY_MEDIA_INFO_PAGE_SIZE);
2133 (void) memset(payload, 0, sizeof (payload));
2134 req.emr_cmd = MC_CMD_GET_PHY_MEDIA_INFO;
2135 req.emr_in_buf = payload;
2136 req.emr_in_length = MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN;
2137 req.emr_out_buf = payload;
2138 req.emr_out_length =
2139 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE);
2141 MCDI_IN_SET_DWORD(req, GET_PHY_MEDIA_INFO_IN_PAGE, mcdi_page);
2143 efx_mcdi_execute(enp, &req);
2145 if (req.emr_rc != 0) {
2150 if (req.emr_out_length_used !=
2151 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE)) {
2156 if (MCDI_OUT_DWORD(req, GET_PHY_MEDIA_INFO_OUT_DATALEN) !=
2157 EFX_PHY_MEDIA_INFO_PAGE_SIZE) {
2163 MCDI_OUT2(req, uint8_t, GET_PHY_MEDIA_INFO_OUT_DATA) + offset,
2173 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2179 * 2-wire device address of the base information in accordance with SFF-8472
2180 * Diagnostic Monitoring Interface for Optical Transceivers section
2181 * 4 Memory Organization.
2183 #define EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE 0xA0
2186 * 2-wire device address of the digital diagnostics monitoring interface
2187 * in accordance with SFF-8472 Diagnostic Monitoring Interface for Optical
2188 * Transceivers section 4 Memory Organization.
2190 #define EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM 0xA2
2193 * Hard wired 2-wire device address for QSFP+ in accordance with SFF-8436
2194 * QSFP+ 10 Gbs 4X PLUGGABLE TRANSCEIVER section 7.4 Device Addressing and
2197 #define EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP 0xA0
2199 __checkReturn efx_rc_t
2200 efx_mcdi_phy_module_get_info(
2201 __in efx_nic_t *enp,
2202 __in uint8_t dev_addr,
2203 __in uint8_t offset,
2205 __out_bcount(len) uint8_t *data)
2207 efx_port_t *epp = &(enp->en_port);
2209 uint32_t mcdi_lower_page;
2210 uint32_t mcdi_upper_page;
2212 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
2215 * Map device address to MC_CMD_GET_PHY_MEDIA_INFO pages.
2216 * Offset plus length interface allows to access page 0 only.
2217 * I.e. non-zero upper pages are not accessible.
2218 * See SFF-8472 section 4 Memory Organization and SFF-8436 section 7.6
2219 * QSFP+ Memory Map for details on how information is structured
2222 switch (epp->ep_fixed_port_type) {
2223 case EFX_PHY_MEDIA_SFP_PLUS:
2225 * In accordance with SFF-8472 Diagnostic Monitoring
2226 * Interface for Optical Transceivers section 4 Memory
2227 * Organization two 2-wire addresses are defined.
2230 /* Base information */
2231 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE:
2233 * MCDI page 0 should be used to access lower
2234 * page 0 (0x00 - 0x7f) at the device address 0xA0.
2236 mcdi_lower_page = 0;
2238 * MCDI page 1 should be used to access upper
2239 * page 0 (0x80 - 0xff) at the device address 0xA0.
2241 mcdi_upper_page = 1;
2244 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM:
2246 * MCDI page 2 should be used to access lower
2247 * page 0 (0x00 - 0x7f) at the device address 0xA2.
2249 mcdi_lower_page = 2;
2251 * MCDI page 3 should be used to access upper
2252 * page 0 (0x80 - 0xff) at the device address 0xA2.
2254 mcdi_upper_page = 3;
2261 case EFX_PHY_MEDIA_QSFP_PLUS:
2263 case EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP:
2265 * MCDI page -1 should be used to access lower page 0
2268 mcdi_lower_page = (uint32_t)-1;
2270 * MCDI page 0 should be used to access upper page 0
2273 mcdi_upper_page = 0;
2285 if (offset < EFX_PHY_MEDIA_INFO_PAGE_SIZE) {
2287 MIN(len, EFX_PHY_MEDIA_INFO_PAGE_SIZE - offset);
2289 rc = efx_mcdi_get_phy_media_info(enp,
2290 mcdi_lower_page, offset, read_len, data);
2299 offset -= EFX_PHY_MEDIA_INFO_PAGE_SIZE;
2303 EFSYS_ASSERT3U(len, <=, EFX_PHY_MEDIA_INFO_PAGE_SIZE);
2304 EFSYS_ASSERT3U(offset, <, EFX_PHY_MEDIA_INFO_PAGE_SIZE);
2306 rc = efx_mcdi_get_phy_media_info(enp,
2307 mcdi_upper_page, offset, len, data);
2319 EFSYS_PROBE1(fail1, efx_rc_t, rc);
2324 #endif /* EFSYS_OPT_MCDI */