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