xref: /illumos-gate/usr/src/uts/common/os/ddi_intr.c (revision 71222654)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5102cb92eSjohnny  * Common Development and Distribution License (the "License").
6102cb92eSjohnny  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22a120541cSScott M. Carter  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #include <sys/note.h>
267c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
277c478bd9Sstevel@tonic-gate #include <sys/types.h>
287c478bd9Sstevel@tonic-gate #include <sys/param.h>
297c478bd9Sstevel@tonic-gate #include <sys/systm.h>
307c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
317c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
327c478bd9Sstevel@tonic-gate #include <sys/debug.h>
337c478bd9Sstevel@tonic-gate #include <sys/avintr.h>
347c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
357c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
367c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h>	/* include prototypes */
3720036fe5Segillett #include <sys/atomic.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate /*
407c478bd9Sstevel@tonic-gate  * New DDI interrupt framework
417c478bd9Sstevel@tonic-gate  */
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /*
447c478bd9Sstevel@tonic-gate  * ddi_intr_get_supported_types:
457c478bd9Sstevel@tonic-gate  *	Return, as a bit mask, the hardware interrupt types supported by
467c478bd9Sstevel@tonic-gate  *	both the device and by the host in the integer pointed
477c478bd9Sstevel@tonic-gate  *	to be the 'typesp' argument.
487c478bd9Sstevel@tonic-gate  */
497c478bd9Sstevel@tonic-gate int
ddi_intr_get_supported_types(dev_info_t * dip,int * typesp)507c478bd9Sstevel@tonic-gate ddi_intr_get_supported_types(dev_info_t *dip, int *typesp)
517c478bd9Sstevel@tonic-gate {
527c478bd9Sstevel@tonic-gate 	int			ret;
537c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	hdl;
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate 	if (dip == NULL)
567c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: dip %p\n",
597c478bd9Sstevel@tonic-gate 	    (void *)dip));
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate 	if (*typesp = i_ddi_intr_get_supported_types(dip))
627c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate 	bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
657c478bd9Sstevel@tonic-gate 	hdl.ih_dip = dip;
667c478bd9Sstevel@tonic-gate 
67a195726fSgovinda 	ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_SUPPORTED_TYPES, &hdl,
687c478bd9Sstevel@tonic-gate 	    (void *)typesp);
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS)
717c478bd9Sstevel@tonic-gate 		return (DDI_INTR_NOTFOUND);
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: types %x\n",
747c478bd9Sstevel@tonic-gate 	    *typesp));
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	return (ret);
777c478bd9Sstevel@tonic-gate }
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate /*
807c478bd9Sstevel@tonic-gate  * ddi_intr_get_nintrs:
817c478bd9Sstevel@tonic-gate  * 	Return as an integer in the integer pointed to by the argument
827c478bd9Sstevel@tonic-gate  * 	*nintrsp*, the number of interrupts the device supports for the
837c478bd9Sstevel@tonic-gate  *	given interrupt type.
847c478bd9Sstevel@tonic-gate  */
857c478bd9Sstevel@tonic-gate int
ddi_intr_get_nintrs(dev_info_t * dip,int type,int * nintrsp)867c478bd9Sstevel@tonic-gate ddi_intr_get_nintrs(dev_info_t *dip, int type, int *nintrsp)
877c478bd9Sstevel@tonic-gate {
887c478bd9Sstevel@tonic-gate 	int			ret;
897c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	hdl;
907c478bd9Sstevel@tonic-gate 
91a195726fSgovinda 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs: dip %p, type: %d\n",
92a195726fSgovinda 	    (void *)dip, type));
937c478bd9Sstevel@tonic-gate 
945febcb4aSScott Carter, SD IOSW 	if ((dip == NULL) || (nintrsp == NULL) ||
955febcb4aSScott Carter, SD IOSW 	    !DDI_INTR_TYPE_FLAG_VALID(type) ||
96d626b9f5Sanish 	    !(i_ddi_intr_get_supported_types(dip) & type)) {
975febcb4aSScott Carter, SD IOSW 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs: "
985febcb4aSScott Carter, SD IOSW 		    "Invalid input args\n"));
997c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
100a195726fSgovinda 	}
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 	if (*nintrsp = i_ddi_intr_get_supported_nintrs(dip, type))
1037c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
1067c478bd9Sstevel@tonic-gate 	hdl.ih_dip = dip;
1077c478bd9Sstevel@tonic-gate 	hdl.ih_type = type;
1087c478bd9Sstevel@tonic-gate 
109a195726fSgovinda 	ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_NINTRS, &hdl,
1107c478bd9Sstevel@tonic-gate 	    (void *)nintrsp);
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs:: nintrs %x\n",
1137c478bd9Sstevel@tonic-gate 	    *nintrsp));
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	return (ret);
1167c478bd9Sstevel@tonic-gate }
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate /*
1197c478bd9Sstevel@tonic-gate  * ddi_intr_get_navail:
1207c478bd9Sstevel@tonic-gate  *	Bus nexus driver will return availble interrupt count value for
1217c478bd9Sstevel@tonic-gate  *	a given interrupt type.
1227c478bd9Sstevel@tonic-gate  *
1237c478bd9Sstevel@tonic-gate  * 	Return as an integer in the integer pointed to by the argument
1247c478bd9Sstevel@tonic-gate  * 	*navailp*, the number of interrupts currently available for the
1257c478bd9Sstevel@tonic-gate  *	given interrupt type.
1267c478bd9Sstevel@tonic-gate  */
1277c478bd9Sstevel@tonic-gate int
ddi_intr_get_navail(dev_info_t * dip,int type,int * navailp)1287c478bd9Sstevel@tonic-gate ddi_intr_get_navail(dev_info_t *dip, int type, int *navailp)
1297c478bd9Sstevel@tonic-gate {
130a195726fSgovinda 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_navail: dip %p, type: %d\n",
131a195726fSgovinda 	    (void *)dip, type));
1327c478bd9Sstevel@tonic-gate 
1335febcb4aSScott Carter, SD IOSW 	if ((dip == NULL) || (navailp == NULL) ||
1345febcb4aSScott Carter, SD IOSW 	    !DDI_INTR_TYPE_FLAG_VALID(type) ||
135d626b9f5Sanish 	    !(i_ddi_intr_get_supported_types(dip) & type)) {
1365febcb4aSScott Carter, SD IOSW 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_navail: "
1375febcb4aSScott Carter, SD IOSW 		    "Invalid input args\n"));
1387c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
139a195726fSgovinda 	}
1407c478bd9Sstevel@tonic-gate 
1415febcb4aSScott Carter, SD IOSW 	if ((*navailp = i_ddi_intr_get_current_navail(dip, type)) == 0)
1425febcb4aSScott Carter, SD IOSW 		return (DDI_INTR_NOTFOUND);
1437c478bd9Sstevel@tonic-gate 
1445febcb4aSScott Carter, SD IOSW 	return (DDI_SUCCESS);
1457c478bd9Sstevel@tonic-gate }
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate /*
1487c478bd9Sstevel@tonic-gate  * Interrupt allocate/free functions
1497c478bd9Sstevel@tonic-gate  */
1507c478bd9Sstevel@tonic-gate int
ddi_intr_alloc(dev_info_t * dip,ddi_intr_handle_t * h_array,int type,int inum,int count,int * actualp,int behavior)1517c478bd9Sstevel@tonic-gate ddi_intr_alloc(dev_info_t *dip, ddi_intr_handle_t *h_array, int type, int inum,
1527c478bd9Sstevel@tonic-gate     int count, int *actualp, int behavior)
1537c478bd9Sstevel@tonic-gate {
1547c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp, tmp_hdl;
1555febcb4aSScott Carter, SD IOSW 	int			i, ret, cap = 0, curr_type, nintrs;
1565febcb4aSScott Carter, SD IOSW 	uint_t			pri, navail, curr_nintrs = 0;
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: name %s dip 0x%p "
1597c478bd9Sstevel@tonic-gate 	    "type %x inum %x count %x behavior %x\n", ddi_driver_name(dip),
1607c478bd9Sstevel@tonic-gate 	    (void *)dip, type, inum, count, behavior));
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	/* Validate parameters */
1635febcb4aSScott Carter, SD IOSW 	if ((dip == NULL) || (h_array == NULL) || (inum < 0) || (count < 1) ||
1645febcb4aSScott Carter, SD IOSW 	    (actualp == NULL) || !DDI_INTR_BEHAVIOR_FLAG_VALID(behavior)) {
1655febcb4aSScott Carter, SD IOSW 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: "
1665febcb4aSScott Carter, SD IOSW 		    "Invalid input args\n"));
1677c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
1687c478bd9Sstevel@tonic-gate 	}
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	/* Validate interrupt type */
171d626b9f5Sanish 	if (!DDI_INTR_TYPE_FLAG_VALID(type) ||
172d626b9f5Sanish 	    !(i_ddi_intr_get_supported_types(dip) & type)) {
1737c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x not "
1747c478bd9Sstevel@tonic-gate 		    "supported\n", type));
1757c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
1767c478bd9Sstevel@tonic-gate 	}
1777c478bd9Sstevel@tonic-gate 
1785febcb4aSScott Carter, SD IOSW 	/* Validate inum not previously allocated */
179d626b9f5Sanish 	if ((type == DDI_INTR_TYPE_FIXED) &&
180d626b9f5Sanish 	    (i_ddi_get_intr_handle(dip, inum) != NULL)) {
181d626b9f5Sanish 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: inum %d is already "
1825febcb4aSScott Carter, SD IOSW 		    "in use, cannot allocate again!!\n", inum));
183d626b9f5Sanish 		return (DDI_EINVAL);
184d626b9f5Sanish 	}
185d626b9f5Sanish 
1865febcb4aSScott Carter, SD IOSW 	/* Get how many interrupts the device supports */
1875febcb4aSScott Carter, SD IOSW 	if ((nintrs = i_ddi_intr_get_supported_nintrs(dip, type)) == 0) {
1887c478bd9Sstevel@tonic-gate 		if (ddi_intr_get_nintrs(dip, type, &nintrs) != DDI_SUCCESS) {
1897c478bd9Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no "
1907c478bd9Sstevel@tonic-gate 			    "interrupts found of type %d\n", type));
1917c478bd9Sstevel@tonic-gate 			return (DDI_INTR_NOTFOUND);
1927c478bd9Sstevel@tonic-gate 		}
1937c478bd9Sstevel@tonic-gate 	}
1947c478bd9Sstevel@tonic-gate 
1955febcb4aSScott Carter, SD IOSW 	/* Get how many interrupts the device is already using */
1965febcb4aSScott Carter, SD IOSW 	if ((curr_type = i_ddi_intr_get_current_type(dip)) != 0) {
1975febcb4aSScott Carter, SD IOSW 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x "
1985febcb4aSScott Carter, SD IOSW 		    "is already being used\n", curr_type));
1995febcb4aSScott Carter, SD IOSW 		curr_nintrs = i_ddi_intr_get_current_nintrs(dip);
2007c478bd9Sstevel@tonic-gate 	}
2017c478bd9Sstevel@tonic-gate 
2025febcb4aSScott Carter, SD IOSW 	/* Validate interrupt type consistency */
2035febcb4aSScott Carter, SD IOSW 	if ((curr_type != 0) && (type != curr_type)) {
2047c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Requested "
2057c478bd9Sstevel@tonic-gate 		    "interrupt type %x is different from interrupt type %x"
2065febcb4aSScott Carter, SD IOSW 		    "already in use\n", type, curr_type));
2077c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 
2105febcb4aSScott Carter, SD IOSW 	/* Validate count does not exceed what device supports */
2115febcb4aSScott Carter, SD IOSW 	if (count > nintrs) {
2125febcb4aSScott Carter, SD IOSW 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no of interrupts "
2135febcb4aSScott Carter, SD IOSW 		    "requested %d is more than supported %d\n", count, nintrs));
2145febcb4aSScott Carter, SD IOSW 		return (DDI_EINVAL);
2155febcb4aSScott Carter, SD IOSW 	} else if ((count + curr_nintrs) > nintrs) {
2165febcb4aSScott Carter, SD IOSW 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: count %d "
2175febcb4aSScott Carter, SD IOSW 		    "+ intrs in use %d exceeds supported %d intrs\n",
2185febcb4aSScott Carter, SD IOSW 		    count, curr_nintrs, nintrs));
2195febcb4aSScott Carter, SD IOSW 		return (DDI_EINVAL);
2207c478bd9Sstevel@tonic-gate 	}
2217c478bd9Sstevel@tonic-gate 
2225febcb4aSScott Carter, SD IOSW 	/* Validate power of 2 requirements for MSI */
2235febcb4aSScott Carter, SD IOSW 	if ((type == DDI_INTR_TYPE_MSI) && !ISP2(curr_nintrs + count)) {
2247c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: "
2257c478bd9Sstevel@tonic-gate 		    "MSI count %d is not a power of two\n", count));
2267c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
2277c478bd9Sstevel@tonic-gate 	}
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	/*
2305febcb4aSScott Carter, SD IOSW 	 * Initialize the device's interrupt information structure,
2315febcb4aSScott Carter, SD IOSW 	 * and establish an association with IRM if it is supported.
232ef643aefSegillett 	 *
2335febcb4aSScott Carter, SD IOSW 	 * NOTE: IRM checks minimum support, and can return DDI_EAGAIN.
2347c478bd9Sstevel@tonic-gate 	 */
2355febcb4aSScott Carter, SD IOSW 	if (curr_nintrs == 0) {
2365febcb4aSScott Carter, SD IOSW 		i_ddi_intr_devi_init(dip);
2375febcb4aSScott Carter, SD IOSW 		if (i_ddi_irm_insert(dip, type, count) == DDI_EAGAIN) {
2385febcb4aSScott Carter, SD IOSW 			cmn_err(CE_WARN, "ddi_intr_alloc: "
2395febcb4aSScott Carter, SD IOSW 			    "cannot fit into interrupt pool\n");
2405febcb4aSScott Carter, SD IOSW 			return (DDI_EAGAIN);
2415febcb4aSScott Carter, SD IOSW 		}
2425febcb4aSScott Carter, SD IOSW 	}
2435febcb4aSScott Carter, SD IOSW 
244a120541cSScott M. Carter 	/* Synchronously adjust IRM associations for non-IRM aware drivers */
245a120541cSScott M. Carter 	if (curr_nintrs && (i_ddi_irm_supported(dip, type) != DDI_SUCCESS))
246a120541cSScott M. Carter 		(void) i_ddi_irm_modify(dip, count + curr_nintrs);
247a120541cSScott M. Carter 
2485febcb4aSScott Carter, SD IOSW 	/* Get how many interrupts are currently available */
2495febcb4aSScott Carter, SD IOSW 	navail = i_ddi_intr_get_current_navail(dip, type);
250ef643aefSegillett 
2515febcb4aSScott Carter, SD IOSW 	/* Validate that requested number of interrupts are available */
2525febcb4aSScott Carter, SD IOSW 	if (curr_nintrs == navail) {
2535febcb4aSScott Carter, SD IOSW 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: max # of intrs %d "
2545febcb4aSScott Carter, SD IOSW 		    "already allocated\n", navail));
2555febcb4aSScott Carter, SD IOSW 		return (DDI_EAGAIN);
2565febcb4aSScott Carter, SD IOSW 	}
2575febcb4aSScott Carter, SD IOSW 	if ((count + curr_nintrs) > navail) {
2585febcb4aSScott Carter, SD IOSW 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: requested # of "
2595febcb4aSScott Carter, SD IOSW 		    "intrs %d exceeds # of available intrs %d\n", count,
2605febcb4aSScott Carter, SD IOSW 		    navail - curr_nintrs));
2615febcb4aSScott Carter, SD IOSW 		if (behavior == DDI_INTR_ALLOC_STRICT) {
2627c478bd9Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: "
2635febcb4aSScott Carter, SD IOSW 			    "DDI_INTR_ALLOC_STRICT flag is passed, "
2645febcb4aSScott Carter, SD IOSW 			    "return failure\n"));
265a120541cSScott M. Carter 			if (curr_nintrs == 0)
266a120541cSScott M. Carter 				i_ddi_intr_devi_fini(dip);
267a120541cSScott M. Carter 			else if (i_ddi_irm_supported(dip, type) != DDI_SUCCESS)
268a120541cSScott M. Carter 				(void) i_ddi_irm_modify(dip, curr_nintrs);
2695febcb4aSScott Carter, SD IOSW 			return (DDI_EAGAIN);
2707c478bd9Sstevel@tonic-gate 		}
2715febcb4aSScott Carter, SD IOSW 		count = navail - curr_nintrs;
2727c478bd9Sstevel@tonic-gate 	}
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	/* Now allocate required number of interrupts */
2757c478bd9Sstevel@tonic-gate 	bzero(&tmp_hdl, sizeof (ddi_intr_handle_impl_t));
2767c478bd9Sstevel@tonic-gate 	tmp_hdl.ih_type = type;
2777c478bd9Sstevel@tonic-gate 	tmp_hdl.ih_inum = inum;
2787c478bd9Sstevel@tonic-gate 	tmp_hdl.ih_scratch1 = count;
27980ab886dSwesolows 	tmp_hdl.ih_scratch2 = (void *)(uintptr_t)behavior;
2807c478bd9Sstevel@tonic-gate 	tmp_hdl.ih_dip = dip;
2817c478bd9Sstevel@tonic-gate 
282a195726fSgovinda 	if (i_ddi_intr_ops(dip, dip, DDI_INTROP_ALLOC,
2837c478bd9Sstevel@tonic-gate 	    &tmp_hdl, (void *)actualp) != DDI_SUCCESS) {
2847c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: allocation "
2857c478bd9Sstevel@tonic-gate 		    "failed\n"));
28620036fe5Segillett 		i_ddi_intr_devi_fini(dip);
2877c478bd9Sstevel@tonic-gate 		return (*actualp ? DDI_EAGAIN : DDI_INTR_NOTFOUND);
2887c478bd9Sstevel@tonic-gate 	}
2897c478bd9Sstevel@tonic-gate 
290a195726fSgovinda 	if ((ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_GETPRI,
2917c478bd9Sstevel@tonic-gate 	    &tmp_hdl, (void *)&pri)) != DDI_SUCCESS) {
2927c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get priority "
2937c478bd9Sstevel@tonic-gate 		    "failed\n"));
29420036fe5Segillett 		goto fail;
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: getting capability\n"));
2987c478bd9Sstevel@tonic-gate 
299a195726fSgovinda 	if ((ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_GETCAP,
3007c478bd9Sstevel@tonic-gate 	    &tmp_hdl, (void *)&cap)) != DDI_SUCCESS) {
3017c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get capability "
3027c478bd9Sstevel@tonic-gate 		    "failed\n"));
30320036fe5Segillett 		goto fail;
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 
30620036fe5Segillett 	/*
30720036fe5Segillett 	 * Save current interrupt type, supported and current intr count.
30820036fe5Segillett 	 */
3097c478bd9Sstevel@tonic-gate 	i_ddi_intr_set_current_type(dip, type);
3107c478bd9Sstevel@tonic-gate 	i_ddi_intr_set_supported_nintrs(dip, nintrs);
3117c478bd9Sstevel@tonic-gate 	i_ddi_intr_set_current_nintrs(dip,
3127c478bd9Sstevel@tonic-gate 	    i_ddi_intr_get_current_nintrs(dip) + *actualp);
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	/* Now, go and handle each "handle" */
3155febcb4aSScott Carter, SD IOSW 	for (i = inum; i < (inum + *actualp); i++) {
3167c478bd9Sstevel@tonic-gate 		hdlp = (ddi_intr_handle_impl_t *)kmem_zalloc(
3177c478bd9Sstevel@tonic-gate 		    (sizeof (ddi_intr_handle_impl_t)), KM_SLEEP);
3187c478bd9Sstevel@tonic-gate 		rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
3197c478bd9Sstevel@tonic-gate 		h_array[i] = (struct __ddi_intr_handle *)hdlp;
3207c478bd9Sstevel@tonic-gate 		hdlp->ih_type = type;
3217c478bd9Sstevel@tonic-gate 		hdlp->ih_pri = pri;
3227c478bd9Sstevel@tonic-gate 		hdlp->ih_cap = cap;
3237c478bd9Sstevel@tonic-gate 		hdlp->ih_ver = DDI_INTR_VERSION;
3247c478bd9Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ALLOC;
3257c478bd9Sstevel@tonic-gate 		hdlp->ih_dip = dip;
3265febcb4aSScott Carter, SD IOSW 		hdlp->ih_inum = i;
3277a364d25Sschwartz 		i_ddi_alloc_intr_phdl(hdlp);
3287c478bd9Sstevel@tonic-gate 		if (type & DDI_INTR_TYPE_FIXED)
3295febcb4aSScott Carter, SD IOSW 			i_ddi_set_intr_handle(dip, hdlp->ih_inum,
3305febcb4aSScott Carter, SD IOSW 			    (ddi_intr_handle_t)hdlp);
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: hdlp = 0x%p\n",
3337c478bd9Sstevel@tonic-gate 		    (void *)h_array[i]));
3347c478bd9Sstevel@tonic-gate 	}
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
33720036fe5Segillett 
33820036fe5Segillett fail:
33920036fe5Segillett 	(void) i_ddi_intr_ops(tmp_hdl.ih_dip, tmp_hdl.ih_dip,
34020036fe5Segillett 	    DDI_INTROP_FREE, &tmp_hdl, NULL);
34120036fe5Segillett 	i_ddi_intr_devi_fini(dip);
34220036fe5Segillett 
34320036fe5Segillett 	return (ret);
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate int
ddi_intr_free(ddi_intr_handle_t h)3477c478bd9Sstevel@tonic-gate ddi_intr_free(ddi_intr_handle_t h)
3487c478bd9Sstevel@tonic-gate {
3497c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
3507c478bd9Sstevel@tonic-gate 	int			ret;
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_free: hdlp = %p\n", (void *)hdlp));
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
3557c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
35820036fe5Segillett 	if (((hdlp->ih_flags & DDI_INTR_MSIX_DUP) &&
35920036fe5Segillett 	    (hdlp->ih_state != DDI_IHDL_STATE_ADDED)) ||
36020036fe5Segillett 	    ((hdlp->ih_state != DDI_IHDL_STATE_ALLOC) &&
36120036fe5Segillett 	    (!(hdlp->ih_flags & DDI_INTR_MSIX_DUP)))) {
3627c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
3637c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 
366023ccc1eSegillett 	/* Set the number of interrupts to free */
367023ccc1eSegillett 	hdlp->ih_scratch1 = 1;
368023ccc1eSegillett 
369a195726fSgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
3707c478bd9Sstevel@tonic-gate 	    DDI_INTROP_FREE, hdlp, NULL);
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
3737c478bd9Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
37420036fe5Segillett 		/* This would be the dup vector */
37520036fe5Segillett 		if (hdlp->ih_flags & DDI_INTR_MSIX_DUP)
37620036fe5Segillett 			atomic_dec_32(&hdlp->ih_main->ih_dup_cnt);
37720036fe5Segillett 		else {
378a120541cSScott M. Carter 			int	n, curr_type;
379a120541cSScott M. Carter 
380a120541cSScott M. Carter 			n = i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1;
381a120541cSScott M. Carter 			curr_type = i_ddi_intr_get_current_type(hdlp->ih_dip);
382a120541cSScott M. Carter 
383a120541cSScott M. Carter 			i_ddi_intr_set_current_nintrs(hdlp->ih_dip, n);
384a120541cSScott M. Carter 
385a120541cSScott M. Carter 			if ((i_ddi_irm_supported(hdlp->ih_dip, curr_type)
386a120541cSScott M. Carter 			    != DDI_SUCCESS) && (n > 0))
387a120541cSScott M. Carter 				(void) i_ddi_irm_modify(hdlp->ih_dip, n);
38820036fe5Segillett 
389023ccc1eSegillett 			if (hdlp->ih_type & DDI_INTR_TYPE_FIXED)
390023ccc1eSegillett 				i_ddi_set_intr_handle(hdlp->ih_dip,
391023ccc1eSegillett 				    hdlp->ih_inum, NULL);
39220036fe5Segillett 
393023ccc1eSegillett 			i_ddi_intr_devi_fini(hdlp->ih_dip);
39420036fe5Segillett 			i_ddi_free_intr_phdl(hdlp);
395a195726fSgovinda 		}
3967c478bd9Sstevel@tonic-gate 		rw_destroy(&hdlp->ih_rwlock);
3977c478bd9Sstevel@tonic-gate 		kmem_free(hdlp, sizeof (ddi_intr_handle_impl_t));
3987c478bd9Sstevel@tonic-gate 	}
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	return (ret);
4017c478bd9Sstevel@tonic-gate }
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate /*
4047c478bd9Sstevel@tonic-gate  * Interrupt get/set capacity functions
4057c478bd9Sstevel@tonic-gate  *
4067c478bd9Sstevel@tonic-gate  * The logic used to figure this out is shown here:
4077c478bd9Sstevel@tonic-gate  *
4087c478bd9Sstevel@tonic-gate  *			Device level		Platform level	    Intr source
4097c478bd9Sstevel@tonic-gate  * 1. Fixed interrupts
4107c478bd9Sstevel@tonic-gate  * (non-PCI)
4117c478bd9Sstevel@tonic-gate  * o Flags supported	N/A			Maskable/Pending/    rootnex
4127c478bd9Sstevel@tonic-gate  *						No Block Enable
4137c478bd9Sstevel@tonic-gate  * o navail					1
4147c478bd9Sstevel@tonic-gate  *
4157c478bd9Sstevel@tonic-gate  * 2. PCI Fixed interrupts
4167c478bd9Sstevel@tonic-gate  * o Flags supported	pending/Maskable	Maskable/pending/    pci
4177c478bd9Sstevel@tonic-gate  *						No Block enable
4187c478bd9Sstevel@tonic-gate  * o navail		N/A			1
4197c478bd9Sstevel@tonic-gate  *
4207c478bd9Sstevel@tonic-gate  * 3. PCI MSI
4217c478bd9Sstevel@tonic-gate  * o Flags supported	Maskable/Pending	Maskable/Pending    pci
4227c478bd9Sstevel@tonic-gate  *			Block Enable		(if drvr doesn't)   Block Enable
4237c478bd9Sstevel@tonic-gate  * o navail		N/A			#vectors - #used    N/A
4247c478bd9Sstevel@tonic-gate  *
4257c478bd9Sstevel@tonic-gate  * 4. PCI MSI-X
4267c478bd9Sstevel@tonic-gate  * o Flags supported	Maskable/Pending	Maskable/Pending    pci
4277c478bd9Sstevel@tonic-gate  *			Block Enable				    Block Enable
4287c478bd9Sstevel@tonic-gate  * o navail		N/A			#vectors - #used    N/A
4297c478bd9Sstevel@tonic-gate  *
4307c478bd9Sstevel@tonic-gate  * where:
4317c478bd9Sstevel@tonic-gate  *	#vectors	- Total numbers of vectors available
4327c478bd9Sstevel@tonic-gate  *	#used		- Total numbers of vectors currently being used
4337c478bd9Sstevel@tonic-gate  *
4347c478bd9Sstevel@tonic-gate  * For devices complying to PCI2.3 or greater, see bit10 of Command Register
4357c478bd9Sstevel@tonic-gate  * 0 - enables assertion of INTx
4367c478bd9Sstevel@tonic-gate  * 1 - disables assertion of INTx
4377c478bd9Sstevel@tonic-gate  *
4387c478bd9Sstevel@tonic-gate  * For non MSI/X interrupts; if the IRQ is shared then all ddi_intr_set_*()
4397c478bd9Sstevel@tonic-gate  * operations return failure.
4407c478bd9Sstevel@tonic-gate  */
4417c478bd9Sstevel@tonic-gate int
ddi_intr_get_cap(ddi_intr_handle_t h,int * flagsp)4427c478bd9Sstevel@tonic-gate ddi_intr_get_cap(ddi_intr_handle_t h, int *flagsp)
4437c478bd9Sstevel@tonic-gate {
4447c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
4457c478bd9Sstevel@tonic-gate 	int			ret;
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_cap: hdlp = %p\n",
4487c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	*flagsp = 0;
4517c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
4527c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	if (hdlp->ih_cap) {
4577c478bd9Sstevel@tonic-gate 		*flagsp = hdlp->ih_cap & ~DDI_INTR_FLAG_MSI64;
4587c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
4597c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
4607c478bd9Sstevel@tonic-gate 	}
4617c478bd9Sstevel@tonic-gate 
462a195726fSgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
4637c478bd9Sstevel@tonic-gate 	    DDI_INTROP_GETCAP, hdlp, (void *)flagsp);
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
4667c478bd9Sstevel@tonic-gate 		hdlp->ih_cap = *flagsp;
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 		/* Mask out MSI/X 64-bit support to the consumer */
4697c478bd9Sstevel@tonic-gate 		*flagsp &= ~DDI_INTR_FLAG_MSI64;
4707c478bd9Sstevel@tonic-gate 	}
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
4737c478bd9Sstevel@tonic-gate 	return (ret);
4747c478bd9Sstevel@tonic-gate }
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate int
ddi_intr_set_cap(ddi_intr_handle_t h,int flags)4777c478bd9Sstevel@tonic-gate ddi_intr_set_cap(ddi_intr_handle_t h, int flags)
4787c478bd9Sstevel@tonic-gate {
4797c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
4807c478bd9Sstevel@tonic-gate 	int			ret;
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_cap: hdlp = %p", (void *)hdlp));
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
4857c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
4887c478bd9Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
4897c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
4907c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
4917c478bd9Sstevel@tonic-gate 	}
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	/* Only DDI_INTR_FLAG_LEVEL or DDI_INTR_FLAG_EDGE are allowed */
4947c478bd9Sstevel@tonic-gate 	if (!(flags & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) {
4957c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "%s%d: only LEVEL or EDGE capability "
4967c478bd9Sstevel@tonic-gate 		    "can be set\n", ddi_driver_name(hdlp->ih_dip),
4977c478bd9Sstevel@tonic-gate 		    ddi_get_instance(hdlp->ih_dip)));
4987c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
4997c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	/* Both level/edge flags must be currently supported */
5037c478bd9Sstevel@tonic-gate 	if (!(hdlp->ih_cap & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) {
5047c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "%s%d: Both LEVEL and EDGE capability"
5057c478bd9Sstevel@tonic-gate 		    " must be supported\n", ddi_driver_name(hdlp->ih_dip),
5067c478bd9Sstevel@tonic-gate 		    ddi_get_instance(hdlp->ih_dip)));
5077c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
5087c478bd9Sstevel@tonic-gate 		return (DDI_ENOTSUP);
5097c478bd9Sstevel@tonic-gate 	}
5107c478bd9Sstevel@tonic-gate 
511a195726fSgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
5127c478bd9Sstevel@tonic-gate 	    DDI_INTROP_SETCAP, hdlp, &flags);
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
5157c478bd9Sstevel@tonic-gate 	return (ret);
5167c478bd9Sstevel@tonic-gate }
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate /*
5197c478bd9Sstevel@tonic-gate  * Priority related functions
5207c478bd9Sstevel@tonic-gate  */
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate /*
5237c478bd9Sstevel@tonic-gate  * ddi_intr_get_hilevel_pri:
5247c478bd9Sstevel@tonic-gate  *	Returns the minimum priority level for a
5257c478bd9Sstevel@tonic-gate  *	high-level interrupt on a platform.
5267c478bd9Sstevel@tonic-gate  */
5277c478bd9Sstevel@tonic-gate uint_t
ddi_intr_get_hilevel_pri(void)5287c478bd9Sstevel@tonic-gate ddi_intr_get_hilevel_pri(void)
5297c478bd9Sstevel@tonic-gate {
5307c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_hilevel_pri:\n"));
5317c478bd9Sstevel@tonic-gate 	return (LOCK_LEVEL + 1);
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate int
ddi_intr_get_pri(ddi_intr_handle_t h,uint_t * prip)5357c478bd9Sstevel@tonic-gate ddi_intr_get_pri(ddi_intr_handle_t h, uint_t *prip)
5367c478bd9Sstevel@tonic-gate {
5377c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
5387c478bd9Sstevel@tonic-gate 	int			ret;
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pri: hdlp = %p\n",
5417c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	*prip = 0;
5447c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
5457c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
5487c478bd9Sstevel@tonic-gate 	/* Already initialized, just return that */
5497c478bd9Sstevel@tonic-gate 	if (hdlp->ih_pri) {
5507c478bd9Sstevel@tonic-gate 		*prip = hdlp->ih_pri;
5517c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
5527c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
5537c478bd9Sstevel@tonic-gate 	}
5547c478bd9Sstevel@tonic-gate 
555a195726fSgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
5567c478bd9Sstevel@tonic-gate 	    DDI_INTROP_GETPRI, hdlp, (void *)prip);
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	if (ret == DDI_SUCCESS)
5597c478bd9Sstevel@tonic-gate 		hdlp->ih_pri = *prip;
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
5627c478bd9Sstevel@tonic-gate 	return (ret);
5637c478bd9Sstevel@tonic-gate }
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate int
ddi_intr_set_pri(ddi_intr_handle_t h,uint_t pri)5667c478bd9Sstevel@tonic-gate ddi_intr_set_pri(ddi_intr_handle_t h, uint_t pri)
5677c478bd9Sstevel@tonic-gate {
5687c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
5697c478bd9Sstevel@tonic-gate 	int			ret;
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: hdlp = %p", (void *)hdlp));
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
5747c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	/* Validate priority argument */
5777c478bd9Sstevel@tonic-gate 	if (pri < DDI_INTR_PRI_MIN || pri > DDI_INTR_PRI_MAX) {
5787c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: invalid priority "
5797c478bd9Sstevel@tonic-gate 		    "specified  = %x\n", pri));
5807c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
5817c478bd9Sstevel@tonic-gate 	}
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
5847c478bd9Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
5857c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
5867c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
5877c478bd9Sstevel@tonic-gate 	}
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	/* If the passed priority is same as existing priority; do nothing */
5907c478bd9Sstevel@tonic-gate 	if (pri == hdlp->ih_pri) {
5917c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
5927c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
5937c478bd9Sstevel@tonic-gate 	}
5947c478bd9Sstevel@tonic-gate 
595a195726fSgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
5967c478bd9Sstevel@tonic-gate 	    DDI_INTROP_SETPRI, hdlp, &pri);
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 	if (ret == DDI_SUCCESS)
5997c478bd9Sstevel@tonic-gate 		hdlp->ih_pri = pri;
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
6027c478bd9Sstevel@tonic-gate 	return (ret);
6037c478bd9Sstevel@tonic-gate }
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate /*
6067c478bd9Sstevel@tonic-gate  * Interrupt add/duplicate/remove handlers
6077c478bd9Sstevel@tonic-gate  */
6087c478bd9Sstevel@tonic-gate int
ddi_intr_add_handler(ddi_intr_handle_t h,ddi_intr_handler_t inthandler,void * arg1,void * arg2)6097c478bd9Sstevel@tonic-gate ddi_intr_add_handler(ddi_intr_handle_t h, ddi_intr_handler_t inthandler,
6107c478bd9Sstevel@tonic-gate     void *arg1, void *arg2)
6117c478bd9Sstevel@tonic-gate {
6127c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
6137c478bd9Sstevel@tonic-gate 	int			ret;
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_handler: hdlp = 0x%p\n",
6167c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	if ((hdlp == NULL) || (inthandler == NULL))
6197c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
6227c478bd9Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
6237c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
6247c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
6257c478bd9Sstevel@tonic-gate 	}
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	hdlp->ih_cb_func = inthandler;
6287c478bd9Sstevel@tonic-gate 	hdlp->ih_cb_arg1 = arg1;
6297c478bd9Sstevel@tonic-gate 	hdlp->ih_cb_arg2 = arg2;
6307c478bd9Sstevel@tonic-gate 
631a195726fSgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
6327c478bd9Sstevel@tonic-gate 	    DDI_INTROP_ADDISR, hdlp, NULL);
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
6357c478bd9Sstevel@tonic-gate 		hdlp->ih_cb_func = NULL;
6367c478bd9Sstevel@tonic-gate 		hdlp->ih_cb_arg1 = NULL;
6377c478bd9Sstevel@tonic-gate 		hdlp->ih_cb_arg2 = NULL;
6387c478bd9Sstevel@tonic-gate 	} else
6397c478bd9Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ADDED;
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
6427c478bd9Sstevel@tonic-gate 	return (ret);
6437c478bd9Sstevel@tonic-gate }
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate int
ddi_intr_dup_handler(ddi_intr_handle_t org,int dup_inum,ddi_intr_handle_t * dup)64620036fe5Segillett ddi_intr_dup_handler(ddi_intr_handle_t org, int dup_inum,
64720036fe5Segillett     ddi_intr_handle_t *dup)
6487c478bd9Sstevel@tonic-gate {
6497c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)org;
6507c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*dup_hdlp;
6517c478bd9Sstevel@tonic-gate 	int			ret;
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_dup_handler: hdlp = 0x%p\n",
6547c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
6557c478bd9Sstevel@tonic-gate 
65620036fe5Segillett 	/* Do some input argument checking ("dup" handle is not allocated) */
657d626b9f5Sanish 	if ((hdlp == NULL) || (*dup != NULL) || (dup_inum < 0)) {
658d626b9f5Sanish 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_dup_handler: Invalid "
659d626b9f5Sanish 		    "input args\n"));
6607c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
661d626b9f5Sanish 	}
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	/* Do some input argument checking */
6667c478bd9Sstevel@tonic-gate 	if ((hdlp->ih_state == DDI_IHDL_STATE_ALLOC) ||	/* intr handle alloc? */
66720036fe5Segillett 	    (hdlp->ih_type != DDI_INTR_TYPE_MSIX) ||	/* only MSI-X allowed */
66820036fe5Segillett 	    (hdlp->ih_flags & DDI_INTR_MSIX_DUP)) {	/* only dup original */
6697c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
6707c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
6717c478bd9Sstevel@tonic-gate 	}
6727c478bd9Sstevel@tonic-gate 
67320036fe5Segillett 	hdlp->ih_scratch1 = dup_inum;
674a195726fSgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
67520036fe5Segillett 	    DDI_INTROP_DUPVEC, hdlp, NULL);
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
6787c478bd9Sstevel@tonic-gate 		dup_hdlp = (ddi_intr_handle_impl_t *)
67920036fe5Segillett 		    kmem_alloc(sizeof (ddi_intr_handle_impl_t), KM_SLEEP);
6807c478bd9Sstevel@tonic-gate 
6811a5e258fSJosef 'Jeff' Sipek 		atomic_inc_32(&hdlp->ih_dup_cnt);
68220036fe5Segillett 
68320036fe5Segillett 		*dup = (ddi_intr_handle_t)dup_hdlp;
68420036fe5Segillett 		bcopy(hdlp, dup_hdlp, sizeof (ddi_intr_handle_impl_t));
68520036fe5Segillett 
68620036fe5Segillett 		/* These fields are unique to each dupped msi-x vector */
6877c478bd9Sstevel@tonic-gate 		rw_init(&dup_hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
6887c478bd9Sstevel@tonic-gate 		dup_hdlp->ih_state = DDI_IHDL_STATE_ADDED;
68920036fe5Segillett 		dup_hdlp->ih_inum = dup_inum;
69020036fe5Segillett 		dup_hdlp->ih_flags |= DDI_INTR_MSIX_DUP;
69120036fe5Segillett 		dup_hdlp->ih_dup_cnt = 0;
6927c478bd9Sstevel@tonic-gate 
69320036fe5Segillett 		/* Point back to original vector */
69420036fe5Segillett 		dup_hdlp->ih_main = hdlp;
6957c478bd9Sstevel@tonic-gate 	}
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
6987c478bd9Sstevel@tonic-gate 	return (ret);
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate int
ddi_intr_remove_handler(ddi_intr_handle_t h)7027c478bd9Sstevel@tonic-gate ddi_intr_remove_handler(ddi_intr_handle_t h)
7037c478bd9Sstevel@tonic-gate {
7047c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
70520036fe5Segillett 	int			ret = DDI_SUCCESS;
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_handler: hdlp = %p\n",
7087c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
7117c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
71420036fe5Segillett 
7157c478bd9Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ADDED) {
71620036fe5Segillett 		ret = DDI_EINVAL;
71720036fe5Segillett 		goto done;
71820036fe5Segillett 	} else if (hdlp->ih_flags & DDI_INTR_MSIX_DUP)
71920036fe5Segillett 		goto done;
72020036fe5Segillett 
72120036fe5Segillett 	ASSERT(hdlp->ih_dup_cnt == 0);
72220036fe5Segillett 	if (hdlp->ih_dup_cnt > 0) {
72320036fe5Segillett 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_handler: MSI-X "
72420036fe5Segillett 		    "dup_cnt %d is not 0\n", hdlp->ih_dup_cnt));
72520036fe5Segillett 		ret = DDI_FAILURE;
72620036fe5Segillett 		goto done;
7277c478bd9Sstevel@tonic-gate 	}
7287c478bd9Sstevel@tonic-gate 
729a195726fSgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
7307c478bd9Sstevel@tonic-gate 	    DDI_INTROP_REMISR, hdlp, NULL);
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
7337c478bd9Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ALLOC;
7347c478bd9Sstevel@tonic-gate 		hdlp->ih_cb_func = NULL;
7357c478bd9Sstevel@tonic-gate 		hdlp->ih_cb_arg1 = NULL;
7367c478bd9Sstevel@tonic-gate 		hdlp->ih_cb_arg2 = NULL;
7377c478bd9Sstevel@tonic-gate 	}
7387c478bd9Sstevel@tonic-gate 
73920036fe5Segillett done:
7407c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
7417c478bd9Sstevel@tonic-gate 	return (ret);
7427c478bd9Sstevel@tonic-gate }
7437c478bd9Sstevel@tonic-gate 
74409b1eac2SEvan Yan 
7457c478bd9Sstevel@tonic-gate /*
7467c478bd9Sstevel@tonic-gate  * Interrupt enable/disable/block_enable/block_disable handlers
7477c478bd9Sstevel@tonic-gate  */
7487c478bd9Sstevel@tonic-gate int
ddi_intr_enable(ddi_intr_handle_t h)7497c478bd9Sstevel@tonic-gate ddi_intr_enable(ddi_intr_handle_t h)
7507c478bd9Sstevel@tonic-gate {
7517c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
7527c478bd9Sstevel@tonic-gate 	int			ret;
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_enable: hdlp = %p\n",
7557c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
7587c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
7617c478bd9Sstevel@tonic-gate 	if ((hdlp->ih_state != DDI_IHDL_STATE_ADDED) ||
7627c478bd9Sstevel@tonic-gate 	    ((hdlp->ih_type == DDI_INTR_TYPE_MSI) &&
7637c478bd9Sstevel@tonic-gate 	    (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) {
7647c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
7657c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
7667c478bd9Sstevel@tonic-gate 	}
7677c478bd9Sstevel@tonic-gate 
76820036fe5Segillett 	I_DDI_VERIFY_MSIX_HANDLE(hdlp);
76920036fe5Segillett 
770a195726fSgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
7717c478bd9Sstevel@tonic-gate 	    DDI_INTROP_ENABLE, hdlp, NULL);
7727c478bd9Sstevel@tonic-gate 
7732145b8d4SGuoli Shu 	if (ret == DDI_SUCCESS) {
7747c478bd9Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ENABLE;
7752145b8d4SGuoli Shu 		i_ddi_intr_set_current_nenables(hdlp->ih_dip,
7762145b8d4SGuoli Shu 		    i_ddi_intr_get_current_nenables(hdlp->ih_dip) + 1);
7772145b8d4SGuoli Shu 	}
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
7807c478bd9Sstevel@tonic-gate 	return (ret);
7817c478bd9Sstevel@tonic-gate }
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate int
ddi_intr_disable(ddi_intr_handle_t h)7847c478bd9Sstevel@tonic-gate ddi_intr_disable(ddi_intr_handle_t h)
7857c478bd9Sstevel@tonic-gate {
7867c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
7877c478bd9Sstevel@tonic-gate 	int			ret;
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_disable: hdlp = %p\n",
7907c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
7937c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
7967c478bd9Sstevel@tonic-gate 	if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
7977c478bd9Sstevel@tonic-gate 	    ((hdlp->ih_type == DDI_INTR_TYPE_MSI) &&
7987c478bd9Sstevel@tonic-gate 	    (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) {
7997c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
8007c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
8017c478bd9Sstevel@tonic-gate 	}
8027c478bd9Sstevel@tonic-gate 
80320036fe5Segillett 	I_DDI_VERIFY_MSIX_HANDLE(hdlp);
80420036fe5Segillett 
805a195726fSgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
8067c478bd9Sstevel@tonic-gate 	    DDI_INTROP_DISABLE, hdlp, NULL);
8077c478bd9Sstevel@tonic-gate 
8082145b8d4SGuoli Shu 	if (ret == DDI_SUCCESS) {
8097c478bd9Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ADDED;
8102145b8d4SGuoli Shu 		i_ddi_intr_set_current_nenables(hdlp->ih_dip,
8112145b8d4SGuoli Shu 		    i_ddi_intr_get_current_nenables(hdlp->ih_dip) - 1);
8122145b8d4SGuoli Shu 	}
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
8157c478bd9Sstevel@tonic-gate 	return (ret);
8167c478bd9Sstevel@tonic-gate }
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate int
ddi_intr_block_enable(ddi_intr_handle_t * h_array,int count)8197c478bd9Sstevel@tonic-gate ddi_intr_block_enable(ddi_intr_handle_t *h_array, int count)
8207c478bd9Sstevel@tonic-gate {
8217c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp;
8227c478bd9Sstevel@tonic-gate 	int			i, ret;
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_enable: h_array = %p\n",
8257c478bd9Sstevel@tonic-gate 	    (void *)h_array));
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	if (h_array == NULL)
8287c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
8317c478bd9Sstevel@tonic-gate 		hdlp = (ddi_intr_handle_impl_t *)h_array[i];
8327c478bd9Sstevel@tonic-gate 		rw_enter(&hdlp->ih_rwlock, RW_READER);
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 		if (hdlp->ih_state != DDI_IHDL_STATE_ADDED ||
8357c478bd9Sstevel@tonic-gate 		    hdlp->ih_type != DDI_INTR_TYPE_MSI ||
8367c478bd9Sstevel@tonic-gate 		    !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) {
8377c478bd9Sstevel@tonic-gate 			rw_exit(&hdlp->ih_rwlock);
8387c478bd9Sstevel@tonic-gate 			return (DDI_EINVAL);
8397c478bd9Sstevel@tonic-gate 		}
8407c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
8417c478bd9Sstevel@tonic-gate 	}
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 	hdlp = (ddi_intr_handle_impl_t *)h_array[0];
8447c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
8457c478bd9Sstevel@tonic-gate 	hdlp->ih_scratch1 = count;
846102cb92eSjohnny 	hdlp->ih_scratch2 = (void *)h_array;
8477c478bd9Sstevel@tonic-gate 
848a195726fSgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
8497c478bd9Sstevel@tonic-gate 	    DDI_INTROP_BLOCKENABLE, hdlp, NULL);
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
8547c478bd9Sstevel@tonic-gate 		for (i = 0; i < count; i++) {
8557c478bd9Sstevel@tonic-gate 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
8567c478bd9Sstevel@tonic-gate 			rw_enter(&hdlp->ih_rwlock, RW_WRITER);
8577c478bd9Sstevel@tonic-gate 			hdlp->ih_state = DDI_IHDL_STATE_ENABLE;
8587c478bd9Sstevel@tonic-gate 			rw_exit(&hdlp->ih_rwlock);
8597c478bd9Sstevel@tonic-gate 		}
8602145b8d4SGuoli Shu 		i_ddi_intr_set_current_nenables(hdlp->ih_dip, 1);
8617c478bd9Sstevel@tonic-gate 	}
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 	return (ret);
8647c478bd9Sstevel@tonic-gate }
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate int
ddi_intr_block_disable(ddi_intr_handle_t * h_array,int count)8677c478bd9Sstevel@tonic-gate ddi_intr_block_disable(ddi_intr_handle_t *h_array, int count)
8687c478bd9Sstevel@tonic-gate {
8697c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp;
8707c478bd9Sstevel@tonic-gate 	int			i, ret;
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_disable: h_array = %p\n",
8737c478bd9Sstevel@tonic-gate 	    (void *)h_array));
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	if (h_array == NULL)
8767c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
8797c478bd9Sstevel@tonic-gate 		hdlp = (ddi_intr_handle_impl_t *)h_array[i];
8807c478bd9Sstevel@tonic-gate 		rw_enter(&hdlp->ih_rwlock, RW_READER);
8817c478bd9Sstevel@tonic-gate 		if (hdlp->ih_state != DDI_IHDL_STATE_ENABLE ||
8827c478bd9Sstevel@tonic-gate 		    hdlp->ih_type != DDI_INTR_TYPE_MSI ||
8837c478bd9Sstevel@tonic-gate 		    !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) {
8847c478bd9Sstevel@tonic-gate 			rw_exit(&hdlp->ih_rwlock);
8857c478bd9Sstevel@tonic-gate 			return (DDI_EINVAL);
8867c478bd9Sstevel@tonic-gate 		}
8877c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
8887c478bd9Sstevel@tonic-gate 	}
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 	hdlp = (ddi_intr_handle_impl_t *)h_array[0];
8917c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
8927c478bd9Sstevel@tonic-gate 	hdlp->ih_scratch1 = count;
893102cb92eSjohnny 	hdlp->ih_scratch2 = (void *)h_array;
8947c478bd9Sstevel@tonic-gate 
895a195726fSgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
8967c478bd9Sstevel@tonic-gate 	    DDI_INTROP_BLOCKDISABLE, hdlp, NULL);
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
9017c478bd9Sstevel@tonic-gate 		for (i = 0; i < count; i++) {
9027c478bd9Sstevel@tonic-gate 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
9037c478bd9Sstevel@tonic-gate 			rw_enter(&hdlp->ih_rwlock, RW_WRITER);
9047c478bd9Sstevel@tonic-gate 			hdlp->ih_state = DDI_IHDL_STATE_ADDED;
9057c478bd9Sstevel@tonic-gate 			rw_exit(&hdlp->ih_rwlock);
9067c478bd9Sstevel@tonic-gate 		}
9072145b8d4SGuoli Shu 		i_ddi_intr_set_current_nenables(hdlp->ih_dip, 0);
9087c478bd9Sstevel@tonic-gate 	}
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	return (ret);
9117c478bd9Sstevel@tonic-gate }
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate /*
9147c478bd9Sstevel@tonic-gate  * Interrupt set/clr mask handlers
9157c478bd9Sstevel@tonic-gate  */
9167c478bd9Sstevel@tonic-gate int
ddi_intr_set_mask(ddi_intr_handle_t h)9177c478bd9Sstevel@tonic-gate ddi_intr_set_mask(ddi_intr_handle_t h)
9187c478bd9Sstevel@tonic-gate {
9197c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
9207c478bd9Sstevel@tonic-gate 	int			ret;
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_mask: hdlp = %p\n",
9237c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
9267c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
92907f14c08Sgovinda 	if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
93007f14c08Sgovinda 	    (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE))) {
9317c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
9327c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
9337c478bd9Sstevel@tonic-gate 	}
9347c478bd9Sstevel@tonic-gate 
935a195726fSgovinda 	ret =  i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
9367c478bd9Sstevel@tonic-gate 	    DDI_INTROP_SETMASK, hdlp, NULL);
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
9397c478bd9Sstevel@tonic-gate 	return (ret);
9407c478bd9Sstevel@tonic-gate }
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate int
ddi_intr_clr_mask(ddi_intr_handle_t h)9437c478bd9Sstevel@tonic-gate ddi_intr_clr_mask(ddi_intr_handle_t h)
9447c478bd9Sstevel@tonic-gate {
9457c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
9467c478bd9Sstevel@tonic-gate 	int			ret;
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_clr_mask: hdlp = %p\n",
9497c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
9527c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
95507f14c08Sgovinda 	if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
95607f14c08Sgovinda 	    (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE))) {
9577c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
9587c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
9597c478bd9Sstevel@tonic-gate 	}
9607c478bd9Sstevel@tonic-gate 
961a195726fSgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
9627c478bd9Sstevel@tonic-gate 	    DDI_INTROP_CLRMASK, hdlp, NULL);
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
9657c478bd9Sstevel@tonic-gate 	return (ret);
9667c478bd9Sstevel@tonic-gate }
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate /*
9697c478bd9Sstevel@tonic-gate  * Interrupt get_pending handler
9707c478bd9Sstevel@tonic-gate  */
9717c478bd9Sstevel@tonic-gate int
ddi_intr_get_pending(ddi_intr_handle_t h,int * pendingp)9727c478bd9Sstevel@tonic-gate ddi_intr_get_pending(ddi_intr_handle_t h, int *pendingp)
9737c478bd9Sstevel@tonic-gate {
9747c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
9757c478bd9Sstevel@tonic-gate 	int			ret;
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pending: hdlp = %p\n",
9787c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
9817c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
9847c478bd9Sstevel@tonic-gate 	if (!(hdlp->ih_cap & DDI_INTR_FLAG_PENDING)) {
9857c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
9867c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
9877c478bd9Sstevel@tonic-gate 	}
9887c478bd9Sstevel@tonic-gate 
989a195726fSgovinda 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
9907c478bd9Sstevel@tonic-gate 	    DDI_INTROP_GETPENDING, hdlp, (void *)pendingp);
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
9937c478bd9Sstevel@tonic-gate 	return (ret);
9947c478bd9Sstevel@tonic-gate }
9957c478bd9Sstevel@tonic-gate 
99609b1eac2SEvan Yan /*
99709b1eac2SEvan Yan  * Set the number of interrupts requested from IRM
99809b1eac2SEvan Yan  */
99909b1eac2SEvan Yan int
ddi_intr_set_nreq(dev_info_t * dip,int nreq)100009b1eac2SEvan Yan ddi_intr_set_nreq(dev_info_t *dip, int nreq)
100109b1eac2SEvan Yan {
1002a120541cSScott M. Carter 	int	curr_type, nintrs;
1003a120541cSScott M. Carter 
100409b1eac2SEvan Yan 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_nreq: dip %p, nreq %d\n",
100509b1eac2SEvan Yan 	    (void *)dip, nreq));
100609b1eac2SEvan Yan 
1007a120541cSScott M. Carter 	ASSERT(dip != NULL);
1008a120541cSScott M. Carter 	ASSERT(nreq > 0);
1009a120541cSScott M. Carter 
1010a120541cSScott M. Carter 	/* Sanity check inputs */
1011a120541cSScott M. Carter 	if ((dip == NULL) || (nreq < 1))
1012a120541cSScott M. Carter 		return (DDI_EINVAL);
1013a120541cSScott M. Carter 
1014a120541cSScott M. Carter 	curr_type = i_ddi_intr_get_current_type(dip);
1015a120541cSScott M. Carter 
1016a120541cSScott M. Carter 	/* Only valid for IRM drivers actively using interrupts */
1017a120541cSScott M. Carter 	if ((curr_type == 0) ||
1018a120541cSScott M. Carter 	    (i_ddi_irm_supported(dip, curr_type) != DDI_SUCCESS))
1019a120541cSScott M. Carter 		return (DDI_ENOTSUP);
1020a120541cSScott M. Carter 
1021a120541cSScott M. Carter 	/* Range check */
1022a120541cSScott M. Carter 	if (ddi_intr_get_nintrs(dip, curr_type, &nintrs) != DDI_SUCCESS)
1023a120541cSScott M. Carter 		return (DDI_FAILURE);
1024a120541cSScott M. Carter 	if (nreq > nintrs)
102509b1eac2SEvan Yan 		return (DDI_EINVAL);
102609b1eac2SEvan Yan 
102709b1eac2SEvan Yan 	return (i_ddi_irm_modify(dip, nreq));
102809b1eac2SEvan Yan }
102909b1eac2SEvan Yan 
10307c478bd9Sstevel@tonic-gate /*
10317c478bd9Sstevel@tonic-gate  * Soft interrupt handlers
10327c478bd9Sstevel@tonic-gate  */
10337c478bd9Sstevel@tonic-gate /*
10347c478bd9Sstevel@tonic-gate  * Add a soft interrupt and register its handler
10357c478bd9Sstevel@tonic-gate  */
10367c478bd9Sstevel@tonic-gate /* ARGSUSED */
10377c478bd9Sstevel@tonic-gate int
ddi_intr_add_softint(dev_info_t * dip,ddi_softint_handle_t * h_p,int soft_pri,ddi_intr_handler_t handler,void * arg1)10387c478bd9Sstevel@tonic-gate ddi_intr_add_softint(dev_info_t *dip, ddi_softint_handle_t *h_p, int soft_pri,
10397c478bd9Sstevel@tonic-gate     ddi_intr_handler_t handler, void *arg1)
10407c478bd9Sstevel@tonic-gate {
10417c478bd9Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp;
10427c478bd9Sstevel@tonic-gate 	int			ret;
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: dip = %p, "
10457c478bd9Sstevel@tonic-gate 	    "softpri = 0x%x\n", (void *)dip, soft_pri));
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (h_p == NULL) || (handler == NULL)) {
10487c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: "
10497c478bd9Sstevel@tonic-gate 		    "invalid arguments"));
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
10527c478bd9Sstevel@tonic-gate 	}
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	/* Validate input arguments */
10557c478bd9Sstevel@tonic-gate 	if (soft_pri < DDI_INTR_SOFTPRI_MIN ||
10567c478bd9Sstevel@tonic-gate 	    soft_pri > DDI_INTR_SOFTPRI_MAX) {
10577c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: invalid "
10587c478bd9Sstevel@tonic-gate 		    "soft_pri input given  = %x\n", soft_pri));
10597c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
10607c478bd9Sstevel@tonic-gate 	}
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	hdlp = (ddi_softint_hdl_impl_t *)kmem_zalloc(
10637c478bd9Sstevel@tonic-gate 	    sizeof (ddi_softint_hdl_impl_t), KM_SLEEP);
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate 	/* fill up internally */
10667c478bd9Sstevel@tonic-gate 	rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
10677c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
10687c478bd9Sstevel@tonic-gate 	hdlp->ih_pri = soft_pri;
10697c478bd9Sstevel@tonic-gate 	hdlp->ih_dip = dip;
10707c478bd9Sstevel@tonic-gate 	hdlp->ih_cb_func = handler;
10717c478bd9Sstevel@tonic-gate 	hdlp->ih_cb_arg1 = arg1;
10727c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: hdlp = %p\n",
10737c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	/* do the platform specific calls */
10767c478bd9Sstevel@tonic-gate 	if ((ret = i_ddi_add_softint(hdlp)) != DDI_SUCCESS) {
10777c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
10787c478bd9Sstevel@tonic-gate 		rw_destroy(&hdlp->ih_rwlock);
10797c478bd9Sstevel@tonic-gate 		kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t));
10807c478bd9Sstevel@tonic-gate 		return (ret);
10817c478bd9Sstevel@tonic-gate 	}
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	*h_p = (ddi_softint_handle_t)hdlp;
10847c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
10857c478bd9Sstevel@tonic-gate 	return (ret);
10867c478bd9Sstevel@tonic-gate }
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate /*
10897c478bd9Sstevel@tonic-gate  * Remove the soft interrupt
10907c478bd9Sstevel@tonic-gate  */
10917c478bd9Sstevel@tonic-gate int
ddi_intr_remove_softint(ddi_softint_handle_t h)10927c478bd9Sstevel@tonic-gate ddi_intr_remove_softint(ddi_softint_handle_t h)
10937c478bd9Sstevel@tonic-gate {
10947c478bd9Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp = (ddi_softint_hdl_impl_t *)h;
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_softint: hdlp = %p\n",
10977c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
11007c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
11037c478bd9Sstevel@tonic-gate 	i_ddi_remove_softint(hdlp);
11047c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
11057c478bd9Sstevel@tonic-gate 	rw_destroy(&hdlp->ih_rwlock);
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 	/* kmem_free the hdl impl_t structure allocated earlier */
11087c478bd9Sstevel@tonic-gate 	kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t));
11097c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
11107c478bd9Sstevel@tonic-gate }
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate /*
11137c478bd9Sstevel@tonic-gate  * Trigger a soft interrupt
11147c478bd9Sstevel@tonic-gate  */
11157c478bd9Sstevel@tonic-gate int
ddi_intr_trigger_softint(ddi_softint_handle_t h,void * arg2)11167c478bd9Sstevel@tonic-gate ddi_intr_trigger_softint(ddi_softint_handle_t h, void *arg2)
11177c478bd9Sstevel@tonic-gate {
11187c478bd9Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp = (ddi_softint_hdl_impl_t *)h;
11197c478bd9Sstevel@tonic-gate 	int			ret;
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
11227c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
11237c478bd9Sstevel@tonic-gate 
1124b08160e2Sgovinda 	if ((ret = i_ddi_trigger_softint(hdlp, arg2)) != DDI_SUCCESS) {
11257c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_trigger_softint: failed, "
11267c478bd9Sstevel@tonic-gate 		    " ret 0%x\n", ret));
1127b08160e2Sgovinda 
1128b08160e2Sgovinda 		return (ret);
11297c478bd9Sstevel@tonic-gate 	}
11307c478bd9Sstevel@tonic-gate 
1131b08160e2Sgovinda 	hdlp->ih_cb_arg2 = arg2;
1132b08160e2Sgovinda 	return (DDI_SUCCESS);
11337c478bd9Sstevel@tonic-gate }
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate /*
11367c478bd9Sstevel@tonic-gate  * Get the soft interrupt priority
11377c478bd9Sstevel@tonic-gate  */
11387c478bd9Sstevel@tonic-gate int
ddi_intr_get_softint_pri(ddi_softint_handle_t h,uint_t * soft_prip)11397c478bd9Sstevel@tonic-gate ddi_intr_get_softint_pri(ddi_softint_handle_t h, uint_t *soft_prip)
11407c478bd9Sstevel@tonic-gate {
11417c478bd9Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp = (ddi_softint_hdl_impl_t *)h;
11427c478bd9Sstevel@tonic-gate 
11437c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_softint_pri: h = %p\n",
11447c478bd9Sstevel@tonic-gate 	    (void *)h));
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
11477c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
11487c478bd9Sstevel@tonic-gate 
11497c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
11507c478bd9Sstevel@tonic-gate 	*soft_prip = hdlp->ih_pri;
11517c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
11527c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
11537c478bd9Sstevel@tonic-gate }
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate /*
11567c478bd9Sstevel@tonic-gate  * Set the soft interrupt priority
11577c478bd9Sstevel@tonic-gate  */
11587c478bd9Sstevel@tonic-gate int
ddi_intr_set_softint_pri(ddi_softint_handle_t h,uint_t soft_pri)11597c478bd9Sstevel@tonic-gate ddi_intr_set_softint_pri(ddi_softint_handle_t h, uint_t soft_pri)
11607c478bd9Sstevel@tonic-gate {
11617c478bd9Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp = (ddi_softint_hdl_impl_t *)h;
11627c478bd9Sstevel@tonic-gate 	int			ret;
11637c478bd9Sstevel@tonic-gate 	uint_t			orig_soft_pri;
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: h = %p\n",
11667c478bd9Sstevel@tonic-gate 	    (void *)h));
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
11697c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 	/* Validate priority argument */
11727c478bd9Sstevel@tonic-gate 	if (soft_pri < DDI_INTR_SOFTPRI_MIN ||
11737c478bd9Sstevel@tonic-gate 	    soft_pri > DDI_INTR_SOFTPRI_MAX) {
11747c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: invalid "
11757c478bd9Sstevel@tonic-gate 		    "soft_pri input given  = %x\n", soft_pri));
11767c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
11777c478bd9Sstevel@tonic-gate 	}
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
11807c478bd9Sstevel@tonic-gate 	orig_soft_pri = hdlp->ih_pri;
11817c478bd9Sstevel@tonic-gate 	hdlp->ih_pri = soft_pri;
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 	if ((ret = i_ddi_set_softint_pri(hdlp, orig_soft_pri)) != DDI_SUCCESS) {
11847c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: failed, "
11857c478bd9Sstevel@tonic-gate 		    " ret 0%x\n", ret));
11867c478bd9Sstevel@tonic-gate 		hdlp->ih_pri = orig_soft_pri;
11877c478bd9Sstevel@tonic-gate 	}
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
11907c478bd9Sstevel@tonic-gate 	return (ret);
11917c478bd9Sstevel@tonic-gate }
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate /*
11947c478bd9Sstevel@tonic-gate  * Old DDI interrupt framework
1195a195726fSgovinda  *
1196a195726fSgovinda  * The following DDI interrupt interfaces are obsolete.
1197a195726fSgovinda  * Use the above new DDI interrupt interfaces instead.
11987c478bd9Sstevel@tonic-gate  */
11997c478bd9Sstevel@tonic-gate 
12007c478bd9Sstevel@tonic-gate int
ddi_intr_hilevel(dev_info_t * dip,uint_t inumber)12017c478bd9Sstevel@tonic-gate ddi_intr_hilevel(dev_info_t *dip, uint_t inumber)
12027c478bd9Sstevel@tonic-gate {
12035febcb4aSScott Carter, SD IOSW 	ddi_intr_handle_t	hdl;
12045febcb4aSScott Carter, SD IOSW 	ddi_intr_handle_t	*hdl_p;
12055febcb4aSScott Carter, SD IOSW 	size_t			hdl_sz = 0;
12067c478bd9Sstevel@tonic-gate 	int			actual, ret;
12077c478bd9Sstevel@tonic-gate 	uint_t			high_pri, pri;
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: name=%s%d dip=0x%p "
12107c478bd9Sstevel@tonic-gate 	    "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
12117c478bd9Sstevel@tonic-gate 	    (void *)dip, inumber));
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 	/*
12147c478bd9Sstevel@tonic-gate 	 * The device driver may have already registed with the
12157c478bd9Sstevel@tonic-gate 	 * framework. If so, first try to get the existing interrupt handle
12167c478bd9Sstevel@tonic-gate 	 * for that given inumber and use that handle.
12177c478bd9Sstevel@tonic-gate 	 */
12185febcb4aSScott Carter, SD IOSW 	if ((hdl = i_ddi_get_intr_handle(dip, inumber)) == NULL) {
12195febcb4aSScott Carter, SD IOSW 		hdl_sz = sizeof (ddi_intr_handle_t) * (inumber + 1);
12205febcb4aSScott Carter, SD IOSW 		hdl_p = kmem_zalloc(hdl_sz, KM_SLEEP);
12215febcb4aSScott Carter, SD IOSW 		if ((ret = ddi_intr_alloc(dip, hdl_p, DDI_INTR_TYPE_FIXED,
12229c75c6bfSgovinda 		    inumber, 1, &actual,
12239c75c6bfSgovinda 		    DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) {
12247c478bd9Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: "
12257c478bd9Sstevel@tonic-gate 			    "ddi_intr_alloc failed, ret 0x%x\n", ret));
12265febcb4aSScott Carter, SD IOSW 			kmem_free(hdl_p, hdl_sz);
12277c478bd9Sstevel@tonic-gate 			return (0);
12287c478bd9Sstevel@tonic-gate 		}
12295febcb4aSScott Carter, SD IOSW 		hdl = hdl_p[inumber];
12307c478bd9Sstevel@tonic-gate 	}
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate 	if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) {
12337c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: "
12347c478bd9Sstevel@tonic-gate 		    "ddi_intr_get_pri failed, ret 0x%x\n", ret));
12357c478bd9Sstevel@tonic-gate 		(void) ddi_intr_free(hdl);
12365febcb4aSScott Carter, SD IOSW 		if (hdl_sz)
12375febcb4aSScott Carter, SD IOSW 			kmem_free(hdl_p, hdl_sz);
12387c478bd9Sstevel@tonic-gate 		return (0);
12397c478bd9Sstevel@tonic-gate 	}
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 	high_pri = ddi_intr_get_hilevel_pri();
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: pri = %x, "
12447c478bd9Sstevel@tonic-gate 	    "high_pri = %x\n", pri, high_pri));
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 	/* Free the handle allocated here only if no existing handle exists */
12475febcb4aSScott Carter, SD IOSW 	if (hdl_sz) {
12487c478bd9Sstevel@tonic-gate 		(void) ddi_intr_free(hdl);
12495febcb4aSScott Carter, SD IOSW 		kmem_free(hdl_p, hdl_sz);
12505febcb4aSScott Carter, SD IOSW 	}
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	return (pri >= high_pri);
12537c478bd9Sstevel@tonic-gate }
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate int
ddi_dev_nintrs(dev_info_t * dip,int * result)12567c478bd9Sstevel@tonic-gate ddi_dev_nintrs(dev_info_t *dip, int *result)
12577c478bd9Sstevel@tonic-gate {
12587c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: name=%s%d dip=0x%p\n",
12597c478bd9Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip), (void *)dip));
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 	if (ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED,
12627c478bd9Sstevel@tonic-gate 	    result) != DDI_SUCCESS) {
12637c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: "
12647c478bd9Sstevel@tonic-gate 		    "ddi_intr_get_nintrs failed\n"));
12657c478bd9Sstevel@tonic-gate 		*result = 0;
12667c478bd9Sstevel@tonic-gate 	}
12677c478bd9Sstevel@tonic-gate 
12687c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
12697c478bd9Sstevel@tonic-gate }
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate int
ddi_get_iblock_cookie(dev_info_t * dip,uint_t inumber,ddi_iblock_cookie_t * iblock_cookiep)12727c478bd9Sstevel@tonic-gate ddi_get_iblock_cookie(dev_info_t *dip, uint_t inumber,
12737c478bd9Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep)
12747c478bd9Sstevel@tonic-gate {
12755febcb4aSScott Carter, SD IOSW 	ddi_intr_handle_t	hdl;
12765febcb4aSScott Carter, SD IOSW 	ddi_intr_handle_t	*hdl_p;
12775febcb4aSScott Carter, SD IOSW 	size_t			hdl_sz = 0;
12787c478bd9Sstevel@tonic-gate 	int			actual, ret;
12797c478bd9Sstevel@tonic-gate 	uint_t			pri;
12807c478bd9Sstevel@tonic-gate 
12817c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: name=%s%d dip=0x%p "
12827c478bd9Sstevel@tonic-gate 	    "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
12837c478bd9Sstevel@tonic-gate 	    (void *)dip, inumber));
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 	ASSERT(iblock_cookiep != NULL);
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 	/*
12887c478bd9Sstevel@tonic-gate 	 * The device driver may have already registed with the
12897c478bd9Sstevel@tonic-gate 	 * framework. If so, first try to get the existing interrupt handle
12907c478bd9Sstevel@tonic-gate 	 * for that given inumber and use that handle.
12917c478bd9Sstevel@tonic-gate 	 */
12925febcb4aSScott Carter, SD IOSW 	if ((hdl = i_ddi_get_intr_handle(dip, inumber)) == NULL) {
12935febcb4aSScott Carter, SD IOSW 		hdl_sz = sizeof (ddi_intr_handle_t) * (inumber + 1);
12945febcb4aSScott Carter, SD IOSW 		hdl_p = kmem_zalloc(hdl_sz, KM_SLEEP);
12955febcb4aSScott Carter, SD IOSW 		if ((ret = ddi_intr_alloc(dip, hdl_p,
12965febcb4aSScott Carter, SD IOSW 		    DDI_INTR_TYPE_FIXED, inumber, 1, &actual,
12979c75c6bfSgovinda 		    DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) {
12987c478bd9Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: "
12997c478bd9Sstevel@tonic-gate 			    "ddi_intr_alloc failed, ret 0x%x\n", ret));
13005febcb4aSScott Carter, SD IOSW 			kmem_free(hdl_p, hdl_sz);
13017c478bd9Sstevel@tonic-gate 			return (DDI_INTR_NOTFOUND);
13027c478bd9Sstevel@tonic-gate 		}
13035febcb4aSScott Carter, SD IOSW 		hdl = hdl_p[inumber];
13047c478bd9Sstevel@tonic-gate 	}
13057c478bd9Sstevel@tonic-gate 
13067c478bd9Sstevel@tonic-gate 	if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) {
13077c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: "
13087c478bd9Sstevel@tonic-gate 		    "ddi_intr_get_pri failed, ret 0x%x\n", ret));
13097c478bd9Sstevel@tonic-gate 		(void) ddi_intr_free(hdl);
13105febcb4aSScott Carter, SD IOSW 		if (hdl_sz)
13115febcb4aSScott Carter, SD IOSW 			kmem_free(hdl_p, hdl_sz);
13127c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
13137c478bd9Sstevel@tonic-gate 	}
13147c478bd9Sstevel@tonic-gate 
1315abdbd06dSagiri 	*iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)pri;
13167c478bd9Sstevel@tonic-gate 	/* Free the handle allocated here only if no existing handle exists */
13175febcb4aSScott Carter, SD IOSW 	if (hdl_sz) {
13187c478bd9Sstevel@tonic-gate 		(void) ddi_intr_free(hdl);
13195febcb4aSScott Carter, SD IOSW 		kmem_free(hdl_p, hdl_sz);
13205febcb4aSScott Carter, SD IOSW 	}
13217c478bd9Sstevel@tonic-gate 
13227c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
13237c478bd9Sstevel@tonic-gate }
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate int
ddi_add_intr(dev_info_t * dip,uint_t inumber,ddi_iblock_cookie_t * iblock_cookiep,ddi_idevice_cookie_t * idevice_cookiep,uint_t (* int_handler)(caddr_t int_handler_arg),caddr_t int_handler_arg)13267c478bd9Sstevel@tonic-gate ddi_add_intr(dev_info_t *dip, uint_t inumber,
13277c478bd9Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep,
13287c478bd9Sstevel@tonic-gate     ddi_idevice_cookie_t *idevice_cookiep,
13297c478bd9Sstevel@tonic-gate     uint_t (*int_handler)(caddr_t int_handler_arg),
13307c478bd9Sstevel@tonic-gate     caddr_t int_handler_arg)
13317c478bd9Sstevel@tonic-gate {
13327c478bd9Sstevel@tonic-gate 	ddi_intr_handle_t	*hdl_p;
13335febcb4aSScott Carter, SD IOSW 	size_t			hdl_sz;
13347c478bd9Sstevel@tonic-gate 	int			actual, ret;
13357c478bd9Sstevel@tonic-gate 	uint_t			pri;
1336*71222654SToomas Soome 	ddi_intr_handler_t	*handler;
13377c478bd9Sstevel@tonic-gate 
1338*71222654SToomas Soome 	handler = (ddi_intr_handler_t *)(uintptr_t)int_handler;
13397c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: name=%s%d dip=0x%p "
13407c478bd9Sstevel@tonic-gate 	    "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
13417c478bd9Sstevel@tonic-gate 	    (void *)dip, inumber));
13427c478bd9Sstevel@tonic-gate 
13435febcb4aSScott Carter, SD IOSW 	hdl_sz = sizeof (ddi_intr_handle_t) * (inumber + 1);
13445febcb4aSScott Carter, SD IOSW 	hdl_p = kmem_zalloc(hdl_sz, KM_SLEEP);
13457c478bd9Sstevel@tonic-gate 
13467c478bd9Sstevel@tonic-gate 	if ((ret = ddi_intr_alloc(dip, hdl_p, DDI_INTR_TYPE_FIXED,
13479c75c6bfSgovinda 	    inumber, 1, &actual, DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) {
13487c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
13497c478bd9Sstevel@tonic-gate 		    "ddi_intr_alloc failed, ret 0x%x\n", ret));
13505febcb4aSScott Carter, SD IOSW 		kmem_free(hdl_p, hdl_sz);
13517c478bd9Sstevel@tonic-gate 		return (DDI_INTR_NOTFOUND);
13527c478bd9Sstevel@tonic-gate 	}
13537c478bd9Sstevel@tonic-gate 
13545febcb4aSScott Carter, SD IOSW 	if ((ret = ddi_intr_get_pri(hdl_p[inumber], &pri)) != DDI_SUCCESS)  {
13557c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
13567c478bd9Sstevel@tonic-gate 		    "ddi_intr_get_pri failed, ret 0x%x\n", ret));
13575febcb4aSScott Carter, SD IOSW 		(void) ddi_intr_free(hdl_p[inumber]);
13585febcb4aSScott Carter, SD IOSW 		kmem_free(hdl_p, hdl_sz);
13597c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
13607c478bd9Sstevel@tonic-gate 	}
13617c478bd9Sstevel@tonic-gate 
1362*71222654SToomas Soome 	if ((ret = ddi_intr_add_handler(hdl_p[inumber], handler,
1363*71222654SToomas Soome 	    int_handler_arg, NULL)) != DDI_SUCCESS) {
13647c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
13657c478bd9Sstevel@tonic-gate 		    "ddi_intr_add_handler failed, ret 0x%x\n", ret));
13665febcb4aSScott Carter, SD IOSW 		(void) ddi_intr_free(hdl_p[inumber]);
13675febcb4aSScott Carter, SD IOSW 		kmem_free(hdl_p, hdl_sz);
13687c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
13697c478bd9Sstevel@tonic-gate 	}
13707c478bd9Sstevel@tonic-gate 
13715febcb4aSScott Carter, SD IOSW 	if ((ret = ddi_intr_enable(hdl_p[inumber])) != DDI_SUCCESS) {
13727c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
13737c478bd9Sstevel@tonic-gate 		    "ddi_intr_enable failed, ret 0x%x\n", ret));
13745febcb4aSScott Carter, SD IOSW 		(void) ddi_intr_remove_handler(hdl_p[inumber]);
13755febcb4aSScott Carter, SD IOSW 		(void) ddi_intr_free(hdl_p[inumber]);
13765febcb4aSScott Carter, SD IOSW 		kmem_free(hdl_p, hdl_sz);
13777c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
13787c478bd9Sstevel@tonic-gate 	}
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate 	if (iblock_cookiep)
1381abdbd06dSagiri 		*iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)pri;
13827c478bd9Sstevel@tonic-gate 
13837c478bd9Sstevel@tonic-gate 	if (idevice_cookiep) {
13847c478bd9Sstevel@tonic-gate 		idevice_cookiep->idev_vector = 0;
13857c478bd9Sstevel@tonic-gate 		idevice_cookiep->idev_priority = pri;
13867c478bd9Sstevel@tonic-gate 	}
13877c478bd9Sstevel@tonic-gate 
13885febcb4aSScott Carter, SD IOSW 	kmem_free(hdl_p, hdl_sz);
13895febcb4aSScott Carter, SD IOSW 
13907c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
13917c478bd9Sstevel@tonic-gate }
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate /* ARGSUSED */
13947c478bd9Sstevel@tonic-gate int
ddi_add_fastintr(dev_info_t * dip,uint_t inumber,ddi_iblock_cookie_t * iblock_cookiep,ddi_idevice_cookie_t * idevice_cookiep,uint_t (* hi_int_handler)(void))13957c478bd9Sstevel@tonic-gate ddi_add_fastintr(dev_info_t *dip, uint_t inumber,
13967c478bd9Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep,
13977c478bd9Sstevel@tonic-gate     ddi_idevice_cookie_t *idevice_cookiep,
13987c478bd9Sstevel@tonic-gate     uint_t (*hi_int_handler)(void))
13997c478bd9Sstevel@tonic-gate {
14007c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_fastintr: name=%s%d dip=0x%p "
14017c478bd9Sstevel@tonic-gate 	    "inum=0x%x: Not supported, return failure\n", ddi_driver_name(dip),
14027c478bd9Sstevel@tonic-gate 	    ddi_get_instance(dip), (void *)dip, inumber));
14037c478bd9Sstevel@tonic-gate 
14047c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
14057c478bd9Sstevel@tonic-gate }
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate /* ARGSUSED */
14087c478bd9Sstevel@tonic-gate void
ddi_remove_intr(dev_info_t * dip,uint_t inum,ddi_iblock_cookie_t iblock_cookie)14097c478bd9Sstevel@tonic-gate ddi_remove_intr(dev_info_t *dip, uint_t inum, ddi_iblock_cookie_t iblock_cookie)
14107c478bd9Sstevel@tonic-gate {
14115febcb4aSScott Carter, SD IOSW 	ddi_intr_handle_t	hdl;
14127c478bd9Sstevel@tonic-gate 	int			ret;
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: name=%s%d dip=0x%p "
14157c478bd9Sstevel@tonic-gate 	    "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
14167c478bd9Sstevel@tonic-gate 	    (void *)dip, inum));
14177c478bd9Sstevel@tonic-gate 
14185febcb4aSScott Carter, SD IOSW 	if ((hdl = i_ddi_get_intr_handle(dip, inum)) == NULL) {
14197c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: no handle "
14207c478bd9Sstevel@tonic-gate 		    "found\n"));
14217c478bd9Sstevel@tonic-gate 		return;
14227c478bd9Sstevel@tonic-gate 	}
14237c478bd9Sstevel@tonic-gate 
14245febcb4aSScott Carter, SD IOSW 	if ((ret = ddi_intr_disable(hdl)) != DDI_SUCCESS) {
14257c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
14267c478bd9Sstevel@tonic-gate 		    "ddi_intr_disable failed, ret 0x%x\n", ret));
14277c478bd9Sstevel@tonic-gate 		return;
14287c478bd9Sstevel@tonic-gate 	}
14297c478bd9Sstevel@tonic-gate 
14305febcb4aSScott Carter, SD IOSW 	if ((ret = ddi_intr_remove_handler(hdl)) != DDI_SUCCESS) {
14317c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
14327c478bd9Sstevel@tonic-gate 		    "ddi_intr_remove_handler failed, ret 0x%x\n", ret));
14337c478bd9Sstevel@tonic-gate 		return;
14347c478bd9Sstevel@tonic-gate 	}
14357c478bd9Sstevel@tonic-gate 
14365febcb4aSScott Carter, SD IOSW 	if ((ret = ddi_intr_free(hdl)) != DDI_SUCCESS) {
14377c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
14387c478bd9Sstevel@tonic-gate 		    "ddi_intr_free failed, ret 0x%x\n", ret));
14397c478bd9Sstevel@tonic-gate 		return;
14407c478bd9Sstevel@tonic-gate 	}
14417c478bd9Sstevel@tonic-gate }
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate /* ARGSUSED */
14447c478bd9Sstevel@tonic-gate int
ddi_get_soft_iblock_cookie(dev_info_t * dip,int preference,ddi_iblock_cookie_t * iblock_cookiep)14457c478bd9Sstevel@tonic-gate ddi_get_soft_iblock_cookie(dev_info_t *dip, int preference,
14467c478bd9Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep)
14477c478bd9Sstevel@tonic-gate {
14487c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_get_soft_iblock_cookie: name=%s%d "
14497c478bd9Sstevel@tonic-gate 	    "dip=0x%p pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
14507c478bd9Sstevel@tonic-gate 	    (void *)dip, preference));
14517c478bd9Sstevel@tonic-gate 
14527c478bd9Sstevel@tonic-gate 	ASSERT(iblock_cookiep != NULL);
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate 	if (preference == DDI_SOFTINT_FIXED)
14557c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
14567c478bd9Sstevel@tonic-gate 
1457abdbd06dSagiri 	*iblock_cookiep = (ddi_iblock_cookie_t)((uintptr_t)
14587c478bd9Sstevel@tonic-gate 	    ((preference > DDI_SOFTINT_MED) ? DDI_SOFT_INTR_PRI_H :
14597c478bd9Sstevel@tonic-gate 	    DDI_SOFT_INTR_PRI_M));
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
14627c478bd9Sstevel@tonic-gate }
14637c478bd9Sstevel@tonic-gate 
14647c478bd9Sstevel@tonic-gate int
ddi_add_softintr(dev_info_t * dip,int preference,ddi_softintr_t * idp,ddi_iblock_cookie_t * iblock_cookiep,ddi_idevice_cookie_t * idevice_cookiep,uint_t (* int_handler)(caddr_t int_handler_arg),caddr_t int_handler_arg)14657c478bd9Sstevel@tonic-gate ddi_add_softintr(dev_info_t *dip, int preference, ddi_softintr_t *idp,
14667c478bd9Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep,
14677c478bd9Sstevel@tonic-gate     ddi_idevice_cookie_t *idevice_cookiep,
14687c478bd9Sstevel@tonic-gate     uint_t (*int_handler)(caddr_t int_handler_arg),
14697c478bd9Sstevel@tonic-gate     caddr_t int_handler_arg)
14707c478bd9Sstevel@tonic-gate {
14717c478bd9Sstevel@tonic-gate 	ddi_softint_handle_t	*hdl_p;
14727c478bd9Sstevel@tonic-gate 	uint64_t		softpri;
14737c478bd9Sstevel@tonic-gate 	int			ret;
1474*71222654SToomas Soome 	ddi_intr_handler_t	*handler;
14757c478bd9Sstevel@tonic-gate 
1476*71222654SToomas Soome 	handler = (ddi_intr_handler_t *)(uintptr_t)int_handler;
14777c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: name=%s%d dip=0x%p "
14787c478bd9Sstevel@tonic-gate 	    "pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
14797c478bd9Sstevel@tonic-gate 	    (void *)dip, preference));
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate 	if ((idp == NULL) || ((preference == DDI_SOFTINT_FIXED) &&
14827c478bd9Sstevel@tonic-gate 	    (iblock_cookiep == NULL)))
14837c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
14847c478bd9Sstevel@tonic-gate 
14857c478bd9Sstevel@tonic-gate 	/* Translate the priority preference */
14867c478bd9Sstevel@tonic-gate 	if (preference == DDI_SOFTINT_FIXED) {
1487b52a2671Seota 		softpri = (uint64_t)(uintptr_t)*iblock_cookiep;
14887c478bd9Sstevel@tonic-gate 		softpri = MIN(softpri, DDI_SOFT_INTR_PRI_H);
14897c478bd9Sstevel@tonic-gate 	} else {
14907c478bd9Sstevel@tonic-gate 		softpri = (uint64_t)((preference > DDI_SOFTINT_MED) ?
14917c478bd9Sstevel@tonic-gate 		    DDI_SOFT_INTR_PRI_H : DDI_SOFT_INTR_PRI_M);
14927c478bd9Sstevel@tonic-gate 	}
14937c478bd9Sstevel@tonic-gate 
14947c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: preference 0x%x "
14957c478bd9Sstevel@tonic-gate 	    "softpri 0x%lx\n", preference, (long)softpri));
14967c478bd9Sstevel@tonic-gate 
14977c478bd9Sstevel@tonic-gate 	hdl_p = kmem_zalloc(sizeof (ddi_softint_handle_t), KM_SLEEP);
14987c478bd9Sstevel@tonic-gate 	if ((ret = ddi_intr_add_softint(dip, hdl_p, softpri,
1499*71222654SToomas Soome 	    handler, int_handler_arg)) != DDI_SUCCESS) {
15007c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: "
15017c478bd9Sstevel@tonic-gate 		    "ddi_intr_add_softint failed, ret 0x%x\n", ret));
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate 		kmem_free(hdl_p, sizeof (ddi_softint_handle_t));
15047c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
15057c478bd9Sstevel@tonic-gate 	}
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate 	if (iblock_cookiep)
1508b52a2671Seota 		*iblock_cookiep =  (ddi_iblock_cookie_t)(uintptr_t)softpri;
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 	if (idevice_cookiep) {
15117c478bd9Sstevel@tonic-gate 		idevice_cookiep->idev_vector = 0;
15127c478bd9Sstevel@tonic-gate 		idevice_cookiep->idev_priority = softpri;
15137c478bd9Sstevel@tonic-gate 	}
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate 	*idp = (ddi_softintr_t)hdl_p;
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: dip = 0x%p, "
15187c478bd9Sstevel@tonic-gate 	    "idp = 0x%p, ret = %x\n", (void *)dip, (void *)*idp, ret));
15197c478bd9Sstevel@tonic-gate 
15207c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
15217c478bd9Sstevel@tonic-gate }
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate void
ddi_remove_softintr(ddi_softintr_t id)15247c478bd9Sstevel@tonic-gate ddi_remove_softintr(ddi_softintr_t id)
15257c478bd9Sstevel@tonic-gate {
15267c478bd9Sstevel@tonic-gate 	ddi_softint_handle_t	*h_p = (ddi_softint_handle_t *)id;
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: id=0x%p\n",
15297c478bd9Sstevel@tonic-gate 	    (void *)id));
15307c478bd9Sstevel@tonic-gate 
15317c478bd9Sstevel@tonic-gate 	if (h_p == NULL)
15327c478bd9Sstevel@tonic-gate 		return;
15337c478bd9Sstevel@tonic-gate 
15347c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: handle 0x%p\n",
15357c478bd9Sstevel@tonic-gate 	    (void *)h_p));
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate 	(void) ddi_intr_remove_softint(*h_p);
15387c478bd9Sstevel@tonic-gate 	kmem_free(h_p, sizeof (ddi_softint_handle_t));
15397c478bd9Sstevel@tonic-gate }
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate void
ddi_trigger_softintr(ddi_softintr_t id)15427c478bd9Sstevel@tonic-gate ddi_trigger_softintr(ddi_softintr_t id)
15437c478bd9Sstevel@tonic-gate {
15447c478bd9Sstevel@tonic-gate 	ddi_softint_handle_t	*h_p = (ddi_softint_handle_t *)id;
15457c478bd9Sstevel@tonic-gate 	int			ret;
15467c478bd9Sstevel@tonic-gate 
15477c478bd9Sstevel@tonic-gate 	if (h_p == NULL)
15487c478bd9Sstevel@tonic-gate 		return;
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate 	if ((ret = ddi_intr_trigger_softint(*h_p, NULL)) != DDI_SUCCESS) {
15517c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_trigger_softintr: "
15527c478bd9Sstevel@tonic-gate 		    "ddi_intr_trigger_softint failed, hdlp 0x%p "
15537c478bd9Sstevel@tonic-gate 		    "ret 0x%x\n", (void *)h_p, ret));
15547c478bd9Sstevel@tonic-gate 	}
15557c478bd9Sstevel@tonic-gate }
1556