xref: /illumos-gate/usr/src/uts/common/io/sfxge/sfxge_intr.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
1 /*
2  * Copyright (c) 2008-2016 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 		/* This cannot fail unless given invalid inputs. */
227 		err = ddi_intr_get_pri(sip->si_table[add_index], &pri);
228 		ASSERT(err == DDI_SUCCESS);
229 
230 		DTRACE_PROBE2(pri, unsigned int, add_index, unsigned int, pri);
231 
232 		err = ddi_intr_add_handler(sip->si_table[add_index], handler,
233 		    (caddr_t)sp, (caddr_t)(uintptr_t)add_index);
234 		if (err != DDI_SUCCESS) {
235 			dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
236 			    "bus_enable: ddi_intr_add_handler failed"
237 			    " err=%d (h=%p idx=%d nalloc=%d)",
238 			    err, (void *)sip->si_table[add_index], add_index,
239 			    sip->si_nalloc);
240 
241 			rc = (err == DDI_EINVAL) ? EINVAL : EFAULT;
242 			goto fail2;
243 		}
244 	}
245 
246 	/* Get interrupt capabilities */
247 	err = ddi_intr_get_cap(sip->si_table[0], &(sip->si_cap));
248 	if (err != DDI_SUCCESS) {
249 		dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
250 		    "bus_enable: ddi_intr_get_cap failed"
251 		    " err=%d (h=%p idx=%d nalloc=%d)",
252 		    err, (void *)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 			dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
270 			    "bus_enable: ddi_intr_block_enable failed"
271 			    " err=%d (table=%p nalloc=%d)",
272 			    err, (void *)sip->si_table, sip->si_nalloc);
273 
274 			rc = (err == DDI_EINVAL) ? EINVAL : EFAULT;
275 			goto fail4;
276 		}
277 	} else {
278 		for (en_index = 0; en_index < sip->si_nalloc; en_index++) {
279 			err = ddi_intr_enable(sip->si_table[en_index]);
280 			if (err != DDI_SUCCESS) {
281 				dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
282 				    "bus_enable: ddi_intr_enable failed"
283 				    " err=%d (h=%p idx=%d nalloc=%d)",
284 				    err, (void *)sip->si_table[en_index],
285 				    en_index, sip->si_nalloc);
286 
287 				rc = (err == DDI_EINVAL) ? EINVAL : EFAULT;
288 				goto fail4;
289 			}
290 		}
291 	}
292 
293 	mutex_exit(&sfxge_global_lock);
294 	return (0);
295 
296 fail4:
297 	DTRACE_PROBE(fail4);
298 
299 	/* Disable the enabled handlers */
300 	if (!(sip->si_cap & DDI_INTR_FLAG_BLOCK)) {
301 		while (--en_index >= 0) {
302 			err = ddi_intr_disable(sip->si_table[en_index]);
303 			if (err != DDI_SUCCESS) {
304 				dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
305 				    "bus_enable: ddi_intr_disable"
306 				    " failed err=%d (h=%p idx=%d nalloc=%d)",
307 				    err, (void *)sip->si_table[en_index],
308 				    en_index, sip->si_nalloc);
309 			}
310 		}
311 	}
312 
313 fail3:
314 	DTRACE_PROBE(fail3);
315 
316 	/* Remove all handlers */
317 	add_index = sip->si_nalloc;
318 
319 fail2:
320 	DTRACE_PROBE(fail2);
321 
322 	/* Remove remaining handlers */
323 	while (--add_index >= 0) {
324 		err = ddi_intr_remove_handler(sip->si_table[add_index]);
325 		if (err != DDI_SUCCESS) {
326 			dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
327 			    "bus_enable: ddi_intr_remove_handler"
328 			    " failed err=%d (h=%p idx=%d nalloc=%d)",
329 			    err, (void *)sip->si_table[add_index], add_index,
330 			    sip->si_nalloc);
331 		}
332 	}
333 
334 fail1:
335 	DTRACE_PROBE1(fail1, int, rc);
336 
337 	mutex_exit(&sfxge_global_lock);
338 	return (rc);
339 }
340 
341 static void
342 sfxge_intr_bus_disable(sfxge_t *sp)
343 {
344 	sfxge_intr_t *sip = &(sp->s_intr);
345 	int index;
346 	int err;
347 
348 	/* Serialise all instances to avoid problems seen in bug31184. */
349 	mutex_enter(&sfxge_global_lock);
350 
351 	/* Disable interrupts at the bus */
352 	if (sip->si_cap & DDI_INTR_FLAG_BLOCK) {
353 		err = ddi_intr_block_disable(sip->si_table, sip->si_nalloc);
354 		if (err != DDI_SUCCESS) {
355 			dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
356 			    "bus_disable: ddi_intr_block_disable"
357 			    " failed err=%d (table=%p nalloc=%d)",
358 			    err, (void *)sip->si_table, sip->si_nalloc);
359 		}
360 	} else {
361 		index = sip->si_nalloc;
362 		while (--index >= 0) {
363 			err = ddi_intr_disable(sip->si_table[index]);
364 			if (err != DDI_SUCCESS) {
365 				dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
366 				    "bus_disable: ddi_intr_disable"
367 				    " failed err=%d (h=%p idx=%d nalloc=%d)",
368 				    err, (void *)sip->si_table[index], index,
369 				    sip->si_nalloc);
370 			}
371 		}
372 	}
373 
374 	sip->si_cap = 0;
375 
376 	/* Remove all handlers */
377 	index = sip->si_nalloc;
378 	while (--index >= 0) {
379 		err = ddi_intr_remove_handler(sip->si_table[index]);
380 		if (err != DDI_SUCCESS) {
381 			dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
382 			    "bus_disable: ddi_intr_remove_handler"
383 			    " failed err=%d (h=%p idx=%d nalloc=%d)",
384 			    err, (void *)sip->si_table[index], index,
385 			    sip->si_nalloc);
386 		}
387 	}
388 
389 	mutex_exit(&sfxge_global_lock);
390 }
391 
392 static int
393 sfxge_intr_nic_enable(sfxge_t *sp)
394 {
395 	sfxge_intr_t *sip = &(sp->s_intr);
396 	efsys_mem_t *esmp = &(sip->si_mem);
397 	efx_nic_t *enp = sp->s_enp;
398 	unsigned int index;
399 	uint64_t mask;
400 	unsigned int count;
401 	int rc;
402 
403 	/* Zero the memory */
404 	bzero(esmp->esm_base, EFX_INTR_SIZE);
405 
406 	/* Enable interrupts at the NIC */
407 	if ((rc = efx_intr_init(enp, sip->si_type, esmp)) != 0)
408 		goto fail1;
409 
410 	efx_intr_enable(enp);
411 
412 	/* FIXME FIXME FIXME */
413 	if (sp->s_family == EFX_FAMILY_HUNTINGTON) {
414 		/* Disable interrupt test until supported on Huntington. */
415 		return (0);
416 	}
417 	/* FIXME FIXME FIXME */
418 
419 	/* Test the interrupts */
420 	mask = 0;
421 	for (index = 0; index < sip->si_nalloc; index++) {
422 		mask |= (1 << index);
423 
424 		rc = efx_intr_trigger(enp, index);
425 		ASSERT3U(rc, ==, 0);
426 	}
427 
428 	/* Wait for the tests to complete */
429 	count = 0;
430 	do {
431 		DTRACE_PROBE1(wait, unsigned int, count);
432 
433 		/* Spin for 1 ms */
434 		drv_usecwait(1000);
435 
436 		/*
437 		 * Check to see that all the test interrupts have been
438 		 * processed.
439 		 */
440 		if ((mask & sip->si_mask) == mask)
441 			goto done;
442 
443 	} while (++count < 20);
444 
445 	rc = ETIMEDOUT;
446 	goto fail2;
447 
448 done:
449 	return (0);
450 
451 fail2:
452 	DTRACE_PROBE(fail2);
453 
454 	dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
455 	    "Interrupt test failed (mask=%"PRIx64" got=%"
456 	    PRIx64"). NIC is disabled",
457 	    mask, sip->si_mask);
458 
459 	DTRACE_PROBE2(int_test_fail, uint64_t, mask, uint64_t, sip->si_mask);
460 
461 	sip->si_mask = 0;
462 
463 	/* Disable interrupts at the NIC */
464 	efx_intr_disable(enp);
465 	efx_intr_fini(enp);
466 
467 fail1:
468 	DTRACE_PROBE1(fail1, int, rc);
469 
470 	return (rc);
471 }
472 
473 static void
474 sfxge_intr_nic_disable(sfxge_t *sp)
475 {
476 	sfxge_intr_t *sip = &(sp->s_intr);
477 	efx_nic_t *enp = sp->s_enp;
478 
479 	sip->si_mask = 0;
480 
481 	/* Disable interrupts at the NIC */
482 	efx_intr_disable(enp);
483 	efx_intr_fini(enp);
484 }
485 
486 static inline unsigned
487 pow2_le(unsigned long n)
488 {
489 	unsigned int order = 1;
490 	ASSERT3U(n, >, 0);
491 	while ((1ul << order) <= n) ++order;
492 	return (1ul << (order - 1));
493 }
494 
495 int
496 sfxge_intr_init(sfxge_t *sp)
497 {
498 	dev_info_t *dip = sp->s_dip;
499 	sfxge_intr_t *sip = &(sp->s_intr);
500 	efsys_mem_t *esmp = &(sip->si_mem);
501 	sfxge_dma_buffer_attr_t dma_attr;
502 	int err;
503 	int rc;
504 	int types;
505 	int type;
506 	int index;
507 	unsigned int nalloc;
508 	int navail;
509 
510 	SFXGE_OBJ_CHECK(sip, sfxge_intr_t);
511 
512 	ASSERT3U(sip->si_state, ==, SFXGE_INTR_UNINITIALIZED);
513 
514 #ifdef __sparc
515 	/* PSARC 2007/453 */
516 	(void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
517 	    "#msix-request", NULL, 0);
518 #endif
519 
520 	/* Get the map of supported interrupt types */
521 	err = ddi_intr_get_supported_types(dip, &types);
522 	if (err != DDI_SUCCESS) {
523 		dev_err(dip, CE_WARN, SFXGE_CMN_ERR
524 		    "intr_init: ddi_intr_get_supported_types failed err=%d",
525 		    err);
526 
527 		if (err == DDI_EINVAL)
528 			rc = EINVAL;
529 		else if (err == DDI_INTR_NOTFOUND)
530 			rc = ENOENT;
531 		else
532 			rc = EFAULT;
533 
534 		goto fail1;
535 	}
536 
537 	/* Choose most favourable type */
538 	if (types & DDI_INTR_TYPE_MSIX) {
539 		DTRACE_PROBE(msix);
540 
541 		type = DDI_INTR_TYPE_MSIX;
542 		sip->si_type = EFX_INTR_MESSAGE;
543 	} else {
544 		DTRACE_PROBE(fixed);
545 
546 		ASSERT(types & DDI_INTR_TYPE_FIXED);
547 
548 		type = DDI_INTR_TYPE_FIXED;
549 		sip->si_type = EFX_INTR_LINE;
550 	}
551 
552 	/* Get the number of available interrupts */
553 	navail = 0;
554 	err = ddi_intr_get_navail(dip, type, &navail);
555 	if (err != DDI_SUCCESS) {
556 		dev_err(dip, CE_WARN, SFXGE_CMN_ERR
557 		    "intr_init: ddi_intr_get_navail failed err=%d", err);
558 
559 		if (err == DDI_EINVAL)
560 			rc = EINVAL;
561 		else if (err == DDI_INTR_NOTFOUND)
562 			rc = ENOENT;
563 		else
564 			rc = EFAULT;
565 
566 		goto fail2;
567 	}
568 
569 	/* Double-check */
570 	if (navail == 0) {
571 		rc = ENOENT;
572 		goto fail2;
573 	}
574 
575 	/*
576 	 * Allow greater number of MSI-X interrupts than CPUs.
577 	 * This can be useful to prevent RX no desc drops; See task 32179.
578 	 * Limit non MSI-X interrupts to a single instance.
579 	 */
580 	if (type != DDI_INTR_TYPE_MSIX)
581 		navail = 1;
582 	else
583 		navail = min(navail, sfxge_rx_scale_prop_get(sp));
584 
585 	DTRACE_PROBE1(navail, unsigned int, navail);
586 
587 	/* Allocate a handle table */
588 	sip->si_table_size = navail * sizeof (ddi_intr_handle_t);
589 	sip->si_table = kmem_zalloc(sip->si_table_size, KM_SLEEP);
590 
591 	/*
592 	 * Allocate interrupt handles.
593 	 * Serialise all device instances to avoid problems seen in bug31184.
594 	 */
595 	mutex_enter(&sfxge_global_lock);
596 
597 	err = ddi_intr_alloc(dip, sip->si_table, type, 0,
598 	    navail, &(sip->si_nalloc), DDI_INTR_ALLOC_NORMAL);
599 
600 	mutex_exit(&sfxge_global_lock);
601 
602 	if (err != DDI_SUCCESS) {
603 		dev_err(dip, CE_WARN, SFXGE_CMN_ERR
604 		    "intr_init: ddi_intr_alloc failed err=%d"
605 		    " (navail=%d nalloc=%d)",
606 		    err, navail, sip->si_nalloc);
607 
608 		if (err == DDI_EINVAL)
609 			rc = EINVAL;
610 		else if (err == DDI_EAGAIN)
611 			rc = EAGAIN;
612 		else if (err == DDI_INTR_NOTFOUND)
613 			rc = ENOENT;
614 		else
615 			rc = EFAULT;
616 
617 		goto fail3;
618 	}
619 
620 	/* Double-check */
621 	if (sip->si_nalloc == 0) {
622 		rc = ENOENT;
623 		goto fail3;
624 	}
625 
626 	/* Round down to a power of 2 */
627 	nalloc = pow2_le(sip->si_nalloc);
628 
629 	/* Free off any excess handles */
630 	mutex_enter(&sfxge_global_lock);
631 
632 	index = sip->si_nalloc;
633 	while (--index >= nalloc) {
634 		(void) ddi_intr_free(sip->si_table[index]);
635 		sip->si_table[index] = NULL;
636 	}
637 
638 	mutex_exit(&sfxge_global_lock);
639 
640 	sip->si_nalloc = nalloc;
641 	DTRACE_PROBE1(nalloc, unsigned int, sip->si_nalloc);
642 
643 	dma_attr.sdba_dip	 = sp->s_dip;
644 	dma_attr.sdba_dattrp	 = &sfxge_intr_dma_attr;
645 	dma_attr.sdba_callback	 = DDI_DMA_SLEEP;
646 	dma_attr.sdba_length	 = EFX_INTR_SIZE;
647 	dma_attr.sdba_memflags	 = DDI_DMA_CONSISTENT;
648 	dma_attr.sdba_devaccp	 = &sfxge_intr_devacc;
649 	dma_attr.sdba_bindflags	 = DDI_DMA_RDWR | DDI_DMA_CONSISTENT;
650 	dma_attr.sdba_maxcookies = 1;
651 	dma_attr.sdba_zeroinit	 = B_TRUE;
652 
653 	if ((rc = sfxge_dma_buffer_create(esmp, &dma_attr)) != 0)
654 		goto fail4;
655 
656 	/* Store the highest priority for convenience */
657 	sip->si_intr_pri = 0;
658 	for (index = 0; index < sip->si_nalloc; index++) {
659 		uint_t pri;
660 		if ((rc = ddi_intr_get_pri(sip->si_table[index], &pri)) !=  0)
661 			goto fail5;
662 		if (pri > sip->si_intr_pri)
663 			sip->si_intr_pri = pri;
664 	}
665 
666 	sip->si_state = SFXGE_INTR_INITIALIZED;
667 	return (0);
668 
669 fail5:
670 	DTRACE_PROBE(fail5);
671 
672 fail4:
673 	DTRACE_PROBE(fail4);
674 
675 	/* Free interrupt handles */
676 	mutex_exit(&sfxge_global_lock);
677 
678 	index = sip->si_nalloc;
679 	while (--index >= 0) {
680 		err = ddi_intr_free(sip->si_table[index]);
681 		if (err != DDI_SUCCESS) {
682 			dev_err(dip, CE_WARN, SFXGE_CMN_ERR
683 			    "intr_init: ddi_intr_free failed err=%d"
684 			    " (h=%p idx=%d nalloc=%d)",
685 			    err, (void *)sip->si_table[index], index,
686 			    sip->si_nalloc);
687 		}
688 		sip->si_table[index] = NULL;
689 	}
690 	sip->si_nalloc = 0;
691 
692 	mutex_exit(&sfxge_global_lock);
693 
694 fail3:
695 	DTRACE_PROBE(fail3);
696 
697 	/* Free the handle table */
698 	kmem_free(sip->si_table, sip->si_table_size);
699 	sip->si_table = NULL;
700 	sip->si_table_size = 0;
701 
702 fail2:
703 	DTRACE_PROBE(fail2);
704 
705 	/* Clear the interrupt type */
706 	sip->si_type = EFX_INTR_INVALID;
707 
708 fail1:
709 	DTRACE_PROBE1(fail1, int, rc);
710 
711 	SFXGE_OBJ_CHECK(sip, sfxge_intr_t);
712 
713 	return (rc);
714 }
715 
716 int
717 sfxge_intr_start(sfxge_t *sp)
718 {
719 	sfxge_intr_t *sip = &(sp->s_intr);
720 	int rc;
721 
722 	ASSERT3U(sip->si_state, ==, SFXGE_INTR_INITIALIZED);
723 
724 	/* Enable interrupts at the bus */
725 	if ((rc = sfxge_intr_bus_enable(sp)) != 0)
726 		goto fail1;
727 
728 	sip->si_state = SFXGE_INTR_TESTING;
729 
730 	/* Enable interrupts at the NIC */
731 	if ((rc = sfxge_intr_nic_enable(sp)) != 0)
732 		goto fail2;
733 
734 	sip->si_state = SFXGE_INTR_STARTED;
735 
736 	return (0);
737 
738 fail2:
739 	DTRACE_PROBE(fail2);
740 
741 	/* Disable interrupts at the bus */
742 	sfxge_intr_bus_disable(sp);
743 
744 fail1:
745 	DTRACE_PROBE1(fail1, int, rc);
746 
747 	sip->si_state = SFXGE_INTR_INITIALIZED;
748 
749 	return (rc);
750 }
751 
752 void
753 sfxge_intr_stop(sfxge_t *sp)
754 {
755 	sfxge_intr_t *sip = &(sp->s_intr);
756 
757 	ASSERT3U(sip->si_state, ==, SFXGE_INTR_STARTED);
758 
759 	sip->si_state = SFXGE_INTR_INITIALIZED;
760 
761 	/* Disable interrupts at the NIC */
762 	sfxge_intr_nic_disable(sp);
763 
764 	/* Disable interrupts at the bus */
765 	sfxge_intr_bus_disable(sp);
766 }
767 
768 void
769 sfxge_intr_fini(sfxge_t *sp)
770 {
771 	sfxge_intr_t *sip = &(sp->s_intr);
772 	efsys_mem_t *esmp = &(sip->si_mem);
773 	int index;
774 	int err;
775 
776 	ASSERT3U(sip->si_state, ==, SFXGE_INTR_INITIALIZED);
777 
778 	sip->si_state = SFXGE_INTR_UNINITIALIZED;
779 
780 	/* Tear down dma setup */
781 	sfxge_dma_buffer_destroy(esmp);
782 
783 
784 	/* Free interrupt handles */
785 	mutex_enter(&sfxge_global_lock);
786 
787 	index = sip->si_nalloc;
788 	while (--index >= 0) {
789 		err = ddi_intr_free(sip->si_table[index]);
790 		if (err != DDI_SUCCESS) {
791 			dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
792 			    "intr_fini: ddi_intr_free failed err=%d"
793 			    " (h=%p idx=%d nalloc=%d)",
794 			    err, (void *)sip->si_table[index],
795 			    index, sip->si_nalloc);
796 		}
797 		sip->si_table[index] = NULL;
798 	}
799 	sip->si_nalloc = 0;
800 
801 	mutex_exit(&sfxge_global_lock);
802 
803 	/* Free the handle table */
804 	kmem_free(sip->si_table, sip->si_table_size);
805 	sip->si_table = NULL;
806 	sip->si_table_size = 0;
807 
808 	/* Clear the interrupt type */
809 	sip->si_type = EFX_INTR_INVALID;
810 
811 	SFXGE_OBJ_CHECK(sip, sfxge_intr_t);
812 }
813