xref: /onnv-gate/usr/src/uts/common/os/ddi_intr_impl.c (revision 12564:c898fb4dec77)
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
51997Sanish  * Common Development and Distribution License (the "License").
61997Sanish  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
2212473SScott.Carter@Oracle.COM  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate #include <sys/note.h>
260Sstevel@tonic-gate #include <sys/sysmacros.h>
270Sstevel@tonic-gate #include <sys/types.h>
280Sstevel@tonic-gate #include <sys/param.h>
290Sstevel@tonic-gate #include <sys/systm.h>
300Sstevel@tonic-gate #include <sys/kmem.h>
310Sstevel@tonic-gate #include <sys/cmn_err.h>
320Sstevel@tonic-gate #include <sys/debug.h>
330Sstevel@tonic-gate #include <sys/avintr.h>
340Sstevel@tonic-gate #include <sys/autoconf.h>
350Sstevel@tonic-gate #include <sys/sunndi.h>
360Sstevel@tonic-gate #include <sys/ndi_impldefs.h>	/* include prototypes */
370Sstevel@tonic-gate 
388925SEvan.Yan@Sun.COM #if defined(__i386) || defined(__amd64)
398925SEvan.Yan@Sun.COM /*
408925SEvan.Yan@Sun.COM  * MSI-X allocation limit.
418925SEvan.Yan@Sun.COM  */
428925SEvan.Yan@Sun.COM uint_t		ddi_msix_alloc_limit = DDI_DEFAULT_MSIX_ALLOC;
438925SEvan.Yan@Sun.COM #endif
444974Segillett 
450Sstevel@tonic-gate /*
460Sstevel@tonic-gate  * New DDI interrupt framework
470Sstevel@tonic-gate  */
480Sstevel@tonic-gate void
i_ddi_intr_devi_init(dev_info_t * dip)490Sstevel@tonic-gate i_ddi_intr_devi_init(dev_info_t *dip)
500Sstevel@tonic-gate {
510Sstevel@tonic-gate 	int	supported_types;
520Sstevel@tonic-gate 
530Sstevel@tonic-gate 	DDI_INTR_APIDBG((CE_CONT, "i_ddi_intr_devi_init: dip %p\n",
540Sstevel@tonic-gate 	    (void *)dip));
550Sstevel@tonic-gate 
560Sstevel@tonic-gate 	if (DEVI(dip)->devi_intr_p)
570Sstevel@tonic-gate 		return;
580Sstevel@tonic-gate 
598561SScott.Carter@Sun.COM 	DEVI(dip)->devi_intr_p = kmem_zalloc(sizeof (devinfo_intr_t), KM_SLEEP);
600Sstevel@tonic-gate 
610Sstevel@tonic-gate 	supported_types = i_ddi_intr_get_supported_types(dip);
620Sstevel@tonic-gate 
630Sstevel@tonic-gate 	/* Save supported interrupt types information */
640Sstevel@tonic-gate 	i_ddi_intr_set_supported_types(dip, supported_types);
650Sstevel@tonic-gate }
660Sstevel@tonic-gate 
670Sstevel@tonic-gate void
i_ddi_intr_devi_fini(dev_info_t * dip)680Sstevel@tonic-gate i_ddi_intr_devi_fini(dev_info_t *dip)
690Sstevel@tonic-gate {
700Sstevel@tonic-gate 	devinfo_intr_t	*intr_p = DEVI(dip)->devi_intr_p;
710Sstevel@tonic-gate 
72693Sgovinda 	DDI_INTR_APIDBG((CE_CONT, "i_ddi_intr_devi_fini: dip %p\n",
73693Sgovinda 	    (void *)dip));
74693Sgovinda 
758561SScott.Carter@Sun.COM 	if ((intr_p == NULL) || i_ddi_intr_get_current_nintrs(dip))
76693Sgovinda 		return;
77693Sgovinda 
780Sstevel@tonic-gate 	/*
790Sstevel@tonic-gate 	 * devi_intr_handle_p will only be used for devices
800Sstevel@tonic-gate 	 * which are using the legacy DDI Interrupt interfaces.
810Sstevel@tonic-gate 	 */
820Sstevel@tonic-gate 	if (intr_p->devi_intr_handle_p) {
830Sstevel@tonic-gate 		/* nintrs could be zero; so check for it first */
840Sstevel@tonic-gate 		if (intr_p->devi_intr_sup_nintrs) {
850Sstevel@tonic-gate 			kmem_free(intr_p->devi_intr_handle_p,
860Sstevel@tonic-gate 			    intr_p->devi_intr_sup_nintrs *
870Sstevel@tonic-gate 			    sizeof (ddi_intr_handle_t));
880Sstevel@tonic-gate 		}
890Sstevel@tonic-gate 	}
90693Sgovinda 
918561SScott.Carter@Sun.COM 	/*
928561SScott.Carter@Sun.COM 	 * devi_irm_req_p will only be used for devices which
938561SScott.Carter@Sun.COM 	 * are mapped to an Interrupt Resource Management pool.
948561SScott.Carter@Sun.COM 	 */
958561SScott.Carter@Sun.COM 	if (intr_p->devi_irm_req_p)
968561SScott.Carter@Sun.COM 		(void) i_ddi_irm_remove(dip);
978561SScott.Carter@Sun.COM 
980Sstevel@tonic-gate 	kmem_free(DEVI(dip)->devi_intr_p, sizeof (devinfo_intr_t));
990Sstevel@tonic-gate 	DEVI(dip)->devi_intr_p = NULL;
1000Sstevel@tonic-gate }
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate uint_t
i_ddi_intr_get_supported_types(dev_info_t * dip)1030Sstevel@tonic-gate i_ddi_intr_get_supported_types(dev_info_t *dip)
1040Sstevel@tonic-gate {
1050Sstevel@tonic-gate 	devinfo_intr_t		*intr_p = DEVI(dip)->devi_intr_p;
1060Sstevel@tonic-gate 	ddi_intr_handle_impl_t	hdl;
1070Sstevel@tonic-gate 	int			ret, intr_types;
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 	if ((intr_p) && (intr_p->devi_intr_sup_types))
1100Sstevel@tonic-gate 		return (intr_p->devi_intr_sup_types);
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
1130Sstevel@tonic-gate 	hdl.ih_dip = dip;
1140Sstevel@tonic-gate 
115693Sgovinda 	ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_SUPPORTED_TYPES, &hdl,
1160Sstevel@tonic-gate 	    (void *)&intr_types);
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 	return ((ret == DDI_SUCCESS) ? intr_types : 0);
1190Sstevel@tonic-gate }
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate /*
1220Sstevel@tonic-gate  * NOTE: This function is only called by i_ddi_dev_init().
1230Sstevel@tonic-gate  */
1240Sstevel@tonic-gate void
i_ddi_intr_set_supported_types(dev_info_t * dip,int intr_types)1250Sstevel@tonic-gate i_ddi_intr_set_supported_types(dev_info_t *dip, int intr_types)
1260Sstevel@tonic-gate {
1270Sstevel@tonic-gate 	devinfo_intr_t		*intr_p = DEVI(dip)->devi_intr_p;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	if (intr_p)
1300Sstevel@tonic-gate 		intr_p->devi_intr_sup_types = intr_types;
1310Sstevel@tonic-gate }
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate uint_t
i_ddi_intr_get_supported_nintrs(dev_info_t * dip,int intr_type)1340Sstevel@tonic-gate i_ddi_intr_get_supported_nintrs(dev_info_t *dip, int intr_type)
1350Sstevel@tonic-gate {
1360Sstevel@tonic-gate 	devinfo_intr_t		*intr_p = DEVI(dip)->devi_intr_p;
1370Sstevel@tonic-gate 	ddi_intr_handle_impl_t	hdl;
1380Sstevel@tonic-gate 	int			ret, nintrs;
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 	if ((intr_p) && (intr_p->devi_intr_curr_type == intr_type) &&
1410Sstevel@tonic-gate 	    (intr_p->devi_intr_sup_nintrs))
1420Sstevel@tonic-gate 		return (intr_p->devi_intr_sup_nintrs);
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
1450Sstevel@tonic-gate 	hdl.ih_dip = dip;
1460Sstevel@tonic-gate 	hdl.ih_type = intr_type;
1470Sstevel@tonic-gate 
148693Sgovinda 	ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_NINTRS, &hdl,
1490Sstevel@tonic-gate 	    (void *)&nintrs);
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 	return ((ret == DDI_SUCCESS) ? nintrs : 0);
1520Sstevel@tonic-gate }
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate /*
1550Sstevel@tonic-gate  * NOTE: This function is only called by ddi_intr_alloc().
1560Sstevel@tonic-gate  */
1570Sstevel@tonic-gate void
i_ddi_intr_set_supported_nintrs(dev_info_t * dip,int nintrs)1580Sstevel@tonic-gate i_ddi_intr_set_supported_nintrs(dev_info_t *dip, int nintrs)
1590Sstevel@tonic-gate {
1600Sstevel@tonic-gate 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	if (intr_p)
1630Sstevel@tonic-gate 		intr_p->devi_intr_sup_nintrs = nintrs;
1640Sstevel@tonic-gate }
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate uint_t
i_ddi_intr_get_current_type(dev_info_t * dip)1670Sstevel@tonic-gate i_ddi_intr_get_current_type(dev_info_t *dip)
1680Sstevel@tonic-gate {
1690Sstevel@tonic-gate 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	return (intr_p ? intr_p->devi_intr_curr_type : 0);
1720Sstevel@tonic-gate }
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate /*
1750Sstevel@tonic-gate  * NOTE: This function is only called by
1760Sstevel@tonic-gate  *       ddi_intr_alloc() and ddi_intr_free().
1770Sstevel@tonic-gate  */
1780Sstevel@tonic-gate void
i_ddi_intr_set_current_type(dev_info_t * dip,int intr_type)1790Sstevel@tonic-gate i_ddi_intr_set_current_type(dev_info_t *dip, int intr_type)
1800Sstevel@tonic-gate {
1810Sstevel@tonic-gate 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	if (intr_p)
1840Sstevel@tonic-gate 		intr_p->devi_intr_curr_type = intr_type;
1850Sstevel@tonic-gate }
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate uint_t
i_ddi_intr_get_current_nintrs(dev_info_t * dip)1880Sstevel@tonic-gate i_ddi_intr_get_current_nintrs(dev_info_t *dip)
1890Sstevel@tonic-gate {
1900Sstevel@tonic-gate 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	return (intr_p ? intr_p->devi_intr_curr_nintrs : 0);
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate /*
1960Sstevel@tonic-gate  * NOTE: This function is only called by
1970Sstevel@tonic-gate  *       ddi_intr_alloc() and ddi_intr_free().
1980Sstevel@tonic-gate  */
1990Sstevel@tonic-gate void
i_ddi_intr_set_current_nintrs(dev_info_t * dip,int nintrs)2000Sstevel@tonic-gate i_ddi_intr_set_current_nintrs(dev_info_t *dip, int nintrs)
2010Sstevel@tonic-gate {
2020Sstevel@tonic-gate 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	if (intr_p)
2050Sstevel@tonic-gate 		intr_p->devi_intr_curr_nintrs = nintrs;
2060Sstevel@tonic-gate }
2070Sstevel@tonic-gate 
2088561SScott.Carter@Sun.COM uint_t
i_ddi_intr_get_current_nenables(dev_info_t * dip)2098817SKerry.Shu@Sun.COM i_ddi_intr_get_current_nenables(dev_info_t *dip)
2108817SKerry.Shu@Sun.COM {
2118817SKerry.Shu@Sun.COM 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
2128817SKerry.Shu@Sun.COM 
2138817SKerry.Shu@Sun.COM 	return (intr_p ? intr_p->devi_intr_curr_nenables : 0);
2148817SKerry.Shu@Sun.COM }
2158817SKerry.Shu@Sun.COM 
2168817SKerry.Shu@Sun.COM void
i_ddi_intr_set_current_nenables(dev_info_t * dip,int nintrs)2178817SKerry.Shu@Sun.COM i_ddi_intr_set_current_nenables(dev_info_t *dip, int nintrs)
2188817SKerry.Shu@Sun.COM {
2198817SKerry.Shu@Sun.COM 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
2208817SKerry.Shu@Sun.COM 
2218817SKerry.Shu@Sun.COM 	if (intr_p)
2228817SKerry.Shu@Sun.COM 		intr_p->devi_intr_curr_nenables = nintrs;
2238817SKerry.Shu@Sun.COM }
2248817SKerry.Shu@Sun.COM 
22512473SScott.Carter@Oracle.COM /*
22612473SScott.Carter@Oracle.COM  * i_ddi_intr_get_current_navail:
22712473SScott.Carter@Oracle.COM  *
22812473SScott.Carter@Oracle.COM  *	Return the number of interrupts currently available.
22912473SScott.Carter@Oracle.COM  *	If a precise number set by IRM is not available, then
23012473SScott.Carter@Oracle.COM  *	return the limit determined by i_ddi_intr_get_limit().
23112473SScott.Carter@Oracle.COM  */
2328817SKerry.Shu@Sun.COM uint_t
i_ddi_intr_get_current_navail(dev_info_t * dip,int type)2338561SScott.Carter@Sun.COM i_ddi_intr_get_current_navail(dev_info_t *dip, int type)
2348561SScott.Carter@Sun.COM {
23512473SScott.Carter@Oracle.COM 	devinfo_intr_t		*intr_p;
2368561SScott.Carter@Sun.COM 	ddi_irm_pool_t		*pool_p;
2378561SScott.Carter@Sun.COM 	ddi_irm_req_t		*req_p;
23812473SScott.Carter@Oracle.COM 	uint_t			navail;
2398561SScott.Carter@Sun.COM 
24012473SScott.Carter@Oracle.COM 	/* Check for a precise number from IRM */
24112473SScott.Carter@Oracle.COM 	if (((intr_p = DEVI(dip)->devi_intr_p) != NULL) &&
24212473SScott.Carter@Oracle.COM 	    ((req_p = intr_p->devi_irm_req_p) != NULL) &&
24312473SScott.Carter@Oracle.COM 	    (type == req_p->ireq_type) &&
24412473SScott.Carter@Oracle.COM 	    ((pool_p = req_p->ireq_pool_p) != NULL)) {
24512473SScott.Carter@Oracle.COM 		/*
24612473SScott.Carter@Oracle.COM 		 * Lock to be sure a rebalance is not in progress.
24712473SScott.Carter@Oracle.COM 		 * (Should be changed to a rwlock.)
24812473SScott.Carter@Oracle.COM 		 */
24912473SScott.Carter@Oracle.COM 		mutex_enter(&pool_p->ipool_navail_lock);
25012473SScott.Carter@Oracle.COM 		navail = req_p->ireq_navail;
25112473SScott.Carter@Oracle.COM 		mutex_exit(&pool_p->ipool_navail_lock);
25212473SScott.Carter@Oracle.COM 		return (navail);
25312473SScott.Carter@Oracle.COM 	}
2548561SScott.Carter@Sun.COM 
25512473SScott.Carter@Oracle.COM 	/* Otherwise, return the limit */
25612473SScott.Carter@Oracle.COM 	return (i_ddi_intr_get_limit(dip, type, NULL));
25712473SScott.Carter@Oracle.COM }
25812473SScott.Carter@Oracle.COM 
25912473SScott.Carter@Oracle.COM /*
26012473SScott.Carter@Oracle.COM  * i_ddi_intr_get_limit:
26112473SScott.Carter@Oracle.COM  *
26212473SScott.Carter@Oracle.COM  *	Return the limit of how many interrupts a driver can allocate.
26312473SScott.Carter@Oracle.COM  */
26412473SScott.Carter@Oracle.COM uint_t
i_ddi_intr_get_limit(dev_info_t * dip,int type,ddi_irm_pool_t * pool_p)26512473SScott.Carter@Oracle.COM i_ddi_intr_get_limit(dev_info_t *dip, int type, ddi_irm_pool_t *pool_p)
26612473SScott.Carter@Oracle.COM {
26712473SScott.Carter@Oracle.COM 	ddi_intr_handle_impl_t	hdl;
26812473SScott.Carter@Oracle.COM 	uint_t			limit, nintrs;
26912473SScott.Carter@Oracle.COM 
27012473SScott.Carter@Oracle.COM 	/* Check for interrupt pool */
27112473SScott.Carter@Oracle.COM 	if (pool_p == NULL)
27212473SScott.Carter@Oracle.COM 		pool_p = i_ddi_intr_get_pool(dip, type);
27312473SScott.Carter@Oracle.COM 
27412473SScott.Carter@Oracle.COM 	/* Get default limit, from interrupt pool or by INTROP method */
27512473SScott.Carter@Oracle.COM 	if (pool_p != NULL) {
27612473SScott.Carter@Oracle.COM 		limit = pool_p->ipool_defsz;
2778561SScott.Carter@Sun.COM 	} else {
2788561SScott.Carter@Sun.COM 		bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
2798561SScott.Carter@Sun.COM 		hdl.ih_dip = dip;
2808561SScott.Carter@Sun.COM 		hdl.ih_type = type;
2818561SScott.Carter@Sun.COM 		if (i_ddi_intr_ops(dip, dip, DDI_INTROP_NAVAIL, &hdl,
28212473SScott.Carter@Oracle.COM 		    (void *)&limit) != DDI_SUCCESS)
2838561SScott.Carter@Sun.COM 			return (0);
2848561SScott.Carter@Sun.COM 	}
2858561SScott.Carter@Sun.COM 
28612473SScott.Carter@Oracle.COM 	/* Get maximum supported by the device */
28712473SScott.Carter@Oracle.COM 	nintrs = i_ddi_intr_get_supported_nintrs(dip, type);
28812473SScott.Carter@Oracle.COM 
28912473SScott.Carter@Oracle.COM 	/* No limit if device and system both support IRM */
29012473SScott.Carter@Oracle.COM 	if ((pool_p != NULL) && (i_ddi_irm_supported(dip, type) == DDI_SUCCESS))
29112473SScott.Carter@Oracle.COM 		return (nintrs);
29212473SScott.Carter@Oracle.COM 
29312473SScott.Carter@Oracle.COM 	/* Limit cannot exceed what device supports */
29412473SScott.Carter@Oracle.COM 	limit = MIN(limit, nintrs);
29512473SScott.Carter@Oracle.COM 
29612473SScott.Carter@Oracle.COM 	/* Impose a global MSI-X limit on x86 */
2978925SEvan.Yan@Sun.COM #if defined(__i386) || defined(__amd64)
29812473SScott.Carter@Oracle.COM 	if (type == DDI_INTR_TYPE_MSIX)
29912473SScott.Carter@Oracle.COM 		limit = MIN(limit, ddi_msix_alloc_limit);
3008925SEvan.Yan@Sun.COM #endif
3018561SScott.Carter@Sun.COM 
30212473SScott.Carter@Oracle.COM 	/* Impose a global MSI limit on all platforms */
3038561SScott.Carter@Sun.COM 	if (type == DDI_INTR_TYPE_MSI)
30412473SScott.Carter@Oracle.COM 		limit = MIN(limit, DDI_MAX_MSI_ALLOC);
3058561SScott.Carter@Sun.COM 
30612473SScott.Carter@Oracle.COM 	return (limit);
3078561SScott.Carter@Sun.COM }
3088561SScott.Carter@Sun.COM 
3090Sstevel@tonic-gate ddi_intr_msix_t *
i_ddi_get_msix(dev_info_t * dip)3100Sstevel@tonic-gate i_ddi_get_msix(dev_info_t *dip)
3110Sstevel@tonic-gate {
3120Sstevel@tonic-gate 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	return (intr_p ? intr_p->devi_msix_p : NULL);
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate void
i_ddi_set_msix(dev_info_t * dip,ddi_intr_msix_t * msix_p)3180Sstevel@tonic-gate i_ddi_set_msix(dev_info_t *dip, ddi_intr_msix_t *msix_p)
3190Sstevel@tonic-gate {
3200Sstevel@tonic-gate 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	if (intr_p)
3230Sstevel@tonic-gate 		intr_p->devi_msix_p = msix_p;
3240Sstevel@tonic-gate }
3250Sstevel@tonic-gate 
3268561SScott.Carter@Sun.COM ddi_intr_handle_t
i_ddi_get_intr_handle(dev_info_t * dip,int inum)3270Sstevel@tonic-gate i_ddi_get_intr_handle(dev_info_t *dip, int inum)
3280Sstevel@tonic-gate {
3290Sstevel@tonic-gate 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 	if (intr_p == NULL)
3320Sstevel@tonic-gate 		return (NULL);
3330Sstevel@tonic-gate 
33414Sanish 	/*
33514Sanish 	 * Changed this to a check and return NULL if an invalid inum
33614Sanish 	 * is passed to retrieve a handle
33714Sanish 	 */
33814Sanish 	if ((inum < 0) || (inum >= intr_p->devi_intr_sup_nintrs))
33914Sanish 		return (NULL);
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	return ((intr_p->devi_intr_handle_p) ?
3420Sstevel@tonic-gate 	    intr_p->devi_intr_handle_p[inum] : NULL);
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate void
i_ddi_set_intr_handle(dev_info_t * dip,int inum,ddi_intr_handle_t intr_hdl)3468561SScott.Carter@Sun.COM i_ddi_set_intr_handle(dev_info_t *dip, int inum, ddi_intr_handle_t intr_hdl)
3470Sstevel@tonic-gate {
3480Sstevel@tonic-gate 	devinfo_intr_t	*intr_p = DEVI(dip)->devi_intr_p;
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	if (intr_p == NULL)
3510Sstevel@tonic-gate 		return;
3520Sstevel@tonic-gate 
35314Sanish 	/*
35414Sanish 	 * Changed this to a check and return if an invalid inum
35514Sanish 	 * is passed to set a handle
35614Sanish 	 */
35714Sanish 	if ((inum < 0) || (inum >= intr_p->devi_intr_sup_nintrs))
35814Sanish 		return;
3590Sstevel@tonic-gate 
3608561SScott.Carter@Sun.COM 	if (intr_hdl && (intr_p->devi_intr_handle_p == NULL)) {
3610Sstevel@tonic-gate 		/* nintrs could be zero; so check for it first */
3620Sstevel@tonic-gate 		if (intr_p->devi_intr_sup_nintrs)
3630Sstevel@tonic-gate 			intr_p->devi_intr_handle_p = kmem_zalloc(
3640Sstevel@tonic-gate 			    sizeof (ddi_intr_handle_t) *
3650Sstevel@tonic-gate 			    intr_p->devi_intr_sup_nintrs, KM_SLEEP);
3660Sstevel@tonic-gate 	}
3670Sstevel@tonic-gate 
368693Sgovinda 	if (intr_p->devi_intr_handle_p)
3698561SScott.Carter@Sun.COM 		intr_p->devi_intr_handle_p[inum] = intr_hdl;
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate /*
3730Sstevel@tonic-gate  * The "ddi-intr-weight" property contains the weight of each interrupt
3740Sstevel@tonic-gate  * associated with a dev_info node. For devices with multiple interrupts per
3750Sstevel@tonic-gate  * dev_info node, the total load of the device is "devi_intr_weight * nintr",
3760Sstevel@tonic-gate  * possibly spread out over multiple CPUs.
3770Sstevel@tonic-gate  *
3780Sstevel@tonic-gate  * Maintaining this as a property permits possible tweaking in the product
3790Sstevel@tonic-gate  * in response to customer problems via driver.conf property definitions at
3800Sstevel@tonic-gate  * the driver or the instance level.  This does not mean that "ddi-intr_weight"
3810Sstevel@tonic-gate  * is a formal or committed interface.
3820Sstevel@tonic-gate  */
3830Sstevel@tonic-gate int32_t
i_ddi_get_intr_weight(dev_info_t * dip)3840Sstevel@tonic-gate i_ddi_get_intr_weight(dev_info_t *dip)
3850Sstevel@tonic-gate {
3860Sstevel@tonic-gate 	int32_t	weight;
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	weight = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
3890Sstevel@tonic-gate 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "ddi-intr-weight", -1);
3900Sstevel@tonic-gate 	if (weight < -1)
3910Sstevel@tonic-gate 		weight = -1;			/* undefined */
3920Sstevel@tonic-gate 	return (weight);
3930Sstevel@tonic-gate }
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate int32_t
i_ddi_set_intr_weight(dev_info_t * dip,int32_t weight)3960Sstevel@tonic-gate i_ddi_set_intr_weight(dev_info_t *dip, int32_t weight)
3970Sstevel@tonic-gate {
3980Sstevel@tonic-gate 	int32_t oweight;
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	oweight = i_ddi_get_intr_weight(dip);
4010Sstevel@tonic-gate 	if ((weight > 0) && (oweight != weight))
4020Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
4030Sstevel@tonic-gate 		    "ddi-intr-weight", weight);
4040Sstevel@tonic-gate 	return (oweight);
4050Sstevel@tonic-gate }
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate /*
4080Sstevel@tonic-gate  * Old DDI interrupt framework
4090Sstevel@tonic-gate  *
4100Sstevel@tonic-gate  * NOTE:
4110Sstevel@tonic-gate  *	The following 4 busops entry points are obsoleted with version
4120Sstevel@tonic-gate  *	9 or greater. Use i_ddi_intr_op interface in place of these
4130Sstevel@tonic-gate  *	obsolete interfaces.
4140Sstevel@tonic-gate  *
4150Sstevel@tonic-gate  *	Remove these busops entry points and all related data structures
4160Sstevel@tonic-gate  *	in future major/minor solaris release.
4170Sstevel@tonic-gate  */
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate /* ARGSUSED */
4200Sstevel@tonic-gate ddi_intrspec_t
i_ddi_get_intrspec(dev_info_t * dip,dev_info_t * rdip,uint_t inumber)4210Sstevel@tonic-gate i_ddi_get_intrspec(dev_info_t *dip, dev_info_t *rdip, uint_t inumber)
4220Sstevel@tonic-gate {
4230Sstevel@tonic-gate 	dev_info_t	*pdip = ddi_get_parent(dip);
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	cmn_err(CE_WARN, "Failed to process interrupt "
4260Sstevel@tonic-gate 	    "for %s%d due to down-rev nexus driver %s%d",
427693Sgovinda 	    ddi_driver_name(rdip), ddi_get_instance(rdip),
428693Sgovinda 	    ddi_driver_name(pdip), ddi_get_instance(pdip));
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	return (NULL);
4310Sstevel@tonic-gate }
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate /* ARGSUSED */
4340Sstevel@tonic-gate int
i_ddi_add_intrspec(dev_info_t * dip,dev_info_t * rdip,ddi_intrspec_t intrspec,ddi_iblock_cookie_t * iblock_cookiep,ddi_idevice_cookie_t * idevice_cookiep,uint_t (* int_handler)(caddr_t int_handler_arg),caddr_t int_handler_arg,int kind)4350Sstevel@tonic-gate i_ddi_add_intrspec(dev_info_t *dip, dev_info_t *rdip, ddi_intrspec_t intrspec,
4360Sstevel@tonic-gate     ddi_iblock_cookie_t *iblock_cookiep,
4370Sstevel@tonic-gate     ddi_idevice_cookie_t *idevice_cookiep,
4380Sstevel@tonic-gate     uint_t (*int_handler)(caddr_t int_handler_arg),
4390Sstevel@tonic-gate     caddr_t int_handler_arg, int kind)
4400Sstevel@tonic-gate {
4410Sstevel@tonic-gate 	dev_info_t	*pdip = ddi_get_parent(dip);
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	cmn_err(CE_WARN, "Failed to process interrupt "
4440Sstevel@tonic-gate 	    "for %s%d due to down-rev nexus driver %s%d",
445693Sgovinda 	    ddi_driver_name(rdip), ddi_get_instance(rdip),
446693Sgovinda 	    ddi_driver_name(pdip), ddi_get_instance(pdip));
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	return (DDI_ENOTSUP);
4490Sstevel@tonic-gate }
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate /* ARGSUSED */
4520Sstevel@tonic-gate void
i_ddi_remove_intrspec(dev_info_t * dip,dev_info_t * rdip,ddi_intrspec_t intrspec,ddi_iblock_cookie_t iblock_cookie)4530Sstevel@tonic-gate i_ddi_remove_intrspec(dev_info_t *dip, dev_info_t *rdip,
4540Sstevel@tonic-gate     ddi_intrspec_t intrspec, ddi_iblock_cookie_t iblock_cookie)
4550Sstevel@tonic-gate {
4560Sstevel@tonic-gate 	dev_info_t	*pdip = ddi_get_parent(dip);
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	cmn_err(CE_WARN, "Failed to process interrupt "
4590Sstevel@tonic-gate 	    "for %s%d due to down-rev nexus driver %s%d",
460693Sgovinda 	    ddi_driver_name(rdip), ddi_get_instance(rdip),
461693Sgovinda 	    ddi_driver_name(pdip), ddi_get_instance(pdip));
4620Sstevel@tonic-gate }
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate /* ARGSUSED */
4650Sstevel@tonic-gate int
i_ddi_intr_ctlops(dev_info_t * dip,dev_info_t * rdip,ddi_intr_ctlop_t op,void * arg,void * val)4660Sstevel@tonic-gate i_ddi_intr_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_ctlop_t op,
4670Sstevel@tonic-gate     void *arg, void *val)
4680Sstevel@tonic-gate {
4690Sstevel@tonic-gate 	dev_info_t	*pdip = ddi_get_parent(dip);
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	cmn_err(CE_WARN, "Failed to process interrupt "
4720Sstevel@tonic-gate 	    "for %s%d due to down-rev nexus driver %s%d",
473693Sgovinda 	    ddi_driver_name(rdip), ddi_get_instance(rdip),
474693Sgovinda 	    ddi_driver_name(pdip), ddi_get_instance(pdip));
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	return (DDI_ENOTSUP);
4770Sstevel@tonic-gate }
4781997Sanish 
479*12564SGongtian.Zhao@Sun.COM /*
480*12564SGongtian.Zhao@Sun.COM  * Interrupt target get/set functions
481*12564SGongtian.Zhao@Sun.COM  */
482*12564SGongtian.Zhao@Sun.COM int
get_intr_affinity(ddi_intr_handle_t h,processorid_t * tgt_p)483*12564SGongtian.Zhao@Sun.COM get_intr_affinity(ddi_intr_handle_t h, processorid_t *tgt_p)
484*12564SGongtian.Zhao@Sun.COM {
485*12564SGongtian.Zhao@Sun.COM 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
486*12564SGongtian.Zhao@Sun.COM 	int			ret;
487*12564SGongtian.Zhao@Sun.COM 
488*12564SGongtian.Zhao@Sun.COM 	DDI_INTR_APIDBG((CE_CONT, "get_intr_affinity: hdlp = %p\n",
489*12564SGongtian.Zhao@Sun.COM 	    (void *)hdlp));
490*12564SGongtian.Zhao@Sun.COM 
491*12564SGongtian.Zhao@Sun.COM 	if ((hdlp == NULL) || (tgt_p == NULL))
492*12564SGongtian.Zhao@Sun.COM 		return (DDI_EINVAL);
493*12564SGongtian.Zhao@Sun.COM 
494*12564SGongtian.Zhao@Sun.COM 	rw_enter(&hdlp->ih_rwlock, RW_READER);
495*12564SGongtian.Zhao@Sun.COM 	if (hdlp->ih_state != DDI_IHDL_STATE_ENABLE) {
496*12564SGongtian.Zhao@Sun.COM 		rw_exit(&hdlp->ih_rwlock);
497*12564SGongtian.Zhao@Sun.COM 		return (DDI_EINVAL);
498*12564SGongtian.Zhao@Sun.COM 	}
499*12564SGongtian.Zhao@Sun.COM 
500*12564SGongtian.Zhao@Sun.COM 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
501*12564SGongtian.Zhao@Sun.COM 	    DDI_INTROP_GETTARGET, hdlp, (void *)tgt_p);
502*12564SGongtian.Zhao@Sun.COM 
503*12564SGongtian.Zhao@Sun.COM 	DDI_INTR_APIDBG((CE_CONT, "get_intr_affinity: target %x\n",
504*12564SGongtian.Zhao@Sun.COM 	    *tgt_p));
505*12564SGongtian.Zhao@Sun.COM 
506*12564SGongtian.Zhao@Sun.COM 	if (ret == DDI_SUCCESS)
507*12564SGongtian.Zhao@Sun.COM 		hdlp->ih_target = *tgt_p;
508*12564SGongtian.Zhao@Sun.COM 
509*12564SGongtian.Zhao@Sun.COM 	rw_exit(&hdlp->ih_rwlock);
510*12564SGongtian.Zhao@Sun.COM 	return (ret);
511*12564SGongtian.Zhao@Sun.COM }
512*12564SGongtian.Zhao@Sun.COM 
513*12564SGongtian.Zhao@Sun.COM int
set_intr_affinity(ddi_intr_handle_t h,processorid_t tgt)514*12564SGongtian.Zhao@Sun.COM set_intr_affinity(ddi_intr_handle_t h, processorid_t tgt)
515*12564SGongtian.Zhao@Sun.COM {
516*12564SGongtian.Zhao@Sun.COM 	ddi_intr_handle_impl_t	*hdlp = (ddi_intr_handle_impl_t *)h;
517*12564SGongtian.Zhao@Sun.COM 	int			ret;
518*12564SGongtian.Zhao@Sun.COM 
519*12564SGongtian.Zhao@Sun.COM 	DDI_INTR_APIDBG((CE_CONT, "set_intr_affinity: hdlp = %p "
520*12564SGongtian.Zhao@Sun.COM 	    "target %x\n", (void *)hdlp, tgt));
521*12564SGongtian.Zhao@Sun.COM 
522*12564SGongtian.Zhao@Sun.COM 	if (hdlp == NULL)
523*12564SGongtian.Zhao@Sun.COM 		return (DDI_EINVAL);
524*12564SGongtian.Zhao@Sun.COM 
525*12564SGongtian.Zhao@Sun.COM 	rw_enter(&hdlp->ih_rwlock, RW_WRITER);
526*12564SGongtian.Zhao@Sun.COM 	if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
527*12564SGongtian.Zhao@Sun.COM 	    (hdlp->ih_type != DDI_INTR_TYPE_MSIX)) {
528*12564SGongtian.Zhao@Sun.COM 		rw_exit(&hdlp->ih_rwlock);
529*12564SGongtian.Zhao@Sun.COM 		return (DDI_EINVAL);
530*12564SGongtian.Zhao@Sun.COM 	}
531*12564SGongtian.Zhao@Sun.COM 
532*12564SGongtian.Zhao@Sun.COM 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
533*12564SGongtian.Zhao@Sun.COM 	    DDI_INTROP_SETTARGET, hdlp, &tgt);
534*12564SGongtian.Zhao@Sun.COM 
535*12564SGongtian.Zhao@Sun.COM 	if (ret == DDI_SUCCESS)
536*12564SGongtian.Zhao@Sun.COM 		hdlp->ih_target = tgt;
537*12564SGongtian.Zhao@Sun.COM 
538*12564SGongtian.Zhao@Sun.COM 	rw_exit(&hdlp->ih_rwlock);
539*12564SGongtian.Zhao@Sun.COM 	return (ret);
540*12564SGongtian.Zhao@Sun.COM }
541*12564SGongtian.Zhao@Sun.COM 
5421997Sanish #if defined(__i386) || defined(__amd64)
5431997Sanish ddi_acc_handle_t
i_ddi_get_pci_config_handle(dev_info_t * dip)5441997Sanish i_ddi_get_pci_config_handle(dev_info_t *dip)
5451997Sanish {
5461997Sanish 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
5471997Sanish 
5481997Sanish 	return (intr_p ? intr_p->devi_cfg_handle : NULL);
5491997Sanish }
5501997Sanish 
5511997Sanish void
i_ddi_set_pci_config_handle(dev_info_t * dip,ddi_acc_handle_t handle)5521997Sanish i_ddi_set_pci_config_handle(dev_info_t *dip, ddi_acc_handle_t handle)
5531997Sanish {
5541997Sanish 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
5551997Sanish 
5561997Sanish 	if (intr_p)
5571997Sanish 		intr_p->devi_cfg_handle = handle;
5581997Sanish }
5591997Sanish 
5601997Sanish 
5611997Sanish int
i_ddi_get_msi_msix_cap_ptr(dev_info_t * dip)5621997Sanish i_ddi_get_msi_msix_cap_ptr(dev_info_t *dip)
5631997Sanish {
5641997Sanish 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
5651997Sanish 
5661997Sanish 	return (intr_p ? intr_p->devi_cap_ptr : 0);
5671997Sanish }
5681997Sanish 
5691997Sanish void
i_ddi_set_msi_msix_cap_ptr(dev_info_t * dip,int cap_ptr)5701997Sanish i_ddi_set_msi_msix_cap_ptr(dev_info_t *dip, int cap_ptr)
5711997Sanish {
5721997Sanish 	devinfo_intr_t *intr_p = DEVI(dip)->devi_intr_p;
5731997Sanish 
5741997Sanish 	if (intr_p)
5751997Sanish 		intr_p->devi_cap_ptr = cap_ptr;
5761997Sanish }
5771997Sanish #endif
578