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