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