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