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