xref: /onnv-gate/usr/src/uts/common/os/ddi_intr.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/note.h>
30*0Sstevel@tonic-gate #include <sys/sysmacros.h>
31*0Sstevel@tonic-gate #include <sys/types.h>
32*0Sstevel@tonic-gate #include <sys/param.h>
33*0Sstevel@tonic-gate #include <sys/systm.h>
34*0Sstevel@tonic-gate #include <sys/kmem.h>
35*0Sstevel@tonic-gate #include <sys/cmn_err.h>
36*0Sstevel@tonic-gate #include <sys/debug.h>
37*0Sstevel@tonic-gate #include <sys/avintr.h>
38*0Sstevel@tonic-gate #include <sys/autoconf.h>
39*0Sstevel@tonic-gate #include <sys/sunndi.h>
40*0Sstevel@tonic-gate #include <sys/ndi_impldefs.h>	/* include prototypes */
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate /*
43*0Sstevel@tonic-gate  * New DDI interrupt framework
44*0Sstevel@tonic-gate  */
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate /*
47*0Sstevel@tonic-gate  * MSI/X allocation limit.
48*0Sstevel@tonic-gate  * This limit will change with Resource Management support.
49*0Sstevel@tonic-gate  */
50*0Sstevel@tonic-gate uint_t		ddi_msix_alloc_limit = 2;
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate /*
53*0Sstevel@tonic-gate  * ddi_intr_get_supported_types:
54*0Sstevel@tonic-gate  *	Return, as a bit mask, the hardware interrupt types supported by
55*0Sstevel@tonic-gate  *	both the device and by the host in the integer pointed
56*0Sstevel@tonic-gate  *	to be the 'typesp' argument.
57*0Sstevel@tonic-gate  */
58*0Sstevel@tonic-gate int
59*0Sstevel@tonic-gate ddi_intr_get_supported_types(dev_info_t *dip, int *typesp)
60*0Sstevel@tonic-gate {
61*0Sstevel@tonic-gate 	int			ret;
62*0Sstevel@tonic-gate 	ddi_intr_handle_impl_t	hdl;
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate 	if (dip == NULL)
65*0Sstevel@tonic-gate 		return (DDI_EINVAL);
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: dip %p\n",
68*0Sstevel@tonic-gate 	    (void *)dip));
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate 	if (*typesp = i_ddi_intr_get_supported_types(dip))
71*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate 	bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
74*0Sstevel@tonic-gate 	hdl.ih_dip = dip;
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(dip, dip, DDI_INTROP_SUPPORTED_TYPES, &hdl,
77*0Sstevel@tonic-gate 	    (void *)typesp);
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate 	if (ret != DDI_SUCCESS)
80*0Sstevel@tonic-gate 		return (DDI_INTR_NOTFOUND);
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: types %x\n",
83*0Sstevel@tonic-gate 	    *typesp));
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate 	return (ret);
86*0Sstevel@tonic-gate }
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate /*
90*0Sstevel@tonic-gate  * ddi_intr_get_nintrs:
91*0Sstevel@tonic-gate  * 	Return as an integer in the integer pointed to by the argument
92*0Sstevel@tonic-gate  * 	*nintrsp*, the number of interrupts the device supports for the
93*0Sstevel@tonic-gate  *	given interrupt type.
94*0Sstevel@tonic-gate  */
95*0Sstevel@tonic-gate int
96*0Sstevel@tonic-gate ddi_intr_get_nintrs(dev_info_t *dip, int type, int *nintrsp)
97*0Sstevel@tonic-gate {
98*0Sstevel@tonic-gate 	int			ret;
99*0Sstevel@tonic-gate 	ddi_intr_handle_impl_t	hdl;
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 	if (dip == NULL)
102*0Sstevel@tonic-gate 		return (DDI_EINVAL);
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs: dip %p\n",
105*0Sstevel@tonic-gate 	    (void *)dip));
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate 	if (!(i_ddi_intr_get_supported_types(dip) & type))
108*0Sstevel@tonic-gate 		return (DDI_EINVAL);
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate 	if (*nintrsp = i_ddi_intr_get_supported_nintrs(dip, type))
111*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate 	bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
114*0Sstevel@tonic-gate 	hdl.ih_dip = dip;
115*0Sstevel@tonic-gate 	hdl.ih_type = type;
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(dip, dip, DDI_INTROP_NINTRS, &hdl,
118*0Sstevel@tonic-gate 	    (void *)nintrsp);
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs:: nintrs %x\n",
121*0Sstevel@tonic-gate 	    *nintrsp));
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate 	return (ret);
124*0Sstevel@tonic-gate }
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate /*
128*0Sstevel@tonic-gate  * ddi_intr_get_navail:
129*0Sstevel@tonic-gate  *	Bus nexus driver will return availble interrupt count value for
130*0Sstevel@tonic-gate  *	a given interrupt type.
131*0Sstevel@tonic-gate  *
132*0Sstevel@tonic-gate  * 	Return as an integer in the integer pointed to by the argument
133*0Sstevel@tonic-gate  * 	*navailp*, the number of interrupts currently available for the
134*0Sstevel@tonic-gate  *	given interrupt type.
135*0Sstevel@tonic-gate  */
136*0Sstevel@tonic-gate int
137*0Sstevel@tonic-gate ddi_intr_get_navail(dev_info_t *dip, int type, int *navailp)
138*0Sstevel@tonic-gate {
139*0Sstevel@tonic-gate 	int			ret;
140*0Sstevel@tonic-gate 	ddi_intr_handle_impl_t	hdl;
141*0Sstevel@tonic-gate 
142*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_navail: dip %p\n",
143*0Sstevel@tonic-gate 	    (void *)dip));
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate 	if (dip == NULL)
146*0Sstevel@tonic-gate 		return (DDI_EINVAL);
147*0Sstevel@tonic-gate 
148*0Sstevel@tonic-gate 	if (!(i_ddi_intr_get_supported_types(dip) & type))
149*0Sstevel@tonic-gate 		return (DDI_EINVAL);
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate 	/*
152*0Sstevel@tonic-gate 	 * In future, this interface implementation will change
153*0Sstevel@tonic-gate 	 * with Resource Management support.
154*0Sstevel@tonic-gate 	 */
155*0Sstevel@tonic-gate 	bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
156*0Sstevel@tonic-gate 	hdl.ih_dip = dip;
157*0Sstevel@tonic-gate 	hdl.ih_type = type;
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(dip, dip,
160*0Sstevel@tonic-gate 	    DDI_INTROP_NAVAIL, &hdl, (void *)navailp);
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 	return (ret == DDI_SUCCESS ? DDI_SUCCESS : DDI_INTR_NOTFOUND);
163*0Sstevel@tonic-gate }
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate /*
167*0Sstevel@tonic-gate  * Interrupt allocate/free functions
168*0Sstevel@tonic-gate  */
169*0Sstevel@tonic-gate int
170*0Sstevel@tonic-gate ddi_intr_alloc(dev_info_t *dip, ddi_intr_handle_t *h_array, int type, int inum,
171*0Sstevel@tonic-gate     int count, int *actualp, int behavior)
172*0Sstevel@tonic-gate {
173*0Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp, tmp_hdl;
174*0Sstevel@tonic-gate 	int			i, ret, cap = 0, intr_type, nintrs = 0;
175*0Sstevel@tonic-gate 	uint_t			pri;
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: name %s dip 0x%p "
178*0Sstevel@tonic-gate 	    "type %x inum %x count %x behavior %x\n", ddi_driver_name(dip),
179*0Sstevel@tonic-gate 	    (void *)dip, type, inum, count, behavior));
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 	/* Validate parameters */
182*0Sstevel@tonic-gate 	if (dip == NULL || h_array == NULL || count < 1) {
183*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Invalid args\n"));
184*0Sstevel@tonic-gate 		return (DDI_EINVAL);
185*0Sstevel@tonic-gate 	}
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate 	/* Validate interrupt type */
188*0Sstevel@tonic-gate 	if (!(i_ddi_intr_get_supported_types(dip) & type)) {
189*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x not "
190*0Sstevel@tonic-gate 		    "supported\n", type));
191*0Sstevel@tonic-gate 		return (DDI_EINVAL);
192*0Sstevel@tonic-gate 	}
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 	/* First, get how many interrupts the device supports */
195*0Sstevel@tonic-gate 	if (!(nintrs = i_ddi_intr_get_supported_nintrs(dip, type))) {
196*0Sstevel@tonic-gate 		if (ddi_intr_get_nintrs(dip, type, &nintrs) != DDI_SUCCESS) {
197*0Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no "
198*0Sstevel@tonic-gate 			    "interrupts found of type %d\n", type));
199*0Sstevel@tonic-gate 			return (DDI_INTR_NOTFOUND);
200*0Sstevel@tonic-gate 		}
201*0Sstevel@tonic-gate 	}
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate 	/* Is this function invoked with more interrupt than device supports? */
204*0Sstevel@tonic-gate 	if (count > nintrs) {
205*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no of interrupts "
206*0Sstevel@tonic-gate 		    "requested %d is more than supported %d\n", count, nintrs));
207*0Sstevel@tonic-gate 		return (DDI_EINVAL);
208*0Sstevel@tonic-gate 	}
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate 	/*
211*0Sstevel@tonic-gate 	 * Check if requested interrupt type is not same as interrupt
212*0Sstevel@tonic-gate 	 * type is in use if any.
213*0Sstevel@tonic-gate 	 */
214*0Sstevel@tonic-gate 	if (((intr_type = i_ddi_intr_get_current_type(dip)) != 0) &&
215*0Sstevel@tonic-gate 	    (intr_type != type)) {
216*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Requested "
217*0Sstevel@tonic-gate 		    "interrupt type %x is different from interrupt type %x"
218*0Sstevel@tonic-gate 		    "already in use\n", type, intr_type));
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 		return (DDI_EINVAL);
221*0Sstevel@tonic-gate 	}
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 	/*
224*0Sstevel@tonic-gate 	 * Check if requested interrupt type is in use and requested number
225*0Sstevel@tonic-gate 	 * of interrupts and number of interrupts already in use exceeds the
226*0Sstevel@tonic-gate 	 * number of interrupts supported by this device.
227*0Sstevel@tonic-gate 	 */
228*0Sstevel@tonic-gate 	if (intr_type) {
229*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x "
230*0Sstevel@tonic-gate 		    "is already being used\n", type));
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate 		if ((count + i_ddi_intr_get_current_nintrs(dip)) > nintrs) {
233*0Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: count %d "
234*0Sstevel@tonic-gate 			    "+ intrs in use %d exceeds supported %d intrs\n",
235*0Sstevel@tonic-gate 			    count, i_ddi_intr_get_current_nintrs(dip), nintrs));
236*0Sstevel@tonic-gate 			return (DDI_EINVAL);
237*0Sstevel@tonic-gate 		}
238*0Sstevel@tonic-gate 	}
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 	/*
241*0Sstevel@tonic-gate 	 * For MSI, ensure that the requested interrupt count is a power of 2
242*0Sstevel@tonic-gate 	 */
243*0Sstevel@tonic-gate 	if (type == DDI_INTR_TYPE_MSI && !ISP2(count)) {
244*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: "
245*0Sstevel@tonic-gate 		    "MSI count %d is not a power of two\n", count));
246*0Sstevel@tonic-gate 		return (DDI_EINVAL);
247*0Sstevel@tonic-gate 	}
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 	/*
250*0Sstevel@tonic-gate 	 * Limit max MSI/X allocation to ddi_msix_alloc_limit.
251*0Sstevel@tonic-gate 	 * This limit will change with Resource Management support.
252*0Sstevel@tonic-gate 	 */
253*0Sstevel@tonic-gate 	if (DDI_INTR_IS_MSI_OR_MSIX(type) && (count > ddi_msix_alloc_limit)) {
254*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Requested MSI/Xs %d"
255*0Sstevel@tonic-gate 		    "Max MSI/Xs limit %d\n", count, ddi_msix_alloc_limit));
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 		if (behavior == DDI_INTR_ALLOC_STRICT) {
258*0Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: "
259*0Sstevel@tonic-gate 			    "DDI_INTR_ALLOC_STRICT flag is passed, "
260*0Sstevel@tonic-gate 			    "return failure\n"));
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 			return (DDI_EAGAIN);
263*0Sstevel@tonic-gate 		}
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 		count = ddi_msix_alloc_limit;
266*0Sstevel@tonic-gate 	}
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate 	/* Now allocate required number of interrupts */
269*0Sstevel@tonic-gate 	bzero(&tmp_hdl, sizeof (ddi_intr_handle_impl_t));
270*0Sstevel@tonic-gate 	tmp_hdl.ih_type = type;
271*0Sstevel@tonic-gate 	tmp_hdl.ih_inum = inum;
272*0Sstevel@tonic-gate 	tmp_hdl.ih_scratch1 = count;
273*0Sstevel@tonic-gate 	tmp_hdl.ih_scratch2 = behavior;
274*0Sstevel@tonic-gate 	tmp_hdl.ih_dip = dip;
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate 	if (i_ddi_handle_intr_ops(dip, dip, DDI_INTROP_ALLOC,
277*0Sstevel@tonic-gate 	    &tmp_hdl, (void *)actualp) != DDI_SUCCESS) {
278*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: allocation "
279*0Sstevel@tonic-gate 		    "failed\n"));
280*0Sstevel@tonic-gate 		return (*actualp ? DDI_EAGAIN : DDI_INTR_NOTFOUND);
281*0Sstevel@tonic-gate 	}
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 	if ((ret = i_ddi_handle_intr_ops(dip, dip, DDI_INTROP_GETPRI,
284*0Sstevel@tonic-gate 	    &tmp_hdl, (void *)&pri)) != DDI_SUCCESS) {
285*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get priority "
286*0Sstevel@tonic-gate 		    "failed\n"));
287*0Sstevel@tonic-gate 		return (ret);
288*0Sstevel@tonic-gate 	}
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: getting capability\n"));
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate 	if ((ret = i_ddi_handle_intr_ops(dip, dip, DDI_INTROP_GETCAP,
293*0Sstevel@tonic-gate 	    &tmp_hdl, (void *)&cap)) != DDI_SUCCESS) {
294*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get capability "
295*0Sstevel@tonic-gate 		    "failed\n"));
296*0Sstevel@tonic-gate 		return (ret);
297*0Sstevel@tonic-gate 	}
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 	/* Save current interrupt type, supported and current intr count */
300*0Sstevel@tonic-gate 	i_ddi_intr_devi_init(dip);
301*0Sstevel@tonic-gate 	i_ddi_intr_set_current_type(dip, type);
302*0Sstevel@tonic-gate 	i_ddi_intr_set_supported_nintrs(dip, nintrs);
303*0Sstevel@tonic-gate 	i_ddi_intr_set_current_nintrs(dip,
304*0Sstevel@tonic-gate 	    i_ddi_intr_get_current_nintrs(dip) + *actualp);
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate 	/* Now, go and handle each "handle" */
307*0Sstevel@tonic-gate 	for (i = 0; i < *actualp; i++) {
308*0Sstevel@tonic-gate 		hdlp = (ddi_intr_handle_impl_t *)kmem_zalloc(
309*0Sstevel@tonic-gate 		    (sizeof (ddi_intr_handle_impl_t)), KM_SLEEP);
310*0Sstevel@tonic-gate 		rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
311*0Sstevel@tonic-gate 		h_array[i] = (struct __ddi_intr_handle *)hdlp;
312*0Sstevel@tonic-gate 		hdlp->ih_type = type;
313*0Sstevel@tonic-gate 		hdlp->ih_pri = pri;
314*0Sstevel@tonic-gate 		hdlp->ih_cap = cap;
315*0Sstevel@tonic-gate 		hdlp->ih_ver = DDI_INTR_VERSION;
316*0Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ALLOC;
317*0Sstevel@tonic-gate 		hdlp->ih_dip = dip;
318*0Sstevel@tonic-gate 		hdlp->ih_inum = inum + i;
319*0Sstevel@tonic-gate 		if (type & DDI_INTR_TYPE_FIXED)
320*0Sstevel@tonic-gate 			i_ddi_set_intr_handle(dip, i, &h_array[i]);
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: hdlp = 0x%p\n",
323*0Sstevel@tonic-gate 		    (void *)h_array[i]));
324*0Sstevel@tonic-gate 	}
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
327*0Sstevel@tonic-gate }
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate int
331*0Sstevel@tonic-gate ddi_intr_free(ddi_intr_handle_t h)
332*0Sstevel@tonic-gate {
333*0Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
334*0Sstevel@tonic-gate 	int			ret;
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_free: hdlp = %p\n", (void *)hdlp));
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	if (hdlp == NULL)
339*0Sstevel@tonic-gate 		return (DDI_EINVAL);
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
342*0Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
343*0Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
344*0Sstevel@tonic-gate 		return (DDI_EINVAL);
345*0Sstevel@tonic-gate 	}
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
348*0Sstevel@tonic-gate 	    DDI_INTROP_FREE, hdlp, NULL);
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
351*0Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
352*0Sstevel@tonic-gate 		if ((i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1) == 0)
353*0Sstevel@tonic-gate 			/* Reset current interrupt type and count used */
354*0Sstevel@tonic-gate 			i_ddi_intr_set_current_type(hdlp->ih_dip, 0);
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate 		i_ddi_intr_set_current_nintrs(hdlp->ih_dip,
357*0Sstevel@tonic-gate 		    i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1);
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 		if (hdlp->ih_type & DDI_INTR_TYPE_FIXED)
360*0Sstevel@tonic-gate 			i_ddi_set_intr_handle(hdlp->ih_dip,
361*0Sstevel@tonic-gate 			    hdlp->ih_inum, NULL);
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 		rw_destroy(&hdlp->ih_rwlock);
364*0Sstevel@tonic-gate 		kmem_free(hdlp, sizeof (ddi_intr_handle_impl_t));
365*0Sstevel@tonic-gate 	}
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 	return (ret);
368*0Sstevel@tonic-gate }
369*0Sstevel@tonic-gate 
370*0Sstevel@tonic-gate /*
371*0Sstevel@tonic-gate  * Interrupt get/set capacity functions
372*0Sstevel@tonic-gate  *
373*0Sstevel@tonic-gate  * The logic used to figure this out is shown here:
374*0Sstevel@tonic-gate  *
375*0Sstevel@tonic-gate  *			Device level		Platform level	    Intr source
376*0Sstevel@tonic-gate  * 1. Fixed interrupts
377*0Sstevel@tonic-gate  * (non-PCI)
378*0Sstevel@tonic-gate  * o Flags supported	N/A			Maskable/Pending/    rootnex
379*0Sstevel@tonic-gate  *						No Block Enable
380*0Sstevel@tonic-gate  * o navail					1
381*0Sstevel@tonic-gate  *
382*0Sstevel@tonic-gate  * 2. PCI Fixed interrupts
383*0Sstevel@tonic-gate  * o Flags supported	pending/Maskable	Maskable/pending/    pci
384*0Sstevel@tonic-gate  *						No Block enable
385*0Sstevel@tonic-gate  * o navail		N/A			1
386*0Sstevel@tonic-gate  *
387*0Sstevel@tonic-gate  * 3. PCI MSI
388*0Sstevel@tonic-gate  * o Flags supported	Maskable/Pending	Maskable/Pending    pci
389*0Sstevel@tonic-gate  *			Block Enable		(if drvr doesn't)   Block Enable
390*0Sstevel@tonic-gate  * o navail		N/A			#vectors - #used    N/A
391*0Sstevel@tonic-gate  *
392*0Sstevel@tonic-gate  * 4. PCI MSI-X
393*0Sstevel@tonic-gate  * o Flags supported	Maskable/Pending	Maskable/Pending    pci
394*0Sstevel@tonic-gate  *			Block Enable				    Block Enable
395*0Sstevel@tonic-gate  * o navail		N/A			#vectors - #used    N/A
396*0Sstevel@tonic-gate  *
397*0Sstevel@tonic-gate  * where:
398*0Sstevel@tonic-gate  *	#vectors	- Total numbers of vectors available
399*0Sstevel@tonic-gate  *	#used		- Total numbers of vectors currently being used
400*0Sstevel@tonic-gate  *
401*0Sstevel@tonic-gate  * For devices complying to PCI2.3 or greater, see bit10 of Command Register
402*0Sstevel@tonic-gate  * 0 - enables assertion of INTx
403*0Sstevel@tonic-gate  * 1 - disables assertion of INTx
404*0Sstevel@tonic-gate  *
405*0Sstevel@tonic-gate  * For non MSI/X interrupts; if the IRQ is shared then all ddi_intr_set_*()
406*0Sstevel@tonic-gate  * operations return failure.
407*0Sstevel@tonic-gate  */
408*0Sstevel@tonic-gate int
409*0Sstevel@tonic-gate ddi_intr_get_cap(ddi_intr_handle_t h, int *flagsp)
410*0Sstevel@tonic-gate {
411*0Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
412*0Sstevel@tonic-gate 	int			ret;
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_cap: hdlp = %p\n",
415*0Sstevel@tonic-gate 	    (void *)hdlp));
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 	*flagsp = 0;
418*0Sstevel@tonic-gate 	if (hdlp == NULL)
419*0Sstevel@tonic-gate 		return (DDI_EINVAL);
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate 	if (hdlp->ih_cap) {
424*0Sstevel@tonic-gate 		*flagsp = hdlp->ih_cap & ~DDI_INTR_FLAG_MSI64;
425*0Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
426*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
427*0Sstevel@tonic-gate 	}
428*0Sstevel@tonic-gate 
429*0Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
430*0Sstevel@tonic-gate 	    DDI_INTROP_GETCAP, hdlp, (void *)flagsp);
431*0Sstevel@tonic-gate 
432*0Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
433*0Sstevel@tonic-gate 		hdlp->ih_cap = *flagsp;
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 		/* Mask out MSI/X 64-bit support to the consumer */
436*0Sstevel@tonic-gate 		*flagsp &= ~DDI_INTR_FLAG_MSI64;
437*0Sstevel@tonic-gate 	}
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
440*0Sstevel@tonic-gate 	return (ret);
441*0Sstevel@tonic-gate }
442*0Sstevel@tonic-gate 
443*0Sstevel@tonic-gate int
444*0Sstevel@tonic-gate ddi_intr_set_cap(ddi_intr_handle_t h, int flags)
445*0Sstevel@tonic-gate {
446*0Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
447*0Sstevel@tonic-gate 	int			ret;
448*0Sstevel@tonic-gate 
449*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_cap: hdlp = %p", (void *)hdlp));
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 	if (hdlp == NULL)
452*0Sstevel@tonic-gate 		return (DDI_EINVAL);
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
455*0Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
456*0Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
457*0Sstevel@tonic-gate 		return (DDI_EINVAL);
458*0Sstevel@tonic-gate 	}
459*0Sstevel@tonic-gate 
460*0Sstevel@tonic-gate 	/* Only DDI_INTR_FLAG_LEVEL or DDI_INTR_FLAG_EDGE are allowed */
461*0Sstevel@tonic-gate 	if (!(flags & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) {
462*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "%s%d: only LEVEL or EDGE capability "
463*0Sstevel@tonic-gate 		    "can be set\n", ddi_driver_name(hdlp->ih_dip),
464*0Sstevel@tonic-gate 		    ddi_get_instance(hdlp->ih_dip)));
465*0Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
466*0Sstevel@tonic-gate 		return (DDI_EINVAL);
467*0Sstevel@tonic-gate 	}
468*0Sstevel@tonic-gate 
469*0Sstevel@tonic-gate 	/* Both level/edge flags must be currently supported */
470*0Sstevel@tonic-gate 	if (!(hdlp->ih_cap & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) {
471*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "%s%d: Both LEVEL and EDGE capability"
472*0Sstevel@tonic-gate 		    " must be supported\n", ddi_driver_name(hdlp->ih_dip),
473*0Sstevel@tonic-gate 		    ddi_get_instance(hdlp->ih_dip)));
474*0Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
475*0Sstevel@tonic-gate 		return (DDI_ENOTSUP);
476*0Sstevel@tonic-gate 	}
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
479*0Sstevel@tonic-gate 	    DDI_INTROP_SETCAP, hdlp, &flags);
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
482*0Sstevel@tonic-gate 	return (ret);
483*0Sstevel@tonic-gate }
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate /*
486*0Sstevel@tonic-gate  * Priority related functions
487*0Sstevel@tonic-gate  */
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate /*
490*0Sstevel@tonic-gate  * ddi_intr_get_hilevel_pri:
491*0Sstevel@tonic-gate  *	Returns the minimum priority level for a
492*0Sstevel@tonic-gate  *	high-level interrupt on a platform.
493*0Sstevel@tonic-gate  */
494*0Sstevel@tonic-gate uint_t
495*0Sstevel@tonic-gate ddi_intr_get_hilevel_pri(void)
496*0Sstevel@tonic-gate {
497*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_hilevel_pri:\n"));
498*0Sstevel@tonic-gate 	return (LOCK_LEVEL + 1);
499*0Sstevel@tonic-gate }
500*0Sstevel@tonic-gate 
501*0Sstevel@tonic-gate int
502*0Sstevel@tonic-gate ddi_intr_get_pri(ddi_intr_handle_t h, uint_t *prip)
503*0Sstevel@tonic-gate {
504*0Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
505*0Sstevel@tonic-gate 	int			ret;
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pri: hdlp = %p\n",
508*0Sstevel@tonic-gate 	    (void *)hdlp));
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate 	*prip = 0;
511*0Sstevel@tonic-gate 	if (hdlp == NULL)
512*0Sstevel@tonic-gate 		return (DDI_EINVAL);
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
515*0Sstevel@tonic-gate 	/* Already initialized, just return that */
516*0Sstevel@tonic-gate 	if (hdlp->ih_pri) {
517*0Sstevel@tonic-gate 		*prip = hdlp->ih_pri;
518*0Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
519*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
520*0Sstevel@tonic-gate 	}
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
523*0Sstevel@tonic-gate 	    DDI_INTROP_GETPRI, hdlp, (void *)prip);
524*0Sstevel@tonic-gate 
525*0Sstevel@tonic-gate 	if (ret == DDI_SUCCESS)
526*0Sstevel@tonic-gate 		hdlp->ih_pri = *prip;
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
529*0Sstevel@tonic-gate 	return (ret);
530*0Sstevel@tonic-gate }
531*0Sstevel@tonic-gate 
532*0Sstevel@tonic-gate int
533*0Sstevel@tonic-gate ddi_intr_set_pri(ddi_intr_handle_t h, uint_t pri)
534*0Sstevel@tonic-gate {
535*0Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
536*0Sstevel@tonic-gate 	int			ret;
537*0Sstevel@tonic-gate 
538*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: hdlp = %p", (void *)hdlp));
539*0Sstevel@tonic-gate 
540*0Sstevel@tonic-gate 	if (hdlp == NULL)
541*0Sstevel@tonic-gate 		return (DDI_EINVAL);
542*0Sstevel@tonic-gate 
543*0Sstevel@tonic-gate 	/* Validate priority argument */
544*0Sstevel@tonic-gate 	if (pri < DDI_INTR_PRI_MIN || pri > DDI_INTR_PRI_MAX) {
545*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: invalid priority "
546*0Sstevel@tonic-gate 		    "specified  = %x\n", pri));
547*0Sstevel@tonic-gate 		return (DDI_EINVAL);
548*0Sstevel@tonic-gate 	}
549*0Sstevel@tonic-gate 
550*0Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
551*0Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
552*0Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
553*0Sstevel@tonic-gate 		return (DDI_EINVAL);
554*0Sstevel@tonic-gate 	}
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 	/* If the passed priority is same as existing priority; do nothing */
557*0Sstevel@tonic-gate 	if (pri == hdlp->ih_pri) {
558*0Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
559*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
560*0Sstevel@tonic-gate 	}
561*0Sstevel@tonic-gate 
562*0Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
563*0Sstevel@tonic-gate 	    DDI_INTROP_SETPRI, hdlp, &pri);
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate 	if (ret == DDI_SUCCESS)
566*0Sstevel@tonic-gate 		hdlp->ih_pri = pri;
567*0Sstevel@tonic-gate 
568*0Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
569*0Sstevel@tonic-gate 	return (ret);
570*0Sstevel@tonic-gate }
571*0Sstevel@tonic-gate 
572*0Sstevel@tonic-gate /*
573*0Sstevel@tonic-gate  * Interrupt add/duplicate/remove handlers
574*0Sstevel@tonic-gate  */
575*0Sstevel@tonic-gate int
576*0Sstevel@tonic-gate ddi_intr_add_handler(ddi_intr_handle_t h, ddi_intr_handler_t inthandler,
577*0Sstevel@tonic-gate     void *arg1, void *arg2)
578*0Sstevel@tonic-gate {
579*0Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
580*0Sstevel@tonic-gate 	int			ret;
581*0Sstevel@tonic-gate 
582*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_handler: hdlp = 0x%p\n",
583*0Sstevel@tonic-gate 	    (void *)hdlp));
584*0Sstevel@tonic-gate 
585*0Sstevel@tonic-gate 	if ((hdlp == NULL) || (inthandler == NULL))
586*0Sstevel@tonic-gate 		return (DDI_EINVAL);
587*0Sstevel@tonic-gate 
588*0Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
589*0Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
590*0Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
591*0Sstevel@tonic-gate 		return (DDI_EINVAL);
592*0Sstevel@tonic-gate 	}
593*0Sstevel@tonic-gate 
594*0Sstevel@tonic-gate 	hdlp->ih_cb_func = inthandler;
595*0Sstevel@tonic-gate 	hdlp->ih_cb_arg1 = arg1;
596*0Sstevel@tonic-gate 	hdlp->ih_cb_arg2 = arg2;
597*0Sstevel@tonic-gate 
598*0Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
599*0Sstevel@tonic-gate 	    DDI_INTROP_ADDISR, hdlp, NULL);
600*0Sstevel@tonic-gate 
601*0Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
602*0Sstevel@tonic-gate 		hdlp->ih_cb_func = NULL;
603*0Sstevel@tonic-gate 		hdlp->ih_cb_arg1 = NULL;
604*0Sstevel@tonic-gate 		hdlp->ih_cb_arg2 = NULL;
605*0Sstevel@tonic-gate 	} else
606*0Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ADDED;
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
609*0Sstevel@tonic-gate 	return (ret);
610*0Sstevel@tonic-gate }
611*0Sstevel@tonic-gate 
612*0Sstevel@tonic-gate int
613*0Sstevel@tonic-gate ddi_intr_dup_handler(ddi_intr_handle_t org, int vector, ddi_intr_handle_t *dup)
614*0Sstevel@tonic-gate {
615*0Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)org;
616*0Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*dup_hdlp;
617*0Sstevel@tonic-gate 	int			ret;
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_dup_handler: hdlp = 0x%p\n",
620*0Sstevel@tonic-gate 	    (void *)hdlp));
621*0Sstevel@tonic-gate 
622*0Sstevel@tonic-gate 	/* Do some input argument checking ("dup" is not allocated) */
623*0Sstevel@tonic-gate 	if ((hdlp == NULL) || (dup != NULL))
624*0Sstevel@tonic-gate 		return (DDI_EINVAL);
625*0Sstevel@tonic-gate 
626*0Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
627*0Sstevel@tonic-gate 
628*0Sstevel@tonic-gate 	/* Do some input argument checking */
629*0Sstevel@tonic-gate 	if ((hdlp->ih_state == DDI_IHDL_STATE_ALLOC) ||	/* intr handle alloc? */
630*0Sstevel@tonic-gate 	    (hdlp->ih_type != DDI_INTR_TYPE_MSIX)) {	/* only MSI-X allowed */
631*0Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
632*0Sstevel@tonic-gate 		return (DDI_EINVAL);
633*0Sstevel@tonic-gate 	}
634*0Sstevel@tonic-gate 
635*0Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
636*0Sstevel@tonic-gate 	    DDI_INTROP_DUPVEC, hdlp, (void *)&vector);
637*0Sstevel@tonic-gate 
638*0Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
639*0Sstevel@tonic-gate 		dup_hdlp = (ddi_intr_handle_impl_t *)
640*0Sstevel@tonic-gate 		    kmem_zalloc(sizeof (ddi_intr_handle_impl_t), KM_SLEEP);
641*0Sstevel@tonic-gate 
642*0Sstevel@tonic-gate 		dup = (ddi_intr_handle_t *)dup_hdlp;
643*0Sstevel@tonic-gate 		rw_init(&dup_hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
644*0Sstevel@tonic-gate 		rw_enter(&dup_hdlp->ih_rwlock, RW_WRITER);
645*0Sstevel@tonic-gate 		dup_hdlp->ih_ver = DDI_INTR_VERSION;
646*0Sstevel@tonic-gate 		dup_hdlp->ih_state = DDI_IHDL_STATE_ADDED;
647*0Sstevel@tonic-gate 		dup_hdlp->ih_dip = hdlp->ih_dip;
648*0Sstevel@tonic-gate 		dup_hdlp->ih_type = hdlp->ih_type;
649*0Sstevel@tonic-gate 		dup_hdlp->ih_pri = hdlp->ih_pri;
650*0Sstevel@tonic-gate 		dup_hdlp->ih_cap = hdlp->ih_cap;
651*0Sstevel@tonic-gate 		dup_hdlp->ih_inum = hdlp->ih_inum;
652*0Sstevel@tonic-gate 		/* What about MSI-X vector */
653*0Sstevel@tonic-gate 
654*0Sstevel@tonic-gate 		dup_hdlp->ih_cb_func = hdlp->ih_cb_func;
655*0Sstevel@tonic-gate 		dup_hdlp->ih_cb_arg1 = hdlp->ih_cb_arg1;
656*0Sstevel@tonic-gate 		dup_hdlp->ih_cb_arg2 = hdlp->ih_cb_arg2;
657*0Sstevel@tonic-gate 		rw_exit(&dup_hdlp->ih_rwlock);
658*0Sstevel@tonic-gate 	}
659*0Sstevel@tonic-gate 
660*0Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
661*0Sstevel@tonic-gate 	return (ret);
662*0Sstevel@tonic-gate }
663*0Sstevel@tonic-gate 
664*0Sstevel@tonic-gate int
665*0Sstevel@tonic-gate ddi_intr_remove_handler(ddi_intr_handle_t h)
666*0Sstevel@tonic-gate {
667*0Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
668*0Sstevel@tonic-gate 	int			ret;
669*0Sstevel@tonic-gate 
670*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_handler: hdlp = %p\n",
671*0Sstevel@tonic-gate 	    (void *)hdlp));
672*0Sstevel@tonic-gate 
673*0Sstevel@tonic-gate 	if (hdlp == NULL)
674*0Sstevel@tonic-gate 		return (DDI_EINVAL);
675*0Sstevel@tonic-gate 
676*0Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
677*0Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ADDED) {
678*0Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
679*0Sstevel@tonic-gate 		return (DDI_EINVAL);
680*0Sstevel@tonic-gate 	}
681*0Sstevel@tonic-gate 
682*0Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
683*0Sstevel@tonic-gate 	    DDI_INTROP_REMISR, hdlp, NULL);
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
686*0Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ALLOC;
687*0Sstevel@tonic-gate 		hdlp->ih_cb_func = NULL;
688*0Sstevel@tonic-gate 		hdlp->ih_cb_arg1 = NULL;
689*0Sstevel@tonic-gate 		hdlp->ih_cb_arg2 = NULL;
690*0Sstevel@tonic-gate 	}
691*0Sstevel@tonic-gate 
692*0Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
693*0Sstevel@tonic-gate 	return (ret);
694*0Sstevel@tonic-gate }
695*0Sstevel@tonic-gate 
696*0Sstevel@tonic-gate /*
697*0Sstevel@tonic-gate  * Interrupt enable/disable/block_enable/block_disable handlers
698*0Sstevel@tonic-gate  */
699*0Sstevel@tonic-gate int
700*0Sstevel@tonic-gate ddi_intr_enable(ddi_intr_handle_t h)
701*0Sstevel@tonic-gate {
702*0Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
703*0Sstevel@tonic-gate 	int			ret;
704*0Sstevel@tonic-gate 
705*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_enable: hdlp = %p\n",
706*0Sstevel@tonic-gate 	    (void *)hdlp));
707*0Sstevel@tonic-gate 
708*0Sstevel@tonic-gate 	if (hdlp == NULL)
709*0Sstevel@tonic-gate 		return (DDI_EINVAL);
710*0Sstevel@tonic-gate 
711*0Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
712*0Sstevel@tonic-gate 	if ((hdlp->ih_state != DDI_IHDL_STATE_ADDED) ||
713*0Sstevel@tonic-gate 	    ((hdlp->ih_type == DDI_INTR_TYPE_MSI) &&
714*0Sstevel@tonic-gate 	    (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) {
715*0Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
716*0Sstevel@tonic-gate 		return (DDI_EINVAL);
717*0Sstevel@tonic-gate 	}
718*0Sstevel@tonic-gate 
719*0Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
720*0Sstevel@tonic-gate 	    DDI_INTROP_ENABLE, hdlp, NULL);
721*0Sstevel@tonic-gate 
722*0Sstevel@tonic-gate 	if (ret == DDI_SUCCESS)
723*0Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ENABLE;
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
726*0Sstevel@tonic-gate 	return (ret);
727*0Sstevel@tonic-gate }
728*0Sstevel@tonic-gate 
729*0Sstevel@tonic-gate int
730*0Sstevel@tonic-gate ddi_intr_disable(ddi_intr_handle_t h)
731*0Sstevel@tonic-gate {
732*0Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
733*0Sstevel@tonic-gate 	int			ret;
734*0Sstevel@tonic-gate 
735*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_disable: hdlp = %p\n",
736*0Sstevel@tonic-gate 	    (void *)hdlp));
737*0Sstevel@tonic-gate 
738*0Sstevel@tonic-gate 	if (hdlp == NULL)
739*0Sstevel@tonic-gate 		return (DDI_EINVAL);
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
742*0Sstevel@tonic-gate 	if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
743*0Sstevel@tonic-gate 	    ((hdlp->ih_type == DDI_INTR_TYPE_MSI) &&
744*0Sstevel@tonic-gate 	    (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) {
745*0Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
746*0Sstevel@tonic-gate 		return (DDI_EINVAL);
747*0Sstevel@tonic-gate 	}
748*0Sstevel@tonic-gate 
749*0Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
750*0Sstevel@tonic-gate 	    DDI_INTROP_DISABLE, hdlp, NULL);
751*0Sstevel@tonic-gate 
752*0Sstevel@tonic-gate 	if (ret == DDI_SUCCESS)
753*0Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ADDED;
754*0Sstevel@tonic-gate 
755*0Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
756*0Sstevel@tonic-gate 	return (ret);
757*0Sstevel@tonic-gate }
758*0Sstevel@tonic-gate 
759*0Sstevel@tonic-gate int
760*0Sstevel@tonic-gate ddi_intr_block_enable(ddi_intr_handle_t *h_array, int count)
761*0Sstevel@tonic-gate {
762*0Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp;
763*0Sstevel@tonic-gate 	int			i, ret;
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_enable: h_array = %p\n",
766*0Sstevel@tonic-gate 	    (void *)h_array));
767*0Sstevel@tonic-gate 
768*0Sstevel@tonic-gate 	if (h_array == NULL)
769*0Sstevel@tonic-gate 		return (DDI_EINVAL);
770*0Sstevel@tonic-gate 
771*0Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
772*0Sstevel@tonic-gate 		hdlp = (ddi_intr_handle_impl_t *)h_array[i];
773*0Sstevel@tonic-gate 		rw_enter(&hdlp->ih_rwlock, RW_READER);
774*0Sstevel@tonic-gate 
775*0Sstevel@tonic-gate 		if (hdlp->ih_state != DDI_IHDL_STATE_ADDED ||
776*0Sstevel@tonic-gate 		    hdlp->ih_type != DDI_INTR_TYPE_MSI ||
777*0Sstevel@tonic-gate 		    !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) {
778*0Sstevel@tonic-gate 			rw_exit(&hdlp->ih_rwlock);
779*0Sstevel@tonic-gate 			return (DDI_EINVAL);
780*0Sstevel@tonic-gate 		}
781*0Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
782*0Sstevel@tonic-gate 	}
783*0Sstevel@tonic-gate 
784*0Sstevel@tonic-gate 	hdlp = (ddi_intr_handle_impl_t *)h_array[0];
785*0Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
786*0Sstevel@tonic-gate 	hdlp->ih_scratch1 = count;
787*0Sstevel@tonic-gate 
788*0Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
789*0Sstevel@tonic-gate 	    DDI_INTROP_BLOCKENABLE, hdlp, NULL);
790*0Sstevel@tonic-gate 
791*0Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
792*0Sstevel@tonic-gate 
793*0Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
794*0Sstevel@tonic-gate 		for (i = 0; i < count; i++) {
795*0Sstevel@tonic-gate 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
796*0Sstevel@tonic-gate 			rw_enter(&hdlp->ih_rwlock, RW_WRITER);
797*0Sstevel@tonic-gate 			hdlp->ih_state = DDI_IHDL_STATE_ENABLE;
798*0Sstevel@tonic-gate 			rw_exit(&hdlp->ih_rwlock);
799*0Sstevel@tonic-gate 		}
800*0Sstevel@tonic-gate 	}
801*0Sstevel@tonic-gate 
802*0Sstevel@tonic-gate 	return (ret);
803*0Sstevel@tonic-gate }
804*0Sstevel@tonic-gate 
805*0Sstevel@tonic-gate int
806*0Sstevel@tonic-gate ddi_intr_block_disable(ddi_intr_handle_t *h_array, int count)
807*0Sstevel@tonic-gate {
808*0Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp;
809*0Sstevel@tonic-gate 	int			i, ret;
810*0Sstevel@tonic-gate 
811*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_disable: h_array = %p\n",
812*0Sstevel@tonic-gate 	    (void *)h_array));
813*0Sstevel@tonic-gate 
814*0Sstevel@tonic-gate 	if (h_array == NULL)
815*0Sstevel@tonic-gate 		return (DDI_EINVAL);
816*0Sstevel@tonic-gate 
817*0Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
818*0Sstevel@tonic-gate 		hdlp = (ddi_intr_handle_impl_t *)h_array[i];
819*0Sstevel@tonic-gate 		rw_enter(&hdlp->ih_rwlock, RW_READER);
820*0Sstevel@tonic-gate 		if (hdlp->ih_state != DDI_IHDL_STATE_ENABLE ||
821*0Sstevel@tonic-gate 		    hdlp->ih_type != DDI_INTR_TYPE_MSI ||
822*0Sstevel@tonic-gate 		    !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) {
823*0Sstevel@tonic-gate 			rw_exit(&hdlp->ih_rwlock);
824*0Sstevel@tonic-gate 			return (DDI_EINVAL);
825*0Sstevel@tonic-gate 		}
826*0Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
827*0Sstevel@tonic-gate 	}
828*0Sstevel@tonic-gate 
829*0Sstevel@tonic-gate 	hdlp = (ddi_intr_handle_impl_t *)h_array[0];
830*0Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
831*0Sstevel@tonic-gate 	hdlp->ih_scratch1 = count;
832*0Sstevel@tonic-gate 
833*0Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
834*0Sstevel@tonic-gate 	    DDI_INTROP_BLOCKDISABLE, hdlp, NULL);
835*0Sstevel@tonic-gate 
836*0Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
837*0Sstevel@tonic-gate 
838*0Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
839*0Sstevel@tonic-gate 		for (i = 0; i < count; i++) {
840*0Sstevel@tonic-gate 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
841*0Sstevel@tonic-gate 			rw_enter(&hdlp->ih_rwlock, RW_WRITER);
842*0Sstevel@tonic-gate 			hdlp->ih_state = DDI_IHDL_STATE_ADDED;
843*0Sstevel@tonic-gate 			rw_exit(&hdlp->ih_rwlock);
844*0Sstevel@tonic-gate 		}
845*0Sstevel@tonic-gate 	}
846*0Sstevel@tonic-gate 
847*0Sstevel@tonic-gate 	return (ret);
848*0Sstevel@tonic-gate }
849*0Sstevel@tonic-gate 
850*0Sstevel@tonic-gate /*
851*0Sstevel@tonic-gate  * Interrupt set/clr mask handlers
852*0Sstevel@tonic-gate  */
853*0Sstevel@tonic-gate int
854*0Sstevel@tonic-gate ddi_intr_set_mask(ddi_intr_handle_t h)
855*0Sstevel@tonic-gate {
856*0Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
857*0Sstevel@tonic-gate 	int			ret;
858*0Sstevel@tonic-gate 
859*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_mask: hdlp = %p\n",
860*0Sstevel@tonic-gate 	    (void *)hdlp));
861*0Sstevel@tonic-gate 
862*0Sstevel@tonic-gate 	if (hdlp == NULL)
863*0Sstevel@tonic-gate 		return (DDI_EINVAL);
864*0Sstevel@tonic-gate 
865*0Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
866*0Sstevel@tonic-gate 	if (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE)) {
867*0Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
868*0Sstevel@tonic-gate 		return (DDI_EINVAL);
869*0Sstevel@tonic-gate 	}
870*0Sstevel@tonic-gate 
871*0Sstevel@tonic-gate 	ret =  i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
872*0Sstevel@tonic-gate 	    DDI_INTROP_SETMASK, hdlp, NULL);
873*0Sstevel@tonic-gate 
874*0Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
875*0Sstevel@tonic-gate 	return (ret);
876*0Sstevel@tonic-gate }
877*0Sstevel@tonic-gate 
878*0Sstevel@tonic-gate int
879*0Sstevel@tonic-gate ddi_intr_clr_mask(ddi_intr_handle_t h)
880*0Sstevel@tonic-gate {
881*0Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
882*0Sstevel@tonic-gate 	int			ret;
883*0Sstevel@tonic-gate 
884*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_clr_mask: hdlp = %p\n",
885*0Sstevel@tonic-gate 	    (void *)hdlp));
886*0Sstevel@tonic-gate 
887*0Sstevel@tonic-gate 	if (hdlp == NULL)
888*0Sstevel@tonic-gate 		return (DDI_EINVAL);
889*0Sstevel@tonic-gate 
890*0Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
891*0Sstevel@tonic-gate 	if (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE)) {
892*0Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
893*0Sstevel@tonic-gate 		return (DDI_EINVAL);
894*0Sstevel@tonic-gate 	}
895*0Sstevel@tonic-gate 
896*0Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
897*0Sstevel@tonic-gate 	    DDI_INTROP_CLRMASK, hdlp, NULL);
898*0Sstevel@tonic-gate 
899*0Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
900*0Sstevel@tonic-gate 	return (ret);
901*0Sstevel@tonic-gate }
902*0Sstevel@tonic-gate 
903*0Sstevel@tonic-gate /*
904*0Sstevel@tonic-gate  * Interrupt get_pending handler
905*0Sstevel@tonic-gate  */
906*0Sstevel@tonic-gate int
907*0Sstevel@tonic-gate ddi_intr_get_pending(ddi_intr_handle_t h, int *pendingp)
908*0Sstevel@tonic-gate {
909*0Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
910*0Sstevel@tonic-gate 	int			ret;
911*0Sstevel@tonic-gate 
912*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pending: hdlp = %p\n",
913*0Sstevel@tonic-gate 	    (void *)hdlp));
914*0Sstevel@tonic-gate 
915*0Sstevel@tonic-gate 	if (hdlp == NULL)
916*0Sstevel@tonic-gate 		return (DDI_EINVAL);
917*0Sstevel@tonic-gate 
918*0Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
919*0Sstevel@tonic-gate 	if (!(hdlp->ih_cap & DDI_INTR_FLAG_PENDING)) {
920*0Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
921*0Sstevel@tonic-gate 		return (DDI_EINVAL);
922*0Sstevel@tonic-gate 	}
923*0Sstevel@tonic-gate 
924*0Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
925*0Sstevel@tonic-gate 	    DDI_INTROP_GETPENDING, hdlp, (void *)pendingp);
926*0Sstevel@tonic-gate 
927*0Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
928*0Sstevel@tonic-gate 	return (ret);
929*0Sstevel@tonic-gate }
930*0Sstevel@tonic-gate 
931*0Sstevel@tonic-gate /*
932*0Sstevel@tonic-gate  * Soft interrupt handlers
933*0Sstevel@tonic-gate  */
934*0Sstevel@tonic-gate /*
935*0Sstevel@tonic-gate  * Add a soft interrupt and register its handler
936*0Sstevel@tonic-gate  */
937*0Sstevel@tonic-gate /* ARGSUSED */
938*0Sstevel@tonic-gate int
939*0Sstevel@tonic-gate ddi_intr_add_softint(dev_info_t *dip, ddi_softint_handle_t *h_p, int soft_pri,
940*0Sstevel@tonic-gate     ddi_intr_handler_t handler, void *arg1)
941*0Sstevel@tonic-gate {
942*0Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp;
943*0Sstevel@tonic-gate 	int			ret;
944*0Sstevel@tonic-gate 
945*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: dip = %p, "
946*0Sstevel@tonic-gate 	    "softpri = 0x%x\n", (void *)dip, soft_pri));
947*0Sstevel@tonic-gate 
948*0Sstevel@tonic-gate 	if ((dip == NULL) || (h_p == NULL) || (handler == NULL)) {
949*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: "
950*0Sstevel@tonic-gate 		    "invalid arguments"));
951*0Sstevel@tonic-gate 
952*0Sstevel@tonic-gate 		return (DDI_EINVAL);
953*0Sstevel@tonic-gate 	}
954*0Sstevel@tonic-gate 
955*0Sstevel@tonic-gate 	/* Validate input arguments */
956*0Sstevel@tonic-gate 	if (soft_pri < DDI_INTR_SOFTPRI_MIN ||
957*0Sstevel@tonic-gate 	    soft_pri > DDI_INTR_SOFTPRI_MAX) {
958*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: invalid "
959*0Sstevel@tonic-gate 		    "soft_pri input given  = %x\n", soft_pri));
960*0Sstevel@tonic-gate 		return (DDI_EINVAL);
961*0Sstevel@tonic-gate 	}
962*0Sstevel@tonic-gate 
963*0Sstevel@tonic-gate 	hdlp = (ddi_softint_hdl_impl_t *)kmem_zalloc(
964*0Sstevel@tonic-gate 	    sizeof (ddi_softint_hdl_impl_t), KM_SLEEP);
965*0Sstevel@tonic-gate 
966*0Sstevel@tonic-gate 	/* fill up internally */
967*0Sstevel@tonic-gate 	rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
968*0Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
969*0Sstevel@tonic-gate 	hdlp->ih_pri = soft_pri;
970*0Sstevel@tonic-gate 	hdlp->ih_dip = dip;
971*0Sstevel@tonic-gate 	hdlp->ih_cb_func = handler;
972*0Sstevel@tonic-gate 	hdlp->ih_cb_arg1 = arg1;
973*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: hdlp = %p\n",
974*0Sstevel@tonic-gate 	    (void *)hdlp));
975*0Sstevel@tonic-gate 
976*0Sstevel@tonic-gate 	/* do the platform specific calls */
977*0Sstevel@tonic-gate 	if ((ret = i_ddi_add_softint(hdlp)) != DDI_SUCCESS) {
978*0Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
979*0Sstevel@tonic-gate 		rw_destroy(&hdlp->ih_rwlock);
980*0Sstevel@tonic-gate 		kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t));
981*0Sstevel@tonic-gate 		return (ret);
982*0Sstevel@tonic-gate 	}
983*0Sstevel@tonic-gate 
984*0Sstevel@tonic-gate 	*h_p = (ddi_softint_handle_t)hdlp;
985*0Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
986*0Sstevel@tonic-gate 	return (ret);
987*0Sstevel@tonic-gate }
988*0Sstevel@tonic-gate 
989*0Sstevel@tonic-gate /*
990*0Sstevel@tonic-gate  * Remove the soft interrupt
991*0Sstevel@tonic-gate  */
992*0Sstevel@tonic-gate int
993*0Sstevel@tonic-gate ddi_intr_remove_softint(ddi_softint_handle_t h)
994*0Sstevel@tonic-gate {
995*0Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp = (ddi_softint_hdl_impl_t *)h;
996*0Sstevel@tonic-gate 
997*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_softint: hdlp = %p\n",
998*0Sstevel@tonic-gate 	    (void *)hdlp));
999*0Sstevel@tonic-gate 
1000*0Sstevel@tonic-gate 	if (hdlp == NULL)
1001*0Sstevel@tonic-gate 		return (DDI_EINVAL);
1002*0Sstevel@tonic-gate 
1003*0Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
1004*0Sstevel@tonic-gate 	i_ddi_remove_softint(hdlp);
1005*0Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
1006*0Sstevel@tonic-gate 	rw_destroy(&hdlp->ih_rwlock);
1007*0Sstevel@tonic-gate 
1008*0Sstevel@tonic-gate 	/* kmem_free the hdl impl_t structure allocated earlier */
1009*0Sstevel@tonic-gate 	kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t));
1010*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
1011*0Sstevel@tonic-gate }
1012*0Sstevel@tonic-gate 
1013*0Sstevel@tonic-gate /*
1014*0Sstevel@tonic-gate  * Trigger a soft interrupt
1015*0Sstevel@tonic-gate  */
1016*0Sstevel@tonic-gate /* ARGSUSED */
1017*0Sstevel@tonic-gate int
1018*0Sstevel@tonic-gate ddi_intr_trigger_softint(ddi_softint_handle_t h, void *arg2)
1019*0Sstevel@tonic-gate {
1020*0Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp = (ddi_softint_hdl_impl_t *)h;
1021*0Sstevel@tonic-gate 	caddr_t			orig_arg2;
1022*0Sstevel@tonic-gate 	int			ret;
1023*0Sstevel@tonic-gate 
1024*0Sstevel@tonic-gate 	if (hdlp == NULL)
1025*0Sstevel@tonic-gate 		return (DDI_EINVAL);
1026*0Sstevel@tonic-gate 
1027*0Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
1028*0Sstevel@tonic-gate 
1029*0Sstevel@tonic-gate 	/*
1030*0Sstevel@tonic-gate 	 * Need to reset "arg2" everytime.
1031*0Sstevel@tonic-gate 	 * Multiple invocations of trigger_softint() are blocked
1032*0Sstevel@tonic-gate 	 */
1033*0Sstevel@tonic-gate 	orig_arg2 = hdlp->ih_cb_arg2;
1034*0Sstevel@tonic-gate 	hdlp->ih_cb_arg2 = arg2;
1035*0Sstevel@tonic-gate 
1036*0Sstevel@tonic-gate 	if ((ret = i_ddi_trigger_softint(hdlp)) != DDI_SUCCESS) {
1037*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_trigger_softint: failed, "
1038*0Sstevel@tonic-gate 		    " ret 0%x\n", ret));
1039*0Sstevel@tonic-gate 		hdlp->ih_cb_arg2 = orig_arg2;
1040*0Sstevel@tonic-gate 	}
1041*0Sstevel@tonic-gate 
1042*0Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
1043*0Sstevel@tonic-gate 	return (ret);
1044*0Sstevel@tonic-gate }
1045*0Sstevel@tonic-gate 
1046*0Sstevel@tonic-gate /*
1047*0Sstevel@tonic-gate  * Get the soft interrupt priority
1048*0Sstevel@tonic-gate  */
1049*0Sstevel@tonic-gate int
1050*0Sstevel@tonic-gate ddi_intr_get_softint_pri(ddi_softint_handle_t h, uint_t *soft_prip)
1051*0Sstevel@tonic-gate {
1052*0Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp = (ddi_softint_hdl_impl_t *)h;
1053*0Sstevel@tonic-gate 
1054*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_softint_pri: h = %p\n",
1055*0Sstevel@tonic-gate 	    (void *)h));
1056*0Sstevel@tonic-gate 
1057*0Sstevel@tonic-gate 	if (hdlp == NULL)
1058*0Sstevel@tonic-gate 		return (DDI_EINVAL);
1059*0Sstevel@tonic-gate 
1060*0Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
1061*0Sstevel@tonic-gate 	*soft_prip = hdlp->ih_pri;
1062*0Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
1063*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
1064*0Sstevel@tonic-gate }
1065*0Sstevel@tonic-gate 
1066*0Sstevel@tonic-gate /*
1067*0Sstevel@tonic-gate  * Set the soft interrupt priority
1068*0Sstevel@tonic-gate  */
1069*0Sstevel@tonic-gate int
1070*0Sstevel@tonic-gate ddi_intr_set_softint_pri(ddi_softint_handle_t h, uint_t soft_pri)
1071*0Sstevel@tonic-gate {
1072*0Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp = (ddi_softint_hdl_impl_t *)h;
1073*0Sstevel@tonic-gate 	int			ret;
1074*0Sstevel@tonic-gate 	uint_t			orig_soft_pri;
1075*0Sstevel@tonic-gate 
1076*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: h = %p\n",
1077*0Sstevel@tonic-gate 	    (void *)h));
1078*0Sstevel@tonic-gate 
1079*0Sstevel@tonic-gate 	if (hdlp == NULL)
1080*0Sstevel@tonic-gate 		return (DDI_EINVAL);
1081*0Sstevel@tonic-gate 
1082*0Sstevel@tonic-gate 	/* Validate priority argument */
1083*0Sstevel@tonic-gate 	if (soft_pri < DDI_INTR_SOFTPRI_MIN ||
1084*0Sstevel@tonic-gate 	    soft_pri > DDI_INTR_SOFTPRI_MAX) {
1085*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: invalid "
1086*0Sstevel@tonic-gate 		    "soft_pri input given  = %x\n", soft_pri));
1087*0Sstevel@tonic-gate 		return (DDI_EINVAL);
1088*0Sstevel@tonic-gate 	}
1089*0Sstevel@tonic-gate 
1090*0Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
1091*0Sstevel@tonic-gate 	orig_soft_pri = hdlp->ih_pri;
1092*0Sstevel@tonic-gate 	hdlp->ih_pri = soft_pri;
1093*0Sstevel@tonic-gate 
1094*0Sstevel@tonic-gate 	if ((ret = i_ddi_set_softint_pri(hdlp, orig_soft_pri)) != DDI_SUCCESS) {
1095*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: failed, "
1096*0Sstevel@tonic-gate 		    " ret 0%x\n", ret));
1097*0Sstevel@tonic-gate 		hdlp->ih_pri = orig_soft_pri;
1098*0Sstevel@tonic-gate 	}
1099*0Sstevel@tonic-gate 
1100*0Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
1101*0Sstevel@tonic-gate 	return (ret);
1102*0Sstevel@tonic-gate }
1103*0Sstevel@tonic-gate 
1104*0Sstevel@tonic-gate /*
1105*0Sstevel@tonic-gate  * Old DDI interrupt framework
1106*0Sstevel@tonic-gate  */
1107*0Sstevel@tonic-gate 
1108*0Sstevel@tonic-gate int
1109*0Sstevel@tonic-gate ddi_intr_hilevel(dev_info_t *dip, uint_t inumber)
1110*0Sstevel@tonic-gate {
1111*0Sstevel@tonic-gate 	ddi_intr_handle_t	hdl, *existing_hdlp;
1112*0Sstevel@tonic-gate 	int			actual, ret;
1113*0Sstevel@tonic-gate 	uint_t			high_pri, pri;
1114*0Sstevel@tonic-gate 
1115*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: name=%s%d dip=0x%p "
1116*0Sstevel@tonic-gate 	    "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
1117*0Sstevel@tonic-gate 	    (void *)dip, inumber));
1118*0Sstevel@tonic-gate 
1119*0Sstevel@tonic-gate 	/*
1120*0Sstevel@tonic-gate 	 * The device driver may have already registed with the
1121*0Sstevel@tonic-gate 	 * framework. If so, first try to get the existing interrupt handle
1122*0Sstevel@tonic-gate 	 * for that given inumber and use that handle.
1123*0Sstevel@tonic-gate 	 */
1124*0Sstevel@tonic-gate 	existing_hdlp = i_ddi_get_intr_handle(dip, inumber);
1125*0Sstevel@tonic-gate 	if (existing_hdlp) {
1126*0Sstevel@tonic-gate 		hdl = existing_hdlp[0];	/* Use existing handle */
1127*0Sstevel@tonic-gate 	} else {
1128*0Sstevel@tonic-gate 		if ((ret = ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED,
1129*0Sstevel@tonic-gate 		    inumber, 1, &actual, 0)) != DDI_SUCCESS) {
1130*0Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: "
1131*0Sstevel@tonic-gate 			    "ddi_intr_alloc failed, ret 0x%x\n", ret));
1132*0Sstevel@tonic-gate 			return (0);
1133*0Sstevel@tonic-gate 		}
1134*0Sstevel@tonic-gate 	}
1135*0Sstevel@tonic-gate 
1136*0Sstevel@tonic-gate 	if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) {
1137*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: "
1138*0Sstevel@tonic-gate 		    "ddi_intr_get_pri failed, ret 0x%x\n", ret));
1139*0Sstevel@tonic-gate 		(void) ddi_intr_free(hdl);
1140*0Sstevel@tonic-gate 		return (0);
1141*0Sstevel@tonic-gate 	}
1142*0Sstevel@tonic-gate 
1143*0Sstevel@tonic-gate 	high_pri = ddi_intr_get_hilevel_pri();
1144*0Sstevel@tonic-gate 
1145*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: pri = %x, "
1146*0Sstevel@tonic-gate 	    "high_pri = %x\n", pri, high_pri));
1147*0Sstevel@tonic-gate 
1148*0Sstevel@tonic-gate 	/* Free the handle allocated here only if no existing handle exists */
1149*0Sstevel@tonic-gate 	if (existing_hdlp == NULL)
1150*0Sstevel@tonic-gate 		(void) ddi_intr_free(hdl);
1151*0Sstevel@tonic-gate 
1152*0Sstevel@tonic-gate 	return (pri >= high_pri);
1153*0Sstevel@tonic-gate }
1154*0Sstevel@tonic-gate 
1155*0Sstevel@tonic-gate int
1156*0Sstevel@tonic-gate ddi_dev_nintrs(dev_info_t *dip, int *result)
1157*0Sstevel@tonic-gate {
1158*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: name=%s%d dip=0x%p\n",
1159*0Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip), (void *)dip));
1160*0Sstevel@tonic-gate 
1161*0Sstevel@tonic-gate 	if (ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED,
1162*0Sstevel@tonic-gate 	    result) != DDI_SUCCESS) {
1163*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: "
1164*0Sstevel@tonic-gate 		    "ddi_intr_get_nintrs failed\n"));
1165*0Sstevel@tonic-gate 		*result = 0;
1166*0Sstevel@tonic-gate 	}
1167*0Sstevel@tonic-gate 
1168*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
1169*0Sstevel@tonic-gate }
1170*0Sstevel@tonic-gate 
1171*0Sstevel@tonic-gate int
1172*0Sstevel@tonic-gate ddi_get_iblock_cookie(dev_info_t *dip, uint_t inumber,
1173*0Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep)
1174*0Sstevel@tonic-gate {
1175*0Sstevel@tonic-gate 	ddi_intr_handle_t	hdl, *existing_hdlp;
1176*0Sstevel@tonic-gate 	int			actual, ret;
1177*0Sstevel@tonic-gate 	uint_t			pri;
1178*0Sstevel@tonic-gate 
1179*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: name=%s%d dip=0x%p "
1180*0Sstevel@tonic-gate 	    "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
1181*0Sstevel@tonic-gate 	    (void *)dip, inumber));
1182*0Sstevel@tonic-gate 
1183*0Sstevel@tonic-gate 	ASSERT(iblock_cookiep != NULL);
1184*0Sstevel@tonic-gate 
1185*0Sstevel@tonic-gate 	/*
1186*0Sstevel@tonic-gate 	 * The device driver may have already registed with the
1187*0Sstevel@tonic-gate 	 * framework. If so, first try to get the existing interrupt handle
1188*0Sstevel@tonic-gate 	 * for that given inumber and use that handle.
1189*0Sstevel@tonic-gate 	 */
1190*0Sstevel@tonic-gate 	existing_hdlp = i_ddi_get_intr_handle(dip, inumber);
1191*0Sstevel@tonic-gate 	if (existing_hdlp) {
1192*0Sstevel@tonic-gate 		hdl = existing_hdlp[0];	/* Use existing handle */
1193*0Sstevel@tonic-gate 	} else {
1194*0Sstevel@tonic-gate 		if ((ret = ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED,
1195*0Sstevel@tonic-gate 		    inumber, 1, &actual, 0)) != DDI_SUCCESS) {
1196*0Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: "
1197*0Sstevel@tonic-gate 			    "ddi_intr_alloc failed, ret 0x%x\n", ret));
1198*0Sstevel@tonic-gate 			return (DDI_INTR_NOTFOUND);
1199*0Sstevel@tonic-gate 		}
1200*0Sstevel@tonic-gate 	}
1201*0Sstevel@tonic-gate 
1202*0Sstevel@tonic-gate 	if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) {
1203*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: "
1204*0Sstevel@tonic-gate 		    "ddi_intr_get_pri failed, ret 0x%x\n", ret));
1205*0Sstevel@tonic-gate 
1206*0Sstevel@tonic-gate 		(void) ddi_intr_free(hdl);
1207*0Sstevel@tonic-gate 		return (DDI_FAILURE);
1208*0Sstevel@tonic-gate 	}
1209*0Sstevel@tonic-gate 
1210*0Sstevel@tonic-gate 	*iblock_cookiep = (ddi_iblock_cookie_t)(uint64_t)pri;
1211*0Sstevel@tonic-gate 	/* Free the handle allocated here only if no existing handle exists */
1212*0Sstevel@tonic-gate 	if (existing_hdlp == NULL)
1213*0Sstevel@tonic-gate 		(void) ddi_intr_free(hdl);
1214*0Sstevel@tonic-gate 
1215*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
1216*0Sstevel@tonic-gate }
1217*0Sstevel@tonic-gate 
1218*0Sstevel@tonic-gate int
1219*0Sstevel@tonic-gate ddi_add_intr(dev_info_t *dip, uint_t inumber,
1220*0Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep,
1221*0Sstevel@tonic-gate     ddi_idevice_cookie_t *idevice_cookiep,
1222*0Sstevel@tonic-gate     uint_t (*int_handler)(caddr_t int_handler_arg),
1223*0Sstevel@tonic-gate     caddr_t int_handler_arg)
1224*0Sstevel@tonic-gate {
1225*0Sstevel@tonic-gate 	ddi_intr_handle_t	*hdl_p;
1226*0Sstevel@tonic-gate 	int			actual, ret;
1227*0Sstevel@tonic-gate 	uint_t			pri;
1228*0Sstevel@tonic-gate 
1229*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: name=%s%d dip=0x%p "
1230*0Sstevel@tonic-gate 	    "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
1231*0Sstevel@tonic-gate 	    (void *)dip, inumber));
1232*0Sstevel@tonic-gate 
1233*0Sstevel@tonic-gate 	hdl_p = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP);
1234*0Sstevel@tonic-gate 
1235*0Sstevel@tonic-gate 	if ((ret = ddi_intr_alloc(dip, hdl_p, DDI_INTR_TYPE_FIXED,
1236*0Sstevel@tonic-gate 	    inumber, 1, &actual, 0)) != DDI_SUCCESS) {
1237*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
1238*0Sstevel@tonic-gate 		    "ddi_intr_alloc failed, ret 0x%x\n", ret));
1239*0Sstevel@tonic-gate 		kmem_free(hdl_p, sizeof (ddi_intr_handle_t));
1240*0Sstevel@tonic-gate 		return (DDI_INTR_NOTFOUND);
1241*0Sstevel@tonic-gate 	}
1242*0Sstevel@tonic-gate 
1243*0Sstevel@tonic-gate 	if ((ret = ddi_intr_get_pri(hdl_p[0], &pri)) != DDI_SUCCESS)  {
1244*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
1245*0Sstevel@tonic-gate 		    "ddi_intr_get_pri failed, ret 0x%x\n", ret));
1246*0Sstevel@tonic-gate 		(void) ddi_intr_free(hdl_p[0]);
1247*0Sstevel@tonic-gate 		kmem_free(hdl_p, sizeof (ddi_intr_handle_t));
1248*0Sstevel@tonic-gate 		return (DDI_FAILURE);
1249*0Sstevel@tonic-gate 	}
1250*0Sstevel@tonic-gate 
1251*0Sstevel@tonic-gate 	if ((ret = ddi_intr_add_handler(hdl_p[0], (ddi_intr_handler_t *)
1252*0Sstevel@tonic-gate 	    int_handler, int_handler_arg, NULL)) != DDI_SUCCESS) {
1253*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
1254*0Sstevel@tonic-gate 		    "ddi_intr_add_handler failed, ret 0x%x\n", ret));
1255*0Sstevel@tonic-gate 		(void) ddi_intr_free(hdl_p[0]);
1256*0Sstevel@tonic-gate 		kmem_free(hdl_p, sizeof (ddi_intr_handle_t));
1257*0Sstevel@tonic-gate 		return (DDI_FAILURE);
1258*0Sstevel@tonic-gate 	}
1259*0Sstevel@tonic-gate 
1260*0Sstevel@tonic-gate 	if ((ret = ddi_intr_enable(hdl_p[0])) != DDI_SUCCESS) {
1261*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
1262*0Sstevel@tonic-gate 		    "ddi_intr_enable failed, ret 0x%x\n", ret));
1263*0Sstevel@tonic-gate 		(void) ddi_intr_remove_handler(hdl_p[0]);
1264*0Sstevel@tonic-gate 		(void) ddi_intr_free(hdl_p[0]);
1265*0Sstevel@tonic-gate 		kmem_free(hdl_p, sizeof (ddi_intr_handle_t));
1266*0Sstevel@tonic-gate 		return (DDI_FAILURE);
1267*0Sstevel@tonic-gate 	}
1268*0Sstevel@tonic-gate 
1269*0Sstevel@tonic-gate 	if (iblock_cookiep)
1270*0Sstevel@tonic-gate 		*iblock_cookiep = (ddi_iblock_cookie_t)(uint64_t)pri;
1271*0Sstevel@tonic-gate 
1272*0Sstevel@tonic-gate 	if (idevice_cookiep) {
1273*0Sstevel@tonic-gate 		idevice_cookiep->idev_vector = 0;
1274*0Sstevel@tonic-gate 		idevice_cookiep->idev_priority = pri;
1275*0Sstevel@tonic-gate 	}
1276*0Sstevel@tonic-gate 
1277*0Sstevel@tonic-gate 	/* this line may be removed in near future */
1278*0Sstevel@tonic-gate 	i_ddi_set_intr_handle(dip, inumber, hdl_p);
1279*0Sstevel@tonic-gate 
1280*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
1281*0Sstevel@tonic-gate }
1282*0Sstevel@tonic-gate 
1283*0Sstevel@tonic-gate /* ARGSUSED */
1284*0Sstevel@tonic-gate int
1285*0Sstevel@tonic-gate ddi_add_fastintr(dev_info_t *dip, uint_t inumber,
1286*0Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep,
1287*0Sstevel@tonic-gate     ddi_idevice_cookie_t *idevice_cookiep,
1288*0Sstevel@tonic-gate     uint_t (*hi_int_handler)(void))
1289*0Sstevel@tonic-gate {
1290*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_fastintr: name=%s%d dip=0x%p "
1291*0Sstevel@tonic-gate 	    "inum=0x%x: Not supported, return failure\n", ddi_driver_name(dip),
1292*0Sstevel@tonic-gate 	    ddi_get_instance(dip), (void *)dip, inumber));
1293*0Sstevel@tonic-gate 
1294*0Sstevel@tonic-gate 	return (DDI_FAILURE);
1295*0Sstevel@tonic-gate }
1296*0Sstevel@tonic-gate 
1297*0Sstevel@tonic-gate /* ARGSUSED */
1298*0Sstevel@tonic-gate void
1299*0Sstevel@tonic-gate ddi_remove_intr(dev_info_t *dip, uint_t inum, ddi_iblock_cookie_t iblock_cookie)
1300*0Sstevel@tonic-gate {
1301*0Sstevel@tonic-gate 	ddi_intr_handle_t	*hdl_p;
1302*0Sstevel@tonic-gate 	int			ret;
1303*0Sstevel@tonic-gate 
1304*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: name=%s%d dip=0x%p "
1305*0Sstevel@tonic-gate 	    "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
1306*0Sstevel@tonic-gate 	    (void *)dip, inum));
1307*0Sstevel@tonic-gate 
1308*0Sstevel@tonic-gate 	if ((hdl_p = i_ddi_get_intr_handle(dip, inum)) == NULL) {
1309*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: no handle "
1310*0Sstevel@tonic-gate 		    "found\n"));
1311*0Sstevel@tonic-gate 		return;
1312*0Sstevel@tonic-gate 	}
1313*0Sstevel@tonic-gate 
1314*0Sstevel@tonic-gate 	if ((ret = ddi_intr_disable(hdl_p[0])) != DDI_SUCCESS) {
1315*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
1316*0Sstevel@tonic-gate 		    "ddi_intr_disable failed, ret 0x%x\n", ret));
1317*0Sstevel@tonic-gate 		return;
1318*0Sstevel@tonic-gate 	}
1319*0Sstevel@tonic-gate 
1320*0Sstevel@tonic-gate 	if ((ret = ddi_intr_remove_handler(hdl_p[0])) != DDI_SUCCESS) {
1321*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
1322*0Sstevel@tonic-gate 		    "ddi_intr_remove_handler failed, ret 0x%x\n", ret));
1323*0Sstevel@tonic-gate 		return;
1324*0Sstevel@tonic-gate 	}
1325*0Sstevel@tonic-gate 
1326*0Sstevel@tonic-gate 	if ((ret = ddi_intr_free(hdl_p[0])) != DDI_SUCCESS) {
1327*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
1328*0Sstevel@tonic-gate 		    "ddi_intr_free failed, ret 0x%x\n", ret));
1329*0Sstevel@tonic-gate 		return;
1330*0Sstevel@tonic-gate 	}
1331*0Sstevel@tonic-gate 
1332*0Sstevel@tonic-gate 	kmem_free(hdl_p, sizeof (ddi_intr_handle_t));
1333*0Sstevel@tonic-gate 
1334*0Sstevel@tonic-gate 	/* this line may be removed in near future */
1335*0Sstevel@tonic-gate 	i_ddi_set_intr_handle(dip, inum, NULL);
1336*0Sstevel@tonic-gate }
1337*0Sstevel@tonic-gate 
1338*0Sstevel@tonic-gate /* ARGSUSED */
1339*0Sstevel@tonic-gate int
1340*0Sstevel@tonic-gate ddi_get_soft_iblock_cookie(dev_info_t *dip, int preference,
1341*0Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep)
1342*0Sstevel@tonic-gate {
1343*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_get_soft_iblock_cookie: name=%s%d "
1344*0Sstevel@tonic-gate 	    "dip=0x%p pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
1345*0Sstevel@tonic-gate 	    (void *)dip, preference));
1346*0Sstevel@tonic-gate 
1347*0Sstevel@tonic-gate 	ASSERT(iblock_cookiep != NULL);
1348*0Sstevel@tonic-gate 
1349*0Sstevel@tonic-gate 	if (preference == DDI_SOFTINT_FIXED)
1350*0Sstevel@tonic-gate 		return (DDI_FAILURE);
1351*0Sstevel@tonic-gate 
1352*0Sstevel@tonic-gate 	*iblock_cookiep = (ddi_iblock_cookie_t)((uint64_t)
1353*0Sstevel@tonic-gate 	    ((preference > DDI_SOFTINT_MED) ? DDI_SOFT_INTR_PRI_H :
1354*0Sstevel@tonic-gate 	    DDI_SOFT_INTR_PRI_M));
1355*0Sstevel@tonic-gate 
1356*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
1357*0Sstevel@tonic-gate }
1358*0Sstevel@tonic-gate 
1359*0Sstevel@tonic-gate int
1360*0Sstevel@tonic-gate ddi_add_softintr(dev_info_t *dip, int preference, ddi_softintr_t *idp,
1361*0Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep,
1362*0Sstevel@tonic-gate     ddi_idevice_cookie_t *idevice_cookiep,
1363*0Sstevel@tonic-gate     uint_t (*int_handler)(caddr_t int_handler_arg),
1364*0Sstevel@tonic-gate     caddr_t int_handler_arg)
1365*0Sstevel@tonic-gate {
1366*0Sstevel@tonic-gate 	ddi_softint_handle_t	*hdl_p;
1367*0Sstevel@tonic-gate 	uint64_t		softpri;
1368*0Sstevel@tonic-gate 	int			ret;
1369*0Sstevel@tonic-gate 
1370*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: name=%s%d dip=0x%p "
1371*0Sstevel@tonic-gate 	    "pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
1372*0Sstevel@tonic-gate 	    (void *)dip, preference));
1373*0Sstevel@tonic-gate 
1374*0Sstevel@tonic-gate 	if ((idp == NULL) || ((preference == DDI_SOFTINT_FIXED) &&
1375*0Sstevel@tonic-gate 	    (iblock_cookiep == NULL)))
1376*0Sstevel@tonic-gate 		return (DDI_FAILURE);
1377*0Sstevel@tonic-gate 
1378*0Sstevel@tonic-gate 	/* Translate the priority preference */
1379*0Sstevel@tonic-gate 	if (preference == DDI_SOFTINT_FIXED) {
1380*0Sstevel@tonic-gate 		softpri = (uint64_t)*iblock_cookiep;
1381*0Sstevel@tonic-gate 		softpri = MIN(softpri, DDI_SOFT_INTR_PRI_H);
1382*0Sstevel@tonic-gate 	} else {
1383*0Sstevel@tonic-gate 		softpri = (uint64_t)((preference > DDI_SOFTINT_MED) ?
1384*0Sstevel@tonic-gate 		    DDI_SOFT_INTR_PRI_H : DDI_SOFT_INTR_PRI_M);
1385*0Sstevel@tonic-gate 	}
1386*0Sstevel@tonic-gate 
1387*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: preference 0x%x "
1388*0Sstevel@tonic-gate 	    "softpri 0x%lx\n", preference, (long)softpri));
1389*0Sstevel@tonic-gate 
1390*0Sstevel@tonic-gate 	hdl_p = kmem_zalloc(sizeof (ddi_softint_handle_t), KM_SLEEP);
1391*0Sstevel@tonic-gate 	if ((ret = ddi_intr_add_softint(dip, hdl_p, softpri,
1392*0Sstevel@tonic-gate 	    (ddi_intr_handler_t *)int_handler, int_handler_arg)) !=
1393*0Sstevel@tonic-gate 	    DDI_SUCCESS) {
1394*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: "
1395*0Sstevel@tonic-gate 		    "ddi_intr_add_softint failed, ret 0x%x\n", ret));
1396*0Sstevel@tonic-gate 
1397*0Sstevel@tonic-gate 		kmem_free(hdl_p, sizeof (ddi_softint_handle_t));
1398*0Sstevel@tonic-gate 		return (DDI_FAILURE);
1399*0Sstevel@tonic-gate 	}
1400*0Sstevel@tonic-gate 
1401*0Sstevel@tonic-gate 	if (iblock_cookiep)
1402*0Sstevel@tonic-gate 		*iblock_cookiep = (ddi_iblock_cookie_t)softpri;
1403*0Sstevel@tonic-gate 
1404*0Sstevel@tonic-gate 	if (idevice_cookiep) {
1405*0Sstevel@tonic-gate 		idevice_cookiep->idev_vector = 0;
1406*0Sstevel@tonic-gate 		idevice_cookiep->idev_priority = softpri;
1407*0Sstevel@tonic-gate 	}
1408*0Sstevel@tonic-gate 
1409*0Sstevel@tonic-gate 	*idp = (ddi_softintr_t)hdl_p;
1410*0Sstevel@tonic-gate 
1411*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: dip = 0x%p, "
1412*0Sstevel@tonic-gate 	    "idp = 0x%p, ret = %x\n", (void *)dip, (void *)*idp, ret));
1413*0Sstevel@tonic-gate 
1414*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
1415*0Sstevel@tonic-gate }
1416*0Sstevel@tonic-gate 
1417*0Sstevel@tonic-gate void
1418*0Sstevel@tonic-gate ddi_remove_softintr(ddi_softintr_t id)
1419*0Sstevel@tonic-gate {
1420*0Sstevel@tonic-gate 	ddi_softint_handle_t	*h_p = (ddi_softint_handle_t *)id;
1421*0Sstevel@tonic-gate 
1422*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: id=0x%p\n",
1423*0Sstevel@tonic-gate 	    (void *)id));
1424*0Sstevel@tonic-gate 
1425*0Sstevel@tonic-gate 	if (h_p == NULL)
1426*0Sstevel@tonic-gate 		return;
1427*0Sstevel@tonic-gate 
1428*0Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: handle 0x%p\n",
1429*0Sstevel@tonic-gate 	    (void *)h_p));
1430*0Sstevel@tonic-gate 
1431*0Sstevel@tonic-gate 	(void) ddi_intr_remove_softint(*h_p);
1432*0Sstevel@tonic-gate 	kmem_free(h_p, sizeof (ddi_softint_handle_t));
1433*0Sstevel@tonic-gate }
1434*0Sstevel@tonic-gate 
1435*0Sstevel@tonic-gate void
1436*0Sstevel@tonic-gate ddi_trigger_softintr(ddi_softintr_t id)
1437*0Sstevel@tonic-gate {
1438*0Sstevel@tonic-gate 	ddi_softint_handle_t	*h_p = (ddi_softint_handle_t *)id;
1439*0Sstevel@tonic-gate 	int			ret;
1440*0Sstevel@tonic-gate 
1441*0Sstevel@tonic-gate 	if (h_p == NULL)
1442*0Sstevel@tonic-gate 		return;
1443*0Sstevel@tonic-gate 
1444*0Sstevel@tonic-gate 	if ((ret = ddi_intr_trigger_softint(*h_p, NULL)) != DDI_SUCCESS) {
1445*0Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_trigger_softintr: "
1446*0Sstevel@tonic-gate 		    "ddi_intr_trigger_softint failed, hdlp 0x%p "
1447*0Sstevel@tonic-gate 		    "ret 0x%x\n", (void *)h_p, ret));
1448*0Sstevel@tonic-gate 	}
1449*0Sstevel@tonic-gate }
1450