xref: /onnv-gate/usr/src/uts/common/os/ddi_intr.c (revision 10053:79ff8cfc9153)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51542Sjohnny  * Common Development and Distribution License (the "License").
61542Sjohnny  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
228561SScott.Carter@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <sys/note.h>
270Sstevel@tonic-gate #include <sys/sysmacros.h>
280Sstevel@tonic-gate #include <sys/types.h>
290Sstevel@tonic-gate #include <sys/param.h>
300Sstevel@tonic-gate #include <sys/systm.h>
310Sstevel@tonic-gate #include <sys/kmem.h>
320Sstevel@tonic-gate #include <sys/cmn_err.h>
330Sstevel@tonic-gate #include <sys/debug.h>
340Sstevel@tonic-gate #include <sys/avintr.h>
350Sstevel@tonic-gate #include <sys/autoconf.h>
360Sstevel@tonic-gate #include <sys/sunndi.h>
370Sstevel@tonic-gate #include <sys/ndi_impldefs.h>	/* include prototypes */
381725Segillett #include <sys/atomic.h>
390Sstevel@tonic-gate 
400Sstevel@tonic-gate /*
410Sstevel@tonic-gate  * New DDI interrupt framework
420Sstevel@tonic-gate  */
430Sstevel@tonic-gate 
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate  * ddi_intr_get_supported_types:
460Sstevel@tonic-gate  *	Return, as a bit mask, the hardware interrupt types supported by
470Sstevel@tonic-gate  *	both the device and by the host in the integer pointed
480Sstevel@tonic-gate  *	to be the 'typesp' argument.
490Sstevel@tonic-gate  */
500Sstevel@tonic-gate int
510Sstevel@tonic-gate ddi_intr_get_supported_types(dev_info_t *dip, int *typesp)
520Sstevel@tonic-gate {
530Sstevel@tonic-gate 	int			ret;
540Sstevel@tonic-gate 	ddi_intr_handle_impl_t	hdl;
550Sstevel@tonic-gate 
560Sstevel@tonic-gate 	if (dip == NULL)
570Sstevel@tonic-gate 		return (DDI_EINVAL);
580Sstevel@tonic-gate 
590Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: dip %p\n",
600Sstevel@tonic-gate 	    (void *)dip));
610Sstevel@tonic-gate 
620Sstevel@tonic-gate 	if (*typesp = i_ddi_intr_get_supported_types(dip))
630Sstevel@tonic-gate 		return (DDI_SUCCESS);
640Sstevel@tonic-gate 
650Sstevel@tonic-gate 	bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
660Sstevel@tonic-gate 	hdl.ih_dip = dip;
670Sstevel@tonic-gate 
68693Sgovinda 	ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_SUPPORTED_TYPES, &hdl,
690Sstevel@tonic-gate 	    (void *)typesp);
700Sstevel@tonic-gate 
710Sstevel@tonic-gate 	if (ret != DDI_SUCCESS)
720Sstevel@tonic-gate 		return (DDI_INTR_NOTFOUND);
730Sstevel@tonic-gate 
740Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: types %x\n",
750Sstevel@tonic-gate 	    *typesp));
760Sstevel@tonic-gate 
770Sstevel@tonic-gate 	return (ret);
780Sstevel@tonic-gate }
790Sstevel@tonic-gate 
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate  * ddi_intr_get_nintrs:
820Sstevel@tonic-gate  * 	Return as an integer in the integer pointed to by the argument
830Sstevel@tonic-gate  * 	*nintrsp*, the number of interrupts the device supports for the
840Sstevel@tonic-gate  *	given interrupt type.
850Sstevel@tonic-gate  */
860Sstevel@tonic-gate int
870Sstevel@tonic-gate ddi_intr_get_nintrs(dev_info_t *dip, int type, int *nintrsp)
880Sstevel@tonic-gate {
890Sstevel@tonic-gate 	int			ret;
900Sstevel@tonic-gate 	ddi_intr_handle_impl_t	hdl;
910Sstevel@tonic-gate 
92693Sgovinda 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs: dip %p, type: %d\n",
93693Sgovinda 	    (void *)dip, type));
940Sstevel@tonic-gate 
958561SScott.Carter@Sun.COM 	if ((dip == NULL) || (nintrsp == NULL) ||
968561SScott.Carter@Sun.COM 	    !DDI_INTR_TYPE_FLAG_VALID(type) ||
972433Sanish 	    !(i_ddi_intr_get_supported_types(dip) & type)) {
988561SScott.Carter@Sun.COM 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs: "
998561SScott.Carter@Sun.COM 		    "Invalid input args\n"));
1000Sstevel@tonic-gate 		return (DDI_EINVAL);
101693Sgovinda 	}
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 	if (*nintrsp = i_ddi_intr_get_supported_nintrs(dip, type))
1040Sstevel@tonic-gate 		return (DDI_SUCCESS);
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate 	bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
1070Sstevel@tonic-gate 	hdl.ih_dip = dip;
1080Sstevel@tonic-gate 	hdl.ih_type = type;
1090Sstevel@tonic-gate 
110693Sgovinda 	ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_NINTRS, &hdl,
1110Sstevel@tonic-gate 	    (void *)nintrsp);
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs:: nintrs %x\n",
1140Sstevel@tonic-gate 	    *nintrsp));
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	return (ret);
1170Sstevel@tonic-gate }
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate /*
1200Sstevel@tonic-gate  * ddi_intr_get_navail:
1210Sstevel@tonic-gate  *	Bus nexus driver will return availble interrupt count value for
1220Sstevel@tonic-gate  *	a given interrupt type.
1230Sstevel@tonic-gate  *
1240Sstevel@tonic-gate  * 	Return as an integer in the integer pointed to by the argument
1250Sstevel@tonic-gate  * 	*navailp*, the number of interrupts currently available for the
1260Sstevel@tonic-gate  *	given interrupt type.
1270Sstevel@tonic-gate  */
1280Sstevel@tonic-gate int
1290Sstevel@tonic-gate ddi_intr_get_navail(dev_info_t *dip, int type, int *navailp)
1300Sstevel@tonic-gate {
131693Sgovinda 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_navail: dip %p, type: %d\n",
132693Sgovinda 	    (void *)dip, type));
1330Sstevel@tonic-gate 
1348561SScott.Carter@Sun.COM 	if ((dip == NULL) || (navailp == NULL) ||
1358561SScott.Carter@Sun.COM 	    !DDI_INTR_TYPE_FLAG_VALID(type) ||
1362433Sanish 	    !(i_ddi_intr_get_supported_types(dip) & type)) {
1378561SScott.Carter@Sun.COM 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_navail: "
1388561SScott.Carter@Sun.COM 		    "Invalid input args\n"));
1390Sstevel@tonic-gate 		return (DDI_EINVAL);
140693Sgovinda 	}
1410Sstevel@tonic-gate 
1428561SScott.Carter@Sun.COM 	if ((*navailp = i_ddi_intr_get_current_navail(dip, type)) == 0)
1438561SScott.Carter@Sun.COM 		return (DDI_INTR_NOTFOUND);
1440Sstevel@tonic-gate 
1458561SScott.Carter@Sun.COM 	return (DDI_SUCCESS);
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate /*
1490Sstevel@tonic-gate  * Interrupt allocate/free functions
1500Sstevel@tonic-gate  */
1510Sstevel@tonic-gate int
1520Sstevel@tonic-gate ddi_intr_alloc(dev_info_t *dip, ddi_intr_handle_t *h_array, int type, int inum,
1530Sstevel@tonic-gate     int count, int *actualp, int behavior)
1540Sstevel@tonic-gate {
1550Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp, tmp_hdl;
1568561SScott.Carter@Sun.COM 	int			i, ret, cap = 0, curr_type, nintrs;
1578561SScott.Carter@Sun.COM 	uint_t			pri, navail, curr_nintrs = 0;
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: name %s dip 0x%p "
1600Sstevel@tonic-gate 	    "type %x inum %x count %x behavior %x\n", ddi_driver_name(dip),
1610Sstevel@tonic-gate 	    (void *)dip, type, inum, count, behavior));
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	/* Validate parameters */
1648561SScott.Carter@Sun.COM 	if ((dip == NULL) || (h_array == NULL) || (inum < 0) || (count < 1) ||
1658561SScott.Carter@Sun.COM 	    (actualp == NULL) || !DDI_INTR_BEHAVIOR_FLAG_VALID(behavior)) {
1668561SScott.Carter@Sun.COM 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: "
1678561SScott.Carter@Sun.COM 		    "Invalid input args\n"));
1680Sstevel@tonic-gate 		return (DDI_EINVAL);
1690Sstevel@tonic-gate 	}
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	/* Validate interrupt type */
1722433Sanish 	if (!DDI_INTR_TYPE_FLAG_VALID(type) ||
1732433Sanish 	    !(i_ddi_intr_get_supported_types(dip) & type)) {
1740Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x not "
1750Sstevel@tonic-gate 		    "supported\n", type));
1760Sstevel@tonic-gate 		return (DDI_EINVAL);
1770Sstevel@tonic-gate 	}
1780Sstevel@tonic-gate 
1798561SScott.Carter@Sun.COM 	/* Validate inum not previously allocated */
1802433Sanish 	if ((type == DDI_INTR_TYPE_FIXED) &&
1812433Sanish 	    (i_ddi_get_intr_handle(dip, inum) != NULL)) {
1822433Sanish 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: inum %d is already "
1838561SScott.Carter@Sun.COM 		    "in use, cannot allocate again!!\n", inum));
1842433Sanish 		return (DDI_EINVAL);
1852433Sanish 	}
1862433Sanish 
1878561SScott.Carter@Sun.COM 	/* Get how many interrupts the device supports */
1888561SScott.Carter@Sun.COM 	if ((nintrs = i_ddi_intr_get_supported_nintrs(dip, type)) == 0) {
1890Sstevel@tonic-gate 		if (ddi_intr_get_nintrs(dip, type, &nintrs) != DDI_SUCCESS) {
1900Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no "
1910Sstevel@tonic-gate 			    "interrupts found of type %d\n", type));
1920Sstevel@tonic-gate 			return (DDI_INTR_NOTFOUND);
1930Sstevel@tonic-gate 		}
1940Sstevel@tonic-gate 	}
1950Sstevel@tonic-gate 
1968561SScott.Carter@Sun.COM 	/* Get how many interrupts the device is already using */
1978561SScott.Carter@Sun.COM 	if ((curr_type = i_ddi_intr_get_current_type(dip)) != 0) {
1988561SScott.Carter@Sun.COM 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x "
1998561SScott.Carter@Sun.COM 		    "is already being used\n", curr_type));
2008561SScott.Carter@Sun.COM 		curr_nintrs = i_ddi_intr_get_current_nintrs(dip);
2018561SScott.Carter@Sun.COM 	}
2028561SScott.Carter@Sun.COM 
2038561SScott.Carter@Sun.COM 	/* Validate interrupt type consistency */
2048561SScott.Carter@Sun.COM 	if ((curr_type != 0) && (type != curr_type)) {
2058561SScott.Carter@Sun.COM 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Requested "
2068561SScott.Carter@Sun.COM 		    "interrupt type %x is different from interrupt type %x"
2078561SScott.Carter@Sun.COM 		    "already in use\n", type, curr_type));
2088561SScott.Carter@Sun.COM 		return (DDI_EINVAL);
2098561SScott.Carter@Sun.COM 	}
2108561SScott.Carter@Sun.COM 
2118561SScott.Carter@Sun.COM 	/* Validate count does not exceed what device supports */
2120Sstevel@tonic-gate 	if (count > nintrs) {
2130Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no of interrupts "
2140Sstevel@tonic-gate 		    "requested %d is more than supported %d\n", count, nintrs));
2150Sstevel@tonic-gate 		return (DDI_EINVAL);
2168561SScott.Carter@Sun.COM 	} else if ((count + curr_nintrs) > nintrs) {
2178561SScott.Carter@Sun.COM 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: count %d "
2188561SScott.Carter@Sun.COM 		    "+ intrs in use %d exceeds supported %d intrs\n",
2198561SScott.Carter@Sun.COM 		    count, curr_nintrs, nintrs));
2200Sstevel@tonic-gate 		return (DDI_EINVAL);
2210Sstevel@tonic-gate 	}
2220Sstevel@tonic-gate 
2238561SScott.Carter@Sun.COM 	/* Validate power of 2 requirements for MSI */
2248561SScott.Carter@Sun.COM 	if ((type == DDI_INTR_TYPE_MSI) && !ISP2(curr_nintrs + count)) {
2250Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: "
2260Sstevel@tonic-gate 		    "MSI count %d is not a power of two\n", count));
2270Sstevel@tonic-gate 		return (DDI_EINVAL);
2280Sstevel@tonic-gate 	}
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	/*
2318561SScott.Carter@Sun.COM 	 * Initialize the device's interrupt information structure,
2328561SScott.Carter@Sun.COM 	 * and establish an association with IRM if it is supported.
2334974Segillett 	 *
2348561SScott.Carter@Sun.COM 	 * NOTE: IRM checks minimum support, and can return DDI_EAGAIN.
2350Sstevel@tonic-gate 	 */
2368561SScott.Carter@Sun.COM 	if (curr_nintrs == 0) {
2378561SScott.Carter@Sun.COM 		i_ddi_intr_devi_init(dip);
2388561SScott.Carter@Sun.COM 		if (i_ddi_irm_insert(dip, type, count) == DDI_EAGAIN) {
2398561SScott.Carter@Sun.COM 			cmn_err(CE_WARN, "ddi_intr_alloc: "
2408561SScott.Carter@Sun.COM 			    "cannot fit into interrupt pool\n");
2418561SScott.Carter@Sun.COM 			return (DDI_EAGAIN);
2428561SScott.Carter@Sun.COM 		}
2438561SScott.Carter@Sun.COM 	}
2448561SScott.Carter@Sun.COM 
2458561SScott.Carter@Sun.COM 	/* Get how many interrupts are currently available */
2468561SScott.Carter@Sun.COM 	navail = i_ddi_intr_get_current_navail(dip, type);
2474974Segillett 
2488561SScott.Carter@Sun.COM 	/* Validate that requested number of interrupts are available */
2498561SScott.Carter@Sun.COM 	if (curr_nintrs == navail) {
2508561SScott.Carter@Sun.COM 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: max # of intrs %d "
2518561SScott.Carter@Sun.COM 		    "already allocated\n", navail));
2528561SScott.Carter@Sun.COM 		return (DDI_EAGAIN);
2538561SScott.Carter@Sun.COM 	}
2548561SScott.Carter@Sun.COM 	if ((count + curr_nintrs) > navail) {
2558561SScott.Carter@Sun.COM 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: requested # of "
2568561SScott.Carter@Sun.COM 		    "intrs %d exceeds # of available intrs %d\n", count,
2578561SScott.Carter@Sun.COM 		    navail - curr_nintrs));
2588561SScott.Carter@Sun.COM 		if (behavior == DDI_INTR_ALLOC_STRICT) {
2590Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: "
2608561SScott.Carter@Sun.COM 			    "DDI_INTR_ALLOC_STRICT flag is passed, "
2618561SScott.Carter@Sun.COM 			    "return failure\n"));
2628561SScott.Carter@Sun.COM 			i_ddi_intr_devi_fini(dip);
2638561SScott.Carter@Sun.COM 			return (DDI_EAGAIN);
2643625Segillett 		}
2658561SScott.Carter@Sun.COM 		count = navail - curr_nintrs;
2660Sstevel@tonic-gate 	}
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	/* Now allocate required number of interrupts */
2690Sstevel@tonic-gate 	bzero(&tmp_hdl, sizeof (ddi_intr_handle_impl_t));
2700Sstevel@tonic-gate 	tmp_hdl.ih_type = type;
2710Sstevel@tonic-gate 	tmp_hdl.ih_inum = inum;
2720Sstevel@tonic-gate 	tmp_hdl.ih_scratch1 = count;
2731717Swesolows 	tmp_hdl.ih_scratch2 = (void *)(uintptr_t)behavior;
2740Sstevel@tonic-gate 	tmp_hdl.ih_dip = dip;
2750Sstevel@tonic-gate 
276693Sgovinda 	if (i_ddi_intr_ops(dip, dip, DDI_INTROP_ALLOC,
2770Sstevel@tonic-gate 	    &tmp_hdl, (void *)actualp) != DDI_SUCCESS) {
2780Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: allocation "
2790Sstevel@tonic-gate 		    "failed\n"));
2801725Segillett 		i_ddi_intr_devi_fini(dip);
2810Sstevel@tonic-gate 		return (*actualp ? DDI_EAGAIN : DDI_INTR_NOTFOUND);
2820Sstevel@tonic-gate 	}
2830Sstevel@tonic-gate 
284693Sgovinda 	if ((ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_GETPRI,
2850Sstevel@tonic-gate 	    &tmp_hdl, (void *)&pri)) != DDI_SUCCESS) {
2860Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get priority "
2870Sstevel@tonic-gate 		    "failed\n"));
2881725Segillett 		goto fail;
2890Sstevel@tonic-gate 	}
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: getting capability\n"));
2920Sstevel@tonic-gate 
293693Sgovinda 	if ((ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_GETCAP,
2940Sstevel@tonic-gate 	    &tmp_hdl, (void *)&cap)) != DDI_SUCCESS) {
2950Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get capability "
2960Sstevel@tonic-gate 		    "failed\n"));
2971725Segillett 		goto fail;
2980Sstevel@tonic-gate 	}
2990Sstevel@tonic-gate 
3001725Segillett 	/*
3011725Segillett 	 * Save current interrupt type, supported and current intr count.
3021725Segillett 	 */
3030Sstevel@tonic-gate 	i_ddi_intr_set_current_type(dip, type);
3040Sstevel@tonic-gate 	i_ddi_intr_set_supported_nintrs(dip, nintrs);
3050Sstevel@tonic-gate 	i_ddi_intr_set_current_nintrs(dip,
3060Sstevel@tonic-gate 	    i_ddi_intr_get_current_nintrs(dip) + *actualp);
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	/* Now, go and handle each "handle" */
3098561SScott.Carter@Sun.COM 	for (i = inum; i < (inum + *actualp); i++) {
3100Sstevel@tonic-gate 		hdlp = (ddi_intr_handle_impl_t *)kmem_zalloc(
3110Sstevel@tonic-gate 		    (sizeof (ddi_intr_handle_impl_t)), KM_SLEEP);
3120Sstevel@tonic-gate 		rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
3130Sstevel@tonic-gate 		h_array[i] = (struct __ddi_intr_handle *)hdlp;
3140Sstevel@tonic-gate 		hdlp->ih_type = type;
3150Sstevel@tonic-gate 		hdlp->ih_pri = pri;
3160Sstevel@tonic-gate 		hdlp->ih_cap = cap;
3170Sstevel@tonic-gate 		hdlp->ih_ver = DDI_INTR_VERSION;
3180Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ALLOC;
3190Sstevel@tonic-gate 		hdlp->ih_dip = dip;
3208561SScott.Carter@Sun.COM 		hdlp->ih_inum = i;
321916Sschwartz 		i_ddi_alloc_intr_phdl(hdlp);
3220Sstevel@tonic-gate 		if (type & DDI_INTR_TYPE_FIXED)
3238561SScott.Carter@Sun.COM 			i_ddi_set_intr_handle(dip, hdlp->ih_inum,
3248561SScott.Carter@Sun.COM 			    (ddi_intr_handle_t)hdlp);
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: hdlp = 0x%p\n",
3270Sstevel@tonic-gate 		    (void *)h_array[i]));
3280Sstevel@tonic-gate 	}
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	return (DDI_SUCCESS);
3311725Segillett 
3321725Segillett fail:
3331725Segillett 	(void) i_ddi_intr_ops(tmp_hdl.ih_dip, tmp_hdl.ih_dip,
3341725Segillett 	    DDI_INTROP_FREE, &tmp_hdl, NULL);
3351725Segillett 	i_ddi_intr_devi_fini(dip);
3361725Segillett 
3371725Segillett 	return (ret);
3380Sstevel@tonic-gate }
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate int
3410Sstevel@tonic-gate ddi_intr_free(ddi_intr_handle_t h)
3420Sstevel@tonic-gate {
3430Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
3440Sstevel@tonic-gate 	int			ret;
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_free: hdlp = %p\n", (void *)hdlp));
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	if (hdlp == NULL)
3490Sstevel@tonic-gate 		return (DDI_EINVAL);
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
3521725Segillett 	if (((hdlp->ih_flags & DDI_INTR_MSIX_DUP) &&
3531725Segillett 	    (hdlp->ih_state != DDI_IHDL_STATE_ADDED)) ||
3541725Segillett 	    ((hdlp->ih_state != DDI_IHDL_STATE_ALLOC) &&
3551725Segillett 	    (!(hdlp->ih_flags & DDI_INTR_MSIX_DUP)))) {
3560Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
3570Sstevel@tonic-gate 		return (DDI_EINVAL);
3580Sstevel@tonic-gate 	}
3590Sstevel@tonic-gate 
3602588Segillett 	/* Set the number of interrupts to free */
3612588Segillett 	hdlp->ih_scratch1 = 1;
3622588Segillett 
363693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
3640Sstevel@tonic-gate 	    DDI_INTROP_FREE, hdlp, NULL);
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
3670Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
3681725Segillett 		/* This would be the dup vector */
3691725Segillett 		if (hdlp->ih_flags & DDI_INTR_MSIX_DUP)
3701725Segillett 			atomic_dec_32(&hdlp->ih_main->ih_dup_cnt);
3711725Segillett 		else {
3721725Segillett 			i_ddi_intr_set_current_nintrs(hdlp->ih_dip,
3731725Segillett 			    i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1);
3740Sstevel@tonic-gate 
3752588Segillett 			if (hdlp->ih_type & DDI_INTR_TYPE_FIXED)
3762588Segillett 				i_ddi_set_intr_handle(hdlp->ih_dip,
3772588Segillett 				    hdlp->ih_inum, NULL);
3781725Segillett 
3792588Segillett 			i_ddi_intr_devi_fini(hdlp->ih_dip);
3801725Segillett 			i_ddi_free_intr_phdl(hdlp);
381693Sgovinda 		}
3820Sstevel@tonic-gate 		rw_destroy(&hdlp->ih_rwlock);
3830Sstevel@tonic-gate 		kmem_free(hdlp, sizeof (ddi_intr_handle_impl_t));
3840Sstevel@tonic-gate 	}
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 	return (ret);
3870Sstevel@tonic-gate }
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate /*
3900Sstevel@tonic-gate  * Interrupt get/set capacity functions
3910Sstevel@tonic-gate  *
3920Sstevel@tonic-gate  * The logic used to figure this out is shown here:
3930Sstevel@tonic-gate  *
3940Sstevel@tonic-gate  *			Device level		Platform level	    Intr source
3950Sstevel@tonic-gate  * 1. Fixed interrupts
3960Sstevel@tonic-gate  * (non-PCI)
3970Sstevel@tonic-gate  * o Flags supported	N/A			Maskable/Pending/    rootnex
3980Sstevel@tonic-gate  *						No Block Enable
3990Sstevel@tonic-gate  * o navail					1
4000Sstevel@tonic-gate  *
4010Sstevel@tonic-gate  * 2. PCI Fixed interrupts
4020Sstevel@tonic-gate  * o Flags supported	pending/Maskable	Maskable/pending/    pci
4030Sstevel@tonic-gate  *						No Block enable
4040Sstevel@tonic-gate  * o navail		N/A			1
4050Sstevel@tonic-gate  *
4060Sstevel@tonic-gate  * 3. PCI MSI
4070Sstevel@tonic-gate  * o Flags supported	Maskable/Pending	Maskable/Pending    pci
4080Sstevel@tonic-gate  *			Block Enable		(if drvr doesn't)   Block Enable
4090Sstevel@tonic-gate  * o navail		N/A			#vectors - #used    N/A
4100Sstevel@tonic-gate  *
4110Sstevel@tonic-gate  * 4. PCI MSI-X
4120Sstevel@tonic-gate  * o Flags supported	Maskable/Pending	Maskable/Pending    pci
4130Sstevel@tonic-gate  *			Block Enable				    Block Enable
4140Sstevel@tonic-gate  * o navail		N/A			#vectors - #used    N/A
4150Sstevel@tonic-gate  *
4160Sstevel@tonic-gate  * where:
4170Sstevel@tonic-gate  *	#vectors	- Total numbers of vectors available
4180Sstevel@tonic-gate  *	#used		- Total numbers of vectors currently being used
4190Sstevel@tonic-gate  *
4200Sstevel@tonic-gate  * For devices complying to PCI2.3 or greater, see bit10 of Command Register
4210Sstevel@tonic-gate  * 0 - enables assertion of INTx
4220Sstevel@tonic-gate  * 1 - disables assertion of INTx
4230Sstevel@tonic-gate  *
4240Sstevel@tonic-gate  * For non MSI/X interrupts; if the IRQ is shared then all ddi_intr_set_*()
4250Sstevel@tonic-gate  * operations return failure.
4260Sstevel@tonic-gate  */
4270Sstevel@tonic-gate int
4280Sstevel@tonic-gate ddi_intr_get_cap(ddi_intr_handle_t h, int *flagsp)
4290Sstevel@tonic-gate {
4300Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
4310Sstevel@tonic-gate 	int			ret;
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_cap: hdlp = %p\n",
4340Sstevel@tonic-gate 	    (void *)hdlp));
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	*flagsp = 0;
4370Sstevel@tonic-gate 	if (hdlp == NULL)
4380Sstevel@tonic-gate 		return (DDI_EINVAL);
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	if (hdlp->ih_cap) {
4430Sstevel@tonic-gate 		*flagsp = hdlp->ih_cap & ~DDI_INTR_FLAG_MSI64;
4440Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
4450Sstevel@tonic-gate 		return (DDI_SUCCESS);
4460Sstevel@tonic-gate 	}
4470Sstevel@tonic-gate 
448693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
4490Sstevel@tonic-gate 	    DDI_INTROP_GETCAP, hdlp, (void *)flagsp);
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
4520Sstevel@tonic-gate 		hdlp->ih_cap = *flagsp;
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 		/* Mask out MSI/X 64-bit support to the consumer */
4550Sstevel@tonic-gate 		*flagsp &= ~DDI_INTR_FLAG_MSI64;
4560Sstevel@tonic-gate 	}
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
4590Sstevel@tonic-gate 	return (ret);
4600Sstevel@tonic-gate }
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate int
4630Sstevel@tonic-gate ddi_intr_set_cap(ddi_intr_handle_t h, int flags)
4640Sstevel@tonic-gate {
4650Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
4660Sstevel@tonic-gate 	int			ret;
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_cap: hdlp = %p", (void *)hdlp));
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	if (hdlp == NULL)
4710Sstevel@tonic-gate 		return (DDI_EINVAL);
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
4740Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
4750Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
4760Sstevel@tonic-gate 		return (DDI_EINVAL);
4770Sstevel@tonic-gate 	}
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	/* Only DDI_INTR_FLAG_LEVEL or DDI_INTR_FLAG_EDGE are allowed */
4800Sstevel@tonic-gate 	if (!(flags & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) {
4810Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "%s%d: only LEVEL or EDGE capability "
4820Sstevel@tonic-gate 		    "can be set\n", ddi_driver_name(hdlp->ih_dip),
4830Sstevel@tonic-gate 		    ddi_get_instance(hdlp->ih_dip)));
4840Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
4850Sstevel@tonic-gate 		return (DDI_EINVAL);
4860Sstevel@tonic-gate 	}
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	/* Both level/edge flags must be currently supported */
4890Sstevel@tonic-gate 	if (!(hdlp->ih_cap & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) {
4900Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "%s%d: Both LEVEL and EDGE capability"
4910Sstevel@tonic-gate 		    " must be supported\n", ddi_driver_name(hdlp->ih_dip),
4920Sstevel@tonic-gate 		    ddi_get_instance(hdlp->ih_dip)));
4930Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
4940Sstevel@tonic-gate 		return (DDI_ENOTSUP);
4950Sstevel@tonic-gate 	}
4960Sstevel@tonic-gate 
497693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
4980Sstevel@tonic-gate 	    DDI_INTROP_SETCAP, hdlp, &flags);
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
5010Sstevel@tonic-gate 	return (ret);
5020Sstevel@tonic-gate }
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate /*
5050Sstevel@tonic-gate  * Priority related functions
5060Sstevel@tonic-gate  */
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate /*
5090Sstevel@tonic-gate  * ddi_intr_get_hilevel_pri:
5100Sstevel@tonic-gate  *	Returns the minimum priority level for a
5110Sstevel@tonic-gate  *	high-level interrupt on a platform.
5120Sstevel@tonic-gate  */
5130Sstevel@tonic-gate uint_t
5140Sstevel@tonic-gate ddi_intr_get_hilevel_pri(void)
5150Sstevel@tonic-gate {
5160Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_hilevel_pri:\n"));
5170Sstevel@tonic-gate 	return (LOCK_LEVEL + 1);
5180Sstevel@tonic-gate }
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate int
5210Sstevel@tonic-gate ddi_intr_get_pri(ddi_intr_handle_t h, uint_t *prip)
5220Sstevel@tonic-gate {
5230Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
5240Sstevel@tonic-gate 	int			ret;
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pri: hdlp = %p\n",
5270Sstevel@tonic-gate 	    (void *)hdlp));
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	*prip = 0;
5300Sstevel@tonic-gate 	if (hdlp == NULL)
5310Sstevel@tonic-gate 		return (DDI_EINVAL);
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
5340Sstevel@tonic-gate 	/* Already initialized, just return that */
5350Sstevel@tonic-gate 	if (hdlp->ih_pri) {
5360Sstevel@tonic-gate 		*prip = hdlp->ih_pri;
5370Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
5380Sstevel@tonic-gate 		return (DDI_SUCCESS);
5390Sstevel@tonic-gate 	}
5400Sstevel@tonic-gate 
541693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
5420Sstevel@tonic-gate 	    DDI_INTROP_GETPRI, hdlp, (void *)prip);
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 	if (ret == DDI_SUCCESS)
5450Sstevel@tonic-gate 		hdlp->ih_pri = *prip;
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
5480Sstevel@tonic-gate 	return (ret);
5490Sstevel@tonic-gate }
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate int
5520Sstevel@tonic-gate ddi_intr_set_pri(ddi_intr_handle_t h, uint_t pri)
5530Sstevel@tonic-gate {
5540Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
5550Sstevel@tonic-gate 	int			ret;
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: hdlp = %p", (void *)hdlp));
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	if (hdlp == NULL)
5600Sstevel@tonic-gate 		return (DDI_EINVAL);
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	/* Validate priority argument */
5630Sstevel@tonic-gate 	if (pri < DDI_INTR_PRI_MIN || pri > DDI_INTR_PRI_MAX) {
5640Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: invalid priority "
5650Sstevel@tonic-gate 		    "specified  = %x\n", pri));
5660Sstevel@tonic-gate 		return (DDI_EINVAL);
5670Sstevel@tonic-gate 	}
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
5700Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
5710Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
5720Sstevel@tonic-gate 		return (DDI_EINVAL);
5730Sstevel@tonic-gate 	}
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	/* If the passed priority is same as existing priority; do nothing */
5760Sstevel@tonic-gate 	if (pri == hdlp->ih_pri) {
5770Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
5780Sstevel@tonic-gate 		return (DDI_SUCCESS);
5790Sstevel@tonic-gate 	}
5800Sstevel@tonic-gate 
581693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
5820Sstevel@tonic-gate 	    DDI_INTROP_SETPRI, hdlp, &pri);
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	if (ret == DDI_SUCCESS)
5850Sstevel@tonic-gate 		hdlp->ih_pri = pri;
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
5880Sstevel@tonic-gate 	return (ret);
5890Sstevel@tonic-gate }
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate /*
5920Sstevel@tonic-gate  * Interrupt add/duplicate/remove handlers
5930Sstevel@tonic-gate  */
5940Sstevel@tonic-gate int
5950Sstevel@tonic-gate ddi_intr_add_handler(ddi_intr_handle_t h, ddi_intr_handler_t inthandler,
5960Sstevel@tonic-gate     void *arg1, void *arg2)
5970Sstevel@tonic-gate {
5980Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
5990Sstevel@tonic-gate 	int			ret;
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_handler: hdlp = 0x%p\n",
6020Sstevel@tonic-gate 	    (void *)hdlp));
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	if ((hdlp == NULL) || (inthandler == NULL))
6050Sstevel@tonic-gate 		return (DDI_EINVAL);
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
6080Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
6090Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
6100Sstevel@tonic-gate 		return (DDI_EINVAL);
6110Sstevel@tonic-gate 	}
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	hdlp->ih_cb_func = inthandler;
6140Sstevel@tonic-gate 	hdlp->ih_cb_arg1 = arg1;
6150Sstevel@tonic-gate 	hdlp->ih_cb_arg2 = arg2;
6160Sstevel@tonic-gate 
617693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
6180Sstevel@tonic-gate 	    DDI_INTROP_ADDISR, hdlp, NULL);
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
6210Sstevel@tonic-gate 		hdlp->ih_cb_func = NULL;
6220Sstevel@tonic-gate 		hdlp->ih_cb_arg1 = NULL;
6230Sstevel@tonic-gate 		hdlp->ih_cb_arg2 = NULL;
6240Sstevel@tonic-gate 	} else
6250Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ADDED;
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
6280Sstevel@tonic-gate 	return (ret);
6290Sstevel@tonic-gate }
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate int
6321725Segillett ddi_intr_dup_handler(ddi_intr_handle_t org, int dup_inum,
6331725Segillett     ddi_intr_handle_t *dup)
6340Sstevel@tonic-gate {
6350Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)org;
6360Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*dup_hdlp;
6370Sstevel@tonic-gate 	int			ret;
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_dup_handler: hdlp = 0x%p\n",
6400Sstevel@tonic-gate 	    (void *)hdlp));
6410Sstevel@tonic-gate 
6421725Segillett 	/* Do some input argument checking ("dup" handle is not allocated) */
6432433Sanish 	if ((hdlp == NULL) || (*dup != NULL) || (dup_inum < 0)) {
6442433Sanish 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_dup_handler: Invalid "
6452433Sanish 		    "input args\n"));
6460Sstevel@tonic-gate 		return (DDI_EINVAL);
6472433Sanish 	}
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	/* Do some input argument checking */
6520Sstevel@tonic-gate 	if ((hdlp->ih_state == DDI_IHDL_STATE_ALLOC) ||	/* intr handle alloc? */
6531725Segillett 	    (hdlp->ih_type != DDI_INTR_TYPE_MSIX) ||	/* only MSI-X allowed */
6541725Segillett 	    (hdlp->ih_flags & DDI_INTR_MSIX_DUP)) {	/* only dup original */
6550Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
6560Sstevel@tonic-gate 		return (DDI_EINVAL);
6570Sstevel@tonic-gate 	}
6580Sstevel@tonic-gate 
6591725Segillett 	hdlp->ih_scratch1 = dup_inum;
660693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
6611725Segillett 	    DDI_INTROP_DUPVEC, hdlp, NULL);
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
6640Sstevel@tonic-gate 		dup_hdlp = (ddi_intr_handle_impl_t *)
6651725Segillett 		    kmem_alloc(sizeof (ddi_intr_handle_impl_t), KM_SLEEP);
6661725Segillett 
6671725Segillett 		atomic_add_32(&hdlp->ih_dup_cnt, 1);
6680Sstevel@tonic-gate 
6691725Segillett 		*dup = (ddi_intr_handle_t)dup_hdlp;
6701725Segillett 		bcopy(hdlp, dup_hdlp, sizeof (ddi_intr_handle_impl_t));
6711725Segillett 
6721725Segillett 		/* These fields are unique to each dupped msi-x vector */
6730Sstevel@tonic-gate 		rw_init(&dup_hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
6740Sstevel@tonic-gate 		dup_hdlp->ih_state = DDI_IHDL_STATE_ADDED;
6751725Segillett 		dup_hdlp->ih_inum = dup_inum;
6761725Segillett 		dup_hdlp->ih_flags |= DDI_INTR_MSIX_DUP;
6771725Segillett 		dup_hdlp->ih_dup_cnt = 0;
6780Sstevel@tonic-gate 
6791725Segillett 		/* Point back to original vector */
6801725Segillett 		dup_hdlp->ih_main = hdlp;
6810Sstevel@tonic-gate 	}
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
6840Sstevel@tonic-gate 	return (ret);
6850Sstevel@tonic-gate }
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate int
6880Sstevel@tonic-gate ddi_intr_remove_handler(ddi_intr_handle_t h)
6890Sstevel@tonic-gate {
6900Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
6911725Segillett 	int			ret = DDI_SUCCESS;
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_handler: hdlp = %p\n",
6940Sstevel@tonic-gate 	    (void *)hdlp));
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 	if (hdlp == NULL)
6970Sstevel@tonic-gate 		return (DDI_EINVAL);
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
7001725Segillett 
7010Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ADDED) {
7021725Segillett 		ret = DDI_EINVAL;
7031725Segillett 		goto done;
7041725Segillett 	} else if (hdlp->ih_flags & DDI_INTR_MSIX_DUP)
7051725Segillett 		goto done;
7061725Segillett 
7071725Segillett 	ASSERT(hdlp->ih_dup_cnt == 0);
7081725Segillett 	if (hdlp->ih_dup_cnt > 0) {
7091725Segillett 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_handler: MSI-X "
7101725Segillett 		    "dup_cnt %d is not 0\n", hdlp->ih_dup_cnt));
7111725Segillett 		ret = DDI_FAILURE;
7121725Segillett 		goto done;
7130Sstevel@tonic-gate 	}
7140Sstevel@tonic-gate 
715693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
7160Sstevel@tonic-gate 	    DDI_INTROP_REMISR, hdlp, NULL);
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
7190Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ALLOC;
7200Sstevel@tonic-gate 		hdlp->ih_cb_func = NULL;
7210Sstevel@tonic-gate 		hdlp->ih_cb_arg1 = NULL;
7220Sstevel@tonic-gate 		hdlp->ih_cb_arg2 = NULL;
7230Sstevel@tonic-gate 	}
7240Sstevel@tonic-gate 
7251725Segillett done:
7260Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
7270Sstevel@tonic-gate 	return (ret);
7280Sstevel@tonic-gate }
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate /*
731*10053SEvan.Yan@Sun.COM  * Interrupt target get/set functions
732*10053SEvan.Yan@Sun.COM  */
733*10053SEvan.Yan@Sun.COM int
734*10053SEvan.Yan@Sun.COM ddi_intr_get_affinity(ddi_intr_handle_t h, ddi_intr_target_t *tgt_p)
735*10053SEvan.Yan@Sun.COM {
736*10053SEvan.Yan@Sun.COM 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
737*10053SEvan.Yan@Sun.COM 	int			ret;
738*10053SEvan.Yan@Sun.COM 
739*10053SEvan.Yan@Sun.COM 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_affinity: hdlp = %p\n",
740*10053SEvan.Yan@Sun.COM 	    (void *)hdlp));
741*10053SEvan.Yan@Sun.COM 
742*10053SEvan.Yan@Sun.COM 	if ((hdlp == NULL) || (tgt_p == NULL))
743*10053SEvan.Yan@Sun.COM 		return (DDI_EINVAL);
744*10053SEvan.Yan@Sun.COM 
745*10053SEvan.Yan@Sun.COM 	rw_enter(&hdlp->ih_rwlock, RW_READER);
746*10053SEvan.Yan@Sun.COM 	if (hdlp->ih_state != DDI_IHDL_STATE_ENABLE) {
747*10053SEvan.Yan@Sun.COM 		rw_exit(&hdlp->ih_rwlock);
748*10053SEvan.Yan@Sun.COM 		return (DDI_EINVAL);
749*10053SEvan.Yan@Sun.COM 	}
750*10053SEvan.Yan@Sun.COM 
751*10053SEvan.Yan@Sun.COM 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
752*10053SEvan.Yan@Sun.COM 	    DDI_INTROP_GETTARGET, hdlp, (void *)tgt_p);
753*10053SEvan.Yan@Sun.COM 
754*10053SEvan.Yan@Sun.COM 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_affinity: target %x\n",
755*10053SEvan.Yan@Sun.COM 	    *tgt_p));
756*10053SEvan.Yan@Sun.COM 
757*10053SEvan.Yan@Sun.COM 	if (ret == DDI_SUCCESS)
758*10053SEvan.Yan@Sun.COM 		hdlp->ih_target = *tgt_p;
759*10053SEvan.Yan@Sun.COM 
760*10053SEvan.Yan@Sun.COM 	rw_exit(&hdlp->ih_rwlock);
761*10053SEvan.Yan@Sun.COM 	return (ret);
762*10053SEvan.Yan@Sun.COM }
763*10053SEvan.Yan@Sun.COM 
764*10053SEvan.Yan@Sun.COM int
765*10053SEvan.Yan@Sun.COM ddi_intr_set_affinity(ddi_intr_handle_t h, ddi_intr_target_t tgt)
766*10053SEvan.Yan@Sun.COM {
767*10053SEvan.Yan@Sun.COM 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
768*10053SEvan.Yan@Sun.COM 	int			ret;
769*10053SEvan.Yan@Sun.COM 
770*10053SEvan.Yan@Sun.COM 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_affinity: hdlp = %p "
771*10053SEvan.Yan@Sun.COM 	    "target %x\n", (void *)hdlp, tgt));
772*10053SEvan.Yan@Sun.COM 
773*10053SEvan.Yan@Sun.COM 	if (hdlp == NULL)
774*10053SEvan.Yan@Sun.COM 		return (DDI_EINVAL);
775*10053SEvan.Yan@Sun.COM 
776*10053SEvan.Yan@Sun.COM 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
777*10053SEvan.Yan@Sun.COM 	if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
778*10053SEvan.Yan@Sun.COM 	    !(hdlp->ih_cap & DDI_INTR_FLAG_RETARGETABLE)) {
779*10053SEvan.Yan@Sun.COM 		rw_exit(&hdlp->ih_rwlock);
780*10053SEvan.Yan@Sun.COM 		return (DDI_EINVAL);
781*10053SEvan.Yan@Sun.COM 	}
782*10053SEvan.Yan@Sun.COM 
783*10053SEvan.Yan@Sun.COM 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
784*10053SEvan.Yan@Sun.COM 	    DDI_INTROP_SETTARGET, hdlp, &tgt);
785*10053SEvan.Yan@Sun.COM 
786*10053SEvan.Yan@Sun.COM 	if (ret == DDI_SUCCESS)
787*10053SEvan.Yan@Sun.COM 		hdlp->ih_target = tgt;
788*10053SEvan.Yan@Sun.COM 
789*10053SEvan.Yan@Sun.COM 	rw_exit(&hdlp->ih_rwlock);
790*10053SEvan.Yan@Sun.COM 	return (ret);
791*10053SEvan.Yan@Sun.COM }
792*10053SEvan.Yan@Sun.COM 
793*10053SEvan.Yan@Sun.COM /*
7940Sstevel@tonic-gate  * Interrupt enable/disable/block_enable/block_disable handlers
7950Sstevel@tonic-gate  */
7960Sstevel@tonic-gate int
7970Sstevel@tonic-gate ddi_intr_enable(ddi_intr_handle_t h)
7980Sstevel@tonic-gate {
7990Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
8000Sstevel@tonic-gate 	int			ret;
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_enable: hdlp = %p\n",
8030Sstevel@tonic-gate 	    (void *)hdlp));
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 	if (hdlp == NULL)
8060Sstevel@tonic-gate 		return (DDI_EINVAL);
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
8090Sstevel@tonic-gate 	if ((hdlp->ih_state != DDI_IHDL_STATE_ADDED) ||
8100Sstevel@tonic-gate 	    ((hdlp->ih_type == DDI_INTR_TYPE_MSI) &&
8110Sstevel@tonic-gate 	    (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) {
8120Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
8130Sstevel@tonic-gate 		return (DDI_EINVAL);
8140Sstevel@tonic-gate 	}
8150Sstevel@tonic-gate 
8161725Segillett 	I_DDI_VERIFY_MSIX_HANDLE(hdlp);
8171725Segillett 
818693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
8190Sstevel@tonic-gate 	    DDI_INTROP_ENABLE, hdlp, NULL);
8200Sstevel@tonic-gate 
8218817SKerry.Shu@Sun.COM 	if (ret == DDI_SUCCESS) {
8220Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ENABLE;
8238817SKerry.Shu@Sun.COM 		i_ddi_intr_set_current_nenables(hdlp->ih_dip,
8248817SKerry.Shu@Sun.COM 		    i_ddi_intr_get_current_nenables(hdlp->ih_dip) + 1);
8258817SKerry.Shu@Sun.COM 	}
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
8280Sstevel@tonic-gate 	return (ret);
8290Sstevel@tonic-gate }
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate int
8320Sstevel@tonic-gate ddi_intr_disable(ddi_intr_handle_t h)
8330Sstevel@tonic-gate {
8340Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
8350Sstevel@tonic-gate 	int			ret;
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_disable: hdlp = %p\n",
8380Sstevel@tonic-gate 	    (void *)hdlp));
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 	if (hdlp == NULL)
8410Sstevel@tonic-gate 		return (DDI_EINVAL);
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
8440Sstevel@tonic-gate 	if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
8450Sstevel@tonic-gate 	    ((hdlp->ih_type == DDI_INTR_TYPE_MSI) &&
8460Sstevel@tonic-gate 	    (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) {
8470Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
8480Sstevel@tonic-gate 		return (DDI_EINVAL);
8490Sstevel@tonic-gate 	}
8500Sstevel@tonic-gate 
8511725Segillett 	I_DDI_VERIFY_MSIX_HANDLE(hdlp);
8521725Segillett 
853693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
8540Sstevel@tonic-gate 	    DDI_INTROP_DISABLE, hdlp, NULL);
8550Sstevel@tonic-gate 
8568817SKerry.Shu@Sun.COM 	if (ret == DDI_SUCCESS) {
8570Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ADDED;
8588817SKerry.Shu@Sun.COM 		i_ddi_intr_set_current_nenables(hdlp->ih_dip,
8598817SKerry.Shu@Sun.COM 		    i_ddi_intr_get_current_nenables(hdlp->ih_dip) - 1);
8608817SKerry.Shu@Sun.COM 	}
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
8630Sstevel@tonic-gate 	return (ret);
8640Sstevel@tonic-gate }
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate int
8670Sstevel@tonic-gate ddi_intr_block_enable(ddi_intr_handle_t *h_array, int count)
8680Sstevel@tonic-gate {
8690Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp;
8700Sstevel@tonic-gate 	int			i, ret;
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_enable: h_array = %p\n",
8730Sstevel@tonic-gate 	    (void *)h_array));
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 	if (h_array == NULL)
8760Sstevel@tonic-gate 		return (DDI_EINVAL);
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
8790Sstevel@tonic-gate 		hdlp = (ddi_intr_handle_impl_t *)h_array[i];
8800Sstevel@tonic-gate 		rw_enter(&hdlp->ih_rwlock, RW_READER);
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 		if (hdlp->ih_state != DDI_IHDL_STATE_ADDED ||
8830Sstevel@tonic-gate 		    hdlp->ih_type != DDI_INTR_TYPE_MSI ||
8840Sstevel@tonic-gate 		    !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) {
8850Sstevel@tonic-gate 			rw_exit(&hdlp->ih_rwlock);
8860Sstevel@tonic-gate 			return (DDI_EINVAL);
8870Sstevel@tonic-gate 		}
8880Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
8890Sstevel@tonic-gate 	}
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	hdlp = (ddi_intr_handle_impl_t *)h_array[0];
8920Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
8930Sstevel@tonic-gate 	hdlp->ih_scratch1 = count;
8941542Sjohnny 	hdlp->ih_scratch2 = (void *)h_array;
8950Sstevel@tonic-gate 
896693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
8970Sstevel@tonic-gate 	    DDI_INTROP_BLOCKENABLE, hdlp, NULL);
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
9020Sstevel@tonic-gate 		for (i = 0; i < count; i++) {
9030Sstevel@tonic-gate 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
9040Sstevel@tonic-gate 			rw_enter(&hdlp->ih_rwlock, RW_WRITER);
9050Sstevel@tonic-gate 			hdlp->ih_state = DDI_IHDL_STATE_ENABLE;
9060Sstevel@tonic-gate 			rw_exit(&hdlp->ih_rwlock);
9070Sstevel@tonic-gate 		}
9088817SKerry.Shu@Sun.COM 		i_ddi_intr_set_current_nenables(hdlp->ih_dip, 1);
9090Sstevel@tonic-gate 	}
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 	return (ret);
9120Sstevel@tonic-gate }
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate int
9150Sstevel@tonic-gate ddi_intr_block_disable(ddi_intr_handle_t *h_array, int count)
9160Sstevel@tonic-gate {
9170Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp;
9180Sstevel@tonic-gate 	int			i, ret;
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_disable: h_array = %p\n",
9210Sstevel@tonic-gate 	    (void *)h_array));
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 	if (h_array == NULL)
9240Sstevel@tonic-gate 		return (DDI_EINVAL);
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
9270Sstevel@tonic-gate 		hdlp = (ddi_intr_handle_impl_t *)h_array[i];
9280Sstevel@tonic-gate 		rw_enter(&hdlp->ih_rwlock, RW_READER);
9290Sstevel@tonic-gate 		if (hdlp->ih_state != DDI_IHDL_STATE_ENABLE ||
9300Sstevel@tonic-gate 		    hdlp->ih_type != DDI_INTR_TYPE_MSI ||
9310Sstevel@tonic-gate 		    !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) {
9320Sstevel@tonic-gate 			rw_exit(&hdlp->ih_rwlock);
9330Sstevel@tonic-gate 			return (DDI_EINVAL);
9340Sstevel@tonic-gate 		}
9350Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
9360Sstevel@tonic-gate 	}
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 	hdlp = (ddi_intr_handle_impl_t *)h_array[0];
9390Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
9400Sstevel@tonic-gate 	hdlp->ih_scratch1 = count;
9411542Sjohnny 	hdlp->ih_scratch2 = (void *)h_array;
9420Sstevel@tonic-gate 
943693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
9440Sstevel@tonic-gate 	    DDI_INTROP_BLOCKDISABLE, hdlp, NULL);
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
9490Sstevel@tonic-gate 		for (i = 0; i < count; i++) {
9500Sstevel@tonic-gate 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
9510Sstevel@tonic-gate 			rw_enter(&hdlp->ih_rwlock, RW_WRITER);
9520Sstevel@tonic-gate 			hdlp->ih_state = DDI_IHDL_STATE_ADDED;
9530Sstevel@tonic-gate 			rw_exit(&hdlp->ih_rwlock);
9540Sstevel@tonic-gate 		}
9558817SKerry.Shu@Sun.COM 		i_ddi_intr_set_current_nenables(hdlp->ih_dip, 0);
9560Sstevel@tonic-gate 	}
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 	return (ret);
9590Sstevel@tonic-gate }
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate /*
9620Sstevel@tonic-gate  * Interrupt set/clr mask handlers
9630Sstevel@tonic-gate  */
9640Sstevel@tonic-gate int
9650Sstevel@tonic-gate ddi_intr_set_mask(ddi_intr_handle_t h)
9660Sstevel@tonic-gate {
9670Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
9680Sstevel@tonic-gate 	int			ret;
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_mask: hdlp = %p\n",
9710Sstevel@tonic-gate 	    (void *)hdlp));
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 	if (hdlp == NULL)
9740Sstevel@tonic-gate 		return (DDI_EINVAL);
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
9771653Sgovinda 	if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
9781653Sgovinda 	    (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE))) {
9790Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
9800Sstevel@tonic-gate 		return (DDI_EINVAL);
9810Sstevel@tonic-gate 	}
9820Sstevel@tonic-gate 
983693Sgovinda 	ret =  i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
9840Sstevel@tonic-gate 	    DDI_INTROP_SETMASK, hdlp, NULL);
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
9870Sstevel@tonic-gate 	return (ret);
9880Sstevel@tonic-gate }
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate int
9910Sstevel@tonic-gate ddi_intr_clr_mask(ddi_intr_handle_t h)
9920Sstevel@tonic-gate {
9930Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
9940Sstevel@tonic-gate 	int			ret;
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_clr_mask: hdlp = %p\n",
9970Sstevel@tonic-gate 	    (void *)hdlp));
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 	if (hdlp == NULL)
10000Sstevel@tonic-gate 		return (DDI_EINVAL);
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
10031653Sgovinda 	if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
10041653Sgovinda 	    (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE))) {
10050Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
10060Sstevel@tonic-gate 		return (DDI_EINVAL);
10070Sstevel@tonic-gate 	}
10080Sstevel@tonic-gate 
1009693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
10100Sstevel@tonic-gate 	    DDI_INTROP_CLRMASK, hdlp, NULL);
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
10130Sstevel@tonic-gate 	return (ret);
10140Sstevel@tonic-gate }
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate /*
10170Sstevel@tonic-gate  * Interrupt get_pending handler
10180Sstevel@tonic-gate  */
10190Sstevel@tonic-gate int
10200Sstevel@tonic-gate ddi_intr_get_pending(ddi_intr_handle_t h, int *pendingp)
10210Sstevel@tonic-gate {
10220Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
10230Sstevel@tonic-gate 	int			ret;
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pending: hdlp = %p\n",
10260Sstevel@tonic-gate 	    (void *)hdlp));
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 	if (hdlp == NULL)
10290Sstevel@tonic-gate 		return (DDI_EINVAL);
10300Sstevel@tonic-gate 
10310Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
10320Sstevel@tonic-gate 	if (!(hdlp->ih_cap & DDI_INTR_FLAG_PENDING)) {
10330Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
10340Sstevel@tonic-gate 		return (DDI_EINVAL);
10350Sstevel@tonic-gate 	}
10360Sstevel@tonic-gate 
1037693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
10380Sstevel@tonic-gate 	    DDI_INTROP_GETPENDING, hdlp, (void *)pendingp);
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
10410Sstevel@tonic-gate 	return (ret);
10420Sstevel@tonic-gate }
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate /*
1045*10053SEvan.Yan@Sun.COM  * Set the number of interrupts requested from IRM
1046*10053SEvan.Yan@Sun.COM  */
1047*10053SEvan.Yan@Sun.COM int
1048*10053SEvan.Yan@Sun.COM ddi_intr_set_nreq(dev_info_t *dip, int nreq)
1049*10053SEvan.Yan@Sun.COM {
1050*10053SEvan.Yan@Sun.COM 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_nreq: dip %p, nreq %d\n",
1051*10053SEvan.Yan@Sun.COM 	    (void *)dip, nreq));
1052*10053SEvan.Yan@Sun.COM 
1053*10053SEvan.Yan@Sun.COM 	if (dip == NULL)
1054*10053SEvan.Yan@Sun.COM 		return (DDI_EINVAL);
1055*10053SEvan.Yan@Sun.COM 
1056*10053SEvan.Yan@Sun.COM 	return (i_ddi_irm_modify(dip, nreq));
1057*10053SEvan.Yan@Sun.COM }
1058*10053SEvan.Yan@Sun.COM 
1059*10053SEvan.Yan@Sun.COM /*
10600Sstevel@tonic-gate  * Soft interrupt handlers
10610Sstevel@tonic-gate  */
10620Sstevel@tonic-gate /*
10630Sstevel@tonic-gate  * Add a soft interrupt and register its handler
10640Sstevel@tonic-gate  */
10650Sstevel@tonic-gate /* ARGSUSED */
10660Sstevel@tonic-gate int
10670Sstevel@tonic-gate ddi_intr_add_softint(dev_info_t *dip, ddi_softint_handle_t *h_p, int soft_pri,
10680Sstevel@tonic-gate     ddi_intr_handler_t handler, void *arg1)
10690Sstevel@tonic-gate {
10700Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp;
10710Sstevel@tonic-gate 	int			ret;
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: dip = %p, "
10740Sstevel@tonic-gate 	    "softpri = 0x%x\n", (void *)dip, soft_pri));
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 	if ((dip == NULL) || (h_p == NULL) || (handler == NULL)) {
10770Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: "
10780Sstevel@tonic-gate 		    "invalid arguments"));
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate 		return (DDI_EINVAL);
10810Sstevel@tonic-gate 	}
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 	/* Validate input arguments */
10840Sstevel@tonic-gate 	if (soft_pri < DDI_INTR_SOFTPRI_MIN ||
10850Sstevel@tonic-gate 	    soft_pri > DDI_INTR_SOFTPRI_MAX) {
10860Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: invalid "
10870Sstevel@tonic-gate 		    "soft_pri input given  = %x\n", soft_pri));
10880Sstevel@tonic-gate 		return (DDI_EINVAL);
10890Sstevel@tonic-gate 	}
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 	hdlp = (ddi_softint_hdl_impl_t *)kmem_zalloc(
10920Sstevel@tonic-gate 	    sizeof (ddi_softint_hdl_impl_t), KM_SLEEP);
10930Sstevel@tonic-gate 
10940Sstevel@tonic-gate 	/* fill up internally */
10950Sstevel@tonic-gate 	rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
10960Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
10970Sstevel@tonic-gate 	hdlp->ih_pri = soft_pri;
10980Sstevel@tonic-gate 	hdlp->ih_dip = dip;
10990Sstevel@tonic-gate 	hdlp->ih_cb_func = handler;
11000Sstevel@tonic-gate 	hdlp->ih_cb_arg1 = arg1;
11010Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: hdlp = %p\n",
11020Sstevel@tonic-gate 	    (void *)hdlp));
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 	/* do the platform specific calls */
11050Sstevel@tonic-gate 	if ((ret = i_ddi_add_softint(hdlp)) != DDI_SUCCESS) {
11060Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
11070Sstevel@tonic-gate 		rw_destroy(&hdlp->ih_rwlock);
11080Sstevel@tonic-gate 		kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t));
11090Sstevel@tonic-gate 		return (ret);
11100Sstevel@tonic-gate 	}
11110Sstevel@tonic-gate 
11120Sstevel@tonic-gate 	*h_p = (ddi_softint_handle_t)hdlp;
11130Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
11140Sstevel@tonic-gate 	return (ret);
11150Sstevel@tonic-gate }
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate /*
11180Sstevel@tonic-gate  * Remove the soft interrupt
11190Sstevel@tonic-gate  */
11200Sstevel@tonic-gate int
11210Sstevel@tonic-gate ddi_intr_remove_softint(ddi_softint_handle_t h)
11220Sstevel@tonic-gate {
11230Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp = (ddi_softint_hdl_impl_t *)h;
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_softint: hdlp = %p\n",
11260Sstevel@tonic-gate 	    (void *)hdlp));
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate 	if (hdlp == NULL)
11290Sstevel@tonic-gate 		return (DDI_EINVAL);
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
11320Sstevel@tonic-gate 	i_ddi_remove_softint(hdlp);
11330Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
11340Sstevel@tonic-gate 	rw_destroy(&hdlp->ih_rwlock);
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	/* kmem_free the hdl impl_t structure allocated earlier */
11370Sstevel@tonic-gate 	kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t));
11380Sstevel@tonic-gate 	return (DDI_SUCCESS);
11390Sstevel@tonic-gate }
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate /*
11420Sstevel@tonic-gate  * Trigger a soft interrupt
11430Sstevel@tonic-gate  */
11440Sstevel@tonic-gate int
11450Sstevel@tonic-gate ddi_intr_trigger_softint(ddi_softint_handle_t h, void *arg2)
11460Sstevel@tonic-gate {
11470Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp = (ddi_softint_hdl_impl_t *)h;
11480Sstevel@tonic-gate 	int			ret;
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate 	if (hdlp == NULL)
11510Sstevel@tonic-gate 		return (DDI_EINVAL);
11520Sstevel@tonic-gate 
1153278Sgovinda 	if ((ret = i_ddi_trigger_softint(hdlp, arg2)) != DDI_SUCCESS) {
11540Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_trigger_softint: failed, "
11550Sstevel@tonic-gate 		    " ret 0%x\n", ret));
1156278Sgovinda 
1157278Sgovinda 		return (ret);
11580Sstevel@tonic-gate 	}
11590Sstevel@tonic-gate 
1160278Sgovinda 	hdlp->ih_cb_arg2 = arg2;
1161278Sgovinda 	return (DDI_SUCCESS);
11620Sstevel@tonic-gate }
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate /*
11650Sstevel@tonic-gate  * Get the soft interrupt priority
11660Sstevel@tonic-gate  */
11670Sstevel@tonic-gate int
11680Sstevel@tonic-gate ddi_intr_get_softint_pri(ddi_softint_handle_t h, uint_t *soft_prip)
11690Sstevel@tonic-gate {
11700Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp = (ddi_softint_hdl_impl_t *)h;
11710Sstevel@tonic-gate 
11720Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_softint_pri: h = %p\n",
11730Sstevel@tonic-gate 	    (void *)h));
11740Sstevel@tonic-gate 
11750Sstevel@tonic-gate 	if (hdlp == NULL)
11760Sstevel@tonic-gate 		return (DDI_EINVAL);
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
11790Sstevel@tonic-gate 	*soft_prip = hdlp->ih_pri;
11800Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
11810Sstevel@tonic-gate 	return (DDI_SUCCESS);
11820Sstevel@tonic-gate }
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate /*
11850Sstevel@tonic-gate  * Set the soft interrupt priority
11860Sstevel@tonic-gate  */
11870Sstevel@tonic-gate int
11880Sstevel@tonic-gate ddi_intr_set_softint_pri(ddi_softint_handle_t h, uint_t soft_pri)
11890Sstevel@tonic-gate {
11900Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp = (ddi_softint_hdl_impl_t *)h;
11910Sstevel@tonic-gate 	int			ret;
11920Sstevel@tonic-gate 	uint_t			orig_soft_pri;
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: h = %p\n",
11950Sstevel@tonic-gate 	    (void *)h));
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate 	if (hdlp == NULL)
11980Sstevel@tonic-gate 		return (DDI_EINVAL);
11990Sstevel@tonic-gate 
12000Sstevel@tonic-gate 	/* Validate priority argument */
12010Sstevel@tonic-gate 	if (soft_pri < DDI_INTR_SOFTPRI_MIN ||
12020Sstevel@tonic-gate 	    soft_pri > DDI_INTR_SOFTPRI_MAX) {
12030Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: invalid "
12040Sstevel@tonic-gate 		    "soft_pri input given  = %x\n", soft_pri));
12050Sstevel@tonic-gate 		return (DDI_EINVAL);
12060Sstevel@tonic-gate 	}
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
12090Sstevel@tonic-gate 	orig_soft_pri = hdlp->ih_pri;
12100Sstevel@tonic-gate 	hdlp->ih_pri = soft_pri;
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate 	if ((ret = i_ddi_set_softint_pri(hdlp, orig_soft_pri)) != DDI_SUCCESS) {
12130Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: failed, "
12140Sstevel@tonic-gate 		    " ret 0%x\n", ret));
12150Sstevel@tonic-gate 		hdlp->ih_pri = orig_soft_pri;
12160Sstevel@tonic-gate 	}
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
12190Sstevel@tonic-gate 	return (ret);
12200Sstevel@tonic-gate }
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate /*
12230Sstevel@tonic-gate  * Old DDI interrupt framework
1224693Sgovinda  *
1225693Sgovinda  * The following DDI interrupt interfaces are obsolete.
1226693Sgovinda  * Use the above new DDI interrupt interfaces instead.
12270Sstevel@tonic-gate  */
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate int
12300Sstevel@tonic-gate ddi_intr_hilevel(dev_info_t *dip, uint_t inumber)
12310Sstevel@tonic-gate {
12328561SScott.Carter@Sun.COM 	ddi_intr_handle_t	hdl;
12338561SScott.Carter@Sun.COM 	ddi_intr_handle_t	*hdl_p;
12348561SScott.Carter@Sun.COM 	size_t			hdl_sz = 0;
12350Sstevel@tonic-gate 	int			actual, ret;
12360Sstevel@tonic-gate 	uint_t			high_pri, pri;
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: name=%s%d dip=0x%p "
12390Sstevel@tonic-gate 	    "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
12400Sstevel@tonic-gate 	    (void *)dip, inumber));
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate 	/*
12430Sstevel@tonic-gate 	 * The device driver may have already registed with the
12440Sstevel@tonic-gate 	 * framework. If so, first try to get the existing interrupt handle
12450Sstevel@tonic-gate 	 * for that given inumber and use that handle.
12460Sstevel@tonic-gate 	 */
12478561SScott.Carter@Sun.COM 	if ((hdl = i_ddi_get_intr_handle(dip, inumber)) == NULL) {
12488561SScott.Carter@Sun.COM 		hdl_sz = sizeof (ddi_intr_handle_t) * (inumber + 1);
12498561SScott.Carter@Sun.COM 		hdl_p = kmem_zalloc(hdl_sz, KM_SLEEP);
12508561SScott.Carter@Sun.COM 		if ((ret = ddi_intr_alloc(dip, hdl_p, DDI_INTR_TYPE_FIXED,
1251965Sgovinda 		    inumber, 1, &actual,
1252965Sgovinda 		    DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) {
12530Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: "
12540Sstevel@tonic-gate 			    "ddi_intr_alloc failed, ret 0x%x\n", ret));
12558561SScott.Carter@Sun.COM 			kmem_free(hdl_p, hdl_sz);
12560Sstevel@tonic-gate 			return (0);
12570Sstevel@tonic-gate 		}
12588561SScott.Carter@Sun.COM 		hdl = hdl_p[inumber];
12590Sstevel@tonic-gate 	}
12600Sstevel@tonic-gate 
12610Sstevel@tonic-gate 	if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) {
12620Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: "
12630Sstevel@tonic-gate 		    "ddi_intr_get_pri failed, ret 0x%x\n", ret));
12640Sstevel@tonic-gate 		(void) ddi_intr_free(hdl);
12658561SScott.Carter@Sun.COM 		if (hdl_sz)
12668561SScott.Carter@Sun.COM 			kmem_free(hdl_p, hdl_sz);
12670Sstevel@tonic-gate 		return (0);
12680Sstevel@tonic-gate 	}
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 	high_pri = ddi_intr_get_hilevel_pri();
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: pri = %x, "
12730Sstevel@tonic-gate 	    "high_pri = %x\n", pri, high_pri));
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 	/* Free the handle allocated here only if no existing handle exists */
12768561SScott.Carter@Sun.COM 	if (hdl_sz) {
12770Sstevel@tonic-gate 		(void) ddi_intr_free(hdl);
12788561SScott.Carter@Sun.COM 		kmem_free(hdl_p, hdl_sz);
12798561SScott.Carter@Sun.COM 	}
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate 	return (pri >= high_pri);
12820Sstevel@tonic-gate }
12830Sstevel@tonic-gate 
12840Sstevel@tonic-gate int
12850Sstevel@tonic-gate ddi_dev_nintrs(dev_info_t *dip, int *result)
12860Sstevel@tonic-gate {
12870Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: name=%s%d dip=0x%p\n",
12880Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip), (void *)dip));
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate 	if (ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED,
12910Sstevel@tonic-gate 	    result) != DDI_SUCCESS) {
12920Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: "
12930Sstevel@tonic-gate 		    "ddi_intr_get_nintrs failed\n"));
12940Sstevel@tonic-gate 		*result = 0;
12950Sstevel@tonic-gate 	}
12960Sstevel@tonic-gate 
12970Sstevel@tonic-gate 	return (DDI_SUCCESS);
12980Sstevel@tonic-gate }
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate int
13010Sstevel@tonic-gate ddi_get_iblock_cookie(dev_info_t *dip, uint_t inumber,
13020Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep)
13030Sstevel@tonic-gate {
13048561SScott.Carter@Sun.COM 	ddi_intr_handle_t	hdl;
13058561SScott.Carter@Sun.COM 	ddi_intr_handle_t	*hdl_p;
13068561SScott.Carter@Sun.COM 	size_t			hdl_sz = 0;
13070Sstevel@tonic-gate 	int			actual, ret;
13080Sstevel@tonic-gate 	uint_t			pri;
13090Sstevel@tonic-gate 
13100Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: name=%s%d dip=0x%p "
13110Sstevel@tonic-gate 	    "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
13120Sstevel@tonic-gate 	    (void *)dip, inumber));
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate 	ASSERT(iblock_cookiep != NULL);
13150Sstevel@tonic-gate 
13160Sstevel@tonic-gate 	/*
13170Sstevel@tonic-gate 	 * The device driver may have already registed with the
13180Sstevel@tonic-gate 	 * framework. If so, first try to get the existing interrupt handle
13190Sstevel@tonic-gate 	 * for that given inumber and use that handle.
13200Sstevel@tonic-gate 	 */
13218561SScott.Carter@Sun.COM 	if ((hdl = i_ddi_get_intr_handle(dip, inumber)) == NULL) {
13228561SScott.Carter@Sun.COM 		hdl_sz = sizeof (ddi_intr_handle_t) * (inumber + 1);
13238561SScott.Carter@Sun.COM 		hdl_p = kmem_zalloc(hdl_sz, KM_SLEEP);
13248561SScott.Carter@Sun.COM 		if ((ret = ddi_intr_alloc(dip, hdl_p,
13258561SScott.Carter@Sun.COM 		    DDI_INTR_TYPE_FIXED, inumber, 1, &actual,
1326965Sgovinda 		    DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) {
13270Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: "
13280Sstevel@tonic-gate 			    "ddi_intr_alloc failed, ret 0x%x\n", ret));
13298561SScott.Carter@Sun.COM 			kmem_free(hdl_p, hdl_sz);
13300Sstevel@tonic-gate 			return (DDI_INTR_NOTFOUND);
13310Sstevel@tonic-gate 		}
13328561SScott.Carter@Sun.COM 		hdl = hdl_p[inumber];
13330Sstevel@tonic-gate 	}
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate 	if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) {
13360Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: "
13370Sstevel@tonic-gate 		    "ddi_intr_get_pri failed, ret 0x%x\n", ret));
13380Sstevel@tonic-gate 		(void) ddi_intr_free(hdl);
13398561SScott.Carter@Sun.COM 		if (hdl_sz)
13408561SScott.Carter@Sun.COM 			kmem_free(hdl_p, hdl_sz);
13410Sstevel@tonic-gate 		return (DDI_FAILURE);
13420Sstevel@tonic-gate 	}
13430Sstevel@tonic-gate 
134442Sagiri 	*iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)pri;
13450Sstevel@tonic-gate 	/* Free the handle allocated here only if no existing handle exists */
13468561SScott.Carter@Sun.COM 	if (hdl_sz) {
13470Sstevel@tonic-gate 		(void) ddi_intr_free(hdl);
13488561SScott.Carter@Sun.COM 		kmem_free(hdl_p, hdl_sz);
13498561SScott.Carter@Sun.COM 	}
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate 	return (DDI_SUCCESS);
13520Sstevel@tonic-gate }
13530Sstevel@tonic-gate 
13540Sstevel@tonic-gate int
13550Sstevel@tonic-gate ddi_add_intr(dev_info_t *dip, uint_t inumber,
13560Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep,
13570Sstevel@tonic-gate     ddi_idevice_cookie_t *idevice_cookiep,
13580Sstevel@tonic-gate     uint_t (*int_handler)(caddr_t int_handler_arg),
13590Sstevel@tonic-gate     caddr_t int_handler_arg)
13600Sstevel@tonic-gate {
13610Sstevel@tonic-gate 	ddi_intr_handle_t	*hdl_p;
13628561SScott.Carter@Sun.COM 	size_t			hdl_sz;
13630Sstevel@tonic-gate 	int			actual, ret;
13640Sstevel@tonic-gate 	uint_t			pri;
13650Sstevel@tonic-gate 
13660Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: name=%s%d dip=0x%p "
13670Sstevel@tonic-gate 	    "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
13680Sstevel@tonic-gate 	    (void *)dip, inumber));
13690Sstevel@tonic-gate 
13708561SScott.Carter@Sun.COM 	hdl_sz = sizeof (ddi_intr_handle_t) * (inumber + 1);
13718561SScott.Carter@Sun.COM 	hdl_p = kmem_zalloc(hdl_sz, KM_SLEEP);
13720Sstevel@tonic-gate 
13730Sstevel@tonic-gate 	if ((ret = ddi_intr_alloc(dip, hdl_p, DDI_INTR_TYPE_FIXED,
1374965Sgovinda 	    inumber, 1, &actual, DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) {
13750Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
13760Sstevel@tonic-gate 		    "ddi_intr_alloc failed, ret 0x%x\n", ret));
13778561SScott.Carter@Sun.COM 		kmem_free(hdl_p, hdl_sz);
13780Sstevel@tonic-gate 		return (DDI_INTR_NOTFOUND);
13790Sstevel@tonic-gate 	}
13800Sstevel@tonic-gate 
13818561SScott.Carter@Sun.COM 	if ((ret = ddi_intr_get_pri(hdl_p[inumber], &pri)) != DDI_SUCCESS)  {
13820Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
13830Sstevel@tonic-gate 		    "ddi_intr_get_pri failed, ret 0x%x\n", ret));
13848561SScott.Carter@Sun.COM 		(void) ddi_intr_free(hdl_p[inumber]);
13858561SScott.Carter@Sun.COM 		kmem_free(hdl_p, hdl_sz);
13860Sstevel@tonic-gate 		return (DDI_FAILURE);
13870Sstevel@tonic-gate 	}
13880Sstevel@tonic-gate 
13898561SScott.Carter@Sun.COM 	if ((ret = ddi_intr_add_handler(hdl_p[inumber], (ddi_intr_handler_t *)
13900Sstevel@tonic-gate 	    int_handler, int_handler_arg, NULL)) != DDI_SUCCESS) {
13910Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
13920Sstevel@tonic-gate 		    "ddi_intr_add_handler failed, ret 0x%x\n", ret));
13938561SScott.Carter@Sun.COM 		(void) ddi_intr_free(hdl_p[inumber]);
13948561SScott.Carter@Sun.COM 		kmem_free(hdl_p, hdl_sz);
13950Sstevel@tonic-gate 		return (DDI_FAILURE);
13960Sstevel@tonic-gate 	}
13970Sstevel@tonic-gate 
13988561SScott.Carter@Sun.COM 	if ((ret = ddi_intr_enable(hdl_p[inumber])) != DDI_SUCCESS) {
13990Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
14000Sstevel@tonic-gate 		    "ddi_intr_enable failed, ret 0x%x\n", ret));
14018561SScott.Carter@Sun.COM 		(void) ddi_intr_remove_handler(hdl_p[inumber]);
14028561SScott.Carter@Sun.COM 		(void) ddi_intr_free(hdl_p[inumber]);
14038561SScott.Carter@Sun.COM 		kmem_free(hdl_p, hdl_sz);
14040Sstevel@tonic-gate 		return (DDI_FAILURE);
14050Sstevel@tonic-gate 	}
14060Sstevel@tonic-gate 
14070Sstevel@tonic-gate 	if (iblock_cookiep)
140842Sagiri 		*iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)pri;
14090Sstevel@tonic-gate 
14100Sstevel@tonic-gate 	if (idevice_cookiep) {
14110Sstevel@tonic-gate 		idevice_cookiep->idev_vector = 0;
14120Sstevel@tonic-gate 		idevice_cookiep->idev_priority = pri;
14130Sstevel@tonic-gate 	}
14140Sstevel@tonic-gate 
14158561SScott.Carter@Sun.COM 	kmem_free(hdl_p, hdl_sz);
14168561SScott.Carter@Sun.COM 
14170Sstevel@tonic-gate 	return (DDI_SUCCESS);
14180Sstevel@tonic-gate }
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate /* ARGSUSED */
14210Sstevel@tonic-gate int
14220Sstevel@tonic-gate ddi_add_fastintr(dev_info_t *dip, uint_t inumber,
14230Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep,
14240Sstevel@tonic-gate     ddi_idevice_cookie_t *idevice_cookiep,
14250Sstevel@tonic-gate     uint_t (*hi_int_handler)(void))
14260Sstevel@tonic-gate {
14270Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_fastintr: name=%s%d dip=0x%p "
14280Sstevel@tonic-gate 	    "inum=0x%x: Not supported, return failure\n", ddi_driver_name(dip),
14290Sstevel@tonic-gate 	    ddi_get_instance(dip), (void *)dip, inumber));
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate 	return (DDI_FAILURE);
14320Sstevel@tonic-gate }
14330Sstevel@tonic-gate 
14340Sstevel@tonic-gate /* ARGSUSED */
14350Sstevel@tonic-gate void
14360Sstevel@tonic-gate ddi_remove_intr(dev_info_t *dip, uint_t inum, ddi_iblock_cookie_t iblock_cookie)
14370Sstevel@tonic-gate {
14388561SScott.Carter@Sun.COM 	ddi_intr_handle_t	hdl;
14390Sstevel@tonic-gate 	int			ret;
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: name=%s%d dip=0x%p "
14420Sstevel@tonic-gate 	    "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
14430Sstevel@tonic-gate 	    (void *)dip, inum));
14440Sstevel@tonic-gate 
14458561SScott.Carter@Sun.COM 	if ((hdl = i_ddi_get_intr_handle(dip, inum)) == NULL) {
14460Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: no handle "
14470Sstevel@tonic-gate 		    "found\n"));
14480Sstevel@tonic-gate 		return;
14490Sstevel@tonic-gate 	}
14500Sstevel@tonic-gate 
14518561SScott.Carter@Sun.COM 	if ((ret = ddi_intr_disable(hdl)) != DDI_SUCCESS) {
14520Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
14530Sstevel@tonic-gate 		    "ddi_intr_disable failed, ret 0x%x\n", ret));
14540Sstevel@tonic-gate 		return;
14550Sstevel@tonic-gate 	}
14560Sstevel@tonic-gate 
14578561SScott.Carter@Sun.COM 	if ((ret = ddi_intr_remove_handler(hdl)) != DDI_SUCCESS) {
14580Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
14590Sstevel@tonic-gate 		    "ddi_intr_remove_handler failed, ret 0x%x\n", ret));
14600Sstevel@tonic-gate 		return;
14610Sstevel@tonic-gate 	}
14620Sstevel@tonic-gate 
14638561SScott.Carter@Sun.COM 	if ((ret = ddi_intr_free(hdl)) != DDI_SUCCESS) {
14640Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
14650Sstevel@tonic-gate 		    "ddi_intr_free failed, ret 0x%x\n", ret));
14660Sstevel@tonic-gate 		return;
14670Sstevel@tonic-gate 	}
14680Sstevel@tonic-gate }
14690Sstevel@tonic-gate 
14700Sstevel@tonic-gate /* ARGSUSED */
14710Sstevel@tonic-gate int
14720Sstevel@tonic-gate ddi_get_soft_iblock_cookie(dev_info_t *dip, int preference,
14730Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep)
14740Sstevel@tonic-gate {
14750Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_get_soft_iblock_cookie: name=%s%d "
14760Sstevel@tonic-gate 	    "dip=0x%p pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
14770Sstevel@tonic-gate 	    (void *)dip, preference));
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate 	ASSERT(iblock_cookiep != NULL);
14800Sstevel@tonic-gate 
14810Sstevel@tonic-gate 	if (preference == DDI_SOFTINT_FIXED)
14820Sstevel@tonic-gate 		return (DDI_FAILURE);
14830Sstevel@tonic-gate 
148442Sagiri 	*iblock_cookiep = (ddi_iblock_cookie_t)((uintptr_t)
14850Sstevel@tonic-gate 	    ((preference > DDI_SOFTINT_MED) ? DDI_SOFT_INTR_PRI_H :
14860Sstevel@tonic-gate 	    DDI_SOFT_INTR_PRI_M));
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate 	return (DDI_SUCCESS);
14890Sstevel@tonic-gate }
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate int
14920Sstevel@tonic-gate ddi_add_softintr(dev_info_t *dip, int preference, ddi_softintr_t *idp,
14930Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep,
14940Sstevel@tonic-gate     ddi_idevice_cookie_t *idevice_cookiep,
14950Sstevel@tonic-gate     uint_t (*int_handler)(caddr_t int_handler_arg),
14960Sstevel@tonic-gate     caddr_t int_handler_arg)
14970Sstevel@tonic-gate {
14980Sstevel@tonic-gate 	ddi_softint_handle_t	*hdl_p;
14990Sstevel@tonic-gate 	uint64_t		softpri;
15000Sstevel@tonic-gate 	int			ret;
15010Sstevel@tonic-gate 
15020Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: name=%s%d dip=0x%p "
15030Sstevel@tonic-gate 	    "pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
15040Sstevel@tonic-gate 	    (void *)dip, preference));
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 	if ((idp == NULL) || ((preference == DDI_SOFTINT_FIXED) &&
15070Sstevel@tonic-gate 	    (iblock_cookiep == NULL)))
15080Sstevel@tonic-gate 		return (DDI_FAILURE);
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate 	/* Translate the priority preference */
15110Sstevel@tonic-gate 	if (preference == DDI_SOFTINT_FIXED) {
1512190Seota 		softpri = (uint64_t)(uintptr_t)*iblock_cookiep;
15130Sstevel@tonic-gate 		softpri = MIN(softpri, DDI_SOFT_INTR_PRI_H);
15140Sstevel@tonic-gate 	} else {
15150Sstevel@tonic-gate 		softpri = (uint64_t)((preference > DDI_SOFTINT_MED) ?
15160Sstevel@tonic-gate 		    DDI_SOFT_INTR_PRI_H : DDI_SOFT_INTR_PRI_M);
15170Sstevel@tonic-gate 	}
15180Sstevel@tonic-gate 
15190Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: preference 0x%x "
15200Sstevel@tonic-gate 	    "softpri 0x%lx\n", preference, (long)softpri));
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate 	hdl_p = kmem_zalloc(sizeof (ddi_softint_handle_t), KM_SLEEP);
15230Sstevel@tonic-gate 	if ((ret = ddi_intr_add_softint(dip, hdl_p, softpri,
15240Sstevel@tonic-gate 	    (ddi_intr_handler_t *)int_handler, int_handler_arg)) !=
15250Sstevel@tonic-gate 	    DDI_SUCCESS) {
15260Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: "
15270Sstevel@tonic-gate 		    "ddi_intr_add_softint failed, ret 0x%x\n", ret));
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate 		kmem_free(hdl_p, sizeof (ddi_softint_handle_t));
15300Sstevel@tonic-gate 		return (DDI_FAILURE);
15310Sstevel@tonic-gate 	}
15320Sstevel@tonic-gate 
15330Sstevel@tonic-gate 	if (iblock_cookiep)
1534190Seota 		*iblock_cookiep =  (ddi_iblock_cookie_t)(uintptr_t)softpri;
15350Sstevel@tonic-gate 
15360Sstevel@tonic-gate 	if (idevice_cookiep) {
15370Sstevel@tonic-gate 		idevice_cookiep->idev_vector = 0;
15380Sstevel@tonic-gate 		idevice_cookiep->idev_priority = softpri;
15390Sstevel@tonic-gate 	}
15400Sstevel@tonic-gate 
15410Sstevel@tonic-gate 	*idp = (ddi_softintr_t)hdl_p;
15420Sstevel@tonic-gate 
15430Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: dip = 0x%p, "
15440Sstevel@tonic-gate 	    "idp = 0x%p, ret = %x\n", (void *)dip, (void *)*idp, ret));
15450Sstevel@tonic-gate 
15460Sstevel@tonic-gate 	return (DDI_SUCCESS);
15470Sstevel@tonic-gate }
15480Sstevel@tonic-gate 
15490Sstevel@tonic-gate void
15500Sstevel@tonic-gate ddi_remove_softintr(ddi_softintr_t id)
15510Sstevel@tonic-gate {
15520Sstevel@tonic-gate 	ddi_softint_handle_t	*h_p = (ddi_softint_handle_t *)id;
15530Sstevel@tonic-gate 
15540Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: id=0x%p\n",
15550Sstevel@tonic-gate 	    (void *)id));
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate 	if (h_p == NULL)
15580Sstevel@tonic-gate 		return;
15590Sstevel@tonic-gate 
15600Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: handle 0x%p\n",
15610Sstevel@tonic-gate 	    (void *)h_p));
15620Sstevel@tonic-gate 
15630Sstevel@tonic-gate 	(void) ddi_intr_remove_softint(*h_p);
15640Sstevel@tonic-gate 	kmem_free(h_p, sizeof (ddi_softint_handle_t));
15650Sstevel@tonic-gate }
15660Sstevel@tonic-gate 
15670Sstevel@tonic-gate void
15680Sstevel@tonic-gate ddi_trigger_softintr(ddi_softintr_t id)
15690Sstevel@tonic-gate {
15700Sstevel@tonic-gate 	ddi_softint_handle_t	*h_p = (ddi_softint_handle_t *)id;
15710Sstevel@tonic-gate 	int			ret;
15720Sstevel@tonic-gate 
15730Sstevel@tonic-gate 	if (h_p == NULL)
15740Sstevel@tonic-gate 		return;
15750Sstevel@tonic-gate 
15760Sstevel@tonic-gate 	if ((ret = ddi_intr_trigger_softint(*h_p, NULL)) != DDI_SUCCESS) {
15770Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_trigger_softintr: "
15780Sstevel@tonic-gate 		    "ddi_intr_trigger_softint failed, hdlp 0x%p "
15790Sstevel@tonic-gate 		    "ret 0x%x\n", (void *)h_p, ret));
15800Sstevel@tonic-gate 	}
15810Sstevel@tonic-gate }
1582