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