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