xref: /onnv-gate/usr/src/uts/common/os/ddi_intr_impl.c (revision 14:81812c944e90)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <sys/note.h>
300Sstevel@tonic-gate #include <sys/sysmacros.h>
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #include <sys/param.h>
330Sstevel@tonic-gate #include <sys/systm.h>
340Sstevel@tonic-gate #include <sys/kmem.h>
350Sstevel@tonic-gate #include <sys/cmn_err.h>
360Sstevel@tonic-gate #include <sys/debug.h>
370Sstevel@tonic-gate #include <sys/avintr.h>
380Sstevel@tonic-gate #include <sys/autoconf.h>
390Sstevel@tonic-gate #include <sys/sunndi.h>
400Sstevel@tonic-gate #include <sys/ndi_impldefs.h>	/* include prototypes */
410Sstevel@tonic-gate 
420Sstevel@tonic-gate /*
430Sstevel@tonic-gate  * New DDI interrupt framework
440Sstevel@tonic-gate  */
450Sstevel@tonic-gate void
460Sstevel@tonic-gate i_ddi_intr_devi_init(dev_info_t *dip)
470Sstevel@tonic-gate {
480Sstevel@tonic-gate 	int	supported_types;
490Sstevel@tonic-gate 
500Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "i_ddi_intr_devi_init: dip %p\n",
510Sstevel@tonic-gate 	    (void *)dip));
520Sstevel@tonic-gate 
530Sstevel@tonic-gate 	if (DEVI(dip)->devi_intr_p)
540Sstevel@tonic-gate 		return;
550Sstevel@tonic-gate 
560Sstevel@tonic-gate 	DEVI(dip)->devi_intr_p = kmem_zalloc(sizeof (devinfo_intr_t),
570Sstevel@tonic-gate 	    KM_SLEEP);
580Sstevel@tonic-gate 
590Sstevel@tonic-gate 	supported_types = i_ddi_intr_get_supported_types(dip);
600Sstevel@tonic-gate 
610Sstevel@tonic-gate 	/* Save supported interrupt types information */
620Sstevel@tonic-gate 	i_ddi_intr_set_supported_types(dip, supported_types);
630Sstevel@tonic-gate }
640Sstevel@tonic-gate 
650Sstevel@tonic-gate void
660Sstevel@tonic-gate i_ddi_intr_devi_fini(dev_info_t *dip)
670Sstevel@tonic-gate {
680Sstevel@tonic-gate 	devinfo_intr_t	*intr_p = DEVI(dip)->devi_intr_p;
690Sstevel@tonic-gate 
700Sstevel@tonic-gate 	/*
710Sstevel@tonic-gate 	 * devi_intr_handle_p will only be used for devices
720Sstevel@tonic-gate 	 * which are using the legacy DDI Interrupt interfaces.
730Sstevel@tonic-gate 	 */
740Sstevel@tonic-gate 	if (intr_p->devi_intr_handle_p) {
750Sstevel@tonic-gate 		/* nintrs could be zero; so check for it first */
760Sstevel@tonic-gate 		if (intr_p->devi_intr_sup_nintrs) {
770Sstevel@tonic-gate 			kmem_free(intr_p->devi_intr_handle_p,
780Sstevel@tonic-gate 			    intr_p->devi_intr_sup_nintrs *
790Sstevel@tonic-gate 			    sizeof (ddi_intr_handle_t));
800Sstevel@tonic-gate 		}
810Sstevel@tonic-gate 	}
820Sstevel@tonic-gate 	kmem_free(DEVI(dip)->devi_intr_p, sizeof (devinfo_intr_t));
830Sstevel@tonic-gate 	DEVI(dip)->devi_intr_p = NULL;
840Sstevel@tonic-gate }
850Sstevel@tonic-gate 
860Sstevel@tonic-gate uint_t
870Sstevel@tonic-gate i_ddi_intr_get_supported_types(dev_info_t *dip)
880Sstevel@tonic-gate {
890Sstevel@tonic-gate 	devinfo_intr_t		*intr_p = DEVI(dip)->devi_intr_p;
900Sstevel@tonic-gate 	ddi_intr_handle_impl_t	hdl;
910Sstevel@tonic-gate 	int			ret, intr_types;
920Sstevel@tonic-gate 
930Sstevel@tonic-gate 	if ((intr_p) && (intr_p->devi_intr_sup_types))
940Sstevel@tonic-gate 		return (intr_p->devi_intr_sup_types);
950Sstevel@tonic-gate 
960Sstevel@tonic-gate 	bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
970Sstevel@tonic-gate 	hdl.ih_dip = dip;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(dip, dip, DDI_INTROP_SUPPORTED_TYPES, &hdl,
1000Sstevel@tonic-gate 	    (void *)&intr_types);
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 	return ((ret == DDI_SUCCESS) ? intr_types : 0);
1030Sstevel@tonic-gate }
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate /*
1060Sstevel@tonic-gate  * NOTE: This function is only called by i_ddi_dev_init().
1070Sstevel@tonic-gate  */
1080Sstevel@tonic-gate void
1090Sstevel@tonic-gate i_ddi_intr_set_supported_types(dev_info_t *dip, int intr_types)
1100Sstevel@tonic-gate {
1110Sstevel@tonic-gate 	devinfo_intr_t		*intr_p = DEVI(dip)->devi_intr_p;
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 	if (intr_p)
1140Sstevel@tonic-gate 		intr_p->devi_intr_sup_types = intr_types;
1150Sstevel@tonic-gate }
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate uint_t
1180Sstevel@tonic-gate i_ddi_intr_get_supported_nintrs(dev_info_t *dip, int intr_type)
1190Sstevel@tonic-gate {
1200Sstevel@tonic-gate 	devinfo_intr_t		*intr_p = DEVI(dip)->devi_intr_p;
1210Sstevel@tonic-gate 	ddi_intr_handle_impl_t	hdl;
1220Sstevel@tonic-gate 	int			ret, nintrs;
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	if ((intr_p) && (intr_p->devi_intr_curr_type == intr_type) &&
1250Sstevel@tonic-gate 	    (intr_p->devi_intr_sup_nintrs))
1260Sstevel@tonic-gate 		return (intr_p->devi_intr_sup_nintrs);
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
1290Sstevel@tonic-gate 	hdl.ih_dip = dip;
1300Sstevel@tonic-gate 	hdl.ih_type = intr_type;
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate 	ret = i_ddi_handle_intr_ops(dip, dip, DDI_INTROP_NINTRS, &hdl,
1330Sstevel@tonic-gate 	    (void *)&nintrs);
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	return ((ret == DDI_SUCCESS) ? nintrs : 0);
1360Sstevel@tonic-gate }
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate /*
1390Sstevel@tonic-gate  * NOTE: This function is only called by ddi_intr_alloc().
1400Sstevel@tonic-gate  */
1410Sstevel@tonic-gate void
1420Sstevel@tonic-gate i_ddi_intr_set_supported_nintrs(dev_info_t *dip, int nintrs)
1430Sstevel@tonic-gate {
1440Sstevel@tonic-gate 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 	if (intr_p)
1470Sstevel@tonic-gate 		intr_p->devi_intr_sup_nintrs = nintrs;
1480Sstevel@tonic-gate }
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate uint_t
1510Sstevel@tonic-gate i_ddi_intr_get_current_type(dev_info_t *dip)
1520Sstevel@tonic-gate {
1530Sstevel@tonic-gate 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	return (intr_p ? intr_p->devi_intr_curr_type : 0);
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate /*
1590Sstevel@tonic-gate  * NOTE: This function is only called by
1600Sstevel@tonic-gate  *       ddi_intr_alloc() and ddi_intr_free().
1610Sstevel@tonic-gate  */
1620Sstevel@tonic-gate void
1630Sstevel@tonic-gate i_ddi_intr_set_current_type(dev_info_t *dip, int intr_type)
1640Sstevel@tonic-gate {
1650Sstevel@tonic-gate 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	if (intr_p)
1680Sstevel@tonic-gate 		intr_p->devi_intr_curr_type = intr_type;
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate uint_t
1720Sstevel@tonic-gate i_ddi_intr_get_current_nintrs(dev_info_t *dip)
1730Sstevel@tonic-gate {
1740Sstevel@tonic-gate 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	return (intr_p ? intr_p->devi_intr_curr_nintrs : 0);
1770Sstevel@tonic-gate }
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate /*
1800Sstevel@tonic-gate  * NOTE: This function is only called by
1810Sstevel@tonic-gate  *       ddi_intr_alloc() and ddi_intr_free().
1820Sstevel@tonic-gate  */
1830Sstevel@tonic-gate void
1840Sstevel@tonic-gate i_ddi_intr_set_current_nintrs(dev_info_t *dip, int nintrs)
1850Sstevel@tonic-gate {
1860Sstevel@tonic-gate 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 	if (intr_p)
1890Sstevel@tonic-gate 		intr_p->devi_intr_curr_nintrs = nintrs;
1900Sstevel@tonic-gate }
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate ddi_intr_msix_t *
1930Sstevel@tonic-gate i_ddi_get_msix(dev_info_t *dip)
1940Sstevel@tonic-gate {
1950Sstevel@tonic-gate 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	return (intr_p ? intr_p->devi_msix_p : NULL);
1980Sstevel@tonic-gate }
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate void
2010Sstevel@tonic-gate i_ddi_set_msix(dev_info_t *dip, ddi_intr_msix_t *msix_p)
2020Sstevel@tonic-gate {
2030Sstevel@tonic-gate 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	if (intr_p)
2060Sstevel@tonic-gate 		intr_p->devi_msix_p = msix_p;
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate ddi_intr_handle_t *
2100Sstevel@tonic-gate i_ddi_get_intr_handle(dev_info_t *dip, int inum)
2110Sstevel@tonic-gate {
2120Sstevel@tonic-gate 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	if (intr_p == NULL)
2150Sstevel@tonic-gate 		return (NULL);
2160Sstevel@tonic-gate 
217*14Sanish 	/*
218*14Sanish 	 * Changed this to a check and return NULL if an invalid inum
219*14Sanish 	 * is passed to retrieve a handle
220*14Sanish 	 */
221*14Sanish 	if ((inum < 0) || (inum >= intr_p->devi_intr_sup_nintrs))
222*14Sanish 		return (NULL);
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	return ((intr_p->devi_intr_handle_p) ?
2250Sstevel@tonic-gate 	    intr_p->devi_intr_handle_p[inum] : NULL);
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate void
2290Sstevel@tonic-gate i_ddi_set_intr_handle(dev_info_t *dip, int inum,
2300Sstevel@tonic-gate     ddi_intr_handle_t *intr_hdlp)
2310Sstevel@tonic-gate {
2320Sstevel@tonic-gate 	devinfo_intr_t	*intr_p = DEVI(dip)->devi_intr_p;
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 	if (intr_p == NULL)
2350Sstevel@tonic-gate 		return;
2360Sstevel@tonic-gate 
237*14Sanish 	/*
238*14Sanish 	 * Changed this to a check and return if an invalid inum
239*14Sanish 	 * is passed to set a handle
240*14Sanish 	 */
241*14Sanish 	if ((inum < 0) || (inum >= intr_p->devi_intr_sup_nintrs))
242*14Sanish 		return;
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	if (intr_p->devi_intr_handle_p == NULL) {
2450Sstevel@tonic-gate 		/* nintrs could be zero; so check for it first */
2460Sstevel@tonic-gate 		if (intr_p->devi_intr_sup_nintrs)
2470Sstevel@tonic-gate 			intr_p->devi_intr_handle_p = kmem_zalloc(
2480Sstevel@tonic-gate 			    sizeof (ddi_intr_handle_t) *
2490Sstevel@tonic-gate 			    intr_p->devi_intr_sup_nintrs, KM_SLEEP);
2500Sstevel@tonic-gate 	}
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	intr_p->devi_intr_handle_p[inum] = intr_hdlp;
2530Sstevel@tonic-gate }
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate /*
2560Sstevel@tonic-gate  * The "ddi-intr-weight" property contains the weight of each interrupt
2570Sstevel@tonic-gate  * associated with a dev_info node. For devices with multiple interrupts per
2580Sstevel@tonic-gate  * dev_info node, the total load of the device is "devi_intr_weight * nintr",
2590Sstevel@tonic-gate  * possibly spread out over multiple CPUs.
2600Sstevel@tonic-gate  *
2610Sstevel@tonic-gate  * Maintaining this as a property permits possible tweaking in the product
2620Sstevel@tonic-gate  * in response to customer problems via driver.conf property definitions at
2630Sstevel@tonic-gate  * the driver or the instance level.  This does not mean that "ddi-intr_weight"
2640Sstevel@tonic-gate  * is a formal or committed interface.
2650Sstevel@tonic-gate  */
2660Sstevel@tonic-gate int32_t
2670Sstevel@tonic-gate i_ddi_get_intr_weight(dev_info_t *dip)
2680Sstevel@tonic-gate {
2690Sstevel@tonic-gate 	int32_t	weight;
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	weight = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
2720Sstevel@tonic-gate 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "ddi-intr-weight", -1);
2730Sstevel@tonic-gate 	if (weight < -1)
2740Sstevel@tonic-gate 		weight = -1;			/* undefined */
2750Sstevel@tonic-gate 	return (weight);
2760Sstevel@tonic-gate }
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate int32_t
2790Sstevel@tonic-gate i_ddi_set_intr_weight(dev_info_t *dip, int32_t weight)
2800Sstevel@tonic-gate {
2810Sstevel@tonic-gate 	int32_t oweight;
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	oweight = i_ddi_get_intr_weight(dip);
2840Sstevel@tonic-gate 	if ((weight > 0) && (oweight != weight))
2850Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
2860Sstevel@tonic-gate 		    "ddi-intr-weight", weight);
2870Sstevel@tonic-gate 	return (oweight);
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate /*
2910Sstevel@tonic-gate  * Old DDI interrupt framework
2920Sstevel@tonic-gate  *
2930Sstevel@tonic-gate  * NOTE:
2940Sstevel@tonic-gate  *	The following 4 busops entry points are obsoleted with version
2950Sstevel@tonic-gate  *	9 or greater. Use i_ddi_intr_op interface in place of these
2960Sstevel@tonic-gate  *	obsolete interfaces.
2970Sstevel@tonic-gate  *
2980Sstevel@tonic-gate  *	Remove these busops entry points and all related data structures
2990Sstevel@tonic-gate  *	in future major/minor solaris release.
3000Sstevel@tonic-gate  */
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate /* ARGSUSED */
3030Sstevel@tonic-gate ddi_intrspec_t
3040Sstevel@tonic-gate i_ddi_get_intrspec(dev_info_t *dip, dev_info_t *rdip, uint_t inumber)
3050Sstevel@tonic-gate {
3060Sstevel@tonic-gate 	dev_info_t	*pdip = ddi_get_parent(dip);
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	cmn_err(CE_WARN, "Failed to process interrupt "
3090Sstevel@tonic-gate 	    "for %s%d due to down-rev nexus driver %s%d",
3100Sstevel@tonic-gate 	    ddi_get_name(rdip), ddi_get_instance(rdip),
3110Sstevel@tonic-gate 	    ddi_get_name(pdip), ddi_get_instance(pdip));
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	return (NULL);
3140Sstevel@tonic-gate }
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate /* ARGSUSED */
3170Sstevel@tonic-gate int
3180Sstevel@tonic-gate i_ddi_add_intrspec(dev_info_t *dip, dev_info_t *rdip, ddi_intrspec_t intrspec,
3190Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep,
3200Sstevel@tonic-gate     ddi_idevice_cookie_t *idevice_cookiep,
3210Sstevel@tonic-gate     uint_t (*int_handler)(caddr_t int_handler_arg),
3220Sstevel@tonic-gate     caddr_t int_handler_arg, int kind)
3230Sstevel@tonic-gate {
3240Sstevel@tonic-gate 	dev_info_t	*pdip = ddi_get_parent(dip);
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	cmn_err(CE_WARN, "Failed to process interrupt "
3270Sstevel@tonic-gate 	    "for %s%d due to down-rev nexus driver %s%d",
3280Sstevel@tonic-gate 	    ddi_get_name(rdip), ddi_get_instance(rdip),
3290Sstevel@tonic-gate 	    ddi_get_name(pdip), ddi_get_instance(pdip));
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 	return (DDI_ENOTSUP);
3320Sstevel@tonic-gate }
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate /* ARGSUSED */
3350Sstevel@tonic-gate void
3360Sstevel@tonic-gate i_ddi_remove_intrspec(dev_info_t *dip, dev_info_t *rdip,
3370Sstevel@tonic-gate     ddi_intrspec_t intrspec, ddi_iblock_cookie_t iblock_cookie)
3380Sstevel@tonic-gate {
3390Sstevel@tonic-gate 	dev_info_t	*pdip = ddi_get_parent(dip);
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	cmn_err(CE_WARN, "Failed to process interrupt "
3420Sstevel@tonic-gate 	    "for %s%d due to down-rev nexus driver %s%d",
3430Sstevel@tonic-gate 	    ddi_get_name(rdip), ddi_get_instance(rdip),
3440Sstevel@tonic-gate 	    ddi_get_name(pdip), ddi_get_instance(pdip));
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate /* ARGSUSED */
3480Sstevel@tonic-gate int
3490Sstevel@tonic-gate i_ddi_intr_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_ctlop_t op,
3500Sstevel@tonic-gate     void *arg, void *val)
3510Sstevel@tonic-gate {
3520Sstevel@tonic-gate 	dev_info_t	*pdip = ddi_get_parent(dip);
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 	cmn_err(CE_WARN, "Failed to process interrupt "
3550Sstevel@tonic-gate 	    "for %s%d due to down-rev nexus driver %s%d",
3560Sstevel@tonic-gate 	    ddi_get_name(rdip), ddi_get_instance(rdip),
3570Sstevel@tonic-gate 	    ddi_get_name(pdip), ddi_get_instance(pdip));
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	return (DDI_ENOTSUP);
3600Sstevel@tonic-gate }
361