net/sfc/base: add Medford2 support to NIC module
[dpdk.git] / drivers / net / sfc / base / efx_mcdi.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright (c) 2008-2018 Solarflare Communications Inc.
4  * All rights reserved.
5  */
6
7 #include "efx.h"
8 #include "efx_impl.h"
9
10 #if EFSYS_OPT_MCDI
11
12 /*
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.
18  *
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.
23  *
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.
26  *
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.
29  */
30
31
32
33 #if EFSYS_OPT_SIENA
34
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 */
44 };
45
46 #endif  /* EFSYS_OPT_SIENA */
47
48 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
49
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 */
59 };
60
61 #endif  /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
62
63
64
65         __checkReturn   efx_rc_t
66 efx_mcdi_init(
67         __in            efx_nic_t *enp,
68         __in            const efx_mcdi_transport_t *emtp)
69 {
70         const efx_mcdi_ops_t *emcop;
71         efx_rc_t rc;
72
73         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
74         EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
75
76         switch (enp->en_family) {
77 #if EFSYS_OPT_SIENA
78         case EFX_FAMILY_SIENA:
79                 emcop = &__efx_mcdi_siena_ops;
80                 break;
81 #endif  /* EFSYS_OPT_SIENA */
82
83 #if EFSYS_OPT_HUNTINGTON
84         case EFX_FAMILY_HUNTINGTON:
85                 emcop = &__efx_mcdi_ef10_ops;
86                 break;
87 #endif  /* EFSYS_OPT_HUNTINGTON */
88
89 #if EFSYS_OPT_MEDFORD
90         case EFX_FAMILY_MEDFORD:
91                 emcop = &__efx_mcdi_ef10_ops;
92                 break;
93 #endif  /* EFSYS_OPT_MEDFORD */
94
95         default:
96                 EFSYS_ASSERT(0);
97                 rc = ENOTSUP;
98                 goto fail1;
99         }
100
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) {
104                         rc = EINVAL;
105                         goto fail2;
106                 }
107         }
108         enp->en_mcdi.em_emtp = emtp;
109
110         if (emcop != NULL && emcop->emco_init != NULL) {
111                 if ((rc = emcop->emco_init(enp, emtp)) != 0)
112                         goto fail3;
113         }
114
115         enp->en_mcdi.em_emcop = emcop;
116         enp->en_mod_flags |= EFX_MOD_MCDI;
117
118         return (0);
119
120 fail3:
121         EFSYS_PROBE(fail3);
122 fail2:
123         EFSYS_PROBE(fail2);
124 fail1:
125         EFSYS_PROBE1(fail1, efx_rc_t, rc);
126
127         enp->en_mcdi.em_emcop = NULL;
128         enp->en_mcdi.em_emtp = NULL;
129         enp->en_mod_flags &= ~EFX_MOD_MCDI;
130
131         return (rc);
132 }
133
134                         void
135 efx_mcdi_fini(
136         __in            efx_nic_t *enp)
137 {
138         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
139         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
140
141         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
142         EFSYS_ASSERT3U(enp->en_mod_flags, ==, EFX_MOD_MCDI);
143
144         if (emcop != NULL && emcop->emco_fini != NULL)
145                 emcop->emco_fini(enp);
146
147         emip->emi_port = 0;
148         emip->emi_aborted = 0;
149
150         enp->en_mcdi.em_emcop = NULL;
151         enp->en_mod_flags &= ~EFX_MOD_MCDI;
152 }
153
154                         void
155 efx_mcdi_new_epoch(
156         __in            efx_nic_t *enp)
157 {
158         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
159         efsys_lock_state_t state;
160
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);
165 }
166
167 static                  void
168 efx_mcdi_send_request(
169         __in            efx_nic_t *enp,
170         __in            void *hdrp,
171         __in            size_t hdr_len,
172         __in            void *sdup,
173         __in            size_t sdu_len)
174 {
175         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
176
177         emcop->emco_send_request(enp, hdrp, hdr_len, sdup, sdu_len);
178 }
179
180 static                  efx_rc_t
181 efx_mcdi_poll_reboot(
182         __in            efx_nic_t *enp)
183 {
184         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
185         efx_rc_t rc;
186
187         rc = emcop->emco_poll_reboot(enp);
188         return (rc);
189 }
190
191 static                  boolean_t
192 efx_mcdi_poll_response(
193         __in            efx_nic_t *enp)
194 {
195         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
196         boolean_t available;
197
198         available = emcop->emco_poll_response(enp);
199         return (available);
200 }
201
202 static                  void
203 efx_mcdi_read_response(
204         __in            efx_nic_t *enp,
205         __out           void *bufferp,
206         __in            size_t offset,
207         __in            size_t length)
208 {
209         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
210
211         emcop->emco_read_response(enp, bufferp, offset, length);
212 }
213
214                         void
215 efx_mcdi_request_start(
216         __in            efx_nic_t *enp,
217         __in            efx_mcdi_req_t *emrp,
218         __in            boolean_t ev_cpl)
219 {
220 #if EFSYS_OPT_MCDI_LOGGING
221         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
222 #endif
223         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
224         efx_dword_t hdr[2];
225         size_t hdr_len;
226         unsigned int max_version;
227         unsigned int seq;
228         unsigned int xflags;
229         boolean_t new_epoch;
230         efsys_lock_state_t state;
231
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);
235
236         /*
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
246          * en_eslp lock.
247          */
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);
257
258         xflags = 0;
259         if (ev_cpl)
260                 xflags |= MCDI_HEADER_XFLAGS_EVREQ;
261
262         /*
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.
266          */
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);
282
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);
286         } else {
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);
298         }
299
300 #if EFSYS_OPT_MCDI_LOGGING
301         if (emtp->emt_logger != NULL) {
302                 emtp->emt_logger(emtp->emt_context, EFX_LOG_MCDI_REQUEST,
303                     &hdr[0], hdr_len,
304                     emrp->emr_in_buf, emrp->emr_in_length);
305         }
306 #endif /* EFSYS_OPT_MCDI_LOGGING */
307
308         efx_mcdi_send_request(enp, &hdr[0], hdr_len,
309             emrp->emr_in_buf, emrp->emr_in_length);
310 }
311
312
313 static                  void
314 efx_mcdi_read_response_header(
315         __in            efx_nic_t *enp,
316         __inout         efx_mcdi_req_t *emrp)
317 {
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);
322         efx_dword_t hdr[2];
323         unsigned int hdr_len;
324         unsigned int data_len;
325         unsigned int seq;
326         unsigned int cmd;
327         unsigned int error;
328         efx_rc_t rc;
329
330         EFSYS_ASSERT(emrp != NULL);
331
332         efx_mcdi_read_response(enp, &hdr[0], 0, sizeof (hdr[0]));
333         hdr_len = sizeof (hdr[0]);
334
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);
338
339         if (cmd != MC_CMD_V2_EXTN) {
340                 data_len = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_DATALEN);
341         } else {
342                 efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1]));
343                 hdr_len += sizeof (hdr[1]);
344
345                 cmd = EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_EXTENDED_CMD);
346                 data_len =
347                     EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
348         }
349
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);
354                 rc = EIO;
355                 goto fail1;
356         }
357         if ((cmd != emrp->emr_cmd) ||
358             (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
359                 /* Response is for a different request */
360                 rc = EIO;
361                 goto fail2;
362         }
363         if (error) {
364                 efx_dword_t err[2];
365                 unsigned int err_len = MIN(data_len, sizeof (err));
366                 int err_code = MC_CMD_ERR_EPROTO;
367                 int err_arg = 0;
368
369                 /* Read error code (and arg num for MCDI v2 commands) */
370                 efx_mcdi_read_response(enp, &err, hdr_len, err_len);
371
372                 if (err_len >= (MC_CMD_ERR_CODE_OFST + sizeof (efx_dword_t)))
373                         err_code = EFX_DWORD_FIELD(err[0], EFX_DWORD_0);
374 #ifdef WITH_MCDI_V2
375                 if (err_len >= (MC_CMD_ERR_ARG_OFST + sizeof (efx_dword_t)))
376                         err_arg = EFX_DWORD_FIELD(err[1], EFX_DWORD_0);
377 #endif
378                 emrp->emr_err_code = err_code;
379                 emrp->emr_err_arg = err_arg;
380
381 #if EFSYS_OPT_MCDI_PROXY_AUTH
382                 if ((err_code == MC_CMD_ERR_PROXY_PENDING) &&
383                     (err_len == sizeof (err))) {
384                         /*
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.
388                          *
389                          * Save the authorization request handle. The client
390                          * must wait for a PROXY_RESPONSE event, or timeout.
391                          */
392                         emrp->emr_proxy_handle = err_arg;
393                 }
394 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
395
396 #if EFSYS_OPT_MCDI_LOGGING
397                 if (emtp->emt_logger != NULL) {
398                         emtp->emt_logger(emtp->emt_context,
399                             EFX_LOG_MCDI_RESPONSE,
400                             &hdr[0], hdr_len,
401                             &err[0], err_len);
402                 }
403 #endif /* EFSYS_OPT_MCDI_LOGGING */
404
405                 if (!emrp->emr_quiet) {
406                         EFSYS_PROBE3(mcdi_err_arg, int, emrp->emr_cmd,
407                             int, err_code, int, err_arg);
408                 }
409
410                 rc = efx_mcdi_request_errcode(err_code);
411                 goto fail3;
412         }
413
414         emrp->emr_rc = 0;
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 */
419         return;
420
421 fail3:
422 fail2:
423 fail1:
424         emrp->emr_rc = rc;
425         emrp->emr_out_length_used = 0;
426 }
427
428 static                  void
429 efx_mcdi_finish_response(
430         __in            efx_nic_t *enp,
431         __in            efx_mcdi_req_t *emrp)
432 {
433 #if EFSYS_OPT_MCDI_LOGGING
434         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
435 #endif /* EFSYS_OPT_MCDI_LOGGING */
436         efx_dword_t hdr[2];
437         unsigned int hdr_len;
438         size_t bytes;
439
440         if (emrp->emr_out_buf == NULL)
441                 return;
442
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) {
447                 /*
448                  * Read the actual payload length. The length given in the event
449                  * is only correct for responses with the V1 format.
450                  */
451                 efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1]));
452                 hdr_len += sizeof (hdr[1]);
453
454                 emrp->emr_out_length_used = EFX_DWORD_FIELD(hdr[1],
455                                             MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
456         }
457
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);
461
462 #if EFSYS_OPT_MCDI_LOGGING
463         if (emtp->emt_logger != NULL) {
464                 emtp->emt_logger(emtp->emt_context,
465                     EFX_LOG_MCDI_RESPONSE,
466                     &hdr[0], hdr_len,
467                     emrp->emr_out_buf, bytes);
468         }
469 #endif /* EFSYS_OPT_MCDI_LOGGING */
470 }
471
472
473         __checkReturn   boolean_t
474 efx_mcdi_request_poll(
475         __in            efx_nic_t *enp)
476 {
477         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
478         efx_mcdi_req_t *emrp;
479         efsys_lock_state_t state;
480         efx_rc_t rc;
481
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);
485
486         /* Serialise against post-watchdog efx_mcdi_ev* */
487         EFSYS_LOCK(enp->en_eslp, state);
488
489         EFSYS_ASSERT(emip->emi_pending_req != NULL);
490         EFSYS_ASSERT(!emip->emi_ev_cpl);
491         emrp = emip->emi_pending_req;
492
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);
498
499                         /* Reboot/Assertion */
500                         if (rc == EIO || rc == EINTR)
501                                 efx_mcdi_raise_exception(enp, emrp, rc);
502
503                         goto fail1;
504                 }
505         }
506
507         /* Check if a response is available */
508         if (efx_mcdi_poll_response(enp) == B_FALSE) {
509                 EFSYS_UNLOCK(enp->en_eslp, state);
510                 return (B_FALSE);
511         }
512
513         /* Read the response header */
514         efx_mcdi_read_response_header(enp, emrp);
515
516         /* Request complete */
517         emip->emi_pending_req = NULL;
518
519         /* Ensure stale MCDI requests fail after an MC reboot. */
520         emip->emi_new_epoch = B_FALSE;
521
522         EFSYS_UNLOCK(enp->en_eslp, state);
523
524         if ((rc = emrp->emr_rc) != 0)
525                 goto fail2;
526
527         efx_mcdi_finish_response(enp, emrp);
528         return (B_TRUE);
529
530 fail2:
531         if (!emrp->emr_quiet)
532                 EFSYS_PROBE(fail2);
533 fail1:
534         if (!emrp->emr_quiet)
535                 EFSYS_PROBE1(fail1, efx_rc_t, rc);
536
537         return (B_TRUE);
538 }
539
540         __checkReturn   boolean_t
541 efx_mcdi_request_abort(
542         __in            efx_nic_t *enp)
543 {
544         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
545         efx_mcdi_req_t *emrp;
546         boolean_t aborted;
547         efsys_lock_state_t state;
548
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);
552
553         /*
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.
559          */
560         EFSYS_LOCK(enp->en_eslp, state);
561         emrp = emip->emi_pending_req;
562         aborted = (emrp != NULL);
563         if (aborted) {
564                 emip->emi_pending_req = NULL;
565
566                 /* Error the request */
567                 emrp->emr_out_length_used = 0;
568                 emrp->emr_rc = ETIMEDOUT;
569
570                 /* Provide a credit for seqno/emr_pending_req mismatches */
571                 if (emip->emi_ev_cpl)
572                         ++emip->emi_aborted;
573
574                 /*
575                  * The upper layer has called us, so we don't
576                  * need to complete the request.
577                  */
578         }
579         EFSYS_UNLOCK(enp->en_eslp, state);
580
581         return (aborted);
582 }
583
584                         void
585 efx_mcdi_get_timeout(
586         __in            efx_nic_t *enp,
587         __in            efx_mcdi_req_t *emrp,
588         __out           uint32_t *timeoutp)
589 {
590         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
591
592         emcop->emco_get_timeout(enp, emrp, timeoutp);
593 }
594
595         __checkReturn   efx_rc_t
596 efx_mcdi_request_errcode(
597         __in            unsigned int err)
598 {
599
600         switch (err) {
601                 /* MCDI v1 */
602         case MC_CMD_ERR_EPERM:
603                 return (EACCES);
604         case MC_CMD_ERR_ENOENT:
605                 return (ENOENT);
606         case MC_CMD_ERR_EINTR:
607                 return (EINTR);
608         case MC_CMD_ERR_EACCES:
609                 return (EACCES);
610         case MC_CMD_ERR_EBUSY:
611                 return (EBUSY);
612         case MC_CMD_ERR_EINVAL:
613                 return (EINVAL);
614         case MC_CMD_ERR_EDEADLK:
615                 return (EDEADLK);
616         case MC_CMD_ERR_ENOSYS:
617                 return (ENOTSUP);
618         case MC_CMD_ERR_ETIME:
619                 return (ETIMEDOUT);
620         case MC_CMD_ERR_ENOTSUP:
621                 return (ENOTSUP);
622         case MC_CMD_ERR_EALREADY:
623                 return (EALREADY);
624
625                 /* MCDI v2 */
626         case MC_CMD_ERR_EEXIST:
627                 return (EEXIST);
628 #ifdef MC_CMD_ERR_EAGAIN
629         case MC_CMD_ERR_EAGAIN:
630                 return (EAGAIN);
631 #endif
632 #ifdef MC_CMD_ERR_ENOSPC
633         case MC_CMD_ERR_ENOSPC:
634                 return (ENOSPC);
635 #endif
636         case MC_CMD_ERR_ERANGE:
637                 return (ERANGE);
638
639         case MC_CMD_ERR_ALLOC_FAIL:
640                 return (ENOMEM);
641         case MC_CMD_ERR_NO_VADAPTOR:
642                 return (ENOENT);
643         case MC_CMD_ERR_NO_EVB_PORT:
644                 return (ENOENT);
645         case MC_CMD_ERR_NO_VSWITCH:
646                 return (ENODEV);
647         case MC_CMD_ERR_VLAN_LIMIT:
648                 return (EINVAL);
649         case MC_CMD_ERR_BAD_PCI_FUNC:
650                 return (ENODEV);
651         case MC_CMD_ERR_BAD_VLAN_MODE:
652                 return (EINVAL);
653         case MC_CMD_ERR_BAD_VSWITCH_TYPE:
654                 return (EINVAL);
655         case MC_CMD_ERR_BAD_VPORT_TYPE:
656                 return (EINVAL);
657         case MC_CMD_ERR_MAC_EXIST:
658                 return (EEXIST);
659
660         case MC_CMD_ERR_PROXY_PENDING:
661                 return (EAGAIN);
662
663         default:
664                 EFSYS_PROBE1(mc_pcol_error, int, err);
665                 return (EIO);
666         }
667 }
668
669                         void
670 efx_mcdi_raise_exception(
671         __in            efx_nic_t *enp,
672         __in_opt        efx_mcdi_req_t *emrp,
673         __in            int rc)
674 {
675         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
676         efx_mcdi_exception_t exception;
677
678         /* Reboot or Assertion failure only */
679         EFSYS_ASSERT(rc == EIO || rc == EINTR);
680
681         /*
682          * If MC_CMD_REBOOT causes a reboot (dependent on parameters),
683          * then the EIO is not worthy of an exception.
684          */
685         if (emrp != NULL && emrp->emr_cmd == MC_CMD_REBOOT && rc == EIO)
686                 return;
687
688         exception = (rc == EIO)
689                 ? EFX_MCDI_EXCEPTION_MC_REBOOT
690                 : EFX_MCDI_EXCEPTION_MC_BADASSERT;
691
692         emtp->emt_exception(emtp->emt_context, exception);
693 }
694
695                         void
696 efx_mcdi_execute(
697         __in            efx_nic_t *enp,
698         __inout         efx_mcdi_req_t *emrp)
699 {
700         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
701
702         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
703         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
704
705         emrp->emr_quiet = B_FALSE;
706         emtp->emt_execute(emtp->emt_context, emrp);
707 }
708
709                         void
710 efx_mcdi_execute_quiet(
711         __in            efx_nic_t *enp,
712         __inout         efx_mcdi_req_t *emrp)
713 {
714         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
715
716         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
717         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
718
719         emrp->emr_quiet = B_TRUE;
720         emtp->emt_execute(emtp->emt_context, emrp);
721 }
722
723                         void
724 efx_mcdi_ev_cpl(
725         __in            efx_nic_t *enp,
726         __in            unsigned int seq,
727         __in            unsigned int outlen,
728         __in            int errcode)
729 {
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;
734
735         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
736         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
737
738         /*
739          * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start()
740          * when we're completing an aborted request.
741          */
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)
747                         --emip->emi_aborted;
748                 EFSYS_UNLOCK(enp->en_eslp, state);
749                 return;
750         }
751
752         emrp = emip->emi_pending_req;
753         emip->emi_pending_req = NULL;
754         EFSYS_UNLOCK(enp->en_eslp, state);
755
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);
759         } else {
760                 if (errcode != 0) {
761                         if (!emrp->emr_quiet) {
762                                 EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd,
763                                     int, errcode);
764                         }
765                         emrp->emr_out_length_used = 0;
766                         emrp->emr_rc = efx_mcdi_request_errcode(errcode);
767                 } else {
768                         emrp->emr_out_length_used = outlen;
769                         emrp->emr_rc = 0;
770                 }
771         }
772         if (emrp->emr_rc == 0)
773                 efx_mcdi_finish_response(enp, emrp);
774
775         emtp->emt_ev_cpl(emtp->emt_context);
776 }
777
778 #if EFSYS_OPT_MCDI_PROXY_AUTH
779
780         __checkReturn   efx_rc_t
781 efx_mcdi_get_proxy_handle(
782         __in            efx_nic_t *enp,
783         __in            efx_mcdi_req_t *emrp,
784         __out           uint32_t *handlep)
785 {
786         efx_rc_t rc;
787
788         _NOTE(ARGUNUSED(enp))
789
790         /*
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.
794          */
795         if ((emrp == NULL) || (handlep == NULL)) {
796                 rc = EINVAL;
797                 goto fail1;
798         }
799         if ((emrp->emr_rc != 0) &&
800             (emrp->emr_err_code == MC_CMD_ERR_PROXY_PENDING)) {
801                 *handlep = emrp->emr_proxy_handle;
802                 rc = 0;
803         } else {
804                 *handlep = 0;
805                 rc = ENOENT;
806         }
807         return (rc);
808
809 fail1:
810         EFSYS_PROBE1(fail1, efx_rc_t, rc);
811         return (rc);
812 }
813
814                         void
815 efx_mcdi_ev_proxy_response(
816         __in            efx_nic_t *enp,
817         __in            unsigned int handle,
818         __in            unsigned int status)
819 {
820         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
821         efx_rc_t rc;
822
823         /*
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.
829          */
830         rc = (status == 0) ? 0 : efx_mcdi_request_errcode(status);
831
832         emtp->emt_ev_proxy_response(emtp->emt_context, handle, rc);
833 }
834 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
835
836                         void
837 efx_mcdi_ev_death(
838         __in            efx_nic_t *enp,
839         __in            int rc)
840 {
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;
844         boolean_t ev_cpl;
845         efsys_lock_state_t state;
846
847         /*
848          * The MCDI request (if there is one) has been terminated, either
849          * by a BADASSERT or REBOOT event.
850          *
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.
855          *
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.
859          */
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;
865
866                 emrp->emr_out_length_used = 0;
867                 emrp->emr_rc = rc;
868                 ++emip->emi_aborted;
869         }
870
871         /*
872          * Since we're running in parallel with a request, consume the
873          * status word before dropping the lock.
874          */
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;
879         }
880
881         EFSYS_UNLOCK(enp->en_eslp, state);
882
883         efx_mcdi_raise_exception(enp, emrp, rc);
884
885         if (emrp != NULL && ev_cpl)
886                 emtp->emt_ev_cpl(emtp->emt_context);
887 }
888
889         __checkReturn           efx_rc_t
890 efx_mcdi_version(
891         __in                    efx_nic_t *enp,
892         __out_ecount_opt(4)     uint16_t versionp[4],
893         __out_opt               uint32_t *buildp,
894         __out_opt               efx_mcdi_boot_t *statusp)
895 {
896         efx_mcdi_req_t req;
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;
902         uint16_t version[4];
903         uint32_t build;
904         efx_mcdi_boot_t status;
905         efx_rc_t rc;
906
907         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
908
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;
915
916         efx_mcdi_execute(enp, &req);
917
918         if (req.emr_rc != 0) {
919                 rc = req.emr_rc;
920                 goto fail1;
921         }
922
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);
927
928                 goto version;
929         }
930
931         if (req.emr_out_length_used < MC_CMD_GET_VERSION_OUT_LEN) {
932                 rc = EMSGSIZE;
933                 goto fail2;
934         }
935
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);
942
943 version:
944         /* The bootrom doesn't understand BOOT_STATUS */
945         if (MC_FW_VERSION_IS_BOOTLOADER(build)) {
946                 status = EFX_MCDI_BOOT_ROM;
947                 goto out;
948         }
949
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;
956
957         efx_mcdi_execute_quiet(enp, &req);
958
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;
963                 build = 0;
964                 goto out;
965         }
966
967         if (req.emr_rc != 0) {
968                 rc = req.emr_rc;
969                 goto fail3;
970         }
971
972         if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) {
973                 rc = EMSGSIZE;
974                 goto fail4;
975         }
976
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;
980         else
981                 status = EFX_MCDI_BOOT_SECONDARY;
982
983 out:
984         if (versionp != NULL)
985                 memcpy(versionp, version, sizeof (version));
986         if (buildp != NULL)
987                 *buildp = build;
988         if (statusp != NULL)
989                 *statusp = status;
990
991         return (0);
992
993 fail4:
994         EFSYS_PROBE(fail4);
995 fail3:
996         EFSYS_PROBE(fail3);
997 fail2:
998         EFSYS_PROBE(fail2);
999 fail1:
1000         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1001
1002         return (rc);
1003 }
1004
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)
1013 {
1014         efx_mcdi_req_t req;
1015         uint8_t payload[MAX(MC_CMD_GET_CAPABILITIES_IN_LEN,
1016                             MC_CMD_GET_CAPABILITIES_V2_OUT_LEN)];
1017         boolean_t v2_capable;
1018         efx_rc_t rc;
1019
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;
1026
1027         efx_mcdi_execute_quiet(enp, &req);
1028
1029         if (req.emr_rc != 0) {
1030                 rc = req.emr_rc;
1031                 goto fail1;
1032         }
1033
1034         if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_OUT_LEN) {
1035                 rc = EMSGSIZE;
1036                 goto fail2;
1037         }
1038
1039         if (flagsp != NULL)
1040                 *flagsp = MCDI_OUT_DWORD(req, GET_CAPABILITIES_OUT_FLAGS1);
1041
1042         if (rx_dpcpu_fw_idp != NULL)
1043                 *rx_dpcpu_fw_idp = MCDI_OUT_WORD(req,
1044                                         GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID);
1045
1046         if (tx_dpcpu_fw_idp != NULL)
1047                 *tx_dpcpu_fw_idp = MCDI_OUT_WORD(req,
1048                                         GET_CAPABILITIES_OUT_TX_DPCPU_FW_ID);
1049
1050         if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_V2_OUT_LEN)
1051                 v2_capable = B_FALSE;
1052         else
1053                 v2_capable = B_TRUE;
1054
1055         if (flags2p != NULL) {
1056                 *flags2p = (v2_capable) ?
1057                         MCDI_OUT_DWORD(req, GET_CAPABILITIES_V2_OUT_FLAGS2) :
1058                         0;
1059         }
1060
1061         if (tso2ncp != NULL) {
1062                 *tso2ncp = (v2_capable) ?
1063                         MCDI_OUT_WORD(req,
1064                                 GET_CAPABILITIES_V2_OUT_TX_TSO_V2_N_CONTEXTS) :
1065                         0;
1066         }
1067
1068         return (0);
1069
1070 fail2:
1071         EFSYS_PROBE(fail2);
1072 fail1:
1073         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1074
1075         return (rc);
1076 }
1077
1078 static  __checkReturn   efx_rc_t
1079 efx_mcdi_do_reboot(
1080         __in            efx_nic_t *enp,
1081         __in            boolean_t after_assertion)
1082 {
1083         uint8_t payload[MAX(MC_CMD_REBOOT_IN_LEN, MC_CMD_REBOOT_OUT_LEN)];
1084         efx_mcdi_req_t req;
1085         efx_rc_t rc;
1086
1087         /*
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.
1093          */
1094         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1095
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;
1102
1103         MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS,
1104             (after_assertion ? MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION : 0));
1105
1106         efx_mcdi_execute_quiet(enp, &req);
1107
1108         if (req.emr_rc == EACCES) {
1109                 /* Unprivileged functions cannot reboot the MC. */
1110                 goto out;
1111         }
1112
1113         /* A successful reboot request returns EIO. */
1114         if (req.emr_rc != 0 && req.emr_rc != EIO) {
1115                 rc = req.emr_rc;
1116                 goto fail1;
1117         }
1118
1119 out:
1120         return (0);
1121
1122 fail1:
1123         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1124
1125         return (rc);
1126 }
1127
1128         __checkReturn   efx_rc_t
1129 efx_mcdi_reboot(
1130         __in            efx_nic_t *enp)
1131 {
1132         return (efx_mcdi_do_reboot(enp, B_FALSE));
1133 }
1134
1135         __checkReturn   efx_rc_t
1136 efx_mcdi_exit_assertion_handler(
1137         __in            efx_nic_t *enp)
1138 {
1139         return (efx_mcdi_do_reboot(enp, B_TRUE));
1140 }
1141
1142         __checkReturn   efx_rc_t
1143 efx_mcdi_read_assertion(
1144         __in            efx_nic_t *enp)
1145 {
1146         efx_mcdi_req_t req;
1147         uint8_t payload[MAX(MC_CMD_GET_ASSERTS_IN_LEN,
1148                             MC_CMD_GET_ASSERTS_OUT_LEN)];
1149         const char *reason;
1150         unsigned int flags;
1151         unsigned int index;
1152         unsigned int ofst;
1153         int retry;
1154         efx_rc_t rc;
1155
1156         /*
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().
1160          *
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.
1166          */
1167         retry = 2;
1168         do {
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;
1175
1176                 MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1);
1177                 efx_mcdi_execute_quiet(enp, &req);
1178
1179         } while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0);
1180
1181         if (req.emr_rc != 0) {
1182                 if (req.emr_rc == EACCES) {
1183                         /* Unprivileged functions cannot clear assertions. */
1184                         goto out;
1185                 }
1186                 rc = req.emr_rc;
1187                 goto fail1;
1188         }
1189
1190         if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) {
1191                 rc = EMSGSIZE;
1192                 goto fail2;
1193         }
1194
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)
1198                 return (0);
1199
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)
1205                 ? "watchdog reset"
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),
1212             unsigned int,
1213             MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS));
1214
1215         /* Print out the registers (r1 ... r31) */
1216         ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST;
1217         for (index = 1;
1218                 index < 1 + MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM;
1219                 index++) {
1220                 EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int,
1221                             EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst),
1222                                             EFX_DWORD_0));
1223                 ofst += sizeof (efx_dword_t);
1224         }
1225         EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN);
1226
1227 out:
1228         return (0);
1229
1230 fail2:
1231         EFSYS_PROBE(fail2);
1232 fail1:
1233         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1234
1235         return (rc);
1236 }
1237
1238
1239 /*
1240  * Internal routines for for specific MCDI requests.
1241  */
1242
1243         __checkReturn   efx_rc_t
1244 efx_mcdi_drv_attach(
1245         __in            efx_nic_t *enp,
1246         __in            boolean_t attach)
1247 {
1248         efx_mcdi_req_t req;
1249         uint8_t payload[MAX(MC_CMD_DRV_ATTACH_IN_LEN,
1250                             MC_CMD_DRV_ATTACH_EXT_OUT_LEN)];
1251         efx_rc_t rc;
1252
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;
1259
1260         /*
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.
1264          */
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);
1268
1269         efx_mcdi_execute(enp, &req);
1270
1271         if (req.emr_rc != 0) {
1272                 rc = req.emr_rc;
1273                 goto fail1;
1274         }
1275
1276         if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) {
1277                 rc = EMSGSIZE;
1278                 goto fail2;
1279         }
1280
1281         return (0);
1282
1283 fail2:
1284         EFSYS_PROBE(fail2);
1285 fail1:
1286         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1287
1288         return (rc);
1289 }
1290
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])
1297 {
1298         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
1299         efx_mcdi_req_t req;
1300         uint8_t payload[MAX(MC_CMD_GET_BOARD_CFG_IN_LEN,
1301                             MC_CMD_GET_BOARD_CFG_OUT_LENMIN)];
1302         efx_rc_t rc;
1303
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;
1310
1311         efx_mcdi_execute(enp, &req);
1312
1313         if (req.emr_rc != 0) {
1314                 rc = req.emr_rc;
1315                 goto fail1;
1316         }
1317
1318         if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
1319                 rc = EMSGSIZE;
1320                 goto fail2;
1321         }
1322
1323         if (mac_addrp != NULL) {
1324                 uint8_t *addrp;
1325
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);
1332                 } else {
1333                         rc = EINVAL;
1334                         goto fail3;
1335                 }
1336
1337                 EFX_MAC_ADDR_COPY(mac_addrp, addrp);
1338         }
1339
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);
1347                 } else {
1348                         rc = EINVAL;
1349                         goto fail4;
1350                 }
1351         }
1352
1353         if (board_typep != NULL) {
1354                 *board_typep = MCDI_OUT_DWORD(req,
1355                     GET_BOARD_CFG_OUT_BOARD_TYPE);
1356         }
1357
1358         return (0);
1359
1360 fail4:
1361         EFSYS_PROBE(fail4);
1362 fail3:
1363         EFSYS_PROBE(fail3);
1364 fail2:
1365         EFSYS_PROBE(fail2);
1366 fail1:
1367         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1368
1369         return (rc);
1370 }
1371
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)
1378 {
1379         efx_mcdi_req_t req;
1380         uint8_t payload[MAX(MC_CMD_GET_RESOURCE_LIMITS_IN_LEN,
1381                             MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN)];
1382         efx_rc_t rc;
1383
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;
1390
1391         efx_mcdi_execute(enp, &req);
1392
1393         if (req.emr_rc != 0) {
1394                 rc = req.emr_rc;
1395                 goto fail1;
1396         }
1397
1398         if (req.emr_out_length_used < MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) {
1399                 rc = EMSGSIZE;
1400                 goto fail2;
1401         }
1402
1403         if (nevqp != NULL)
1404                 *nevqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_EVQ);
1405         if (nrxqp != NULL)
1406                 *nrxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ);
1407         if (ntxqp != NULL)
1408                 *ntxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ);
1409
1410         return (0);
1411
1412 fail2:
1413         EFSYS_PROBE(fail2);
1414 fail1:
1415         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1416
1417         return (rc);
1418 }
1419
1420         __checkReturn   efx_rc_t
1421 efx_mcdi_get_phy_cfg(
1422         __in            efx_nic_t *enp)
1423 {
1424         efx_port_t *epp = &(enp->en_port);
1425         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1426         efx_mcdi_req_t req;
1427         uint8_t payload[MAX(MC_CMD_GET_PHY_CFG_IN_LEN,
1428                             MC_CMD_GET_PHY_CFG_OUT_LEN)];
1429         efx_rc_t rc;
1430
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;
1437
1438         efx_mcdi_execute(enp, &req);
1439
1440         if (req.emr_rc != 0) {
1441                 rc = req.emr_rc;
1442                 goto fail1;
1443         }
1444
1445         if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) {
1446                 rc = EMSGSIZE;
1447                 goto fail2;
1448         }
1449
1450         encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE);
1451 #if EFSYS_OPT_NAMES
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 */
1468
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;
1481
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 */
1487
1488         encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT);
1489
1490         /* Populate internal state */
1491         encp->enc_mcdi_mdio_channel =
1492                 (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL);
1493
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 */
1498
1499 #if EFSYS_OPT_BIST
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 */
1511
1512         return (0);
1513
1514 fail2:
1515         EFSYS_PROBE(fail2);
1516 fail1:
1517         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1518
1519         return (rc);
1520 }
1521
1522         __checkReturn           efx_rc_t
1523 efx_mcdi_firmware_update_supported(
1524         __in                    efx_nic_t *enp,
1525         __out                   boolean_t *supportedp)
1526 {
1527         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1528         efx_rc_t rc;
1529
1530         if (emcop != NULL) {
1531                 if ((rc = emcop->emco_feature_supported(enp,
1532                             EFX_MCDI_FEATURE_FW_UPDATE, supportedp)) != 0)
1533                         goto fail1;
1534         } else {
1535                 /* Earlier devices always supported updates */
1536                 *supportedp = B_TRUE;
1537         }
1538
1539         return (0);
1540
1541 fail1:
1542         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1543
1544         return (rc);
1545 }
1546
1547         __checkReturn           efx_rc_t
1548 efx_mcdi_macaddr_change_supported(
1549         __in                    efx_nic_t *enp,
1550         __out                   boolean_t *supportedp)
1551 {
1552         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1553         efx_rc_t rc;
1554
1555         if (emcop != NULL) {
1556                 if ((rc = emcop->emco_feature_supported(enp,
1557                             EFX_MCDI_FEATURE_MACADDR_CHANGE, supportedp)) != 0)
1558                         goto fail1;
1559         } else {
1560                 /* Earlier devices always supported MAC changes */
1561                 *supportedp = B_TRUE;
1562         }
1563
1564         return (0);
1565
1566 fail1:
1567         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1568
1569         return (rc);
1570 }
1571
1572         __checkReturn           efx_rc_t
1573 efx_mcdi_link_control_supported(
1574         __in                    efx_nic_t *enp,
1575         __out                   boolean_t *supportedp)
1576 {
1577         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1578         efx_rc_t rc;
1579
1580         if (emcop != NULL) {
1581                 if ((rc = emcop->emco_feature_supported(enp,
1582                             EFX_MCDI_FEATURE_LINK_CONTROL, supportedp)) != 0)
1583                         goto fail1;
1584         } else {
1585                 /* Earlier devices always supported link control */
1586                 *supportedp = B_TRUE;
1587         }
1588
1589         return (0);
1590
1591 fail1:
1592         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1593
1594         return (rc);
1595 }
1596
1597         __checkReturn           efx_rc_t
1598 efx_mcdi_mac_spoofing_supported(
1599         __in                    efx_nic_t *enp,
1600         __out                   boolean_t *supportedp)
1601 {
1602         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1603         efx_rc_t rc;
1604
1605         if (emcop != NULL) {
1606                 if ((rc = emcop->emco_feature_supported(enp,
1607                             EFX_MCDI_FEATURE_MAC_SPOOFING, supportedp)) != 0)
1608                         goto fail1;
1609         } else {
1610                 /* Earlier devices always supported MAC spoofing */
1611                 *supportedp = B_TRUE;
1612         }
1613
1614         return (0);
1615
1616 fail1:
1617         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1618
1619         return (rc);
1620 }
1621
1622 #if EFSYS_OPT_BIST
1623
1624 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
1625 /*
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.
1629  */
1630         __checkReturn           efx_rc_t
1631 efx_mcdi_bist_enable_offline(
1632         __in                    efx_nic_t *enp)
1633 {
1634         efx_mcdi_req_t req;
1635         efx_rc_t rc;
1636
1637         EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_IN_LEN == 0);
1638         EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_OUT_LEN == 0);
1639
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;
1645
1646         efx_mcdi_execute(enp, &req);
1647
1648         if (req.emr_rc != 0) {
1649                 rc = req.emr_rc;
1650                 goto fail1;
1651         }
1652
1653         return (0);
1654
1655 fail1:
1656         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1657
1658         return (rc);
1659 }
1660 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
1661
1662         __checkReturn           efx_rc_t
1663 efx_mcdi_bist_start(
1664         __in                    efx_nic_t *enp,
1665         __in                    efx_bist_type_t type)
1666 {
1667         efx_mcdi_req_t req;
1668         uint8_t payload[MAX(MC_CMD_START_BIST_IN_LEN,
1669                             MC_CMD_START_BIST_OUT_LEN)];
1670         efx_rc_t rc;
1671
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;
1678
1679         switch (type) {
1680         case EFX_BIST_TYPE_PHY_NORMAL:
1681                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST);
1682                 break;
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);
1686                 break;
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);
1690                 break;
1691         case EFX_BIST_TYPE_MC_MEM:
1692                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1693                     MC_CMD_MC_MEM_BIST);
1694                 break;
1695         case EFX_BIST_TYPE_SAT_MEM:
1696                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1697                     MC_CMD_PORT_MEM_BIST);
1698                 break;
1699         case EFX_BIST_TYPE_REG:
1700                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1701                     MC_CMD_REG_BIST);
1702                 break;
1703         default:
1704                 EFSYS_ASSERT(0);
1705         }
1706
1707         efx_mcdi_execute(enp, &req);
1708
1709         if (req.emr_rc != 0) {
1710                 rc = req.emr_rc;
1711                 goto fail1;
1712         }
1713
1714         return (0);
1715
1716 fail1:
1717         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1718
1719         return (rc);
1720 }
1721
1722 #endif /* EFSYS_OPT_BIST */
1723
1724
1725 /* Enable logging of some events (e.g. link state changes) */
1726         __checkReturn   efx_rc_t
1727 efx_mcdi_log_ctrl(
1728         __in            efx_nic_t *enp)
1729 {
1730         efx_mcdi_req_t req;
1731         uint8_t payload[MAX(MC_CMD_LOG_CTRL_IN_LEN,
1732                             MC_CMD_LOG_CTRL_OUT_LEN)];
1733         efx_rc_t rc;
1734
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;
1741
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);
1745
1746         efx_mcdi_execute(enp, &req);
1747
1748         if (req.emr_rc != 0) {
1749                 rc = req.emr_rc;
1750                 goto fail1;
1751         }
1752
1753         return (0);
1754
1755 fail1:
1756         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1757
1758         return (rc);
1759 }
1760
1761
1762 #if EFSYS_OPT_MAC_STATS
1763
1764 typedef enum efx_stats_action_e {
1765         EFX_STATS_CLEAR,
1766         EFX_STATS_UPLOAD,
1767         EFX_STATS_ENABLE_NOEVENTS,
1768         EFX_STATS_ENABLE_EVENTS,
1769         EFX_STATS_DISABLE,
1770 } efx_stats_action_t;
1771
1772 static  __checkReturn   efx_rc_t
1773 efx_mcdi_mac_stats(
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)
1778 {
1779         efx_mcdi_req_t req;
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);
1787         efx_rc_t rc;
1788
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;
1795
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);
1803
1804         if (esmp != NULL) {
1805                 int bytes = MC_CMD_MAC_NSTATS * sizeof (uint64_t);
1806
1807                 EFX_STATIC_ASSERT(MC_CMD_MAC_NSTATS * sizeof (uint64_t) <=
1808                     EFX_MAC_STATS_SIZE);
1809
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);
1815         } else {
1816                 EFSYS_ASSERT(!upload && !enable && !events);
1817         }
1818
1819         /*
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.
1823          */
1824         MCDI_IN_SET_DWORD(req, MAC_STATS_IN_PORT_ID,
1825             (disable ? EVB_PORT_ID_NULL : enp->en_vport_id));
1826
1827         efx_mcdi_execute(enp, &req);
1828
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)) {
1833                         rc = req.emr_rc;
1834                         goto fail1;
1835                 }
1836         }
1837
1838         return (0);
1839
1840 fail1:
1841         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1842
1843         return (rc);
1844 }
1845
1846         __checkReturn   efx_rc_t
1847 efx_mcdi_mac_stats_clear(
1848         __in            efx_nic_t *enp)
1849 {
1850         efx_rc_t rc;
1851
1852         if ((rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_CLEAR, 0)) != 0)
1853                 goto fail1;
1854
1855         return (0);
1856
1857 fail1:
1858         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1859
1860         return (rc);
1861 }
1862
1863         __checkReturn   efx_rc_t
1864 efx_mcdi_mac_stats_upload(
1865         __in            efx_nic_t *enp,
1866         __in            efsys_mem_t *esmp)
1867 {
1868         efx_rc_t rc;
1869
1870         /*
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.
1874          */
1875         if ((rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_UPLOAD, 0)) != 0)
1876                 goto fail1;
1877
1878         return (0);
1879
1880 fail1:
1881         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1882
1883         return (rc);
1884 }
1885
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)
1892 {
1893         efx_rc_t rc;
1894
1895         /*
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.
1901          */
1902         if (period_ms == 0)
1903                 rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_DISABLE, 0);
1904         else if (events)
1905                 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_EVENTS,
1906                     period_ms);
1907         else
1908                 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_NOEVENTS,
1909                     period_ms);
1910
1911         if (rc != 0)
1912                 goto fail1;
1913
1914         return (0);
1915
1916 fail1:
1917         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1918
1919         return (rc);
1920 }
1921
1922 #endif  /* EFSYS_OPT_MAC_STATS */
1923
1924 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
1925
1926 /*
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).
1931  */
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)
1937 {
1938         efx_mcdi_req_t req;
1939         uint8_t payload[MAX(MC_CMD_GET_FUNCTION_INFO_IN_LEN,
1940                             MC_CMD_GET_FUNCTION_INFO_OUT_LEN)];
1941         efx_rc_t rc;
1942
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;
1949
1950         efx_mcdi_execute(enp, &req);
1951
1952         if (req.emr_rc != 0) {
1953                 rc = req.emr_rc;
1954                 goto fail1;
1955         }
1956
1957         if (req.emr_out_length_used < MC_CMD_GET_FUNCTION_INFO_OUT_LEN) {
1958                 rc = EMSGSIZE;
1959                 goto fail2;
1960         }
1961
1962         *pfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_PF);
1963         if (vfp != NULL)
1964                 *vfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_VF);
1965
1966         return (0);
1967
1968 fail2:
1969         EFSYS_PROBE(fail2);
1970 fail1:
1971         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1972
1973         return (rc);
1974 }
1975
1976         __checkReturn           efx_rc_t
1977 efx_mcdi_privilege_mask(
1978         __in                    efx_nic_t *enp,
1979         __in                    uint32_t pf,
1980         __in                    uint32_t vf,
1981         __out                   uint32_t *maskp)
1982 {
1983         efx_mcdi_req_t req;
1984         uint8_t payload[MAX(MC_CMD_PRIVILEGE_MASK_IN_LEN,
1985                             MC_CMD_PRIVILEGE_MASK_OUT_LEN)];
1986         efx_rc_t rc;
1987
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;
1994
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);
1998
1999         efx_mcdi_execute(enp, &req);
2000
2001         if (req.emr_rc != 0) {
2002                 rc = req.emr_rc;
2003                 goto fail1;
2004         }
2005
2006         if (req.emr_out_length_used < MC_CMD_PRIVILEGE_MASK_OUT_LEN) {
2007                 rc = EMSGSIZE;
2008                 goto fail2;
2009         }
2010
2011         *maskp = MCDI_OUT_DWORD(req, PRIVILEGE_MASK_OUT_OLD_MASK);
2012
2013         return (0);
2014
2015 fail2:
2016         EFSYS_PROBE(fail2);
2017 fail1:
2018         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2019
2020         return (rc);
2021 }
2022
2023 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
2024
2025         __checkReturn           efx_rc_t
2026 efx_mcdi_set_workaround(
2027         __in                    efx_nic_t *enp,
2028         __in                    uint32_t type,
2029         __in                    boolean_t enabled,
2030         __out_opt               uint32_t *flagsp)
2031 {
2032         efx_mcdi_req_t req;
2033         uint8_t payload[MAX(MC_CMD_WORKAROUND_IN_LEN,
2034                             MC_CMD_WORKAROUND_EXT_OUT_LEN)];
2035         efx_rc_t rc;
2036
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;
2043
2044         MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, type);
2045         MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, enabled ? 1 : 0);
2046
2047         efx_mcdi_execute_quiet(enp, &req);
2048
2049         if (req.emr_rc != 0) {
2050                 rc = req.emr_rc;
2051                 goto fail1;
2052         }
2053
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);
2057                 else
2058                         *flagsp = 0;
2059         }
2060
2061         return (0);
2062
2063 fail1:
2064         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2065
2066         return (rc);
2067 }
2068
2069
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)
2075 {
2076         efx_mcdi_req_t req;
2077         uint8_t payload[MC_CMD_GET_WORKAROUNDS_OUT_LEN];
2078         efx_rc_t rc;
2079
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;
2086
2087         efx_mcdi_execute(enp, &req);
2088
2089         if (req.emr_rc != 0) {
2090                 rc = req.emr_rc;
2091                 goto fail1;
2092         }
2093
2094         if (implementedp != NULL) {
2095                 *implementedp =
2096                     MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_IMPLEMENTED);
2097         }
2098
2099         if (enabledp != NULL) {
2100                 *enabledp = MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_ENABLED);
2101         }
2102
2103         return (0);
2104
2105 fail1:
2106         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2107
2108         return (rc);
2109 }
2110
2111 /*
2112  * Size of media information page in accordance with SFF-8472 and SFF-8436.
2113  * It is used in MCDI interface as well.
2114  */
2115 #define EFX_PHY_MEDIA_INFO_PAGE_SIZE            0x80
2116
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,
2122         __in                    uint8_t len,
2123         __out_bcount(len)       uint8_t *data)
2124 {
2125         efx_mcdi_req_t req;
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))];
2129         efx_rc_t rc;
2130
2131         EFSYS_ASSERT((uint32_t)offset + len <= EFX_PHY_MEDIA_INFO_PAGE_SIZE);
2132
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);
2140
2141         MCDI_IN_SET_DWORD(req, GET_PHY_MEDIA_INFO_IN_PAGE, mcdi_page);
2142
2143         efx_mcdi_execute(enp, &req);
2144
2145         if (req.emr_rc != 0) {
2146                 rc = req.emr_rc;
2147                 goto fail1;
2148         }
2149
2150         if (req.emr_out_length_used !=
2151             MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE)) {
2152                 rc = EMSGSIZE;
2153                 goto fail2;
2154         }
2155
2156         if (MCDI_OUT_DWORD(req, GET_PHY_MEDIA_INFO_OUT_DATALEN) !=
2157             EFX_PHY_MEDIA_INFO_PAGE_SIZE) {
2158                 rc = EIO;
2159                 goto fail3;
2160         }
2161
2162         memcpy(data,
2163             MCDI_OUT2(req, uint8_t, GET_PHY_MEDIA_INFO_OUT_DATA) + offset,
2164             len);
2165
2166         return (0);
2167
2168 fail3:
2169         EFSYS_PROBE(fail3);
2170 fail2:
2171         EFSYS_PROBE(fail2);
2172 fail1:
2173         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2174
2175         return (rc);
2176 }
2177
2178 /*
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.
2182  */
2183 #define EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE    0xA0
2184
2185 /*
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.
2189  */
2190 #define EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM     0xA2
2191
2192 /*
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
2195  * Operation.
2196  */
2197 #define EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP        0xA0
2198
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,
2204         __in                    uint8_t len,
2205         __out_bcount(len)       uint8_t *data)
2206 {
2207         efx_port_t *epp = &(enp->en_port);
2208         efx_rc_t rc;
2209         uint32_t mcdi_lower_page;
2210         uint32_t mcdi_upper_page;
2211
2212         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
2213
2214         /*
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
2220          * and accessible.
2221          */
2222         switch (epp->ep_fixed_port_type) {
2223         case EFX_PHY_MEDIA_SFP_PLUS:
2224                 /*
2225                  * In accordance with SFF-8472 Diagnostic Monitoring
2226                  * Interface for Optical Transceivers section 4 Memory
2227                  * Organization two 2-wire addresses are defined.
2228                  */
2229                 switch (dev_addr) {
2230                 /* Base information */
2231                 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE:
2232                         /*
2233                          * MCDI page 0 should be used to access lower
2234                          * page 0 (0x00 - 0x7f) at the device address 0xA0.
2235                          */
2236                         mcdi_lower_page = 0;
2237                         /*
2238                          * MCDI page 1 should be used to access  upper
2239                          * page 0 (0x80 - 0xff) at the device address 0xA0.
2240                          */
2241                         mcdi_upper_page = 1;
2242                         break;
2243                 /* Diagnostics */
2244                 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM:
2245                         /*
2246                          * MCDI page 2 should be used to access lower
2247                          * page 0 (0x00 - 0x7f) at the device address 0xA2.
2248                          */
2249                         mcdi_lower_page = 2;
2250                         /*
2251                          * MCDI page 3 should be used to access upper
2252                          * page 0 (0x80 - 0xff) at the device address 0xA2.
2253                          */
2254                         mcdi_upper_page = 3;
2255                         break;
2256                 default:
2257                         rc = ENOTSUP;
2258                         goto fail1;
2259                 }
2260                 break;
2261         case EFX_PHY_MEDIA_QSFP_PLUS:
2262                 switch (dev_addr) {
2263                 case EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP:
2264                         /*
2265                          * MCDI page -1 should be used to access lower page 0
2266                          * (0x00 - 0x7f).
2267                          */
2268                         mcdi_lower_page = (uint32_t)-1;
2269                         /*
2270                          * MCDI page 0 should be used to access upper page 0
2271                          * (0x80h - 0xff).
2272                          */
2273                         mcdi_upper_page = 0;
2274                         break;
2275                 default:
2276                         rc = ENOTSUP;
2277                         goto fail1;
2278                 }
2279                 break;
2280         default:
2281                 rc = ENOTSUP;
2282                 goto fail1;
2283         }
2284
2285         if (offset < EFX_PHY_MEDIA_INFO_PAGE_SIZE) {
2286                 uint8_t read_len =
2287                     MIN(len, EFX_PHY_MEDIA_INFO_PAGE_SIZE - offset);
2288
2289                 rc = efx_mcdi_get_phy_media_info(enp,
2290                     mcdi_lower_page, offset, read_len, data);
2291                 if (rc != 0)
2292                         goto fail2;
2293
2294                 data += read_len;
2295                 len -= read_len;
2296
2297                 offset = 0;
2298         } else {
2299                 offset -= EFX_PHY_MEDIA_INFO_PAGE_SIZE;
2300         }
2301
2302         if (len > 0) {
2303                 EFSYS_ASSERT3U(len, <=, EFX_PHY_MEDIA_INFO_PAGE_SIZE);
2304                 EFSYS_ASSERT3U(offset, <, EFX_PHY_MEDIA_INFO_PAGE_SIZE);
2305
2306                 rc = efx_mcdi_get_phy_media_info(enp,
2307                     mcdi_upper_page, offset, len, data);
2308                 if (rc != 0)
2309                         goto fail3;
2310         }
2311
2312         return (0);
2313
2314 fail3:
2315         EFSYS_PROBE(fail3);
2316 fail2:
2317         EFSYS_PROBE(fail2);
2318 fail1:
2319         EFSYS_PROBE1(fail1, efx_rc_t, rc);
2320
2321         return (rc);
2322 }
2323
2324 #endif  /* EFSYS_OPT_MCDI */