1 /*
2 * Copyright 2008-2013 Solarflare Communications Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 #include "efsys.h"
27 #include "efx.h"
28 #include "efx_types.h"
29 #include "efx_regs.h"
30 #include "efx_regs_mcdi.h"
31 #include "efx_impl.h"
32
33 #if EFSYS_OPT_MCDI
34
35 /*
36 * A reboot/assertion causes the MCDI status word to be set after the
37 * command word is set or a REBOOT event is sent. If we notice a reboot
38 * via these mechanisms then wait 10ms for the status word to be set.
39 */
40 #define MCDI_STATUS_SLEEP_US 10000
41
42 void
43 efx_mcdi_request_start(
44 __in efx_nic_t *enp,
45 __in efx_mcdi_req_t *emrp,
46 __in boolean_t ev_cpl)
47 {
48 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
49 efx_dword_t dword;
50 unsigned int seq;
51 unsigned int xflags;
52 unsigned int pdur;
53 unsigned int dbr;
54 unsigned int pos;
55 int state;
56
57 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
58 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
59 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
60
61 switch (emip->emi_port) {
62 case 1:
63 pdur = MC_SMEM_P0_PDU_OFST >> 2;
64 dbr = MC_SMEM_P0_DOORBELL_OFST >> 2;
65 break;
66 case 2:
67 pdur = MC_SMEM_P1_PDU_OFST >> 2;
68 dbr = MC_SMEM_P1_DOORBELL_OFST >> 2;
69 break;
70 default:
71 EFSYS_ASSERT(0);
72 pdur = dbr = 0;
73 };
74
75 /*
76 * efx_mcdi_request_start() is naturally serialised against both
77 * efx_mcdi_request_poll() and efx_mcdi_ev_cpl()/efx_mcdi_ev_death(),
78 * by virtue of there only being one oustanding MCDI request.
79 * Unfortunately, upper layers may also call efx_mcdi_request_abort()
80 * at any time, to timeout a pending mcdi request, That request may
81 * then subsequently complete, meaning efx_mcdi_ev_cpl() or
82 * efx_mcdi_ev_death() may end up running in parallel with
83 * efx_mcdi_request_start(). This race is handled by ensuring that
84 * %emi_pending_req, %emi_ev_cpl and %emi_seq are protected by the
85 * en_eslp lock.
86 */
87 EFSYS_LOCK(enp->en_eslp, state);
88 EFSYS_ASSERT(emip->emi_pending_req == NULL);
89 emip->emi_pending_req = emrp;
90 emip->emi_ev_cpl = ev_cpl;
91 emip->emi_poll_cnt = 0;
92 seq = emip->emi_seq++ & 0xf;
93 EFSYS_UNLOCK(enp->en_eslp, state);
94
95 xflags = 0;
96 if (ev_cpl)
97 xflags |= MCDI_HEADER_XFLAGS_EVREQ;
98
99 /* Construct the header in shared memory */
100 EFX_POPULATE_DWORD_6(dword,
101 MCDI_HEADER_CODE, emrp->emr_cmd,
102 MCDI_HEADER_RESYNC, 1,
103 MCDI_HEADER_DATALEN, emrp->emr_in_length,
104 MCDI_HEADER_SEQ, seq,
105 MCDI_HEADER_RESPONSE, 0,
106 MCDI_HEADER_XFLAGS, xflags);
107 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, pdur, &dword, B_TRUE);
108
109 for (pos = 0; pos < emrp->emr_in_length; pos += sizeof (efx_dword_t)) {
110 memcpy(&dword, MCDI_IN(*emrp, efx_dword_t, pos),
111 MIN(sizeof (dword), emrp->emr_in_length - pos));
112 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM,
113 pdur + 1 + (pos >> 2), &dword, B_FALSE);
114 }
115
116 /* Ring the doorbell */
117 EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 0xd004be11);
118 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, dbr, &dword, B_FALSE);
119 }
120
121 static void
122 efx_mcdi_request_copyout(
123 __in efx_nic_t *enp,
124 __in efx_mcdi_req_t *emrp)
125 {
126 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
127 unsigned int pos;
128 unsigned int pdur;
129 efx_dword_t data;
130
131 pdur = (emip->emi_port == 1)
132 ? MC_SMEM_P0_PDU_OFST >> 2
133 : MC_SMEM_P1_PDU_OFST >> 2;
134
135 /* Copy payload out if caller supplied buffer */
136 if (emrp->emr_out_buf != NULL) {
137 size_t bytes = MIN(emrp->emr_out_length_used,
138 emrp->emr_out_length);
139 for (pos = 0; pos < bytes; pos += sizeof (efx_dword_t)) {
140 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM,
141 pdur + 1 + (pos >> 2), &data, B_FALSE);
142 memcpy(MCDI_OUT(*emrp, efx_dword_t, pos), &data,
143 MIN(sizeof (data), bytes - pos));
144 }
145 }
146 }
147
148 static int
149 efx_mcdi_request_errcode(
150 __in unsigned int err)
151 {
152
153 switch (err) {
154 case MC_CMD_ERR_ENOENT:
155 return (ENOENT);
156 case MC_CMD_ERR_EINTR:
157 return (EINTR);
158 case MC_CMD_ERR_EACCES:
159 return (EACCES);
160 case MC_CMD_ERR_EBUSY:
161 return (EBUSY);
162 case MC_CMD_ERR_EINVAL:
163 return (EINVAL);
164 case MC_CMD_ERR_EDEADLK:
165 return (EDEADLK);
166 case MC_CMD_ERR_ENOSYS:
167 return (ENOTSUP);
168 case MC_CMD_ERR_ETIME:
169 return (ETIMEDOUT);
170 #ifdef WITH_MCDI_V2
171 case MC_CMD_ERR_EAGAIN:
172 return (EAGAIN);
173 case MC_CMD_ERR_ENOSPC:
174 return (ENOSPC);
175 #endif
176 default:
177 EFSYS_PROBE1(mc_pcol_error, int, err);
178 return (EIO);
179 }
180 }
181
182 static void
183 efx_mcdi_raise_exception(
184 __in efx_nic_t *enp,
185 __in_opt efx_mcdi_req_t *emrp,
186 __in int rc)
187 {
188 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
189 const efx_mcdi_transport_t *emtp = emip->emi_mtp;
190 efx_mcdi_exception_t exception;
191
192 /* Reboot or Assertion failure only */
193 EFSYS_ASSERT(rc == EIO || rc == EINTR);
194
195 /*
196 * If MC_CMD_REBOOT causes a reboot (dependent on parameters),
197 * then the EIO is not worthy of an exception.
198 */
199 if (emrp != NULL && emrp->emr_cmd == MC_CMD_REBOOT && rc == EIO)
200 return;
201
202 exception = (rc == EIO)
203 ? EFX_MCDI_EXCEPTION_MC_REBOOT
204 : EFX_MCDI_EXCEPTION_MC_BADASSERT;
205
206 emtp->emt_exception(emtp->emt_context, exception);
207 }
208
209 static int
210 efx_mcdi_poll_reboot(
211 __in efx_nic_t *enp)
212 {
213 #if 1
214 /*
215 * XXX Bug 25922, bug 26099: This function is not being used
216 * properly. Until its callers are fixed, it should always
217 * return 0.
218 */
219 _NOTE(ARGUNUSED(enp))
220 return (0);
221 #else
222 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
223 unsigned int rebootr;
224 efx_dword_t dword;
225 uint32_t value;
226
227 EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
228 rebootr = ((emip->emi_port == 1)
229 ? MC_SMEM_P0_STATUS_OFST >> 2
230 : MC_SMEM_P1_STATUS_OFST >> 2);
231
232 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE);
233 value = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
234
235 if (value == 0)
236 return (0);
237
238 EFX_ZERO_DWORD(dword);
239 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE);
240
241 if (value == MC_STATUS_DWORD_ASSERT)
242 return (EINTR);
243 else
244 return (EIO);
245 #endif
246 }
247
248 __checkReturn boolean_t
249 efx_mcdi_request_poll(
250 __in efx_nic_t *enp)
251 {
252 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
253 efx_mcdi_req_t *emrp;
254 efx_dword_t dword;
255 unsigned int pdur;
256 unsigned int seq;
257 unsigned int length;
258 int state;
259 int rc;
260
261 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
262 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
263 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
264 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
265
266 /* Serialise against post-watchdog efx_mcdi_ev* */
267 EFSYS_LOCK(enp->en_eslp, state);
268
269 EFSYS_ASSERT(emip->emi_pending_req != NULL);
270 EFSYS_ASSERT(!emip->emi_ev_cpl);
271 emrp = emip->emi_pending_req;
272
273 /* Check for reboot atomically w.r.t efx_mcdi_request_start */
274 if (emip->emi_poll_cnt++ == 0) {
275 if ((rc = efx_mcdi_poll_reboot(enp)) != 0) {
276 emip->emi_pending_req = NULL;
277 EFSYS_UNLOCK(enp->en_eslp, state);
278
279 goto fail1;
280 }
281 }
282
283 EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
284 pdur = (emip->emi_port == 1)
285 ? MC_SMEM_P0_PDU_OFST >> 2
286 : MC_SMEM_P1_PDU_OFST >> 2;
287
288 /* Read the command header */
289 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, pdur, &dword, B_FALSE);
290 if (EFX_DWORD_FIELD(dword, MCDI_HEADER_RESPONSE) == 0) {
291 EFSYS_UNLOCK(enp->en_eslp, state);
292 return (B_FALSE);
293 }
294
295 /* Request complete */
296 emip->emi_pending_req = NULL;
297 seq = (emip->emi_seq - 1) & 0xf;
298
299 /* Check for synchronous reboot */
300 if (EFX_DWORD_FIELD(dword, MCDI_HEADER_ERROR) != 0 &&
301 EFX_DWORD_FIELD(dword, MCDI_HEADER_DATALEN) == 0) {
302 /* Consume status word */
303 EFSYS_SPIN(MCDI_STATUS_SLEEP_US);
304 efx_mcdi_poll_reboot(enp);
305 EFSYS_UNLOCK(enp->en_eslp, state);
306 rc = EIO;
307 goto fail2;
308 }
309
310 EFSYS_UNLOCK(enp->en_eslp, state);
311
312 /* Check that the returned data is consistent */
313 if (EFX_DWORD_FIELD(dword, MCDI_HEADER_CODE) != emrp->emr_cmd ||
314 EFX_DWORD_FIELD(dword, MCDI_HEADER_SEQ) != seq) {
315 /* Response is for a different request */
316 rc = EIO;
317 goto fail3;
318 }
319
320 length = EFX_DWORD_FIELD(dword, MCDI_HEADER_DATALEN);
321 if (EFX_DWORD_FIELD(dword, MCDI_HEADER_ERROR)) {
322 efx_dword_t errdword;
323 int errcode;
324
325 EFSYS_ASSERT3U(length, ==, 4);
326 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM,
327 pdur + 1 + (MC_CMD_ERR_CODE_OFST >> 2),
328 &errdword, B_FALSE);
329 errcode = EFX_DWORD_FIELD(errdword, EFX_DWORD_0);
330 rc = efx_mcdi_request_errcode(errcode);
331 EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd, int, errcode);
332 goto fail4;
333
334 } else {
335 emrp->emr_out_length_used = length;
336 emrp->emr_rc = 0;
337 efx_mcdi_request_copyout(enp, emrp);
338 }
339
340 goto out;
341
342 fail4:
343 EFSYS_PROBE(fail4);
344 fail3:
345 EFSYS_PROBE(fail3);
346 fail2:
347 EFSYS_PROBE(fail2);
348 fail1:
349 EFSYS_PROBE1(fail1, int, rc);
350
351 /* Fill out error state */
352 emrp->emr_rc = rc;
353 emrp->emr_out_length_used = 0;
354
355 /* Reboot/Assertion */
356 if (rc == EIO || rc == EINTR)
357 efx_mcdi_raise_exception(enp, emrp, rc);
358
359 out:
360 return (B_TRUE);
361 }
362
363 void
364 efx_mcdi_execute(
365 __in efx_nic_t *enp,
366 __in efx_mcdi_req_t *emrp)
367 {
368 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
369 const efx_mcdi_transport_t *emtp = emip->emi_mtp;
370
371 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
372 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
373 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
374
375 emtp->emt_execute(emtp->emt_context, emrp);
376 }
377
378 void
379 efx_mcdi_ev_cpl(
380 __in efx_nic_t *enp,
381 __in unsigned int seq,
382 __in unsigned int outlen,
383 __in int errcode)
384 {
385 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
386 const efx_mcdi_transport_t *emtp = emip->emi_mtp;
387 efx_mcdi_req_t *emrp;
388 int state;
389
390 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
391 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
392 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
393
394 /*
395 * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start()
396 * when we're completing an aborted request.
397 */
398 EFSYS_LOCK(enp->en_eslp, state);
399 if (emip->emi_pending_req == NULL || !emip->emi_ev_cpl ||
400 (seq != ((emip->emi_seq - 1) & 0xf))) {
401 EFSYS_ASSERT(emip->emi_aborted > 0);
402 if (emip->emi_aborted > 0)
403 --emip->emi_aborted;
404 EFSYS_UNLOCK(enp->en_eslp, state);
405 return;
406 }
407
408 emrp = emip->emi_pending_req;
409 emip->emi_pending_req = NULL;
410 EFSYS_UNLOCK(enp->en_eslp, state);
411
412 /*
413 * Fill out the remaining hdr fields, and copyout the payload
414 * if the user supplied an output buffer.
415 */
416 if (errcode != 0) {
417 EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd,
418 int, errcode);
419 emrp->emr_out_length_used = 0;
420 emrp->emr_rc = efx_mcdi_request_errcode(errcode);
421 } else {
422 emrp->emr_out_length_used = outlen;
423 emrp->emr_rc = 0;
424 efx_mcdi_request_copyout(enp, emrp);
425 }
426
427 emtp->emt_ev_cpl(emtp->emt_context);
428 }
429
430 void
431 efx_mcdi_ev_death(
432 __in efx_nic_t *enp,
433 __in int rc)
434 {
435 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
436 const efx_mcdi_transport_t *emtp = emip->emi_mtp;
437 efx_mcdi_req_t *emrp = NULL;
438 boolean_t ev_cpl;
439 int state;
440
441 /*
442 * The MCDI request (if there is one) has been terminated, either
443 * by a BADASSERT or REBOOT event.
444 *
445 * If there is an oustanding event-completed MCDI operation, then we
446 * will never receive the completion event (because both MCDI
447 * completions and BADASSERT events are sent to the same evq). So
448 * complete this MCDI op.
449 *
450 * This function might run in parallel with efx_mcdi_request_poll()
451 * for poll completed mcdi requests, and also with
452 * efx_mcdi_request_start() for post-watchdog completions.
453 */
454 EFSYS_LOCK(enp->en_eslp, state);
455 emrp = emip->emi_pending_req;
456 ev_cpl = emip->emi_ev_cpl;
457 if (emrp != NULL && emip->emi_ev_cpl) {
458 emip->emi_pending_req = NULL;
459
460 emrp->emr_out_length_used = 0;
461 emrp->emr_rc = rc;
462 ++emip->emi_aborted;
463 }
464
465 /*
466 * Since we're running in parallel with a request, consume the
467 * status word before dropping the lock.
468 */
469 if (rc == EIO || rc == EINTR) {
470 EFSYS_SPIN(MCDI_STATUS_SLEEP_US);
471 (void) efx_mcdi_poll_reboot(enp);
472 }
473
474 EFSYS_UNLOCK(enp->en_eslp, state);
475
476 efx_mcdi_raise_exception(enp, emrp, rc);
477
478 if (emrp != NULL && ev_cpl)
479 emtp->emt_ev_cpl(emtp->emt_context);
480 }
481
482 __checkReturn int
483 efx_mcdi_version(
484 __in efx_nic_t *enp,
485 __out_ecount_opt(4) uint16_t versionp[4],
486 __out_opt uint32_t *buildp,
487 __out_opt efx_mcdi_boot_t *statusp)
488 {
489 uint8_t outbuf[MAX(MC_CMD_GET_VERSION_OUT_LEN,
490 MC_CMD_GET_BOOT_STATUS_OUT_LEN)];
491 efx_mcdi_req_t req;
492 efx_word_t *ver_words;
493 uint16_t version[4];
494 uint32_t build;
495 efx_mcdi_boot_t status;
496 int rc;
497
498 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
499 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
500
501 EFX_STATIC_ASSERT(MC_CMD_GET_VERSION_IN_LEN == 0);
502 req.emr_cmd = MC_CMD_GET_VERSION;
503 req.emr_in_buf = NULL;
504 req.emr_in_length = 0;
505 req.emr_out_buf = outbuf;
506 req.emr_out_length = MC_CMD_GET_VERSION_OUT_LEN;
507
508 efx_mcdi_execute(enp, &req);
509
510 if (req.emr_rc != 0) {
511 rc = req.emr_rc;
512 goto fail1;
513 }
514
515 /* bootrom support */
516 if (req.emr_out_length_used == MC_CMD_GET_VERSION_V0_OUT_LEN) {
517 version[0] = version[1] = version[2] = version[3] = 0;
518 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
519
520 goto version;
521 }
522
523 if (req.emr_out_length_used < MC_CMD_GET_VERSION_OUT_LEN) {
524 rc = EMSGSIZE;
525 goto fail2;
526 }
527
528 ver_words = MCDI_OUT2(req, efx_word_t, GET_VERSION_OUT_VERSION);
529 version[0] = EFX_WORD_FIELD(ver_words[0], EFX_WORD_0);
530 version[1] = EFX_WORD_FIELD(ver_words[1], EFX_WORD_0);
531 version[2] = EFX_WORD_FIELD(ver_words[2], EFX_WORD_0);
532 version[3] = EFX_WORD_FIELD(ver_words[3], EFX_WORD_0);
533 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
534
535 version:
536 /* The bootrom doesn't understand BOOT_STATUS */
537 if (build == MC_CMD_GET_VERSION_OUT_FIRMWARE_BOOTROM) {
538 status = EFX_MCDI_BOOT_ROM;
539 goto out;
540 }
541
542 req.emr_cmd = MC_CMD_GET_BOOT_STATUS;
543 EFX_STATIC_ASSERT(MC_CMD_GET_BOOT_STATUS_IN_LEN == 0);
544 req.emr_in_buf = NULL;
545 req.emr_in_length = 0;
546 req.emr_out_buf = outbuf;
547 req.emr_out_length = MC_CMD_GET_BOOT_STATUS_OUT_LEN;
548
549 efx_mcdi_execute(enp, &req);
550
551 if (req.emr_rc != 0) {
552 rc = req.emr_rc;
553 goto fail3;
554 }
555
556 if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) {
557 rc = EMSGSIZE;
558 goto fail4;
559 }
560
561 if (MCDI_OUT_DWORD_FIELD(req, GET_BOOT_STATUS_OUT_FLAGS,
562 GET_BOOT_STATUS_OUT_FLAGS_PRIMARY))
563 status = EFX_MCDI_BOOT_PRIMARY;
564 else
565 status = EFX_MCDI_BOOT_SECONDARY;
566
567 out:
568 if (versionp != NULL)
569 memcpy(versionp, version, sizeof (version));
570 if (buildp != NULL)
571 *buildp = build;
572 if (statusp != NULL)
573 *statusp = status;
574
575 return (0);
576
577 fail4:
578 EFSYS_PROBE(fail4);
579 fail3:
580 EFSYS_PROBE(fail3);
581 fail2:
582 EFSYS_PROBE(fail2);
583 fail1:
584 EFSYS_PROBE1(fail1, int, rc);
585
586 return (rc);
587 }
588
589 __checkReturn int
590 efx_mcdi_init(
591 __in efx_nic_t *enp,
592 __in const efx_mcdi_transport_t *mtp)
593 {
594 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
595 efx_oword_t oword;
596 unsigned int portnum;
597 int rc;
598
599 EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
600 enp->en_mod_flags |= EFX_MOD_MCDI;
601
602 if (enp->en_family == EFX_FAMILY_FALCON)
603 return (0);
604
605 emip->emi_mtp = mtp;
606
607 /* Determine the port number to use for MCDI */
608 EFX_BAR_READO(enp, FR_AZ_CS_DEBUG_REG, &oword);
609 portnum = EFX_OWORD_FIELD(oword, FRF_CZ_CS_PORT_NUM);
610
611 if (portnum == 0) {
612 /* Presumably booted from ROM; only MCDI port 1 will work */
613 emip->emi_port = 1;
614 } else if (portnum <= 2) {
615 emip->emi_port = portnum;
616 } else {
617 rc = EINVAL;
618 goto fail1;
619 }
620
621 /*
622 * Wipe the atomic reboot status so subsequent MCDI requests succeed.
623 * BOOT_STATUS is preserved so eno_nic_probe() can boot out of the
624 * assertion handler.
625 */
626 (void) efx_mcdi_poll_reboot(enp);
627
628 return (0);
629
630 fail1:
631 EFSYS_PROBE1(fail1, int, rc);
632
633 enp->en_mod_flags &= ~EFX_MOD_MCDI;
634
635 return (rc);
636 }
637
638
639 __checkReturn int
640 efx_mcdi_reboot(
641 __in efx_nic_t *enp)
642 {
643 uint8_t payload[MC_CMD_REBOOT_IN_LEN];
644 efx_mcdi_req_t req;
645 int rc;
646
647 /*
648 * We could require the caller to have caused en_mod_flags=0 to
649 * call this function. This doesn't help the other port though,
650 * who's about to get the MC ripped out from underneath them.
651 * Since they have to cope with the subsequent fallout of MCDI
652 * failures, we should as well.
653 */
654 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
655
656 req.emr_cmd = MC_CMD_REBOOT;
657 req.emr_in_buf = payload;
658 req.emr_in_length = MC_CMD_REBOOT_IN_LEN;
659 req.emr_out_buf = NULL;
660 req.emr_out_length = 0;
661
662 MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS, 0);
663
664 efx_mcdi_execute(enp, &req);
665
666 /* Invert EIO */
667 if (req.emr_rc != EIO) {
668 rc = EIO;
669 goto fail1;
670 }
671
672 return (0);
673
674 fail1:
675 EFSYS_PROBE1(fail1, int, rc);
676
677 return (rc);
678 }
679
680 __checkReturn boolean_t
681 efx_mcdi_request_abort(
682 __in efx_nic_t *enp)
683 {
684 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
685 efx_mcdi_req_t *emrp;
686 boolean_t aborted;
687 int state;
688
689 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
690 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
691
692 /*
693 * efx_mcdi_ev_* may have already completed this event, and be
694 * spinning/blocked on the upper layer lock. So it *is* legitimate
695 * to for emi_pending_req to be NULL. If there is a pending event
696 * completed request, then provide a "credit" to allow
697 * efx_mcdi_ev_cpl() to accept a single spurious completion.
698 */
699 EFSYS_LOCK(enp->en_eslp, state);
700 emrp = emip->emi_pending_req;
701 aborted = (emrp != NULL);
702 if (aborted) {
703 emip->emi_pending_req = NULL;
704
705 /* Error the request */
706 emrp->emr_out_length_used = 0;
707 emrp->emr_rc = ETIMEDOUT;
708
709 /* Provide a credit for seqno/emr_pending_req mismatches */
710 if (emip->emi_ev_cpl)
711 ++emip->emi_aborted;
712
713 /*
714 * The upper layer has called us, so we don't
715 * need to complete the request.
716 */
717 }
718 EFSYS_UNLOCK(enp->en_eslp, state);
719
720 return (aborted);
721 }
722
723 void
724 efx_mcdi_fini(
725 __in efx_nic_t *enp)
726 {
727 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
728
729 EFSYS_ASSERT3U(enp->en_mod_flags, ==, EFX_MOD_MCDI);
730 enp->en_mod_flags &= ~EFX_MOD_MCDI;
731
732 if (~(enp->en_features) & EFX_FEATURE_MCDI)
733 return;
734
735 emip->emi_mtp = NULL;
736 emip->emi_port = 0;
737 emip->emi_aborted = 0;
738 }
739
740 #endif /* EFSYS_OPT_MCDI */