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 || EFSYS_OPT_MEDFORD2
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 || EFSYS_OPT_MEDFORD2 */
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 */
95 #if EFSYS_OPT_MEDFORD2
96 case EFX_FAMILY_MEDFORD2
:
97 emcop
= &__efx_mcdi_ef10_ops
;
99 #endif /* EFSYS_OPT_MEDFORD2 */
107 if (enp
->en_features
& EFX_FEATURE_MCDI_DMA
) {
108 /* MCDI requires a DMA buffer in host memory */
109 if ((emtp
== NULL
) || (emtp
->emt_dma_mem
) == NULL
) {
114 enp
->en_mcdi
.em_emtp
= emtp
;
116 if (emcop
!= NULL
&& emcop
->emco_init
!= NULL
) {
117 if ((rc
= emcop
->emco_init(enp
, emtp
)) != 0)
121 enp
->en_mcdi
.em_emcop
= emcop
;
122 enp
->en_mod_flags
|= EFX_MOD_MCDI
;
131 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
133 enp
->en_mcdi
.em_emcop
= NULL
;
134 enp
->en_mcdi
.em_emtp
= NULL
;
135 enp
->en_mod_flags
&= ~EFX_MOD_MCDI
;
144 efx_mcdi_iface_t
*emip
= &(enp
->en_mcdi
.em_emip
);
145 const efx_mcdi_ops_t
*emcop
= enp
->en_mcdi
.em_emcop
;
147 EFSYS_ASSERT3U(enp
->en_magic
, ==, EFX_NIC_MAGIC
);
148 EFSYS_ASSERT3U(enp
->en_mod_flags
, ==, EFX_MOD_MCDI
);
150 if (emcop
!= NULL
&& emcop
->emco_fini
!= NULL
)
151 emcop
->emco_fini(enp
);
154 emip
->emi_aborted
= 0;
156 enp
->en_mcdi
.em_emcop
= NULL
;
157 enp
->en_mod_flags
&= ~EFX_MOD_MCDI
;
164 efx_mcdi_iface_t
*emip
= &(enp
->en_mcdi
.em_emip
);
165 efsys_lock_state_t state
;
167 /* Start a new epoch (allow fresh MCDI requests to succeed) */
168 EFSYS_LOCK(enp
->en_eslp
, state
);
169 emip
->emi_new_epoch
= B_TRUE
;
170 EFSYS_UNLOCK(enp
->en_eslp
, state
);
174 efx_mcdi_send_request(
181 const efx_mcdi_ops_t
*emcop
= enp
->en_mcdi
.em_emcop
;
183 emcop
->emco_send_request(enp
, hdrp
, hdr_len
, sdup
, sdu_len
);
187 efx_mcdi_poll_reboot(
190 const efx_mcdi_ops_t
*emcop
= enp
->en_mcdi
.em_emcop
;
193 rc
= emcop
->emco_poll_reboot(enp
);
198 efx_mcdi_poll_response(
201 const efx_mcdi_ops_t
*emcop
= enp
->en_mcdi
.em_emcop
;
204 available
= emcop
->emco_poll_response(enp
);
209 efx_mcdi_read_response(
215 const efx_mcdi_ops_t
*emcop
= enp
->en_mcdi
.em_emcop
;
217 emcop
->emco_read_response(enp
, bufferp
, offset
, length
);
221 efx_mcdi_request_start(
223 __in efx_mcdi_req_t
*emrp
,
224 __in boolean_t ev_cpl
)
226 #if EFSYS_OPT_MCDI_LOGGING
227 const efx_mcdi_transport_t
*emtp
= enp
->en_mcdi
.em_emtp
;
229 efx_mcdi_iface_t
*emip
= &(enp
->en_mcdi
.em_emip
);
232 unsigned int max_version
;
236 efsys_lock_state_t state
;
238 EFSYS_ASSERT3U(enp
->en_magic
, ==, EFX_NIC_MAGIC
);
239 EFSYS_ASSERT3U(enp
->en_mod_flags
, &, EFX_MOD_MCDI
);
240 EFSYS_ASSERT3U(enp
->en_features
, &, EFX_FEATURE_MCDI
);
243 * efx_mcdi_request_start() is naturally serialised against both
244 * efx_mcdi_request_poll() and efx_mcdi_ev_cpl()/efx_mcdi_ev_death(),
245 * by virtue of there only being one outstanding MCDI request.
246 * Unfortunately, upper layers may also call efx_mcdi_request_abort()
247 * at any time, to timeout a pending mcdi request, That request may
248 * then subsequently complete, meaning efx_mcdi_ev_cpl() or
249 * efx_mcdi_ev_death() may end up running in parallel with
250 * efx_mcdi_request_start(). This race is handled by ensuring that
251 * %emi_pending_req, %emi_ev_cpl and %emi_seq are protected by the
254 EFSYS_LOCK(enp
->en_eslp
, state
);
255 EFSYS_ASSERT(emip
->emi_pending_req
== NULL
);
256 emip
->emi_pending_req
= emrp
;
257 emip
->emi_ev_cpl
= ev_cpl
;
258 emip
->emi_poll_cnt
= 0;
259 seq
= emip
->emi_seq
++ & EFX_MASK32(MCDI_HEADER_SEQ
);
260 new_epoch
= emip
->emi_new_epoch
;
261 max_version
= emip
->emi_max_version
;
262 EFSYS_UNLOCK(enp
->en_eslp
, state
);
266 xflags
|= MCDI_HEADER_XFLAGS_EVREQ
;
269 * Huntington firmware supports MCDIv2, but the Huntington BootROM only
270 * supports MCDIv1. Use MCDIv1 headers for MCDIv1 commands where
271 * possible to support this.
273 if ((max_version
>= 2) &&
274 ((emrp
->emr_cmd
> MC_CMD_CMD_SPACE_ESCAPE_7
) ||
275 (emrp
->emr_in_length
> MCDI_CTL_SDU_LEN_MAX_V1
) ||
276 (emrp
->emr_out_length
> MCDI_CTL_SDU_LEN_MAX_V1
))) {
277 /* Construct MCDI v2 header */
278 hdr_len
= sizeof (hdr
);
279 EFX_POPULATE_DWORD_8(hdr
[0],
280 MCDI_HEADER_CODE
, MC_CMD_V2_EXTN
,
281 MCDI_HEADER_RESYNC
, 1,
282 MCDI_HEADER_DATALEN
, 0,
283 MCDI_HEADER_SEQ
, seq
,
284 MCDI_HEADER_NOT_EPOCH
, new_epoch
? 0 : 1,
285 MCDI_HEADER_ERROR
, 0,
286 MCDI_HEADER_RESPONSE
, 0,
287 MCDI_HEADER_XFLAGS
, xflags
);
289 EFX_POPULATE_DWORD_2(hdr
[1],
290 MC_CMD_V2_EXTN_IN_EXTENDED_CMD
, emrp
->emr_cmd
,
291 MC_CMD_V2_EXTN_IN_ACTUAL_LEN
, emrp
->emr_in_length
);
293 /* Construct MCDI v1 header */
294 hdr_len
= sizeof (hdr
[0]);
295 EFX_POPULATE_DWORD_8(hdr
[0],
296 MCDI_HEADER_CODE
, emrp
->emr_cmd
,
297 MCDI_HEADER_RESYNC
, 1,
298 MCDI_HEADER_DATALEN
, emrp
->emr_in_length
,
299 MCDI_HEADER_SEQ
, seq
,
300 MCDI_HEADER_NOT_EPOCH
, new_epoch
? 0 : 1,
301 MCDI_HEADER_ERROR
, 0,
302 MCDI_HEADER_RESPONSE
, 0,
303 MCDI_HEADER_XFLAGS
, xflags
);
306 #if EFSYS_OPT_MCDI_LOGGING
307 if (emtp
->emt_logger
!= NULL
) {
308 emtp
->emt_logger(emtp
->emt_context
, EFX_LOG_MCDI_REQUEST
,
310 emrp
->emr_in_buf
, emrp
->emr_in_length
);
312 #endif /* EFSYS_OPT_MCDI_LOGGING */
314 efx_mcdi_send_request(enp
, &hdr
[0], hdr_len
,
315 emrp
->emr_in_buf
, emrp
->emr_in_length
);
320 efx_mcdi_read_response_header(
322 __inout efx_mcdi_req_t
*emrp
)
324 #if EFSYS_OPT_MCDI_LOGGING
325 const efx_mcdi_transport_t
*emtp
= enp
->en_mcdi
.em_emtp
;
326 #endif /* EFSYS_OPT_MCDI_LOGGING */
327 efx_mcdi_iface_t
*emip
= &(enp
->en_mcdi
.em_emip
);
329 unsigned int hdr_len
;
330 unsigned int data_len
;
336 EFSYS_ASSERT(emrp
!= NULL
);
338 efx_mcdi_read_response(enp
, &hdr
[0], 0, sizeof (hdr
[0]));
339 hdr_len
= sizeof (hdr
[0]);
341 cmd
= EFX_DWORD_FIELD(hdr
[0], MCDI_HEADER_CODE
);
342 seq
= EFX_DWORD_FIELD(hdr
[0], MCDI_HEADER_SEQ
);
343 error
= EFX_DWORD_FIELD(hdr
[0], MCDI_HEADER_ERROR
);
345 if (cmd
!= MC_CMD_V2_EXTN
) {
346 data_len
= EFX_DWORD_FIELD(hdr
[0], MCDI_HEADER_DATALEN
);
348 efx_mcdi_read_response(enp
, &hdr
[1], hdr_len
, sizeof (hdr
[1]));
349 hdr_len
+= sizeof (hdr
[1]);
351 cmd
= EFX_DWORD_FIELD(hdr
[1], MC_CMD_V2_EXTN_IN_EXTENDED_CMD
);
353 EFX_DWORD_FIELD(hdr
[1], MC_CMD_V2_EXTN_IN_ACTUAL_LEN
);
356 if (error
&& (data_len
== 0)) {
357 /* The MC has rebooted since the request was sent. */
358 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US
);
359 efx_mcdi_poll_reboot(enp
);
363 if ((cmd
!= emrp
->emr_cmd
) ||
364 (seq
!= ((emip
->emi_seq
- 1) & EFX_MASK32(MCDI_HEADER_SEQ
)))) {
365 /* Response is for a different request */
371 unsigned int err_len
= MIN(data_len
, sizeof (err
));
372 int err_code
= MC_CMD_ERR_EPROTO
;
375 /* Read error code (and arg num for MCDI v2 commands) */
376 efx_mcdi_read_response(enp
, &err
, hdr_len
, err_len
);
378 if (err_len
>= (MC_CMD_ERR_CODE_OFST
+ sizeof (efx_dword_t
)))
379 err_code
= EFX_DWORD_FIELD(err
[0], EFX_DWORD_0
);
381 if (err_len
>= (MC_CMD_ERR_ARG_OFST
+ sizeof (efx_dword_t
)))
382 err_arg
= EFX_DWORD_FIELD(err
[1], EFX_DWORD_0
);
384 emrp
->emr_err_code
= err_code
;
385 emrp
->emr_err_arg
= err_arg
;
387 #if EFSYS_OPT_MCDI_PROXY_AUTH
388 if ((err_code
== MC_CMD_ERR_PROXY_PENDING
) &&
389 (err_len
== sizeof (err
))) {
391 * The MCDI request would normally fail with EPERM, but
392 * firmware has forwarded it to an authorization agent
393 * attached to a privileged PF.
395 * Save the authorization request handle. The client
396 * must wait for a PROXY_RESPONSE event, or timeout.
398 emrp
->emr_proxy_handle
= err_arg
;
400 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
402 #if EFSYS_OPT_MCDI_LOGGING
403 if (emtp
->emt_logger
!= NULL
) {
404 emtp
->emt_logger(emtp
->emt_context
,
405 EFX_LOG_MCDI_RESPONSE
,
409 #endif /* EFSYS_OPT_MCDI_LOGGING */
411 if (!emrp
->emr_quiet
) {
412 EFSYS_PROBE3(mcdi_err_arg
, int, emrp
->emr_cmd
,
413 int, err_code
, int, err_arg
);
416 rc
= efx_mcdi_request_errcode(err_code
);
421 emrp
->emr_out_length_used
= data_len
;
422 #if EFSYS_OPT_MCDI_PROXY_AUTH
423 emrp
->emr_proxy_handle
= 0;
424 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
431 emrp
->emr_out_length_used
= 0;
435 efx_mcdi_finish_response(
437 __in efx_mcdi_req_t
*emrp
)
439 #if EFSYS_OPT_MCDI_LOGGING
440 const efx_mcdi_transport_t
*emtp
= enp
->en_mcdi
.em_emtp
;
441 #endif /* EFSYS_OPT_MCDI_LOGGING */
443 unsigned int hdr_len
;
446 if (emrp
->emr_out_buf
== NULL
)
449 /* Read the command header to detect MCDI response format */
450 hdr_len
= sizeof (hdr
[0]);
451 efx_mcdi_read_response(enp
, &hdr
[0], 0, hdr_len
);
452 if (EFX_DWORD_FIELD(hdr
[0], MCDI_HEADER_CODE
) == MC_CMD_V2_EXTN
) {
454 * Read the actual payload length. The length given in the event
455 * is only correct for responses with the V1 format.
457 efx_mcdi_read_response(enp
, &hdr
[1], hdr_len
, sizeof (hdr
[1]));
458 hdr_len
+= sizeof (hdr
[1]);
460 emrp
->emr_out_length_used
= EFX_DWORD_FIELD(hdr
[1],
461 MC_CMD_V2_EXTN_IN_ACTUAL_LEN
);
464 /* Copy payload out into caller supplied buffer */
465 bytes
= MIN(emrp
->emr_out_length_used
, emrp
->emr_out_length
);
466 efx_mcdi_read_response(enp
, emrp
->emr_out_buf
, hdr_len
, bytes
);
468 #if EFSYS_OPT_MCDI_LOGGING
469 if (emtp
->emt_logger
!= NULL
) {
470 emtp
->emt_logger(emtp
->emt_context
,
471 EFX_LOG_MCDI_RESPONSE
,
473 emrp
->emr_out_buf
, bytes
);
475 #endif /* EFSYS_OPT_MCDI_LOGGING */
479 __checkReturn boolean_t
480 efx_mcdi_request_poll(
483 efx_mcdi_iface_t
*emip
= &(enp
->en_mcdi
.em_emip
);
484 efx_mcdi_req_t
*emrp
;
485 efsys_lock_state_t state
;
488 EFSYS_ASSERT3U(enp
->en_magic
, ==, EFX_NIC_MAGIC
);
489 EFSYS_ASSERT3U(enp
->en_mod_flags
, &, EFX_MOD_MCDI
);
490 EFSYS_ASSERT3U(enp
->en_features
, &, EFX_FEATURE_MCDI
);
492 /* Serialise against post-watchdog efx_mcdi_ev* */
493 EFSYS_LOCK(enp
->en_eslp
, state
);
495 EFSYS_ASSERT(emip
->emi_pending_req
!= NULL
);
496 EFSYS_ASSERT(!emip
->emi_ev_cpl
);
497 emrp
= emip
->emi_pending_req
;
499 /* Check for reboot atomically w.r.t efx_mcdi_request_start */
500 if (emip
->emi_poll_cnt
++ == 0) {
501 if ((rc
= efx_mcdi_poll_reboot(enp
)) != 0) {
502 emip
->emi_pending_req
= NULL
;
503 EFSYS_UNLOCK(enp
->en_eslp
, state
);
505 /* Reboot/Assertion */
506 if (rc
== EIO
|| rc
== EINTR
)
507 efx_mcdi_raise_exception(enp
, emrp
, rc
);
513 /* Check if a response is available */
514 if (efx_mcdi_poll_response(enp
) == B_FALSE
) {
515 EFSYS_UNLOCK(enp
->en_eslp
, state
);
519 /* Read the response header */
520 efx_mcdi_read_response_header(enp
, emrp
);
522 /* Request complete */
523 emip
->emi_pending_req
= NULL
;
525 /* Ensure stale MCDI requests fail after an MC reboot. */
526 emip
->emi_new_epoch
= B_FALSE
;
528 EFSYS_UNLOCK(enp
->en_eslp
, state
);
530 if ((rc
= emrp
->emr_rc
) != 0)
533 efx_mcdi_finish_response(enp
, emrp
);
537 if (!emrp
->emr_quiet
)
540 if (!emrp
->emr_quiet
)
541 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
546 __checkReturn boolean_t
547 efx_mcdi_request_abort(
550 efx_mcdi_iface_t
*emip
= &(enp
->en_mcdi
.em_emip
);
551 efx_mcdi_req_t
*emrp
;
553 efsys_lock_state_t state
;
555 EFSYS_ASSERT3U(enp
->en_magic
, ==, EFX_NIC_MAGIC
);
556 EFSYS_ASSERT3U(enp
->en_mod_flags
, &, EFX_MOD_MCDI
);
557 EFSYS_ASSERT3U(enp
->en_features
, &, EFX_FEATURE_MCDI
);
560 * efx_mcdi_ev_* may have already completed this event, and be
561 * spinning/blocked on the upper layer lock. So it *is* legitimate
562 * to for emi_pending_req to be NULL. If there is a pending event
563 * completed request, then provide a "credit" to allow
564 * efx_mcdi_ev_cpl() to accept a single spurious completion.
566 EFSYS_LOCK(enp
->en_eslp
, state
);
567 emrp
= emip
->emi_pending_req
;
568 aborted
= (emrp
!= NULL
);
570 emip
->emi_pending_req
= NULL
;
572 /* Error the request */
573 emrp
->emr_out_length_used
= 0;
574 emrp
->emr_rc
= ETIMEDOUT
;
576 /* Provide a credit for seqno/emr_pending_req mismatches */
577 if (emip
->emi_ev_cpl
)
581 * The upper layer has called us, so we don't
582 * need to complete the request.
585 EFSYS_UNLOCK(enp
->en_eslp
, state
);
591 efx_mcdi_get_timeout(
593 __in efx_mcdi_req_t
*emrp
,
594 __out
uint32_t *timeoutp
)
596 const efx_mcdi_ops_t
*emcop
= enp
->en_mcdi
.em_emcop
;
598 emcop
->emco_get_timeout(enp
, emrp
, timeoutp
);
601 __checkReturn efx_rc_t
602 efx_mcdi_request_errcode(
603 __in
unsigned int err
)
608 case MC_CMD_ERR_EPERM
:
610 case MC_CMD_ERR_ENOENT
:
612 case MC_CMD_ERR_EINTR
:
614 case MC_CMD_ERR_EACCES
:
616 case MC_CMD_ERR_EBUSY
:
618 case MC_CMD_ERR_EINVAL
:
620 case MC_CMD_ERR_EDEADLK
:
622 case MC_CMD_ERR_ENOSYS
:
624 case MC_CMD_ERR_ETIME
:
626 case MC_CMD_ERR_ENOTSUP
:
628 case MC_CMD_ERR_EALREADY
:
632 case MC_CMD_ERR_EEXIST
:
634 #ifdef MC_CMD_ERR_EAGAIN
635 case MC_CMD_ERR_EAGAIN
:
638 #ifdef MC_CMD_ERR_ENOSPC
639 case MC_CMD_ERR_ENOSPC
:
642 case MC_CMD_ERR_ERANGE
:
645 case MC_CMD_ERR_ALLOC_FAIL
:
647 case MC_CMD_ERR_NO_VADAPTOR
:
649 case MC_CMD_ERR_NO_EVB_PORT
:
651 case MC_CMD_ERR_NO_VSWITCH
:
653 case MC_CMD_ERR_VLAN_LIMIT
:
655 case MC_CMD_ERR_BAD_PCI_FUNC
:
657 case MC_CMD_ERR_BAD_VLAN_MODE
:
659 case MC_CMD_ERR_BAD_VSWITCH_TYPE
:
661 case MC_CMD_ERR_BAD_VPORT_TYPE
:
663 case MC_CMD_ERR_MAC_EXIST
:
666 case MC_CMD_ERR_PROXY_PENDING
:
670 EFSYS_PROBE1(mc_pcol_error
, int, err
);
676 efx_mcdi_raise_exception(
678 __in_opt efx_mcdi_req_t
*emrp
,
681 const efx_mcdi_transport_t
*emtp
= enp
->en_mcdi
.em_emtp
;
682 efx_mcdi_exception_t exception
;
684 /* Reboot or Assertion failure only */
685 EFSYS_ASSERT(rc
== EIO
|| rc
== EINTR
);
688 * If MC_CMD_REBOOT causes a reboot (dependent on parameters),
689 * then the EIO is not worthy of an exception.
691 if (emrp
!= NULL
&& emrp
->emr_cmd
== MC_CMD_REBOOT
&& rc
== EIO
)
694 exception
= (rc
== EIO
)
695 ? EFX_MCDI_EXCEPTION_MC_REBOOT
696 : EFX_MCDI_EXCEPTION_MC_BADASSERT
;
698 emtp
->emt_exception(emtp
->emt_context
, exception
);
704 __inout efx_mcdi_req_t
*emrp
)
706 const efx_mcdi_transport_t
*emtp
= enp
->en_mcdi
.em_emtp
;
708 EFSYS_ASSERT3U(enp
->en_mod_flags
, &, EFX_MOD_MCDI
);
709 EFSYS_ASSERT3U(enp
->en_features
, &, EFX_FEATURE_MCDI
);
711 emrp
->emr_quiet
= B_FALSE
;
712 emtp
->emt_execute(emtp
->emt_context
, emrp
);
716 efx_mcdi_execute_quiet(
718 __inout efx_mcdi_req_t
*emrp
)
720 const efx_mcdi_transport_t
*emtp
= enp
->en_mcdi
.em_emtp
;
722 EFSYS_ASSERT3U(enp
->en_mod_flags
, &, EFX_MOD_MCDI
);
723 EFSYS_ASSERT3U(enp
->en_features
, &, EFX_FEATURE_MCDI
);
725 emrp
->emr_quiet
= B_TRUE
;
726 emtp
->emt_execute(emtp
->emt_context
, emrp
);
732 __in
unsigned int seq
,
733 __in
unsigned int outlen
,
736 efx_mcdi_iface_t
*emip
= &(enp
->en_mcdi
.em_emip
);
737 const efx_mcdi_transport_t
*emtp
= enp
->en_mcdi
.em_emtp
;
738 efx_mcdi_req_t
*emrp
;
739 efsys_lock_state_t state
;
741 EFSYS_ASSERT3U(enp
->en_mod_flags
, &, EFX_MOD_MCDI
);
742 EFSYS_ASSERT3U(enp
->en_features
, &, EFX_FEATURE_MCDI
);
745 * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start()
746 * when we're completing an aborted request.
748 EFSYS_LOCK(enp
->en_eslp
, state
);
749 if (emip
->emi_pending_req
== NULL
|| !emip
->emi_ev_cpl
||
750 (seq
!= ((emip
->emi_seq
- 1) & EFX_MASK32(MCDI_HEADER_SEQ
)))) {
751 EFSYS_ASSERT(emip
->emi_aborted
> 0);
752 if (emip
->emi_aborted
> 0)
754 EFSYS_UNLOCK(enp
->en_eslp
, state
);
758 emrp
= emip
->emi_pending_req
;
759 emip
->emi_pending_req
= NULL
;
760 EFSYS_UNLOCK(enp
->en_eslp
, state
);
762 if (emip
->emi_max_version
>= 2) {
763 /* MCDIv2 response details do not fit into an event. */
764 efx_mcdi_read_response_header(enp
, emrp
);
767 if (!emrp
->emr_quiet
) {
768 EFSYS_PROBE2(mcdi_err
, int, emrp
->emr_cmd
,
771 emrp
->emr_out_length_used
= 0;
772 emrp
->emr_rc
= efx_mcdi_request_errcode(errcode
);
774 emrp
->emr_out_length_used
= outlen
;
778 if (emrp
->emr_rc
== 0)
779 efx_mcdi_finish_response(enp
, emrp
);
781 emtp
->emt_ev_cpl(emtp
->emt_context
);
784 #if EFSYS_OPT_MCDI_PROXY_AUTH
786 __checkReturn efx_rc_t
787 efx_mcdi_get_proxy_handle(
789 __in efx_mcdi_req_t
*emrp
,
790 __out
uint32_t *handlep
)
794 _NOTE(ARGUNUSED(enp
))
797 * Return proxy handle from MCDI request that returned with error
798 * MC_MCD_ERR_PROXY_PENDING. This handle is used to wait for a matching
799 * PROXY_RESPONSE event.
801 if ((emrp
== NULL
) || (handlep
== NULL
)) {
805 if ((emrp
->emr_rc
!= 0) &&
806 (emrp
->emr_err_code
== MC_CMD_ERR_PROXY_PENDING
)) {
807 *handlep
= emrp
->emr_proxy_handle
;
816 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
821 efx_mcdi_ev_proxy_response(
823 __in
unsigned int handle
,
824 __in
unsigned int status
)
826 const efx_mcdi_transport_t
*emtp
= enp
->en_mcdi
.em_emtp
;
830 * Handle results of an authorization request for a privileged MCDI
831 * command. If authorization was granted then we must re-issue the
832 * original MCDI request. If authorization failed or timed out,
833 * then the original MCDI request should be completed with the
834 * result code from this event.
836 rc
= (status
== 0) ? 0 : efx_mcdi_request_errcode(status
);
838 emtp
->emt_ev_proxy_response(emtp
->emt_context
, handle
, rc
);
840 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
847 efx_mcdi_iface_t
*emip
= &(enp
->en_mcdi
.em_emip
);
848 const efx_mcdi_transport_t
*emtp
= enp
->en_mcdi
.em_emtp
;
849 efx_mcdi_req_t
*emrp
= NULL
;
851 efsys_lock_state_t state
;
854 * The MCDI request (if there is one) has been terminated, either
855 * by a BADASSERT or REBOOT event.
857 * If there is an outstanding event-completed MCDI operation, then we
858 * will never receive the completion event (because both MCDI
859 * completions and BADASSERT events are sent to the same evq). So
860 * complete this MCDI op.
862 * This function might run in parallel with efx_mcdi_request_poll()
863 * for poll completed mcdi requests, and also with
864 * efx_mcdi_request_start() for post-watchdog completions.
866 EFSYS_LOCK(enp
->en_eslp
, state
);
867 emrp
= emip
->emi_pending_req
;
868 ev_cpl
= emip
->emi_ev_cpl
;
869 if (emrp
!= NULL
&& emip
->emi_ev_cpl
) {
870 emip
->emi_pending_req
= NULL
;
872 emrp
->emr_out_length_used
= 0;
878 * Since we're running in parallel with a request, consume the
879 * status word before dropping the lock.
881 if (rc
== EIO
|| rc
== EINTR
) {
882 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US
);
883 (void) efx_mcdi_poll_reboot(enp
);
884 emip
->emi_new_epoch
= B_TRUE
;
887 EFSYS_UNLOCK(enp
->en_eslp
, state
);
889 efx_mcdi_raise_exception(enp
, emrp
, rc
);
891 if (emrp
!= NULL
&& ev_cpl
)
892 emtp
->emt_ev_cpl(emtp
->emt_context
);
895 __checkReturn efx_rc_t
898 __out_ecount_opt(4) uint16_t versionp
[4],
899 __out_opt
uint32_t *buildp
,
900 __out_opt efx_mcdi_boot_t
*statusp
)
903 uint8_t payload
[MAX(MAX(MC_CMD_GET_VERSION_IN_LEN
,
904 MC_CMD_GET_VERSION_OUT_LEN
),
905 MAX(MC_CMD_GET_BOOT_STATUS_IN_LEN
,
906 MC_CMD_GET_BOOT_STATUS_OUT_LEN
))];
907 efx_word_t
*ver_words
;
910 efx_mcdi_boot_t status
;
913 EFSYS_ASSERT3U(enp
->en_features
, &, EFX_FEATURE_MCDI
);
915 (void) memset(payload
, 0, sizeof (payload
));
916 req
.emr_cmd
= MC_CMD_GET_VERSION
;
917 req
.emr_in_buf
= payload
;
918 req
.emr_in_length
= MC_CMD_GET_VERSION_IN_LEN
;
919 req
.emr_out_buf
= payload
;
920 req
.emr_out_length
= MC_CMD_GET_VERSION_OUT_LEN
;
922 efx_mcdi_execute(enp
, &req
);
924 if (req
.emr_rc
!= 0) {
929 /* bootrom support */
930 if (req
.emr_out_length_used
== MC_CMD_GET_VERSION_V0_OUT_LEN
) {
931 version
[0] = version
[1] = version
[2] = version
[3] = 0;
932 build
= MCDI_OUT_DWORD(req
, GET_VERSION_OUT_FIRMWARE
);
937 if (req
.emr_out_length_used
< MC_CMD_GET_VERSION_OUT_LEN
) {
942 ver_words
= MCDI_OUT2(req
, efx_word_t
, GET_VERSION_OUT_VERSION
);
943 version
[0] = EFX_WORD_FIELD(ver_words
[0], EFX_WORD_0
);
944 version
[1] = EFX_WORD_FIELD(ver_words
[1], EFX_WORD_0
);
945 version
[2] = EFX_WORD_FIELD(ver_words
[2], EFX_WORD_0
);
946 version
[3] = EFX_WORD_FIELD(ver_words
[3], EFX_WORD_0
);
947 build
= MCDI_OUT_DWORD(req
, GET_VERSION_OUT_FIRMWARE
);
950 /* The bootrom doesn't understand BOOT_STATUS */
951 if (MC_FW_VERSION_IS_BOOTLOADER(build
)) {
952 status
= EFX_MCDI_BOOT_ROM
;
956 (void) memset(payload
, 0, sizeof (payload
));
957 req
.emr_cmd
= MC_CMD_GET_BOOT_STATUS
;
958 req
.emr_in_buf
= payload
;
959 req
.emr_in_length
= MC_CMD_GET_BOOT_STATUS_IN_LEN
;
960 req
.emr_out_buf
= payload
;
961 req
.emr_out_length
= MC_CMD_GET_BOOT_STATUS_OUT_LEN
;
963 efx_mcdi_execute_quiet(enp
, &req
);
965 if (req
.emr_rc
== EACCES
) {
966 /* Unprivileged functions cannot access BOOT_STATUS */
967 status
= EFX_MCDI_BOOT_PRIMARY
;
968 version
[0] = version
[1] = version
[2] = version
[3] = 0;
973 if (req
.emr_rc
!= 0) {
978 if (req
.emr_out_length_used
< MC_CMD_GET_BOOT_STATUS_OUT_LEN
) {
983 if (MCDI_OUT_DWORD_FIELD(req
, GET_BOOT_STATUS_OUT_FLAGS
,
984 GET_BOOT_STATUS_OUT_FLAGS_PRIMARY
))
985 status
= EFX_MCDI_BOOT_PRIMARY
;
987 status
= EFX_MCDI_BOOT_SECONDARY
;
990 if (versionp
!= NULL
)
991 memcpy(versionp
, version
, sizeof (version
));
1006 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1011 __checkReturn efx_rc_t
1012 efx_mcdi_get_capabilities(
1013 __in efx_nic_t
*enp
,
1014 __out_opt
uint32_t *flagsp
,
1015 __out_opt
uint16_t *rx_dpcpu_fw_idp
,
1016 __out_opt
uint16_t *tx_dpcpu_fw_idp
,
1017 __out_opt
uint32_t *flags2p
,
1018 __out_opt
uint32_t *tso2ncp
)
1021 uint8_t payload
[MAX(MC_CMD_GET_CAPABILITIES_IN_LEN
,
1022 MC_CMD_GET_CAPABILITIES_V2_OUT_LEN
)];
1023 boolean_t v2_capable
;
1026 (void) memset(payload
, 0, sizeof (payload
));
1027 req
.emr_cmd
= MC_CMD_GET_CAPABILITIES
;
1028 req
.emr_in_buf
= payload
;
1029 req
.emr_in_length
= MC_CMD_GET_CAPABILITIES_IN_LEN
;
1030 req
.emr_out_buf
= payload
;
1031 req
.emr_out_length
= MC_CMD_GET_CAPABILITIES_V2_OUT_LEN
;
1033 efx_mcdi_execute_quiet(enp
, &req
);
1035 if (req
.emr_rc
!= 0) {
1040 if (req
.emr_out_length_used
< MC_CMD_GET_CAPABILITIES_OUT_LEN
) {
1046 *flagsp
= MCDI_OUT_DWORD(req
, GET_CAPABILITIES_OUT_FLAGS1
);
1048 if (rx_dpcpu_fw_idp
!= NULL
)
1049 *rx_dpcpu_fw_idp
= MCDI_OUT_WORD(req
,
1050 GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID
);
1052 if (tx_dpcpu_fw_idp
!= NULL
)
1053 *tx_dpcpu_fw_idp
= MCDI_OUT_WORD(req
,
1054 GET_CAPABILITIES_OUT_TX_DPCPU_FW_ID
);
1056 if (req
.emr_out_length_used
< MC_CMD_GET_CAPABILITIES_V2_OUT_LEN
)
1057 v2_capable
= B_FALSE
;
1059 v2_capable
= B_TRUE
;
1061 if (flags2p
!= NULL
) {
1062 *flags2p
= (v2_capable
) ?
1063 MCDI_OUT_DWORD(req
, GET_CAPABILITIES_V2_OUT_FLAGS2
) :
1067 if (tso2ncp
!= NULL
) {
1068 *tso2ncp
= (v2_capable
) ?
1070 GET_CAPABILITIES_V2_OUT_TX_TSO_V2_N_CONTEXTS
) :
1079 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1084 static __checkReturn efx_rc_t
1086 __in efx_nic_t
*enp
,
1087 __in boolean_t after_assertion
)
1089 uint8_t payload
[MAX(MC_CMD_REBOOT_IN_LEN
, MC_CMD_REBOOT_OUT_LEN
)];
1094 * We could require the caller to have caused en_mod_flags=0 to
1095 * call this function. This doesn't help the other port though,
1096 * who's about to get the MC ripped out from underneath them.
1097 * Since they have to cope with the subsequent fallout of MCDI
1098 * failures, we should as well.
1100 EFSYS_ASSERT3U(enp
->en_magic
, ==, EFX_NIC_MAGIC
);
1102 (void) memset(payload
, 0, sizeof (payload
));
1103 req
.emr_cmd
= MC_CMD_REBOOT
;
1104 req
.emr_in_buf
= payload
;
1105 req
.emr_in_length
= MC_CMD_REBOOT_IN_LEN
;
1106 req
.emr_out_buf
= payload
;
1107 req
.emr_out_length
= MC_CMD_REBOOT_OUT_LEN
;
1109 MCDI_IN_SET_DWORD(req
, REBOOT_IN_FLAGS
,
1110 (after_assertion
? MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION
: 0));
1112 efx_mcdi_execute_quiet(enp
, &req
);
1114 if (req
.emr_rc
== EACCES
) {
1115 /* Unprivileged functions cannot reboot the MC. */
1119 /* A successful reboot request returns EIO. */
1120 if (req
.emr_rc
!= 0 && req
.emr_rc
!= EIO
) {
1129 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1134 __checkReturn efx_rc_t
1136 __in efx_nic_t
*enp
)
1138 return (efx_mcdi_do_reboot(enp
, B_FALSE
));
1141 __checkReturn efx_rc_t
1142 efx_mcdi_exit_assertion_handler(
1143 __in efx_nic_t
*enp
)
1145 return (efx_mcdi_do_reboot(enp
, B_TRUE
));
1148 __checkReturn efx_rc_t
1149 efx_mcdi_read_assertion(
1150 __in efx_nic_t
*enp
)
1153 uint8_t payload
[MAX(MC_CMD_GET_ASSERTS_IN_LEN
,
1154 MC_CMD_GET_ASSERTS_OUT_LEN
)];
1163 * Before we attempt to chat to the MC, we should verify that the MC
1164 * isn't in it's assertion handler, either due to a previous reboot,
1165 * or because we're reinitializing due to an eec_exception().
1167 * Use GET_ASSERTS to read any assertion state that may be present.
1168 * Retry this command twice. Once because a boot-time assertion failure
1169 * might cause the 1st MCDI request to fail. And once again because
1170 * we might race with efx_mcdi_exit_assertion_handler() running on
1171 * partner port(s) on the same NIC.
1175 (void) memset(payload
, 0, sizeof (payload
));
1176 req
.emr_cmd
= MC_CMD_GET_ASSERTS
;
1177 req
.emr_in_buf
= payload
;
1178 req
.emr_in_length
= MC_CMD_GET_ASSERTS_IN_LEN
;
1179 req
.emr_out_buf
= payload
;
1180 req
.emr_out_length
= MC_CMD_GET_ASSERTS_OUT_LEN
;
1182 MCDI_IN_SET_DWORD(req
, GET_ASSERTS_IN_CLEAR
, 1);
1183 efx_mcdi_execute_quiet(enp
, &req
);
1185 } while ((req
.emr_rc
== EINTR
|| req
.emr_rc
== EIO
) && retry
-- > 0);
1187 if (req
.emr_rc
!= 0) {
1188 if (req
.emr_rc
== EACCES
) {
1189 /* Unprivileged functions cannot clear assertions. */
1196 if (req
.emr_out_length_used
< MC_CMD_GET_ASSERTS_OUT_LEN
) {
1201 /* Print out any assertion state recorded */
1202 flags
= MCDI_OUT_DWORD(req
, GET_ASSERTS_OUT_GLOBAL_FLAGS
);
1203 if (flags
== MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS
)
1206 reason
= (flags
== MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL
)
1207 ? "system-level assertion"
1208 : (flags
== MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL
)
1209 ? "thread-level assertion"
1210 : (flags
== MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED
)
1212 : (flags
== MC_CMD_GET_ASSERTS_FLAGS_ADDR_TRAP
)
1213 ? "illegal address trap"
1214 : "unknown assertion";
1215 EFSYS_PROBE3(mcpu_assertion
,
1216 const char *, reason
, unsigned int,
1217 MCDI_OUT_DWORD(req
, GET_ASSERTS_OUT_SAVED_PC_OFFS
),
1219 MCDI_OUT_DWORD(req
, GET_ASSERTS_OUT_THREAD_OFFS
));
1221 /* Print out the registers (r1 ... r31) */
1222 ofst
= MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST
;
1224 index
< 1 + MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM
;
1226 EFSYS_PROBE2(mcpu_register
, unsigned int, index
, unsigned int,
1227 EFX_DWORD_FIELD(*MCDI_OUT(req
, efx_dword_t
, ofst
),
1229 ofst
+= sizeof (efx_dword_t
);
1231 EFSYS_ASSERT(ofst
<= MC_CMD_GET_ASSERTS_OUT_LEN
);
1239 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1246 * Internal routines for for specific MCDI requests.
1249 __checkReturn efx_rc_t
1250 efx_mcdi_drv_attach(
1251 __in efx_nic_t
*enp
,
1252 __in boolean_t attach
)
1255 uint8_t payload
[MAX(MC_CMD_DRV_ATTACH_IN_LEN
,
1256 MC_CMD_DRV_ATTACH_EXT_OUT_LEN
)];
1259 (void) memset(payload
, 0, sizeof (payload
));
1260 req
.emr_cmd
= MC_CMD_DRV_ATTACH
;
1261 req
.emr_in_buf
= payload
;
1262 req
.emr_in_length
= MC_CMD_DRV_ATTACH_IN_LEN
;
1263 req
.emr_out_buf
= payload
;
1264 req
.emr_out_length
= MC_CMD_DRV_ATTACH_EXT_OUT_LEN
;
1267 * Typically, client drivers use DONT_CARE for the datapath firmware
1268 * type to ensure that the driver can attach to an unprivileged
1269 * function. The datapath firmware type to use is controlled by the
1271 * If a client driver wishes to attach with a specific datapath firmware
1272 * type, that can be passed in second argument of efx_nic_probe API. One
1273 * such example is the ESXi native driver that attempts attaching with
1274 * FULL_FEATURED datapath firmware type first and fall backs to
1275 * DONT_CARE datapath firmware type if MC_CMD_DRV_ATTACH fails.
1277 MCDI_IN_POPULATE_DWORD_2(req
, DRV_ATTACH_IN_NEW_STATE
,
1278 DRV_ATTACH_IN_ATTACH
, attach
? 1 : 0,
1279 DRV_ATTACH_IN_SUBVARIANT_AWARE
, EFSYS_OPT_FW_SUBVARIANT_AWARE
);
1280 MCDI_IN_SET_DWORD(req
, DRV_ATTACH_IN_UPDATE
, 1);
1281 MCDI_IN_SET_DWORD(req
, DRV_ATTACH_IN_FIRMWARE_ID
, enp
->efv
);
1283 efx_mcdi_execute(enp
, &req
);
1285 if (req
.emr_rc
!= 0) {
1290 if (req
.emr_out_length_used
< MC_CMD_DRV_ATTACH_OUT_LEN
) {
1300 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1305 __checkReturn efx_rc_t
1306 efx_mcdi_get_board_cfg(
1307 __in efx_nic_t
*enp
,
1308 __out_opt
uint32_t *board_typep
,
1309 __out_opt efx_dword_t
*capabilitiesp
,
1310 __out_ecount_opt(6) uint8_t mac_addrp
[6])
1312 efx_mcdi_iface_t
*emip
= &(enp
->en_mcdi
.em_emip
);
1314 uint8_t payload
[MAX(MC_CMD_GET_BOARD_CFG_IN_LEN
,
1315 MC_CMD_GET_BOARD_CFG_OUT_LENMIN
)];
1318 (void) memset(payload
, 0, sizeof (payload
));
1319 req
.emr_cmd
= MC_CMD_GET_BOARD_CFG
;
1320 req
.emr_in_buf
= payload
;
1321 req
.emr_in_length
= MC_CMD_GET_BOARD_CFG_IN_LEN
;
1322 req
.emr_out_buf
= payload
;
1323 req
.emr_out_length
= MC_CMD_GET_BOARD_CFG_OUT_LENMIN
;
1325 efx_mcdi_execute(enp
, &req
);
1327 if (req
.emr_rc
!= 0) {
1332 if (req
.emr_out_length_used
< MC_CMD_GET_BOARD_CFG_OUT_LENMIN
) {
1337 if (mac_addrp
!= NULL
) {
1340 if (emip
->emi_port
== 1) {
1341 addrp
= MCDI_OUT2(req
, uint8_t,
1342 GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0
);
1343 } else if (emip
->emi_port
== 2) {
1344 addrp
= MCDI_OUT2(req
, uint8_t,
1345 GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1
);
1351 EFX_MAC_ADDR_COPY(mac_addrp
, addrp
);
1354 if (capabilitiesp
!= NULL
) {
1355 if (emip
->emi_port
== 1) {
1356 *capabilitiesp
= *MCDI_OUT2(req
, efx_dword_t
,
1357 GET_BOARD_CFG_OUT_CAPABILITIES_PORT0
);
1358 } else if (emip
->emi_port
== 2) {
1359 *capabilitiesp
= *MCDI_OUT2(req
, efx_dword_t
,
1360 GET_BOARD_CFG_OUT_CAPABILITIES_PORT1
);
1367 if (board_typep
!= NULL
) {
1368 *board_typep
= MCDI_OUT_DWORD(req
,
1369 GET_BOARD_CFG_OUT_BOARD_TYPE
);
1381 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1386 __checkReturn efx_rc_t
1387 efx_mcdi_get_resource_limits(
1388 __in efx_nic_t
*enp
,
1389 __out_opt
uint32_t *nevqp
,
1390 __out_opt
uint32_t *nrxqp
,
1391 __out_opt
uint32_t *ntxqp
)
1394 uint8_t payload
[MAX(MC_CMD_GET_RESOURCE_LIMITS_IN_LEN
,
1395 MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN
)];
1398 (void) memset(payload
, 0, sizeof (payload
));
1399 req
.emr_cmd
= MC_CMD_GET_RESOURCE_LIMITS
;
1400 req
.emr_in_buf
= payload
;
1401 req
.emr_in_length
= MC_CMD_GET_RESOURCE_LIMITS_IN_LEN
;
1402 req
.emr_out_buf
= payload
;
1403 req
.emr_out_length
= MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN
;
1405 efx_mcdi_execute(enp
, &req
);
1407 if (req
.emr_rc
!= 0) {
1412 if (req
.emr_out_length_used
< MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN
) {
1418 *nevqp
= MCDI_OUT_DWORD(req
, GET_RESOURCE_LIMITS_OUT_EVQ
);
1420 *nrxqp
= MCDI_OUT_DWORD(req
, GET_RESOURCE_LIMITS_OUT_RXQ
);
1422 *ntxqp
= MCDI_OUT_DWORD(req
, GET_RESOURCE_LIMITS_OUT_TXQ
);
1429 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1434 __checkReturn efx_rc_t
1435 efx_mcdi_get_phy_cfg(
1436 __in efx_nic_t
*enp
)
1438 efx_port_t
*epp
= &(enp
->en_port
);
1439 efx_nic_cfg_t
*encp
= &(enp
->en_nic_cfg
);
1441 uint8_t payload
[MAX(MC_CMD_GET_PHY_CFG_IN_LEN
,
1442 MC_CMD_GET_PHY_CFG_OUT_LEN
)];
1447 uint32_t phy_media_type
;
1450 (void) memset(payload
, 0, sizeof (payload
));
1451 req
.emr_cmd
= MC_CMD_GET_PHY_CFG
;
1452 req
.emr_in_buf
= payload
;
1453 req
.emr_in_length
= MC_CMD_GET_PHY_CFG_IN_LEN
;
1454 req
.emr_out_buf
= payload
;
1455 req
.emr_out_length
= MC_CMD_GET_PHY_CFG_OUT_LEN
;
1457 efx_mcdi_execute(enp
, &req
);
1459 if (req
.emr_rc
!= 0) {
1464 if (req
.emr_out_length_used
< MC_CMD_GET_PHY_CFG_OUT_LEN
) {
1469 encp
->enc_phy_type
= MCDI_OUT_DWORD(req
, GET_PHY_CFG_OUT_TYPE
);
1471 namep
= MCDI_OUT2(req
, char, GET_PHY_CFG_OUT_NAME
);
1472 namelen
= MIN(sizeof (encp
->enc_phy_name
) - 1,
1473 strnlen(namep
, MC_CMD_GET_PHY_CFG_OUT_NAME_LEN
));
1474 (void) memset(encp
->enc_phy_name
, 0,
1475 sizeof (encp
->enc_phy_name
));
1476 memcpy(encp
->enc_phy_name
, namep
, namelen
);
1477 #endif /* EFSYS_OPT_NAMES */
1478 (void) memset(encp
->enc_phy_revision
, 0,
1479 sizeof (encp
->enc_phy_revision
));
1480 memcpy(encp
->enc_phy_revision
,
1481 MCDI_OUT2(req
, char, GET_PHY_CFG_OUT_REVISION
),
1482 MIN(sizeof (encp
->enc_phy_revision
) - 1,
1483 MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN
));
1484 #if EFSYS_OPT_PHY_LED_CONTROL
1485 encp
->enc_led_mask
= ((1 << EFX_PHY_LED_DEFAULT
) |
1486 (1 << EFX_PHY_LED_OFF
) |
1487 (1 << EFX_PHY_LED_ON
));
1488 #endif /* EFSYS_OPT_PHY_LED_CONTROL */
1490 /* Get the media type of the fixed port, if recognised. */
1491 EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI
== EFX_PHY_MEDIA_XAUI
);
1492 EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4
== EFX_PHY_MEDIA_CX4
);
1493 EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4
== EFX_PHY_MEDIA_KX4
);
1494 EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP
== EFX_PHY_MEDIA_XFP
);
1495 EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS
== EFX_PHY_MEDIA_SFP_PLUS
);
1496 EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T
== EFX_PHY_MEDIA_BASE_T
);
1497 EFX_STATIC_ASSERT(MC_CMD_MEDIA_QSFP_PLUS
== EFX_PHY_MEDIA_QSFP_PLUS
);
1498 phy_media_type
= MCDI_OUT_DWORD(req
, GET_PHY_CFG_OUT_MEDIA_TYPE
);
1499 epp
->ep_fixed_port_type
= (efx_phy_media_type_t
)phy_media_type
;
1500 if (epp
->ep_fixed_port_type
>= EFX_PHY_MEDIA_NTYPES
)
1501 epp
->ep_fixed_port_type
= EFX_PHY_MEDIA_INVALID
;
1503 epp
->ep_phy_cap_mask
=
1504 MCDI_OUT_DWORD(req
, GET_PHY_CFG_OUT_SUPPORTED_CAP
);
1505 #if EFSYS_OPT_PHY_FLAGS
1506 encp
->enc_phy_flags_mask
= MCDI_OUT_DWORD(req
, GET_PHY_CFG_OUT_FLAGS
);
1507 #endif /* EFSYS_OPT_PHY_FLAGS */
1509 encp
->enc_port
= (uint8_t)MCDI_OUT_DWORD(req
, GET_PHY_CFG_OUT_PRT
);
1511 /* Populate internal state */
1512 encp
->enc_mcdi_mdio_channel
=
1513 (uint8_t)MCDI_OUT_DWORD(req
, GET_PHY_CFG_OUT_CHANNEL
);
1515 #if EFSYS_OPT_PHY_STATS
1516 encp
->enc_mcdi_phy_stat_mask
=
1517 MCDI_OUT_DWORD(req
, GET_PHY_CFG_OUT_STATS_MASK
);
1518 #endif /* EFSYS_OPT_PHY_STATS */
1521 encp
->enc_bist_mask
= 0;
1522 if (MCDI_OUT_DWORD_FIELD(req
, GET_PHY_CFG_OUT_FLAGS
,
1523 GET_PHY_CFG_OUT_BIST_CABLE_SHORT
))
1524 encp
->enc_bist_mask
|= (1 << EFX_BIST_TYPE_PHY_CABLE_SHORT
);
1525 if (MCDI_OUT_DWORD_FIELD(req
, GET_PHY_CFG_OUT_FLAGS
,
1526 GET_PHY_CFG_OUT_BIST_CABLE_LONG
))
1527 encp
->enc_bist_mask
|= (1 << EFX_BIST_TYPE_PHY_CABLE_LONG
);
1528 if (MCDI_OUT_DWORD_FIELD(req
, GET_PHY_CFG_OUT_FLAGS
,
1529 GET_PHY_CFG_OUT_BIST
))
1530 encp
->enc_bist_mask
|= (1 << EFX_BIST_TYPE_PHY_NORMAL
);
1531 #endif /* EFSYS_OPT_BIST */
1538 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1543 __checkReturn efx_rc_t
1544 efx_mcdi_firmware_update_supported(
1545 __in efx_nic_t
*enp
,
1546 __out boolean_t
*supportedp
)
1548 const efx_mcdi_ops_t
*emcop
= enp
->en_mcdi
.em_emcop
;
1551 if (emcop
!= NULL
) {
1552 if ((rc
= emcop
->emco_feature_supported(enp
,
1553 EFX_MCDI_FEATURE_FW_UPDATE
, supportedp
)) != 0)
1556 /* Earlier devices always supported updates */
1557 *supportedp
= B_TRUE
;
1563 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1568 __checkReturn efx_rc_t
1569 efx_mcdi_macaddr_change_supported(
1570 __in efx_nic_t
*enp
,
1571 __out boolean_t
*supportedp
)
1573 const efx_mcdi_ops_t
*emcop
= enp
->en_mcdi
.em_emcop
;
1576 if (emcop
!= NULL
) {
1577 if ((rc
= emcop
->emco_feature_supported(enp
,
1578 EFX_MCDI_FEATURE_MACADDR_CHANGE
, supportedp
)) != 0)
1581 /* Earlier devices always supported MAC changes */
1582 *supportedp
= B_TRUE
;
1588 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1593 __checkReturn efx_rc_t
1594 efx_mcdi_link_control_supported(
1595 __in efx_nic_t
*enp
,
1596 __out boolean_t
*supportedp
)
1598 const efx_mcdi_ops_t
*emcop
= enp
->en_mcdi
.em_emcop
;
1601 if (emcop
!= NULL
) {
1602 if ((rc
= emcop
->emco_feature_supported(enp
,
1603 EFX_MCDI_FEATURE_LINK_CONTROL
, supportedp
)) != 0)
1606 /* Earlier devices always supported link control */
1607 *supportedp
= B_TRUE
;
1613 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1618 __checkReturn efx_rc_t
1619 efx_mcdi_mac_spoofing_supported(
1620 __in efx_nic_t
*enp
,
1621 __out boolean_t
*supportedp
)
1623 const efx_mcdi_ops_t
*emcop
= enp
->en_mcdi
.em_emcop
;
1626 if (emcop
!= NULL
) {
1627 if ((rc
= emcop
->emco_feature_supported(enp
,
1628 EFX_MCDI_FEATURE_MAC_SPOOFING
, supportedp
)) != 0)
1631 /* Earlier devices always supported MAC spoofing */
1632 *supportedp
= B_TRUE
;
1638 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1645 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
1647 * Enter bist offline mode. This is a fw mode which puts the NIC into a state
1648 * where memory BIST tests can be run and not much else can interfere or happen.
1649 * A reboot is required to exit this mode.
1651 __checkReturn efx_rc_t
1652 efx_mcdi_bist_enable_offline(
1653 __in efx_nic_t
*enp
)
1658 EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_IN_LEN
== 0);
1659 EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_OUT_LEN
== 0);
1661 req
.emr_cmd
= MC_CMD_ENABLE_OFFLINE_BIST
;
1662 req
.emr_in_buf
= NULL
;
1663 req
.emr_in_length
= 0;
1664 req
.emr_out_buf
= NULL
;
1665 req
.emr_out_length
= 0;
1667 efx_mcdi_execute(enp
, &req
);
1669 if (req
.emr_rc
!= 0) {
1677 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1681 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
1683 __checkReturn efx_rc_t
1684 efx_mcdi_bist_start(
1685 __in efx_nic_t
*enp
,
1686 __in efx_bist_type_t type
)
1689 uint8_t payload
[MAX(MC_CMD_START_BIST_IN_LEN
,
1690 MC_CMD_START_BIST_OUT_LEN
)];
1693 (void) memset(payload
, 0, sizeof (payload
));
1694 req
.emr_cmd
= MC_CMD_START_BIST
;
1695 req
.emr_in_buf
= payload
;
1696 req
.emr_in_length
= MC_CMD_START_BIST_IN_LEN
;
1697 req
.emr_out_buf
= payload
;
1698 req
.emr_out_length
= MC_CMD_START_BIST_OUT_LEN
;
1701 case EFX_BIST_TYPE_PHY_NORMAL
:
1702 MCDI_IN_SET_DWORD(req
, START_BIST_IN_TYPE
, MC_CMD_PHY_BIST
);
1704 case EFX_BIST_TYPE_PHY_CABLE_SHORT
:
1705 MCDI_IN_SET_DWORD(req
, START_BIST_IN_TYPE
,
1706 MC_CMD_PHY_BIST_CABLE_SHORT
);
1708 case EFX_BIST_TYPE_PHY_CABLE_LONG
:
1709 MCDI_IN_SET_DWORD(req
, START_BIST_IN_TYPE
,
1710 MC_CMD_PHY_BIST_CABLE_LONG
);
1712 case EFX_BIST_TYPE_MC_MEM
:
1713 MCDI_IN_SET_DWORD(req
, START_BIST_IN_TYPE
,
1714 MC_CMD_MC_MEM_BIST
);
1716 case EFX_BIST_TYPE_SAT_MEM
:
1717 MCDI_IN_SET_DWORD(req
, START_BIST_IN_TYPE
,
1718 MC_CMD_PORT_MEM_BIST
);
1720 case EFX_BIST_TYPE_REG
:
1721 MCDI_IN_SET_DWORD(req
, START_BIST_IN_TYPE
,
1728 efx_mcdi_execute(enp
, &req
);
1730 if (req
.emr_rc
!= 0) {
1738 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1743 #endif /* EFSYS_OPT_BIST */
1746 /* Enable logging of some events (e.g. link state changes) */
1747 __checkReturn efx_rc_t
1749 __in efx_nic_t
*enp
)
1752 uint8_t payload
[MAX(MC_CMD_LOG_CTRL_IN_LEN
,
1753 MC_CMD_LOG_CTRL_OUT_LEN
)];
1756 (void) memset(payload
, 0, sizeof (payload
));
1757 req
.emr_cmd
= MC_CMD_LOG_CTRL
;
1758 req
.emr_in_buf
= payload
;
1759 req
.emr_in_length
= MC_CMD_LOG_CTRL_IN_LEN
;
1760 req
.emr_out_buf
= payload
;
1761 req
.emr_out_length
= MC_CMD_LOG_CTRL_OUT_LEN
;
1763 MCDI_IN_SET_DWORD(req
, LOG_CTRL_IN_LOG_DEST
,
1764 MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ
);
1765 MCDI_IN_SET_DWORD(req
, LOG_CTRL_IN_LOG_DEST_EVQ
, 0);
1767 efx_mcdi_execute(enp
, &req
);
1769 if (req
.emr_rc
!= 0) {
1777 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1783 #if EFSYS_OPT_MAC_STATS
1785 typedef enum efx_stats_action_e
{
1788 EFX_STATS_ENABLE_NOEVENTS
,
1789 EFX_STATS_ENABLE_EVENTS
,
1791 } efx_stats_action_t
;
1793 static __checkReturn efx_rc_t
1795 __in efx_nic_t
*enp
,
1796 __in_opt efsys_mem_t
*esmp
,
1797 __in efx_stats_action_t action
,
1798 __in
uint16_t period_ms
)
1801 uint8_t payload
[MAX(MC_CMD_MAC_STATS_IN_LEN
,
1802 MC_CMD_MAC_STATS_V2_OUT_DMA_LEN
)];
1803 int clear
= (action
== EFX_STATS_CLEAR
);
1804 int upload
= (action
== EFX_STATS_UPLOAD
);
1805 int enable
= (action
== EFX_STATS_ENABLE_NOEVENTS
);
1806 int events
= (action
== EFX_STATS_ENABLE_EVENTS
);
1807 int disable
= (action
== EFX_STATS_DISABLE
);
1810 (void) memset(payload
, 0, sizeof (payload
));
1811 req
.emr_cmd
= MC_CMD_MAC_STATS
;
1812 req
.emr_in_buf
= payload
;
1813 req
.emr_in_length
= MC_CMD_MAC_STATS_IN_LEN
;
1814 req
.emr_out_buf
= payload
;
1815 req
.emr_out_length
= MC_CMD_MAC_STATS_V2_OUT_DMA_LEN
;
1817 MCDI_IN_POPULATE_DWORD_6(req
, MAC_STATS_IN_CMD
,
1818 MAC_STATS_IN_DMA
, upload
,
1819 MAC_STATS_IN_CLEAR
, clear
,
1820 MAC_STATS_IN_PERIODIC_CHANGE
, enable
| events
| disable
,
1821 MAC_STATS_IN_PERIODIC_ENABLE
, enable
| events
,
1822 MAC_STATS_IN_PERIODIC_NOEVENT
, !events
,
1823 MAC_STATS_IN_PERIOD_MS
, (enable
| events
) ? period_ms
: 0);
1825 if (enable
|| events
|| upload
) {
1826 const efx_nic_cfg_t
*encp
= &enp
->en_nic_cfg
;
1829 /* Periodic stats or stats upload require a DMA buffer */
1835 if (encp
->enc_mac_stats_nstats
< MC_CMD_MAC_NSTATS
) {
1836 /* MAC stats count too small for legacy MAC stats */
1841 bytes
= encp
->enc_mac_stats_nstats
* sizeof (efx_qword_t
);
1843 if (EFSYS_MEM_SIZE(esmp
) < bytes
) {
1844 /* DMA buffer too small */
1849 MCDI_IN_SET_DWORD(req
, MAC_STATS_IN_DMA_ADDR_LO
,
1850 EFSYS_MEM_ADDR(esmp
) & 0xffffffff);
1851 MCDI_IN_SET_DWORD(req
, MAC_STATS_IN_DMA_ADDR_HI
,
1852 EFSYS_MEM_ADDR(esmp
) >> 32);
1853 MCDI_IN_SET_DWORD(req
, MAC_STATS_IN_DMA_LEN
, bytes
);
1857 * NOTE: Do not use EVB_PORT_ID_ASSIGNED when disabling periodic stats,
1858 * as this may fail (and leave periodic DMA enabled) if the
1859 * vadapter has already been deleted.
1861 MCDI_IN_SET_DWORD(req
, MAC_STATS_IN_PORT_ID
,
1862 (disable
? EVB_PORT_ID_NULL
: enp
->en_vport_id
));
1864 efx_mcdi_execute(enp
, &req
);
1866 if (req
.emr_rc
!= 0) {
1867 /* EF10: Expect ENOENT if no DMA queues are initialised */
1868 if ((req
.emr_rc
!= ENOENT
) ||
1869 (enp
->en_rx_qcount
+ enp
->en_tx_qcount
!= 0)) {
1884 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1889 __checkReturn efx_rc_t
1890 efx_mcdi_mac_stats_clear(
1891 __in efx_nic_t
*enp
)
1895 if ((rc
= efx_mcdi_mac_stats(enp
, NULL
, EFX_STATS_CLEAR
, 0)) != 0)
1901 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1906 __checkReturn efx_rc_t
1907 efx_mcdi_mac_stats_upload(
1908 __in efx_nic_t
*enp
,
1909 __in efsys_mem_t
*esmp
)
1914 * The MC DMAs aggregate statistics for our convenience, so we can
1915 * avoid having to pull the statistics buffer into the cache to
1916 * maintain cumulative statistics.
1918 if ((rc
= efx_mcdi_mac_stats(enp
, esmp
, EFX_STATS_UPLOAD
, 0)) != 0)
1924 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1929 __checkReturn efx_rc_t
1930 efx_mcdi_mac_stats_periodic(
1931 __in efx_nic_t
*enp
,
1932 __in efsys_mem_t
*esmp
,
1933 __in
uint16_t period_ms
,
1934 __in boolean_t events
)
1939 * The MC DMAs aggregate statistics for our convenience, so we can
1940 * avoid having to pull the statistics buffer into the cache to
1941 * maintain cumulative statistics.
1942 * Huntington uses a fixed 1sec period.
1943 * Medford uses a fixed 1sec period before v6.2.1.1033 firmware.
1946 rc
= efx_mcdi_mac_stats(enp
, NULL
, EFX_STATS_DISABLE
, 0);
1948 rc
= efx_mcdi_mac_stats(enp
, esmp
, EFX_STATS_ENABLE_EVENTS
,
1951 rc
= efx_mcdi_mac_stats(enp
, esmp
, EFX_STATS_ENABLE_NOEVENTS
,
1960 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1965 #endif /* EFSYS_OPT_MAC_STATS */
1967 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
1970 * This function returns the pf and vf number of a function. If it is a pf the
1971 * vf number is 0xffff. The vf number is the index of the vf on that
1972 * function. So if you have 3 vfs on pf 0 the 3 vfs will return (pf=0,vf=0),
1973 * (pf=0,vf=1), (pf=0,vf=2) aand the pf will return (pf=0, vf=0xffff).
1975 __checkReturn efx_rc_t
1976 efx_mcdi_get_function_info(
1977 __in efx_nic_t
*enp
,
1978 __out
uint32_t *pfp
,
1979 __out_opt
uint32_t *vfp
)
1982 uint8_t payload
[MAX(MC_CMD_GET_FUNCTION_INFO_IN_LEN
,
1983 MC_CMD_GET_FUNCTION_INFO_OUT_LEN
)];
1986 (void) memset(payload
, 0, sizeof (payload
));
1987 req
.emr_cmd
= MC_CMD_GET_FUNCTION_INFO
;
1988 req
.emr_in_buf
= payload
;
1989 req
.emr_in_length
= MC_CMD_GET_FUNCTION_INFO_IN_LEN
;
1990 req
.emr_out_buf
= payload
;
1991 req
.emr_out_length
= MC_CMD_GET_FUNCTION_INFO_OUT_LEN
;
1993 efx_mcdi_execute(enp
, &req
);
1995 if (req
.emr_rc
!= 0) {
2000 if (req
.emr_out_length_used
< MC_CMD_GET_FUNCTION_INFO_OUT_LEN
) {
2005 *pfp
= MCDI_OUT_DWORD(req
, GET_FUNCTION_INFO_OUT_PF
);
2007 *vfp
= MCDI_OUT_DWORD(req
, GET_FUNCTION_INFO_OUT_VF
);
2014 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
2019 __checkReturn efx_rc_t
2020 efx_mcdi_privilege_mask(
2021 __in efx_nic_t
*enp
,
2024 __out
uint32_t *maskp
)
2027 uint8_t payload
[MAX(MC_CMD_PRIVILEGE_MASK_IN_LEN
,
2028 MC_CMD_PRIVILEGE_MASK_OUT_LEN
)];
2031 (void) memset(payload
, 0, sizeof (payload
));
2032 req
.emr_cmd
= MC_CMD_PRIVILEGE_MASK
;
2033 req
.emr_in_buf
= payload
;
2034 req
.emr_in_length
= MC_CMD_PRIVILEGE_MASK_IN_LEN
;
2035 req
.emr_out_buf
= payload
;
2036 req
.emr_out_length
= MC_CMD_PRIVILEGE_MASK_OUT_LEN
;
2038 MCDI_IN_POPULATE_DWORD_2(req
, PRIVILEGE_MASK_IN_FUNCTION
,
2039 PRIVILEGE_MASK_IN_FUNCTION_PF
, pf
,
2040 PRIVILEGE_MASK_IN_FUNCTION_VF
, vf
);
2042 efx_mcdi_execute(enp
, &req
);
2044 if (req
.emr_rc
!= 0) {
2049 if (req
.emr_out_length_used
< MC_CMD_PRIVILEGE_MASK_OUT_LEN
) {
2054 *maskp
= MCDI_OUT_DWORD(req
, PRIVILEGE_MASK_OUT_OLD_MASK
);
2061 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
2066 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
2068 __checkReturn efx_rc_t
2069 efx_mcdi_set_workaround(
2070 __in efx_nic_t
*enp
,
2072 __in boolean_t enabled
,
2073 __out_opt
uint32_t *flagsp
)
2076 uint8_t payload
[MAX(MC_CMD_WORKAROUND_IN_LEN
,
2077 MC_CMD_WORKAROUND_EXT_OUT_LEN
)];
2080 (void) memset(payload
, 0, sizeof (payload
));
2081 req
.emr_cmd
= MC_CMD_WORKAROUND
;
2082 req
.emr_in_buf
= payload
;
2083 req
.emr_in_length
= MC_CMD_WORKAROUND_IN_LEN
;
2084 req
.emr_out_buf
= payload
;
2085 req
.emr_out_length
= MC_CMD_WORKAROUND_OUT_LEN
;
2087 MCDI_IN_SET_DWORD(req
, WORKAROUND_IN_TYPE
, type
);
2088 MCDI_IN_SET_DWORD(req
, WORKAROUND_IN_ENABLED
, enabled
? 1 : 0);
2090 efx_mcdi_execute_quiet(enp
, &req
);
2092 if (req
.emr_rc
!= 0) {
2097 if (flagsp
!= NULL
) {
2098 if (req
.emr_out_length_used
>= MC_CMD_WORKAROUND_EXT_OUT_LEN
)
2099 *flagsp
= MCDI_OUT_DWORD(req
, WORKAROUND_EXT_OUT_FLAGS
);
2107 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
2113 __checkReturn efx_rc_t
2114 efx_mcdi_get_workarounds(
2115 __in efx_nic_t
*enp
,
2116 __out_opt
uint32_t *implementedp
,
2117 __out_opt
uint32_t *enabledp
)
2120 uint8_t payload
[MC_CMD_GET_WORKAROUNDS_OUT_LEN
];
2123 (void) memset(payload
, 0, sizeof (payload
));
2124 req
.emr_cmd
= MC_CMD_GET_WORKAROUNDS
;
2125 req
.emr_in_buf
= NULL
;
2126 req
.emr_in_length
= 0;
2127 req
.emr_out_buf
= payload
;
2128 req
.emr_out_length
= MC_CMD_GET_WORKAROUNDS_OUT_LEN
;
2130 efx_mcdi_execute(enp
, &req
);
2132 if (req
.emr_rc
!= 0) {
2137 if (implementedp
!= NULL
) {
2139 MCDI_OUT_DWORD(req
, GET_WORKAROUNDS_OUT_IMPLEMENTED
);
2142 if (enabledp
!= NULL
) {
2143 *enabledp
= MCDI_OUT_DWORD(req
, GET_WORKAROUNDS_OUT_ENABLED
);
2149 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
2155 * Size of media information page in accordance with SFF-8472 and SFF-8436.
2156 * It is used in MCDI interface as well.
2158 #define EFX_PHY_MEDIA_INFO_PAGE_SIZE 0x80
2160 static __checkReturn efx_rc_t
2161 efx_mcdi_get_phy_media_info(
2162 __in efx_nic_t
*enp
,
2163 __in
uint32_t mcdi_page
,
2164 __in
uint8_t offset
,
2166 __out_bcount(len
) uint8_t *data
)
2169 uint8_t payload
[MAX(MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN
,
2170 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(
2171 EFX_PHY_MEDIA_INFO_PAGE_SIZE
))];
2174 EFSYS_ASSERT((uint32_t)offset
+ len
<= EFX_PHY_MEDIA_INFO_PAGE_SIZE
);
2176 (void) memset(payload
, 0, sizeof (payload
));
2177 req
.emr_cmd
= MC_CMD_GET_PHY_MEDIA_INFO
;
2178 req
.emr_in_buf
= payload
;
2179 req
.emr_in_length
= MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN
;
2180 req
.emr_out_buf
= payload
;
2181 req
.emr_out_length
=
2182 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE
);
2184 MCDI_IN_SET_DWORD(req
, GET_PHY_MEDIA_INFO_IN_PAGE
, mcdi_page
);
2186 efx_mcdi_execute(enp
, &req
);
2188 if (req
.emr_rc
!= 0) {
2193 if (req
.emr_out_length_used
!=
2194 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE
)) {
2199 if (MCDI_OUT_DWORD(req
, GET_PHY_MEDIA_INFO_OUT_DATALEN
) !=
2200 EFX_PHY_MEDIA_INFO_PAGE_SIZE
) {
2206 MCDI_OUT2(req
, uint8_t, GET_PHY_MEDIA_INFO_OUT_DATA
) + offset
,
2216 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
2222 * 2-wire device address of the base information in accordance with SFF-8472
2223 * Diagnostic Monitoring Interface for Optical Transceivers section
2224 * 4 Memory Organization.
2226 #define EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE 0xA0
2229 * 2-wire device address of the digital diagnostics monitoring interface
2230 * in accordance with SFF-8472 Diagnostic Monitoring Interface for Optical
2231 * Transceivers section 4 Memory Organization.
2233 #define EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM 0xA2
2236 * Hard wired 2-wire device address for QSFP+ in accordance with SFF-8436
2237 * QSFP+ 10 Gbs 4X PLUGGABLE TRANSCEIVER section 7.4 Device Addressing and
2240 #define EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP 0xA0
2242 __checkReturn efx_rc_t
2243 efx_mcdi_phy_module_get_info(
2244 __in efx_nic_t
*enp
,
2245 __in
uint8_t dev_addr
,
2246 __in
uint8_t offset
,
2248 __out_bcount(len
) uint8_t *data
)
2250 efx_port_t
*epp
= &(enp
->en_port
);
2252 uint32_t mcdi_lower_page
;
2253 uint32_t mcdi_upper_page
;
2255 EFSYS_ASSERT3U(enp
->en_mod_flags
, &, EFX_MOD_PROBE
);
2258 * Map device address to MC_CMD_GET_PHY_MEDIA_INFO pages.
2259 * Offset plus length interface allows to access page 0 only.
2260 * I.e. non-zero upper pages are not accessible.
2261 * See SFF-8472 section 4 Memory Organization and SFF-8436 section 7.6
2262 * QSFP+ Memory Map for details on how information is structured
2265 switch (epp
->ep_fixed_port_type
) {
2266 case EFX_PHY_MEDIA_SFP_PLUS
:
2268 * In accordance with SFF-8472 Diagnostic Monitoring
2269 * Interface for Optical Transceivers section 4 Memory
2270 * Organization two 2-wire addresses are defined.
2273 /* Base information */
2274 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE
:
2276 * MCDI page 0 should be used to access lower
2277 * page 0 (0x00 - 0x7f) at the device address 0xA0.
2279 mcdi_lower_page
= 0;
2281 * MCDI page 1 should be used to access upper
2282 * page 0 (0x80 - 0xff) at the device address 0xA0.
2284 mcdi_upper_page
= 1;
2287 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM
:
2289 * MCDI page 2 should be used to access lower
2290 * page 0 (0x00 - 0x7f) at the device address 0xA2.
2292 mcdi_lower_page
= 2;
2294 * MCDI page 3 should be used to access upper
2295 * page 0 (0x80 - 0xff) at the device address 0xA2.
2297 mcdi_upper_page
= 3;
2304 case EFX_PHY_MEDIA_QSFP_PLUS
:
2306 case EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP
:
2308 * MCDI page -1 should be used to access lower page 0
2311 mcdi_lower_page
= (uint32_t)-1;
2313 * MCDI page 0 should be used to access upper page 0
2316 mcdi_upper_page
= 0;
2328 if (offset
< EFX_PHY_MEDIA_INFO_PAGE_SIZE
) {
2330 MIN(len
, EFX_PHY_MEDIA_INFO_PAGE_SIZE
- offset
);
2332 rc
= efx_mcdi_get_phy_media_info(enp
,
2333 mcdi_lower_page
, offset
, read_len
, data
);
2342 offset
-= EFX_PHY_MEDIA_INFO_PAGE_SIZE
;
2346 EFSYS_ASSERT3U(len
, <=, EFX_PHY_MEDIA_INFO_PAGE_SIZE
);
2347 EFSYS_ASSERT3U(offset
, <, EFX_PHY_MEDIA_INFO_PAGE_SIZE
);
2349 rc
= efx_mcdi_get_phy_media_info(enp
,
2350 mcdi_upper_page
, offset
, len
, data
);
2362 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
2367 #endif /* EFSYS_OPT_MCDI */