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 51542Sjohnny * Common Development and Distribution License (the "License"). 61542Sjohnny * 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 /* 221542Sjohnny * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <sys/note.h> 290Sstevel@tonic-gate #include <sys/sysmacros.h> 300Sstevel@tonic-gate #include <sys/types.h> 310Sstevel@tonic-gate #include <sys/param.h> 320Sstevel@tonic-gate #include <sys/systm.h> 330Sstevel@tonic-gate #include <sys/kmem.h> 340Sstevel@tonic-gate #include <sys/cmn_err.h> 350Sstevel@tonic-gate #include <sys/debug.h> 360Sstevel@tonic-gate #include <sys/avintr.h> 370Sstevel@tonic-gate #include <sys/autoconf.h> 380Sstevel@tonic-gate #include <sys/sunndi.h> 390Sstevel@tonic-gate #include <sys/ndi_impldefs.h> /* include prototypes */ 40*1725Segillett #include <sys/atomic.h> 410Sstevel@tonic-gate 420Sstevel@tonic-gate /* 430Sstevel@tonic-gate * New DDI interrupt framework 440Sstevel@tonic-gate */ 450Sstevel@tonic-gate 460Sstevel@tonic-gate /* 470Sstevel@tonic-gate * MSI/X allocation limit. 480Sstevel@tonic-gate * This limit will change with Resource Management support. 490Sstevel@tonic-gate */ 500Sstevel@tonic-gate uint_t ddi_msix_alloc_limit = 2; 510Sstevel@tonic-gate 520Sstevel@tonic-gate /* 530Sstevel@tonic-gate * ddi_intr_get_supported_types: 540Sstevel@tonic-gate * Return, as a bit mask, the hardware interrupt types supported by 550Sstevel@tonic-gate * both the device and by the host in the integer pointed 560Sstevel@tonic-gate * to be the 'typesp' argument. 570Sstevel@tonic-gate */ 580Sstevel@tonic-gate int 590Sstevel@tonic-gate ddi_intr_get_supported_types(dev_info_t *dip, int *typesp) 600Sstevel@tonic-gate { 610Sstevel@tonic-gate int ret; 620Sstevel@tonic-gate ddi_intr_handle_impl_t hdl; 630Sstevel@tonic-gate 640Sstevel@tonic-gate if (dip == NULL) 650Sstevel@tonic-gate return (DDI_EINVAL); 660Sstevel@tonic-gate 670Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: dip %p\n", 680Sstevel@tonic-gate (void *)dip)); 690Sstevel@tonic-gate 700Sstevel@tonic-gate if (*typesp = i_ddi_intr_get_supported_types(dip)) 710Sstevel@tonic-gate return (DDI_SUCCESS); 720Sstevel@tonic-gate 730Sstevel@tonic-gate bzero(&hdl, sizeof (ddi_intr_handle_impl_t)); 740Sstevel@tonic-gate hdl.ih_dip = dip; 750Sstevel@tonic-gate 76693Sgovinda ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_SUPPORTED_TYPES, &hdl, 770Sstevel@tonic-gate (void *)typesp); 780Sstevel@tonic-gate 790Sstevel@tonic-gate if (ret != DDI_SUCCESS) 800Sstevel@tonic-gate return (DDI_INTR_NOTFOUND); 810Sstevel@tonic-gate 820Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: types %x\n", 830Sstevel@tonic-gate *typesp)); 840Sstevel@tonic-gate 850Sstevel@tonic-gate return (ret); 860Sstevel@tonic-gate } 870Sstevel@tonic-gate 880Sstevel@tonic-gate 890Sstevel@tonic-gate /* 900Sstevel@tonic-gate * ddi_intr_get_nintrs: 910Sstevel@tonic-gate * Return as an integer in the integer pointed to by the argument 920Sstevel@tonic-gate * *nintrsp*, the number of interrupts the device supports for the 930Sstevel@tonic-gate * given interrupt type. 940Sstevel@tonic-gate */ 950Sstevel@tonic-gate int 960Sstevel@tonic-gate ddi_intr_get_nintrs(dev_info_t *dip, int type, int *nintrsp) 970Sstevel@tonic-gate { 980Sstevel@tonic-gate int ret; 990Sstevel@tonic-gate ddi_intr_handle_impl_t hdl; 1000Sstevel@tonic-gate 101693Sgovinda DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs: dip %p, type: %d\n", 102693Sgovinda (void *)dip, type)); 1030Sstevel@tonic-gate 104693Sgovinda if ((dip == NULL) || (type & ~(DDI_INTR_SUP_TYPES))) { 105693Sgovinda *nintrsp = 0; 106693Sgovinda return (DDI_EINVAL); 107693Sgovinda } 1080Sstevel@tonic-gate 109693Sgovinda if (!(i_ddi_intr_get_supported_types(dip) & type)) { 110693Sgovinda *nintrsp = 0; 1110Sstevel@tonic-gate return (DDI_EINVAL); 112693Sgovinda } 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate if (*nintrsp = i_ddi_intr_get_supported_nintrs(dip, type)) 1150Sstevel@tonic-gate return (DDI_SUCCESS); 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate bzero(&hdl, sizeof (ddi_intr_handle_impl_t)); 1180Sstevel@tonic-gate hdl.ih_dip = dip; 1190Sstevel@tonic-gate hdl.ih_type = type; 1200Sstevel@tonic-gate 121693Sgovinda ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_NINTRS, &hdl, 1220Sstevel@tonic-gate (void *)nintrsp); 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs:: nintrs %x\n", 1250Sstevel@tonic-gate *nintrsp)); 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate return (ret); 1280Sstevel@tonic-gate } 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate /* 1320Sstevel@tonic-gate * ddi_intr_get_navail: 1330Sstevel@tonic-gate * Bus nexus driver will return availble interrupt count value for 1340Sstevel@tonic-gate * a given interrupt type. 1350Sstevel@tonic-gate * 1360Sstevel@tonic-gate * Return as an integer in the integer pointed to by the argument 1370Sstevel@tonic-gate * *navailp*, the number of interrupts currently available for the 1380Sstevel@tonic-gate * given interrupt type. 1390Sstevel@tonic-gate */ 1400Sstevel@tonic-gate int 1410Sstevel@tonic-gate ddi_intr_get_navail(dev_info_t *dip, int type, int *navailp) 1420Sstevel@tonic-gate { 1430Sstevel@tonic-gate int ret; 1440Sstevel@tonic-gate ddi_intr_handle_impl_t hdl; 1450Sstevel@tonic-gate 146693Sgovinda DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_navail: dip %p, type: %d\n", 147693Sgovinda (void *)dip, type)); 1480Sstevel@tonic-gate 149693Sgovinda if ((dip == NULL) || (type & ~(DDI_INTR_SUP_TYPES))) { 150693Sgovinda *navailp = 0; 1510Sstevel@tonic-gate return (DDI_EINVAL); 152693Sgovinda } 1530Sstevel@tonic-gate 154693Sgovinda if (!(i_ddi_intr_get_supported_types(dip) & type)) { 155693Sgovinda *navailp = 0; 1560Sstevel@tonic-gate return (DDI_EINVAL); 157693Sgovinda } 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate /* 1600Sstevel@tonic-gate * In future, this interface implementation will change 1610Sstevel@tonic-gate * with Resource Management support. 1620Sstevel@tonic-gate */ 1630Sstevel@tonic-gate bzero(&hdl, sizeof (ddi_intr_handle_impl_t)); 1640Sstevel@tonic-gate hdl.ih_dip = dip; 1650Sstevel@tonic-gate hdl.ih_type = type; 1660Sstevel@tonic-gate 167693Sgovinda ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_NAVAIL, &hdl, 168693Sgovinda (void *)navailp); 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate return (ret == DDI_SUCCESS ? DDI_SUCCESS : DDI_INTR_NOTFOUND); 1710Sstevel@tonic-gate } 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate /* 1750Sstevel@tonic-gate * Interrupt allocate/free functions 1760Sstevel@tonic-gate */ 1770Sstevel@tonic-gate int 1780Sstevel@tonic-gate ddi_intr_alloc(dev_info_t *dip, ddi_intr_handle_t *h_array, int type, int inum, 1790Sstevel@tonic-gate int count, int *actualp, int behavior) 1800Sstevel@tonic-gate { 1810Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, tmp_hdl; 1820Sstevel@tonic-gate int i, ret, cap = 0, intr_type, nintrs = 0; 1830Sstevel@tonic-gate uint_t pri; 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: name %s dip 0x%p " 1860Sstevel@tonic-gate "type %x inum %x count %x behavior %x\n", ddi_driver_name(dip), 1870Sstevel@tonic-gate (void *)dip, type, inum, count, behavior)); 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate /* Validate parameters */ 1900Sstevel@tonic-gate if (dip == NULL || h_array == NULL || count < 1) { 1910Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Invalid args\n")); 1920Sstevel@tonic-gate return (DDI_EINVAL); 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate /* Validate interrupt type */ 1960Sstevel@tonic-gate if (!(i_ddi_intr_get_supported_types(dip) & type)) { 1970Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x not " 1980Sstevel@tonic-gate "supported\n", type)); 1990Sstevel@tonic-gate return (DDI_EINVAL); 2000Sstevel@tonic-gate } 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate /* First, get how many interrupts the device supports */ 2030Sstevel@tonic-gate if (!(nintrs = i_ddi_intr_get_supported_nintrs(dip, type))) { 2040Sstevel@tonic-gate if (ddi_intr_get_nintrs(dip, type, &nintrs) != DDI_SUCCESS) { 2050Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no " 2060Sstevel@tonic-gate "interrupts found of type %d\n", type)); 2070Sstevel@tonic-gate return (DDI_INTR_NOTFOUND); 2080Sstevel@tonic-gate } 2090Sstevel@tonic-gate } 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate /* Is this function invoked with more interrupt than device supports? */ 2120Sstevel@tonic-gate if (count > nintrs) { 2130Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no of interrupts " 2140Sstevel@tonic-gate "requested %d is more than supported %d\n", count, nintrs)); 2150Sstevel@tonic-gate return (DDI_EINVAL); 2160Sstevel@tonic-gate } 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate /* 2190Sstevel@tonic-gate * Check if requested interrupt type is not same as interrupt 2200Sstevel@tonic-gate * type is in use if any. 2210Sstevel@tonic-gate */ 2220Sstevel@tonic-gate if (((intr_type = i_ddi_intr_get_current_type(dip)) != 0) && 2230Sstevel@tonic-gate (intr_type != type)) { 2240Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Requested " 2250Sstevel@tonic-gate "interrupt type %x is different from interrupt type %x" 2260Sstevel@tonic-gate "already in use\n", type, intr_type)); 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate return (DDI_EINVAL); 2290Sstevel@tonic-gate } 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate /* 2320Sstevel@tonic-gate * Check if requested interrupt type is in use and requested number 2330Sstevel@tonic-gate * of interrupts and number of interrupts already in use exceeds the 2340Sstevel@tonic-gate * number of interrupts supported by this device. 2350Sstevel@tonic-gate */ 2360Sstevel@tonic-gate if (intr_type) { 2370Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x " 2380Sstevel@tonic-gate "is already being used\n", type)); 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate if ((count + i_ddi_intr_get_current_nintrs(dip)) > nintrs) { 2410Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: count %d " 2420Sstevel@tonic-gate "+ intrs in use %d exceeds supported %d intrs\n", 2430Sstevel@tonic-gate count, i_ddi_intr_get_current_nintrs(dip), nintrs)); 2440Sstevel@tonic-gate return (DDI_EINVAL); 2450Sstevel@tonic-gate } 2460Sstevel@tonic-gate } 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate /* 2490Sstevel@tonic-gate * For MSI, ensure that the requested interrupt count is a power of 2 2500Sstevel@tonic-gate */ 2510Sstevel@tonic-gate if (type == DDI_INTR_TYPE_MSI && !ISP2(count)) { 2520Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: " 2530Sstevel@tonic-gate "MSI count %d is not a power of two\n", count)); 2540Sstevel@tonic-gate return (DDI_EINVAL); 2550Sstevel@tonic-gate } 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate /* 2580Sstevel@tonic-gate * Limit max MSI/X allocation to ddi_msix_alloc_limit. 2590Sstevel@tonic-gate * This limit will change with Resource Management support. 2600Sstevel@tonic-gate */ 2610Sstevel@tonic-gate if (DDI_INTR_IS_MSI_OR_MSIX(type) && (count > ddi_msix_alloc_limit)) { 2620Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Requested MSI/Xs %d" 2630Sstevel@tonic-gate "Max MSI/Xs limit %d\n", count, ddi_msix_alloc_limit)); 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate if (behavior == DDI_INTR_ALLOC_STRICT) { 2660Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: " 2670Sstevel@tonic-gate "DDI_INTR_ALLOC_STRICT flag is passed, " 2680Sstevel@tonic-gate "return failure\n")); 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate return (DDI_EAGAIN); 2710Sstevel@tonic-gate } 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate count = ddi_msix_alloc_limit; 2740Sstevel@tonic-gate } 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate /* Now allocate required number of interrupts */ 2770Sstevel@tonic-gate bzero(&tmp_hdl, sizeof (ddi_intr_handle_impl_t)); 2780Sstevel@tonic-gate tmp_hdl.ih_type = type; 2790Sstevel@tonic-gate tmp_hdl.ih_inum = inum; 2800Sstevel@tonic-gate tmp_hdl.ih_scratch1 = count; 2811717Swesolows tmp_hdl.ih_scratch2 = (void *)(uintptr_t)behavior; 2820Sstevel@tonic-gate tmp_hdl.ih_dip = dip; 2830Sstevel@tonic-gate 284*1725Segillett i_ddi_intr_devi_init(dip); 285*1725Segillett 286693Sgovinda if (i_ddi_intr_ops(dip, dip, DDI_INTROP_ALLOC, 2870Sstevel@tonic-gate &tmp_hdl, (void *)actualp) != DDI_SUCCESS) { 2880Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: allocation " 2890Sstevel@tonic-gate "failed\n")); 290*1725Segillett i_ddi_intr_devi_fini(dip); 2910Sstevel@tonic-gate return (*actualp ? DDI_EAGAIN : DDI_INTR_NOTFOUND); 2920Sstevel@tonic-gate } 2930Sstevel@tonic-gate 294693Sgovinda if ((ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_GETPRI, 2950Sstevel@tonic-gate &tmp_hdl, (void *)&pri)) != DDI_SUCCESS) { 2960Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get priority " 2970Sstevel@tonic-gate "failed\n")); 298*1725Segillett goto fail; 2990Sstevel@tonic-gate } 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: getting capability\n")); 3020Sstevel@tonic-gate 303693Sgovinda if ((ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_GETCAP, 3040Sstevel@tonic-gate &tmp_hdl, (void *)&cap)) != DDI_SUCCESS) { 3050Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get capability " 3060Sstevel@tonic-gate "failed\n")); 307*1725Segillett goto fail; 3080Sstevel@tonic-gate } 3090Sstevel@tonic-gate 310*1725Segillett /* 311*1725Segillett * Save current interrupt type, supported and current intr count. 312*1725Segillett */ 3130Sstevel@tonic-gate i_ddi_intr_set_current_type(dip, type); 3140Sstevel@tonic-gate i_ddi_intr_set_supported_nintrs(dip, nintrs); 3150Sstevel@tonic-gate i_ddi_intr_set_current_nintrs(dip, 3160Sstevel@tonic-gate i_ddi_intr_get_current_nintrs(dip) + *actualp); 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate /* Now, go and handle each "handle" */ 3190Sstevel@tonic-gate for (i = 0; i < *actualp; i++) { 3200Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)kmem_zalloc( 3210Sstevel@tonic-gate (sizeof (ddi_intr_handle_impl_t)), KM_SLEEP); 3220Sstevel@tonic-gate rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL); 3230Sstevel@tonic-gate h_array[i] = (struct __ddi_intr_handle *)hdlp; 3240Sstevel@tonic-gate hdlp->ih_type = type; 3250Sstevel@tonic-gate hdlp->ih_pri = pri; 3260Sstevel@tonic-gate hdlp->ih_cap = cap; 3270Sstevel@tonic-gate hdlp->ih_ver = DDI_INTR_VERSION; 3280Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ALLOC; 3290Sstevel@tonic-gate hdlp->ih_dip = dip; 3300Sstevel@tonic-gate hdlp->ih_inum = inum + i; 331916Sschwartz i_ddi_alloc_intr_phdl(hdlp); 3320Sstevel@tonic-gate if (type & DDI_INTR_TYPE_FIXED) 3339Segillett i_ddi_set_intr_handle(dip, hdlp->ih_inum, &h_array[i]); 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: hdlp = 0x%p\n", 3360Sstevel@tonic-gate (void *)h_array[i])); 3370Sstevel@tonic-gate } 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate return (DDI_SUCCESS); 340*1725Segillett 341*1725Segillett fail: 342*1725Segillett (void) i_ddi_intr_ops(tmp_hdl.ih_dip, tmp_hdl.ih_dip, 343*1725Segillett DDI_INTROP_FREE, &tmp_hdl, NULL); 344*1725Segillett i_ddi_intr_devi_fini(dip); 345*1725Segillett 346*1725Segillett return (ret); 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate int 3510Sstevel@tonic-gate ddi_intr_free(ddi_intr_handle_t h) 3520Sstevel@tonic-gate { 3530Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 3540Sstevel@tonic-gate int ret; 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_free: hdlp = %p\n", (void *)hdlp)); 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate if (hdlp == NULL) 3590Sstevel@tonic-gate return (DDI_EINVAL); 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 362*1725Segillett if (((hdlp->ih_flags & DDI_INTR_MSIX_DUP) && 363*1725Segillett (hdlp->ih_state != DDI_IHDL_STATE_ADDED)) || 364*1725Segillett ((hdlp->ih_state != DDI_IHDL_STATE_ALLOC) && 365*1725Segillett (!(hdlp->ih_flags & DDI_INTR_MSIX_DUP)))) { 3660Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 3670Sstevel@tonic-gate return (DDI_EINVAL); 3680Sstevel@tonic-gate } 3690Sstevel@tonic-gate 370693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 3710Sstevel@tonic-gate DDI_INTROP_FREE, hdlp, NULL); 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 3740Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 375*1725Segillett /* This would be the dup vector */ 376*1725Segillett if (hdlp->ih_flags & DDI_INTR_MSIX_DUP) 377*1725Segillett atomic_dec_32(&hdlp->ih_main->ih_dup_cnt); 378*1725Segillett else { 379*1725Segillett i_ddi_intr_set_current_nintrs(hdlp->ih_dip, 380*1725Segillett i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1); 3810Sstevel@tonic-gate 382*1725Segillett if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) == 0) { 383*1725Segillett i_ddi_intr_devi_fini(hdlp->ih_dip); 384*1725Segillett } else { 385*1725Segillett if (hdlp->ih_type & DDI_INTR_TYPE_FIXED) 386*1725Segillett i_ddi_set_intr_handle(hdlp->ih_dip, 387*1725Segillett hdlp->ih_inum, NULL); 388*1725Segillett } 389*1725Segillett 390*1725Segillett i_ddi_free_intr_phdl(hdlp); 391693Sgovinda } 3920Sstevel@tonic-gate rw_destroy(&hdlp->ih_rwlock); 3930Sstevel@tonic-gate kmem_free(hdlp, sizeof (ddi_intr_handle_impl_t)); 3940Sstevel@tonic-gate } 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate return (ret); 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate /* 4000Sstevel@tonic-gate * Interrupt get/set capacity functions 4010Sstevel@tonic-gate * 4020Sstevel@tonic-gate * The logic used to figure this out is shown here: 4030Sstevel@tonic-gate * 4040Sstevel@tonic-gate * Device level Platform level Intr source 4050Sstevel@tonic-gate * 1. Fixed interrupts 4060Sstevel@tonic-gate * (non-PCI) 4070Sstevel@tonic-gate * o Flags supported N/A Maskable/Pending/ rootnex 4080Sstevel@tonic-gate * No Block Enable 4090Sstevel@tonic-gate * o navail 1 4100Sstevel@tonic-gate * 4110Sstevel@tonic-gate * 2. PCI Fixed interrupts 4120Sstevel@tonic-gate * o Flags supported pending/Maskable Maskable/pending/ pci 4130Sstevel@tonic-gate * No Block enable 4140Sstevel@tonic-gate * o navail N/A 1 4150Sstevel@tonic-gate * 4160Sstevel@tonic-gate * 3. PCI MSI 4170Sstevel@tonic-gate * o Flags supported Maskable/Pending Maskable/Pending pci 4180Sstevel@tonic-gate * Block Enable (if drvr doesn't) Block Enable 4190Sstevel@tonic-gate * o navail N/A #vectors - #used N/A 4200Sstevel@tonic-gate * 4210Sstevel@tonic-gate * 4. PCI MSI-X 4220Sstevel@tonic-gate * o Flags supported Maskable/Pending Maskable/Pending pci 4230Sstevel@tonic-gate * Block Enable Block Enable 4240Sstevel@tonic-gate * o navail N/A #vectors - #used N/A 4250Sstevel@tonic-gate * 4260Sstevel@tonic-gate * where: 4270Sstevel@tonic-gate * #vectors - Total numbers of vectors available 4280Sstevel@tonic-gate * #used - Total numbers of vectors currently being used 4290Sstevel@tonic-gate * 4300Sstevel@tonic-gate * For devices complying to PCI2.3 or greater, see bit10 of Command Register 4310Sstevel@tonic-gate * 0 - enables assertion of INTx 4320Sstevel@tonic-gate * 1 - disables assertion of INTx 4330Sstevel@tonic-gate * 4340Sstevel@tonic-gate * For non MSI/X interrupts; if the IRQ is shared then all ddi_intr_set_*() 4350Sstevel@tonic-gate * operations return failure. 4360Sstevel@tonic-gate */ 4370Sstevel@tonic-gate int 4380Sstevel@tonic-gate ddi_intr_get_cap(ddi_intr_handle_t h, int *flagsp) 4390Sstevel@tonic-gate { 4400Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 4410Sstevel@tonic-gate int ret; 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_cap: hdlp = %p\n", 4440Sstevel@tonic-gate (void *)hdlp)); 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate *flagsp = 0; 4470Sstevel@tonic-gate if (hdlp == NULL) 4480Sstevel@tonic-gate return (DDI_EINVAL); 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate if (hdlp->ih_cap) { 4530Sstevel@tonic-gate *flagsp = hdlp->ih_cap & ~DDI_INTR_FLAG_MSI64; 4540Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 4550Sstevel@tonic-gate return (DDI_SUCCESS); 4560Sstevel@tonic-gate } 4570Sstevel@tonic-gate 458693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 4590Sstevel@tonic-gate DDI_INTROP_GETCAP, hdlp, (void *)flagsp); 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 4620Sstevel@tonic-gate hdlp->ih_cap = *flagsp; 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate /* Mask out MSI/X 64-bit support to the consumer */ 4650Sstevel@tonic-gate *flagsp &= ~DDI_INTR_FLAG_MSI64; 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate 4680Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 4690Sstevel@tonic-gate return (ret); 4700Sstevel@tonic-gate } 4710Sstevel@tonic-gate 4720Sstevel@tonic-gate int 4730Sstevel@tonic-gate ddi_intr_set_cap(ddi_intr_handle_t h, int flags) 4740Sstevel@tonic-gate { 4750Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 4760Sstevel@tonic-gate int ret; 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_cap: hdlp = %p", (void *)hdlp)); 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate if (hdlp == NULL) 4810Sstevel@tonic-gate return (DDI_EINVAL); 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 4840Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) { 4850Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 4860Sstevel@tonic-gate return (DDI_EINVAL); 4870Sstevel@tonic-gate } 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate /* Only DDI_INTR_FLAG_LEVEL or DDI_INTR_FLAG_EDGE are allowed */ 4900Sstevel@tonic-gate if (!(flags & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) { 4910Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "%s%d: only LEVEL or EDGE capability " 4920Sstevel@tonic-gate "can be set\n", ddi_driver_name(hdlp->ih_dip), 4930Sstevel@tonic-gate ddi_get_instance(hdlp->ih_dip))); 4940Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 4950Sstevel@tonic-gate return (DDI_EINVAL); 4960Sstevel@tonic-gate } 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate /* Both level/edge flags must be currently supported */ 4990Sstevel@tonic-gate if (!(hdlp->ih_cap & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) { 5000Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "%s%d: Both LEVEL and EDGE capability" 5010Sstevel@tonic-gate " must be supported\n", ddi_driver_name(hdlp->ih_dip), 5020Sstevel@tonic-gate ddi_get_instance(hdlp->ih_dip))); 5030Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 5040Sstevel@tonic-gate return (DDI_ENOTSUP); 5050Sstevel@tonic-gate } 5060Sstevel@tonic-gate 507693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 5080Sstevel@tonic-gate DDI_INTROP_SETCAP, hdlp, &flags); 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 5110Sstevel@tonic-gate return (ret); 5120Sstevel@tonic-gate } 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate /* 5150Sstevel@tonic-gate * Priority related functions 5160Sstevel@tonic-gate */ 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate /* 5190Sstevel@tonic-gate * ddi_intr_get_hilevel_pri: 5200Sstevel@tonic-gate * Returns the minimum priority level for a 5210Sstevel@tonic-gate * high-level interrupt on a platform. 5220Sstevel@tonic-gate */ 5230Sstevel@tonic-gate uint_t 5240Sstevel@tonic-gate ddi_intr_get_hilevel_pri(void) 5250Sstevel@tonic-gate { 5260Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_hilevel_pri:\n")); 5270Sstevel@tonic-gate return (LOCK_LEVEL + 1); 5280Sstevel@tonic-gate } 5290Sstevel@tonic-gate 5300Sstevel@tonic-gate int 5310Sstevel@tonic-gate ddi_intr_get_pri(ddi_intr_handle_t h, uint_t *prip) 5320Sstevel@tonic-gate { 5330Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 5340Sstevel@tonic-gate int ret; 5350Sstevel@tonic-gate 5360Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pri: hdlp = %p\n", 5370Sstevel@tonic-gate (void *)hdlp)); 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate *prip = 0; 5400Sstevel@tonic-gate if (hdlp == NULL) 5410Sstevel@tonic-gate return (DDI_EINVAL); 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 5440Sstevel@tonic-gate /* Already initialized, just return that */ 5450Sstevel@tonic-gate if (hdlp->ih_pri) { 5460Sstevel@tonic-gate *prip = hdlp->ih_pri; 5470Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 5480Sstevel@tonic-gate return (DDI_SUCCESS); 5490Sstevel@tonic-gate } 5500Sstevel@tonic-gate 551693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 5520Sstevel@tonic-gate DDI_INTROP_GETPRI, hdlp, (void *)prip); 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate if (ret == DDI_SUCCESS) 5550Sstevel@tonic-gate hdlp->ih_pri = *prip; 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 5580Sstevel@tonic-gate return (ret); 5590Sstevel@tonic-gate } 5600Sstevel@tonic-gate 5610Sstevel@tonic-gate int 5620Sstevel@tonic-gate ddi_intr_set_pri(ddi_intr_handle_t h, uint_t pri) 5630Sstevel@tonic-gate { 5640Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 5650Sstevel@tonic-gate int ret; 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: hdlp = %p", (void *)hdlp)); 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate if (hdlp == NULL) 5700Sstevel@tonic-gate return (DDI_EINVAL); 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate /* Validate priority argument */ 5730Sstevel@tonic-gate if (pri < DDI_INTR_PRI_MIN || pri > DDI_INTR_PRI_MAX) { 5740Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: invalid priority " 5750Sstevel@tonic-gate "specified = %x\n", pri)); 5760Sstevel@tonic-gate return (DDI_EINVAL); 5770Sstevel@tonic-gate } 5780Sstevel@tonic-gate 5790Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 5800Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) { 5810Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 5820Sstevel@tonic-gate return (DDI_EINVAL); 5830Sstevel@tonic-gate } 5840Sstevel@tonic-gate 5850Sstevel@tonic-gate /* If the passed priority is same as existing priority; do nothing */ 5860Sstevel@tonic-gate if (pri == hdlp->ih_pri) { 5870Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 5880Sstevel@tonic-gate return (DDI_SUCCESS); 5890Sstevel@tonic-gate } 5900Sstevel@tonic-gate 591693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 5920Sstevel@tonic-gate DDI_INTROP_SETPRI, hdlp, &pri); 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate if (ret == DDI_SUCCESS) 5950Sstevel@tonic-gate hdlp->ih_pri = pri; 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 5980Sstevel@tonic-gate return (ret); 5990Sstevel@tonic-gate } 6000Sstevel@tonic-gate 6010Sstevel@tonic-gate /* 6020Sstevel@tonic-gate * Interrupt add/duplicate/remove handlers 6030Sstevel@tonic-gate */ 6040Sstevel@tonic-gate int 6050Sstevel@tonic-gate ddi_intr_add_handler(ddi_intr_handle_t h, ddi_intr_handler_t inthandler, 6060Sstevel@tonic-gate void *arg1, void *arg2) 6070Sstevel@tonic-gate { 6080Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 6090Sstevel@tonic-gate int ret; 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_handler: hdlp = 0x%p\n", 6120Sstevel@tonic-gate (void *)hdlp)); 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate if ((hdlp == NULL) || (inthandler == NULL)) 6150Sstevel@tonic-gate return (DDI_EINVAL); 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 6180Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) { 6190Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 6200Sstevel@tonic-gate return (DDI_EINVAL); 6210Sstevel@tonic-gate } 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate hdlp->ih_cb_func = inthandler; 6240Sstevel@tonic-gate hdlp->ih_cb_arg1 = arg1; 6250Sstevel@tonic-gate hdlp->ih_cb_arg2 = arg2; 6260Sstevel@tonic-gate 627693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 6280Sstevel@tonic-gate DDI_INTROP_ADDISR, hdlp, NULL); 6290Sstevel@tonic-gate 6300Sstevel@tonic-gate if (ret != DDI_SUCCESS) { 6310Sstevel@tonic-gate hdlp->ih_cb_func = NULL; 6320Sstevel@tonic-gate hdlp->ih_cb_arg1 = NULL; 6330Sstevel@tonic-gate hdlp->ih_cb_arg2 = NULL; 6340Sstevel@tonic-gate } else 6350Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ADDED; 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 6380Sstevel@tonic-gate return (ret); 6390Sstevel@tonic-gate } 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate int 642*1725Segillett ddi_intr_dup_handler(ddi_intr_handle_t org, int dup_inum, 643*1725Segillett ddi_intr_handle_t *dup) 6440Sstevel@tonic-gate { 6450Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)org; 6460Sstevel@tonic-gate ddi_intr_handle_impl_t *dup_hdlp; 6470Sstevel@tonic-gate int ret; 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_dup_handler: hdlp = 0x%p\n", 6500Sstevel@tonic-gate (void *)hdlp)); 6510Sstevel@tonic-gate 652*1725Segillett /* Do some input argument checking ("dup" handle is not allocated) */ 653*1725Segillett if ((hdlp == NULL) || (*dup != NULL)) 6540Sstevel@tonic-gate return (DDI_EINVAL); 6550Sstevel@tonic-gate 6560Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate /* Do some input argument checking */ 6590Sstevel@tonic-gate if ((hdlp->ih_state == DDI_IHDL_STATE_ALLOC) || /* intr handle alloc? */ 660*1725Segillett (hdlp->ih_type != DDI_INTR_TYPE_MSIX) || /* only MSI-X allowed */ 661*1725Segillett (hdlp->ih_flags & DDI_INTR_MSIX_DUP)) { /* only dup original */ 6620Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 6630Sstevel@tonic-gate return (DDI_EINVAL); 6640Sstevel@tonic-gate } 6650Sstevel@tonic-gate 666*1725Segillett hdlp->ih_scratch1 = dup_inum; 667693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 668*1725Segillett DDI_INTROP_DUPVEC, hdlp, NULL); 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 6710Sstevel@tonic-gate dup_hdlp = (ddi_intr_handle_impl_t *) 672*1725Segillett kmem_alloc(sizeof (ddi_intr_handle_impl_t), KM_SLEEP); 673*1725Segillett 674*1725Segillett atomic_add_32(&hdlp->ih_dup_cnt, 1); 6750Sstevel@tonic-gate 676*1725Segillett *dup = (ddi_intr_handle_t)dup_hdlp; 677*1725Segillett bcopy(hdlp, dup_hdlp, sizeof (ddi_intr_handle_impl_t)); 678*1725Segillett 679*1725Segillett /* These fields are unique to each dupped msi-x vector */ 6800Sstevel@tonic-gate rw_init(&dup_hdlp->ih_rwlock, NULL, RW_DRIVER, NULL); 6810Sstevel@tonic-gate dup_hdlp->ih_state = DDI_IHDL_STATE_ADDED; 682*1725Segillett dup_hdlp->ih_inum = dup_inum; 683*1725Segillett dup_hdlp->ih_flags |= DDI_INTR_MSIX_DUP; 684*1725Segillett dup_hdlp->ih_dup_cnt = 0; 6850Sstevel@tonic-gate 686*1725Segillett /* Point back to original vector */ 687*1725Segillett dup_hdlp->ih_main = hdlp; 6880Sstevel@tonic-gate } 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 6910Sstevel@tonic-gate return (ret); 6920Sstevel@tonic-gate } 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate int 6950Sstevel@tonic-gate ddi_intr_remove_handler(ddi_intr_handle_t h) 6960Sstevel@tonic-gate { 6970Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 698*1725Segillett int ret = DDI_SUCCESS; 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_handler: hdlp = %p\n", 7010Sstevel@tonic-gate (void *)hdlp)); 7020Sstevel@tonic-gate 7030Sstevel@tonic-gate if (hdlp == NULL) 7040Sstevel@tonic-gate return (DDI_EINVAL); 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 707*1725Segillett 7080Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ADDED) { 709*1725Segillett ret = DDI_EINVAL; 710*1725Segillett goto done; 711*1725Segillett } else if (hdlp->ih_flags & DDI_INTR_MSIX_DUP) 712*1725Segillett goto done; 713*1725Segillett 714*1725Segillett ASSERT(hdlp->ih_dup_cnt == 0); 715*1725Segillett if (hdlp->ih_dup_cnt > 0) { 716*1725Segillett DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_handler: MSI-X " 717*1725Segillett "dup_cnt %d is not 0\n", hdlp->ih_dup_cnt)); 718*1725Segillett ret = DDI_FAILURE; 719*1725Segillett goto done; 7200Sstevel@tonic-gate } 7210Sstevel@tonic-gate 722693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 7230Sstevel@tonic-gate DDI_INTROP_REMISR, hdlp, NULL); 7240Sstevel@tonic-gate 7250Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 7260Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ALLOC; 7270Sstevel@tonic-gate hdlp->ih_cb_func = NULL; 7280Sstevel@tonic-gate hdlp->ih_cb_arg1 = NULL; 7290Sstevel@tonic-gate hdlp->ih_cb_arg2 = NULL; 7300Sstevel@tonic-gate } 7310Sstevel@tonic-gate 732*1725Segillett done: 7330Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 7340Sstevel@tonic-gate return (ret); 7350Sstevel@tonic-gate } 7360Sstevel@tonic-gate 7370Sstevel@tonic-gate /* 7380Sstevel@tonic-gate * Interrupt enable/disable/block_enable/block_disable handlers 7390Sstevel@tonic-gate */ 7400Sstevel@tonic-gate int 7410Sstevel@tonic-gate ddi_intr_enable(ddi_intr_handle_t h) 7420Sstevel@tonic-gate { 7430Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 7440Sstevel@tonic-gate int ret; 7450Sstevel@tonic-gate 7460Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_enable: hdlp = %p\n", 7470Sstevel@tonic-gate (void *)hdlp)); 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate if (hdlp == NULL) 7500Sstevel@tonic-gate return (DDI_EINVAL); 7510Sstevel@tonic-gate 7520Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 7530Sstevel@tonic-gate if ((hdlp->ih_state != DDI_IHDL_STATE_ADDED) || 7540Sstevel@tonic-gate ((hdlp->ih_type == DDI_INTR_TYPE_MSI) && 7550Sstevel@tonic-gate (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) { 7560Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 7570Sstevel@tonic-gate return (DDI_EINVAL); 7580Sstevel@tonic-gate } 7590Sstevel@tonic-gate 760*1725Segillett I_DDI_VERIFY_MSIX_HANDLE(hdlp); 761*1725Segillett 762693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 7630Sstevel@tonic-gate DDI_INTROP_ENABLE, hdlp, NULL); 7640Sstevel@tonic-gate 7650Sstevel@tonic-gate if (ret == DDI_SUCCESS) 7660Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ENABLE; 7670Sstevel@tonic-gate 7680Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 7690Sstevel@tonic-gate return (ret); 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate int 7730Sstevel@tonic-gate ddi_intr_disable(ddi_intr_handle_t h) 7740Sstevel@tonic-gate { 7750Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 7760Sstevel@tonic-gate int ret; 7770Sstevel@tonic-gate 7780Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_disable: hdlp = %p\n", 7790Sstevel@tonic-gate (void *)hdlp)); 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate if (hdlp == NULL) 7820Sstevel@tonic-gate return (DDI_EINVAL); 7830Sstevel@tonic-gate 7840Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 7850Sstevel@tonic-gate if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) || 7860Sstevel@tonic-gate ((hdlp->ih_type == DDI_INTR_TYPE_MSI) && 7870Sstevel@tonic-gate (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) { 7880Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 7890Sstevel@tonic-gate return (DDI_EINVAL); 7900Sstevel@tonic-gate } 7910Sstevel@tonic-gate 792*1725Segillett I_DDI_VERIFY_MSIX_HANDLE(hdlp); 793*1725Segillett 794693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 7950Sstevel@tonic-gate DDI_INTROP_DISABLE, hdlp, NULL); 7960Sstevel@tonic-gate 7970Sstevel@tonic-gate if (ret == DDI_SUCCESS) 7980Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ADDED; 7990Sstevel@tonic-gate 8000Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 8010Sstevel@tonic-gate return (ret); 8020Sstevel@tonic-gate } 8030Sstevel@tonic-gate 8040Sstevel@tonic-gate int 8050Sstevel@tonic-gate ddi_intr_block_enable(ddi_intr_handle_t *h_array, int count) 8060Sstevel@tonic-gate { 8070Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp; 8080Sstevel@tonic-gate int i, ret; 8090Sstevel@tonic-gate 8100Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_enable: h_array = %p\n", 8110Sstevel@tonic-gate (void *)h_array)); 8120Sstevel@tonic-gate 8130Sstevel@tonic-gate if (h_array == NULL) 8140Sstevel@tonic-gate return (DDI_EINVAL); 8150Sstevel@tonic-gate 8160Sstevel@tonic-gate for (i = 0; i < count; i++) { 8170Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 8180Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 8190Sstevel@tonic-gate 8200Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ADDED || 8210Sstevel@tonic-gate hdlp->ih_type != DDI_INTR_TYPE_MSI || 8220Sstevel@tonic-gate !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) { 8230Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 8240Sstevel@tonic-gate return (DDI_EINVAL); 8250Sstevel@tonic-gate } 8260Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 8270Sstevel@tonic-gate } 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[0]; 8300Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 8310Sstevel@tonic-gate hdlp->ih_scratch1 = count; 8321542Sjohnny hdlp->ih_scratch2 = (void *)h_array; 8330Sstevel@tonic-gate 834693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 8350Sstevel@tonic-gate DDI_INTROP_BLOCKENABLE, hdlp, NULL); 8360Sstevel@tonic-gate 8370Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 8380Sstevel@tonic-gate 8390Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 8400Sstevel@tonic-gate for (i = 0; i < count; i++) { 8410Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 8420Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 8430Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ENABLE; 8440Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 8450Sstevel@tonic-gate } 8460Sstevel@tonic-gate } 8470Sstevel@tonic-gate 8480Sstevel@tonic-gate return (ret); 8490Sstevel@tonic-gate } 8500Sstevel@tonic-gate 8510Sstevel@tonic-gate int 8520Sstevel@tonic-gate ddi_intr_block_disable(ddi_intr_handle_t *h_array, int count) 8530Sstevel@tonic-gate { 8540Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp; 8550Sstevel@tonic-gate int i, ret; 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_disable: h_array = %p\n", 8580Sstevel@tonic-gate (void *)h_array)); 8590Sstevel@tonic-gate 8600Sstevel@tonic-gate if (h_array == NULL) 8610Sstevel@tonic-gate return (DDI_EINVAL); 8620Sstevel@tonic-gate 8630Sstevel@tonic-gate for (i = 0; i < count; i++) { 8640Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 8650Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 8660Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ENABLE || 8670Sstevel@tonic-gate hdlp->ih_type != DDI_INTR_TYPE_MSI || 8680Sstevel@tonic-gate !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) { 8690Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 8700Sstevel@tonic-gate return (DDI_EINVAL); 8710Sstevel@tonic-gate } 8720Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 8730Sstevel@tonic-gate } 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[0]; 8760Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 8770Sstevel@tonic-gate hdlp->ih_scratch1 = count; 8781542Sjohnny hdlp->ih_scratch2 = (void *)h_array; 8790Sstevel@tonic-gate 880693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 8810Sstevel@tonic-gate DDI_INTROP_BLOCKDISABLE, hdlp, NULL); 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 8860Sstevel@tonic-gate for (i = 0; i < count; i++) { 8870Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 8880Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 8890Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ADDED; 8900Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 8910Sstevel@tonic-gate } 8920Sstevel@tonic-gate } 8930Sstevel@tonic-gate 8940Sstevel@tonic-gate return (ret); 8950Sstevel@tonic-gate } 8960Sstevel@tonic-gate 8970Sstevel@tonic-gate /* 8980Sstevel@tonic-gate * Interrupt set/clr mask handlers 8990Sstevel@tonic-gate */ 9000Sstevel@tonic-gate int 9010Sstevel@tonic-gate ddi_intr_set_mask(ddi_intr_handle_t h) 9020Sstevel@tonic-gate { 9030Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 9040Sstevel@tonic-gate int ret; 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_mask: hdlp = %p\n", 9070Sstevel@tonic-gate (void *)hdlp)); 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate if (hdlp == NULL) 9100Sstevel@tonic-gate return (DDI_EINVAL); 9110Sstevel@tonic-gate 9120Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 9131653Sgovinda if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) || 9141653Sgovinda (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE))) { 9150Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 9160Sstevel@tonic-gate return (DDI_EINVAL); 9170Sstevel@tonic-gate } 9180Sstevel@tonic-gate 919693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 9200Sstevel@tonic-gate DDI_INTROP_SETMASK, hdlp, NULL); 9210Sstevel@tonic-gate 9220Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 9230Sstevel@tonic-gate return (ret); 9240Sstevel@tonic-gate } 9250Sstevel@tonic-gate 9260Sstevel@tonic-gate int 9270Sstevel@tonic-gate ddi_intr_clr_mask(ddi_intr_handle_t h) 9280Sstevel@tonic-gate { 9290Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 9300Sstevel@tonic-gate int ret; 9310Sstevel@tonic-gate 9320Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_clr_mask: hdlp = %p\n", 9330Sstevel@tonic-gate (void *)hdlp)); 9340Sstevel@tonic-gate 9350Sstevel@tonic-gate if (hdlp == NULL) 9360Sstevel@tonic-gate return (DDI_EINVAL); 9370Sstevel@tonic-gate 9380Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 9391653Sgovinda if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) || 9401653Sgovinda (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE))) { 9410Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 9420Sstevel@tonic-gate return (DDI_EINVAL); 9430Sstevel@tonic-gate } 9440Sstevel@tonic-gate 945693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 9460Sstevel@tonic-gate DDI_INTROP_CLRMASK, hdlp, NULL); 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 9490Sstevel@tonic-gate return (ret); 9500Sstevel@tonic-gate } 9510Sstevel@tonic-gate 9520Sstevel@tonic-gate /* 9530Sstevel@tonic-gate * Interrupt get_pending handler 9540Sstevel@tonic-gate */ 9550Sstevel@tonic-gate int 9560Sstevel@tonic-gate ddi_intr_get_pending(ddi_intr_handle_t h, int *pendingp) 9570Sstevel@tonic-gate { 9580Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 9590Sstevel@tonic-gate int ret; 9600Sstevel@tonic-gate 9610Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pending: hdlp = %p\n", 9620Sstevel@tonic-gate (void *)hdlp)); 9630Sstevel@tonic-gate 9640Sstevel@tonic-gate if (hdlp == NULL) 9650Sstevel@tonic-gate return (DDI_EINVAL); 9660Sstevel@tonic-gate 9670Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 9680Sstevel@tonic-gate if (!(hdlp->ih_cap & DDI_INTR_FLAG_PENDING)) { 9690Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 9700Sstevel@tonic-gate return (DDI_EINVAL); 9710Sstevel@tonic-gate } 9720Sstevel@tonic-gate 973693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 9740Sstevel@tonic-gate DDI_INTROP_GETPENDING, hdlp, (void *)pendingp); 9750Sstevel@tonic-gate 9760Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 9770Sstevel@tonic-gate return (ret); 9780Sstevel@tonic-gate } 9790Sstevel@tonic-gate 9800Sstevel@tonic-gate /* 9810Sstevel@tonic-gate * Soft interrupt handlers 9820Sstevel@tonic-gate */ 9830Sstevel@tonic-gate /* 9840Sstevel@tonic-gate * Add a soft interrupt and register its handler 9850Sstevel@tonic-gate */ 9860Sstevel@tonic-gate /* ARGSUSED */ 9870Sstevel@tonic-gate int 9880Sstevel@tonic-gate ddi_intr_add_softint(dev_info_t *dip, ddi_softint_handle_t *h_p, int soft_pri, 9890Sstevel@tonic-gate ddi_intr_handler_t handler, void *arg1) 9900Sstevel@tonic-gate { 9910Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp; 9920Sstevel@tonic-gate int ret; 9930Sstevel@tonic-gate 9940Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: dip = %p, " 9950Sstevel@tonic-gate "softpri = 0x%x\n", (void *)dip, soft_pri)); 9960Sstevel@tonic-gate 9970Sstevel@tonic-gate if ((dip == NULL) || (h_p == NULL) || (handler == NULL)) { 9980Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: " 9990Sstevel@tonic-gate "invalid arguments")); 10000Sstevel@tonic-gate 10010Sstevel@tonic-gate return (DDI_EINVAL); 10020Sstevel@tonic-gate } 10030Sstevel@tonic-gate 10040Sstevel@tonic-gate /* Validate input arguments */ 10050Sstevel@tonic-gate if (soft_pri < DDI_INTR_SOFTPRI_MIN || 10060Sstevel@tonic-gate soft_pri > DDI_INTR_SOFTPRI_MAX) { 10070Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: invalid " 10080Sstevel@tonic-gate "soft_pri input given = %x\n", soft_pri)); 10090Sstevel@tonic-gate return (DDI_EINVAL); 10100Sstevel@tonic-gate } 10110Sstevel@tonic-gate 10120Sstevel@tonic-gate hdlp = (ddi_softint_hdl_impl_t *)kmem_zalloc( 10130Sstevel@tonic-gate sizeof (ddi_softint_hdl_impl_t), KM_SLEEP); 10140Sstevel@tonic-gate 10150Sstevel@tonic-gate /* fill up internally */ 10160Sstevel@tonic-gate rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL); 10170Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 10180Sstevel@tonic-gate hdlp->ih_pri = soft_pri; 10190Sstevel@tonic-gate hdlp->ih_dip = dip; 10200Sstevel@tonic-gate hdlp->ih_cb_func = handler; 10210Sstevel@tonic-gate hdlp->ih_cb_arg1 = arg1; 10220Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: hdlp = %p\n", 10230Sstevel@tonic-gate (void *)hdlp)); 10240Sstevel@tonic-gate 10250Sstevel@tonic-gate /* do the platform specific calls */ 10260Sstevel@tonic-gate if ((ret = i_ddi_add_softint(hdlp)) != DDI_SUCCESS) { 10270Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 10280Sstevel@tonic-gate rw_destroy(&hdlp->ih_rwlock); 10290Sstevel@tonic-gate kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t)); 10300Sstevel@tonic-gate return (ret); 10310Sstevel@tonic-gate } 10320Sstevel@tonic-gate 10330Sstevel@tonic-gate *h_p = (ddi_softint_handle_t)hdlp; 10340Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 10350Sstevel@tonic-gate return (ret); 10360Sstevel@tonic-gate } 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate /* 10390Sstevel@tonic-gate * Remove the soft interrupt 10400Sstevel@tonic-gate */ 10410Sstevel@tonic-gate int 10420Sstevel@tonic-gate ddi_intr_remove_softint(ddi_softint_handle_t h) 10430Sstevel@tonic-gate { 10440Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h; 10450Sstevel@tonic-gate 10460Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_softint: hdlp = %p\n", 10470Sstevel@tonic-gate (void *)hdlp)); 10480Sstevel@tonic-gate 10490Sstevel@tonic-gate if (hdlp == NULL) 10500Sstevel@tonic-gate return (DDI_EINVAL); 10510Sstevel@tonic-gate 10520Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 10530Sstevel@tonic-gate i_ddi_remove_softint(hdlp); 10540Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 10550Sstevel@tonic-gate rw_destroy(&hdlp->ih_rwlock); 10560Sstevel@tonic-gate 10570Sstevel@tonic-gate /* kmem_free the hdl impl_t structure allocated earlier */ 10580Sstevel@tonic-gate kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t)); 10590Sstevel@tonic-gate return (DDI_SUCCESS); 10600Sstevel@tonic-gate } 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate /* 10630Sstevel@tonic-gate * Trigger a soft interrupt 10640Sstevel@tonic-gate */ 10650Sstevel@tonic-gate int 10660Sstevel@tonic-gate ddi_intr_trigger_softint(ddi_softint_handle_t h, void *arg2) 10670Sstevel@tonic-gate { 10680Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h; 10690Sstevel@tonic-gate int ret; 10700Sstevel@tonic-gate 10710Sstevel@tonic-gate if (hdlp == NULL) 10720Sstevel@tonic-gate return (DDI_EINVAL); 10730Sstevel@tonic-gate 1074278Sgovinda if ((ret = i_ddi_trigger_softint(hdlp, arg2)) != DDI_SUCCESS) { 10750Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_trigger_softint: failed, " 10760Sstevel@tonic-gate " ret 0%x\n", ret)); 1077278Sgovinda 1078278Sgovinda return (ret); 10790Sstevel@tonic-gate } 10800Sstevel@tonic-gate 1081278Sgovinda hdlp->ih_cb_arg2 = arg2; 1082278Sgovinda return (DDI_SUCCESS); 10830Sstevel@tonic-gate } 10840Sstevel@tonic-gate 10850Sstevel@tonic-gate /* 10860Sstevel@tonic-gate * Get the soft interrupt priority 10870Sstevel@tonic-gate */ 10880Sstevel@tonic-gate int 10890Sstevel@tonic-gate ddi_intr_get_softint_pri(ddi_softint_handle_t h, uint_t *soft_prip) 10900Sstevel@tonic-gate { 10910Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h; 10920Sstevel@tonic-gate 10930Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_softint_pri: h = %p\n", 10940Sstevel@tonic-gate (void *)h)); 10950Sstevel@tonic-gate 10960Sstevel@tonic-gate if (hdlp == NULL) 10970Sstevel@tonic-gate return (DDI_EINVAL); 10980Sstevel@tonic-gate 10990Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 11000Sstevel@tonic-gate *soft_prip = hdlp->ih_pri; 11010Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 11020Sstevel@tonic-gate return (DDI_SUCCESS); 11030Sstevel@tonic-gate } 11040Sstevel@tonic-gate 11050Sstevel@tonic-gate /* 11060Sstevel@tonic-gate * Set the soft interrupt priority 11070Sstevel@tonic-gate */ 11080Sstevel@tonic-gate int 11090Sstevel@tonic-gate ddi_intr_set_softint_pri(ddi_softint_handle_t h, uint_t soft_pri) 11100Sstevel@tonic-gate { 11110Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h; 11120Sstevel@tonic-gate int ret; 11130Sstevel@tonic-gate uint_t orig_soft_pri; 11140Sstevel@tonic-gate 11150Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: h = %p\n", 11160Sstevel@tonic-gate (void *)h)); 11170Sstevel@tonic-gate 11180Sstevel@tonic-gate if (hdlp == NULL) 11190Sstevel@tonic-gate return (DDI_EINVAL); 11200Sstevel@tonic-gate 11210Sstevel@tonic-gate /* Validate priority argument */ 11220Sstevel@tonic-gate if (soft_pri < DDI_INTR_SOFTPRI_MIN || 11230Sstevel@tonic-gate soft_pri > DDI_INTR_SOFTPRI_MAX) { 11240Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: invalid " 11250Sstevel@tonic-gate "soft_pri input given = %x\n", soft_pri)); 11260Sstevel@tonic-gate return (DDI_EINVAL); 11270Sstevel@tonic-gate } 11280Sstevel@tonic-gate 11290Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 11300Sstevel@tonic-gate orig_soft_pri = hdlp->ih_pri; 11310Sstevel@tonic-gate hdlp->ih_pri = soft_pri; 11320Sstevel@tonic-gate 11330Sstevel@tonic-gate if ((ret = i_ddi_set_softint_pri(hdlp, orig_soft_pri)) != DDI_SUCCESS) { 11340Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: failed, " 11350Sstevel@tonic-gate " ret 0%x\n", ret)); 11360Sstevel@tonic-gate hdlp->ih_pri = orig_soft_pri; 11370Sstevel@tonic-gate } 11380Sstevel@tonic-gate 11390Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 11400Sstevel@tonic-gate return (ret); 11410Sstevel@tonic-gate } 11420Sstevel@tonic-gate 11430Sstevel@tonic-gate /* 11440Sstevel@tonic-gate * Old DDI interrupt framework 1145693Sgovinda * 1146693Sgovinda * The following DDI interrupt interfaces are obsolete. 1147693Sgovinda * Use the above new DDI interrupt interfaces instead. 11480Sstevel@tonic-gate */ 11490Sstevel@tonic-gate 11500Sstevel@tonic-gate int 11510Sstevel@tonic-gate ddi_intr_hilevel(dev_info_t *dip, uint_t inumber) 11520Sstevel@tonic-gate { 11530Sstevel@tonic-gate ddi_intr_handle_t hdl, *existing_hdlp; 11540Sstevel@tonic-gate int actual, ret; 11550Sstevel@tonic-gate uint_t high_pri, pri; 11560Sstevel@tonic-gate 11570Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: name=%s%d dip=0x%p " 11580Sstevel@tonic-gate "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 11590Sstevel@tonic-gate (void *)dip, inumber)); 11600Sstevel@tonic-gate 11610Sstevel@tonic-gate /* 11620Sstevel@tonic-gate * The device driver may have already registed with the 11630Sstevel@tonic-gate * framework. If so, first try to get the existing interrupt handle 11640Sstevel@tonic-gate * for that given inumber and use that handle. 11650Sstevel@tonic-gate */ 11660Sstevel@tonic-gate existing_hdlp = i_ddi_get_intr_handle(dip, inumber); 11670Sstevel@tonic-gate if (existing_hdlp) { 11680Sstevel@tonic-gate hdl = existing_hdlp[0]; /* Use existing handle */ 11690Sstevel@tonic-gate } else { 11700Sstevel@tonic-gate if ((ret = ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED, 1171965Sgovinda inumber, 1, &actual, 1172965Sgovinda DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) { 11730Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: " 11740Sstevel@tonic-gate "ddi_intr_alloc failed, ret 0x%x\n", ret)); 11750Sstevel@tonic-gate return (0); 11760Sstevel@tonic-gate } 11770Sstevel@tonic-gate } 11780Sstevel@tonic-gate 11790Sstevel@tonic-gate if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) { 11800Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: " 11810Sstevel@tonic-gate "ddi_intr_get_pri failed, ret 0x%x\n", ret)); 11820Sstevel@tonic-gate (void) ddi_intr_free(hdl); 11830Sstevel@tonic-gate return (0); 11840Sstevel@tonic-gate } 11850Sstevel@tonic-gate 11860Sstevel@tonic-gate high_pri = ddi_intr_get_hilevel_pri(); 11870Sstevel@tonic-gate 11880Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: pri = %x, " 11890Sstevel@tonic-gate "high_pri = %x\n", pri, high_pri)); 11900Sstevel@tonic-gate 11910Sstevel@tonic-gate /* Free the handle allocated here only if no existing handle exists */ 11920Sstevel@tonic-gate if (existing_hdlp == NULL) 11930Sstevel@tonic-gate (void) ddi_intr_free(hdl); 11940Sstevel@tonic-gate 11950Sstevel@tonic-gate return (pri >= high_pri); 11960Sstevel@tonic-gate } 11970Sstevel@tonic-gate 11980Sstevel@tonic-gate int 11990Sstevel@tonic-gate ddi_dev_nintrs(dev_info_t *dip, int *result) 12000Sstevel@tonic-gate { 12010Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: name=%s%d dip=0x%p\n", 12020Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), (void *)dip)); 12030Sstevel@tonic-gate 12040Sstevel@tonic-gate if (ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED, 12050Sstevel@tonic-gate result) != DDI_SUCCESS) { 12060Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: " 12070Sstevel@tonic-gate "ddi_intr_get_nintrs failed\n")); 12080Sstevel@tonic-gate *result = 0; 12090Sstevel@tonic-gate } 12100Sstevel@tonic-gate 12110Sstevel@tonic-gate return (DDI_SUCCESS); 12120Sstevel@tonic-gate } 12130Sstevel@tonic-gate 12140Sstevel@tonic-gate int 12150Sstevel@tonic-gate ddi_get_iblock_cookie(dev_info_t *dip, uint_t inumber, 12160Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep) 12170Sstevel@tonic-gate { 12180Sstevel@tonic-gate ddi_intr_handle_t hdl, *existing_hdlp; 12190Sstevel@tonic-gate int actual, ret; 12200Sstevel@tonic-gate uint_t pri; 12210Sstevel@tonic-gate 12220Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: name=%s%d dip=0x%p " 12230Sstevel@tonic-gate "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 12240Sstevel@tonic-gate (void *)dip, inumber)); 12250Sstevel@tonic-gate 12260Sstevel@tonic-gate ASSERT(iblock_cookiep != NULL); 12270Sstevel@tonic-gate 12280Sstevel@tonic-gate /* 12290Sstevel@tonic-gate * The device driver may have already registed with the 12300Sstevel@tonic-gate * framework. If so, first try to get the existing interrupt handle 12310Sstevel@tonic-gate * for that given inumber and use that handle. 12320Sstevel@tonic-gate */ 12330Sstevel@tonic-gate existing_hdlp = i_ddi_get_intr_handle(dip, inumber); 12340Sstevel@tonic-gate if (existing_hdlp) { 12350Sstevel@tonic-gate hdl = existing_hdlp[0]; /* Use existing handle */ 12360Sstevel@tonic-gate } else { 12370Sstevel@tonic-gate if ((ret = ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED, 1238965Sgovinda inumber, 1, &actual, 1239965Sgovinda DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) { 12400Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: " 12410Sstevel@tonic-gate "ddi_intr_alloc failed, ret 0x%x\n", ret)); 12420Sstevel@tonic-gate return (DDI_INTR_NOTFOUND); 12430Sstevel@tonic-gate } 12440Sstevel@tonic-gate } 12450Sstevel@tonic-gate 12460Sstevel@tonic-gate if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) { 12470Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: " 12480Sstevel@tonic-gate "ddi_intr_get_pri failed, ret 0x%x\n", ret)); 12490Sstevel@tonic-gate 12500Sstevel@tonic-gate (void) ddi_intr_free(hdl); 12510Sstevel@tonic-gate return (DDI_FAILURE); 12520Sstevel@tonic-gate } 12530Sstevel@tonic-gate 125442Sagiri *iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)pri; 12550Sstevel@tonic-gate /* Free the handle allocated here only if no existing handle exists */ 12560Sstevel@tonic-gate if (existing_hdlp == NULL) 12570Sstevel@tonic-gate (void) ddi_intr_free(hdl); 12580Sstevel@tonic-gate 12590Sstevel@tonic-gate return (DDI_SUCCESS); 12600Sstevel@tonic-gate } 12610Sstevel@tonic-gate 12620Sstevel@tonic-gate int 12630Sstevel@tonic-gate ddi_add_intr(dev_info_t *dip, uint_t inumber, 12640Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep, 12650Sstevel@tonic-gate ddi_idevice_cookie_t *idevice_cookiep, 12660Sstevel@tonic-gate uint_t (*int_handler)(caddr_t int_handler_arg), 12670Sstevel@tonic-gate caddr_t int_handler_arg) 12680Sstevel@tonic-gate { 12690Sstevel@tonic-gate ddi_intr_handle_t *hdl_p; 12700Sstevel@tonic-gate int actual, ret; 12710Sstevel@tonic-gate uint_t pri; 12720Sstevel@tonic-gate 12730Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: name=%s%d dip=0x%p " 12740Sstevel@tonic-gate "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 12750Sstevel@tonic-gate (void *)dip, inumber)); 12760Sstevel@tonic-gate 12770Sstevel@tonic-gate hdl_p = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP); 12780Sstevel@tonic-gate 12790Sstevel@tonic-gate if ((ret = ddi_intr_alloc(dip, hdl_p, DDI_INTR_TYPE_FIXED, 1280965Sgovinda inumber, 1, &actual, DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) { 12810Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: " 12820Sstevel@tonic-gate "ddi_intr_alloc failed, ret 0x%x\n", ret)); 12830Sstevel@tonic-gate kmem_free(hdl_p, sizeof (ddi_intr_handle_t)); 12840Sstevel@tonic-gate return (DDI_INTR_NOTFOUND); 12850Sstevel@tonic-gate } 12860Sstevel@tonic-gate 12870Sstevel@tonic-gate if ((ret = ddi_intr_get_pri(hdl_p[0], &pri)) != DDI_SUCCESS) { 12880Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: " 12890Sstevel@tonic-gate "ddi_intr_get_pri failed, ret 0x%x\n", ret)); 12900Sstevel@tonic-gate (void) ddi_intr_free(hdl_p[0]); 12910Sstevel@tonic-gate kmem_free(hdl_p, sizeof (ddi_intr_handle_t)); 12920Sstevel@tonic-gate return (DDI_FAILURE); 12930Sstevel@tonic-gate } 12940Sstevel@tonic-gate 12950Sstevel@tonic-gate if ((ret = ddi_intr_add_handler(hdl_p[0], (ddi_intr_handler_t *) 12960Sstevel@tonic-gate int_handler, int_handler_arg, NULL)) != DDI_SUCCESS) { 12970Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: " 12980Sstevel@tonic-gate "ddi_intr_add_handler failed, ret 0x%x\n", ret)); 12990Sstevel@tonic-gate (void) ddi_intr_free(hdl_p[0]); 13000Sstevel@tonic-gate kmem_free(hdl_p, sizeof (ddi_intr_handle_t)); 13010Sstevel@tonic-gate return (DDI_FAILURE); 13020Sstevel@tonic-gate } 13030Sstevel@tonic-gate 13040Sstevel@tonic-gate if ((ret = ddi_intr_enable(hdl_p[0])) != DDI_SUCCESS) { 13050Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: " 13060Sstevel@tonic-gate "ddi_intr_enable failed, ret 0x%x\n", ret)); 13070Sstevel@tonic-gate (void) ddi_intr_remove_handler(hdl_p[0]); 13080Sstevel@tonic-gate (void) ddi_intr_free(hdl_p[0]); 13090Sstevel@tonic-gate kmem_free(hdl_p, sizeof (ddi_intr_handle_t)); 13100Sstevel@tonic-gate return (DDI_FAILURE); 13110Sstevel@tonic-gate } 13120Sstevel@tonic-gate 13130Sstevel@tonic-gate if (iblock_cookiep) 131442Sagiri *iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)pri; 13150Sstevel@tonic-gate 13160Sstevel@tonic-gate if (idevice_cookiep) { 13170Sstevel@tonic-gate idevice_cookiep->idev_vector = 0; 13180Sstevel@tonic-gate idevice_cookiep->idev_priority = pri; 13190Sstevel@tonic-gate } 13200Sstevel@tonic-gate 13210Sstevel@tonic-gate return (DDI_SUCCESS); 13220Sstevel@tonic-gate } 13230Sstevel@tonic-gate 13240Sstevel@tonic-gate /* ARGSUSED */ 13250Sstevel@tonic-gate int 13260Sstevel@tonic-gate ddi_add_fastintr(dev_info_t *dip, uint_t inumber, 13270Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep, 13280Sstevel@tonic-gate ddi_idevice_cookie_t *idevice_cookiep, 13290Sstevel@tonic-gate uint_t (*hi_int_handler)(void)) 13300Sstevel@tonic-gate { 13310Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_fastintr: name=%s%d dip=0x%p " 13320Sstevel@tonic-gate "inum=0x%x: Not supported, return failure\n", ddi_driver_name(dip), 13330Sstevel@tonic-gate ddi_get_instance(dip), (void *)dip, inumber)); 13340Sstevel@tonic-gate 13350Sstevel@tonic-gate return (DDI_FAILURE); 13360Sstevel@tonic-gate } 13370Sstevel@tonic-gate 13380Sstevel@tonic-gate /* ARGSUSED */ 13390Sstevel@tonic-gate void 13400Sstevel@tonic-gate ddi_remove_intr(dev_info_t *dip, uint_t inum, ddi_iblock_cookie_t iblock_cookie) 13410Sstevel@tonic-gate { 13420Sstevel@tonic-gate ddi_intr_handle_t *hdl_p; 13430Sstevel@tonic-gate int ret; 13440Sstevel@tonic-gate 13450Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: name=%s%d dip=0x%p " 13460Sstevel@tonic-gate "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 13470Sstevel@tonic-gate (void *)dip, inum)); 13480Sstevel@tonic-gate 13490Sstevel@tonic-gate if ((hdl_p = i_ddi_get_intr_handle(dip, inum)) == NULL) { 13500Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: no handle " 13510Sstevel@tonic-gate "found\n")); 13520Sstevel@tonic-gate return; 13530Sstevel@tonic-gate } 13540Sstevel@tonic-gate 13550Sstevel@tonic-gate if ((ret = ddi_intr_disable(hdl_p[0])) != DDI_SUCCESS) { 13560Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: " 13570Sstevel@tonic-gate "ddi_intr_disable failed, ret 0x%x\n", ret)); 13580Sstevel@tonic-gate return; 13590Sstevel@tonic-gate } 13600Sstevel@tonic-gate 13610Sstevel@tonic-gate if ((ret = ddi_intr_remove_handler(hdl_p[0])) != DDI_SUCCESS) { 13620Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: " 13630Sstevel@tonic-gate "ddi_intr_remove_handler failed, ret 0x%x\n", ret)); 13640Sstevel@tonic-gate return; 13650Sstevel@tonic-gate } 13660Sstevel@tonic-gate 13670Sstevel@tonic-gate if ((ret = ddi_intr_free(hdl_p[0])) != DDI_SUCCESS) { 13680Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: " 13690Sstevel@tonic-gate "ddi_intr_free failed, ret 0x%x\n", ret)); 13700Sstevel@tonic-gate return; 13710Sstevel@tonic-gate } 13720Sstevel@tonic-gate 13730Sstevel@tonic-gate kmem_free(hdl_p, sizeof (ddi_intr_handle_t)); 13740Sstevel@tonic-gate } 13750Sstevel@tonic-gate 13760Sstevel@tonic-gate /* ARGSUSED */ 13770Sstevel@tonic-gate int 13780Sstevel@tonic-gate ddi_get_soft_iblock_cookie(dev_info_t *dip, int preference, 13790Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep) 13800Sstevel@tonic-gate { 13810Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_get_soft_iblock_cookie: name=%s%d " 13820Sstevel@tonic-gate "dip=0x%p pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 13830Sstevel@tonic-gate (void *)dip, preference)); 13840Sstevel@tonic-gate 13850Sstevel@tonic-gate ASSERT(iblock_cookiep != NULL); 13860Sstevel@tonic-gate 13870Sstevel@tonic-gate if (preference == DDI_SOFTINT_FIXED) 13880Sstevel@tonic-gate return (DDI_FAILURE); 13890Sstevel@tonic-gate 139042Sagiri *iblock_cookiep = (ddi_iblock_cookie_t)((uintptr_t) 13910Sstevel@tonic-gate ((preference > DDI_SOFTINT_MED) ? DDI_SOFT_INTR_PRI_H : 13920Sstevel@tonic-gate DDI_SOFT_INTR_PRI_M)); 13930Sstevel@tonic-gate 13940Sstevel@tonic-gate return (DDI_SUCCESS); 13950Sstevel@tonic-gate } 13960Sstevel@tonic-gate 13970Sstevel@tonic-gate int 13980Sstevel@tonic-gate ddi_add_softintr(dev_info_t *dip, int preference, ddi_softintr_t *idp, 13990Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep, 14000Sstevel@tonic-gate ddi_idevice_cookie_t *idevice_cookiep, 14010Sstevel@tonic-gate uint_t (*int_handler)(caddr_t int_handler_arg), 14020Sstevel@tonic-gate caddr_t int_handler_arg) 14030Sstevel@tonic-gate { 14040Sstevel@tonic-gate ddi_softint_handle_t *hdl_p; 14050Sstevel@tonic-gate uint64_t softpri; 14060Sstevel@tonic-gate int ret; 14070Sstevel@tonic-gate 14080Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: name=%s%d dip=0x%p " 14090Sstevel@tonic-gate "pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 14100Sstevel@tonic-gate (void *)dip, preference)); 14110Sstevel@tonic-gate 14120Sstevel@tonic-gate if ((idp == NULL) || ((preference == DDI_SOFTINT_FIXED) && 14130Sstevel@tonic-gate (iblock_cookiep == NULL))) 14140Sstevel@tonic-gate return (DDI_FAILURE); 14150Sstevel@tonic-gate 14160Sstevel@tonic-gate /* Translate the priority preference */ 14170Sstevel@tonic-gate if (preference == DDI_SOFTINT_FIXED) { 1418190Seota softpri = (uint64_t)(uintptr_t)*iblock_cookiep; 14190Sstevel@tonic-gate softpri = MIN(softpri, DDI_SOFT_INTR_PRI_H); 14200Sstevel@tonic-gate } else { 14210Sstevel@tonic-gate softpri = (uint64_t)((preference > DDI_SOFTINT_MED) ? 14220Sstevel@tonic-gate DDI_SOFT_INTR_PRI_H : DDI_SOFT_INTR_PRI_M); 14230Sstevel@tonic-gate } 14240Sstevel@tonic-gate 14250Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: preference 0x%x " 14260Sstevel@tonic-gate "softpri 0x%lx\n", preference, (long)softpri)); 14270Sstevel@tonic-gate 14280Sstevel@tonic-gate hdl_p = kmem_zalloc(sizeof (ddi_softint_handle_t), KM_SLEEP); 14290Sstevel@tonic-gate if ((ret = ddi_intr_add_softint(dip, hdl_p, softpri, 14300Sstevel@tonic-gate (ddi_intr_handler_t *)int_handler, int_handler_arg)) != 14310Sstevel@tonic-gate DDI_SUCCESS) { 14320Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: " 14330Sstevel@tonic-gate "ddi_intr_add_softint failed, ret 0x%x\n", ret)); 14340Sstevel@tonic-gate 14350Sstevel@tonic-gate kmem_free(hdl_p, sizeof (ddi_softint_handle_t)); 14360Sstevel@tonic-gate return (DDI_FAILURE); 14370Sstevel@tonic-gate } 14380Sstevel@tonic-gate 14390Sstevel@tonic-gate if (iblock_cookiep) 1440190Seota *iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)softpri; 14410Sstevel@tonic-gate 14420Sstevel@tonic-gate if (idevice_cookiep) { 14430Sstevel@tonic-gate idevice_cookiep->idev_vector = 0; 14440Sstevel@tonic-gate idevice_cookiep->idev_priority = softpri; 14450Sstevel@tonic-gate } 14460Sstevel@tonic-gate 14470Sstevel@tonic-gate *idp = (ddi_softintr_t)hdl_p; 14480Sstevel@tonic-gate 14490Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: dip = 0x%p, " 14500Sstevel@tonic-gate "idp = 0x%p, ret = %x\n", (void *)dip, (void *)*idp, ret)); 14510Sstevel@tonic-gate 14520Sstevel@tonic-gate return (DDI_SUCCESS); 14530Sstevel@tonic-gate } 14540Sstevel@tonic-gate 14550Sstevel@tonic-gate void 14560Sstevel@tonic-gate ddi_remove_softintr(ddi_softintr_t id) 14570Sstevel@tonic-gate { 14580Sstevel@tonic-gate ddi_softint_handle_t *h_p = (ddi_softint_handle_t *)id; 14590Sstevel@tonic-gate 14600Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: id=0x%p\n", 14610Sstevel@tonic-gate (void *)id)); 14620Sstevel@tonic-gate 14630Sstevel@tonic-gate if (h_p == NULL) 14640Sstevel@tonic-gate return; 14650Sstevel@tonic-gate 14660Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: handle 0x%p\n", 14670Sstevel@tonic-gate (void *)h_p)); 14680Sstevel@tonic-gate 14690Sstevel@tonic-gate (void) ddi_intr_remove_softint(*h_p); 14700Sstevel@tonic-gate kmem_free(h_p, sizeof (ddi_softint_handle_t)); 14710Sstevel@tonic-gate } 14720Sstevel@tonic-gate 14730Sstevel@tonic-gate void 14740Sstevel@tonic-gate ddi_trigger_softintr(ddi_softintr_t id) 14750Sstevel@tonic-gate { 14760Sstevel@tonic-gate ddi_softint_handle_t *h_p = (ddi_softint_handle_t *)id; 14770Sstevel@tonic-gate int ret; 14780Sstevel@tonic-gate 14790Sstevel@tonic-gate if (h_p == NULL) 14800Sstevel@tonic-gate return; 14810Sstevel@tonic-gate 14820Sstevel@tonic-gate if ((ret = ddi_intr_trigger_softint(*h_p, NULL)) != DDI_SUCCESS) { 14830Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_trigger_softintr: " 14840Sstevel@tonic-gate "ddi_intr_trigger_softint failed, hdlp 0x%p " 14850Sstevel@tonic-gate "ret 0x%x\n", (void *)h_p, ret)); 14860Sstevel@tonic-gate } 14870Sstevel@tonic-gate } 1488