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/types.h>
32 #include <sys/ddi.h>
33 #include <sys/sunddi.h>
34 #include <sys/atomic.h>
35 #include <sys/modctl.h>
36 #include <sys/conf.h>
37 #include <sys/ethernet.h>
38 #include <sys/pci.h>
39 #include <sys/pcie.h>
40
41 #include "sfxge.h"
42
43 #include "efx.h"
44
45
46 /* Interrupt table DMA attributes */
47 static ddi_device_acc_attr_t sfxge_intr_devacc = {
48
49 DDI_DEVICE_ATTR_V0, /* devacc_attr_version */
50 DDI_NEVERSWAP_ACC, /* devacc_attr_endian_flags */
51 DDI_STRICTORDER_ACC /* devacc_attr_dataorder */
52 };
53
54 static ddi_dma_attr_t sfxge_intr_dma_attr = {
55 DMA_ATTR_V0, /* dma_attr_version */
56 0, /* dma_attr_addr_lo */
57 0xffffffffffffffffull, /* dma_attr_addr_hi */
58 0xffffffffffffffffull, /* dma_attr_count_max */
59 EFX_INTR_SIZE, /* dma_attr_align */
60 0xffffffff, /* dma_attr_burstsizes */
61 1, /* dma_attr_minxfer */
62 0xffffffffffffffffull, /* dma_attr_maxxfer */
63 0xffffffffffffffffull, /* dma_attr_seg */
64 1, /* dma_attr_sgllen */
65 1, /* dma_attr_granular */
66 0 /* dma_attr_flags */
67 };
68
69 static unsigned int
70 sfxge_intr_line(caddr_t arg1, caddr_t arg2)
71 {
72 sfxge_t *sp = (void *)arg1;
73 efx_nic_t *enp = sp->s_enp;
74 sfxge_intr_t *sip = &(sp->s_intr);
75 unsigned int index;
76 boolean_t fatal;
77 uint32_t qmask;
78 int rc;
79
80 _NOTE(ARGUNUSED(arg2))
81
82 ASSERT3U(sip->si_type, ==, EFX_INTR_LINE);
83
84 if (sip->si_state != SFXGE_INTR_STARTED &&
85 sip->si_state != SFXGE_INTR_TESTING) {
86 rc = DDI_INTR_UNCLAIMED;
87 goto done;
88 }
89
90 if (sip->si_state == SFXGE_INTR_TESTING) {
91 sip->si_mask |= 1; /* only one interrupt */
92 rc = DDI_INTR_CLAIMED;
93 goto done;
94 }
95
96 efx_intr_status_line(enp, &fatal, &qmask);
97
98 if (fatal) {
99 sfxge_intr_fatal(sp);
100
101 rc = DDI_INTR_CLAIMED;
102 goto done;
103 }
104
105 if (qmask != 0) {
106 for (index = 0; index < EFX_INTR_NEVQS; index++) {
107 if (qmask & (1 << index))
108 (void) sfxge_ev_qpoll(sp, index);
109 }
110
111 sip->si_zero_count = 0;
112 sfxge_gld_rx_push(sp);
113 rc = DDI_INTR_CLAIMED;
114 goto done;
115 }
116
117 /*
118 * bug15671/bug17203 workaround. Return CLAIMED for the first ISR=0
119 * interrupt, and poll all evqs for work. For subsequent ISR=0
120 * interrupts (the line must be shared in this case), just rearm the
121 * event queues to ensure we don't miss an interrupt.
122 */
123 if (sip->si_zero_count++ == 0) {
124 for (index = 0; index < EFX_INTR_NEVQS; index++) {
125 if (sp->s_sep[index] != NULL)
126 (void) sfxge_ev_qpoll(sp, index);
127 }
128
129 rc = DDI_INTR_CLAIMED;
130 } else {
131 for (index = 0; index < EFX_INTR_NEVQS; index++) {
132 if (sp->s_sep[index] != NULL)
133 (void) sfxge_ev_qprime(sp, index);
134 }
135
136 rc = DDI_INTR_UNCLAIMED;
137 }
138
139 done:
140 return (rc);
141 }
142
143 static unsigned int
144 sfxge_intr_message(caddr_t arg1, caddr_t arg2)
145 {
146 sfxge_t *sp = (void *)arg1;
147 efx_nic_t *enp = sp->s_enp;
148 sfxge_intr_t *sip = &(sp->s_intr);
149 unsigned int index = (unsigned int)(uintptr_t)arg2;
150 boolean_t fatal;
151 int rc;
152
153 ASSERT3U(sip->si_type, ==, EFX_INTR_MESSAGE);
154
155 if (sip->si_state != SFXGE_INTR_STARTED &&
156 sip->si_state != SFXGE_INTR_TESTING) {
157 rc = DDI_INTR_UNCLAIMED;
158 goto done;
159 }
160
161 if (sip->si_state == SFXGE_INTR_TESTING) {
162 uint64_t mask;
163
164 do {
165 mask = sip->si_mask;
166 } while (atomic_cas_64(&(sip->si_mask), mask,
167 mask | (1 << index)) != mask);
168
169 rc = DDI_INTR_CLAIMED;
170 goto done;
171 }
172
173 efx_intr_status_message(enp, index, &fatal);
174
175 if (fatal) {
176 sfxge_intr_fatal(sp);
177
178 rc = DDI_INTR_CLAIMED;
179 goto done;
180 }
181
182 (void) sfxge_ev_qpoll(sp, index);
183
184 sfxge_gld_rx_push(sp);
185 rc = DDI_INTR_CLAIMED;
186
187 done:
188 return (rc);
189 }
190
191 static int
192 sfxge_intr_bus_enable(sfxge_t *sp)
193 {
194 sfxge_intr_t *sip = &(sp->s_intr);
195 ddi_intr_handler_t *handler;
196 int add_index;
197 int en_index;
198 int err;
199 int rc;
200
201 /* Serialise all instances to avoid problems seen in bug31184. */
202 mutex_enter(&sfxge_global_lock);
203
204 switch (sip->si_type) {
205 case EFX_INTR_MESSAGE:
206 handler = sfxge_intr_message;
207 break;
208
209 case EFX_INTR_LINE:
210 handler = sfxge_intr_line;
211 break;
212
213 default:
214 dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
215 "bus_enable: unknown intr type (si_type=%d nalloc=%d)",
216 sip->si_type, sip->si_nalloc);
217 ASSERT(B_FALSE);
218 rc = EINVAL;
219 goto fail1;
220 }
221
222 /* Try to add the handlers */
223 for (add_index = 0; add_index < sip->si_nalloc; add_index++) {
224 unsigned int pri;
225
226 (void) ddi_intr_get_pri(sip->si_table[add_index], &pri);
227 DTRACE_PROBE2(pri, unsigned int, add_index, unsigned int, pri);
228
229 err = ddi_intr_add_handler(sip->si_table[add_index], handler,
230 (caddr_t)sp, (caddr_t)(uintptr_t)add_index);
231 if (err != DDI_SUCCESS) {
232 dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
233 "bus_enable: ddi_intr_add_handler failed"
234 " err=%d (h=%p idx=%d nalloc=%d)",
235 err, (void *)sip->si_table[add_index], add_index,
236 sip->si_nalloc);
237
238 rc = (err == DDI_EINVAL) ? EINVAL : EFAULT;
239 goto fail2;
240 }
241 }
242
243 /* Get interrupt capabilities */
244 err = ddi_intr_get_cap(sip->si_table[0], &(sip->si_cap));
245 if (err != DDI_SUCCESS) {
246 dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
247 "bus_enable: ddi_intr_get_cap failed"
248 " err=%d (h=%p idx=%d nalloc=%d)",
249 err, (void *)sip->si_table[0], 0, sip->si_nalloc);
250
251 if (err == DDI_EINVAL)
252 rc = EINVAL;
253 else if (err == DDI_ENOTSUP)
254 rc = ENOTSUP;
255 else
256 rc = EFAULT;
257
258 goto fail3;
259 }
260
261 /* Enable interrupts at the bus */
262 if (sip->si_cap & DDI_INTR_FLAG_BLOCK) {
263 en_index = 0; /* Silence gcc */
264 err = ddi_intr_block_enable(sip->si_table, sip->si_nalloc);
265 if (err != DDI_SUCCESS) {
266 dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
267 "bus_enable: ddi_intr_block_enable failed"
268 " err=%d (table=%p nalloc=%d)",
269 err, (void *)sip->si_table, sip->si_nalloc);
270
271 rc = (err == DDI_EINVAL) ? EINVAL : EFAULT;
272 goto fail4;
273 }
274 } else {
275 for (en_index = 0; en_index < sip->si_nalloc; en_index++) {
276 err = ddi_intr_enable(sip->si_table[en_index]);
277 if (err != DDI_SUCCESS) {
278 dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
279 "bus_enable: ddi_intr_enable failed"
280 " err=%d (h=%p idx=%d nalloc=%d)",
281 err, (void *)sip->si_table[en_index],
282 en_index, sip->si_nalloc);
283
284 rc = (err == DDI_EINVAL) ? EINVAL : EFAULT;
285 goto fail4;
286 }
287 }
288 }
289
290 mutex_exit(&sfxge_global_lock);
291 return (0);
292
293 fail4:
294 DTRACE_PROBE(fail4);
295
296 /* Disable the enabled handlers */
297 if (!(sip->si_cap & DDI_INTR_FLAG_BLOCK)) {
298 while (--en_index >= 0) {
299 err = ddi_intr_disable(sip->si_table[en_index]);
300 if (err != DDI_SUCCESS) {
301 dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
302 "bus_enable: ddi_intr_disable"
303 " failed err=%d (h=%p idx=%d nalloc=%d)",
304 err, (void *)sip->si_table[en_index],
305 en_index, sip->si_nalloc);
306 }
307 }
308 }
309
310 fail3:
311 DTRACE_PROBE(fail3);
312
313 /* Remove all handlers */
314 add_index = sip->si_nalloc;
315
316 fail2:
317 DTRACE_PROBE(fail2);
318
319 /* Remove remaining handlers */
320 while (--add_index >= 0) {
321 err = ddi_intr_remove_handler(sip->si_table[add_index]);
322 if (err != DDI_SUCCESS) {
323 dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
324 "bus_enable: ddi_intr_remove_handler"
325 " failed err=%d (h=%p idx=%d nalloc=%d)",
326 err, (void *)sip->si_table[add_index], add_index,
327 sip->si_nalloc);
328 }
329 }
330
331 fail1:
332 DTRACE_PROBE1(fail1, int, rc);
333
334 mutex_exit(&sfxge_global_lock);
335 return (rc);
336 }
337
338 static void
339 sfxge_intr_bus_disable(sfxge_t *sp)
340 {
341 sfxge_intr_t *sip = &(sp->s_intr);
342 int index;
343 int err;
344
345 /* Serialise all instances to avoid problems seen in bug31184. */
346 mutex_enter(&sfxge_global_lock);
347
348 /* Disable interrupts at the bus */
349 if (sip->si_cap & DDI_INTR_FLAG_BLOCK) {
350 err = ddi_intr_block_disable(sip->si_table, sip->si_nalloc);
351 if (err != DDI_SUCCESS) {
352 dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
353 "bus_disable: ddi_intr_block_disable"
354 " failed err=%d (table=%p nalloc=%d)",
355 err, (void *)sip->si_table, sip->si_nalloc);
356 }
357 } else {
358 index = sip->si_nalloc;
359 while (--index >= 0) {
360 err = ddi_intr_disable(sip->si_table[index]);
361 if (err != DDI_SUCCESS) {
362 dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
363 "bus_disable: ddi_intr_disable"
364 " failed err=%d (h=%p idx=%d nalloc=%d)",
365 err, (void *)sip->si_table[index], index,
366 sip->si_nalloc);
367 }
368 }
369 }
370
371 sip->si_cap = 0;
372
373 /* Remove all handlers */
374 index = sip->si_nalloc;
375 while (--index >= 0) {
376 err = ddi_intr_remove_handler(sip->si_table[index]);
377 if (err != DDI_SUCCESS) {
378 dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
379 "bus_disable: ddi_intr_remove_handler"
380 " failed err=%d (h=%p idx=%d nalloc=%d)",
381 err, (void *)sip->si_table[index], index,
382 sip->si_nalloc);
383 }
384 }
385
386 mutex_exit(&sfxge_global_lock);
387 }
388
389 static int
390 sfxge_intr_nic_enable(sfxge_t *sp)
391 {
392 sfxge_intr_t *sip = &(sp->s_intr);
393 efsys_mem_t *esmp = &(sip->si_mem);
394 efx_nic_t *enp = sp->s_enp;
395 unsigned int index;
396 uint64_t mask;
397 unsigned int count;
398 int rc;
399
400 /* Zero the memory */
401 bzero(esmp->esm_base, EFX_INTR_SIZE);
402
403 /* Enable interrupts at the NIC */
404 if ((rc = efx_intr_init(enp, sip->si_type, esmp)) != 0)
405 goto fail1;
406
407 efx_intr_enable(enp);
408
409 /* FIXME FIXME FIXME */
410 if (sp->s_family == EFX_FAMILY_HUNTINGTON) {
411 /* Disable interrupt test until supported on Huntington. */
412 return (0);
413 }
414 /* FIXME FIXME FIXME */
415
416 /* Test the interrupts */
417 mask = 0;
418 for (index = 0; index < sip->si_nalloc; index++) {
419 mask |= (1 << index);
420
421 rc = efx_intr_trigger(enp, index);
422 ASSERT3U(rc, ==, 0);
423 }
424
425 /* Wait for the tests to complete */
426 count = 0;
427 do {
428 DTRACE_PROBE1(wait, unsigned int, count);
429
430 /* Spin for 1 ms */
431 drv_usecwait(1000);
432
433 /*
434 * Check to see that all the test interrupts have been
435 * processed.
436 */
437 if ((mask & sip->si_mask) == mask)
438 goto done;
439
440 } while (++count < 20);
441
442 rc = ETIMEDOUT;
443 goto fail2;
444
445 done:
446 return (0);
447
448 fail2:
449 DTRACE_PROBE(fail2);
450
451 dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
452 "Interrupt test failed (mask=%"PRIx64" got=%"
453 PRIx64"). NIC is disabled",
454 mask, sip->si_mask);
455
456 DTRACE_PROBE2(int_test_fail, uint64_t, mask, uint64_t, sip->si_mask);
457
458 sip->si_mask = 0;
459
460 /* Disable interrupts at the NIC */
461 efx_intr_disable(enp);
462 efx_intr_fini(enp);
463
464 fail1:
465 DTRACE_PROBE1(fail1, int, rc);
466
467 return (rc);
468 }
469
470 static void
471 sfxge_intr_nic_disable(sfxge_t *sp)
472 {
473 sfxge_intr_t *sip = &(sp->s_intr);
474 efx_nic_t *enp = sp->s_enp;
475
476 sip->si_mask = 0;
477
478 /* Disable interrupts at the NIC */
479 efx_intr_disable(enp);
480 efx_intr_fini(enp);
481 }
482
483 inline unsigned pow2_le(unsigned long n) {
484 unsigned int order = 1;
485 ASSERT3U(n, >, 0);
486 while ((1ul << order) <= n) ++order;
487 return (1ul << (order - 1));
488 }
489
490 int
491 sfxge_intr_init(sfxge_t *sp)
492 {
493 dev_info_t *dip = sp->s_dip;
494 sfxge_intr_t *sip = &(sp->s_intr);
495 efsys_mem_t *esmp = &(sip->si_mem);
496 sfxge_dma_buffer_attr_t dma_attr;
497 int err;
498 int rc;
499 int types;
500 int type;
501 int index;
502 unsigned int nalloc;
503 int navail;
504
505 SFXGE_OBJ_CHECK(sip, sfxge_intr_t);
506
507 ASSERT3U(sip->si_state, ==, SFXGE_INTR_UNINITIALIZED);
508
509 #ifdef __sparc
510 /* PSARC 2007/453 */
511 (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
512 "#msix-request", NULL, 0);
513 #endif
514
515 /* Get the map of supported interrupt types */
516 err = ddi_intr_get_supported_types(dip, &types);
517 if (err != DDI_SUCCESS) {
518 dev_err(dip, CE_WARN, SFXGE_CMN_ERR
519 "intr_init: ddi_intr_get_supported_types failed err=%d",
520 err);
521
522 if (err == DDI_EINVAL)
523 rc = EINVAL;
524 else if (err == DDI_INTR_NOTFOUND)
525 rc = ENOENT;
526 else
527 rc = EFAULT;
528
529 goto fail1;
530 }
531
532 /* Choose most favourable type */
533 if (types & DDI_INTR_TYPE_MSIX) {
534 DTRACE_PROBE(msix);
535
536 type = DDI_INTR_TYPE_MSIX;
537 sip->si_type = EFX_INTR_MESSAGE;
538 } else {
539 DTRACE_PROBE(fixed);
540
541 ASSERT(types & DDI_INTR_TYPE_FIXED);
542
543 type = DDI_INTR_TYPE_FIXED;
544 sip->si_type = EFX_INTR_LINE;
545 }
546
547 /* Get the number of available interrupts */
548 navail = 0;
549 err = ddi_intr_get_navail(dip, type, &navail);
550 if (err != DDI_SUCCESS) {
551 dev_err(dip, CE_WARN, SFXGE_CMN_ERR
552 "intr_init: ddi_intr_get_navail failed err=%d", err);
553
554 if (err == DDI_EINVAL)
555 rc = EINVAL;
556 else if (err == DDI_INTR_NOTFOUND)
557 rc = ENOENT;
558 else
559 rc = EFAULT;
560
561 goto fail2;
562 }
563
564 /* Double-check */
565 if (navail == 0) {
566 rc = ENOENT;
567 goto fail2;
568 }
569
570 /*
571 * Allow greater number of MSI-X interrupts than CPUs.
572 * This can be useful to prevent RX no desc drops; See task 32179.
573 * Limit non MSI-X interrupts to a single instance.
574 */
575 if (type != DDI_INTR_TYPE_MSIX)
576 navail = 1;
577 else
578 navail = min(navail, sfxge_rx_scale_prop_get(sp));
579
580 DTRACE_PROBE1(navail, unsigned int, navail);
581
582 /* Allocate a handle table */
583 sip->si_table_size = navail * sizeof (ddi_intr_handle_t);
584 sip->si_table = kmem_zalloc(sip->si_table_size, KM_SLEEP);
585
586 /*
587 * Allocate interrupt handles.
588 * Serialise all device instances to avoid problems seen in bug31184.
589 */
590 mutex_enter(&sfxge_global_lock);
591
592 err = ddi_intr_alloc(dip, sip->si_table, type, 0,
593 navail, &(sip->si_nalloc), DDI_INTR_ALLOC_NORMAL);
594
595 mutex_exit(&sfxge_global_lock);
596
597 if (err != DDI_SUCCESS) {
598 dev_err(dip, CE_WARN, SFXGE_CMN_ERR
599 "intr_init: ddi_intr_alloc failed err=%d"
600 " (navail=%d nalloc=%d)",
601 err, navail, sip->si_nalloc);
602
603 if (err == DDI_EINVAL)
604 rc = EINVAL;
605 else if (err == DDI_EAGAIN)
606 rc = EAGAIN;
607 else if (err == DDI_INTR_NOTFOUND)
608 rc = ENOENT;
609 else
610 rc = EFAULT;
611
612 goto fail3;
613 }
614
615 /* Double-check */
616 if (sip->si_nalloc == 0) {
617 rc = ENOENT;
618 goto fail3;
619 }
620
621 /* Round down to a power of 2 */
622 nalloc = pow2_le(sip->si_nalloc);
623
624 /* Free off any excess handles */
625 mutex_enter(&sfxge_global_lock);
626
627 index = sip->si_nalloc;
628 while (--index >= nalloc) {
629 (void) ddi_intr_free(sip->si_table[index]);
630 sip->si_table[index] = NULL;
631 }
632
633 mutex_exit(&sfxge_global_lock);
634
635 sip->si_nalloc = nalloc;
636 DTRACE_PROBE1(nalloc, unsigned int, sip->si_nalloc);
637
638 dma_attr.sdba_dip = sp->s_dip;
639 dma_attr.sdba_dattrp = &sfxge_intr_dma_attr;
640 dma_attr.sdba_callback = DDI_DMA_SLEEP;
641 dma_attr.sdba_length = EFX_INTR_SIZE;
642 dma_attr.sdba_memflags = DDI_DMA_CONSISTENT;
643 dma_attr.sdba_devaccp = &sfxge_intr_devacc;
644 dma_attr.sdba_bindflags = DDI_DMA_RDWR | DDI_DMA_CONSISTENT;
645 dma_attr.sdba_maxcookies = 1;
646 dma_attr.sdba_zeroinit = B_TRUE;
647
648 if ((rc = sfxge_dma_buffer_create(esmp, &dma_attr)) != 0)
649 goto fail4;
650
651 /* Store the highest priority for convenience */
652 sip->si_intr_pri = 0;
653 for (index = 0; index < sip->si_nalloc; index++) {
654 uint_t pri;
655 if ((rc = ddi_intr_get_pri(sip->si_table[index], &pri)) != 0)
656 goto fail5;
657 if (pri > sip->si_intr_pri)
658 sip->si_intr_pri = pri;
659 }
660
661 sip->si_state = SFXGE_INTR_INITIALIZED;
662 return (0);
663
664 fail5:
665 DTRACE_PROBE(fail5);
666
667 fail4:
668 DTRACE_PROBE(fail4);
669
670 /* Free interrupt handles */
671 mutex_exit(&sfxge_global_lock);
672
673 index = sip->si_nalloc;
674 while (--index >= 0) {
675 err = ddi_intr_free(sip->si_table[index]);
676 if (err != DDI_SUCCESS) {
677 dev_err(dip, CE_WARN, SFXGE_CMN_ERR
678 "intr_init: ddi_intr_free failed err=%d"
679 " (h=%p idx=%d nalloc=%d)",
680 err, (void *)sip->si_table[index], index,
681 sip->si_nalloc);
682 }
683 sip->si_table[index] = NULL;
684 }
685 sip->si_nalloc = 0;
686
687 mutex_exit(&sfxge_global_lock);
688
689 fail3:
690 DTRACE_PROBE(fail3);
691
692 /* Free the handle table */
693 kmem_free(sip->si_table, sip->si_table_size);
694 sip->si_table = NULL;
695 sip->si_table_size = 0;
696
697 fail2:
698 DTRACE_PROBE(fail2);
699
700 /* Clear the interrupt type */
701 sip->si_type = EFX_INTR_INVALID;
702
703 fail1:
704 DTRACE_PROBE1(fail1, int, rc);
705
706 SFXGE_OBJ_CHECK(sip, sfxge_intr_t);
707
708 return (rc);
709 }
710
711 int
712 sfxge_intr_start(sfxge_t *sp)
713 {
714 sfxge_intr_t *sip = &(sp->s_intr);
715 int rc;
716
717 ASSERT3U(sip->si_state, ==, SFXGE_INTR_INITIALIZED);
718
719 /* Enable interrupts at the bus */
720 if ((rc = sfxge_intr_bus_enable(sp)) != 0)
721 goto fail1;
722
723 sip->si_state = SFXGE_INTR_TESTING;
724
725 /* Enable interrupts at the NIC */
726 if ((rc = sfxge_intr_nic_enable(sp)) != 0)
727 goto fail2;
728
729 sip->si_state = SFXGE_INTR_STARTED;
730
731 return (0);
732
733 fail2:
734 DTRACE_PROBE(fail2);
735
736 /* Disable interrupts at the bus */
737 sfxge_intr_bus_disable(sp);
738
739 fail1:
740 DTRACE_PROBE1(fail1, int, rc);
741
742 sip->si_state = SFXGE_INTR_INITIALIZED;
743
744 return (rc);
745 }
746
747 void
748 sfxge_intr_stop(sfxge_t *sp)
749 {
750 sfxge_intr_t *sip = &(sp->s_intr);
751
752 ASSERT3U(sip->si_state, ==, SFXGE_INTR_STARTED);
753
754 sip->si_state = SFXGE_INTR_INITIALIZED;
755
756 /* Disable interrupts at the NIC */
757 sfxge_intr_nic_disable(sp);
758
759 /* Disable interrupts at the bus */
760 sfxge_intr_bus_disable(sp);
761 }
762
763 void
764 sfxge_intr_fini(sfxge_t *sp)
765 {
766 sfxge_intr_t *sip = &(sp->s_intr);
767 efsys_mem_t *esmp = &(sip->si_mem);
768 int index;
769 int err;
770
771 ASSERT3U(sip->si_state, ==, SFXGE_INTR_INITIALIZED);
772
773 sip->si_state = SFXGE_INTR_UNINITIALIZED;
774
775 /* Tear down dma setup */
776 sfxge_dma_buffer_destroy(esmp);
777
778
779 /* Free interrupt handles */
780 mutex_enter(&sfxge_global_lock);
781
782 index = sip->si_nalloc;
783 while (--index >= 0) {
784 err = ddi_intr_free(sip->si_table[index]);
785 if (err != DDI_SUCCESS) {
786 dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
787 "intr_fini: ddi_intr_free failed err=%d"
788 " (h=%p idx=%d nalloc=%d)",
789 err, (void *)sip->si_table[index],
790 index, sip->si_nalloc);
791 }
792 sip->si_table[index] = NULL;
793 }
794 sip->si_nalloc = 0;
795
796 mutex_exit(&sfxge_global_lock);
797
798 /* Free the handle table */
799 kmem_free(sip->si_table, sip->si_table_size);
800 sip->si_table = NULL;
801 sip->si_table_size = 0;
802
803 /* Clear the interrupt type */
804 sip->si_type = EFX_INTR_INVALID;
805
806 SFXGE_OBJ_CHECK(sip, sfxge_intr_t);
807 }