xref: /onnv-gate/usr/src/uts/common/os/ddi_intr.c (revision 1653:b352ea7812e3)
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 /*
221542Sjohnny  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/note.h>
290Sstevel@tonic-gate #include <sys/sysmacros.h>
300Sstevel@tonic-gate #include <sys/types.h>
310Sstevel@tonic-gate #include <sys/param.h>
320Sstevel@tonic-gate #include <sys/systm.h>
330Sstevel@tonic-gate #include <sys/kmem.h>
340Sstevel@tonic-gate #include <sys/cmn_err.h>
350Sstevel@tonic-gate #include <sys/debug.h>
360Sstevel@tonic-gate #include <sys/avintr.h>
370Sstevel@tonic-gate #include <sys/autoconf.h>
380Sstevel@tonic-gate #include <sys/sunndi.h>
390Sstevel@tonic-gate #include <sys/ndi_impldefs.h>	/* include prototypes */
400Sstevel@tonic-gate 
410Sstevel@tonic-gate /*
420Sstevel@tonic-gate  * New DDI interrupt framework
430Sstevel@tonic-gate  */
440Sstevel@tonic-gate 
450Sstevel@tonic-gate /*
460Sstevel@tonic-gate  * MSI/X allocation limit.
470Sstevel@tonic-gate  * This limit will change with Resource Management support.
480Sstevel@tonic-gate  */
490Sstevel@tonic-gate uint_t		ddi_msix_alloc_limit = 2;
500Sstevel@tonic-gate 
510Sstevel@tonic-gate /*
520Sstevel@tonic-gate  * ddi_intr_get_supported_types:
530Sstevel@tonic-gate  *	Return, as a bit mask, the hardware interrupt types supported by
540Sstevel@tonic-gate  *	both the device and by the host in the integer pointed
550Sstevel@tonic-gate  *	to be the 'typesp' argument.
560Sstevel@tonic-gate  */
570Sstevel@tonic-gate int
580Sstevel@tonic-gate ddi_intr_get_supported_types(dev_info_t *dip, int *typesp)
590Sstevel@tonic-gate {
600Sstevel@tonic-gate 	int			ret;
610Sstevel@tonic-gate 	ddi_intr_handle_impl_t	hdl;
620Sstevel@tonic-gate 
630Sstevel@tonic-gate 	if (dip == NULL)
640Sstevel@tonic-gate 		return (DDI_EINVAL);
650Sstevel@tonic-gate 
660Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: dip %p\n",
670Sstevel@tonic-gate 	    (void *)dip));
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 	if (*typesp = i_ddi_intr_get_supported_types(dip))
700Sstevel@tonic-gate 		return (DDI_SUCCESS);
710Sstevel@tonic-gate 
720Sstevel@tonic-gate 	bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
730Sstevel@tonic-gate 	hdl.ih_dip = dip;
740Sstevel@tonic-gate 
75693Sgovinda 	ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_SUPPORTED_TYPES, &hdl,
760Sstevel@tonic-gate 	    (void *)typesp);
770Sstevel@tonic-gate 
780Sstevel@tonic-gate 	if (ret != DDI_SUCCESS)
790Sstevel@tonic-gate 		return (DDI_INTR_NOTFOUND);
800Sstevel@tonic-gate 
810Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: types %x\n",
820Sstevel@tonic-gate 	    *typesp));
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 	return (ret);
850Sstevel@tonic-gate }
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 
880Sstevel@tonic-gate /*
890Sstevel@tonic-gate  * ddi_intr_get_nintrs:
900Sstevel@tonic-gate  * 	Return as an integer in the integer pointed to by the argument
910Sstevel@tonic-gate  * 	*nintrsp*, the number of interrupts the device supports for the
920Sstevel@tonic-gate  *	given interrupt type.
930Sstevel@tonic-gate  */
940Sstevel@tonic-gate int
950Sstevel@tonic-gate ddi_intr_get_nintrs(dev_info_t *dip, int type, int *nintrsp)
960Sstevel@tonic-gate {
970Sstevel@tonic-gate 	int			ret;
980Sstevel@tonic-gate 	ddi_intr_handle_impl_t	hdl;
990Sstevel@tonic-gate 
100693Sgovinda 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs: dip %p, type: %d\n",
101693Sgovinda 	    (void *)dip, type));
1020Sstevel@tonic-gate 
103693Sgovinda 	if ((dip == NULL) || (type & ~(DDI_INTR_SUP_TYPES))) {
104693Sgovinda 		*nintrsp = 0;
105693Sgovinda 		return (DDI_EINVAL);
106693Sgovinda 	}
1070Sstevel@tonic-gate 
108693Sgovinda 	if (!(i_ddi_intr_get_supported_types(dip) & type)) {
109693Sgovinda 		*nintrsp = 0;
1100Sstevel@tonic-gate 		return (DDI_EINVAL);
111693Sgovinda 	}
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 	if (*nintrsp = i_ddi_intr_get_supported_nintrs(dip, type))
1140Sstevel@tonic-gate 		return (DDI_SUCCESS);
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
1170Sstevel@tonic-gate 	hdl.ih_dip = dip;
1180Sstevel@tonic-gate 	hdl.ih_type = type;
1190Sstevel@tonic-gate 
120693Sgovinda 	ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_NINTRS, &hdl,
1210Sstevel@tonic-gate 	    (void *)nintrsp);
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs:: nintrs %x\n",
1240Sstevel@tonic-gate 	    *nintrsp));
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	return (ret);
1270Sstevel@tonic-gate }
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate /*
1310Sstevel@tonic-gate  * ddi_intr_get_navail:
1320Sstevel@tonic-gate  *	Bus nexus driver will return availble interrupt count value for
1330Sstevel@tonic-gate  *	a given interrupt type.
1340Sstevel@tonic-gate  *
1350Sstevel@tonic-gate  * 	Return as an integer in the integer pointed to by the argument
1360Sstevel@tonic-gate  * 	*navailp*, the number of interrupts currently available for the
1370Sstevel@tonic-gate  *	given interrupt type.
1380Sstevel@tonic-gate  */
1390Sstevel@tonic-gate int
1400Sstevel@tonic-gate ddi_intr_get_navail(dev_info_t *dip, int type, int *navailp)
1410Sstevel@tonic-gate {
1420Sstevel@tonic-gate 	int			ret;
1430Sstevel@tonic-gate 	ddi_intr_handle_impl_t	hdl;
1440Sstevel@tonic-gate 
145693Sgovinda 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_navail: dip %p, type: %d\n",
146693Sgovinda 	    (void *)dip, type));
1470Sstevel@tonic-gate 
148693Sgovinda 	if ((dip == NULL) || (type & ~(DDI_INTR_SUP_TYPES))) {
149693Sgovinda 		*navailp = 0;
1500Sstevel@tonic-gate 		return (DDI_EINVAL);
151693Sgovinda 	}
1520Sstevel@tonic-gate 
153693Sgovinda 	if (!(i_ddi_intr_get_supported_types(dip) & type)) {
154693Sgovinda 		*navailp = 0;
1550Sstevel@tonic-gate 		return (DDI_EINVAL);
156693Sgovinda 	}
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	/*
1590Sstevel@tonic-gate 	 * In future, this interface implementation will change
1600Sstevel@tonic-gate 	 * with Resource Management support.
1610Sstevel@tonic-gate 	 */
1620Sstevel@tonic-gate 	bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
1630Sstevel@tonic-gate 	hdl.ih_dip = dip;
1640Sstevel@tonic-gate 	hdl.ih_type = type;
1650Sstevel@tonic-gate 
166693Sgovinda 	ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_NAVAIL, &hdl,
167693Sgovinda 	    (void *)navailp);
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	return (ret == DDI_SUCCESS ? DDI_SUCCESS : DDI_INTR_NOTFOUND);
1700Sstevel@tonic-gate }
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate /*
1740Sstevel@tonic-gate  * Interrupt allocate/free functions
1750Sstevel@tonic-gate  */
1760Sstevel@tonic-gate int
1770Sstevel@tonic-gate ddi_intr_alloc(dev_info_t *dip, ddi_intr_handle_t *h_array, int type, int inum,
1780Sstevel@tonic-gate     int count, int *actualp, int behavior)
1790Sstevel@tonic-gate {
1800Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp, tmp_hdl;
1810Sstevel@tonic-gate 	int			i, ret, cap = 0, intr_type, nintrs = 0;
1820Sstevel@tonic-gate 	uint_t			pri;
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: name %s dip 0x%p "
1850Sstevel@tonic-gate 	    "type %x inum %x count %x behavior %x\n", ddi_driver_name(dip),
1860Sstevel@tonic-gate 	    (void *)dip, type, inum, count, behavior));
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 	/* Validate parameters */
1890Sstevel@tonic-gate 	if (dip == NULL || h_array == NULL || count < 1) {
1900Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Invalid args\n"));
1910Sstevel@tonic-gate 		return (DDI_EINVAL);
1920Sstevel@tonic-gate 	}
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	/* Validate interrupt type */
1950Sstevel@tonic-gate 	if (!(i_ddi_intr_get_supported_types(dip) & type)) {
1960Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x not "
1970Sstevel@tonic-gate 		    "supported\n", type));
1980Sstevel@tonic-gate 		return (DDI_EINVAL);
1990Sstevel@tonic-gate 	}
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	/* First, get how many interrupts the device supports */
2020Sstevel@tonic-gate 	if (!(nintrs = i_ddi_intr_get_supported_nintrs(dip, type))) {
2030Sstevel@tonic-gate 		if (ddi_intr_get_nintrs(dip, type, &nintrs) != DDI_SUCCESS) {
2040Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no "
2050Sstevel@tonic-gate 			    "interrupts found of type %d\n", type));
2060Sstevel@tonic-gate 			return (DDI_INTR_NOTFOUND);
2070Sstevel@tonic-gate 		}
2080Sstevel@tonic-gate 	}
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	/* Is this function invoked with more interrupt than device supports? */
2110Sstevel@tonic-gate 	if (count > nintrs) {
2120Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no of interrupts "
2130Sstevel@tonic-gate 		    "requested %d is more than supported %d\n", count, nintrs));
2140Sstevel@tonic-gate 		return (DDI_EINVAL);
2150Sstevel@tonic-gate 	}
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	/*
2180Sstevel@tonic-gate 	 * Check if requested interrupt type is not same as interrupt
2190Sstevel@tonic-gate 	 * type is in use if any.
2200Sstevel@tonic-gate 	 */
2210Sstevel@tonic-gate 	if (((intr_type = i_ddi_intr_get_current_type(dip)) != 0) &&
2220Sstevel@tonic-gate 	    (intr_type != type)) {
2230Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Requested "
2240Sstevel@tonic-gate 		    "interrupt type %x is different from interrupt type %x"
2250Sstevel@tonic-gate 		    "already in use\n", type, intr_type));
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 		return (DDI_EINVAL);
2280Sstevel@tonic-gate 	}
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	/*
2310Sstevel@tonic-gate 	 * Check if requested interrupt type is in use and requested number
2320Sstevel@tonic-gate 	 * of interrupts and number of interrupts already in use exceeds the
2330Sstevel@tonic-gate 	 * number of interrupts supported by this device.
2340Sstevel@tonic-gate 	 */
2350Sstevel@tonic-gate 	if (intr_type) {
2360Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x "
2370Sstevel@tonic-gate 		    "is already being used\n", type));
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 		if ((count + i_ddi_intr_get_current_nintrs(dip)) > nintrs) {
2400Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: count %d "
2410Sstevel@tonic-gate 			    "+ intrs in use %d exceeds supported %d intrs\n",
2420Sstevel@tonic-gate 			    count, i_ddi_intr_get_current_nintrs(dip), nintrs));
2430Sstevel@tonic-gate 			return (DDI_EINVAL);
2440Sstevel@tonic-gate 		}
2450Sstevel@tonic-gate 	}
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	/*
2480Sstevel@tonic-gate 	 * For MSI, ensure that the requested interrupt count is a power of 2
2490Sstevel@tonic-gate 	 */
2500Sstevel@tonic-gate 	if (type == DDI_INTR_TYPE_MSI && !ISP2(count)) {
2510Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: "
2520Sstevel@tonic-gate 		    "MSI count %d is not a power of two\n", count));
2530Sstevel@tonic-gate 		return (DDI_EINVAL);
2540Sstevel@tonic-gate 	}
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 	/*
2570Sstevel@tonic-gate 	 * Limit max MSI/X allocation to ddi_msix_alloc_limit.
2580Sstevel@tonic-gate 	 * This limit will change with Resource Management support.
2590Sstevel@tonic-gate 	 */
2600Sstevel@tonic-gate 	if (DDI_INTR_IS_MSI_OR_MSIX(type) && (count > ddi_msix_alloc_limit)) {
2610Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Requested MSI/Xs %d"
2620Sstevel@tonic-gate 		    "Max MSI/Xs limit %d\n", count, ddi_msix_alloc_limit));
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 		if (behavior == DDI_INTR_ALLOC_STRICT) {
2650Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: "
2660Sstevel@tonic-gate 			    "DDI_INTR_ALLOC_STRICT flag is passed, "
2670Sstevel@tonic-gate 			    "return failure\n"));
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 			return (DDI_EAGAIN);
2700Sstevel@tonic-gate 		}
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 		count = ddi_msix_alloc_limit;
2730Sstevel@tonic-gate 	}
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	/* Now allocate required number of interrupts */
2760Sstevel@tonic-gate 	bzero(&tmp_hdl, sizeof (ddi_intr_handle_impl_t));
2770Sstevel@tonic-gate 	tmp_hdl.ih_type = type;
2780Sstevel@tonic-gate 	tmp_hdl.ih_inum = inum;
2790Sstevel@tonic-gate 	tmp_hdl.ih_scratch1 = count;
2801542Sjohnny 	tmp_hdl.ih_scratch2 = (void *)behavior;
2810Sstevel@tonic-gate 	tmp_hdl.ih_dip = dip;
2820Sstevel@tonic-gate 
283693Sgovinda 	if (i_ddi_intr_ops(dip, dip, DDI_INTROP_ALLOC,
2840Sstevel@tonic-gate 	    &tmp_hdl, (void *)actualp) != DDI_SUCCESS) {
2850Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: allocation "
2860Sstevel@tonic-gate 		    "failed\n"));
2870Sstevel@tonic-gate 		return (*actualp ? DDI_EAGAIN : DDI_INTR_NOTFOUND);
2880Sstevel@tonic-gate 	}
2890Sstevel@tonic-gate 
290693Sgovinda 	if ((ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_GETPRI,
2910Sstevel@tonic-gate 	    &tmp_hdl, (void *)&pri)) != DDI_SUCCESS) {
2920Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get priority "
2930Sstevel@tonic-gate 		    "failed\n"));
2940Sstevel@tonic-gate 		return (ret);
2950Sstevel@tonic-gate 	}
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: getting capability\n"));
2980Sstevel@tonic-gate 
299693Sgovinda 	if ((ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_GETCAP,
3000Sstevel@tonic-gate 	    &tmp_hdl, (void *)&cap)) != DDI_SUCCESS) {
3010Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get capability "
3020Sstevel@tonic-gate 		    "failed\n"));
3030Sstevel@tonic-gate 		return (ret);
3040Sstevel@tonic-gate 	}
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	/* Save current interrupt type, supported and current intr count */
3070Sstevel@tonic-gate 	i_ddi_intr_devi_init(dip);
3080Sstevel@tonic-gate 	i_ddi_intr_set_current_type(dip, type);
3090Sstevel@tonic-gate 	i_ddi_intr_set_supported_nintrs(dip, nintrs);
3100Sstevel@tonic-gate 	i_ddi_intr_set_current_nintrs(dip,
3110Sstevel@tonic-gate 	    i_ddi_intr_get_current_nintrs(dip) + *actualp);
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	/* Now, go and handle each "handle" */
3140Sstevel@tonic-gate 	for (i = 0; i < *actualp; i++) {
3150Sstevel@tonic-gate 		hdlp = (ddi_intr_handle_impl_t *)kmem_zalloc(
3160Sstevel@tonic-gate 		    (sizeof (ddi_intr_handle_impl_t)), KM_SLEEP);
3170Sstevel@tonic-gate 		rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
3180Sstevel@tonic-gate 		h_array[i] = (struct __ddi_intr_handle *)hdlp;
3190Sstevel@tonic-gate 		hdlp->ih_type = type;
3200Sstevel@tonic-gate 		hdlp->ih_pri = pri;
3210Sstevel@tonic-gate 		hdlp->ih_cap = cap;
3220Sstevel@tonic-gate 		hdlp->ih_ver = DDI_INTR_VERSION;
3230Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ALLOC;
3240Sstevel@tonic-gate 		hdlp->ih_dip = dip;
3250Sstevel@tonic-gate 		hdlp->ih_inum = inum + i;
326916Sschwartz 		i_ddi_alloc_intr_phdl(hdlp);
3270Sstevel@tonic-gate 		if (type & DDI_INTR_TYPE_FIXED)
3289Segillett 			i_ddi_set_intr_handle(dip, hdlp->ih_inum, &h_array[i]);
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: hdlp = 0x%p\n",
3310Sstevel@tonic-gate 		    (void *)h_array[i]));
3320Sstevel@tonic-gate 	}
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	return (DDI_SUCCESS);
3350Sstevel@tonic-gate }
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate int
3390Sstevel@tonic-gate ddi_intr_free(ddi_intr_handle_t h)
3400Sstevel@tonic-gate {
3410Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
3420Sstevel@tonic-gate 	int			ret;
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_free: hdlp = %p\n", (void *)hdlp));
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	if (hdlp == NULL)
3470Sstevel@tonic-gate 		return (DDI_EINVAL);
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
3500Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
3510Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
3520Sstevel@tonic-gate 		return (DDI_EINVAL);
3530Sstevel@tonic-gate 	}
3540Sstevel@tonic-gate 
355693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
3560Sstevel@tonic-gate 	    DDI_INTROP_FREE, hdlp, NULL);
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
3590Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
3600Sstevel@tonic-gate 		i_ddi_intr_set_current_nintrs(hdlp->ih_dip,
3610Sstevel@tonic-gate 		    i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1);
3620Sstevel@tonic-gate 
363693Sgovinda 		if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) == 0) {
364693Sgovinda 			i_ddi_intr_devi_fini(hdlp->ih_dip);
365693Sgovinda 		} else {
366693Sgovinda 			if (hdlp->ih_type & DDI_INTR_TYPE_FIXED)
367693Sgovinda 				i_ddi_set_intr_handle(hdlp->ih_dip,
368693Sgovinda 				    hdlp->ih_inum, NULL);
369693Sgovinda 		}
3700Sstevel@tonic-gate 
371916Sschwartz 		i_ddi_free_intr_phdl(hdlp);
3720Sstevel@tonic-gate 		rw_destroy(&hdlp->ih_rwlock);
3730Sstevel@tonic-gate 		kmem_free(hdlp, sizeof (ddi_intr_handle_impl_t));
3740Sstevel@tonic-gate 	}
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	return (ret);
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate /*
3800Sstevel@tonic-gate  * Interrupt get/set capacity functions
3810Sstevel@tonic-gate  *
3820Sstevel@tonic-gate  * The logic used to figure this out is shown here:
3830Sstevel@tonic-gate  *
3840Sstevel@tonic-gate  *			Device level		Platform level	    Intr source
3850Sstevel@tonic-gate  * 1. Fixed interrupts
3860Sstevel@tonic-gate  * (non-PCI)
3870Sstevel@tonic-gate  * o Flags supported	N/A			Maskable/Pending/    rootnex
3880Sstevel@tonic-gate  *						No Block Enable
3890Sstevel@tonic-gate  * o navail					1
3900Sstevel@tonic-gate  *
3910Sstevel@tonic-gate  * 2. PCI Fixed interrupts
3920Sstevel@tonic-gate  * o Flags supported	pending/Maskable	Maskable/pending/    pci
3930Sstevel@tonic-gate  *						No Block enable
3940Sstevel@tonic-gate  * o navail		N/A			1
3950Sstevel@tonic-gate  *
3960Sstevel@tonic-gate  * 3. PCI MSI
3970Sstevel@tonic-gate  * o Flags supported	Maskable/Pending	Maskable/Pending    pci
3980Sstevel@tonic-gate  *			Block Enable		(if drvr doesn't)   Block Enable
3990Sstevel@tonic-gate  * o navail		N/A			#vectors - #used    N/A
4000Sstevel@tonic-gate  *
4010Sstevel@tonic-gate  * 4. PCI MSI-X
4020Sstevel@tonic-gate  * o Flags supported	Maskable/Pending	Maskable/Pending    pci
4030Sstevel@tonic-gate  *			Block Enable				    Block Enable
4040Sstevel@tonic-gate  * o navail		N/A			#vectors - #used    N/A
4050Sstevel@tonic-gate  *
4060Sstevel@tonic-gate  * where:
4070Sstevel@tonic-gate  *	#vectors	- Total numbers of vectors available
4080Sstevel@tonic-gate  *	#used		- Total numbers of vectors currently being used
4090Sstevel@tonic-gate  *
4100Sstevel@tonic-gate  * For devices complying to PCI2.3 or greater, see bit10 of Command Register
4110Sstevel@tonic-gate  * 0 - enables assertion of INTx
4120Sstevel@tonic-gate  * 1 - disables assertion of INTx
4130Sstevel@tonic-gate  *
4140Sstevel@tonic-gate  * For non MSI/X interrupts; if the IRQ is shared then all ddi_intr_set_*()
4150Sstevel@tonic-gate  * operations return failure.
4160Sstevel@tonic-gate  */
4170Sstevel@tonic-gate int
4180Sstevel@tonic-gate ddi_intr_get_cap(ddi_intr_handle_t h, int *flagsp)
4190Sstevel@tonic-gate {
4200Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
4210Sstevel@tonic-gate 	int			ret;
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_cap: hdlp = %p\n",
4240Sstevel@tonic-gate 	    (void *)hdlp));
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	*flagsp = 0;
4270Sstevel@tonic-gate 	if (hdlp == NULL)
4280Sstevel@tonic-gate 		return (DDI_EINVAL);
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	if (hdlp->ih_cap) {
4330Sstevel@tonic-gate 		*flagsp = hdlp->ih_cap & ~DDI_INTR_FLAG_MSI64;
4340Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
4350Sstevel@tonic-gate 		return (DDI_SUCCESS);
4360Sstevel@tonic-gate 	}
4370Sstevel@tonic-gate 
438693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
4390Sstevel@tonic-gate 	    DDI_INTROP_GETCAP, hdlp, (void *)flagsp);
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
4420Sstevel@tonic-gate 		hdlp->ih_cap = *flagsp;
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 		/* Mask out MSI/X 64-bit support to the consumer */
4450Sstevel@tonic-gate 		*flagsp &= ~DDI_INTR_FLAG_MSI64;
4460Sstevel@tonic-gate 	}
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
4490Sstevel@tonic-gate 	return (ret);
4500Sstevel@tonic-gate }
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate int
4530Sstevel@tonic-gate ddi_intr_set_cap(ddi_intr_handle_t h, int flags)
4540Sstevel@tonic-gate {
4550Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
4560Sstevel@tonic-gate 	int			ret;
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_cap: hdlp = %p", (void *)hdlp));
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	if (hdlp == NULL)
4610Sstevel@tonic-gate 		return (DDI_EINVAL);
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
4640Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
4650Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
4660Sstevel@tonic-gate 		return (DDI_EINVAL);
4670Sstevel@tonic-gate 	}
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	/* Only DDI_INTR_FLAG_LEVEL or DDI_INTR_FLAG_EDGE are allowed */
4700Sstevel@tonic-gate 	if (!(flags & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) {
4710Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "%s%d: only LEVEL or EDGE capability "
4720Sstevel@tonic-gate 		    "can be set\n", ddi_driver_name(hdlp->ih_dip),
4730Sstevel@tonic-gate 		    ddi_get_instance(hdlp->ih_dip)));
4740Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
4750Sstevel@tonic-gate 		return (DDI_EINVAL);
4760Sstevel@tonic-gate 	}
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	/* Both level/edge flags must be currently supported */
4790Sstevel@tonic-gate 	if (!(hdlp->ih_cap & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) {
4800Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "%s%d: Both LEVEL and EDGE capability"
4810Sstevel@tonic-gate 		    " must be supported\n", ddi_driver_name(hdlp->ih_dip),
4820Sstevel@tonic-gate 		    ddi_get_instance(hdlp->ih_dip)));
4830Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
4840Sstevel@tonic-gate 		return (DDI_ENOTSUP);
4850Sstevel@tonic-gate 	}
4860Sstevel@tonic-gate 
487693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
4880Sstevel@tonic-gate 	    DDI_INTROP_SETCAP, hdlp, &flags);
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
4910Sstevel@tonic-gate 	return (ret);
4920Sstevel@tonic-gate }
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate /*
4950Sstevel@tonic-gate  * Priority related functions
4960Sstevel@tonic-gate  */
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate /*
4990Sstevel@tonic-gate  * ddi_intr_get_hilevel_pri:
5000Sstevel@tonic-gate  *	Returns the minimum priority level for a
5010Sstevel@tonic-gate  *	high-level interrupt on a platform.
5020Sstevel@tonic-gate  */
5030Sstevel@tonic-gate uint_t
5040Sstevel@tonic-gate ddi_intr_get_hilevel_pri(void)
5050Sstevel@tonic-gate {
5060Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_hilevel_pri:\n"));
5070Sstevel@tonic-gate 	return (LOCK_LEVEL + 1);
5080Sstevel@tonic-gate }
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate int
5110Sstevel@tonic-gate ddi_intr_get_pri(ddi_intr_handle_t h, uint_t *prip)
5120Sstevel@tonic-gate {
5130Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
5140Sstevel@tonic-gate 	int			ret;
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pri: hdlp = %p\n",
5170Sstevel@tonic-gate 	    (void *)hdlp));
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 	*prip = 0;
5200Sstevel@tonic-gate 	if (hdlp == NULL)
5210Sstevel@tonic-gate 		return (DDI_EINVAL);
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
5240Sstevel@tonic-gate 	/* Already initialized, just return that */
5250Sstevel@tonic-gate 	if (hdlp->ih_pri) {
5260Sstevel@tonic-gate 		*prip = hdlp->ih_pri;
5270Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
5280Sstevel@tonic-gate 		return (DDI_SUCCESS);
5290Sstevel@tonic-gate 	}
5300Sstevel@tonic-gate 
531693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
5320Sstevel@tonic-gate 	    DDI_INTROP_GETPRI, hdlp, (void *)prip);
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 	if (ret == DDI_SUCCESS)
5350Sstevel@tonic-gate 		hdlp->ih_pri = *prip;
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
5380Sstevel@tonic-gate 	return (ret);
5390Sstevel@tonic-gate }
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate int
5420Sstevel@tonic-gate ddi_intr_set_pri(ddi_intr_handle_t h, uint_t pri)
5430Sstevel@tonic-gate {
5440Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
5450Sstevel@tonic-gate 	int			ret;
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: hdlp = %p", (void *)hdlp));
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	if (hdlp == NULL)
5500Sstevel@tonic-gate 		return (DDI_EINVAL);
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	/* Validate priority argument */
5530Sstevel@tonic-gate 	if (pri < DDI_INTR_PRI_MIN || pri > DDI_INTR_PRI_MAX) {
5540Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: invalid priority "
5550Sstevel@tonic-gate 		    "specified  = %x\n", pri));
5560Sstevel@tonic-gate 		return (DDI_EINVAL);
5570Sstevel@tonic-gate 	}
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
5600Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
5610Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
5620Sstevel@tonic-gate 		return (DDI_EINVAL);
5630Sstevel@tonic-gate 	}
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	/* If the passed priority is same as existing priority; do nothing */
5660Sstevel@tonic-gate 	if (pri == hdlp->ih_pri) {
5670Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
5680Sstevel@tonic-gate 		return (DDI_SUCCESS);
5690Sstevel@tonic-gate 	}
5700Sstevel@tonic-gate 
571693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
5720Sstevel@tonic-gate 	    DDI_INTROP_SETPRI, hdlp, &pri);
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	if (ret == DDI_SUCCESS)
5750Sstevel@tonic-gate 		hdlp->ih_pri = pri;
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
5780Sstevel@tonic-gate 	return (ret);
5790Sstevel@tonic-gate }
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate /*
5820Sstevel@tonic-gate  * Interrupt add/duplicate/remove handlers
5830Sstevel@tonic-gate  */
5840Sstevel@tonic-gate int
5850Sstevel@tonic-gate ddi_intr_add_handler(ddi_intr_handle_t h, ddi_intr_handler_t inthandler,
5860Sstevel@tonic-gate     void *arg1, void *arg2)
5870Sstevel@tonic-gate {
5880Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
5890Sstevel@tonic-gate 	int			ret;
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_handler: hdlp = 0x%p\n",
5920Sstevel@tonic-gate 	    (void *)hdlp));
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	if ((hdlp == NULL) || (inthandler == NULL))
5950Sstevel@tonic-gate 		return (DDI_EINVAL);
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
5980Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
5990Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
6000Sstevel@tonic-gate 		return (DDI_EINVAL);
6010Sstevel@tonic-gate 	}
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	hdlp->ih_cb_func = inthandler;
6040Sstevel@tonic-gate 	hdlp->ih_cb_arg1 = arg1;
6050Sstevel@tonic-gate 	hdlp->ih_cb_arg2 = arg2;
6060Sstevel@tonic-gate 
607693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
6080Sstevel@tonic-gate 	    DDI_INTROP_ADDISR, hdlp, NULL);
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
6110Sstevel@tonic-gate 		hdlp->ih_cb_func = NULL;
6120Sstevel@tonic-gate 		hdlp->ih_cb_arg1 = NULL;
6130Sstevel@tonic-gate 		hdlp->ih_cb_arg2 = NULL;
6140Sstevel@tonic-gate 	} else
6150Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ADDED;
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
6180Sstevel@tonic-gate 	return (ret);
6190Sstevel@tonic-gate }
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate int
6220Sstevel@tonic-gate ddi_intr_dup_handler(ddi_intr_handle_t org, int vector, ddi_intr_handle_t *dup)
6230Sstevel@tonic-gate {
6240Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)org;
6250Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*dup_hdlp;
6260Sstevel@tonic-gate 	int			ret;
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_dup_handler: hdlp = 0x%p\n",
6290Sstevel@tonic-gate 	    (void *)hdlp));
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	/* Do some input argument checking ("dup" is not allocated) */
6320Sstevel@tonic-gate 	if ((hdlp == NULL) || (dup != NULL))
6330Sstevel@tonic-gate 		return (DDI_EINVAL);
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	/* Do some input argument checking */
6380Sstevel@tonic-gate 	if ((hdlp->ih_state == DDI_IHDL_STATE_ALLOC) ||	/* intr handle alloc? */
6390Sstevel@tonic-gate 	    (hdlp->ih_type != DDI_INTR_TYPE_MSIX)) {	/* only MSI-X allowed */
6400Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
6410Sstevel@tonic-gate 		return (DDI_EINVAL);
6420Sstevel@tonic-gate 	}
6430Sstevel@tonic-gate 
644693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
6450Sstevel@tonic-gate 	    DDI_INTROP_DUPVEC, hdlp, (void *)&vector);
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
6480Sstevel@tonic-gate 		dup_hdlp = (ddi_intr_handle_impl_t *)
6490Sstevel@tonic-gate 		    kmem_zalloc(sizeof (ddi_intr_handle_impl_t), KM_SLEEP);
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 		dup = (ddi_intr_handle_t *)dup_hdlp;
6520Sstevel@tonic-gate 		rw_init(&dup_hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
6530Sstevel@tonic-gate 		rw_enter(&dup_hdlp->ih_rwlock, RW_WRITER);
6540Sstevel@tonic-gate 		dup_hdlp->ih_ver = DDI_INTR_VERSION;
6550Sstevel@tonic-gate 		dup_hdlp->ih_state = DDI_IHDL_STATE_ADDED;
6560Sstevel@tonic-gate 		dup_hdlp->ih_dip = hdlp->ih_dip;
6570Sstevel@tonic-gate 		dup_hdlp->ih_type = hdlp->ih_type;
6580Sstevel@tonic-gate 		dup_hdlp->ih_pri = hdlp->ih_pri;
6590Sstevel@tonic-gate 		dup_hdlp->ih_cap = hdlp->ih_cap;
6600Sstevel@tonic-gate 		dup_hdlp->ih_inum = hdlp->ih_inum;
6610Sstevel@tonic-gate 		/* What about MSI-X vector */
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 		dup_hdlp->ih_cb_func = hdlp->ih_cb_func;
6640Sstevel@tonic-gate 		dup_hdlp->ih_cb_arg1 = hdlp->ih_cb_arg1;
6650Sstevel@tonic-gate 		dup_hdlp->ih_cb_arg2 = hdlp->ih_cb_arg2;
6660Sstevel@tonic-gate 		rw_exit(&dup_hdlp->ih_rwlock);
6670Sstevel@tonic-gate 	}
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
6700Sstevel@tonic-gate 	return (ret);
6710Sstevel@tonic-gate }
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate int
6740Sstevel@tonic-gate ddi_intr_remove_handler(ddi_intr_handle_t h)
6750Sstevel@tonic-gate {
6760Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
6770Sstevel@tonic-gate 	int			ret;
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_handler: hdlp = %p\n",
6800Sstevel@tonic-gate 	    (void *)hdlp));
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	if (hdlp == NULL)
6830Sstevel@tonic-gate 		return (DDI_EINVAL);
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
6860Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ADDED) {
6870Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
6880Sstevel@tonic-gate 		return (DDI_EINVAL);
6890Sstevel@tonic-gate 	}
6900Sstevel@tonic-gate 
691693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
6920Sstevel@tonic-gate 	    DDI_INTROP_REMISR, hdlp, NULL);
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
6950Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ALLOC;
6960Sstevel@tonic-gate 		hdlp->ih_cb_func = NULL;
6970Sstevel@tonic-gate 		hdlp->ih_cb_arg1 = NULL;
6980Sstevel@tonic-gate 		hdlp->ih_cb_arg2 = NULL;
6990Sstevel@tonic-gate 	}
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
7020Sstevel@tonic-gate 	return (ret);
7030Sstevel@tonic-gate }
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate /*
7060Sstevel@tonic-gate  * Interrupt enable/disable/block_enable/block_disable handlers
7070Sstevel@tonic-gate  */
7080Sstevel@tonic-gate int
7090Sstevel@tonic-gate ddi_intr_enable(ddi_intr_handle_t h)
7100Sstevel@tonic-gate {
7110Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
7120Sstevel@tonic-gate 	int			ret;
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_enable: hdlp = %p\n",
7150Sstevel@tonic-gate 	    (void *)hdlp));
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	if (hdlp == NULL)
7180Sstevel@tonic-gate 		return (DDI_EINVAL);
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
7210Sstevel@tonic-gate 	if ((hdlp->ih_state != DDI_IHDL_STATE_ADDED) ||
7220Sstevel@tonic-gate 	    ((hdlp->ih_type == DDI_INTR_TYPE_MSI) &&
7230Sstevel@tonic-gate 	    (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) {
7240Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
7250Sstevel@tonic-gate 		return (DDI_EINVAL);
7260Sstevel@tonic-gate 	}
7270Sstevel@tonic-gate 
728693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
7290Sstevel@tonic-gate 	    DDI_INTROP_ENABLE, hdlp, NULL);
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	if (ret == DDI_SUCCESS)
7320Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ENABLE;
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
7350Sstevel@tonic-gate 	return (ret);
7360Sstevel@tonic-gate }
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate int
7390Sstevel@tonic-gate ddi_intr_disable(ddi_intr_handle_t h)
7400Sstevel@tonic-gate {
7410Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
7420Sstevel@tonic-gate 	int			ret;
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_disable: hdlp = %p\n",
7450Sstevel@tonic-gate 	    (void *)hdlp));
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	if (hdlp == NULL)
7480Sstevel@tonic-gate 		return (DDI_EINVAL);
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
7510Sstevel@tonic-gate 	if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
7520Sstevel@tonic-gate 	    ((hdlp->ih_type == DDI_INTR_TYPE_MSI) &&
7530Sstevel@tonic-gate 	    (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) {
7540Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
7550Sstevel@tonic-gate 		return (DDI_EINVAL);
7560Sstevel@tonic-gate 	}
7570Sstevel@tonic-gate 
758693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
7590Sstevel@tonic-gate 	    DDI_INTROP_DISABLE, hdlp, NULL);
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 	if (ret == DDI_SUCCESS)
7620Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ADDED;
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
7650Sstevel@tonic-gate 	return (ret);
7660Sstevel@tonic-gate }
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate int
7690Sstevel@tonic-gate ddi_intr_block_enable(ddi_intr_handle_t *h_array, int count)
7700Sstevel@tonic-gate {
7710Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp;
7720Sstevel@tonic-gate 	int			i, ret;
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_enable: h_array = %p\n",
7750Sstevel@tonic-gate 	    (void *)h_array));
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 	if (h_array == NULL)
7780Sstevel@tonic-gate 		return (DDI_EINVAL);
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
7810Sstevel@tonic-gate 		hdlp = (ddi_intr_handle_impl_t *)h_array[i];
7820Sstevel@tonic-gate 		rw_enter(&hdlp->ih_rwlock, RW_READER);
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 		if (hdlp->ih_state != DDI_IHDL_STATE_ADDED ||
7850Sstevel@tonic-gate 		    hdlp->ih_type != DDI_INTR_TYPE_MSI ||
7860Sstevel@tonic-gate 		    !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) {
7870Sstevel@tonic-gate 			rw_exit(&hdlp->ih_rwlock);
7880Sstevel@tonic-gate 			return (DDI_EINVAL);
7890Sstevel@tonic-gate 		}
7900Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
7910Sstevel@tonic-gate 	}
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	hdlp = (ddi_intr_handle_impl_t *)h_array[0];
7940Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
7950Sstevel@tonic-gate 	hdlp->ih_scratch1 = count;
7961542Sjohnny 	hdlp->ih_scratch2 = (void *)h_array;
7970Sstevel@tonic-gate 
798693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
7990Sstevel@tonic-gate 	    DDI_INTROP_BLOCKENABLE, hdlp, NULL);
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
8040Sstevel@tonic-gate 		for (i = 0; i < count; i++) {
8050Sstevel@tonic-gate 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
8060Sstevel@tonic-gate 			rw_enter(&hdlp->ih_rwlock, RW_WRITER);
8070Sstevel@tonic-gate 			hdlp->ih_state = DDI_IHDL_STATE_ENABLE;
8080Sstevel@tonic-gate 			rw_exit(&hdlp->ih_rwlock);
8090Sstevel@tonic-gate 		}
8100Sstevel@tonic-gate 	}
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	return (ret);
8130Sstevel@tonic-gate }
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate int
8160Sstevel@tonic-gate ddi_intr_block_disable(ddi_intr_handle_t *h_array, int count)
8170Sstevel@tonic-gate {
8180Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp;
8190Sstevel@tonic-gate 	int			i, ret;
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_disable: h_array = %p\n",
8220Sstevel@tonic-gate 	    (void *)h_array));
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate 	if (h_array == NULL)
8250Sstevel@tonic-gate 		return (DDI_EINVAL);
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
8280Sstevel@tonic-gate 		hdlp = (ddi_intr_handle_impl_t *)h_array[i];
8290Sstevel@tonic-gate 		rw_enter(&hdlp->ih_rwlock, RW_READER);
8300Sstevel@tonic-gate 		if (hdlp->ih_state != DDI_IHDL_STATE_ENABLE ||
8310Sstevel@tonic-gate 		    hdlp->ih_type != DDI_INTR_TYPE_MSI ||
8320Sstevel@tonic-gate 		    !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) {
8330Sstevel@tonic-gate 			rw_exit(&hdlp->ih_rwlock);
8340Sstevel@tonic-gate 			return (DDI_EINVAL);
8350Sstevel@tonic-gate 		}
8360Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
8370Sstevel@tonic-gate 	}
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate 	hdlp = (ddi_intr_handle_impl_t *)h_array[0];
8400Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
8410Sstevel@tonic-gate 	hdlp->ih_scratch1 = count;
8421542Sjohnny 	hdlp->ih_scratch2 = (void *)h_array;
8430Sstevel@tonic-gate 
844693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
8450Sstevel@tonic-gate 	    DDI_INTROP_BLOCKDISABLE, hdlp, NULL);
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
8500Sstevel@tonic-gate 		for (i = 0; i < count; i++) {
8510Sstevel@tonic-gate 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
8520Sstevel@tonic-gate 			rw_enter(&hdlp->ih_rwlock, RW_WRITER);
8530Sstevel@tonic-gate 			hdlp->ih_state = DDI_IHDL_STATE_ADDED;
8540Sstevel@tonic-gate 			rw_exit(&hdlp->ih_rwlock);
8550Sstevel@tonic-gate 		}
8560Sstevel@tonic-gate 	}
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	return (ret);
8590Sstevel@tonic-gate }
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate /*
8620Sstevel@tonic-gate  * Interrupt set/clr mask handlers
8630Sstevel@tonic-gate  */
8640Sstevel@tonic-gate int
8650Sstevel@tonic-gate ddi_intr_set_mask(ddi_intr_handle_t h)
8660Sstevel@tonic-gate {
8670Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
8680Sstevel@tonic-gate 	int			ret;
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_mask: hdlp = %p\n",
8710Sstevel@tonic-gate 	    (void *)hdlp));
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate 	if (hdlp == NULL)
8740Sstevel@tonic-gate 		return (DDI_EINVAL);
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
877*1653Sgovinda 	if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
878*1653Sgovinda 	    (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE))) {
8790Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
8800Sstevel@tonic-gate 		return (DDI_EINVAL);
8810Sstevel@tonic-gate 	}
8820Sstevel@tonic-gate 
883693Sgovinda 	ret =  i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
8840Sstevel@tonic-gate 	    DDI_INTROP_SETMASK, hdlp, NULL);
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
8870Sstevel@tonic-gate 	return (ret);
8880Sstevel@tonic-gate }
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate int
8910Sstevel@tonic-gate ddi_intr_clr_mask(ddi_intr_handle_t h)
8920Sstevel@tonic-gate {
8930Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
8940Sstevel@tonic-gate 	int			ret;
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_clr_mask: hdlp = %p\n",
8970Sstevel@tonic-gate 	    (void *)hdlp));
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 	if (hdlp == NULL)
9000Sstevel@tonic-gate 		return (DDI_EINVAL);
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
903*1653Sgovinda 	if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
904*1653Sgovinda 	    (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE))) {
9050Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
9060Sstevel@tonic-gate 		return (DDI_EINVAL);
9070Sstevel@tonic-gate 	}
9080Sstevel@tonic-gate 
909693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
9100Sstevel@tonic-gate 	    DDI_INTROP_CLRMASK, hdlp, NULL);
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
9130Sstevel@tonic-gate 	return (ret);
9140Sstevel@tonic-gate }
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate /*
9170Sstevel@tonic-gate  * Interrupt get_pending handler
9180Sstevel@tonic-gate  */
9190Sstevel@tonic-gate int
9200Sstevel@tonic-gate ddi_intr_get_pending(ddi_intr_handle_t h, int *pendingp)
9210Sstevel@tonic-gate {
9220Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
9230Sstevel@tonic-gate 	int			ret;
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pending: hdlp = %p\n",
9260Sstevel@tonic-gate 	    (void *)hdlp));
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 	if (hdlp == NULL)
9290Sstevel@tonic-gate 		return (DDI_EINVAL);
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
9320Sstevel@tonic-gate 	if (!(hdlp->ih_cap & DDI_INTR_FLAG_PENDING)) {
9330Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
9340Sstevel@tonic-gate 		return (DDI_EINVAL);
9350Sstevel@tonic-gate 	}
9360Sstevel@tonic-gate 
937693Sgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
9380Sstevel@tonic-gate 	    DDI_INTROP_GETPENDING, hdlp, (void *)pendingp);
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
9410Sstevel@tonic-gate 	return (ret);
9420Sstevel@tonic-gate }
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate /*
9450Sstevel@tonic-gate  * Soft interrupt handlers
9460Sstevel@tonic-gate  */
9470Sstevel@tonic-gate /*
9480Sstevel@tonic-gate  * Add a soft interrupt and register its handler
9490Sstevel@tonic-gate  */
9500Sstevel@tonic-gate /* ARGSUSED */
9510Sstevel@tonic-gate int
9520Sstevel@tonic-gate ddi_intr_add_softint(dev_info_t *dip, ddi_softint_handle_t *h_p, int soft_pri,
9530Sstevel@tonic-gate     ddi_intr_handler_t handler, void *arg1)
9540Sstevel@tonic-gate {
9550Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp;
9560Sstevel@tonic-gate 	int			ret;
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: dip = %p, "
9590Sstevel@tonic-gate 	    "softpri = 0x%x\n", (void *)dip, soft_pri));
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate 	if ((dip == NULL) || (h_p == NULL) || (handler == NULL)) {
9620Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: "
9630Sstevel@tonic-gate 		    "invalid arguments"));
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 		return (DDI_EINVAL);
9660Sstevel@tonic-gate 	}
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	/* Validate input arguments */
9690Sstevel@tonic-gate 	if (soft_pri < DDI_INTR_SOFTPRI_MIN ||
9700Sstevel@tonic-gate 	    soft_pri > DDI_INTR_SOFTPRI_MAX) {
9710Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: invalid "
9720Sstevel@tonic-gate 		    "soft_pri input given  = %x\n", soft_pri));
9730Sstevel@tonic-gate 		return (DDI_EINVAL);
9740Sstevel@tonic-gate 	}
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 	hdlp = (ddi_softint_hdl_impl_t *)kmem_zalloc(
9770Sstevel@tonic-gate 	    sizeof (ddi_softint_hdl_impl_t), KM_SLEEP);
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 	/* fill up internally */
9800Sstevel@tonic-gate 	rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
9810Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
9820Sstevel@tonic-gate 	hdlp->ih_pri = soft_pri;
9830Sstevel@tonic-gate 	hdlp->ih_dip = dip;
9840Sstevel@tonic-gate 	hdlp->ih_cb_func = handler;
9850Sstevel@tonic-gate 	hdlp->ih_cb_arg1 = arg1;
9860Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: hdlp = %p\n",
9870Sstevel@tonic-gate 	    (void *)hdlp));
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate 	/* do the platform specific calls */
9900Sstevel@tonic-gate 	if ((ret = i_ddi_add_softint(hdlp)) != DDI_SUCCESS) {
9910Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
9920Sstevel@tonic-gate 		rw_destroy(&hdlp->ih_rwlock);
9930Sstevel@tonic-gate 		kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t));
9940Sstevel@tonic-gate 		return (ret);
9950Sstevel@tonic-gate 	}
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate 	*h_p = (ddi_softint_handle_t)hdlp;
9980Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
9990Sstevel@tonic-gate 	return (ret);
10000Sstevel@tonic-gate }
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate /*
10030Sstevel@tonic-gate  * Remove the soft interrupt
10040Sstevel@tonic-gate  */
10050Sstevel@tonic-gate int
10060Sstevel@tonic-gate ddi_intr_remove_softint(ddi_softint_handle_t h)
10070Sstevel@tonic-gate {
10080Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp = (ddi_softint_hdl_impl_t *)h;
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_softint: hdlp = %p\n",
10110Sstevel@tonic-gate 	    (void *)hdlp));
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate 	if (hdlp == NULL)
10140Sstevel@tonic-gate 		return (DDI_EINVAL);
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
10170Sstevel@tonic-gate 	i_ddi_remove_softint(hdlp);
10180Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
10190Sstevel@tonic-gate 	rw_destroy(&hdlp->ih_rwlock);
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	/* kmem_free the hdl impl_t structure allocated earlier */
10220Sstevel@tonic-gate 	kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t));
10230Sstevel@tonic-gate 	return (DDI_SUCCESS);
10240Sstevel@tonic-gate }
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate /*
10270Sstevel@tonic-gate  * Trigger a soft interrupt
10280Sstevel@tonic-gate  */
10290Sstevel@tonic-gate int
10300Sstevel@tonic-gate ddi_intr_trigger_softint(ddi_softint_handle_t h, void *arg2)
10310Sstevel@tonic-gate {
10320Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp = (ddi_softint_hdl_impl_t *)h;
10330Sstevel@tonic-gate 	int			ret;
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 	if (hdlp == NULL)
10360Sstevel@tonic-gate 		return (DDI_EINVAL);
10370Sstevel@tonic-gate 
1038278Sgovinda 	if ((ret = i_ddi_trigger_softint(hdlp, arg2)) != DDI_SUCCESS) {
10390Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_trigger_softint: failed, "
10400Sstevel@tonic-gate 		    " ret 0%x\n", ret));
1041278Sgovinda 
1042278Sgovinda 		return (ret);
10430Sstevel@tonic-gate 	}
10440Sstevel@tonic-gate 
1045278Sgovinda 	hdlp->ih_cb_arg2 = arg2;
1046278Sgovinda 	return (DDI_SUCCESS);
10470Sstevel@tonic-gate }
10480Sstevel@tonic-gate 
10490Sstevel@tonic-gate /*
10500Sstevel@tonic-gate  * Get the soft interrupt priority
10510Sstevel@tonic-gate  */
10520Sstevel@tonic-gate int
10530Sstevel@tonic-gate ddi_intr_get_softint_pri(ddi_softint_handle_t h, uint_t *soft_prip)
10540Sstevel@tonic-gate {
10550Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp = (ddi_softint_hdl_impl_t *)h;
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_softint_pri: h = %p\n",
10580Sstevel@tonic-gate 	    (void *)h));
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate 	if (hdlp == NULL)
10610Sstevel@tonic-gate 		return (DDI_EINVAL);
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
10640Sstevel@tonic-gate 	*soft_prip = hdlp->ih_pri;
10650Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
10660Sstevel@tonic-gate 	return (DDI_SUCCESS);
10670Sstevel@tonic-gate }
10680Sstevel@tonic-gate 
10690Sstevel@tonic-gate /*
10700Sstevel@tonic-gate  * Set the soft interrupt priority
10710Sstevel@tonic-gate  */
10720Sstevel@tonic-gate int
10730Sstevel@tonic-gate ddi_intr_set_softint_pri(ddi_softint_handle_t h, uint_t soft_pri)
10740Sstevel@tonic-gate {
10750Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp = (ddi_softint_hdl_impl_t *)h;
10760Sstevel@tonic-gate 	int			ret;
10770Sstevel@tonic-gate 	uint_t			orig_soft_pri;
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: h = %p\n",
10800Sstevel@tonic-gate 	    (void *)h));
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 	if (hdlp == NULL)
10830Sstevel@tonic-gate 		return (DDI_EINVAL);
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 	/* Validate priority argument */
10860Sstevel@tonic-gate 	if (soft_pri < DDI_INTR_SOFTPRI_MIN ||
10870Sstevel@tonic-gate 	    soft_pri > DDI_INTR_SOFTPRI_MAX) {
10880Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: invalid "
10890Sstevel@tonic-gate 		    "soft_pri input given  = %x\n", soft_pri));
10900Sstevel@tonic-gate 		return (DDI_EINVAL);
10910Sstevel@tonic-gate 	}
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
10940Sstevel@tonic-gate 	orig_soft_pri = hdlp->ih_pri;
10950Sstevel@tonic-gate 	hdlp->ih_pri = soft_pri;
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	if ((ret = i_ddi_set_softint_pri(hdlp, orig_soft_pri)) != DDI_SUCCESS) {
10980Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: failed, "
10990Sstevel@tonic-gate 		    " ret 0%x\n", ret));
11000Sstevel@tonic-gate 		hdlp->ih_pri = orig_soft_pri;
11010Sstevel@tonic-gate 	}
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
11040Sstevel@tonic-gate 	return (ret);
11050Sstevel@tonic-gate }
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate /*
11080Sstevel@tonic-gate  * Old DDI interrupt framework
1109693Sgovinda  *
1110693Sgovinda  * The following DDI interrupt interfaces are obsolete.
1111693Sgovinda  * Use the above new DDI interrupt interfaces instead.
11120Sstevel@tonic-gate  */
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate int
11150Sstevel@tonic-gate ddi_intr_hilevel(dev_info_t *dip, uint_t inumber)
11160Sstevel@tonic-gate {
11170Sstevel@tonic-gate 	ddi_intr_handle_t	hdl, *existing_hdlp;
11180Sstevel@tonic-gate 	int			actual, ret;
11190Sstevel@tonic-gate 	uint_t			high_pri, pri;
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: name=%s%d dip=0x%p "
11220Sstevel@tonic-gate 	    "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
11230Sstevel@tonic-gate 	    (void *)dip, inumber));
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 	/*
11260Sstevel@tonic-gate 	 * The device driver may have already registed with the
11270Sstevel@tonic-gate 	 * framework. If so, first try to get the existing interrupt handle
11280Sstevel@tonic-gate 	 * for that given inumber and use that handle.
11290Sstevel@tonic-gate 	 */
11300Sstevel@tonic-gate 	existing_hdlp = i_ddi_get_intr_handle(dip, inumber);
11310Sstevel@tonic-gate 	if (existing_hdlp) {
11320Sstevel@tonic-gate 		hdl = existing_hdlp[0];	/* Use existing handle */
11330Sstevel@tonic-gate 	} else {
11340Sstevel@tonic-gate 		if ((ret = ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED,
1135965Sgovinda 		    inumber, 1, &actual,
1136965Sgovinda 		    DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) {
11370Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: "
11380Sstevel@tonic-gate 			    "ddi_intr_alloc failed, ret 0x%x\n", ret));
11390Sstevel@tonic-gate 			return (0);
11400Sstevel@tonic-gate 		}
11410Sstevel@tonic-gate 	}
11420Sstevel@tonic-gate 
11430Sstevel@tonic-gate 	if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) {
11440Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: "
11450Sstevel@tonic-gate 		    "ddi_intr_get_pri failed, ret 0x%x\n", ret));
11460Sstevel@tonic-gate 		(void) ddi_intr_free(hdl);
11470Sstevel@tonic-gate 		return (0);
11480Sstevel@tonic-gate 	}
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate 	high_pri = ddi_intr_get_hilevel_pri();
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: pri = %x, "
11530Sstevel@tonic-gate 	    "high_pri = %x\n", pri, high_pri));
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate 	/* Free the handle allocated here only if no existing handle exists */
11560Sstevel@tonic-gate 	if (existing_hdlp == NULL)
11570Sstevel@tonic-gate 		(void) ddi_intr_free(hdl);
11580Sstevel@tonic-gate 
11590Sstevel@tonic-gate 	return (pri >= high_pri);
11600Sstevel@tonic-gate }
11610Sstevel@tonic-gate 
11620Sstevel@tonic-gate int
11630Sstevel@tonic-gate ddi_dev_nintrs(dev_info_t *dip, int *result)
11640Sstevel@tonic-gate {
11650Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: name=%s%d dip=0x%p\n",
11660Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip), (void *)dip));
11670Sstevel@tonic-gate 
11680Sstevel@tonic-gate 	if (ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED,
11690Sstevel@tonic-gate 	    result) != DDI_SUCCESS) {
11700Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: "
11710Sstevel@tonic-gate 		    "ddi_intr_get_nintrs failed\n"));
11720Sstevel@tonic-gate 		*result = 0;
11730Sstevel@tonic-gate 	}
11740Sstevel@tonic-gate 
11750Sstevel@tonic-gate 	return (DDI_SUCCESS);
11760Sstevel@tonic-gate }
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate int
11790Sstevel@tonic-gate ddi_get_iblock_cookie(dev_info_t *dip, uint_t inumber,
11800Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep)
11810Sstevel@tonic-gate {
11820Sstevel@tonic-gate 	ddi_intr_handle_t	hdl, *existing_hdlp;
11830Sstevel@tonic-gate 	int			actual, ret;
11840Sstevel@tonic-gate 	uint_t			pri;
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: name=%s%d dip=0x%p "
11870Sstevel@tonic-gate 	    "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
11880Sstevel@tonic-gate 	    (void *)dip, inumber));
11890Sstevel@tonic-gate 
11900Sstevel@tonic-gate 	ASSERT(iblock_cookiep != NULL);
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 	/*
11930Sstevel@tonic-gate 	 * The device driver may have already registed with the
11940Sstevel@tonic-gate 	 * framework. If so, first try to get the existing interrupt handle
11950Sstevel@tonic-gate 	 * for that given inumber and use that handle.
11960Sstevel@tonic-gate 	 */
11970Sstevel@tonic-gate 	existing_hdlp = i_ddi_get_intr_handle(dip, inumber);
11980Sstevel@tonic-gate 	if (existing_hdlp) {
11990Sstevel@tonic-gate 		hdl = existing_hdlp[0];	/* Use existing handle */
12000Sstevel@tonic-gate 	} else {
12010Sstevel@tonic-gate 		if ((ret = ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED,
1202965Sgovinda 		    inumber, 1, &actual,
1203965Sgovinda 		    DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) {
12040Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: "
12050Sstevel@tonic-gate 			    "ddi_intr_alloc failed, ret 0x%x\n", ret));
12060Sstevel@tonic-gate 			return (DDI_INTR_NOTFOUND);
12070Sstevel@tonic-gate 		}
12080Sstevel@tonic-gate 	}
12090Sstevel@tonic-gate 
12100Sstevel@tonic-gate 	if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) {
12110Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: "
12120Sstevel@tonic-gate 		    "ddi_intr_get_pri failed, ret 0x%x\n", ret));
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 		(void) ddi_intr_free(hdl);
12150Sstevel@tonic-gate 		return (DDI_FAILURE);
12160Sstevel@tonic-gate 	}
12170Sstevel@tonic-gate 
121842Sagiri 	*iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)pri;
12190Sstevel@tonic-gate 	/* Free the handle allocated here only if no existing handle exists */
12200Sstevel@tonic-gate 	if (existing_hdlp == NULL)
12210Sstevel@tonic-gate 		(void) ddi_intr_free(hdl);
12220Sstevel@tonic-gate 
12230Sstevel@tonic-gate 	return (DDI_SUCCESS);
12240Sstevel@tonic-gate }
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate int
12270Sstevel@tonic-gate ddi_add_intr(dev_info_t *dip, uint_t inumber,
12280Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep,
12290Sstevel@tonic-gate     ddi_idevice_cookie_t *idevice_cookiep,
12300Sstevel@tonic-gate     uint_t (*int_handler)(caddr_t int_handler_arg),
12310Sstevel@tonic-gate     caddr_t int_handler_arg)
12320Sstevel@tonic-gate {
12330Sstevel@tonic-gate 	ddi_intr_handle_t	*hdl_p;
12340Sstevel@tonic-gate 	int			actual, ret;
12350Sstevel@tonic-gate 	uint_t			pri;
12360Sstevel@tonic-gate 
12370Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: name=%s%d dip=0x%p "
12380Sstevel@tonic-gate 	    "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
12390Sstevel@tonic-gate 	    (void *)dip, inumber));
12400Sstevel@tonic-gate 
12410Sstevel@tonic-gate 	hdl_p = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP);
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate 	if ((ret = ddi_intr_alloc(dip, hdl_p, DDI_INTR_TYPE_FIXED,
1244965Sgovinda 	    inumber, 1, &actual, DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) {
12450Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
12460Sstevel@tonic-gate 		    "ddi_intr_alloc failed, ret 0x%x\n", ret));
12470Sstevel@tonic-gate 		kmem_free(hdl_p, sizeof (ddi_intr_handle_t));
12480Sstevel@tonic-gate 		return (DDI_INTR_NOTFOUND);
12490Sstevel@tonic-gate 	}
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate 	if ((ret = ddi_intr_get_pri(hdl_p[0], &pri)) != DDI_SUCCESS)  {
12520Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
12530Sstevel@tonic-gate 		    "ddi_intr_get_pri failed, ret 0x%x\n", ret));
12540Sstevel@tonic-gate 		(void) ddi_intr_free(hdl_p[0]);
12550Sstevel@tonic-gate 		kmem_free(hdl_p, sizeof (ddi_intr_handle_t));
12560Sstevel@tonic-gate 		return (DDI_FAILURE);
12570Sstevel@tonic-gate 	}
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 	if ((ret = ddi_intr_add_handler(hdl_p[0], (ddi_intr_handler_t *)
12600Sstevel@tonic-gate 	    int_handler, int_handler_arg, NULL)) != DDI_SUCCESS) {
12610Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
12620Sstevel@tonic-gate 		    "ddi_intr_add_handler failed, ret 0x%x\n", ret));
12630Sstevel@tonic-gate 		(void) ddi_intr_free(hdl_p[0]);
12640Sstevel@tonic-gate 		kmem_free(hdl_p, sizeof (ddi_intr_handle_t));
12650Sstevel@tonic-gate 		return (DDI_FAILURE);
12660Sstevel@tonic-gate 	}
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	if ((ret = ddi_intr_enable(hdl_p[0])) != DDI_SUCCESS) {
12690Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
12700Sstevel@tonic-gate 		    "ddi_intr_enable failed, ret 0x%x\n", ret));
12710Sstevel@tonic-gate 		(void) ddi_intr_remove_handler(hdl_p[0]);
12720Sstevel@tonic-gate 		(void) ddi_intr_free(hdl_p[0]);
12730Sstevel@tonic-gate 		kmem_free(hdl_p, sizeof (ddi_intr_handle_t));
12740Sstevel@tonic-gate 		return (DDI_FAILURE);
12750Sstevel@tonic-gate 	}
12760Sstevel@tonic-gate 
12770Sstevel@tonic-gate 	if (iblock_cookiep)
127842Sagiri 		*iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)pri;
12790Sstevel@tonic-gate 
12800Sstevel@tonic-gate 	if (idevice_cookiep) {
12810Sstevel@tonic-gate 		idevice_cookiep->idev_vector = 0;
12820Sstevel@tonic-gate 		idevice_cookiep->idev_priority = pri;
12830Sstevel@tonic-gate 	}
12840Sstevel@tonic-gate 
12850Sstevel@tonic-gate 	return (DDI_SUCCESS);
12860Sstevel@tonic-gate }
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate /* ARGSUSED */
12890Sstevel@tonic-gate int
12900Sstevel@tonic-gate ddi_add_fastintr(dev_info_t *dip, uint_t inumber,
12910Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep,
12920Sstevel@tonic-gate     ddi_idevice_cookie_t *idevice_cookiep,
12930Sstevel@tonic-gate     uint_t (*hi_int_handler)(void))
12940Sstevel@tonic-gate {
12950Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_fastintr: name=%s%d dip=0x%p "
12960Sstevel@tonic-gate 	    "inum=0x%x: Not supported, return failure\n", ddi_driver_name(dip),
12970Sstevel@tonic-gate 	    ddi_get_instance(dip), (void *)dip, inumber));
12980Sstevel@tonic-gate 
12990Sstevel@tonic-gate 	return (DDI_FAILURE);
13000Sstevel@tonic-gate }
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate /* ARGSUSED */
13030Sstevel@tonic-gate void
13040Sstevel@tonic-gate ddi_remove_intr(dev_info_t *dip, uint_t inum, ddi_iblock_cookie_t iblock_cookie)
13050Sstevel@tonic-gate {
13060Sstevel@tonic-gate 	ddi_intr_handle_t	*hdl_p;
13070Sstevel@tonic-gate 	int			ret;
13080Sstevel@tonic-gate 
13090Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: name=%s%d dip=0x%p "
13100Sstevel@tonic-gate 	    "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
13110Sstevel@tonic-gate 	    (void *)dip, inum));
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate 	if ((hdl_p = i_ddi_get_intr_handle(dip, inum)) == NULL) {
13140Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: no handle "
13150Sstevel@tonic-gate 		    "found\n"));
13160Sstevel@tonic-gate 		return;
13170Sstevel@tonic-gate 	}
13180Sstevel@tonic-gate 
13190Sstevel@tonic-gate 	if ((ret = ddi_intr_disable(hdl_p[0])) != DDI_SUCCESS) {
13200Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
13210Sstevel@tonic-gate 		    "ddi_intr_disable failed, ret 0x%x\n", ret));
13220Sstevel@tonic-gate 		return;
13230Sstevel@tonic-gate 	}
13240Sstevel@tonic-gate 
13250Sstevel@tonic-gate 	if ((ret = ddi_intr_remove_handler(hdl_p[0])) != DDI_SUCCESS) {
13260Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
13270Sstevel@tonic-gate 		    "ddi_intr_remove_handler failed, ret 0x%x\n", ret));
13280Sstevel@tonic-gate 		return;
13290Sstevel@tonic-gate 	}
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate 	if ((ret = ddi_intr_free(hdl_p[0])) != DDI_SUCCESS) {
13320Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
13330Sstevel@tonic-gate 		    "ddi_intr_free failed, ret 0x%x\n", ret));
13340Sstevel@tonic-gate 		return;
13350Sstevel@tonic-gate 	}
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 	kmem_free(hdl_p, sizeof (ddi_intr_handle_t));
13380Sstevel@tonic-gate }
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate /* ARGSUSED */
13410Sstevel@tonic-gate int
13420Sstevel@tonic-gate ddi_get_soft_iblock_cookie(dev_info_t *dip, int preference,
13430Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep)
13440Sstevel@tonic-gate {
13450Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_get_soft_iblock_cookie: name=%s%d "
13460Sstevel@tonic-gate 	    "dip=0x%p pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
13470Sstevel@tonic-gate 	    (void *)dip, preference));
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 	ASSERT(iblock_cookiep != NULL);
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate 	if (preference == DDI_SOFTINT_FIXED)
13520Sstevel@tonic-gate 		return (DDI_FAILURE);
13530Sstevel@tonic-gate 
135442Sagiri 	*iblock_cookiep = (ddi_iblock_cookie_t)((uintptr_t)
13550Sstevel@tonic-gate 	    ((preference > DDI_SOFTINT_MED) ? DDI_SOFT_INTR_PRI_H :
13560Sstevel@tonic-gate 	    DDI_SOFT_INTR_PRI_M));
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 	return (DDI_SUCCESS);
13590Sstevel@tonic-gate }
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate int
13620Sstevel@tonic-gate ddi_add_softintr(dev_info_t *dip, int preference, ddi_softintr_t *idp,
13630Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep,
13640Sstevel@tonic-gate     ddi_idevice_cookie_t *idevice_cookiep,
13650Sstevel@tonic-gate     uint_t (*int_handler)(caddr_t int_handler_arg),
13660Sstevel@tonic-gate     caddr_t int_handler_arg)
13670Sstevel@tonic-gate {
13680Sstevel@tonic-gate 	ddi_softint_handle_t	*hdl_p;
13690Sstevel@tonic-gate 	uint64_t		softpri;
13700Sstevel@tonic-gate 	int			ret;
13710Sstevel@tonic-gate 
13720Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: name=%s%d dip=0x%p "
13730Sstevel@tonic-gate 	    "pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
13740Sstevel@tonic-gate 	    (void *)dip, preference));
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 	if ((idp == NULL) || ((preference == DDI_SOFTINT_FIXED) &&
13770Sstevel@tonic-gate 	    (iblock_cookiep == NULL)))
13780Sstevel@tonic-gate 		return (DDI_FAILURE);
13790Sstevel@tonic-gate 
13800Sstevel@tonic-gate 	/* Translate the priority preference */
13810Sstevel@tonic-gate 	if (preference == DDI_SOFTINT_FIXED) {
1382190Seota 		softpri = (uint64_t)(uintptr_t)*iblock_cookiep;
13830Sstevel@tonic-gate 		softpri = MIN(softpri, DDI_SOFT_INTR_PRI_H);
13840Sstevel@tonic-gate 	} else {
13850Sstevel@tonic-gate 		softpri = (uint64_t)((preference > DDI_SOFTINT_MED) ?
13860Sstevel@tonic-gate 		    DDI_SOFT_INTR_PRI_H : DDI_SOFT_INTR_PRI_M);
13870Sstevel@tonic-gate 	}
13880Sstevel@tonic-gate 
13890Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: preference 0x%x "
13900Sstevel@tonic-gate 	    "softpri 0x%lx\n", preference, (long)softpri));
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 	hdl_p = kmem_zalloc(sizeof (ddi_softint_handle_t), KM_SLEEP);
13930Sstevel@tonic-gate 	if ((ret = ddi_intr_add_softint(dip, hdl_p, softpri,
13940Sstevel@tonic-gate 	    (ddi_intr_handler_t *)int_handler, int_handler_arg)) !=
13950Sstevel@tonic-gate 	    DDI_SUCCESS) {
13960Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: "
13970Sstevel@tonic-gate 		    "ddi_intr_add_softint failed, ret 0x%x\n", ret));
13980Sstevel@tonic-gate 
13990Sstevel@tonic-gate 		kmem_free(hdl_p, sizeof (ddi_softint_handle_t));
14000Sstevel@tonic-gate 		return (DDI_FAILURE);
14010Sstevel@tonic-gate 	}
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate 	if (iblock_cookiep)
1404190Seota 		*iblock_cookiep =  (ddi_iblock_cookie_t)(uintptr_t)softpri;
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate 	if (idevice_cookiep) {
14070Sstevel@tonic-gate 		idevice_cookiep->idev_vector = 0;
14080Sstevel@tonic-gate 		idevice_cookiep->idev_priority = softpri;
14090Sstevel@tonic-gate 	}
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 	*idp = (ddi_softintr_t)hdl_p;
14120Sstevel@tonic-gate 
14130Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: dip = 0x%p, "
14140Sstevel@tonic-gate 	    "idp = 0x%p, ret = %x\n", (void *)dip, (void *)*idp, ret));
14150Sstevel@tonic-gate 
14160Sstevel@tonic-gate 	return (DDI_SUCCESS);
14170Sstevel@tonic-gate }
14180Sstevel@tonic-gate 
14190Sstevel@tonic-gate void
14200Sstevel@tonic-gate ddi_remove_softintr(ddi_softintr_t id)
14210Sstevel@tonic-gate {
14220Sstevel@tonic-gate 	ddi_softint_handle_t	*h_p = (ddi_softint_handle_t *)id;
14230Sstevel@tonic-gate 
14240Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: id=0x%p\n",
14250Sstevel@tonic-gate 	    (void *)id));
14260Sstevel@tonic-gate 
14270Sstevel@tonic-gate 	if (h_p == NULL)
14280Sstevel@tonic-gate 		return;
14290Sstevel@tonic-gate 
14300Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: handle 0x%p\n",
14310Sstevel@tonic-gate 	    (void *)h_p));
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	(void) ddi_intr_remove_softint(*h_p);
14340Sstevel@tonic-gate 	kmem_free(h_p, sizeof (ddi_softint_handle_t));
14350Sstevel@tonic-gate }
14360Sstevel@tonic-gate 
14370Sstevel@tonic-gate void
14380Sstevel@tonic-gate ddi_trigger_softintr(ddi_softintr_t id)
14390Sstevel@tonic-gate {
14400Sstevel@tonic-gate 	ddi_softint_handle_t	*h_p = (ddi_softint_handle_t *)id;
14410Sstevel@tonic-gate 	int			ret;
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate 	if (h_p == NULL)
14440Sstevel@tonic-gate 		return;
14450Sstevel@tonic-gate 
14460Sstevel@tonic-gate 	if ((ret = ddi_intr_trigger_softint(*h_p, NULL)) != DDI_SUCCESS) {
14470Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_trigger_softintr: "
14480Sstevel@tonic-gate 		    "ddi_intr_trigger_softint failed, hdlp 0x%p "
14490Sstevel@tonic-gate 		    "ret 0x%x\n", (void *)h_p, ret));
14500Sstevel@tonic-gate 	}
14510Sstevel@tonic-gate }
1452