xref: /illumos-gate/usr/src/uts/common/os/ddi_intr.c (revision cfb1a455e1728db1d033a1b878ef9b1226e532ab)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <sys/note.h>
307c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate #include <sys/param.h>
337c478bd9Sstevel@tonic-gate #include <sys/systm.h>
347c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
357c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
367c478bd9Sstevel@tonic-gate #include <sys/debug.h>
377c478bd9Sstevel@tonic-gate #include <sys/avintr.h>
387c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
397c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
407c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h>	/* include prototypes */
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate  * New DDI interrupt framework
447c478bd9Sstevel@tonic-gate  */
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate /*
477c478bd9Sstevel@tonic-gate  * MSI/X allocation limit.
487c478bd9Sstevel@tonic-gate  * This limit will change with Resource Management support.
497c478bd9Sstevel@tonic-gate  */
507c478bd9Sstevel@tonic-gate uint_t		ddi_msix_alloc_limit = 2;
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate /*
537c478bd9Sstevel@tonic-gate  * ddi_intr_get_supported_types:
547c478bd9Sstevel@tonic-gate  *	Return, as a bit mask, the hardware interrupt types supported by
557c478bd9Sstevel@tonic-gate  *	both the device and by the host in the integer pointed
567c478bd9Sstevel@tonic-gate  *	to be the 'typesp' argument.
577c478bd9Sstevel@tonic-gate  */
587c478bd9Sstevel@tonic-gate int
597c478bd9Sstevel@tonic-gate ddi_intr_get_supported_types(dev_info_t *dip, int *typesp)
607c478bd9Sstevel@tonic-gate {
617c478bd9Sstevel@tonic-gate 	int			ret;
627c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	hdl;
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate 	if (dip == NULL)
657c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: dip %p\n",
687c478bd9Sstevel@tonic-gate 	    (void *)dip));
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate 	if (*typesp = i_ddi_intr_get_supported_types(dip))
717c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 	bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
747c478bd9Sstevel@tonic-gate 	hdl.ih_dip = dip;
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(dip, dip, DDI_INTROP_SUPPORTED_TYPES, &hdl,
777c478bd9Sstevel@tonic-gate 	    (void *)typesp);
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS)
807c478bd9Sstevel@tonic-gate 		return (DDI_INTR_NOTFOUND);
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: types %x\n",
837c478bd9Sstevel@tonic-gate 	    *typesp));
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	return (ret);
867c478bd9Sstevel@tonic-gate }
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate /*
907c478bd9Sstevel@tonic-gate  * ddi_intr_get_nintrs:
917c478bd9Sstevel@tonic-gate  * 	Return as an integer in the integer pointed to by the argument
927c478bd9Sstevel@tonic-gate  * 	*nintrsp*, the number of interrupts the device supports for the
937c478bd9Sstevel@tonic-gate  *	given interrupt type.
947c478bd9Sstevel@tonic-gate  */
957c478bd9Sstevel@tonic-gate int
967c478bd9Sstevel@tonic-gate ddi_intr_get_nintrs(dev_info_t *dip, int type, int *nintrsp)
977c478bd9Sstevel@tonic-gate {
987c478bd9Sstevel@tonic-gate 	int			ret;
997c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	hdl;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	if (dip == NULL)
1027c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs: dip %p\n",
1057c478bd9Sstevel@tonic-gate 	    (void *)dip));
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	if (!(i_ddi_intr_get_supported_types(dip) & type))
1087c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	if (*nintrsp = i_ddi_intr_get_supported_nintrs(dip, type))
1117c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
1147c478bd9Sstevel@tonic-gate 	hdl.ih_dip = dip;
1157c478bd9Sstevel@tonic-gate 	hdl.ih_type = type;
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(dip, dip, DDI_INTROP_NINTRS, &hdl,
1187c478bd9Sstevel@tonic-gate 	    (void *)nintrsp);
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs:: nintrs %x\n",
1217c478bd9Sstevel@tonic-gate 	    *nintrsp));
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	return (ret);
1247c478bd9Sstevel@tonic-gate }
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate /*
1287c478bd9Sstevel@tonic-gate  * ddi_intr_get_navail:
1297c478bd9Sstevel@tonic-gate  *	Bus nexus driver will return availble interrupt count value for
1307c478bd9Sstevel@tonic-gate  *	a given interrupt type.
1317c478bd9Sstevel@tonic-gate  *
1327c478bd9Sstevel@tonic-gate  * 	Return as an integer in the integer pointed to by the argument
1337c478bd9Sstevel@tonic-gate  * 	*navailp*, the number of interrupts currently available for the
1347c478bd9Sstevel@tonic-gate  *	given interrupt type.
1357c478bd9Sstevel@tonic-gate  */
1367c478bd9Sstevel@tonic-gate int
1377c478bd9Sstevel@tonic-gate ddi_intr_get_navail(dev_info_t *dip, int type, int *navailp)
1387c478bd9Sstevel@tonic-gate {
1397c478bd9Sstevel@tonic-gate 	int			ret;
1407c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	hdl;
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_navail: dip %p\n",
1437c478bd9Sstevel@tonic-gate 	    (void *)dip));
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	if (dip == NULL)
1467c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	if (!(i_ddi_intr_get_supported_types(dip) & type))
1497c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	/*
1527c478bd9Sstevel@tonic-gate 	 * In future, this interface implementation will change
1537c478bd9Sstevel@tonic-gate 	 * with Resource Management support.
1547c478bd9Sstevel@tonic-gate 	 */
1557c478bd9Sstevel@tonic-gate 	bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
1567c478bd9Sstevel@tonic-gate 	hdl.ih_dip = dip;
1577c478bd9Sstevel@tonic-gate 	hdl.ih_type = type;
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(dip, dip,
1607c478bd9Sstevel@tonic-gate 	    DDI_INTROP_NAVAIL, &hdl, (void *)navailp);
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	return (ret == DDI_SUCCESS ? DDI_SUCCESS : DDI_INTR_NOTFOUND);
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate /*
1677c478bd9Sstevel@tonic-gate  * Interrupt allocate/free functions
1687c478bd9Sstevel@tonic-gate  */
1697c478bd9Sstevel@tonic-gate int
1707c478bd9Sstevel@tonic-gate ddi_intr_alloc(dev_info_t *dip, ddi_intr_handle_t *h_array, int type, int inum,
1717c478bd9Sstevel@tonic-gate     int count, int *actualp, int behavior)
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp, tmp_hdl;
1747c478bd9Sstevel@tonic-gate 	int			i, ret, cap = 0, intr_type, nintrs = 0;
1757c478bd9Sstevel@tonic-gate 	uint_t			pri;
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: name %s dip 0x%p "
1787c478bd9Sstevel@tonic-gate 	    "type %x inum %x count %x behavior %x\n", ddi_driver_name(dip),
1797c478bd9Sstevel@tonic-gate 	    (void *)dip, type, inum, count, behavior));
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	/* Validate parameters */
1827c478bd9Sstevel@tonic-gate 	if (dip == NULL || h_array == NULL || count < 1) {
1837c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Invalid args\n"));
1847c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
1857c478bd9Sstevel@tonic-gate 	}
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	/* Validate interrupt type */
1887c478bd9Sstevel@tonic-gate 	if (!(i_ddi_intr_get_supported_types(dip) & type)) {
1897c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x not "
1907c478bd9Sstevel@tonic-gate 		    "supported\n", type));
1917c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
1927c478bd9Sstevel@tonic-gate 	}
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	/* First, get how many interrupts the device supports */
1957c478bd9Sstevel@tonic-gate 	if (!(nintrs = i_ddi_intr_get_supported_nintrs(dip, type))) {
1967c478bd9Sstevel@tonic-gate 		if (ddi_intr_get_nintrs(dip, type, &nintrs) != DDI_SUCCESS) {
1977c478bd9Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no "
1987c478bd9Sstevel@tonic-gate 			    "interrupts found of type %d\n", type));
1997c478bd9Sstevel@tonic-gate 			return (DDI_INTR_NOTFOUND);
2007c478bd9Sstevel@tonic-gate 		}
2017c478bd9Sstevel@tonic-gate 	}
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	/* Is this function invoked with more interrupt than device supports? */
2047c478bd9Sstevel@tonic-gate 	if (count > nintrs) {
2057c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no of interrupts "
2067c478bd9Sstevel@tonic-gate 		    "requested %d is more than supported %d\n", count, nintrs));
2077c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	/*
2117c478bd9Sstevel@tonic-gate 	 * Check if requested interrupt type is not same as interrupt
2127c478bd9Sstevel@tonic-gate 	 * type is in use if any.
2137c478bd9Sstevel@tonic-gate 	 */
2147c478bd9Sstevel@tonic-gate 	if (((intr_type = i_ddi_intr_get_current_type(dip)) != 0) &&
2157c478bd9Sstevel@tonic-gate 	    (intr_type != type)) {
2167c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Requested "
2177c478bd9Sstevel@tonic-gate 		    "interrupt type %x is different from interrupt type %x"
2187c478bd9Sstevel@tonic-gate 		    "already in use\n", type, intr_type));
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
2217c478bd9Sstevel@tonic-gate 	}
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	/*
2247c478bd9Sstevel@tonic-gate 	 * Check if requested interrupt type is in use and requested number
2257c478bd9Sstevel@tonic-gate 	 * of interrupts and number of interrupts already in use exceeds the
2267c478bd9Sstevel@tonic-gate 	 * number of interrupts supported by this device.
2277c478bd9Sstevel@tonic-gate 	 */
2287c478bd9Sstevel@tonic-gate 	if (intr_type) {
2297c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x "
2307c478bd9Sstevel@tonic-gate 		    "is already being used\n", type));
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 		if ((count + i_ddi_intr_get_current_nintrs(dip)) > nintrs) {
2337c478bd9Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: count %d "
2347c478bd9Sstevel@tonic-gate 			    "+ intrs in use %d exceeds supported %d intrs\n",
2357c478bd9Sstevel@tonic-gate 			    count, i_ddi_intr_get_current_nintrs(dip), nintrs));
2367c478bd9Sstevel@tonic-gate 			return (DDI_EINVAL);
2377c478bd9Sstevel@tonic-gate 		}
2387c478bd9Sstevel@tonic-gate 	}
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	/*
2417c478bd9Sstevel@tonic-gate 	 * For MSI, ensure that the requested interrupt count is a power of 2
2427c478bd9Sstevel@tonic-gate 	 */
2437c478bd9Sstevel@tonic-gate 	if (type == DDI_INTR_TYPE_MSI && !ISP2(count)) {
2447c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: "
2457c478bd9Sstevel@tonic-gate 		    "MSI count %d is not a power of two\n", count));
2467c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	/*
2507c478bd9Sstevel@tonic-gate 	 * Limit max MSI/X allocation to ddi_msix_alloc_limit.
2517c478bd9Sstevel@tonic-gate 	 * This limit will change with Resource Management support.
2527c478bd9Sstevel@tonic-gate 	 */
2537c478bd9Sstevel@tonic-gate 	if (DDI_INTR_IS_MSI_OR_MSIX(type) && (count > ddi_msix_alloc_limit)) {
2547c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Requested MSI/Xs %d"
2557c478bd9Sstevel@tonic-gate 		    "Max MSI/Xs limit %d\n", count, ddi_msix_alloc_limit));
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 		if (behavior == DDI_INTR_ALLOC_STRICT) {
2587c478bd9Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: "
2597c478bd9Sstevel@tonic-gate 			    "DDI_INTR_ALLOC_STRICT flag is passed, "
2607c478bd9Sstevel@tonic-gate 			    "return failure\n"));
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 			return (DDI_EAGAIN);
2637c478bd9Sstevel@tonic-gate 		}
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 		count = ddi_msix_alloc_limit;
2667c478bd9Sstevel@tonic-gate 	}
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	/* Now allocate required number of interrupts */
2697c478bd9Sstevel@tonic-gate 	bzero(&tmp_hdl, sizeof (ddi_intr_handle_impl_t));
2707c478bd9Sstevel@tonic-gate 	tmp_hdl.ih_type = type;
2717c478bd9Sstevel@tonic-gate 	tmp_hdl.ih_inum = inum;
2727c478bd9Sstevel@tonic-gate 	tmp_hdl.ih_scratch1 = count;
2737c478bd9Sstevel@tonic-gate 	tmp_hdl.ih_scratch2 = behavior;
2747c478bd9Sstevel@tonic-gate 	tmp_hdl.ih_dip = dip;
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	if (i_ddi_handle_intr_ops(dip, dip, DDI_INTROP_ALLOC,
2777c478bd9Sstevel@tonic-gate 	    &tmp_hdl, (void *)actualp) != DDI_SUCCESS) {
2787c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: allocation "
2797c478bd9Sstevel@tonic-gate 		    "failed\n"));
2807c478bd9Sstevel@tonic-gate 		return (*actualp ? DDI_EAGAIN : DDI_INTR_NOTFOUND);
2817c478bd9Sstevel@tonic-gate 	}
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	if ((ret = i_ddi_handle_intr_ops(dip, dip, DDI_INTROP_GETPRI,
2847c478bd9Sstevel@tonic-gate 	    &tmp_hdl, (void *)&pri)) != DDI_SUCCESS) {
2857c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get priority "
2867c478bd9Sstevel@tonic-gate 		    "failed\n"));
2877c478bd9Sstevel@tonic-gate 		return (ret);
2887c478bd9Sstevel@tonic-gate 	}
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: getting capability\n"));
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	if ((ret = i_ddi_handle_intr_ops(dip, dip, DDI_INTROP_GETCAP,
2937c478bd9Sstevel@tonic-gate 	    &tmp_hdl, (void *)&cap)) != DDI_SUCCESS) {
2947c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get capability "
2957c478bd9Sstevel@tonic-gate 		    "failed\n"));
2967c478bd9Sstevel@tonic-gate 		return (ret);
2977c478bd9Sstevel@tonic-gate 	}
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	/* Save current interrupt type, supported and current intr count */
3007c478bd9Sstevel@tonic-gate 	i_ddi_intr_devi_init(dip);
3017c478bd9Sstevel@tonic-gate 	i_ddi_intr_set_current_type(dip, type);
3027c478bd9Sstevel@tonic-gate 	i_ddi_intr_set_supported_nintrs(dip, nintrs);
3037c478bd9Sstevel@tonic-gate 	i_ddi_intr_set_current_nintrs(dip,
3047c478bd9Sstevel@tonic-gate 	    i_ddi_intr_get_current_nintrs(dip) + *actualp);
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	/* Now, go and handle each "handle" */
3077c478bd9Sstevel@tonic-gate 	for (i = 0; i < *actualp; i++) {
3087c478bd9Sstevel@tonic-gate 		hdlp = (ddi_intr_handle_impl_t *)kmem_zalloc(
3097c478bd9Sstevel@tonic-gate 		    (sizeof (ddi_intr_handle_impl_t)), KM_SLEEP);
3107c478bd9Sstevel@tonic-gate 		rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
3117c478bd9Sstevel@tonic-gate 		h_array[i] = (struct __ddi_intr_handle *)hdlp;
3127c478bd9Sstevel@tonic-gate 		hdlp->ih_type = type;
3137c478bd9Sstevel@tonic-gate 		hdlp->ih_pri = pri;
3147c478bd9Sstevel@tonic-gate 		hdlp->ih_cap = cap;
3157c478bd9Sstevel@tonic-gate 		hdlp->ih_ver = DDI_INTR_VERSION;
3167c478bd9Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ALLOC;
3177c478bd9Sstevel@tonic-gate 		hdlp->ih_dip = dip;
3187c478bd9Sstevel@tonic-gate 		hdlp->ih_inum = inum + i;
3197c478bd9Sstevel@tonic-gate 		if (type & DDI_INTR_TYPE_FIXED)
320*cfb1a455Segillett 			i_ddi_set_intr_handle(dip, hdlp->ih_inum, &h_array[i]);
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: hdlp = 0x%p\n",
3237c478bd9Sstevel@tonic-gate 		    (void *)h_array[i]));
3247c478bd9Sstevel@tonic-gate 	}
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate int
3317c478bd9Sstevel@tonic-gate ddi_intr_free(ddi_intr_handle_t h)
3327c478bd9Sstevel@tonic-gate {
3337c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
3347c478bd9Sstevel@tonic-gate 	int			ret;
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_free: hdlp = %p\n", (void *)hdlp));
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
3397c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
3427c478bd9Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
3437c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
3447c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
3457c478bd9Sstevel@tonic-gate 	}
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
3487c478bd9Sstevel@tonic-gate 	    DDI_INTROP_FREE, hdlp, NULL);
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
3517c478bd9Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
3527c478bd9Sstevel@tonic-gate 		if ((i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1) == 0)
3537c478bd9Sstevel@tonic-gate 			/* Reset current interrupt type and count used */
3547c478bd9Sstevel@tonic-gate 			i_ddi_intr_set_current_type(hdlp->ih_dip, 0);
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 		i_ddi_intr_set_current_nintrs(hdlp->ih_dip,
3577c478bd9Sstevel@tonic-gate 		    i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1);
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 		if (hdlp->ih_type & DDI_INTR_TYPE_FIXED)
3607c478bd9Sstevel@tonic-gate 			i_ddi_set_intr_handle(hdlp->ih_dip,
3617c478bd9Sstevel@tonic-gate 			    hdlp->ih_inum, NULL);
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 		rw_destroy(&hdlp->ih_rwlock);
3647c478bd9Sstevel@tonic-gate 		kmem_free(hdlp, sizeof (ddi_intr_handle_impl_t));
3657c478bd9Sstevel@tonic-gate 	}
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	return (ret);
3687c478bd9Sstevel@tonic-gate }
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate /*
3717c478bd9Sstevel@tonic-gate  * Interrupt get/set capacity functions
3727c478bd9Sstevel@tonic-gate  *
3737c478bd9Sstevel@tonic-gate  * The logic used to figure this out is shown here:
3747c478bd9Sstevel@tonic-gate  *
3757c478bd9Sstevel@tonic-gate  *			Device level		Platform level	    Intr source
3767c478bd9Sstevel@tonic-gate  * 1. Fixed interrupts
3777c478bd9Sstevel@tonic-gate  * (non-PCI)
3787c478bd9Sstevel@tonic-gate  * o Flags supported	N/A			Maskable/Pending/    rootnex
3797c478bd9Sstevel@tonic-gate  *						No Block Enable
3807c478bd9Sstevel@tonic-gate  * o navail					1
3817c478bd9Sstevel@tonic-gate  *
3827c478bd9Sstevel@tonic-gate  * 2. PCI Fixed interrupts
3837c478bd9Sstevel@tonic-gate  * o Flags supported	pending/Maskable	Maskable/pending/    pci
3847c478bd9Sstevel@tonic-gate  *						No Block enable
3857c478bd9Sstevel@tonic-gate  * o navail		N/A			1
3867c478bd9Sstevel@tonic-gate  *
3877c478bd9Sstevel@tonic-gate  * 3. PCI MSI
3887c478bd9Sstevel@tonic-gate  * o Flags supported	Maskable/Pending	Maskable/Pending    pci
3897c478bd9Sstevel@tonic-gate  *			Block Enable		(if drvr doesn't)   Block Enable
3907c478bd9Sstevel@tonic-gate  * o navail		N/A			#vectors - #used    N/A
3917c478bd9Sstevel@tonic-gate  *
3927c478bd9Sstevel@tonic-gate  * 4. PCI MSI-X
3937c478bd9Sstevel@tonic-gate  * o Flags supported	Maskable/Pending	Maskable/Pending    pci
3947c478bd9Sstevel@tonic-gate  *			Block Enable				    Block Enable
3957c478bd9Sstevel@tonic-gate  * o navail		N/A			#vectors - #used    N/A
3967c478bd9Sstevel@tonic-gate  *
3977c478bd9Sstevel@tonic-gate  * where:
3987c478bd9Sstevel@tonic-gate  *	#vectors	- Total numbers of vectors available
3997c478bd9Sstevel@tonic-gate  *	#used		- Total numbers of vectors currently being used
4007c478bd9Sstevel@tonic-gate  *
4017c478bd9Sstevel@tonic-gate  * For devices complying to PCI2.3 or greater, see bit10 of Command Register
4027c478bd9Sstevel@tonic-gate  * 0 - enables assertion of INTx
4037c478bd9Sstevel@tonic-gate  * 1 - disables assertion of INTx
4047c478bd9Sstevel@tonic-gate  *
4057c478bd9Sstevel@tonic-gate  * For non MSI/X interrupts; if the IRQ is shared then all ddi_intr_set_*()
4067c478bd9Sstevel@tonic-gate  * operations return failure.
4077c478bd9Sstevel@tonic-gate  */
4087c478bd9Sstevel@tonic-gate int
4097c478bd9Sstevel@tonic-gate ddi_intr_get_cap(ddi_intr_handle_t h, int *flagsp)
4107c478bd9Sstevel@tonic-gate {
4117c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
4127c478bd9Sstevel@tonic-gate 	int			ret;
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_cap: hdlp = %p\n",
4157c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	*flagsp = 0;
4187c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
4197c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	if (hdlp->ih_cap) {
4247c478bd9Sstevel@tonic-gate 		*flagsp = hdlp->ih_cap & ~DDI_INTR_FLAG_MSI64;
4257c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
4267c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
4277c478bd9Sstevel@tonic-gate 	}
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
4307c478bd9Sstevel@tonic-gate 	    DDI_INTROP_GETCAP, hdlp, (void *)flagsp);
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
4337c478bd9Sstevel@tonic-gate 		hdlp->ih_cap = *flagsp;
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 		/* Mask out MSI/X 64-bit support to the consumer */
4367c478bd9Sstevel@tonic-gate 		*flagsp &= ~DDI_INTR_FLAG_MSI64;
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
4407c478bd9Sstevel@tonic-gate 	return (ret);
4417c478bd9Sstevel@tonic-gate }
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate int
4447c478bd9Sstevel@tonic-gate ddi_intr_set_cap(ddi_intr_handle_t h, int flags)
4457c478bd9Sstevel@tonic-gate {
4467c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
4477c478bd9Sstevel@tonic-gate 	int			ret;
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_cap: hdlp = %p", (void *)hdlp));
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
4527c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
4557c478bd9Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
4567c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
4577c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
4587c478bd9Sstevel@tonic-gate 	}
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	/* Only DDI_INTR_FLAG_LEVEL or DDI_INTR_FLAG_EDGE are allowed */
4617c478bd9Sstevel@tonic-gate 	if (!(flags & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) {
4627c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "%s%d: only LEVEL or EDGE capability "
4637c478bd9Sstevel@tonic-gate 		    "can be set\n", ddi_driver_name(hdlp->ih_dip),
4647c478bd9Sstevel@tonic-gate 		    ddi_get_instance(hdlp->ih_dip)));
4657c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
4667c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
4677c478bd9Sstevel@tonic-gate 	}
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	/* Both level/edge flags must be currently supported */
4707c478bd9Sstevel@tonic-gate 	if (!(hdlp->ih_cap & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) {
4717c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "%s%d: Both LEVEL and EDGE capability"
4727c478bd9Sstevel@tonic-gate 		    " must be supported\n", ddi_driver_name(hdlp->ih_dip),
4737c478bd9Sstevel@tonic-gate 		    ddi_get_instance(hdlp->ih_dip)));
4747c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
4757c478bd9Sstevel@tonic-gate 		return (DDI_ENOTSUP);
4767c478bd9Sstevel@tonic-gate 	}
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
4797c478bd9Sstevel@tonic-gate 	    DDI_INTROP_SETCAP, hdlp, &flags);
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
4827c478bd9Sstevel@tonic-gate 	return (ret);
4837c478bd9Sstevel@tonic-gate }
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate /*
4867c478bd9Sstevel@tonic-gate  * Priority related functions
4877c478bd9Sstevel@tonic-gate  */
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate /*
4907c478bd9Sstevel@tonic-gate  * ddi_intr_get_hilevel_pri:
4917c478bd9Sstevel@tonic-gate  *	Returns the minimum priority level for a
4927c478bd9Sstevel@tonic-gate  *	high-level interrupt on a platform.
4937c478bd9Sstevel@tonic-gate  */
4947c478bd9Sstevel@tonic-gate uint_t
4957c478bd9Sstevel@tonic-gate ddi_intr_get_hilevel_pri(void)
4967c478bd9Sstevel@tonic-gate {
4977c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_hilevel_pri:\n"));
4987c478bd9Sstevel@tonic-gate 	return (LOCK_LEVEL + 1);
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate int
5027c478bd9Sstevel@tonic-gate ddi_intr_get_pri(ddi_intr_handle_t h, uint_t *prip)
5037c478bd9Sstevel@tonic-gate {
5047c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
5057c478bd9Sstevel@tonic-gate 	int			ret;
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pri: hdlp = %p\n",
5087c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	*prip = 0;
5117c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
5127c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
5157c478bd9Sstevel@tonic-gate 	/* Already initialized, just return that */
5167c478bd9Sstevel@tonic-gate 	if (hdlp->ih_pri) {
5177c478bd9Sstevel@tonic-gate 		*prip = hdlp->ih_pri;
5187c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
5197c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
5207c478bd9Sstevel@tonic-gate 	}
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
5237c478bd9Sstevel@tonic-gate 	    DDI_INTROP_GETPRI, hdlp, (void *)prip);
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	if (ret == DDI_SUCCESS)
5267c478bd9Sstevel@tonic-gate 		hdlp->ih_pri = *prip;
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
5297c478bd9Sstevel@tonic-gate 	return (ret);
5307c478bd9Sstevel@tonic-gate }
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate int
5337c478bd9Sstevel@tonic-gate ddi_intr_set_pri(ddi_intr_handle_t h, uint_t pri)
5347c478bd9Sstevel@tonic-gate {
5357c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
5367c478bd9Sstevel@tonic-gate 	int			ret;
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: hdlp = %p", (void *)hdlp));
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
5417c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	/* Validate priority argument */
5447c478bd9Sstevel@tonic-gate 	if (pri < DDI_INTR_PRI_MIN || pri > DDI_INTR_PRI_MAX) {
5457c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: invalid priority "
5467c478bd9Sstevel@tonic-gate 		    "specified  = %x\n", pri));
5477c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
5487c478bd9Sstevel@tonic-gate 	}
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
5517c478bd9Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
5527c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
5537c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
5547c478bd9Sstevel@tonic-gate 	}
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	/* If the passed priority is same as existing priority; do nothing */
5577c478bd9Sstevel@tonic-gate 	if (pri == hdlp->ih_pri) {
5587c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
5597c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
5607c478bd9Sstevel@tonic-gate 	}
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
5637c478bd9Sstevel@tonic-gate 	    DDI_INTROP_SETPRI, hdlp, &pri);
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	if (ret == DDI_SUCCESS)
5667c478bd9Sstevel@tonic-gate 		hdlp->ih_pri = pri;
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
5697c478bd9Sstevel@tonic-gate 	return (ret);
5707c478bd9Sstevel@tonic-gate }
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate /*
5737c478bd9Sstevel@tonic-gate  * Interrupt add/duplicate/remove handlers
5747c478bd9Sstevel@tonic-gate  */
5757c478bd9Sstevel@tonic-gate int
5767c478bd9Sstevel@tonic-gate ddi_intr_add_handler(ddi_intr_handle_t h, ddi_intr_handler_t inthandler,
5777c478bd9Sstevel@tonic-gate     void *arg1, void *arg2)
5787c478bd9Sstevel@tonic-gate {
5797c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
5807c478bd9Sstevel@tonic-gate 	int			ret;
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_handler: hdlp = 0x%p\n",
5837c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	if ((hdlp == NULL) || (inthandler == NULL))
5867c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
5897c478bd9Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
5907c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
5917c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
5927c478bd9Sstevel@tonic-gate 	}
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	hdlp->ih_cb_func = inthandler;
5957c478bd9Sstevel@tonic-gate 	hdlp->ih_cb_arg1 = arg1;
5967c478bd9Sstevel@tonic-gate 	hdlp->ih_cb_arg2 = arg2;
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
5997c478bd9Sstevel@tonic-gate 	    DDI_INTROP_ADDISR, hdlp, NULL);
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
6027c478bd9Sstevel@tonic-gate 		hdlp->ih_cb_func = NULL;
6037c478bd9Sstevel@tonic-gate 		hdlp->ih_cb_arg1 = NULL;
6047c478bd9Sstevel@tonic-gate 		hdlp->ih_cb_arg2 = NULL;
6057c478bd9Sstevel@tonic-gate 	} else
6067c478bd9Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ADDED;
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
6097c478bd9Sstevel@tonic-gate 	return (ret);
6107c478bd9Sstevel@tonic-gate }
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate int
6137c478bd9Sstevel@tonic-gate ddi_intr_dup_handler(ddi_intr_handle_t org, int vector, ddi_intr_handle_t *dup)
6147c478bd9Sstevel@tonic-gate {
6157c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)org;
6167c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*dup_hdlp;
6177c478bd9Sstevel@tonic-gate 	int			ret;
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_dup_handler: hdlp = 0x%p\n",
6207c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	/* Do some input argument checking ("dup" is not allocated) */
6237c478bd9Sstevel@tonic-gate 	if ((hdlp == NULL) || (dup != NULL))
6247c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 	/* Do some input argument checking */
6297c478bd9Sstevel@tonic-gate 	if ((hdlp->ih_state == DDI_IHDL_STATE_ALLOC) ||	/* intr handle alloc? */
6307c478bd9Sstevel@tonic-gate 	    (hdlp->ih_type != DDI_INTR_TYPE_MSIX)) {	/* only MSI-X allowed */
6317c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
6327c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
6337c478bd9Sstevel@tonic-gate 	}
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
6367c478bd9Sstevel@tonic-gate 	    DDI_INTROP_DUPVEC, hdlp, (void *)&vector);
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
6397c478bd9Sstevel@tonic-gate 		dup_hdlp = (ddi_intr_handle_impl_t *)
6407c478bd9Sstevel@tonic-gate 		    kmem_zalloc(sizeof (ddi_intr_handle_impl_t), KM_SLEEP);
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 		dup = (ddi_intr_handle_t *)dup_hdlp;
6437c478bd9Sstevel@tonic-gate 		rw_init(&dup_hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
6447c478bd9Sstevel@tonic-gate 		rw_enter(&dup_hdlp->ih_rwlock, RW_WRITER);
6457c478bd9Sstevel@tonic-gate 		dup_hdlp->ih_ver = DDI_INTR_VERSION;
6467c478bd9Sstevel@tonic-gate 		dup_hdlp->ih_state = DDI_IHDL_STATE_ADDED;
6477c478bd9Sstevel@tonic-gate 		dup_hdlp->ih_dip = hdlp->ih_dip;
6487c478bd9Sstevel@tonic-gate 		dup_hdlp->ih_type = hdlp->ih_type;
6497c478bd9Sstevel@tonic-gate 		dup_hdlp->ih_pri = hdlp->ih_pri;
6507c478bd9Sstevel@tonic-gate 		dup_hdlp->ih_cap = hdlp->ih_cap;
6517c478bd9Sstevel@tonic-gate 		dup_hdlp->ih_inum = hdlp->ih_inum;
6527c478bd9Sstevel@tonic-gate 		/* What about MSI-X vector */
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 		dup_hdlp->ih_cb_func = hdlp->ih_cb_func;
6557c478bd9Sstevel@tonic-gate 		dup_hdlp->ih_cb_arg1 = hdlp->ih_cb_arg1;
6567c478bd9Sstevel@tonic-gate 		dup_hdlp->ih_cb_arg2 = hdlp->ih_cb_arg2;
6577c478bd9Sstevel@tonic-gate 		rw_exit(&dup_hdlp->ih_rwlock);
6587c478bd9Sstevel@tonic-gate 	}
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
6617c478bd9Sstevel@tonic-gate 	return (ret);
6627c478bd9Sstevel@tonic-gate }
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate int
6657c478bd9Sstevel@tonic-gate ddi_intr_remove_handler(ddi_intr_handle_t h)
6667c478bd9Sstevel@tonic-gate {
6677c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
6687c478bd9Sstevel@tonic-gate 	int			ret;
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_handler: hdlp = %p\n",
6717c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
6747c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
6777c478bd9Sstevel@tonic-gate 	if (hdlp->ih_state != DDI_IHDL_STATE_ADDED) {
6787c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
6797c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
6807c478bd9Sstevel@tonic-gate 	}
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
6837c478bd9Sstevel@tonic-gate 	    DDI_INTROP_REMISR, hdlp, NULL);
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
6867c478bd9Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ALLOC;
6877c478bd9Sstevel@tonic-gate 		hdlp->ih_cb_func = NULL;
6887c478bd9Sstevel@tonic-gate 		hdlp->ih_cb_arg1 = NULL;
6897c478bd9Sstevel@tonic-gate 		hdlp->ih_cb_arg2 = NULL;
6907c478bd9Sstevel@tonic-gate 	}
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
6937c478bd9Sstevel@tonic-gate 	return (ret);
6947c478bd9Sstevel@tonic-gate }
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate /*
6977c478bd9Sstevel@tonic-gate  * Interrupt enable/disable/block_enable/block_disable handlers
6987c478bd9Sstevel@tonic-gate  */
6997c478bd9Sstevel@tonic-gate int
7007c478bd9Sstevel@tonic-gate ddi_intr_enable(ddi_intr_handle_t h)
7017c478bd9Sstevel@tonic-gate {
7027c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
7037c478bd9Sstevel@tonic-gate 	int			ret;
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_enable: hdlp = %p\n",
7067c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
7097c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
7127c478bd9Sstevel@tonic-gate 	if ((hdlp->ih_state != DDI_IHDL_STATE_ADDED) ||
7137c478bd9Sstevel@tonic-gate 	    ((hdlp->ih_type == DDI_INTR_TYPE_MSI) &&
7147c478bd9Sstevel@tonic-gate 	    (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) {
7157c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
7167c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
7177c478bd9Sstevel@tonic-gate 	}
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
7207c478bd9Sstevel@tonic-gate 	    DDI_INTROP_ENABLE, hdlp, NULL);
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	if (ret == DDI_SUCCESS)
7237c478bd9Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ENABLE;
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
7267c478bd9Sstevel@tonic-gate 	return (ret);
7277c478bd9Sstevel@tonic-gate }
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate int
7307c478bd9Sstevel@tonic-gate ddi_intr_disable(ddi_intr_handle_t h)
7317c478bd9Sstevel@tonic-gate {
7327c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
7337c478bd9Sstevel@tonic-gate 	int			ret;
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_disable: hdlp = %p\n",
7367c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
7397c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
7427c478bd9Sstevel@tonic-gate 	if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
7437c478bd9Sstevel@tonic-gate 	    ((hdlp->ih_type == DDI_INTR_TYPE_MSI) &&
7447c478bd9Sstevel@tonic-gate 	    (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) {
7457c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
7467c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
7477c478bd9Sstevel@tonic-gate 	}
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
7507c478bd9Sstevel@tonic-gate 	    DDI_INTROP_DISABLE, hdlp, NULL);
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	if (ret == DDI_SUCCESS)
7537c478bd9Sstevel@tonic-gate 		hdlp->ih_state = DDI_IHDL_STATE_ADDED;
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
7567c478bd9Sstevel@tonic-gate 	return (ret);
7577c478bd9Sstevel@tonic-gate }
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate int
7607c478bd9Sstevel@tonic-gate ddi_intr_block_enable(ddi_intr_handle_t *h_array, int count)
7617c478bd9Sstevel@tonic-gate {
7627c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp;
7637c478bd9Sstevel@tonic-gate 	int			i, ret;
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_enable: h_array = %p\n",
7667c478bd9Sstevel@tonic-gate 	    (void *)h_array));
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	if (h_array == NULL)
7697c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
7727c478bd9Sstevel@tonic-gate 		hdlp = (ddi_intr_handle_impl_t *)h_array[i];
7737c478bd9Sstevel@tonic-gate 		rw_enter(&hdlp->ih_rwlock, RW_READER);
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 		if (hdlp->ih_state != DDI_IHDL_STATE_ADDED ||
7767c478bd9Sstevel@tonic-gate 		    hdlp->ih_type != DDI_INTR_TYPE_MSI ||
7777c478bd9Sstevel@tonic-gate 		    !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) {
7787c478bd9Sstevel@tonic-gate 			rw_exit(&hdlp->ih_rwlock);
7797c478bd9Sstevel@tonic-gate 			return (DDI_EINVAL);
7807c478bd9Sstevel@tonic-gate 		}
7817c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
7827c478bd9Sstevel@tonic-gate 	}
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 	hdlp = (ddi_intr_handle_impl_t *)h_array[0];
7857c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
7867c478bd9Sstevel@tonic-gate 	hdlp->ih_scratch1 = count;
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
7897c478bd9Sstevel@tonic-gate 	    DDI_INTROP_BLOCKENABLE, hdlp, NULL);
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
7947c478bd9Sstevel@tonic-gate 		for (i = 0; i < count; i++) {
7957c478bd9Sstevel@tonic-gate 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
7967c478bd9Sstevel@tonic-gate 			rw_enter(&hdlp->ih_rwlock, RW_WRITER);
7977c478bd9Sstevel@tonic-gate 			hdlp->ih_state = DDI_IHDL_STATE_ENABLE;
7987c478bd9Sstevel@tonic-gate 			rw_exit(&hdlp->ih_rwlock);
7997c478bd9Sstevel@tonic-gate 		}
8007c478bd9Sstevel@tonic-gate 	}
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 	return (ret);
8037c478bd9Sstevel@tonic-gate }
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate int
8067c478bd9Sstevel@tonic-gate ddi_intr_block_disable(ddi_intr_handle_t *h_array, int count)
8077c478bd9Sstevel@tonic-gate {
8087c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp;
8097c478bd9Sstevel@tonic-gate 	int			i, ret;
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_disable: h_array = %p\n",
8127c478bd9Sstevel@tonic-gate 	    (void *)h_array));
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 	if (h_array == NULL)
8157c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
8187c478bd9Sstevel@tonic-gate 		hdlp = (ddi_intr_handle_impl_t *)h_array[i];
8197c478bd9Sstevel@tonic-gate 		rw_enter(&hdlp->ih_rwlock, RW_READER);
8207c478bd9Sstevel@tonic-gate 		if (hdlp->ih_state != DDI_IHDL_STATE_ENABLE ||
8217c478bd9Sstevel@tonic-gate 		    hdlp->ih_type != DDI_INTR_TYPE_MSI ||
8227c478bd9Sstevel@tonic-gate 		    !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) {
8237c478bd9Sstevel@tonic-gate 			rw_exit(&hdlp->ih_rwlock);
8247c478bd9Sstevel@tonic-gate 			return (DDI_EINVAL);
8257c478bd9Sstevel@tonic-gate 		}
8267c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
8277c478bd9Sstevel@tonic-gate 	}
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 	hdlp = (ddi_intr_handle_impl_t *)h_array[0];
8307c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
8317c478bd9Sstevel@tonic-gate 	hdlp->ih_scratch1 = count;
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
8347c478bd9Sstevel@tonic-gate 	    DDI_INTROP_BLOCKDISABLE, hdlp, NULL);
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
8397c478bd9Sstevel@tonic-gate 		for (i = 0; i < count; i++) {
8407c478bd9Sstevel@tonic-gate 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
8417c478bd9Sstevel@tonic-gate 			rw_enter(&hdlp->ih_rwlock, RW_WRITER);
8427c478bd9Sstevel@tonic-gate 			hdlp->ih_state = DDI_IHDL_STATE_ADDED;
8437c478bd9Sstevel@tonic-gate 			rw_exit(&hdlp->ih_rwlock);
8447c478bd9Sstevel@tonic-gate 		}
8457c478bd9Sstevel@tonic-gate 	}
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 	return (ret);
8487c478bd9Sstevel@tonic-gate }
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate /*
8517c478bd9Sstevel@tonic-gate  * Interrupt set/clr mask handlers
8527c478bd9Sstevel@tonic-gate  */
8537c478bd9Sstevel@tonic-gate int
8547c478bd9Sstevel@tonic-gate ddi_intr_set_mask(ddi_intr_handle_t h)
8557c478bd9Sstevel@tonic-gate {
8567c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
8577c478bd9Sstevel@tonic-gate 	int			ret;
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_mask: hdlp = %p\n",
8607c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
8637c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
8667c478bd9Sstevel@tonic-gate 	if (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE)) {
8677c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
8687c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
8697c478bd9Sstevel@tonic-gate 	}
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 	ret =  i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
8727c478bd9Sstevel@tonic-gate 	    DDI_INTROP_SETMASK, hdlp, NULL);
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
8757c478bd9Sstevel@tonic-gate 	return (ret);
8767c478bd9Sstevel@tonic-gate }
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate int
8797c478bd9Sstevel@tonic-gate ddi_intr_clr_mask(ddi_intr_handle_t h)
8807c478bd9Sstevel@tonic-gate {
8817c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
8827c478bd9Sstevel@tonic-gate 	int			ret;
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_clr_mask: hdlp = %p\n",
8857c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
8887c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
8917c478bd9Sstevel@tonic-gate 	if (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE)) {
8927c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
8937c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
8947c478bd9Sstevel@tonic-gate 	}
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
8977c478bd9Sstevel@tonic-gate 	    DDI_INTROP_CLRMASK, hdlp, NULL);
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
9007c478bd9Sstevel@tonic-gate 	return (ret);
9017c478bd9Sstevel@tonic-gate }
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate /*
9047c478bd9Sstevel@tonic-gate  * Interrupt get_pending handler
9057c478bd9Sstevel@tonic-gate  */
9067c478bd9Sstevel@tonic-gate int
9077c478bd9Sstevel@tonic-gate ddi_intr_get_pending(ddi_intr_handle_t h, int *pendingp)
9087c478bd9Sstevel@tonic-gate {
9097c478bd9Sstevel@tonic-gate 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
9107c478bd9Sstevel@tonic-gate 	int			ret;
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pending: hdlp = %p\n",
9137c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
9167c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
9197c478bd9Sstevel@tonic-gate 	if (!(hdlp->ih_cap & DDI_INTR_FLAG_PENDING)) {
9207c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
9217c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
9227c478bd9Sstevel@tonic-gate 	}
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
9257c478bd9Sstevel@tonic-gate 	    DDI_INTROP_GETPENDING, hdlp, (void *)pendingp);
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
9287c478bd9Sstevel@tonic-gate 	return (ret);
9297c478bd9Sstevel@tonic-gate }
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate /*
9327c478bd9Sstevel@tonic-gate  * Soft interrupt handlers
9337c478bd9Sstevel@tonic-gate  */
9347c478bd9Sstevel@tonic-gate /*
9357c478bd9Sstevel@tonic-gate  * Add a soft interrupt and register its handler
9367c478bd9Sstevel@tonic-gate  */
9377c478bd9Sstevel@tonic-gate /* ARGSUSED */
9387c478bd9Sstevel@tonic-gate int
9397c478bd9Sstevel@tonic-gate ddi_intr_add_softint(dev_info_t *dip, ddi_softint_handle_t *h_p, int soft_pri,
9407c478bd9Sstevel@tonic-gate     ddi_intr_handler_t handler, void *arg1)
9417c478bd9Sstevel@tonic-gate {
9427c478bd9Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp;
9437c478bd9Sstevel@tonic-gate 	int			ret;
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: dip = %p, "
9467c478bd9Sstevel@tonic-gate 	    "softpri = 0x%x\n", (void *)dip, soft_pri));
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (h_p == NULL) || (handler == NULL)) {
9497c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: "
9507c478bd9Sstevel@tonic-gate 		    "invalid arguments"));
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
9537c478bd9Sstevel@tonic-gate 	}
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	/* Validate input arguments */
9567c478bd9Sstevel@tonic-gate 	if (soft_pri < DDI_INTR_SOFTPRI_MIN ||
9577c478bd9Sstevel@tonic-gate 	    soft_pri > DDI_INTR_SOFTPRI_MAX) {
9587c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: invalid "
9597c478bd9Sstevel@tonic-gate 		    "soft_pri input given  = %x\n", soft_pri));
9607c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
9617c478bd9Sstevel@tonic-gate 	}
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 	hdlp = (ddi_softint_hdl_impl_t *)kmem_zalloc(
9647c478bd9Sstevel@tonic-gate 	    sizeof (ddi_softint_hdl_impl_t), KM_SLEEP);
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	/* fill up internally */
9677c478bd9Sstevel@tonic-gate 	rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
9687c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
9697c478bd9Sstevel@tonic-gate 	hdlp->ih_pri = soft_pri;
9707c478bd9Sstevel@tonic-gate 	hdlp->ih_dip = dip;
9717c478bd9Sstevel@tonic-gate 	hdlp->ih_cb_func = handler;
9727c478bd9Sstevel@tonic-gate 	hdlp->ih_cb_arg1 = arg1;
9737c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: hdlp = %p\n",
9747c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 	/* do the platform specific calls */
9777c478bd9Sstevel@tonic-gate 	if ((ret = i_ddi_add_softint(hdlp)) != DDI_SUCCESS) {
9787c478bd9Sstevel@tonic-gate 		rw_exit(&hdlp->ih_rwlock);
9797c478bd9Sstevel@tonic-gate 		rw_destroy(&hdlp->ih_rwlock);
9807c478bd9Sstevel@tonic-gate 		kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t));
9817c478bd9Sstevel@tonic-gate 		return (ret);
9827c478bd9Sstevel@tonic-gate 	}
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	*h_p = (ddi_softint_handle_t)hdlp;
9857c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
9867c478bd9Sstevel@tonic-gate 	return (ret);
9877c478bd9Sstevel@tonic-gate }
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate /*
9907c478bd9Sstevel@tonic-gate  * Remove the soft interrupt
9917c478bd9Sstevel@tonic-gate  */
9927c478bd9Sstevel@tonic-gate int
9937c478bd9Sstevel@tonic-gate ddi_intr_remove_softint(ddi_softint_handle_t h)
9947c478bd9Sstevel@tonic-gate {
9957c478bd9Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp = (ddi_softint_hdl_impl_t *)h;
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_softint: hdlp = %p\n",
9987c478bd9Sstevel@tonic-gate 	    (void *)hdlp));
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
10017c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
10047c478bd9Sstevel@tonic-gate 	i_ddi_remove_softint(hdlp);
10057c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
10067c478bd9Sstevel@tonic-gate 	rw_destroy(&hdlp->ih_rwlock);
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate 	/* kmem_free the hdl impl_t structure allocated earlier */
10097c478bd9Sstevel@tonic-gate 	kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t));
10107c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
10117c478bd9Sstevel@tonic-gate }
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate /*
10147c478bd9Sstevel@tonic-gate  * Trigger a soft interrupt
10157c478bd9Sstevel@tonic-gate  */
10167c478bd9Sstevel@tonic-gate /* ARGSUSED */
10177c478bd9Sstevel@tonic-gate int
10187c478bd9Sstevel@tonic-gate ddi_intr_trigger_softint(ddi_softint_handle_t h, void *arg2)
10197c478bd9Sstevel@tonic-gate {
10207c478bd9Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp = (ddi_softint_hdl_impl_t *)h;
10217c478bd9Sstevel@tonic-gate 	caddr_t			orig_arg2;
10227c478bd9Sstevel@tonic-gate 	int			ret;
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
10257c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 	/*
10307c478bd9Sstevel@tonic-gate 	 * Need to reset "arg2" everytime.
10317c478bd9Sstevel@tonic-gate 	 * Multiple invocations of trigger_softint() are blocked
10327c478bd9Sstevel@tonic-gate 	 */
10337c478bd9Sstevel@tonic-gate 	orig_arg2 = hdlp->ih_cb_arg2;
10347c478bd9Sstevel@tonic-gate 	hdlp->ih_cb_arg2 = arg2;
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	if ((ret = i_ddi_trigger_softint(hdlp)) != DDI_SUCCESS) {
10377c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_trigger_softint: failed, "
10387c478bd9Sstevel@tonic-gate 		    " ret 0%x\n", ret));
10397c478bd9Sstevel@tonic-gate 		hdlp->ih_cb_arg2 = orig_arg2;
10407c478bd9Sstevel@tonic-gate 	}
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
10437c478bd9Sstevel@tonic-gate 	return (ret);
10447c478bd9Sstevel@tonic-gate }
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate /*
10477c478bd9Sstevel@tonic-gate  * Get the soft interrupt priority
10487c478bd9Sstevel@tonic-gate  */
10497c478bd9Sstevel@tonic-gate int
10507c478bd9Sstevel@tonic-gate ddi_intr_get_softint_pri(ddi_softint_handle_t h, uint_t *soft_prip)
10517c478bd9Sstevel@tonic-gate {
10527c478bd9Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp = (ddi_softint_hdl_impl_t *)h;
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_softint_pri: h = %p\n",
10557c478bd9Sstevel@tonic-gate 	    (void *)h));
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
10587c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_READER);
10617c478bd9Sstevel@tonic-gate 	*soft_prip = hdlp->ih_pri;
10627c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
10637c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
10647c478bd9Sstevel@tonic-gate }
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate /*
10677c478bd9Sstevel@tonic-gate  * Set the soft interrupt priority
10687c478bd9Sstevel@tonic-gate  */
10697c478bd9Sstevel@tonic-gate int
10707c478bd9Sstevel@tonic-gate ddi_intr_set_softint_pri(ddi_softint_handle_t h, uint_t soft_pri)
10717c478bd9Sstevel@tonic-gate {
10727c478bd9Sstevel@tonic-gate 	ddi_softint_hdl_impl_t	*hdlp = (ddi_softint_hdl_impl_t *)h;
10737c478bd9Sstevel@tonic-gate 	int			ret;
10747c478bd9Sstevel@tonic-gate 	uint_t			orig_soft_pri;
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: h = %p\n",
10777c478bd9Sstevel@tonic-gate 	    (void *)h));
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	if (hdlp == NULL)
10807c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	/* Validate priority argument */
10837c478bd9Sstevel@tonic-gate 	if (soft_pri < DDI_INTR_SOFTPRI_MIN ||
10847c478bd9Sstevel@tonic-gate 	    soft_pri > DDI_INTR_SOFTPRI_MAX) {
10857c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: invalid "
10867c478bd9Sstevel@tonic-gate 		    "soft_pri input given  = %x\n", soft_pri));
10877c478bd9Sstevel@tonic-gate 		return (DDI_EINVAL);
10887c478bd9Sstevel@tonic-gate 	}
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
10917c478bd9Sstevel@tonic-gate 	orig_soft_pri = hdlp->ih_pri;
10927c478bd9Sstevel@tonic-gate 	hdlp->ih_pri = soft_pri;
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 	if ((ret = i_ddi_set_softint_pri(hdlp, orig_soft_pri)) != DDI_SUCCESS) {
10957c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: failed, "
10967c478bd9Sstevel@tonic-gate 		    " ret 0%x\n", ret));
10977c478bd9Sstevel@tonic-gate 		hdlp->ih_pri = orig_soft_pri;
10987c478bd9Sstevel@tonic-gate 	}
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	rw_exit(&hdlp->ih_rwlock);
11017c478bd9Sstevel@tonic-gate 	return (ret);
11027c478bd9Sstevel@tonic-gate }
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate /*
11057c478bd9Sstevel@tonic-gate  * Old DDI interrupt framework
11067c478bd9Sstevel@tonic-gate  */
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate int
11097c478bd9Sstevel@tonic-gate ddi_intr_hilevel(dev_info_t *dip, uint_t inumber)
11107c478bd9Sstevel@tonic-gate {
11117c478bd9Sstevel@tonic-gate 	ddi_intr_handle_t	hdl, *existing_hdlp;
11127c478bd9Sstevel@tonic-gate 	int			actual, ret;
11137c478bd9Sstevel@tonic-gate 	uint_t			high_pri, pri;
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: name=%s%d dip=0x%p "
11167c478bd9Sstevel@tonic-gate 	    "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
11177c478bd9Sstevel@tonic-gate 	    (void *)dip, inumber));
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 	/*
11207c478bd9Sstevel@tonic-gate 	 * The device driver may have already registed with the
11217c478bd9Sstevel@tonic-gate 	 * framework. If so, first try to get the existing interrupt handle
11227c478bd9Sstevel@tonic-gate 	 * for that given inumber and use that handle.
11237c478bd9Sstevel@tonic-gate 	 */
11247c478bd9Sstevel@tonic-gate 	existing_hdlp = i_ddi_get_intr_handle(dip, inumber);
11257c478bd9Sstevel@tonic-gate 	if (existing_hdlp) {
11267c478bd9Sstevel@tonic-gate 		hdl = existing_hdlp[0];	/* Use existing handle */
11277c478bd9Sstevel@tonic-gate 	} else {
11287c478bd9Sstevel@tonic-gate 		if ((ret = ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED,
11297c478bd9Sstevel@tonic-gate 		    inumber, 1, &actual, 0)) != DDI_SUCCESS) {
11307c478bd9Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: "
11317c478bd9Sstevel@tonic-gate 			    "ddi_intr_alloc failed, ret 0x%x\n", ret));
11327c478bd9Sstevel@tonic-gate 			return (0);
11337c478bd9Sstevel@tonic-gate 		}
11347c478bd9Sstevel@tonic-gate 	}
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 	if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) {
11377c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: "
11387c478bd9Sstevel@tonic-gate 		    "ddi_intr_get_pri failed, ret 0x%x\n", ret));
11397c478bd9Sstevel@tonic-gate 		(void) ddi_intr_free(hdl);
11407c478bd9Sstevel@tonic-gate 		return (0);
11417c478bd9Sstevel@tonic-gate 	}
11427c478bd9Sstevel@tonic-gate 
11437c478bd9Sstevel@tonic-gate 	high_pri = ddi_intr_get_hilevel_pri();
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: pri = %x, "
11467c478bd9Sstevel@tonic-gate 	    "high_pri = %x\n", pri, high_pri));
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 	/* Free the handle allocated here only if no existing handle exists */
11497c478bd9Sstevel@tonic-gate 	if (existing_hdlp == NULL)
11507c478bd9Sstevel@tonic-gate 		(void) ddi_intr_free(hdl);
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate 	return (pri >= high_pri);
11537c478bd9Sstevel@tonic-gate }
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate int
11567c478bd9Sstevel@tonic-gate ddi_dev_nintrs(dev_info_t *dip, int *result)
11577c478bd9Sstevel@tonic-gate {
11587c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: name=%s%d dip=0x%p\n",
11597c478bd9Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip), (void *)dip));
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 	if (ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED,
11627c478bd9Sstevel@tonic-gate 	    result) != DDI_SUCCESS) {
11637c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: "
11647c478bd9Sstevel@tonic-gate 		    "ddi_intr_get_nintrs failed\n"));
11657c478bd9Sstevel@tonic-gate 		*result = 0;
11667c478bd9Sstevel@tonic-gate 	}
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
11697c478bd9Sstevel@tonic-gate }
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate int
11727c478bd9Sstevel@tonic-gate ddi_get_iblock_cookie(dev_info_t *dip, uint_t inumber,
11737c478bd9Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep)
11747c478bd9Sstevel@tonic-gate {
11757c478bd9Sstevel@tonic-gate 	ddi_intr_handle_t	hdl, *existing_hdlp;
11767c478bd9Sstevel@tonic-gate 	int			actual, ret;
11777c478bd9Sstevel@tonic-gate 	uint_t			pri;
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: name=%s%d dip=0x%p "
11807c478bd9Sstevel@tonic-gate 	    "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
11817c478bd9Sstevel@tonic-gate 	    (void *)dip, inumber));
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 	ASSERT(iblock_cookiep != NULL);
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 	/*
11867c478bd9Sstevel@tonic-gate 	 * The device driver may have already registed with the
11877c478bd9Sstevel@tonic-gate 	 * framework. If so, first try to get the existing interrupt handle
11887c478bd9Sstevel@tonic-gate 	 * for that given inumber and use that handle.
11897c478bd9Sstevel@tonic-gate 	 */
11907c478bd9Sstevel@tonic-gate 	existing_hdlp = i_ddi_get_intr_handle(dip, inumber);
11917c478bd9Sstevel@tonic-gate 	if (existing_hdlp) {
11927c478bd9Sstevel@tonic-gate 		hdl = existing_hdlp[0];	/* Use existing handle */
11937c478bd9Sstevel@tonic-gate 	} else {
11947c478bd9Sstevel@tonic-gate 		if ((ret = ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED,
11957c478bd9Sstevel@tonic-gate 		    inumber, 1, &actual, 0)) != DDI_SUCCESS) {
11967c478bd9Sstevel@tonic-gate 			DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: "
11977c478bd9Sstevel@tonic-gate 			    "ddi_intr_alloc failed, ret 0x%x\n", ret));
11987c478bd9Sstevel@tonic-gate 			return (DDI_INTR_NOTFOUND);
11997c478bd9Sstevel@tonic-gate 		}
12007c478bd9Sstevel@tonic-gate 	}
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate 	if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) {
12037c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: "
12047c478bd9Sstevel@tonic-gate 		    "ddi_intr_get_pri failed, ret 0x%x\n", ret));
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate 		(void) ddi_intr_free(hdl);
12077c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
12087c478bd9Sstevel@tonic-gate 	}
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate 	*iblock_cookiep = (ddi_iblock_cookie_t)(uint64_t)pri;
12117c478bd9Sstevel@tonic-gate 	/* Free the handle allocated here only if no existing handle exists */
12127c478bd9Sstevel@tonic-gate 	if (existing_hdlp == NULL)
12137c478bd9Sstevel@tonic-gate 		(void) ddi_intr_free(hdl);
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
12167c478bd9Sstevel@tonic-gate }
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate int
12197c478bd9Sstevel@tonic-gate ddi_add_intr(dev_info_t *dip, uint_t inumber,
12207c478bd9Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep,
12217c478bd9Sstevel@tonic-gate     ddi_idevice_cookie_t *idevice_cookiep,
12227c478bd9Sstevel@tonic-gate     uint_t (*int_handler)(caddr_t int_handler_arg),
12237c478bd9Sstevel@tonic-gate     caddr_t int_handler_arg)
12247c478bd9Sstevel@tonic-gate {
12257c478bd9Sstevel@tonic-gate 	ddi_intr_handle_t	*hdl_p;
12267c478bd9Sstevel@tonic-gate 	int			actual, ret;
12277c478bd9Sstevel@tonic-gate 	uint_t			pri;
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: name=%s%d dip=0x%p "
12307c478bd9Sstevel@tonic-gate 	    "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
12317c478bd9Sstevel@tonic-gate 	    (void *)dip, inumber));
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	hdl_p = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP);
12347c478bd9Sstevel@tonic-gate 
12357c478bd9Sstevel@tonic-gate 	if ((ret = ddi_intr_alloc(dip, hdl_p, DDI_INTR_TYPE_FIXED,
12367c478bd9Sstevel@tonic-gate 	    inumber, 1, &actual, 0)) != DDI_SUCCESS) {
12377c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
12387c478bd9Sstevel@tonic-gate 		    "ddi_intr_alloc failed, ret 0x%x\n", ret));
12397c478bd9Sstevel@tonic-gate 		kmem_free(hdl_p, sizeof (ddi_intr_handle_t));
12407c478bd9Sstevel@tonic-gate 		return (DDI_INTR_NOTFOUND);
12417c478bd9Sstevel@tonic-gate 	}
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate 	if ((ret = ddi_intr_get_pri(hdl_p[0], &pri)) != DDI_SUCCESS)  {
12447c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
12457c478bd9Sstevel@tonic-gate 		    "ddi_intr_get_pri failed, ret 0x%x\n", ret));
12467c478bd9Sstevel@tonic-gate 		(void) ddi_intr_free(hdl_p[0]);
12477c478bd9Sstevel@tonic-gate 		kmem_free(hdl_p, sizeof (ddi_intr_handle_t));
12487c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
12497c478bd9Sstevel@tonic-gate 	}
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 	if ((ret = ddi_intr_add_handler(hdl_p[0], (ddi_intr_handler_t *)
12527c478bd9Sstevel@tonic-gate 	    int_handler, int_handler_arg, NULL)) != DDI_SUCCESS) {
12537c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
12547c478bd9Sstevel@tonic-gate 		    "ddi_intr_add_handler failed, ret 0x%x\n", ret));
12557c478bd9Sstevel@tonic-gate 		(void) ddi_intr_free(hdl_p[0]);
12567c478bd9Sstevel@tonic-gate 		kmem_free(hdl_p, sizeof (ddi_intr_handle_t));
12577c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
12587c478bd9Sstevel@tonic-gate 	}
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate 	if ((ret = ddi_intr_enable(hdl_p[0])) != DDI_SUCCESS) {
12617c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
12627c478bd9Sstevel@tonic-gate 		    "ddi_intr_enable failed, ret 0x%x\n", ret));
12637c478bd9Sstevel@tonic-gate 		(void) ddi_intr_remove_handler(hdl_p[0]);
12647c478bd9Sstevel@tonic-gate 		(void) ddi_intr_free(hdl_p[0]);
12657c478bd9Sstevel@tonic-gate 		kmem_free(hdl_p, sizeof (ddi_intr_handle_t));
12667c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
12677c478bd9Sstevel@tonic-gate 	}
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 	if (iblock_cookiep)
12707c478bd9Sstevel@tonic-gate 		*iblock_cookiep = (ddi_iblock_cookie_t)(uint64_t)pri;
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate 	if (idevice_cookiep) {
12737c478bd9Sstevel@tonic-gate 		idevice_cookiep->idev_vector = 0;
12747c478bd9Sstevel@tonic-gate 		idevice_cookiep->idev_priority = pri;
12757c478bd9Sstevel@tonic-gate 	}
12767c478bd9Sstevel@tonic-gate 
12777c478bd9Sstevel@tonic-gate 	/* this line may be removed in near future */
12787c478bd9Sstevel@tonic-gate 	i_ddi_set_intr_handle(dip, inumber, hdl_p);
12797c478bd9Sstevel@tonic-gate 
12807c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
12817c478bd9Sstevel@tonic-gate }
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate /* ARGSUSED */
12847c478bd9Sstevel@tonic-gate int
12857c478bd9Sstevel@tonic-gate ddi_add_fastintr(dev_info_t *dip, uint_t inumber,
12867c478bd9Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep,
12877c478bd9Sstevel@tonic-gate     ddi_idevice_cookie_t *idevice_cookiep,
12887c478bd9Sstevel@tonic-gate     uint_t (*hi_int_handler)(void))
12897c478bd9Sstevel@tonic-gate {
12907c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_fastintr: name=%s%d dip=0x%p "
12917c478bd9Sstevel@tonic-gate 	    "inum=0x%x: Not supported, return failure\n", ddi_driver_name(dip),
12927c478bd9Sstevel@tonic-gate 	    ddi_get_instance(dip), (void *)dip, inumber));
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
12957c478bd9Sstevel@tonic-gate }
12967c478bd9Sstevel@tonic-gate 
12977c478bd9Sstevel@tonic-gate /* ARGSUSED */
12987c478bd9Sstevel@tonic-gate void
12997c478bd9Sstevel@tonic-gate ddi_remove_intr(dev_info_t *dip, uint_t inum, ddi_iblock_cookie_t iblock_cookie)
13007c478bd9Sstevel@tonic-gate {
13017c478bd9Sstevel@tonic-gate 	ddi_intr_handle_t	*hdl_p;
13027c478bd9Sstevel@tonic-gate 	int			ret;
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: name=%s%d dip=0x%p "
13057c478bd9Sstevel@tonic-gate 	    "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
13067c478bd9Sstevel@tonic-gate 	    (void *)dip, inum));
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 	if ((hdl_p = i_ddi_get_intr_handle(dip, inum)) == NULL) {
13097c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: no handle "
13107c478bd9Sstevel@tonic-gate 		    "found\n"));
13117c478bd9Sstevel@tonic-gate 		return;
13127c478bd9Sstevel@tonic-gate 	}
13137c478bd9Sstevel@tonic-gate 
13147c478bd9Sstevel@tonic-gate 	if ((ret = ddi_intr_disable(hdl_p[0])) != DDI_SUCCESS) {
13157c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
13167c478bd9Sstevel@tonic-gate 		    "ddi_intr_disable failed, ret 0x%x\n", ret));
13177c478bd9Sstevel@tonic-gate 		return;
13187c478bd9Sstevel@tonic-gate 	}
13197c478bd9Sstevel@tonic-gate 
13207c478bd9Sstevel@tonic-gate 	if ((ret = ddi_intr_remove_handler(hdl_p[0])) != DDI_SUCCESS) {
13217c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
13227c478bd9Sstevel@tonic-gate 		    "ddi_intr_remove_handler failed, ret 0x%x\n", ret));
13237c478bd9Sstevel@tonic-gate 		return;
13247c478bd9Sstevel@tonic-gate 	}
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate 	if ((ret = ddi_intr_free(hdl_p[0])) != DDI_SUCCESS) {
13277c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
13287c478bd9Sstevel@tonic-gate 		    "ddi_intr_free failed, ret 0x%x\n", ret));
13297c478bd9Sstevel@tonic-gate 		return;
13307c478bd9Sstevel@tonic-gate 	}
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 	kmem_free(hdl_p, sizeof (ddi_intr_handle_t));
13337c478bd9Sstevel@tonic-gate 
13347c478bd9Sstevel@tonic-gate 	/* this line may be removed in near future */
13357c478bd9Sstevel@tonic-gate 	i_ddi_set_intr_handle(dip, inum, NULL);
13367c478bd9Sstevel@tonic-gate }
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate /* ARGSUSED */
13397c478bd9Sstevel@tonic-gate int
13407c478bd9Sstevel@tonic-gate ddi_get_soft_iblock_cookie(dev_info_t *dip, int preference,
13417c478bd9Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep)
13427c478bd9Sstevel@tonic-gate {
13437c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_get_soft_iblock_cookie: name=%s%d "
13447c478bd9Sstevel@tonic-gate 	    "dip=0x%p pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
13457c478bd9Sstevel@tonic-gate 	    (void *)dip, preference));
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 	ASSERT(iblock_cookiep != NULL);
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate 	if (preference == DDI_SOFTINT_FIXED)
13507c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate 	*iblock_cookiep = (ddi_iblock_cookie_t)((uint64_t)
13537c478bd9Sstevel@tonic-gate 	    ((preference > DDI_SOFTINT_MED) ? DDI_SOFT_INTR_PRI_H :
13547c478bd9Sstevel@tonic-gate 	    DDI_SOFT_INTR_PRI_M));
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
13577c478bd9Sstevel@tonic-gate }
13587c478bd9Sstevel@tonic-gate 
13597c478bd9Sstevel@tonic-gate int
13607c478bd9Sstevel@tonic-gate ddi_add_softintr(dev_info_t *dip, int preference, ddi_softintr_t *idp,
13617c478bd9Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep,
13627c478bd9Sstevel@tonic-gate     ddi_idevice_cookie_t *idevice_cookiep,
13637c478bd9Sstevel@tonic-gate     uint_t (*int_handler)(caddr_t int_handler_arg),
13647c478bd9Sstevel@tonic-gate     caddr_t int_handler_arg)
13657c478bd9Sstevel@tonic-gate {
13667c478bd9Sstevel@tonic-gate 	ddi_softint_handle_t	*hdl_p;
13677c478bd9Sstevel@tonic-gate 	uint64_t		softpri;
13687c478bd9Sstevel@tonic-gate 	int			ret;
13697c478bd9Sstevel@tonic-gate 
13707c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: name=%s%d dip=0x%p "
13717c478bd9Sstevel@tonic-gate 	    "pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
13727c478bd9Sstevel@tonic-gate 	    (void *)dip, preference));
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate 	if ((idp == NULL) || ((preference == DDI_SOFTINT_FIXED) &&
13757c478bd9Sstevel@tonic-gate 	    (iblock_cookiep == NULL)))
13767c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate 	/* Translate the priority preference */
13797c478bd9Sstevel@tonic-gate 	if (preference == DDI_SOFTINT_FIXED) {
13807c478bd9Sstevel@tonic-gate 		softpri = (uint64_t)*iblock_cookiep;
13817c478bd9Sstevel@tonic-gate 		softpri = MIN(softpri, DDI_SOFT_INTR_PRI_H);
13827c478bd9Sstevel@tonic-gate 	} else {
13837c478bd9Sstevel@tonic-gate 		softpri = (uint64_t)((preference > DDI_SOFTINT_MED) ?
13847c478bd9Sstevel@tonic-gate 		    DDI_SOFT_INTR_PRI_H : DDI_SOFT_INTR_PRI_M);
13857c478bd9Sstevel@tonic-gate 	}
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: preference 0x%x "
13887c478bd9Sstevel@tonic-gate 	    "softpri 0x%lx\n", preference, (long)softpri));
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate 	hdl_p = kmem_zalloc(sizeof (ddi_softint_handle_t), KM_SLEEP);
13917c478bd9Sstevel@tonic-gate 	if ((ret = ddi_intr_add_softint(dip, hdl_p, softpri,
13927c478bd9Sstevel@tonic-gate 	    (ddi_intr_handler_t *)int_handler, int_handler_arg)) !=
13937c478bd9Sstevel@tonic-gate 	    DDI_SUCCESS) {
13947c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: "
13957c478bd9Sstevel@tonic-gate 		    "ddi_intr_add_softint failed, ret 0x%x\n", ret));
13967c478bd9Sstevel@tonic-gate 
13977c478bd9Sstevel@tonic-gate 		kmem_free(hdl_p, sizeof (ddi_softint_handle_t));
13987c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
13997c478bd9Sstevel@tonic-gate 	}
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 	if (iblock_cookiep)
14027c478bd9Sstevel@tonic-gate 		*iblock_cookiep = (ddi_iblock_cookie_t)softpri;
14037c478bd9Sstevel@tonic-gate 
14047c478bd9Sstevel@tonic-gate 	if (idevice_cookiep) {
14057c478bd9Sstevel@tonic-gate 		idevice_cookiep->idev_vector = 0;
14067c478bd9Sstevel@tonic-gate 		idevice_cookiep->idev_priority = softpri;
14077c478bd9Sstevel@tonic-gate 	}
14087c478bd9Sstevel@tonic-gate 
14097c478bd9Sstevel@tonic-gate 	*idp = (ddi_softintr_t)hdl_p;
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: dip = 0x%p, "
14127c478bd9Sstevel@tonic-gate 	    "idp = 0x%p, ret = %x\n", (void *)dip, (void *)*idp, ret));
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
14157c478bd9Sstevel@tonic-gate }
14167c478bd9Sstevel@tonic-gate 
14177c478bd9Sstevel@tonic-gate void
14187c478bd9Sstevel@tonic-gate ddi_remove_softintr(ddi_softintr_t id)
14197c478bd9Sstevel@tonic-gate {
14207c478bd9Sstevel@tonic-gate 	ddi_softint_handle_t	*h_p = (ddi_softint_handle_t *)id;
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: id=0x%p\n",
14237c478bd9Sstevel@tonic-gate 	    (void *)id));
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 	if (h_p == NULL)
14267c478bd9Sstevel@tonic-gate 		return;
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: handle 0x%p\n",
14297c478bd9Sstevel@tonic-gate 	    (void *)h_p));
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 	(void) ddi_intr_remove_softint(*h_p);
14327c478bd9Sstevel@tonic-gate 	kmem_free(h_p, sizeof (ddi_softint_handle_t));
14337c478bd9Sstevel@tonic-gate }
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate void
14367c478bd9Sstevel@tonic-gate ddi_trigger_softintr(ddi_softintr_t id)
14377c478bd9Sstevel@tonic-gate {
14387c478bd9Sstevel@tonic-gate 	ddi_softint_handle_t	*h_p = (ddi_softint_handle_t *)id;
14397c478bd9Sstevel@tonic-gate 	int			ret;
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 	if (h_p == NULL)
14427c478bd9Sstevel@tonic-gate 		return;
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 	if ((ret = ddi_intr_trigger_softint(*h_p, NULL)) != DDI_SUCCESS) {
14457c478bd9Sstevel@tonic-gate 		DDI_INTR_APIDBG((CE_CONT, "ddi_trigger_softintr: "
14467c478bd9Sstevel@tonic-gate 		    "ddi_intr_trigger_softint failed, hdlp 0x%p "
14477c478bd9Sstevel@tonic-gate 		    "ret 0x%x\n", (void *)h_p, ret));
14487c478bd9Sstevel@tonic-gate 	}
14497c478bd9Sstevel@tonic-gate }
1450