xref: /titanic_50/usr/src/uts/i86pc/io/immu_intrmap.c (revision 6a634c9dca3093f3922e4b7ab826d7bdf17bf78e)
13a634bfcSVikram Hegde /*
23a634bfcSVikram Hegde  * CDDL HEADER START
33a634bfcSVikram Hegde  *
43a634bfcSVikram Hegde  * The contents of this file are subject to the terms of the
53a634bfcSVikram Hegde  * Common Development and Distribution License (the "License").
63a634bfcSVikram Hegde  * You may not use this file except in compliance with the License.
73a634bfcSVikram Hegde  *
83a634bfcSVikram Hegde  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93a634bfcSVikram Hegde  * or http://www.opensolaris.org/os/licensing.
103a634bfcSVikram Hegde  * See the License for the specific language governing permissions
113a634bfcSVikram Hegde  * and limitations under the License.
123a634bfcSVikram Hegde  *
133a634bfcSVikram Hegde  * When distributing Covered Code, include this CDDL HEADER in each
143a634bfcSVikram Hegde  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153a634bfcSVikram Hegde  * If applicable, add the following below this CDDL HEADER, with the
163a634bfcSVikram Hegde  * fields enclosed by brackets "[]" replaced with your own identifying
173a634bfcSVikram Hegde  * information: Portions Copyright [yyyy] [name of copyright owner]
183a634bfcSVikram Hegde  *
193a634bfcSVikram Hegde  * CDDL HEADER END
203a634bfcSVikram Hegde  */
213a634bfcSVikram Hegde 
223a634bfcSVikram Hegde /*
237ff178cdSJimmy Vetayases  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
243a634bfcSVikram Hegde  */
253a634bfcSVikram Hegde 
263a634bfcSVikram Hegde /*
273a634bfcSVikram Hegde  * Copyright (c) 2009, Intel Corporation.
283a634bfcSVikram Hegde  * All rights reserved.
293a634bfcSVikram Hegde  */
303a634bfcSVikram Hegde 
313a634bfcSVikram Hegde 
323a634bfcSVikram Hegde #include <sys/apic.h>
333a634bfcSVikram Hegde #include <vm/hat_i86.h>
343a634bfcSVikram Hegde #include <sys/sysmacros.h>
353a634bfcSVikram Hegde #include <sys/smp_impldefs.h>
363a634bfcSVikram Hegde #include <sys/immu.h>
373a634bfcSVikram Hegde 
383a634bfcSVikram Hegde 
393a634bfcSVikram Hegde typedef struct intrmap_private {
403a634bfcSVikram Hegde 	immu_t		*ir_immu;
41*50200e77SFrank Van Der Linden 	immu_inv_wait_t	ir_inv_wait;
423a634bfcSVikram Hegde 	uint16_t	ir_idx;
433a634bfcSVikram Hegde 	uint32_t	ir_sid_svt_sq;
443a634bfcSVikram Hegde } intrmap_private_t;
453a634bfcSVikram Hegde 
467ff178cdSJimmy Vetayases #define	INTRMAP_PRIVATE(intrmap) ((intrmap_private_t *)intrmap)
473a634bfcSVikram Hegde 
483a634bfcSVikram Hegde /* interrupt remapping table entry */
493a634bfcSVikram Hegde typedef struct intrmap_rte {
503a634bfcSVikram Hegde 	uint64_t	lo;
513a634bfcSVikram Hegde 	uint64_t	hi;
523a634bfcSVikram Hegde } intrmap_rte_t;
533a634bfcSVikram Hegde 
543a634bfcSVikram Hegde #define	IRTE_HIGH(sid_svt_sq) (sid_svt_sq)
553a634bfcSVikram Hegde #define	IRTE_LOW(dst, vector, dlm, tm, rh, dm, fpd, p)	\
563a634bfcSVikram Hegde 	    (((uint64_t)(dst) << 32) |  \
573a634bfcSVikram Hegde 	    ((uint64_t)(vector) << 16) | \
583a634bfcSVikram Hegde 	    ((uint64_t)(dlm) << 5) | \
593a634bfcSVikram Hegde 	    ((uint64_t)(tm) << 4) | \
603a634bfcSVikram Hegde 	    ((uint64_t)(rh) << 3) | \
613a634bfcSVikram Hegde 	    ((uint64_t)(dm) << 2) | \
623a634bfcSVikram Hegde 	    ((uint64_t)(fpd) << 1) | \
633a634bfcSVikram Hegde 	    (p))
643a634bfcSVikram Hegde 
653a634bfcSVikram Hegde typedef enum {
663a634bfcSVikram Hegde 	SVT_NO_VERIFY = 0, 	/* no verification */
673a634bfcSVikram Hegde 	SVT_ALL_VERIFY,		/* using sid and sq to verify */
683a634bfcSVikram Hegde 	SVT_BUS_VERIFY,		/* verify #startbus and #endbus */
693a634bfcSVikram Hegde 	SVT_RSVD
703a634bfcSVikram Hegde } intrmap_svt_t;
713a634bfcSVikram Hegde 
723a634bfcSVikram Hegde typedef enum {
733a634bfcSVikram Hegde 	SQ_VERIFY_ALL = 0,	/* verify all 16 bits */
743a634bfcSVikram Hegde 	SQ_VERIFY_IGR_1,	/* ignore bit 3 */
753a634bfcSVikram Hegde 	SQ_VERIFY_IGR_2,	/* ignore bit 2-3 */
763a634bfcSVikram Hegde 	SQ_VERIFY_IGR_3		/* ignore bit 1-3 */
773a634bfcSVikram Hegde } intrmap_sq_t;
783a634bfcSVikram Hegde 
793a634bfcSVikram Hegde /*
803a634bfcSVikram Hegde  * S field of the Interrupt Remapping Table Address Register
813a634bfcSVikram Hegde  * the size of the interrupt remapping table is 1 << (immu_intrmap_irta_s + 1)
823a634bfcSVikram Hegde  */
833a634bfcSVikram Hegde static uint_t intrmap_irta_s = INTRMAP_MAX_IRTA_SIZE;
843a634bfcSVikram Hegde 
853a634bfcSVikram Hegde /*
863a634bfcSVikram Hegde  * If true, arrange to suppress broadcast EOI by setting edge-triggered mode
873a634bfcSVikram Hegde  * even for level-triggered interrupts in the interrupt-remapping engine.
883a634bfcSVikram Hegde  * If false, broadcast EOI can still be suppressed if the CPU supports the
893a634bfcSVikram Hegde  * APIC_SVR_SUPPRESS_BROADCAST_EOI bit.  In both cases, the IOAPIC is still
903a634bfcSVikram Hegde  * programmed with the correct trigger mode, and pcplusmp must send an EOI
913a634bfcSVikram Hegde  * to the IOAPIC by writing to the IOAPIC's EOI register to make up for the
923a634bfcSVikram Hegde  * missing broadcast EOI.
933a634bfcSVikram Hegde  */
943a634bfcSVikram Hegde static int intrmap_suppress_brdcst_eoi = 0;
953a634bfcSVikram Hegde 
963a634bfcSVikram Hegde /*
973a634bfcSVikram Hegde  * whether verify the source id of interrupt request
983a634bfcSVikram Hegde  */
993a634bfcSVikram Hegde static int intrmap_enable_sid_verify = 0;
1003a634bfcSVikram Hegde 
1013a634bfcSVikram Hegde /* fault types for DVMA remapping */
1023a634bfcSVikram Hegde static char *immu_dvma_faults[] = {
1033a634bfcSVikram Hegde 	"Reserved",
1043a634bfcSVikram Hegde 	"The present field in root-entry is Clear",
1053a634bfcSVikram Hegde 	"The present field in context-entry is Clear",
1063a634bfcSVikram Hegde 	"Hardware detected invalid programming of a context-entry",
1073a634bfcSVikram Hegde 	"The DMA request attempted to access an address beyond max support",
1083a634bfcSVikram Hegde 	"The Write field in a page-table entry is Clear when DMA write",
1093a634bfcSVikram Hegde 	"The Read field in a page-table entry is Clear when DMA read",
1103a634bfcSVikram Hegde 	"Access the next level page table resulted in error",
1113a634bfcSVikram Hegde 	"Access the root-entry table resulted in error",
1123a634bfcSVikram Hegde 	"Access the context-entry table resulted in error",
1133a634bfcSVikram Hegde 	"Reserved field not initialized to zero in a present root-entry",
1143a634bfcSVikram Hegde 	"Reserved field not initialized to zero in a present context-entry",
1153a634bfcSVikram Hegde 	"Reserved field not initialized to zero in a present page-table entry",
1163a634bfcSVikram Hegde 	"DMA blocked due to the Translation Type field in context-entry",
1173a634bfcSVikram Hegde 	"Incorrect fault event reason number",
1183a634bfcSVikram Hegde };
1193a634bfcSVikram Hegde #define	DVMA_MAX_FAULTS (sizeof (immu_dvma_faults)/(sizeof (char *))) - 1
1203a634bfcSVikram Hegde 
1213a634bfcSVikram Hegde /* fault types for interrupt remapping */
1223a634bfcSVikram Hegde static char *immu_intrmap_faults[] = {
1233a634bfcSVikram Hegde 	"reserved field set in IRTE",
1243a634bfcSVikram Hegde 	"interrupt_index exceed the intr-remap table size",
1253a634bfcSVikram Hegde 	"present field in IRTE is clear",
1263a634bfcSVikram Hegde 	"hardware access intr-remap table address resulted in error",
1273a634bfcSVikram Hegde 	"reserved field set in IRTE, include various conditional",
1283a634bfcSVikram Hegde 	"hardware blocked an interrupt request in Compatibility format",
1293a634bfcSVikram Hegde 	"remappable interrupt request blocked due to verification failure"
1303a634bfcSVikram Hegde };
1313a634bfcSVikram Hegde #define	INTRMAP_MAX_FAULTS \
1323a634bfcSVikram Hegde 	(sizeof (immu_intrmap_faults) / (sizeof (char *))) - 1
1333a634bfcSVikram Hegde 
1343a634bfcSVikram Hegde /* Function prototypes */
1353a634bfcSVikram Hegde static int immu_intrmap_init(int apic_mode);
1363a634bfcSVikram Hegde static void immu_intrmap_switchon(int suppress_brdcst_eoi);
1377ff178cdSJimmy Vetayases static void immu_intrmap_alloc(void **intrmap_private_tbl, dev_info_t *dip,
1387ff178cdSJimmy Vetayases     uint16_t type, int count, uchar_t ioapic_index);
1397ff178cdSJimmy Vetayases static void immu_intrmap_map(void *intrmap_private, void *intrmap_data,
1407ff178cdSJimmy Vetayases     uint16_t type, int count);
1417ff178cdSJimmy Vetayases static void immu_intrmap_free(void **intrmap_privatep);
1427ff178cdSJimmy Vetayases static void immu_intrmap_rdt(void *intrmap_private, ioapic_rdt_t *irdt);
1437ff178cdSJimmy Vetayases static void immu_intrmap_msi(void *intrmap_private, msi_regs_t *mregs);
1443a634bfcSVikram Hegde 
1453a634bfcSVikram Hegde static struct apic_intrmap_ops intrmap_ops = {
1463a634bfcSVikram Hegde 	immu_intrmap_init,
1473a634bfcSVikram Hegde 	immu_intrmap_switchon,
1483a634bfcSVikram Hegde 	immu_intrmap_alloc,
1493a634bfcSVikram Hegde 	immu_intrmap_map,
1503a634bfcSVikram Hegde 	immu_intrmap_free,
1513a634bfcSVikram Hegde 	immu_intrmap_rdt,
1523a634bfcSVikram Hegde 	immu_intrmap_msi,
1533a634bfcSVikram Hegde };
1543a634bfcSVikram Hegde 
1553a634bfcSVikram Hegde /* apic mode, APIC/X2APIC */
1563a634bfcSVikram Hegde static int intrmap_apic_mode = LOCAL_APIC;
1573a634bfcSVikram Hegde 
1583a634bfcSVikram Hegde 
1593a634bfcSVikram Hegde /*
1603a634bfcSVikram Hegde  * helper functions
1613a634bfcSVikram Hegde  */
1623a634bfcSVikram Hegde static uint_t
bitset_find_free(bitset_t * b,uint_t post)1633a634bfcSVikram Hegde bitset_find_free(bitset_t *b, uint_t post)
1643a634bfcSVikram Hegde {
1653a634bfcSVikram Hegde 	uint_t	i;
1663a634bfcSVikram Hegde 	uint_t	cap = bitset_capacity(b);
1673a634bfcSVikram Hegde 
1683a634bfcSVikram Hegde 	if (post == cap)
1693a634bfcSVikram Hegde 		post = 0;
1703a634bfcSVikram Hegde 
1713a634bfcSVikram Hegde 	ASSERT(post < cap);
1723a634bfcSVikram Hegde 
1733a634bfcSVikram Hegde 	for (i = post; i < cap; i++) {
1743a634bfcSVikram Hegde 		if (!bitset_in_set(b, i))
1753a634bfcSVikram Hegde 			return (i);
1763a634bfcSVikram Hegde 	}
1773a634bfcSVikram Hegde 
1783a634bfcSVikram Hegde 	for (i = 0; i < post; i++) {
1793a634bfcSVikram Hegde 		if (!bitset_in_set(b, i))
1803a634bfcSVikram Hegde 			return (i);
1813a634bfcSVikram Hegde 	}
1823a634bfcSVikram Hegde 
1833a634bfcSVikram Hegde 	return (INTRMAP_IDX_FULL);	/* no free index */
1843a634bfcSVikram Hegde }
1853a634bfcSVikram Hegde 
1863a634bfcSVikram Hegde /*
1873a634bfcSVikram Hegde  * helper function to find 'count' contigous free
1883a634bfcSVikram Hegde  * interrupt remapping table entries
1893a634bfcSVikram Hegde  */
1903a634bfcSVikram Hegde static uint_t
bitset_find_multi_free(bitset_t * b,uint_t post,uint_t count)1913a634bfcSVikram Hegde bitset_find_multi_free(bitset_t *b, uint_t post, uint_t count)
1923a634bfcSVikram Hegde {
1933a634bfcSVikram Hegde 	uint_t  i, j;
1943a634bfcSVikram Hegde 	uint_t	cap = bitset_capacity(b);
1953a634bfcSVikram Hegde 
1963a634bfcSVikram Hegde 	if (post == INTRMAP_IDX_FULL) {
1973a634bfcSVikram Hegde 		return (INTRMAP_IDX_FULL);
1983a634bfcSVikram Hegde 	}
1993a634bfcSVikram Hegde 
2003a634bfcSVikram Hegde 	if (count > cap)
2013a634bfcSVikram Hegde 		return (INTRMAP_IDX_FULL);
2023a634bfcSVikram Hegde 
2033a634bfcSVikram Hegde 	ASSERT(post < cap);
2043a634bfcSVikram Hegde 
2053a634bfcSVikram Hegde 	for (i = post; (i + count) <= cap; i++) {
2063a634bfcSVikram Hegde 		for (j = 0; j < count; j++) {
2073a634bfcSVikram Hegde 			if (bitset_in_set(b, (i + j))) {
2083a634bfcSVikram Hegde 				i = i + j;
2093a634bfcSVikram Hegde 				break;
2103a634bfcSVikram Hegde 			}
2113a634bfcSVikram Hegde 			if (j == count - 1)
2123a634bfcSVikram Hegde 				return (i);
2133a634bfcSVikram Hegde 		}
2143a634bfcSVikram Hegde 	}
2153a634bfcSVikram Hegde 
2163a634bfcSVikram Hegde 	for (i = 0; (i < post) && ((i + count) <= cap); i++) {
2173a634bfcSVikram Hegde 		for (j = 0; j < count; j++) {
2183a634bfcSVikram Hegde 			if (bitset_in_set(b, (i + j))) {
2193a634bfcSVikram Hegde 				i = i + j;
2203a634bfcSVikram Hegde 				break;
2213a634bfcSVikram Hegde 			}
2223a634bfcSVikram Hegde 			if (j == count - 1)
2233a634bfcSVikram Hegde 				return (i);
2243a634bfcSVikram Hegde 		}
2253a634bfcSVikram Hegde 	}
2263a634bfcSVikram Hegde 
2273a634bfcSVikram Hegde 	return (INTRMAP_IDX_FULL);  		/* no free index */
2283a634bfcSVikram Hegde }
2293a634bfcSVikram Hegde 
2303a634bfcSVikram Hegde /* alloc one interrupt remapping table entry */
2313a634bfcSVikram Hegde static int
alloc_tbl_entry(intrmap_t * intrmap)2323a634bfcSVikram Hegde alloc_tbl_entry(intrmap_t *intrmap)
2333a634bfcSVikram Hegde {
2343a634bfcSVikram Hegde 	uint32_t idx;
2353a634bfcSVikram Hegde 
2363a634bfcSVikram Hegde 	for (;;) {
2373a634bfcSVikram Hegde 		mutex_enter(&intrmap->intrmap_lock);
2383a634bfcSVikram Hegde 		idx = intrmap->intrmap_free;
2393a634bfcSVikram Hegde 		if (idx != INTRMAP_IDX_FULL) {
2403a634bfcSVikram Hegde 			bitset_add(&intrmap->intrmap_map, idx);
2413a634bfcSVikram Hegde 			intrmap->intrmap_free =
2423a634bfcSVikram Hegde 			    bitset_find_free(&intrmap->intrmap_map, idx + 1);
2433a634bfcSVikram Hegde 			mutex_exit(&intrmap->intrmap_lock);
2443a634bfcSVikram Hegde 			break;
2453a634bfcSVikram Hegde 		}
2463a634bfcSVikram Hegde 
2473a634bfcSVikram Hegde 		/* no free intr entry, use compatible format intr */
2483a634bfcSVikram Hegde 		mutex_exit(&intrmap->intrmap_lock);
2493a634bfcSVikram Hegde 
2503a634bfcSVikram Hegde 		if (intrmap_apic_mode != LOCAL_X2APIC) {
2513a634bfcSVikram Hegde 			break;
2523a634bfcSVikram Hegde 		}
2533a634bfcSVikram Hegde 
2543a634bfcSVikram Hegde 		/*
2553a634bfcSVikram Hegde 		 * x2apic mode not allowed compatible
2563a634bfcSVikram Hegde 		 * interrupt
2573a634bfcSVikram Hegde 		 */
2583a634bfcSVikram Hegde 		delay(IMMU_ALLOC_RESOURCE_DELAY);
2593a634bfcSVikram Hegde 	}
2603a634bfcSVikram Hegde 
2613a634bfcSVikram Hegde 	return (idx);
2623a634bfcSVikram Hegde }
2633a634bfcSVikram Hegde 
2643a634bfcSVikram Hegde /* alloc 'cnt' contigous interrupt remapping table entries */
2653a634bfcSVikram Hegde static int
alloc_tbl_multi_entries(intrmap_t * intrmap,uint_t cnt)2663a634bfcSVikram Hegde alloc_tbl_multi_entries(intrmap_t *intrmap, uint_t cnt)
2673a634bfcSVikram Hegde {
2683a634bfcSVikram Hegde 	uint_t idx, pos, i;
2693a634bfcSVikram Hegde 
2703a634bfcSVikram Hegde 	for (; ; ) {
2713a634bfcSVikram Hegde 		mutex_enter(&intrmap->intrmap_lock);
2723a634bfcSVikram Hegde 		pos = intrmap->intrmap_free;
2733a634bfcSVikram Hegde 		idx = bitset_find_multi_free(&intrmap->intrmap_map, pos, cnt);
2743a634bfcSVikram Hegde 
2753a634bfcSVikram Hegde 		if (idx != INTRMAP_IDX_FULL) {
2763a634bfcSVikram Hegde 			if (idx <= pos && pos < (idx + cnt)) {
2773a634bfcSVikram Hegde 				intrmap->intrmap_free = bitset_find_free(
2783a634bfcSVikram Hegde 				    &intrmap->intrmap_map, idx + cnt);
2793a634bfcSVikram Hegde 			}
2803a634bfcSVikram Hegde 			for (i = 0; i < cnt; i++) {
2813a634bfcSVikram Hegde 				bitset_add(&intrmap->intrmap_map, idx + i);
2823a634bfcSVikram Hegde 			}
2833a634bfcSVikram Hegde 			mutex_exit(&intrmap->intrmap_lock);
284d2256d26SFrank Van Der Linden 			break;
2853a634bfcSVikram Hegde 		}
2863a634bfcSVikram Hegde 
2873a634bfcSVikram Hegde 		mutex_exit(&intrmap->intrmap_lock);
2883a634bfcSVikram Hegde 
2893a634bfcSVikram Hegde 		if (intrmap_apic_mode != LOCAL_X2APIC) {
2903a634bfcSVikram Hegde 			break;
2913a634bfcSVikram Hegde 		}
2923a634bfcSVikram Hegde 
2933a634bfcSVikram Hegde 		/* x2apic mode not allowed comapitible interrupt */
2943a634bfcSVikram Hegde 		delay(IMMU_ALLOC_RESOURCE_DELAY);
2953a634bfcSVikram Hegde 	}
2963a634bfcSVikram Hegde 
2973a634bfcSVikram Hegde 	return (idx);
2983a634bfcSVikram Hegde }
2993a634bfcSVikram Hegde 
3003a634bfcSVikram Hegde /* init interrupt remapping table */
3013a634bfcSVikram Hegde static int
init_unit(immu_t * immu)3023a634bfcSVikram Hegde init_unit(immu_t *immu)
3033a634bfcSVikram Hegde {
3043a634bfcSVikram Hegde 	intrmap_t *intrmap;
3053a634bfcSVikram Hegde 	size_t size;
3063a634bfcSVikram Hegde 
3073a634bfcSVikram Hegde 	ddi_dma_attr_t intrmap_dma_attr = {
3083a634bfcSVikram Hegde 		DMA_ATTR_V0,
3093a634bfcSVikram Hegde 		0U,
310d2256d26SFrank Van Der Linden 		0xffffffffffffffffULL,
3113a634bfcSVikram Hegde 		0xffffffffU,
3123a634bfcSVikram Hegde 		MMU_PAGESIZE,	/* page aligned */
3133a634bfcSVikram Hegde 		0x1,
3143a634bfcSVikram Hegde 		0x1,
3153a634bfcSVikram Hegde 		0xffffffffU,
316d2256d26SFrank Van Der Linden 		0xffffffffffffffffULL,
3173a634bfcSVikram Hegde 		1,
3183a634bfcSVikram Hegde 		4,
3193a634bfcSVikram Hegde 		0
3203a634bfcSVikram Hegde 	};
3213a634bfcSVikram Hegde 
3223a634bfcSVikram Hegde 	ddi_device_acc_attr_t intrmap_acc_attr = {
3233a634bfcSVikram Hegde 		DDI_DEVICE_ATTR_V0,
3243a634bfcSVikram Hegde 		DDI_NEVERSWAP_ACC,
3253a634bfcSVikram Hegde 		DDI_STRICTORDER_ACC
3263a634bfcSVikram Hegde 	};
3273a634bfcSVikram Hegde 
328c94adbf9SFrank Van Der Linden 	/*
329c94adbf9SFrank Van Der Linden 	 * Using interrupt remapping implies using the queue
330c94adbf9SFrank Van Der Linden 	 * invalidation interface. According to Intel,
331c94adbf9SFrank Van Der Linden 	 * hardware that supports interrupt remapping should
332c94adbf9SFrank Van Der Linden 	 * also support QI.
333c94adbf9SFrank Van Der Linden 	 */
334c94adbf9SFrank Van Der Linden 	ASSERT(IMMU_ECAP_GET_QI(immu->immu_regs_excap));
335c94adbf9SFrank Van Der Linden 
3363a634bfcSVikram Hegde 	if (intrmap_apic_mode == LOCAL_X2APIC) {
3373a634bfcSVikram Hegde 		if (!IMMU_ECAP_GET_EIM(immu->immu_regs_excap)) {
3383a634bfcSVikram Hegde 			return (DDI_FAILURE);
3393a634bfcSVikram Hegde 		}
3403a634bfcSVikram Hegde 	}
3413a634bfcSVikram Hegde 
3423a634bfcSVikram Hegde 	if (intrmap_irta_s > INTRMAP_MAX_IRTA_SIZE) {
3433a634bfcSVikram Hegde 		intrmap_irta_s = INTRMAP_MAX_IRTA_SIZE;
3443a634bfcSVikram Hegde 	}
3453a634bfcSVikram Hegde 
3463a634bfcSVikram Hegde 	intrmap =  kmem_zalloc(sizeof (intrmap_t), KM_SLEEP);
3473a634bfcSVikram Hegde 
3483a634bfcSVikram Hegde 	if (ddi_dma_alloc_handle(immu->immu_dip,
3493a634bfcSVikram Hegde 	    &intrmap_dma_attr,
3503a634bfcSVikram Hegde 	    DDI_DMA_SLEEP,
3513a634bfcSVikram Hegde 	    NULL,
3523a634bfcSVikram Hegde 	    &(intrmap->intrmap_dma_hdl)) != DDI_SUCCESS) {
3533a634bfcSVikram Hegde 		kmem_free(intrmap, sizeof (intrmap_t));
3543a634bfcSVikram Hegde 		return (DDI_FAILURE);
3553a634bfcSVikram Hegde 	}
3563a634bfcSVikram Hegde 
3573a634bfcSVikram Hegde 	intrmap->intrmap_size = 1 << (intrmap_irta_s + 1);
3583a634bfcSVikram Hegde 	size = intrmap->intrmap_size * INTRMAP_RTE_SIZE;
3593a634bfcSVikram Hegde 	if (ddi_dma_mem_alloc(intrmap->intrmap_dma_hdl,
3603a634bfcSVikram Hegde 	    size,
3613a634bfcSVikram Hegde 	    &intrmap_acc_attr,
3623a634bfcSVikram Hegde 	    DDI_DMA_CONSISTENT | IOMEM_DATA_UNCACHED,
3633a634bfcSVikram Hegde 	    DDI_DMA_SLEEP,
3643a634bfcSVikram Hegde 	    NULL,
3653a634bfcSVikram Hegde 	    &(intrmap->intrmap_vaddr),
3663a634bfcSVikram Hegde 	    &size,
3673a634bfcSVikram Hegde 	    &(intrmap->intrmap_acc_hdl)) != DDI_SUCCESS) {
3683a634bfcSVikram Hegde 		ddi_dma_free_handle(&(intrmap->intrmap_dma_hdl));
3693a634bfcSVikram Hegde 		kmem_free(intrmap, sizeof (intrmap_t));
3703a634bfcSVikram Hegde 		return (DDI_FAILURE);
3713a634bfcSVikram Hegde 	}
3723a634bfcSVikram Hegde 
3733a634bfcSVikram Hegde 	ASSERT(!((uintptr_t)intrmap->intrmap_vaddr & MMU_PAGEOFFSET));
3743a634bfcSVikram Hegde 	bzero(intrmap->intrmap_vaddr, size);
3753a634bfcSVikram Hegde 	intrmap->intrmap_paddr = pfn_to_pa(
3763a634bfcSVikram Hegde 	    hat_getpfnum(kas.a_hat, intrmap->intrmap_vaddr));
3773a634bfcSVikram Hegde 
3783a634bfcSVikram Hegde 	mutex_init(&(intrmap->intrmap_lock), NULL, MUTEX_DRIVER, NULL);
3793a634bfcSVikram Hegde 	bitset_init(&intrmap->intrmap_map);
3803a634bfcSVikram Hegde 	bitset_resize(&intrmap->intrmap_map, intrmap->intrmap_size);
3813a634bfcSVikram Hegde 	intrmap->intrmap_free = 0;
3823a634bfcSVikram Hegde 
3833a634bfcSVikram Hegde 	immu->immu_intrmap = intrmap;
3843a634bfcSVikram Hegde 
3853a634bfcSVikram Hegde 	return (DDI_SUCCESS);
3863a634bfcSVikram Hegde }
3873a634bfcSVikram Hegde 
3887ff178cdSJimmy Vetayases static immu_t *
get_immu(dev_info_t * dip,uint16_t type,uchar_t ioapic_index)3897ff178cdSJimmy Vetayases get_immu(dev_info_t *dip, uint16_t type, uchar_t ioapic_index)
3903a634bfcSVikram Hegde {
3913a634bfcSVikram Hegde 	immu_t	*immu = NULL;
3923a634bfcSVikram Hegde 
3937ff178cdSJimmy Vetayases 	if (!DDI_INTR_IS_MSI_OR_MSIX(type)) {
3947ff178cdSJimmy Vetayases 		immu = immu_dmar_ioapic_immu(ioapic_index);
3953a634bfcSVikram Hegde 	} else {
3967ff178cdSJimmy Vetayases 		if (dip != NULL)
3977ff178cdSJimmy Vetayases 			immu = immu_dmar_get_immu(dip);
3983a634bfcSVikram Hegde 	}
3993a634bfcSVikram Hegde 
4007ff178cdSJimmy Vetayases 	return (immu);
4013a634bfcSVikram Hegde }
4023a634bfcSVikram Hegde 
4033a634bfcSVikram Hegde static int
get_top_pcibridge(dev_info_t * dip,void * arg)4043a634bfcSVikram Hegde get_top_pcibridge(dev_info_t *dip, void *arg)
4053a634bfcSVikram Hegde {
4063a634bfcSVikram Hegde 	dev_info_t **topdipp = arg;
4073a634bfcSVikram Hegde 	immu_devi_t *immu_devi;
4083a634bfcSVikram Hegde 
4093a634bfcSVikram Hegde 	mutex_enter(&(DEVI(dip)->devi_lock));
4103a634bfcSVikram Hegde 	immu_devi = DEVI(dip)->devi_iommu;
4113a634bfcSVikram Hegde 	mutex_exit(&(DEVI(dip)->devi_lock));
4123a634bfcSVikram Hegde 
4133a634bfcSVikram Hegde 	if (immu_devi == NULL || immu_devi->imd_pcib_type == IMMU_PCIB_BAD ||
4143a634bfcSVikram Hegde 	    immu_devi->imd_pcib_type == IMMU_PCIB_ENDPOINT) {
4153a634bfcSVikram Hegde 		return (DDI_WALK_CONTINUE);
4163a634bfcSVikram Hegde 	}
4173a634bfcSVikram Hegde 
4183a634bfcSVikram Hegde 	*topdipp = dip;
4193a634bfcSVikram Hegde 
4203a634bfcSVikram Hegde 	return (DDI_WALK_CONTINUE);
4213a634bfcSVikram Hegde }
4223a634bfcSVikram Hegde 
4233a634bfcSVikram Hegde static dev_info_t *
intrmap_top_pcibridge(dev_info_t * rdip)4243a634bfcSVikram Hegde intrmap_top_pcibridge(dev_info_t *rdip)
4253a634bfcSVikram Hegde {
4263a634bfcSVikram Hegde 	dev_info_t *top_pcibridge = NULL;
4273a634bfcSVikram Hegde 
4283a634bfcSVikram Hegde 	if (immu_walk_ancestor(rdip, NULL, get_top_pcibridge,
4293a634bfcSVikram Hegde 	    &top_pcibridge, NULL, 0) != DDI_SUCCESS) {
4303a634bfcSVikram Hegde 		return (NULL);
4313a634bfcSVikram Hegde 	}
4323a634bfcSVikram Hegde 
4333a634bfcSVikram Hegde 	return (top_pcibridge);
4343a634bfcSVikram Hegde }
4353a634bfcSVikram Hegde 
4363a634bfcSVikram Hegde /* function to get interrupt request source id */
4377ff178cdSJimmy Vetayases static uint32_t
get_sid(dev_info_t * dip,uint16_t type,uchar_t ioapic_index)4387ff178cdSJimmy Vetayases get_sid(dev_info_t *dip, uint16_t type, uchar_t ioapic_index)
4393a634bfcSVikram Hegde {
4407ff178cdSJimmy Vetayases 	dev_info_t	*pdip;
4413a634bfcSVikram Hegde 	immu_devi_t	*immu_devi;
4423a634bfcSVikram Hegde 	uint16_t	sid;
4433a634bfcSVikram Hegde 	uchar_t		svt, sq;
4443a634bfcSVikram Hegde 
4453a634bfcSVikram Hegde 	if (!intrmap_enable_sid_verify) {
4467ff178cdSJimmy Vetayases 		return (0);
4473a634bfcSVikram Hegde 	}
4483a634bfcSVikram Hegde 
4497ff178cdSJimmy Vetayases 	if (!DDI_INTR_IS_MSI_OR_MSIX(type)) {
4503a634bfcSVikram Hegde 		/* for interrupt through I/O APIC */
4517ff178cdSJimmy Vetayases 		sid = immu_dmar_ioapic_sid(ioapic_index);
4523a634bfcSVikram Hegde 		svt = SVT_ALL_VERIFY;
4533a634bfcSVikram Hegde 		sq = SQ_VERIFY_ALL;
4543a634bfcSVikram Hegde 	} else {
4553a634bfcSVikram Hegde 		/* MSI/MSI-X interrupt */
4563a634bfcSVikram Hegde 		ASSERT(dip);
4573a634bfcSVikram Hegde 		pdip = intrmap_top_pcibridge(dip);
4583a634bfcSVikram Hegde 		ASSERT(pdip);
4593a634bfcSVikram Hegde 		immu_devi = DEVI(pdip)->devi_iommu;
4603a634bfcSVikram Hegde 		ASSERT(immu_devi);
4613a634bfcSVikram Hegde 		if (immu_devi->imd_pcib_type == IMMU_PCIB_PCIE_PCI) {
4623a634bfcSVikram Hegde 			/* device behind pcie to pci bridge */
4633a634bfcSVikram Hegde 			sid = (immu_devi->imd_bus << 8) | immu_devi->imd_sec;
4643a634bfcSVikram Hegde 			svt = SVT_BUS_VERIFY;
4653a634bfcSVikram Hegde 			sq = SQ_VERIFY_ALL;
4663a634bfcSVikram Hegde 		} else {
4673a634bfcSVikram Hegde 			/* pcie device or device behind pci to pci bridge */
4683a634bfcSVikram Hegde 			sid = (immu_devi->imd_bus << 8) |
4693a634bfcSVikram Hegde 			    immu_devi->imd_devfunc;
4703a634bfcSVikram Hegde 			svt = SVT_ALL_VERIFY;
4713a634bfcSVikram Hegde 			sq = SQ_VERIFY_ALL;
4723a634bfcSVikram Hegde 		}
4733a634bfcSVikram Hegde 	}
4743a634bfcSVikram Hegde 
4757ff178cdSJimmy Vetayases 	return (sid | (svt << 18) | (sq << 16));
4763a634bfcSVikram Hegde }
4773a634bfcSVikram Hegde 
4783a634bfcSVikram Hegde static void
intrmap_enable(immu_t * immu)4793a634bfcSVikram Hegde intrmap_enable(immu_t *immu)
4803a634bfcSVikram Hegde {
4813a634bfcSVikram Hegde 	intrmap_t *intrmap;
4823a634bfcSVikram Hegde 	uint64_t irta_reg;
4833a634bfcSVikram Hegde 
4843a634bfcSVikram Hegde 	intrmap = immu->immu_intrmap;
4853a634bfcSVikram Hegde 
4863a634bfcSVikram Hegde 	irta_reg = intrmap->intrmap_paddr | intrmap_irta_s;
4873a634bfcSVikram Hegde 	if (intrmap_apic_mode == LOCAL_X2APIC) {
4883a634bfcSVikram Hegde 		irta_reg |= (0x1 << 11);
4893a634bfcSVikram Hegde 	}
4903a634bfcSVikram Hegde 
4913a634bfcSVikram Hegde 	immu_regs_intrmap_enable(immu, irta_reg);
4923a634bfcSVikram Hegde }
4933a634bfcSVikram Hegde 
4943a634bfcSVikram Hegde /* ####################################################################### */
4953a634bfcSVikram Hegde 
4963a634bfcSVikram Hegde /*
4973a634bfcSVikram Hegde  * immu_intr_handler()
4983a634bfcSVikram Hegde  * 	the fault event handler for a single immu unit
4993a634bfcSVikram Hegde  */
5003a634bfcSVikram Hegde int
immu_intr_handler(immu_t * immu)5013a634bfcSVikram Hegde immu_intr_handler(immu_t *immu)
5023a634bfcSVikram Hegde {
5033a634bfcSVikram Hegde 	uint32_t status;
5043a634bfcSVikram Hegde 	int index, fault_reg_offset;
5053a634bfcSVikram Hegde 	int max_fault_index;
5063a634bfcSVikram Hegde 	boolean_t found_fault;
5073a634bfcSVikram Hegde 	dev_info_t *idip;
5083a634bfcSVikram Hegde 
5093a634bfcSVikram Hegde 	mutex_enter(&(immu->immu_intr_lock));
5103a634bfcSVikram Hegde 	mutex_enter(&(immu->immu_regs_lock));
5113a634bfcSVikram Hegde 
5123a634bfcSVikram Hegde 	/* read the fault status */
5133a634bfcSVikram Hegde 	status = immu_regs_get32(immu, IMMU_REG_FAULT_STS);
5143a634bfcSVikram Hegde 
5153a634bfcSVikram Hegde 	idip = immu->immu_dip;
5163a634bfcSVikram Hegde 	ASSERT(idip);
5173a634bfcSVikram Hegde 
5183a634bfcSVikram Hegde 	/* check if we have a pending fault for this immu unit */
5193a634bfcSVikram Hegde 	if ((status & IMMU_FAULT_STS_PPF) == 0) {
5203a634bfcSVikram Hegde 		mutex_exit(&(immu->immu_regs_lock));
5213a634bfcSVikram Hegde 		mutex_exit(&(immu->immu_intr_lock));
5223a634bfcSVikram Hegde 		return (DDI_INTR_UNCLAIMED);
5233a634bfcSVikram Hegde 	}
5243a634bfcSVikram Hegde 
5253a634bfcSVikram Hegde 	/*
5263a634bfcSVikram Hegde 	 * handle all primary pending faults
5273a634bfcSVikram Hegde 	 */
5283a634bfcSVikram Hegde 	index = IMMU_FAULT_GET_INDEX(status);
5293a634bfcSVikram Hegde 	max_fault_index =  IMMU_CAP_GET_NFR(immu->immu_regs_cap) - 1;
5303a634bfcSVikram Hegde 	fault_reg_offset = IMMU_CAP_GET_FRO(immu->immu_regs_cap);
5313a634bfcSVikram Hegde 
5323a634bfcSVikram Hegde 	found_fault = B_FALSE;
5333a634bfcSVikram Hegde 	_NOTE(CONSTCOND)
5343a634bfcSVikram Hegde 	while (1) {
5353a634bfcSVikram Hegde 		uint64_t val;
5363a634bfcSVikram Hegde 		uint8_t fault_reason;
5373a634bfcSVikram Hegde 		uint8_t fault_type;
5383a634bfcSVikram Hegde 		uint16_t sid;
5393a634bfcSVikram Hegde 		uint64_t pg_addr;
5403a634bfcSVikram Hegde 		uint64_t idx;
5413a634bfcSVikram Hegde 
5423a634bfcSVikram Hegde 		/* read the higher 64bits */
5433a634bfcSVikram Hegde 		val = immu_regs_get64(immu, fault_reg_offset + index * 16 + 8);
5443a634bfcSVikram Hegde 
5453a634bfcSVikram Hegde 		/* check if this fault register has pending fault */
5463a634bfcSVikram Hegde 		if (!IMMU_FRR_GET_F(val)) {
5473a634bfcSVikram Hegde 			break;
5483a634bfcSVikram Hegde 		}
5493a634bfcSVikram Hegde 
5503a634bfcSVikram Hegde 		found_fault = B_TRUE;
5513a634bfcSVikram Hegde 
5523a634bfcSVikram Hegde 		/* get the fault reason, fault type and sid */
5533a634bfcSVikram Hegde 		fault_reason = IMMU_FRR_GET_FR(val);
5543a634bfcSVikram Hegde 		fault_type = IMMU_FRR_GET_FT(val);
5553a634bfcSVikram Hegde 		sid = IMMU_FRR_GET_SID(val);
5563a634bfcSVikram Hegde 
5573a634bfcSVikram Hegde 		/* read the first 64bits */
5583a634bfcSVikram Hegde 		val = immu_regs_get64(immu, fault_reg_offset + index * 16);
5593a634bfcSVikram Hegde 		pg_addr = val & IMMU_PAGEMASK;
5603a634bfcSVikram Hegde 		idx = val >> 48;
5613a634bfcSVikram Hegde 
5623a634bfcSVikram Hegde 		/* clear the fault */
5633a634bfcSVikram Hegde 		immu_regs_put32(immu, fault_reg_offset + index * 16 + 12,
5643a634bfcSVikram Hegde 		    (((uint32_t)1) << 31));
5653a634bfcSVikram Hegde 
5663a634bfcSVikram Hegde 		/* report the fault info */
5673a634bfcSVikram Hegde 		if (fault_reason < 0x20) {
5683a634bfcSVikram Hegde 			/* immu-remapping fault */
5693a634bfcSVikram Hegde 			ddi_err(DER_WARN, idip,
5703a634bfcSVikram Hegde 			    "generated a fault event when translating DMA %s\n"
5713a634bfcSVikram Hegde 			    "\t on address 0x%" PRIx64 " for PCI(%d, %d, %d), "
5723a634bfcSVikram Hegde 			    "the reason is:\n\t %s",
5733a634bfcSVikram Hegde 			    fault_type ? "read" : "write", pg_addr,
5743a634bfcSVikram Hegde 			    (sid >> 8) & 0xff, (sid >> 3) & 0x1f, sid & 0x7,
5753a634bfcSVikram Hegde 			    immu_dvma_faults[MIN(fault_reason,
5763a634bfcSVikram Hegde 			    DVMA_MAX_FAULTS)]);
577*50200e77SFrank Van Der Linden 			immu_print_fault_info(sid, pg_addr);
5783a634bfcSVikram Hegde 		} else if (fault_reason < 0x27) {
5793a634bfcSVikram Hegde 			/* intr-remapping fault */
5803a634bfcSVikram Hegde 			ddi_err(DER_WARN, idip,
5813a634bfcSVikram Hegde 			    "generated a fault event when translating "
5823a634bfcSVikram Hegde 			    "interrupt request\n"
5833a634bfcSVikram Hegde 			    "\t on index 0x%" PRIx64 " for PCI(%d, %d, %d), "
5843a634bfcSVikram Hegde 			    "the reason is:\n\t %s",
5853a634bfcSVikram Hegde 			    idx,
5863a634bfcSVikram Hegde 			    (sid >> 8) & 0xff, (sid >> 3) & 0x1f, sid & 0x7,
5873a634bfcSVikram Hegde 			    immu_intrmap_faults[MIN((fault_reason - 0x20),
5883a634bfcSVikram Hegde 			    INTRMAP_MAX_FAULTS)]);
5893a634bfcSVikram Hegde 		} else {
5903a634bfcSVikram Hegde 			ddi_err(DER_WARN, idip, "Unknown fault reason: 0x%x",
5913a634bfcSVikram Hegde 			    fault_reason);
5923a634bfcSVikram Hegde 		}
5933a634bfcSVikram Hegde 
5943a634bfcSVikram Hegde 		index++;
5953a634bfcSVikram Hegde 		if (index > max_fault_index)
5963a634bfcSVikram Hegde 			index = 0;
5973a634bfcSVikram Hegde 	}
5983a634bfcSVikram Hegde 
5993a634bfcSVikram Hegde 	/* Clear the fault */
6003a634bfcSVikram Hegde 	if (!found_fault) {
6013a634bfcSVikram Hegde 		ddi_err(DER_MODE, idip,
6023a634bfcSVikram Hegde 		    "Fault register set but no fault present");
6033a634bfcSVikram Hegde 	}
6043a634bfcSVikram Hegde 	immu_regs_put32(immu, IMMU_REG_FAULT_STS, 1);
6053a634bfcSVikram Hegde 	mutex_exit(&(immu->immu_regs_lock));
6063a634bfcSVikram Hegde 	mutex_exit(&(immu->immu_intr_lock));
6073a634bfcSVikram Hegde 	return (DDI_INTR_CLAIMED);
6083a634bfcSVikram Hegde }
6093a634bfcSVikram Hegde /* ######################################################################### */
6103a634bfcSVikram Hegde 
6113a634bfcSVikram Hegde /*
6123a634bfcSVikram Hegde  * Interrupt remap entry points
6133a634bfcSVikram Hegde  */
6143a634bfcSVikram Hegde 
6153a634bfcSVikram Hegde /* initialize interrupt remapping */
6163a634bfcSVikram Hegde static int
immu_intrmap_init(int apic_mode)6173a634bfcSVikram Hegde immu_intrmap_init(int apic_mode)
6183a634bfcSVikram Hegde {
6193a634bfcSVikram Hegde 	immu_t *immu;
6203a634bfcSVikram Hegde 	int error = DDI_FAILURE;
6213a634bfcSVikram Hegde 
6223a634bfcSVikram Hegde 	if (immu_intrmap_enable == B_FALSE) {
6233a634bfcSVikram Hegde 		return (DDI_SUCCESS);
6243a634bfcSVikram Hegde 	}
6253a634bfcSVikram Hegde 
6263a634bfcSVikram Hegde 	intrmap_apic_mode = apic_mode;
6273a634bfcSVikram Hegde 
6283a634bfcSVikram Hegde 	immu = list_head(&immu_list);
6293a634bfcSVikram Hegde 	for (; immu; immu = list_next(&immu_list, immu)) {
6303a634bfcSVikram Hegde 		if ((immu->immu_intrmap_running == B_TRUE) &&
6313a634bfcSVikram Hegde 		    IMMU_ECAP_GET_IR(immu->immu_regs_excap)) {
6323a634bfcSVikram Hegde 			if (init_unit(immu) == DDI_SUCCESS) {
6333a634bfcSVikram Hegde 				error = DDI_SUCCESS;
6343a634bfcSVikram Hegde 			}
6353a634bfcSVikram Hegde 		}
6363a634bfcSVikram Hegde 	}
6373a634bfcSVikram Hegde 
6383a634bfcSVikram Hegde 	/*
6393a634bfcSVikram Hegde 	 * if all IOMMU units disable intr remapping,
6403a634bfcSVikram Hegde 	 * return FAILURE
6413a634bfcSVikram Hegde 	 */
6423a634bfcSVikram Hegde 	return (error);
6433a634bfcSVikram Hegde }
6443a634bfcSVikram Hegde 
6453a634bfcSVikram Hegde 
6463a634bfcSVikram Hegde 
6473a634bfcSVikram Hegde /* enable interrupt remapping */
6483a634bfcSVikram Hegde static void
immu_intrmap_switchon(int suppress_brdcst_eoi)6493a634bfcSVikram Hegde immu_intrmap_switchon(int suppress_brdcst_eoi)
6503a634bfcSVikram Hegde {
6513a634bfcSVikram Hegde 	immu_t *immu;
6523a634bfcSVikram Hegde 
6533a634bfcSVikram Hegde 
6543a634bfcSVikram Hegde 	intrmap_suppress_brdcst_eoi = suppress_brdcst_eoi;
6553a634bfcSVikram Hegde 
6563a634bfcSVikram Hegde 	immu = list_head(&immu_list);
6573a634bfcSVikram Hegde 	for (; immu; immu = list_next(&immu_list, immu)) {
6583a634bfcSVikram Hegde 		if (immu->immu_intrmap_setup == B_TRUE) {
6593a634bfcSVikram Hegde 			intrmap_enable(immu);
6603a634bfcSVikram Hegde 		}
6613a634bfcSVikram Hegde 	}
6623a634bfcSVikram Hegde }
6633a634bfcSVikram Hegde 
6643a634bfcSVikram Hegde /* alloc remapping entry for the interrupt */
6653a634bfcSVikram Hegde static void
immu_intrmap_alloc(void ** intrmap_private_tbl,dev_info_t * dip,uint16_t type,int count,uchar_t ioapic_index)6667ff178cdSJimmy Vetayases immu_intrmap_alloc(void **intrmap_private_tbl, dev_info_t *dip,
6677ff178cdSJimmy Vetayases     uint16_t type, int count, uchar_t ioapic_index)
6683a634bfcSVikram Hegde {
6693a634bfcSVikram Hegde 	immu_t	*immu;
6703a634bfcSVikram Hegde 	intrmap_t *intrmap;
671*50200e77SFrank Van Der Linden 	immu_inv_wait_t *iwp;
6727ff178cdSJimmy Vetayases 	uint32_t		idx, i;
6733a634bfcSVikram Hegde 	uint32_t		sid_svt_sq;
6747ff178cdSJimmy Vetayases 	intrmap_private_t	*intrmap_private;
6753a634bfcSVikram Hegde 
6767ff178cdSJimmy Vetayases 	if (intrmap_private_tbl[0] == INTRMAP_DISABLE ||
6777ff178cdSJimmy Vetayases 	    intrmap_private_tbl[0] != NULL) {
6783a634bfcSVikram Hegde 		return;
6793a634bfcSVikram Hegde 	}
6803a634bfcSVikram Hegde 
6817ff178cdSJimmy Vetayases 	intrmap_private_tbl[0] =
6823a634bfcSVikram Hegde 	    kmem_zalloc(sizeof (intrmap_private_t), KM_SLEEP);
6837ff178cdSJimmy Vetayases 	intrmap_private = INTRMAP_PRIVATE(intrmap_private_tbl[0]);
6843a634bfcSVikram Hegde 
6857ff178cdSJimmy Vetayases 	immu = get_immu(dip, type, ioapic_index);
6867ff178cdSJimmy Vetayases 	if ((immu != NULL) && (immu->immu_intrmap_running == B_TRUE)) {
6877ff178cdSJimmy Vetayases 		intrmap_private->ir_immu = immu;
6887ff178cdSJimmy Vetayases 	} else {
6893a634bfcSVikram Hegde 		goto intrmap_disable;
6903a634bfcSVikram Hegde 	}
6913a634bfcSVikram Hegde 
6923a634bfcSVikram Hegde 	intrmap = immu->immu_intrmap;
6933a634bfcSVikram Hegde 
6947ff178cdSJimmy Vetayases 	if (count == 1) {
6953a634bfcSVikram Hegde 		idx = alloc_tbl_entry(intrmap);
6963a634bfcSVikram Hegde 	} else {
6977ff178cdSJimmy Vetayases 		idx = alloc_tbl_multi_entries(intrmap, count);
6983a634bfcSVikram Hegde 	}
6993a634bfcSVikram Hegde 
7003a634bfcSVikram Hegde 	if (idx == INTRMAP_IDX_FULL) {
7013a634bfcSVikram Hegde 		goto intrmap_disable;
7023a634bfcSVikram Hegde 	}
7033a634bfcSVikram Hegde 
7047ff178cdSJimmy Vetayases 	intrmap_private->ir_idx = idx;
7053a634bfcSVikram Hegde 
7067ff178cdSJimmy Vetayases 	sid_svt_sq = intrmap_private->ir_sid_svt_sq =
7077ff178cdSJimmy Vetayases 	    get_sid(dip, type, ioapic_index);
708*50200e77SFrank Van Der Linden 	iwp = &intrmap_private->ir_inv_wait;
709*50200e77SFrank Van Der Linden 	immu_init_inv_wait(iwp, "intrmaplocal", B_TRUE);
7103a634bfcSVikram Hegde 
7117ff178cdSJimmy Vetayases 	if (count == 1) {
7123a634bfcSVikram Hegde 		if (IMMU_CAP_GET_CM(immu->immu_regs_cap)) {
713*50200e77SFrank Van Der Linden 			immu_qinv_intr_one_cache(immu, idx, iwp);
7143a634bfcSVikram Hegde 		} else {
7153a634bfcSVikram Hegde 			immu_regs_wbf_flush(immu);
7163a634bfcSVikram Hegde 		}
7173a634bfcSVikram Hegde 		return;
7183a634bfcSVikram Hegde 	}
7193a634bfcSVikram Hegde 
7207ff178cdSJimmy Vetayases 	for (i = 1; i < count; i++) {
7217ff178cdSJimmy Vetayases 		intrmap_private_tbl[i] =
7223a634bfcSVikram Hegde 		    kmem_zalloc(sizeof (intrmap_private_t), KM_SLEEP);
7233a634bfcSVikram Hegde 
7247ff178cdSJimmy Vetayases 		INTRMAP_PRIVATE(intrmap_private_tbl[i])->ir_immu = immu;
7257ff178cdSJimmy Vetayases 		INTRMAP_PRIVATE(intrmap_private_tbl[i])->ir_sid_svt_sq =
7267ff178cdSJimmy Vetayases 		    sid_svt_sq;
7277ff178cdSJimmy Vetayases 		INTRMAP_PRIVATE(intrmap_private_tbl[i])->ir_idx = idx + i;
7283a634bfcSVikram Hegde 	}
7293a634bfcSVikram Hegde 
7303a634bfcSVikram Hegde 	if (IMMU_CAP_GET_CM(immu->immu_regs_cap)) {
731*50200e77SFrank Van Der Linden 		immu_qinv_intr_caches(immu, idx, count, iwp);
7323a634bfcSVikram Hegde 	} else {
7333a634bfcSVikram Hegde 		immu_regs_wbf_flush(immu);
7343a634bfcSVikram Hegde 	}
7353a634bfcSVikram Hegde 
7363a634bfcSVikram Hegde 	return;
7373a634bfcSVikram Hegde 
7383a634bfcSVikram Hegde intrmap_disable:
7397ff178cdSJimmy Vetayases 	kmem_free(intrmap_private_tbl[0], sizeof (intrmap_private_t));
7407ff178cdSJimmy Vetayases 	intrmap_private_tbl[0] = INTRMAP_DISABLE;
7413a634bfcSVikram Hegde }
7423a634bfcSVikram Hegde 
7433a634bfcSVikram Hegde 
7443a634bfcSVikram Hegde /* remapping the interrupt */
7453a634bfcSVikram Hegde static void
immu_intrmap_map(void * intrmap_private,void * intrmap_data,uint16_t type,int count)7467ff178cdSJimmy Vetayases immu_intrmap_map(void *intrmap_private, void *intrmap_data, uint16_t type,
7477ff178cdSJimmy Vetayases     int count)
7483a634bfcSVikram Hegde {
7493a634bfcSVikram Hegde 	immu_t	*immu;
750*50200e77SFrank Van Der Linden 	immu_inv_wait_t	*iwp;
7513a634bfcSVikram Hegde 	intrmap_t	*intrmap;
7523a634bfcSVikram Hegde 	ioapic_rdt_t	*irdt = (ioapic_rdt_t *)intrmap_data;
7533a634bfcSVikram Hegde 	msi_regs_t	*mregs = (msi_regs_t *)intrmap_data;
7543a634bfcSVikram Hegde 	intrmap_rte_t	irte;
7557ff178cdSJimmy Vetayases 	uint_t		idx, i;
7563a634bfcSVikram Hegde 	uint32_t	dst, sid_svt_sq;
7573a634bfcSVikram Hegde 	uchar_t		vector, dlm, tm, rh, dm;
7583a634bfcSVikram Hegde 
7597ff178cdSJimmy Vetayases 	if (intrmap_private == INTRMAP_DISABLE)
7603a634bfcSVikram Hegde 		return;
7613a634bfcSVikram Hegde 
7627ff178cdSJimmy Vetayases 	idx = INTRMAP_PRIVATE(intrmap_private)->ir_idx;
7637ff178cdSJimmy Vetayases 	immu = INTRMAP_PRIVATE(intrmap_private)->ir_immu;
764*50200e77SFrank Van Der Linden 	iwp = &INTRMAP_PRIVATE(intrmap_private)->ir_inv_wait;
7653a634bfcSVikram Hegde 	intrmap = immu->immu_intrmap;
7667ff178cdSJimmy Vetayases 	sid_svt_sq = INTRMAP_PRIVATE(intrmap_private)->ir_sid_svt_sq;
7673a634bfcSVikram Hegde 
7687ff178cdSJimmy Vetayases 	if (!DDI_INTR_IS_MSI_OR_MSIX(type)) {
7693a634bfcSVikram Hegde 		dm = RDT_DM(irdt->ir_lo);
7703a634bfcSVikram Hegde 		rh = 0;
7713a634bfcSVikram Hegde 		tm = RDT_TM(irdt->ir_lo);
7723a634bfcSVikram Hegde 		dlm = RDT_DLM(irdt->ir_lo);
7733a634bfcSVikram Hegde 		dst = irdt->ir_hi;
7743a634bfcSVikram Hegde 
7753a634bfcSVikram Hegde 		/*
7763a634bfcSVikram Hegde 		 * Mark the IRTE's TM as Edge to suppress broadcast EOI.
7773a634bfcSVikram Hegde 		 */
7783a634bfcSVikram Hegde 		if (intrmap_suppress_brdcst_eoi) {
7793a634bfcSVikram Hegde 			tm = TRIGGER_MODE_EDGE;
7803a634bfcSVikram Hegde 		}
7817ff178cdSJimmy Vetayases 
7827ff178cdSJimmy Vetayases 		vector = RDT_VECTOR(irdt->ir_lo);
7833a634bfcSVikram Hegde 	} else {
7843a634bfcSVikram Hegde 		dm = MSI_ADDR_DM_PHYSICAL;
7853a634bfcSVikram Hegde 		rh = MSI_ADDR_RH_FIXED;
7863a634bfcSVikram Hegde 		tm = TRIGGER_MODE_EDGE;
7873a634bfcSVikram Hegde 		dlm = 0;
7883a634bfcSVikram Hegde 		dst = mregs->mr_addr;
7897ff178cdSJimmy Vetayases 
7907ff178cdSJimmy Vetayases 		vector = mregs->mr_data & 0xff;
7913a634bfcSVikram Hegde 	}
7923a634bfcSVikram Hegde 
7933a634bfcSVikram Hegde 	if (intrmap_apic_mode == LOCAL_APIC)
7943a634bfcSVikram Hegde 		dst = (dst & 0xFF) << 8;
7953a634bfcSVikram Hegde 
7967ff178cdSJimmy Vetayases 	if (count == 1) {
7973a634bfcSVikram Hegde 		irte.lo = IRTE_LOW(dst, vector, dlm, tm, rh, dm, 0, 1);
7983a634bfcSVikram Hegde 		irte.hi = IRTE_HIGH(sid_svt_sq);
7993a634bfcSVikram Hegde 
8003a634bfcSVikram Hegde 		/* set interrupt remapping table entry */
8013a634bfcSVikram Hegde 		bcopy(&irte, intrmap->intrmap_vaddr +
8023a634bfcSVikram Hegde 		    idx * INTRMAP_RTE_SIZE,
8033a634bfcSVikram Hegde 		    INTRMAP_RTE_SIZE);
8043a634bfcSVikram Hegde 
805*50200e77SFrank Van Der Linden 		immu_qinv_intr_one_cache(immu, idx, iwp);
8063a634bfcSVikram Hegde 
8073a634bfcSVikram Hegde 	} else {
8087ff178cdSJimmy Vetayases 		for (i = 0; i < count; i++) {
8093a634bfcSVikram Hegde 			irte.lo = IRTE_LOW(dst, vector, dlm, tm, rh, dm, 0, 1);
8103a634bfcSVikram Hegde 			irte.hi = IRTE_HIGH(sid_svt_sq);
8113a634bfcSVikram Hegde 
8123a634bfcSVikram Hegde 			/* set interrupt remapping table entry */
8133a634bfcSVikram Hegde 			bcopy(&irte, intrmap->intrmap_vaddr +
8143a634bfcSVikram Hegde 			    idx * INTRMAP_RTE_SIZE,
8153a634bfcSVikram Hegde 			    INTRMAP_RTE_SIZE);
8163a634bfcSVikram Hegde 			vector++;
8173a634bfcSVikram Hegde 			idx++;
8183a634bfcSVikram Hegde 		}
8193a634bfcSVikram Hegde 
820*50200e77SFrank Van Der Linden 		immu_qinv_intr_caches(immu, idx, count, iwp);
8213a634bfcSVikram Hegde 	}
8223a634bfcSVikram Hegde }
8233a634bfcSVikram Hegde 
8243a634bfcSVikram Hegde /* free the remapping entry */
8253a634bfcSVikram Hegde static void
immu_intrmap_free(void ** intrmap_privatep)8267ff178cdSJimmy Vetayases immu_intrmap_free(void **intrmap_privatep)
8273a634bfcSVikram Hegde {
8283a634bfcSVikram Hegde 	immu_t *immu;
829*50200e77SFrank Van Der Linden 	immu_inv_wait_t *iwp;
8303a634bfcSVikram Hegde 	intrmap_t *intrmap;
8313a634bfcSVikram Hegde 	uint32_t idx;
8323a634bfcSVikram Hegde 
8337ff178cdSJimmy Vetayases 	if (*intrmap_privatep == INTRMAP_DISABLE || *intrmap_privatep == NULL) {
8347ff178cdSJimmy Vetayases 		*intrmap_privatep = NULL;
8353a634bfcSVikram Hegde 		return;
8363a634bfcSVikram Hegde 	}
8373a634bfcSVikram Hegde 
8387ff178cdSJimmy Vetayases 	immu = INTRMAP_PRIVATE(*intrmap_privatep)->ir_immu;
839*50200e77SFrank Van Der Linden 	iwp = &INTRMAP_PRIVATE(*intrmap_privatep)->ir_inv_wait;
8403a634bfcSVikram Hegde 	intrmap = immu->immu_intrmap;
8417ff178cdSJimmy Vetayases 	idx = INTRMAP_PRIVATE(*intrmap_privatep)->ir_idx;
8423a634bfcSVikram Hegde 
8433a634bfcSVikram Hegde 	bzero(intrmap->intrmap_vaddr + idx * INTRMAP_RTE_SIZE,
8443a634bfcSVikram Hegde 	    INTRMAP_RTE_SIZE);
8453a634bfcSVikram Hegde 
846*50200e77SFrank Van Der Linden 	immu_qinv_intr_one_cache(immu, idx, iwp);
8473a634bfcSVikram Hegde 
8483a634bfcSVikram Hegde 	mutex_enter(&intrmap->intrmap_lock);
8493a634bfcSVikram Hegde 	bitset_del(&intrmap->intrmap_map, idx);
8503a634bfcSVikram Hegde 	if (intrmap->intrmap_free == INTRMAP_IDX_FULL) {
8513a634bfcSVikram Hegde 		intrmap->intrmap_free = idx;
8523a634bfcSVikram Hegde 	}
8533a634bfcSVikram Hegde 	mutex_exit(&intrmap->intrmap_lock);
8543a634bfcSVikram Hegde 
8557ff178cdSJimmy Vetayases 	kmem_free(*intrmap_privatep, sizeof (intrmap_private_t));
8567ff178cdSJimmy Vetayases 	*intrmap_privatep = NULL;
8573a634bfcSVikram Hegde }
8583a634bfcSVikram Hegde 
8593a634bfcSVikram Hegde /* record the ioapic rdt entry */
8603a634bfcSVikram Hegde static void
immu_intrmap_rdt(void * intrmap_private,ioapic_rdt_t * irdt)8617ff178cdSJimmy Vetayases immu_intrmap_rdt(void *intrmap_private, ioapic_rdt_t *irdt)
8623a634bfcSVikram Hegde {
8633a634bfcSVikram Hegde 	uint32_t rdt_entry, tm, pol, idx, vector;
8643a634bfcSVikram Hegde 
8653a634bfcSVikram Hegde 	rdt_entry = irdt->ir_lo;
8663a634bfcSVikram Hegde 
8677ff178cdSJimmy Vetayases 	if (intrmap_private != INTRMAP_DISABLE && intrmap_private != NULL) {
8687ff178cdSJimmy Vetayases 		idx = INTRMAP_PRIVATE(intrmap_private)->ir_idx;
8693a634bfcSVikram Hegde 		tm = RDT_TM(rdt_entry);
8703a634bfcSVikram Hegde 		pol = RDT_POL(rdt_entry);
8717ff178cdSJimmy Vetayases 		vector = RDT_VECTOR(rdt_entry);
8723a634bfcSVikram Hegde 		irdt->ir_lo = (tm << INTRMAP_IOAPIC_TM_SHIFT) |
8733a634bfcSVikram Hegde 		    (pol << INTRMAP_IOAPIC_POL_SHIFT) |
8743a634bfcSVikram Hegde 		    ((idx >> 15) << INTRMAP_IOAPIC_IDX15_SHIFT) |
8753a634bfcSVikram Hegde 		    vector;
8763a634bfcSVikram Hegde 		irdt->ir_hi = (idx << INTRMAP_IOAPIC_IDX_SHIFT) |
8773a634bfcSVikram Hegde 		    (1 << INTRMAP_IOAPIC_FORMAT_SHIFT);
8783a634bfcSVikram Hegde 	} else {
8793a634bfcSVikram Hegde 		irdt->ir_hi <<= APIC_ID_BIT_OFFSET;
8803a634bfcSVikram Hegde 	}
8813a634bfcSVikram Hegde }
8823a634bfcSVikram Hegde 
8833a634bfcSVikram Hegde /* record the msi interrupt structure */
8843a634bfcSVikram Hegde /*ARGSUSED*/
8853a634bfcSVikram Hegde static void
immu_intrmap_msi(void * intrmap_private,msi_regs_t * mregs)8867ff178cdSJimmy Vetayases immu_intrmap_msi(void *intrmap_private, msi_regs_t *mregs)
8873a634bfcSVikram Hegde {
8883a634bfcSVikram Hegde 	uint_t	idx;
8893a634bfcSVikram Hegde 
8907ff178cdSJimmy Vetayases 	if (intrmap_private != INTRMAP_DISABLE && intrmap_private != NULL) {
8917ff178cdSJimmy Vetayases 		idx = INTRMAP_PRIVATE(intrmap_private)->ir_idx;
8923a634bfcSVikram Hegde 
8933a634bfcSVikram Hegde 		mregs->mr_data = 0;
8943a634bfcSVikram Hegde 		mregs->mr_addr = MSI_ADDR_HDR |
8953a634bfcSVikram Hegde 		    ((idx & 0x7fff) << INTRMAP_MSI_IDX_SHIFT) |
8963a634bfcSVikram Hegde 		    (1 << INTRMAP_MSI_FORMAT_SHIFT) |
8973a634bfcSVikram Hegde 		    (1 << INTRMAP_MSI_SHV_SHIFT) |
8983a634bfcSVikram Hegde 		    ((idx >> 15) << INTRMAP_MSI_IDX15_SHIFT);
8993a634bfcSVikram Hegde 	} else {
9003a634bfcSVikram Hegde 		mregs->mr_addr = MSI_ADDR_HDR |
9013a634bfcSVikram Hegde 		    (MSI_ADDR_RH_FIXED << MSI_ADDR_RH_SHIFT) |
9023a634bfcSVikram Hegde 		    (MSI_ADDR_DM_PHYSICAL << MSI_ADDR_DM_SHIFT) |
9033a634bfcSVikram Hegde 		    (mregs->mr_addr << MSI_ADDR_DEST_SHIFT);
9043a634bfcSVikram Hegde 		mregs->mr_data = (MSI_DATA_TM_EDGE << MSI_DATA_TM_SHIFT) |
9053a634bfcSVikram Hegde 		    mregs->mr_data;
9063a634bfcSVikram Hegde 	}
9073a634bfcSVikram Hegde }
9083a634bfcSVikram Hegde 
9093a634bfcSVikram Hegde /* ######################################################################### */
9103a634bfcSVikram Hegde /*
9113a634bfcSVikram Hegde  * Functions exported by immu_intr.c
9123a634bfcSVikram Hegde  */
9133a634bfcSVikram Hegde void
immu_intrmap_setup(list_t * listp)9143a634bfcSVikram Hegde immu_intrmap_setup(list_t *listp)
9153a634bfcSVikram Hegde {
9163a634bfcSVikram Hegde 	immu_t *immu;
9173a634bfcSVikram Hegde 
9183a634bfcSVikram Hegde 	/*
9193a634bfcSVikram Hegde 	 * Check if ACPI DMAR tables say that
9203a634bfcSVikram Hegde 	 * interrupt remapping is supported
9213a634bfcSVikram Hegde 	 */
9223a634bfcSVikram Hegde 	if (immu_dmar_intrmap_supported() == B_FALSE) {
9233a634bfcSVikram Hegde 		return;
9243a634bfcSVikram Hegde 	}
9253a634bfcSVikram Hegde 
9263a634bfcSVikram Hegde 	/*
9273a634bfcSVikram Hegde 	 * Check if interrupt remapping is disabled.
9283a634bfcSVikram Hegde 	 */
9293a634bfcSVikram Hegde 	if (immu_intrmap_enable == B_FALSE) {
9303a634bfcSVikram Hegde 		return;
9313a634bfcSVikram Hegde 	}
9323a634bfcSVikram Hegde 
9333a634bfcSVikram Hegde 	psm_vt_ops = &intrmap_ops;
9343a634bfcSVikram Hegde 
9353a634bfcSVikram Hegde 	immu = list_head(listp);
9363a634bfcSVikram Hegde 	for (; immu; immu = list_next(listp, immu)) {
9373a634bfcSVikram Hegde 		mutex_init(&(immu->immu_intrmap_lock), NULL,
9383a634bfcSVikram Hegde 		    MUTEX_DEFAULT, NULL);
9393a634bfcSVikram Hegde 		mutex_enter(&(immu->immu_intrmap_lock));
940*50200e77SFrank Van Der Linden 		immu_init_inv_wait(&immu->immu_intrmap_inv_wait,
941*50200e77SFrank Van Der Linden 		    "intrmapglobal", B_TRUE);
9423a634bfcSVikram Hegde 		immu->immu_intrmap_setup = B_TRUE;
9433a634bfcSVikram Hegde 		mutex_exit(&(immu->immu_intrmap_lock));
9443a634bfcSVikram Hegde 	}
9453a634bfcSVikram Hegde }
9463a634bfcSVikram Hegde 
9473a634bfcSVikram Hegde void
immu_intrmap_startup(immu_t * immu)9483a634bfcSVikram Hegde immu_intrmap_startup(immu_t *immu)
9493a634bfcSVikram Hegde {
9503a634bfcSVikram Hegde 	/* do nothing */
9513a634bfcSVikram Hegde 	mutex_enter(&(immu->immu_intrmap_lock));
9523a634bfcSVikram Hegde 	if (immu->immu_intrmap_setup == B_TRUE) {
9533a634bfcSVikram Hegde 		immu->immu_intrmap_running = B_TRUE;
9543a634bfcSVikram Hegde 	}
9553a634bfcSVikram Hegde 	mutex_exit(&(immu->immu_intrmap_lock));
9563a634bfcSVikram Hegde }
9573a634bfcSVikram Hegde 
9583a634bfcSVikram Hegde /*
9593a634bfcSVikram Hegde  * Register a Intel IOMMU unit (i.e. DMAR unit's)
9603a634bfcSVikram Hegde  * interrupt handler
9613a634bfcSVikram Hegde  */
9623a634bfcSVikram Hegde void
immu_intr_register(immu_t * immu)9633a634bfcSVikram Hegde immu_intr_register(immu_t *immu)
9643a634bfcSVikram Hegde {
9653a634bfcSVikram Hegde 	int irq, vect;
9663a634bfcSVikram Hegde 	char intr_handler_name[IMMU_MAXNAMELEN];
9673a634bfcSVikram Hegde 	uint32_t msi_data;
9683a634bfcSVikram Hegde 	uint32_t uaddr;
9693a634bfcSVikram Hegde 	uint32_t msi_addr;
9707ff178cdSJimmy Vetayases 	uint32_t localapic_id = 0;
9717ff178cdSJimmy Vetayases 
9727ff178cdSJimmy Vetayases 	if (psm_get_localapicid)
9737ff178cdSJimmy Vetayases 		localapic_id = psm_get_localapicid(0);
9743a634bfcSVikram Hegde 
9753a634bfcSVikram Hegde 	msi_addr = (MSI_ADDR_HDR |
9767ff178cdSJimmy Vetayases 	    ((localapic_id & 0xFF) << MSI_ADDR_DEST_SHIFT) |
9773a634bfcSVikram Hegde 	    (MSI_ADDR_RH_FIXED << MSI_ADDR_RH_SHIFT) |
9783a634bfcSVikram Hegde 	    (MSI_ADDR_DM_PHYSICAL << MSI_ADDR_DM_SHIFT));
9793a634bfcSVikram Hegde 
9803a634bfcSVikram Hegde 	if (intrmap_apic_mode == LOCAL_X2APIC) {
9817ff178cdSJimmy Vetayases 		uaddr = localapic_id & 0xFFFFFF00;
9823a634bfcSVikram Hegde 	} else {
9833a634bfcSVikram Hegde 		uaddr = 0;
9843a634bfcSVikram Hegde 	}
9853a634bfcSVikram Hegde 
9863a634bfcSVikram Hegde 	/* Dont need to hold immu_intr_lock since we are in boot */
9877ff178cdSJimmy Vetayases 	irq = vect = psm_get_ipivect(IMMU_INTR_IPL, -1);
9887ff178cdSJimmy Vetayases 	if (psm_xlate_vector_by_irq != NULL)
9897ff178cdSJimmy Vetayases 		vect = psm_xlate_vector_by_irq(irq);
9907ff178cdSJimmy Vetayases 
9913a634bfcSVikram Hegde 	msi_data = ((MSI_DATA_DELIVERY_FIXED <<
9923a634bfcSVikram Hegde 	    MSI_DATA_DELIVERY_SHIFT) | vect);
9933a634bfcSVikram Hegde 
9943a634bfcSVikram Hegde 	(void) snprintf(intr_handler_name, sizeof (intr_handler_name),
9953a634bfcSVikram Hegde 	    "%s-intr-handler", immu->immu_name);
9963a634bfcSVikram Hegde 
9973a634bfcSVikram Hegde 	(void) add_avintr((void *)NULL, IMMU_INTR_IPL,
9983a634bfcSVikram Hegde 	    (avfunc)(immu_intr_handler), intr_handler_name, irq,
9993a634bfcSVikram Hegde 	    (caddr_t)immu, NULL, NULL, NULL);
10003a634bfcSVikram Hegde 
10013a634bfcSVikram Hegde 	immu_regs_intr_enable(immu, msi_addr, msi_data, uaddr);
10023a634bfcSVikram Hegde 
10033a634bfcSVikram Hegde 	(void) immu_intr_handler(immu);
10043a634bfcSVikram Hegde }
1005