]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/sfxge/common/efx_mcdi.c
MFC r292090
[FreeBSD/stable/10.git] / sys / dev / sfxge / common / efx_mcdi.c
1 /*-
2  * Copyright (c) 2008-2015 Solarflare Communications Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include "efsys.h"
35 #include "efx.h"
36 #include "efx_types.h"
37 #include "efx_regs.h"
38 #include "efx_regs_mcdi.h"
39 #include "efx_impl.h"
40
41 #if EFSYS_OPT_MCDI
42
43
44 #if EFSYS_OPT_SIENA
45
46 static efx_mcdi_ops_t   __efx_mcdi_siena_ops = {
47         siena_mcdi_init,                /* emco_init */
48         siena_mcdi_request_copyin,      /* emco_request_copyin */
49         siena_mcdi_request_copyout,     /* emco_request_copyout */
50         siena_mcdi_poll_reboot,         /* emco_poll_reboot */
51         siena_mcdi_poll_response,       /* emco_poll_response */
52         siena_mcdi_read_response,       /* emco_read_response */
53         siena_mcdi_fini,                /* emco_fini */
54         siena_mcdi_feature_supported,   /* emco_feature_supported */
55 };
56
57 #endif  /* EFSYS_OPT_SIENA */
58
59 #if EFSYS_OPT_HUNTINGTON
60
61 static efx_mcdi_ops_t   __efx_mcdi_hunt_ops = {
62         hunt_mcdi_init,                 /* emco_init */
63         hunt_mcdi_request_copyin,       /* emco_request_copyin */
64         hunt_mcdi_request_copyout,      /* emco_request_copyout */
65         hunt_mcdi_poll_reboot,          /* emco_poll_reboot */
66         hunt_mcdi_poll_response,        /* emco_poll_response */
67         hunt_mcdi_read_response,        /* emco_read_response */
68         hunt_mcdi_fini,                 /* emco_fini */
69         hunt_mcdi_feature_supported,    /* emco_feature_supported */
70 };
71
72 #endif  /* EFSYS_OPT_HUNTINGTON */
73
74
75
76         __checkReturn   efx_rc_t
77 efx_mcdi_init(
78         __in            efx_nic_t *enp,
79         __in            const efx_mcdi_transport_t *emtp)
80 {
81         efx_mcdi_ops_t *emcop;
82         efx_rc_t rc;
83
84         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
85         EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
86
87         switch (enp->en_family) {
88 #if EFSYS_OPT_FALCON
89         case EFX_FAMILY_FALCON:
90                 emcop = NULL;
91                 emtp = NULL;
92                 break;
93 #endif  /* EFSYS_OPT_FALCON */
94
95 #if EFSYS_OPT_SIENA
96         case EFX_FAMILY_SIENA:
97                 emcop = (efx_mcdi_ops_t *)&__efx_mcdi_siena_ops;
98                 break;
99 #endif  /* EFSYS_OPT_SIENA */
100
101 #if EFSYS_OPT_HUNTINGTON
102         case EFX_FAMILY_HUNTINGTON:
103                 emcop = (efx_mcdi_ops_t *)&__efx_mcdi_hunt_ops;
104                 break;
105 #endif  /* EFSYS_OPT_HUNTINGTON */
106
107         default:
108                 EFSYS_ASSERT(0);
109                 rc = ENOTSUP;
110                 goto fail1;
111         }
112
113         if (enp->en_features & EFX_FEATURE_MCDI_DMA) {
114                 /* MCDI requires a DMA buffer in host memory */
115                 if ((emtp == NULL) || (emtp->emt_dma_mem) == NULL) {
116                         rc = EINVAL;
117                         goto fail2;
118                 }
119         }
120         enp->en_mcdi.em_emtp = emtp;
121
122         if (emcop != NULL && emcop->emco_init != NULL) {
123                 if ((rc = emcop->emco_init(enp, emtp)) != 0)
124                         goto fail3;
125         }
126
127         enp->en_mcdi.em_emcop = emcop;
128         enp->en_mod_flags |= EFX_MOD_MCDI;
129
130         return (0);
131
132 fail3:
133         EFSYS_PROBE(fail3);
134 fail2:
135         EFSYS_PROBE(fail2);
136 fail1:
137         EFSYS_PROBE1(fail1, efx_rc_t, rc);
138
139         enp->en_mcdi.em_emcop = NULL;
140         enp->en_mcdi.em_emtp = NULL;
141         enp->en_mod_flags &= ~EFX_MOD_MCDI;
142
143         return (rc);
144 }
145
146                         void
147 efx_mcdi_fini(
148         __in            efx_nic_t *enp)
149 {
150         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
151         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
152
153         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
154         EFSYS_ASSERT3U(enp->en_mod_flags, ==, EFX_MOD_MCDI);
155
156         if (emcop != NULL && emcop->emco_fini != NULL)
157                 emcop->emco_fini(enp);
158
159         emip->emi_port = 0;
160         emip->emi_aborted = 0;
161
162         enp->en_mcdi.em_emcop = NULL;
163         enp->en_mod_flags &= ~EFX_MOD_MCDI;
164 }
165
166                         void
167 efx_mcdi_new_epoch(
168         __in            efx_nic_t *enp)
169 {
170         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
171         int state;
172
173         /* Start a new epoch (allow fresh MCDI requests to succeed) */
174         EFSYS_LOCK(enp->en_eslp, state);
175         emip->emi_new_epoch = B_TRUE;
176         EFSYS_UNLOCK(enp->en_eslp, state);
177 }
178
179 static                  void
180 efx_mcdi_request_copyin(
181         __in            efx_nic_t *enp,
182         __in            efx_mcdi_req_t *emrp,
183         __in            unsigned int seq,
184         __in            boolean_t ev_cpl,
185         __in            boolean_t new_epoch)
186 {
187         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
188
189         emcop->emco_request_copyin(enp, emrp, seq, ev_cpl, new_epoch);
190 }
191
192 static                  void
193 efx_mcdi_request_copyout(
194         __in            efx_nic_t *enp,
195         __in            efx_mcdi_req_t *emrp)
196 {
197         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
198
199         emcop->emco_request_copyout(enp, emrp);
200 }
201
202 static                  efx_rc_t
203 efx_mcdi_poll_reboot(
204         __in            efx_nic_t *enp)
205 {
206         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
207         efx_rc_t rc;
208
209         rc = emcop->emco_poll_reboot(enp);
210         return (rc);
211 }
212
213 static                  boolean_t
214 efx_mcdi_poll_response(
215         __in            efx_nic_t *enp)
216 {
217         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
218         boolean_t available;
219
220         available = emcop->emco_poll_response(enp);
221         return (available);
222 }
223
224 static                  void
225 efx_mcdi_read_response(
226         __in            efx_nic_t *enp,
227         __out           void *bufferp,
228         __in            size_t offset,
229         __in            size_t length)
230 {
231         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
232
233         emcop->emco_read_response(enp, bufferp, offset, length);
234 }
235
236                         void
237 efx_mcdi_request_start(
238         __in            efx_nic_t *enp,
239         __in            efx_mcdi_req_t *emrp,
240         __in            boolean_t ev_cpl)
241 {
242         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
243         unsigned int seq;
244         boolean_t new_epoch;
245         int state;
246
247         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
248         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
249         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
250
251         /*
252          * efx_mcdi_request_start() is naturally serialised against both
253          * efx_mcdi_request_poll() and efx_mcdi_ev_cpl()/efx_mcdi_ev_death(),
254          * by virtue of there only being one outstanding MCDI request.
255          * Unfortunately, upper layers may also call efx_mcdi_request_abort()
256          * at any time, to timeout a pending mcdi request, That request may
257          * then subsequently complete, meaning efx_mcdi_ev_cpl() or
258          * efx_mcdi_ev_death() may end up running in parallel with
259          * efx_mcdi_request_start(). This race is handled by ensuring that
260          * %emi_pending_req, %emi_ev_cpl and %emi_seq are protected by the
261          * en_eslp lock.
262          */
263         EFSYS_LOCK(enp->en_eslp, state);
264         EFSYS_ASSERT(emip->emi_pending_req == NULL);
265         emip->emi_pending_req = emrp;
266         emip->emi_ev_cpl = ev_cpl;
267         emip->emi_poll_cnt = 0;
268         seq = emip->emi_seq++ & EFX_MASK32(MCDI_HEADER_SEQ);
269         new_epoch = emip->emi_new_epoch;
270         EFSYS_UNLOCK(enp->en_eslp, state);
271
272         efx_mcdi_request_copyin(enp, emrp, seq, ev_cpl, new_epoch);
273 }
274
275
276                         void
277 efx_mcdi_read_response_header(
278         __in            efx_nic_t *enp,
279         __inout         efx_mcdi_req_t *emrp)
280 {
281 #if EFSYS_OPT_MCDI_LOGGING
282         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
283 #endif /* EFSYS_OPT_MCDI_LOGGING */
284         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
285         efx_dword_t hdr[2];
286         unsigned int hdr_len;
287         unsigned int data_len;
288         unsigned int seq;
289         unsigned int cmd;
290         unsigned int error;
291         efx_rc_t rc;
292
293         EFSYS_ASSERT(emrp != NULL);
294
295         efx_mcdi_read_response(enp, &hdr[0], 0, sizeof (hdr[0]));
296         hdr_len = sizeof (hdr[0]);
297
298         cmd = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE);
299         seq = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_SEQ);
300         error = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_ERROR);
301
302         if (cmd != MC_CMD_V2_EXTN) {
303                 data_len = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_DATALEN);
304         } else {
305                 efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1]));
306                 hdr_len += sizeof (hdr[1]);
307
308                 cmd = EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_EXTENDED_CMD);
309                 data_len =
310                     EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
311         }
312
313         if (error && (data_len == 0)) {
314                 /* The MC has rebooted since the request was sent. */
315                 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
316                 efx_mcdi_poll_reboot(enp);
317                 rc = EIO;
318                 goto fail1;
319         }
320         if ((cmd != emrp->emr_cmd) ||
321             (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
322                 /* Response is for a different request */
323                 rc = EIO;
324                 goto fail2;
325         }
326         if (error) {
327                 efx_dword_t err[2];
328                 unsigned int err_len = MIN(data_len, sizeof (err));
329                 int err_code = MC_CMD_ERR_EPROTO;
330                 int err_arg = 0;
331
332                 /* Read error code (and arg num for MCDI v2 commands) */
333                 efx_mcdi_read_response(enp, &err, hdr_len, err_len);
334
335                 if (err_len >= (MC_CMD_ERR_CODE_OFST + sizeof (efx_dword_t)))
336                         err_code = EFX_DWORD_FIELD(err[0], EFX_DWORD_0);
337 #ifdef WITH_MCDI_V2
338                 if (err_len >= (MC_CMD_ERR_ARG_OFST + sizeof (efx_dword_t)))
339                         err_arg = EFX_DWORD_FIELD(err[1], EFX_DWORD_0);
340 #endif
341                 emrp->emr_err_code = err_code;
342                 emrp->emr_err_arg = err_arg;
343
344 #if EFSYS_OPT_MCDI_PROXY_AUTH
345                 if ((err_code == MC_CMD_ERR_PROXY_PENDING) &&
346                     (err_len == sizeof (err))) {
347                         /*
348                          * The MCDI request would normally fail with EPERM, but
349                          * firmware has forwarded it to an authorization agent
350                          * attached to a privileged PF.
351                          *
352                          * Save the authorization request handle. The client
353                          * must wait for a PROXY_RESPONSE event, or timeout.
354                          */
355                         emrp->emr_proxy_handle = err_arg;
356                 }
357 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
358
359 #if EFSYS_OPT_MCDI_LOGGING
360                 if (emtp->emt_logger != NULL) {
361                         emtp->emt_logger(emtp->emt_context,
362                             EFX_LOG_MCDI_RESPONSE,
363                             &hdr, hdr_len,
364                             &err, err_len);
365                 }
366 #endif /* EFSYS_OPT_MCDI_LOGGING */
367
368                 if (!emrp->emr_quiet) {
369                         EFSYS_PROBE3(mcdi_err_arg, int, emrp->emr_cmd,
370                             int, err_code, int, err_arg);
371                 }
372
373                 rc = efx_mcdi_request_errcode(err_code);
374                 goto fail3;
375         }
376
377         emrp->emr_rc = 0;
378         emrp->emr_out_length_used = data_len;
379 #if EFSYS_OPT_MCDI_PROXY_AUTH
380         emrp->emr_proxy_handle = 0;
381 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
382         return;
383
384 fail3:
385         if (!emrp->emr_quiet)
386                 EFSYS_PROBE(fail3);
387 fail2:
388         if (!emrp->emr_quiet)
389                 EFSYS_PROBE(fail2);
390 fail1:
391         if (!emrp->emr_quiet)
392                 EFSYS_PROBE1(fail1, efx_rc_t, rc);
393
394         emrp->emr_rc = rc;
395         emrp->emr_out_length_used = 0;
396 }
397
398
399         __checkReturn   boolean_t
400 efx_mcdi_request_poll(
401         __in            efx_nic_t *enp)
402 {
403         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
404         efx_mcdi_req_t *emrp;
405         int state;
406         efx_rc_t rc;
407
408         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
409         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
410         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
411
412         /* Serialise against post-watchdog efx_mcdi_ev* */
413         EFSYS_LOCK(enp->en_eslp, state);
414
415         EFSYS_ASSERT(emip->emi_pending_req != NULL);
416         EFSYS_ASSERT(!emip->emi_ev_cpl);
417         emrp = emip->emi_pending_req;
418
419         /* Check for reboot atomically w.r.t efx_mcdi_request_start */
420         if (emip->emi_poll_cnt++ == 0) {
421                 if ((rc = efx_mcdi_poll_reboot(enp)) != 0) {
422                         emip->emi_pending_req = NULL;
423                         EFSYS_UNLOCK(enp->en_eslp, state);
424                         goto fail1;
425                 }
426         }
427
428         /* Check if a response is available */
429         if (efx_mcdi_poll_response(enp) == B_FALSE) {
430                 EFSYS_UNLOCK(enp->en_eslp, state);
431                 return (B_FALSE);
432         }
433
434         /* Read the response header */
435         efx_mcdi_read_response_header(enp, emrp);
436
437         /* Request complete */
438         emip->emi_pending_req = NULL;
439
440         EFSYS_UNLOCK(enp->en_eslp, state);
441
442         if ((rc = emrp->emr_rc) != 0)
443                 goto fail2;
444
445         efx_mcdi_request_copyout(enp, emrp);
446         return (B_TRUE);
447
448 fail2:
449         if (!emrp->emr_quiet)
450                 EFSYS_PROBE(fail2);
451 fail1:
452         if (!emrp->emr_quiet)
453                 EFSYS_PROBE1(fail1, efx_rc_t, rc);
454
455         /* Reboot/Assertion */
456         if (rc == EIO || rc == EINTR)
457                 efx_mcdi_raise_exception(enp, emrp, rc);
458
459         return (B_TRUE);
460 }
461
462         __checkReturn   boolean_t
463 efx_mcdi_request_abort(
464         __in            efx_nic_t *enp)
465 {
466         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
467         efx_mcdi_req_t *emrp;
468         boolean_t aborted;
469         int state;
470
471         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
472         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
473         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
474
475         /*
476          * efx_mcdi_ev_* may have already completed this event, and be
477          * spinning/blocked on the upper layer lock. So it *is* legitimate
478          * to for emi_pending_req to be NULL. If there is a pending event
479          * completed request, then provide a "credit" to allow
480          * efx_mcdi_ev_cpl() to accept a single spurious completion.
481          */
482         EFSYS_LOCK(enp->en_eslp, state);
483         emrp = emip->emi_pending_req;
484         aborted = (emrp != NULL);
485         if (aborted) {
486                 emip->emi_pending_req = NULL;
487
488                 /* Error the request */
489                 emrp->emr_out_length_used = 0;
490                 emrp->emr_rc = ETIMEDOUT;
491
492                 /* Provide a credit for seqno/emr_pending_req mismatches */
493                 if (emip->emi_ev_cpl)
494                         ++emip->emi_aborted;
495
496                 /*
497                  * The upper layer has called us, so we don't
498                  * need to complete the request.
499                  */
500         }
501         EFSYS_UNLOCK(enp->en_eslp, state);
502
503         return (aborted);
504 }
505
506         __checkReturn   efx_rc_t
507 efx_mcdi_request_errcode(
508         __in            unsigned int err)
509 {
510
511         switch (err) {
512                 /* MCDI v1 */
513         case MC_CMD_ERR_EPERM:
514                 return (EACCES);
515         case MC_CMD_ERR_ENOENT:
516                 return (ENOENT);
517         case MC_CMD_ERR_EINTR:
518                 return (EINTR);
519         case MC_CMD_ERR_EACCES:
520                 return (EACCES);
521         case MC_CMD_ERR_EBUSY:
522                 return (EBUSY);
523         case MC_CMD_ERR_EINVAL:
524                 return (EINVAL);
525         case MC_CMD_ERR_EDEADLK:
526                 return (EDEADLK);
527         case MC_CMD_ERR_ENOSYS:
528                 return (ENOTSUP);
529         case MC_CMD_ERR_ETIME:
530                 return (ETIMEDOUT);
531         case MC_CMD_ERR_ENOTSUP:
532                 return (ENOTSUP);
533         case MC_CMD_ERR_EALREADY:
534                 return (EALREADY);
535
536                 /* MCDI v2 */
537 #ifdef MC_CMD_ERR_EAGAIN
538         case MC_CMD_ERR_EAGAIN:
539                 return (EAGAIN);
540 #endif
541 #ifdef MC_CMD_ERR_ENOSPC
542         case MC_CMD_ERR_ENOSPC:
543                 return (ENOSPC);
544 #endif
545
546         case MC_CMD_ERR_ALLOC_FAIL:
547                 return (ENOMEM);
548         case MC_CMD_ERR_NO_VADAPTOR:
549                 return (ENOENT);
550         case MC_CMD_ERR_NO_EVB_PORT:
551                 return (ENOENT);
552         case MC_CMD_ERR_NO_VSWITCH:
553                 return (ENODEV);
554         case MC_CMD_ERR_VLAN_LIMIT:
555                 return (EINVAL);
556         case MC_CMD_ERR_BAD_PCI_FUNC:
557                 return (ENODEV);
558         case MC_CMD_ERR_BAD_VLAN_MODE:
559                 return (EINVAL);
560         case MC_CMD_ERR_BAD_VSWITCH_TYPE:
561                 return (EINVAL);
562         case MC_CMD_ERR_BAD_VPORT_TYPE:
563                 return (EINVAL);
564         case MC_CMD_ERR_MAC_EXIST:
565                 return (EEXIST);
566
567         case MC_CMD_ERR_PROXY_PENDING:
568                 return (EAGAIN);
569
570         default:
571                 EFSYS_PROBE1(mc_pcol_error, int, err);
572                 return (EIO);
573         }
574 }
575
576                         void
577 efx_mcdi_raise_exception(
578         __in            efx_nic_t *enp,
579         __in_opt        efx_mcdi_req_t *emrp,
580         __in            int rc)
581 {
582         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
583         efx_mcdi_exception_t exception;
584
585         /* Reboot or Assertion failure only */
586         EFSYS_ASSERT(rc == EIO || rc == EINTR);
587
588         /*
589          * If MC_CMD_REBOOT causes a reboot (dependent on parameters),
590          * then the EIO is not worthy of an exception.
591          */
592         if (emrp != NULL && emrp->emr_cmd == MC_CMD_REBOOT && rc == EIO)
593                 return;
594
595         exception = (rc == EIO)
596                 ? EFX_MCDI_EXCEPTION_MC_REBOOT
597                 : EFX_MCDI_EXCEPTION_MC_BADASSERT;
598
599         emtp->emt_exception(emtp->emt_context, exception);
600 }
601
602                         void
603 efx_mcdi_execute(
604         __in            efx_nic_t *enp,
605         __inout         efx_mcdi_req_t *emrp)
606 {
607         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
608
609         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
610         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
611
612         emrp->emr_quiet = B_FALSE;
613         emtp->emt_execute(emtp->emt_context, emrp);
614 }
615
616                         void
617 efx_mcdi_execute_quiet(
618         __in            efx_nic_t *enp,
619         __inout         efx_mcdi_req_t *emrp)
620 {
621         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
622
623         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
624         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
625
626         emrp->emr_quiet = B_TRUE;
627         emtp->emt_execute(emtp->emt_context, emrp);
628 }
629
630                         void
631 efx_mcdi_ev_cpl(
632         __in            efx_nic_t *enp,
633         __in            unsigned int seq,
634         __in            unsigned int outlen,
635         __in            int errcode)
636 {
637         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
638         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
639         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
640         efx_nic_cfg_t *encp = &enp->en_nic_cfg;
641         efx_mcdi_req_t *emrp;
642         int state;
643
644         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
645         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
646
647         /*
648          * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start()
649          * when we're completing an aborted request.
650          */
651         EFSYS_LOCK(enp->en_eslp, state);
652         if (emip->emi_pending_req == NULL || !emip->emi_ev_cpl ||
653             (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
654                 EFSYS_ASSERT(emip->emi_aborted > 0);
655                 if (emip->emi_aborted > 0)
656                         --emip->emi_aborted;
657                 EFSYS_UNLOCK(enp->en_eslp, state);
658                 return;
659         }
660
661         emrp = emip->emi_pending_req;
662         emip->emi_pending_req = NULL;
663         EFSYS_UNLOCK(enp->en_eslp, state);
664
665         if (encp->enc_mcdi_max_payload_length > MCDI_CTL_SDU_LEN_MAX_V1) {
666                 /* MCDIv2 response details do not fit into an event. */
667                 efx_mcdi_read_response_header(enp, emrp);
668         } else {
669                 if (errcode != 0) {
670                         if (!emrp->emr_quiet) {
671                                 EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd,
672                                     int, errcode);
673                         }
674                         emrp->emr_out_length_used = 0;
675                         emrp->emr_rc = efx_mcdi_request_errcode(errcode);
676                 } else {
677                         emrp->emr_out_length_used = outlen;
678                         emrp->emr_rc = 0;
679                 }
680         }
681         if (errcode == 0) {
682                 emcop->emco_request_copyout(enp, emrp);
683         }
684
685         emtp->emt_ev_cpl(emtp->emt_context);
686 }
687
688 #if EFSYS_OPT_MCDI_PROXY_AUTH
689
690         __checkReturn   efx_rc_t
691 efx_mcdi_get_proxy_handle(
692         __in            efx_nic_t *enp,
693         __in            efx_mcdi_req_t *emrp,
694         __out           uint32_t *handlep)
695 {
696         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
697         efx_rc_t rc;
698
699         /*
700          * Return proxy handle from MCDI request that returned with error
701          * MC_MCD_ERR_PROXY_PENDING. This handle is used to wait for a matching
702          * PROXY_RESPONSE event.
703          */
704         if ((emrp == NULL) || (handlep == NULL)) {
705                 rc = EINVAL;
706                 goto fail1;
707         }
708         if ((emrp->emr_rc != 0) &&
709             (emrp->emr_err_code == MC_CMD_ERR_PROXY_PENDING)) {
710                 *handlep = emrp->emr_proxy_handle;
711                 rc = 0;
712         } else {
713                 *handlep = 0;
714                 rc = ENOENT;
715         }
716         return (rc);
717
718 fail1:
719         EFSYS_PROBE1(fail1, efx_rc_t, rc);
720         return (rc);
721 }
722
723                         void
724 efx_mcdi_ev_proxy_response(
725         __in            efx_nic_t *enp,
726         __in            unsigned int handle,
727         __in            unsigned int status)
728 {
729         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
730         efx_rc_t rc;
731
732         /*
733          * Handle results of an authorization request for a privileged MCDI
734          * command. If authorization was granted then we must re-issue the
735          * original MCDI request. If authorization failed or timed out,
736          * then the original MCDI request should be completed with the
737          * result code from this event.
738          */
739         rc = (status == 0) ? 0 : efx_mcdi_request_errcode(status);
740
741         emtp->emt_ev_proxy_response(emtp->emt_context, handle, rc);
742 }
743 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
744
745                         void
746 efx_mcdi_ev_death(
747         __in            efx_nic_t *enp,
748         __in            int rc)
749 {
750         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
751         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
752         efx_mcdi_req_t *emrp = NULL;
753         boolean_t ev_cpl;
754         int state;
755
756         /*
757          * The MCDI request (if there is one) has been terminated, either
758          * by a BADASSERT or REBOOT event.
759          *
760          * If there is an outstanding event-completed MCDI operation, then we
761          * will never receive the completion event (because both MCDI
762          * completions and BADASSERT events are sent to the same evq). So
763          * complete this MCDI op.
764          *
765          * This function might run in parallel with efx_mcdi_request_poll()
766          * for poll completed mcdi requests, and also with
767          * efx_mcdi_request_start() for post-watchdog completions.
768          */
769         EFSYS_LOCK(enp->en_eslp, state);
770         emrp = emip->emi_pending_req;
771         ev_cpl = emip->emi_ev_cpl;
772         if (emrp != NULL && emip->emi_ev_cpl) {
773                 emip->emi_pending_req = NULL;
774
775                 emrp->emr_out_length_used = 0;
776                 emrp->emr_rc = rc;
777                 ++emip->emi_aborted;
778         }
779
780         /*
781          * Since we're running in parallel with a request, consume the
782          * status word before dropping the lock.
783          */
784         if (rc == EIO || rc == EINTR) {
785                 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
786                 (void) efx_mcdi_poll_reboot(enp);
787                 emip->emi_new_epoch = B_TRUE;
788         }
789
790         EFSYS_UNLOCK(enp->en_eslp, state);
791
792         efx_mcdi_raise_exception(enp, emrp, rc);
793
794         if (emrp != NULL && ev_cpl)
795                 emtp->emt_ev_cpl(emtp->emt_context);
796 }
797
798         __checkReturn           efx_rc_t
799 efx_mcdi_version(
800         __in                    efx_nic_t *enp,
801         __out_ecount_opt(4)     uint16_t versionp[4],
802         __out_opt               uint32_t *buildp,
803         __out_opt               efx_mcdi_boot_t *statusp)
804 {
805         efx_mcdi_req_t req;
806         uint8_t payload[MAX(MAX(MC_CMD_GET_VERSION_IN_LEN,
807                                 MC_CMD_GET_VERSION_OUT_LEN),
808                             MAX(MC_CMD_GET_BOOT_STATUS_IN_LEN,
809                                 MC_CMD_GET_BOOT_STATUS_OUT_LEN))];
810         efx_word_t *ver_words;
811         uint16_t version[4];
812         uint32_t build;
813         efx_mcdi_boot_t status;
814         efx_rc_t rc;
815
816         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
817
818         (void) memset(payload, 0, sizeof (payload));
819         req.emr_cmd = MC_CMD_GET_VERSION;
820         req.emr_in_buf = payload;
821         req.emr_in_length = MC_CMD_GET_VERSION_IN_LEN;
822         req.emr_out_buf = payload;
823         req.emr_out_length = MC_CMD_GET_VERSION_OUT_LEN;
824
825         efx_mcdi_execute(enp, &req);
826
827         if (req.emr_rc != 0) {
828                 rc = req.emr_rc;
829                 goto fail1;
830         }
831
832         /* bootrom support */
833         if (req.emr_out_length_used == MC_CMD_GET_VERSION_V0_OUT_LEN) {
834                 version[0] = version[1] = version[2] = version[3] = 0;
835                 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
836
837                 goto version;
838         }
839
840         if (req.emr_out_length_used < MC_CMD_GET_VERSION_OUT_LEN) {
841                 rc = EMSGSIZE;
842                 goto fail2;
843         }
844
845         ver_words = MCDI_OUT2(req, efx_word_t, GET_VERSION_OUT_VERSION);
846         version[0] = EFX_WORD_FIELD(ver_words[0], EFX_WORD_0);
847         version[1] = EFX_WORD_FIELD(ver_words[1], EFX_WORD_0);
848         version[2] = EFX_WORD_FIELD(ver_words[2], EFX_WORD_0);
849         version[3] = EFX_WORD_FIELD(ver_words[3], EFX_WORD_0);
850         build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
851
852 version:
853         /* The bootrom doesn't understand BOOT_STATUS */
854         if (MC_FW_VERSION_IS_BOOTLOADER(build)) {
855                 status = EFX_MCDI_BOOT_ROM;
856                 goto out;
857         }
858
859         (void) memset(payload, 0, sizeof (payload));
860         req.emr_cmd = MC_CMD_GET_BOOT_STATUS;
861         req.emr_in_buf = payload;
862         req.emr_in_length = MC_CMD_GET_BOOT_STATUS_IN_LEN;
863         req.emr_out_buf = payload;
864         req.emr_out_length = MC_CMD_GET_BOOT_STATUS_OUT_LEN;
865
866         efx_mcdi_execute_quiet(enp, &req);
867
868         if (req.emr_rc == EACCES) {
869                 /* Unprivileged functions cannot access BOOT_STATUS */
870                 status = EFX_MCDI_BOOT_PRIMARY;
871                 version[0] = version[1] = version[2] = version[3] = 0;
872                 build = 0;
873                 goto out;
874         }
875
876         if (req.emr_rc != 0) {
877                 rc = req.emr_rc;
878                 goto fail3;
879         }
880
881         if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) {
882                 rc = EMSGSIZE;
883                 goto fail4;
884         }
885
886         if (MCDI_OUT_DWORD_FIELD(req, GET_BOOT_STATUS_OUT_FLAGS,
887             GET_BOOT_STATUS_OUT_FLAGS_PRIMARY))
888                 status = EFX_MCDI_BOOT_PRIMARY;
889         else
890                 status = EFX_MCDI_BOOT_SECONDARY;
891
892 out:
893         if (versionp != NULL)
894                 memcpy(versionp, version, sizeof (version));
895         if (buildp != NULL)
896                 *buildp = build;
897         if (statusp != NULL)
898                 *statusp = status;
899
900         return (0);
901
902 fail4:
903         EFSYS_PROBE(fail4);
904 fail3:
905         EFSYS_PROBE(fail3);
906 fail2:
907         EFSYS_PROBE(fail2);
908 fail1:
909         EFSYS_PROBE1(fail1, efx_rc_t, rc);
910
911         return (rc);
912 }
913
914 static  __checkReturn   efx_rc_t
915 efx_mcdi_do_reboot(
916         __in            efx_nic_t *enp,
917         __in            boolean_t after_assertion)
918 {
919         uint8_t payload[MAX(MC_CMD_REBOOT_IN_LEN, MC_CMD_REBOOT_OUT_LEN)];
920         efx_mcdi_req_t req;
921         efx_rc_t rc;
922
923         /*
924          * We could require the caller to have caused en_mod_flags=0 to
925          * call this function. This doesn't help the other port though,
926          * who's about to get the MC ripped out from underneath them.
927          * Since they have to cope with the subsequent fallout of MCDI
928          * failures, we should as well.
929          */
930         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
931
932         (void) memset(payload, 0, sizeof (payload));
933         req.emr_cmd = MC_CMD_REBOOT;
934         req.emr_in_buf = payload;
935         req.emr_in_length = MC_CMD_REBOOT_IN_LEN;
936         req.emr_out_buf = payload;
937         req.emr_out_length = MC_CMD_REBOOT_OUT_LEN;
938
939         MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS,
940             (after_assertion ? MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION : 0));
941
942         efx_mcdi_execute_quiet(enp, &req);
943
944         if (req.emr_rc == EACCES) {
945                 /* Unprivileged functions cannot reboot the MC. */
946                 goto out;
947         }
948
949         /* A successful reboot request returns EIO. */
950         if (req.emr_rc != 0 && req.emr_rc != EIO) {
951                 rc = req.emr_rc;
952                 goto fail1;
953         }
954
955 out:
956         return (0);
957
958 fail1:
959         EFSYS_PROBE1(fail1, efx_rc_t, rc);
960
961         return (rc);
962 }
963
964         __checkReturn   efx_rc_t
965 efx_mcdi_reboot(
966         __in            efx_nic_t *enp)
967 {
968         return (efx_mcdi_do_reboot(enp, B_FALSE));
969 }
970
971         __checkReturn   efx_rc_t
972 efx_mcdi_exit_assertion_handler(
973         __in            efx_nic_t *enp)
974 {
975         return (efx_mcdi_do_reboot(enp, B_TRUE));
976 }
977
978         __checkReturn   efx_rc_t
979 efx_mcdi_read_assertion(
980         __in            efx_nic_t *enp)
981 {
982         efx_mcdi_req_t req;
983         uint8_t payload[MAX(MC_CMD_GET_ASSERTS_IN_LEN,
984                             MC_CMD_GET_ASSERTS_OUT_LEN)];
985         const char *reason;
986         unsigned int flags;
987         unsigned int index;
988         unsigned int ofst;
989         int retry;
990         efx_rc_t rc;
991
992         /*
993          * Before we attempt to chat to the MC, we should verify that the MC
994          * isn't in it's assertion handler, either due to a previous reboot,
995          * or because we're reinitializing due to an eec_exception().
996          *
997          * Use GET_ASSERTS to read any assertion state that may be present.
998          * Retry this command twice. Once because a boot-time assertion failure
999          * might cause the 1st MCDI request to fail. And once again because
1000          * we might race with efx_mcdi_exit_assertion_handler() running on
1001          * partner port(s) on the same NIC.
1002          */
1003         retry = 2;
1004         do {
1005                 (void) memset(payload, 0, sizeof (payload));
1006                 req.emr_cmd = MC_CMD_GET_ASSERTS;
1007                 req.emr_in_buf = payload;
1008                 req.emr_in_length = MC_CMD_GET_ASSERTS_IN_LEN;
1009                 req.emr_out_buf = payload;
1010                 req.emr_out_length = MC_CMD_GET_ASSERTS_OUT_LEN;
1011
1012                 MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1);
1013                 efx_mcdi_execute_quiet(enp, &req);
1014
1015         } while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0);
1016
1017         if (req.emr_rc != 0) {
1018                 if (req.emr_rc == EACCES) {
1019                         /* Unprivileged functions cannot clear assertions. */
1020                         goto out;
1021                 }
1022                 rc = req.emr_rc;
1023                 goto fail1;
1024         }
1025
1026         if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) {
1027                 rc = EMSGSIZE;
1028                 goto fail2;
1029         }
1030
1031         /* Print out any assertion state recorded */
1032         flags = MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_GLOBAL_FLAGS);
1033         if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
1034                 return (0);
1035
1036         reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
1037                 ? "system-level assertion"
1038                 : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
1039                 ? "thread-level assertion"
1040                 : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
1041                 ? "watchdog reset"
1042                 : (flags == MC_CMD_GET_ASSERTS_FLAGS_ADDR_TRAP)
1043                 ? "illegal address trap"
1044                 : "unknown assertion";
1045         EFSYS_PROBE3(mcpu_assertion,
1046             const char *, reason, unsigned int,
1047             MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_SAVED_PC_OFFS),
1048             unsigned int,
1049             MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS));
1050
1051         /* Print out the registers (r1 ... r31) */
1052         ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST;
1053         for (index = 1;
1054                 index < 1 + MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM;
1055                 index++) {
1056                 EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int,
1057                             EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst),
1058                                             EFX_DWORD_0));
1059                 ofst += sizeof (efx_dword_t);
1060         }
1061         EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN);
1062
1063 out:
1064         return (0);
1065
1066 fail2:
1067         EFSYS_PROBE(fail2);
1068 fail1:
1069         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1070
1071         return (rc);
1072 }
1073
1074
1075 /*
1076  * Internal routines for for specific MCDI requests.
1077  */
1078
1079         __checkReturn   efx_rc_t
1080 efx_mcdi_drv_attach(
1081         __in            efx_nic_t *enp,
1082         __in            boolean_t attach)
1083 {
1084         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1085         efx_mcdi_req_t req;
1086         uint8_t payload[MAX(MC_CMD_DRV_ATTACH_IN_LEN,
1087                             MC_CMD_DRV_ATTACH_EXT_OUT_LEN)];
1088         uint32_t flags;
1089         efx_rc_t rc;
1090
1091         (void) memset(payload, 0, sizeof (payload));
1092         req.emr_cmd = MC_CMD_DRV_ATTACH;
1093         req.emr_in_buf = payload;
1094         req.emr_in_length = MC_CMD_DRV_ATTACH_IN_LEN;
1095         req.emr_out_buf = payload;
1096         req.emr_out_length = MC_CMD_DRV_ATTACH_EXT_OUT_LEN;
1097
1098         /*
1099          * Use DONT_CARE for the datapath firmware type to ensure that the
1100          * driver can attach to an unprivileged function. The datapath firmware
1101          * type to use is controlled by the 'sfboot' utility.
1102          */
1103         MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_NEW_STATE, attach ? 1 : 0);
1104         MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_UPDATE, 1);
1105         MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_FIRMWARE_ID, MC_CMD_FW_DONT_CARE);
1106
1107         efx_mcdi_execute(enp, &req);
1108
1109         if (req.emr_rc != 0) {
1110                 rc = req.emr_rc;
1111                 goto fail1;
1112         }
1113
1114         if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) {
1115                 rc = EMSGSIZE;
1116                 goto fail2;
1117         }
1118
1119         if (attach == B_FALSE) {
1120                 flags = 0;
1121         } else if (enp->en_family == EFX_FAMILY_SIENA) {
1122                 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
1123
1124                 /* Create synthetic privileges for Siena functions */
1125                 flags = EFX_NIC_FUNC_LINKCTRL | EFX_NIC_FUNC_TRUSTED;
1126                 if (emip->emi_port == 1)
1127                         flags |= EFX_NIC_FUNC_PRIMARY;
1128         } else {
1129                 EFX_STATIC_ASSERT(EFX_NIC_FUNC_PRIMARY ==
1130                     (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_PRIMARY));
1131                 EFX_STATIC_ASSERT(EFX_NIC_FUNC_LINKCTRL ==
1132                     (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL));
1133                 EFX_STATIC_ASSERT(EFX_NIC_FUNC_TRUSTED ==
1134                     (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED));
1135
1136                 /* Save function privilege flags (EF10 and later) */
1137                 if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_EXT_OUT_LEN) {
1138                         rc = EMSGSIZE;
1139                         goto fail3;
1140                 }
1141                 flags = MCDI_OUT_DWORD(req, DRV_ATTACH_EXT_OUT_FUNC_FLAGS);
1142         }
1143         encp->enc_func_flags = flags;
1144
1145         return (0);
1146
1147 fail3:
1148         EFSYS_PROBE(fail3);
1149 fail2:
1150         EFSYS_PROBE(fail2);
1151 fail1:
1152         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1153
1154         return (rc);
1155 }
1156
1157         __checkReturn           efx_rc_t
1158 efx_mcdi_get_board_cfg(
1159         __in                    efx_nic_t *enp,
1160         __out_opt               uint32_t *board_typep,
1161         __out_opt               efx_dword_t *capabilitiesp,
1162         __out_ecount_opt(6)     uint8_t mac_addrp[6])
1163 {
1164         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
1165         efx_mcdi_req_t req;
1166         uint8_t payload[MAX(MC_CMD_GET_BOARD_CFG_IN_LEN,
1167                             MC_CMD_GET_BOARD_CFG_OUT_LENMIN)];
1168         efx_rc_t rc;
1169
1170         (void) memset(payload, 0, sizeof (payload));
1171         req.emr_cmd = MC_CMD_GET_BOARD_CFG;
1172         req.emr_in_buf = payload;
1173         req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN;
1174         req.emr_out_buf = payload;
1175         req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMIN;
1176
1177         efx_mcdi_execute(enp, &req);
1178
1179         if (req.emr_rc != 0) {
1180                 rc = req.emr_rc;
1181                 goto fail1;
1182         }
1183
1184         if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
1185                 rc = EMSGSIZE;
1186                 goto fail2;
1187         }
1188
1189         if (mac_addrp != NULL) {
1190                 uint8_t *addrp;
1191
1192                 if (emip->emi_port == 1) {
1193                         addrp = MCDI_OUT2(req, uint8_t,
1194                             GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0);
1195                 } else if (emip->emi_port == 2) {
1196                         addrp = MCDI_OUT2(req, uint8_t,
1197                             GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1);
1198                 } else {
1199                         rc = EINVAL;
1200                         goto fail3;
1201                 }
1202
1203                 EFX_MAC_ADDR_COPY(mac_addrp, addrp);
1204         }
1205
1206         if (capabilitiesp != NULL) {
1207                 if (emip->emi_port == 1) {
1208                         *capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
1209                             GET_BOARD_CFG_OUT_CAPABILITIES_PORT0);
1210                 } else if (emip->emi_port == 2) {
1211                         *capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
1212                             GET_BOARD_CFG_OUT_CAPABILITIES_PORT1);
1213                 } else {
1214                         rc = EINVAL;
1215                         goto fail4;
1216                 }
1217         }
1218
1219         if (board_typep != NULL) {
1220                 *board_typep = MCDI_OUT_DWORD(req,
1221                     GET_BOARD_CFG_OUT_BOARD_TYPE);
1222         }
1223
1224         return (0);
1225
1226 fail4:
1227         EFSYS_PROBE(fail4);
1228 fail3:
1229         EFSYS_PROBE(fail3);
1230 fail2:
1231         EFSYS_PROBE(fail2);
1232 fail1:
1233         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1234
1235         return (rc);
1236 }
1237
1238         __checkReturn   efx_rc_t
1239 efx_mcdi_get_resource_limits(
1240         __in            efx_nic_t *enp,
1241         __out_opt       uint32_t *nevqp,
1242         __out_opt       uint32_t *nrxqp,
1243         __out_opt       uint32_t *ntxqp)
1244 {
1245         efx_mcdi_req_t req;
1246         uint8_t payload[MAX(MC_CMD_GET_RESOURCE_LIMITS_IN_LEN,
1247                             MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN)];
1248         efx_rc_t rc;
1249
1250         (void) memset(payload, 0, sizeof (payload));
1251         req.emr_cmd = MC_CMD_GET_RESOURCE_LIMITS;
1252         req.emr_in_buf = payload;
1253         req.emr_in_length = MC_CMD_GET_RESOURCE_LIMITS_IN_LEN;
1254         req.emr_out_buf = payload;
1255         req.emr_out_length = MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN;
1256
1257         efx_mcdi_execute(enp, &req);
1258
1259         if (req.emr_rc != 0) {
1260                 rc = req.emr_rc;
1261                 goto fail1;
1262         }
1263
1264         if (req.emr_out_length_used < MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) {
1265                 rc = EMSGSIZE;
1266                 goto fail2;
1267         }
1268
1269         if (nevqp != NULL)
1270                 *nevqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_EVQ);
1271         if (nrxqp != NULL)
1272                 *nrxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ);
1273         if (ntxqp != NULL)
1274                 *ntxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ);
1275
1276         return (0);
1277
1278 fail2:
1279         EFSYS_PROBE(fail2);
1280 fail1:
1281         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1282
1283         return (rc);
1284 }
1285
1286         __checkReturn   efx_rc_t
1287 efx_mcdi_get_phy_cfg(
1288         __in            efx_nic_t *enp)
1289 {
1290         efx_port_t *epp = &(enp->en_port);
1291         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1292         efx_mcdi_req_t req;
1293         uint8_t payload[MAX(MC_CMD_GET_PHY_CFG_IN_LEN,
1294                             MC_CMD_GET_PHY_CFG_OUT_LEN)];
1295         efx_rc_t rc;
1296
1297         (void) memset(payload, 0, sizeof (payload));
1298         req.emr_cmd = MC_CMD_GET_PHY_CFG;
1299         req.emr_in_buf = payload;
1300         req.emr_in_length = MC_CMD_GET_PHY_CFG_IN_LEN;
1301         req.emr_out_buf = payload;
1302         req.emr_out_length = MC_CMD_GET_PHY_CFG_OUT_LEN;
1303
1304         efx_mcdi_execute(enp, &req);
1305
1306         if (req.emr_rc != 0) {
1307                 rc = req.emr_rc;
1308                 goto fail1;
1309         }
1310
1311         if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) {
1312                 rc = EMSGSIZE;
1313                 goto fail2;
1314         }
1315
1316         encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE);
1317 #if EFSYS_OPT_NAMES
1318         (void) strncpy(encp->enc_phy_name,
1319                 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME),
1320                 MIN(sizeof (encp->enc_phy_name) - 1,
1321                     MC_CMD_GET_PHY_CFG_OUT_NAME_LEN));
1322 #endif  /* EFSYS_OPT_NAMES */
1323         (void) memset(encp->enc_phy_revision, 0,
1324             sizeof (encp->enc_phy_revision));
1325         memcpy(encp->enc_phy_revision,
1326                 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION),
1327                 MIN(sizeof (encp->enc_phy_revision) - 1,
1328                     MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN));
1329 #if EFSYS_OPT_PHY_LED_CONTROL
1330         encp->enc_led_mask = ((1 << EFX_PHY_LED_DEFAULT) |
1331                             (1 << EFX_PHY_LED_OFF) |
1332                             (1 << EFX_PHY_LED_ON));
1333 #endif  /* EFSYS_OPT_PHY_LED_CONTROL */
1334
1335 #if EFSYS_OPT_PHY_PROPS
1336         encp->enc_phy_nprops  = 0;
1337 #endif  /* EFSYS_OPT_PHY_PROPS */
1338
1339         /* Get the media type of the fixed port, if recognised. */
1340         EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI);
1341         EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4);
1342         EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4);
1343         EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP);
1344         EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS);
1345         EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T);
1346         EFX_STATIC_ASSERT(MC_CMD_MEDIA_QSFP_PLUS == EFX_PHY_MEDIA_QSFP_PLUS);
1347         epp->ep_fixed_port_type =
1348                 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE);
1349         if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES)
1350                 epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID;
1351
1352         epp->ep_phy_cap_mask =
1353                 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP);
1354 #if EFSYS_OPT_PHY_FLAGS
1355         encp->enc_phy_flags_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_FLAGS);
1356 #endif  /* EFSYS_OPT_PHY_FLAGS */
1357
1358         encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT);
1359
1360         /* Populate internal state */
1361         encp->enc_mcdi_mdio_channel =
1362                 (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL);
1363
1364 #if EFSYS_OPT_PHY_STATS
1365         encp->enc_mcdi_phy_stat_mask =
1366                 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_STATS_MASK);
1367 #endif  /* EFSYS_OPT_PHY_STATS */
1368
1369 #if EFSYS_OPT_BIST
1370         encp->enc_bist_mask = 0;
1371         if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1372             GET_PHY_CFG_OUT_BIST_CABLE_SHORT))
1373                 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_SHORT);
1374         if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1375             GET_PHY_CFG_OUT_BIST_CABLE_LONG))
1376                 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_LONG);
1377         if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1378             GET_PHY_CFG_OUT_BIST))
1379                 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_NORMAL);
1380 #endif  /* EFSYS_OPT_BIST */
1381
1382         return (0);
1383
1384 fail2:
1385         EFSYS_PROBE(fail2);
1386 fail1:
1387         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1388
1389         return (rc);
1390 }
1391
1392         __checkReturn           efx_rc_t
1393 efx_mcdi_firmware_update_supported(
1394         __in                    efx_nic_t *enp,
1395         __out                   boolean_t *supportedp)
1396 {
1397         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1398         efx_rc_t rc;
1399
1400         if (emcop != NULL) {
1401                 if ((rc = emcop->emco_feature_supported(enp,
1402                             EFX_MCDI_FEATURE_FW_UPDATE, supportedp)) != 0)
1403                         goto fail1;
1404         } else {
1405                 /* Earlier devices always supported updates */
1406                 *supportedp = B_TRUE;
1407         }
1408
1409         return (0);
1410
1411 fail1:
1412         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1413
1414         return (rc);
1415 }
1416
1417         __checkReturn           efx_rc_t
1418 efx_mcdi_macaddr_change_supported(
1419         __in                    efx_nic_t *enp,
1420         __out                   boolean_t *supportedp)
1421 {
1422         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1423         efx_rc_t rc;
1424
1425         if (emcop != NULL) {
1426                 if ((rc = emcop->emco_feature_supported(enp,
1427                             EFX_MCDI_FEATURE_MACADDR_CHANGE, supportedp)) != 0)
1428                         goto fail1;
1429         } else {
1430                 /* Earlier devices always supported MAC changes */
1431                 *supportedp = B_TRUE;
1432         }
1433
1434         return (0);
1435
1436 fail1:
1437         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1438
1439         return (rc);
1440 }
1441
1442         __checkReturn           efx_rc_t
1443 efx_mcdi_link_control_supported(
1444         __in                    efx_nic_t *enp,
1445         __out                   boolean_t *supportedp)
1446 {
1447         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1448         efx_rc_t rc;
1449
1450         if (emcop != NULL) {
1451                 if ((rc = emcop->emco_feature_supported(enp,
1452                             EFX_MCDI_FEATURE_LINK_CONTROL, supportedp)) != 0)
1453                         goto fail1;
1454         } else {
1455                 /* Earlier devices always supported link control */
1456                 *supportedp = B_TRUE;
1457         }
1458
1459         return (0);
1460
1461 fail1:
1462         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1463
1464         return (rc);
1465 }
1466
1467         __checkReturn           efx_rc_t
1468 efx_mcdi_mac_spoofing_supported(
1469         __in                    efx_nic_t *enp,
1470         __out                   boolean_t *supportedp)
1471 {
1472         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1473         efx_rc_t rc;
1474
1475         if (emcop != NULL) {
1476                 if ((rc = emcop->emco_feature_supported(enp,
1477                             EFX_MCDI_FEATURE_MAC_SPOOFING, supportedp)) != 0)
1478                         goto fail1;
1479         } else {
1480                 /* Earlier devices always supported MAC spoofing */
1481                 *supportedp = B_TRUE;
1482         }
1483
1484         return (0);
1485
1486 fail1:
1487         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1488
1489         return (rc);
1490 }
1491
1492 #if EFSYS_OPT_BIST
1493
1494 #if EFSYS_OPT_HUNTINGTON
1495 /*
1496  * Enter bist offline mode. This is a fw mode which puts the NIC into a state
1497  * where memory BIST tests can be run and not much else can interfere or happen.
1498  * A reboot is required to exit this mode.
1499  */
1500         __checkReturn           efx_rc_t
1501 efx_mcdi_bist_enable_offline(
1502         __in                    efx_nic_t *enp)
1503 {
1504         efx_mcdi_req_t req;
1505         efx_rc_t rc;
1506
1507         EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_IN_LEN == 0);
1508         EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_OUT_LEN == 0);
1509
1510         req.emr_cmd = MC_CMD_ENABLE_OFFLINE_BIST;
1511         req.emr_in_buf = NULL;
1512         req.emr_in_length = 0;
1513         req.emr_out_buf = NULL;
1514         req.emr_out_length = 0;
1515
1516         efx_mcdi_execute(enp, &req);
1517
1518         if (req.emr_rc != 0) {
1519                 rc = req.emr_rc;
1520                 goto fail1;
1521         }
1522
1523         return (0);
1524
1525 fail1:
1526         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1527
1528         return (rc);
1529 }
1530 #endif /* EFSYS_OPT_HUNTINGTON */
1531
1532         __checkReturn           efx_rc_t
1533 efx_mcdi_bist_start(
1534         __in                    efx_nic_t *enp,
1535         __in                    efx_bist_type_t type)
1536 {
1537         efx_mcdi_req_t req;
1538         uint8_t payload[MAX(MC_CMD_START_BIST_IN_LEN,
1539                             MC_CMD_START_BIST_OUT_LEN)];
1540         efx_rc_t rc;
1541
1542         (void) memset(payload, 0, sizeof (payload));
1543         req.emr_cmd = MC_CMD_START_BIST;
1544         req.emr_in_buf = payload;
1545         req.emr_in_length = MC_CMD_START_BIST_IN_LEN;
1546         req.emr_out_buf = payload;
1547         req.emr_out_length = MC_CMD_START_BIST_OUT_LEN;
1548
1549         switch (type) {
1550         case EFX_BIST_TYPE_PHY_NORMAL:
1551                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST);
1552                 break;
1553         case EFX_BIST_TYPE_PHY_CABLE_SHORT:
1554                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1555                     MC_CMD_PHY_BIST_CABLE_SHORT);
1556                 break;
1557         case EFX_BIST_TYPE_PHY_CABLE_LONG:
1558                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1559                     MC_CMD_PHY_BIST_CABLE_LONG);
1560                 break;
1561         case EFX_BIST_TYPE_MC_MEM:
1562                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1563                     MC_CMD_MC_MEM_BIST);
1564                 break;
1565         case EFX_BIST_TYPE_SAT_MEM:
1566                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1567                     MC_CMD_PORT_MEM_BIST);
1568                 break;
1569         case EFX_BIST_TYPE_REG:
1570                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1571                     MC_CMD_REG_BIST);
1572                 break;
1573         default:
1574                 EFSYS_ASSERT(0);
1575         }
1576
1577         efx_mcdi_execute(enp, &req);
1578
1579         if (req.emr_rc != 0) {
1580                 rc = req.emr_rc;
1581                 goto fail1;
1582         }
1583
1584         return (0);
1585
1586 fail1:
1587         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1588
1589         return (rc);
1590 }
1591
1592 #endif /* EFSYS_OPT_BIST */
1593
1594
1595 /* Enable logging of some events (e.g. link state changes) */
1596         __checkReturn   efx_rc_t
1597 efx_mcdi_log_ctrl(
1598         __in            efx_nic_t *enp)
1599 {
1600         efx_mcdi_req_t req;
1601         uint8_t payload[MAX(MC_CMD_LOG_CTRL_IN_LEN,
1602                             MC_CMD_LOG_CTRL_OUT_LEN)];
1603         efx_rc_t rc;
1604
1605         (void) memset(payload, 0, sizeof (payload));
1606         req.emr_cmd = MC_CMD_LOG_CTRL;
1607         req.emr_in_buf = payload;
1608         req.emr_in_length = MC_CMD_LOG_CTRL_IN_LEN;
1609         req.emr_out_buf = payload;
1610         req.emr_out_length = MC_CMD_LOG_CTRL_OUT_LEN;
1611
1612         MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST,
1613                     MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ);
1614         MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST_EVQ, 0);
1615
1616         efx_mcdi_execute(enp, &req);
1617
1618         if (req.emr_rc != 0) {
1619                 rc = req.emr_rc;
1620                 goto fail1;
1621         }
1622
1623         return (0);
1624
1625 fail1:
1626         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1627
1628         return (rc);
1629 }
1630
1631
1632 #if EFSYS_OPT_MAC_STATS
1633
1634 typedef enum efx_stats_action_e
1635 {
1636         EFX_STATS_CLEAR,
1637         EFX_STATS_UPLOAD,
1638         EFX_STATS_ENABLE_NOEVENTS,
1639         EFX_STATS_ENABLE_EVENTS,
1640         EFX_STATS_DISABLE,
1641 } efx_stats_action_t;
1642
1643 static  __checkReturn   efx_rc_t
1644 efx_mcdi_mac_stats(
1645         __in            efx_nic_t *enp,
1646         __in_opt        efsys_mem_t *esmp,
1647         __in            efx_stats_action_t action)
1648 {
1649         efx_mcdi_req_t req;
1650         uint8_t payload[MAX(MC_CMD_MAC_STATS_IN_LEN,
1651                             MC_CMD_MAC_STATS_OUT_DMA_LEN)];
1652         int clear = (action == EFX_STATS_CLEAR);
1653         int upload = (action == EFX_STATS_UPLOAD);
1654         int enable = (action == EFX_STATS_ENABLE_NOEVENTS);
1655         int events = (action == EFX_STATS_ENABLE_EVENTS);
1656         int disable = (action == EFX_STATS_DISABLE);
1657         efx_rc_t rc;
1658
1659         (void) memset(payload, 0, sizeof (payload));
1660         req.emr_cmd = MC_CMD_MAC_STATS;
1661         req.emr_in_buf = payload;
1662         req.emr_in_length = MC_CMD_MAC_STATS_IN_LEN;
1663         req.emr_out_buf = payload;
1664         req.emr_out_length = MC_CMD_MAC_STATS_OUT_DMA_LEN;
1665
1666         MCDI_IN_POPULATE_DWORD_6(req, MAC_STATS_IN_CMD,
1667             MAC_STATS_IN_DMA, upload,
1668             MAC_STATS_IN_CLEAR, clear,
1669             MAC_STATS_IN_PERIODIC_CHANGE, enable | events | disable,
1670             MAC_STATS_IN_PERIODIC_ENABLE, enable | events,
1671             MAC_STATS_IN_PERIODIC_NOEVENT, !events,
1672             MAC_STATS_IN_PERIOD_MS, (enable | events) ? 1000: 0);
1673
1674         if (esmp != NULL) {
1675                 int bytes = MC_CMD_MAC_NSTATS * sizeof (uint64_t);
1676
1677                 EFX_STATIC_ASSERT(MC_CMD_MAC_NSTATS * sizeof (uint64_t) <=
1678                     EFX_MAC_STATS_SIZE);
1679
1680                 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_LO,
1681                             EFSYS_MEM_ADDR(esmp) & 0xffffffff);
1682                 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_HI,
1683                             EFSYS_MEM_ADDR(esmp) >> 32);
1684                 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_LEN, bytes);
1685         } else {
1686                 EFSYS_ASSERT(!upload && !enable && !events);
1687         }
1688
1689         /*
1690          * NOTE: Do not use EVB_PORT_ID_ASSIGNED when disabling periodic stats,
1691          *       as this may fail (and leave periodic DMA enabled) if the
1692          *       vadapter has already been deleted.
1693          */
1694         MCDI_IN_SET_DWORD(req, MAC_STATS_IN_PORT_ID,
1695             (disable ? EVB_PORT_ID_NULL : enp->en_vport_id));
1696
1697         efx_mcdi_execute(enp, &req);
1698
1699         if (req.emr_rc != 0) {
1700                 /* EF10: Expect ENOENT if no DMA queues are initialised */
1701                 if ((req.emr_rc != ENOENT) ||
1702                     (enp->en_rx_qcount + enp->en_tx_qcount != 0)) {
1703                         rc = req.emr_rc;
1704                         goto fail1;
1705                 }
1706         }
1707
1708         return (0);
1709
1710 fail1:
1711         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1712
1713         return (rc);
1714 }
1715
1716         __checkReturn   efx_rc_t
1717 efx_mcdi_mac_stats_clear(
1718         __in            efx_nic_t *enp)
1719 {
1720         efx_rc_t rc;
1721
1722         if ((rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_CLEAR)) != 0)
1723                 goto fail1;
1724
1725         return (0);
1726
1727 fail1:
1728         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1729
1730         return (rc);
1731 }
1732
1733         __checkReturn   efx_rc_t
1734 efx_mcdi_mac_stats_upload(
1735         __in            efx_nic_t *enp,
1736         __in            efsys_mem_t *esmp)
1737 {
1738         efx_rc_t rc;
1739
1740         /*
1741          * The MC DMAs aggregate statistics for our convenience, so we can
1742          * avoid having to pull the statistics buffer into the cache to
1743          * maintain cumulative statistics.
1744          */
1745         if ((rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_UPLOAD)) != 0)
1746                 goto fail1;
1747
1748         return (0);
1749
1750 fail1:
1751         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1752
1753         return (rc);
1754 }
1755
1756         __checkReturn   efx_rc_t
1757 efx_mcdi_mac_stats_periodic(
1758         __in            efx_nic_t *enp,
1759         __in            efsys_mem_t *esmp,
1760         __in            uint16_t period,
1761         __in            boolean_t events)
1762 {
1763         efx_rc_t rc;
1764
1765         /*
1766          * The MC DMAs aggregate statistics for our convenience, so we can
1767          * avoid having to pull the statistics buffer into the cache to
1768          * maintain cumulative statistics.
1769          * Huntington uses a fixed 1sec period, so use that on Siena too.
1770          */
1771         if (period == 0)
1772                 rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_DISABLE);
1773         else if (events)
1774                 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_EVENTS);
1775         else
1776                 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_NOEVENTS);
1777
1778         if (rc != 0)
1779                 goto fail1;
1780
1781         return (0);
1782
1783 fail1:
1784         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1785
1786         return (rc);
1787 }
1788
1789 #endif  /* EFSYS_OPT_MAC_STATS */
1790
1791 #if EFSYS_OPT_HUNTINGTON
1792
1793 /*
1794  * This function returns the pf and vf number of a function.  If it is a pf the
1795  * vf number is 0xffff.  The vf number is the index of the vf on that
1796  * function. So if you have 3 vfs on pf 0 the 3 vfs will return (pf=0,vf=0),
1797  * (pf=0,vf=1), (pf=0,vf=2) aand the pf will return (pf=0, vf=0xffff).
1798  */
1799         __checkReturn           efx_rc_t
1800 efx_mcdi_get_function_info(
1801         __in                    efx_nic_t *enp,
1802         __out                   uint32_t *pfp,
1803         __out_opt               uint32_t *vfp)
1804 {
1805         efx_mcdi_req_t req;
1806         uint8_t payload[MAX(MC_CMD_GET_FUNCTION_INFO_IN_LEN,
1807                             MC_CMD_GET_FUNCTION_INFO_OUT_LEN)];
1808         efx_rc_t rc;
1809
1810         (void) memset(payload, 0, sizeof (payload));
1811         req.emr_cmd = MC_CMD_GET_FUNCTION_INFO;
1812         req.emr_in_buf = payload;
1813         req.emr_in_length = MC_CMD_GET_FUNCTION_INFO_IN_LEN;
1814         req.emr_out_buf = payload;
1815         req.emr_out_length = MC_CMD_GET_FUNCTION_INFO_OUT_LEN;
1816
1817         efx_mcdi_execute(enp, &req);
1818
1819         if (req.emr_rc != 0) {
1820                 rc = req.emr_rc;
1821                 goto fail1;
1822         }
1823
1824         if (req.emr_out_length_used < MC_CMD_GET_FUNCTION_INFO_OUT_LEN) {
1825                 rc = EMSGSIZE;
1826                 goto fail2;
1827         }
1828
1829         *pfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_PF);
1830         if (vfp != NULL)
1831                 *vfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_VF);
1832
1833         return (0);
1834
1835 fail2:
1836         EFSYS_PROBE(fail2);
1837 fail1:
1838         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1839
1840         return (rc);
1841 }
1842
1843         __checkReturn           efx_rc_t
1844 efx_mcdi_privilege_mask(
1845         __in                    efx_nic_t *enp,
1846         __in                    uint32_t pf,
1847         __in                    uint32_t vf,
1848         __out                   uint32_t *maskp)
1849 {
1850         efx_mcdi_req_t req;
1851         uint8_t payload[MAX(MC_CMD_PRIVILEGE_MASK_IN_LEN,
1852                             MC_CMD_PRIVILEGE_MASK_OUT_LEN)];
1853         efx_rc_t rc;
1854
1855         (void) memset(payload, 0, sizeof (payload));
1856         req.emr_cmd = MC_CMD_PRIVILEGE_MASK;
1857         req.emr_in_buf = payload;
1858         req.emr_in_length = MC_CMD_PRIVILEGE_MASK_IN_LEN;
1859         req.emr_out_buf = payload;
1860         req.emr_out_length = MC_CMD_PRIVILEGE_MASK_OUT_LEN;
1861
1862         MCDI_IN_POPULATE_DWORD_2(req, PRIVILEGE_MASK_IN_FUNCTION,
1863             PRIVILEGE_MASK_IN_FUNCTION_PF, pf,
1864             PRIVILEGE_MASK_IN_FUNCTION_VF, vf);
1865
1866         efx_mcdi_execute(enp, &req);
1867
1868         if (req.emr_rc != 0) {
1869                 rc = req.emr_rc;
1870                 goto fail1;
1871         }
1872
1873         if (req.emr_out_length_used < MC_CMD_PRIVILEGE_MASK_OUT_LEN) {
1874                 rc = EMSGSIZE;
1875                 goto fail2;
1876         }
1877
1878         *maskp = MCDI_OUT_DWORD(req, PRIVILEGE_MASK_OUT_OLD_MASK);
1879
1880         return (0);
1881
1882 fail2:
1883         EFSYS_PROBE(fail2);
1884 fail1:
1885         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1886
1887         return (rc);
1888 }
1889
1890 #endif /* EFSYS_OPT_HUNTINGTON */
1891
1892         __checkReturn           efx_rc_t
1893 efx_mcdi_set_workaround(
1894         __in                    efx_nic_t *enp,
1895         __in                    uint32_t type,
1896         __in                    boolean_t enabled,
1897         __out_opt               uint32_t *flagsp)
1898 {
1899         efx_mcdi_req_t req;
1900         uint8_t payload[MAX(MC_CMD_WORKAROUND_IN_LEN,
1901                             MC_CMD_WORKAROUND_EXT_OUT_LEN)];
1902         efx_rc_t rc;
1903
1904         (void) memset(payload, 0, sizeof (payload));
1905         req.emr_cmd = MC_CMD_WORKAROUND;
1906         req.emr_in_buf = payload;
1907         req.emr_in_length = MC_CMD_WORKAROUND_IN_LEN;
1908         req.emr_out_buf = payload;
1909         req.emr_out_length = MC_CMD_WORKAROUND_OUT_LEN;
1910
1911         MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, type);
1912         MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, enabled ? 1 : 0);
1913
1914         efx_mcdi_execute_quiet(enp, &req);
1915
1916         if (req.emr_rc != 0) {
1917                 rc = req.emr_rc;
1918                 goto fail1;
1919         }
1920
1921         if (flagsp != NULL) {
1922                 if (req.emr_out_length_used >= MC_CMD_WORKAROUND_EXT_OUT_LEN)
1923                         *flagsp = MCDI_OUT_DWORD(req, WORKAROUND_EXT_OUT_FLAGS);
1924                 else
1925                         *flagsp = 0;
1926         }
1927
1928         return (0);
1929
1930 fail1:
1931         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1932
1933         return (rc);
1934 }
1935
1936
1937         __checkReturn           efx_rc_t
1938 efx_mcdi_get_workarounds(
1939         __in                    efx_nic_t *enp,
1940         __out_opt               uint32_t *implementedp,
1941         __out_opt               uint32_t *enabledp)
1942 {
1943         efx_mcdi_req_t req;
1944         uint8_t payload[MC_CMD_GET_WORKAROUNDS_OUT_LEN];
1945         efx_rc_t rc;
1946
1947         (void) memset(payload, 0, sizeof (payload));
1948         req.emr_cmd = MC_CMD_GET_WORKAROUNDS;
1949         req.emr_in_buf = NULL;
1950         req.emr_in_length = 0;
1951         req.emr_out_buf = payload;
1952         req.emr_out_length = MC_CMD_GET_WORKAROUNDS_OUT_LEN;
1953
1954         efx_mcdi_execute(enp, &req);
1955
1956         if (req.emr_rc != 0) {
1957                 rc = req.emr_rc;
1958                 goto fail1;
1959         }
1960
1961         if (implementedp != NULL) {
1962                 *implementedp =
1963                     MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_IMPLEMENTED);
1964         }
1965
1966         if (enabledp != NULL) {
1967                 *enabledp = MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_ENABLED);
1968         }
1969
1970         return (0);
1971
1972 fail1:
1973         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1974
1975         return (rc);
1976 }
1977
1978
1979 #endif  /* EFSYS_OPT_MCDI */