1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/note.h> 30*0Sstevel@tonic-gate #include <sys/sysmacros.h> 31*0Sstevel@tonic-gate #include <sys/types.h> 32*0Sstevel@tonic-gate #include <sys/param.h> 33*0Sstevel@tonic-gate #include <sys/systm.h> 34*0Sstevel@tonic-gate #include <sys/kmem.h> 35*0Sstevel@tonic-gate #include <sys/cmn_err.h> 36*0Sstevel@tonic-gate #include <sys/debug.h> 37*0Sstevel@tonic-gate #include <sys/avintr.h> 38*0Sstevel@tonic-gate #include <sys/autoconf.h> 39*0Sstevel@tonic-gate #include <sys/sunndi.h> 40*0Sstevel@tonic-gate #include <sys/ndi_impldefs.h> /* include prototypes */ 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate /* 43*0Sstevel@tonic-gate * New DDI interrupt framework 44*0Sstevel@tonic-gate */ 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate /* 47*0Sstevel@tonic-gate * MSI/X allocation limit. 48*0Sstevel@tonic-gate * This limit will change with Resource Management support. 49*0Sstevel@tonic-gate */ 50*0Sstevel@tonic-gate uint_t ddi_msix_alloc_limit = 2; 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate /* 53*0Sstevel@tonic-gate * ddi_intr_get_supported_types: 54*0Sstevel@tonic-gate * Return, as a bit mask, the hardware interrupt types supported by 55*0Sstevel@tonic-gate * both the device and by the host in the integer pointed 56*0Sstevel@tonic-gate * to be the 'typesp' argument. 57*0Sstevel@tonic-gate */ 58*0Sstevel@tonic-gate int 59*0Sstevel@tonic-gate ddi_intr_get_supported_types(dev_info_t *dip, int *typesp) 60*0Sstevel@tonic-gate { 61*0Sstevel@tonic-gate int ret; 62*0Sstevel@tonic-gate ddi_intr_handle_impl_t hdl; 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate if (dip == NULL) 65*0Sstevel@tonic-gate return (DDI_EINVAL); 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: dip %p\n", 68*0Sstevel@tonic-gate (void *)dip)); 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate if (*typesp = i_ddi_intr_get_supported_types(dip)) 71*0Sstevel@tonic-gate return (DDI_SUCCESS); 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate bzero(&hdl, sizeof (ddi_intr_handle_impl_t)); 74*0Sstevel@tonic-gate hdl.ih_dip = dip; 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate ret = i_ddi_handle_intr_ops(dip, dip, DDI_INTROP_SUPPORTED_TYPES, &hdl, 77*0Sstevel@tonic-gate (void *)typesp); 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate if (ret != DDI_SUCCESS) 80*0Sstevel@tonic-gate return (DDI_INTR_NOTFOUND); 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: types %x\n", 83*0Sstevel@tonic-gate *typesp)); 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate return (ret); 86*0Sstevel@tonic-gate } 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate /* 90*0Sstevel@tonic-gate * ddi_intr_get_nintrs: 91*0Sstevel@tonic-gate * Return as an integer in the integer pointed to by the argument 92*0Sstevel@tonic-gate * *nintrsp*, the number of interrupts the device supports for the 93*0Sstevel@tonic-gate * given interrupt type. 94*0Sstevel@tonic-gate */ 95*0Sstevel@tonic-gate int 96*0Sstevel@tonic-gate ddi_intr_get_nintrs(dev_info_t *dip, int type, int *nintrsp) 97*0Sstevel@tonic-gate { 98*0Sstevel@tonic-gate int ret; 99*0Sstevel@tonic-gate ddi_intr_handle_impl_t hdl; 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate if (dip == NULL) 102*0Sstevel@tonic-gate return (DDI_EINVAL); 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs: dip %p\n", 105*0Sstevel@tonic-gate (void *)dip)); 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate if (!(i_ddi_intr_get_supported_types(dip) & type)) 108*0Sstevel@tonic-gate return (DDI_EINVAL); 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate if (*nintrsp = i_ddi_intr_get_supported_nintrs(dip, type)) 111*0Sstevel@tonic-gate return (DDI_SUCCESS); 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate bzero(&hdl, sizeof (ddi_intr_handle_impl_t)); 114*0Sstevel@tonic-gate hdl.ih_dip = dip; 115*0Sstevel@tonic-gate hdl.ih_type = type; 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate ret = i_ddi_handle_intr_ops(dip, dip, DDI_INTROP_NINTRS, &hdl, 118*0Sstevel@tonic-gate (void *)nintrsp); 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs:: nintrs %x\n", 121*0Sstevel@tonic-gate *nintrsp)); 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate return (ret); 124*0Sstevel@tonic-gate } 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate /* 128*0Sstevel@tonic-gate * ddi_intr_get_navail: 129*0Sstevel@tonic-gate * Bus nexus driver will return availble interrupt count value for 130*0Sstevel@tonic-gate * a given interrupt type. 131*0Sstevel@tonic-gate * 132*0Sstevel@tonic-gate * Return as an integer in the integer pointed to by the argument 133*0Sstevel@tonic-gate * *navailp*, the number of interrupts currently available for the 134*0Sstevel@tonic-gate * given interrupt type. 135*0Sstevel@tonic-gate */ 136*0Sstevel@tonic-gate int 137*0Sstevel@tonic-gate ddi_intr_get_navail(dev_info_t *dip, int type, int *navailp) 138*0Sstevel@tonic-gate { 139*0Sstevel@tonic-gate int ret; 140*0Sstevel@tonic-gate ddi_intr_handle_impl_t hdl; 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_navail: dip %p\n", 143*0Sstevel@tonic-gate (void *)dip)); 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate if (dip == NULL) 146*0Sstevel@tonic-gate return (DDI_EINVAL); 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate if (!(i_ddi_intr_get_supported_types(dip) & type)) 149*0Sstevel@tonic-gate return (DDI_EINVAL); 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate /* 152*0Sstevel@tonic-gate * In future, this interface implementation will change 153*0Sstevel@tonic-gate * with Resource Management support. 154*0Sstevel@tonic-gate */ 155*0Sstevel@tonic-gate bzero(&hdl, sizeof (ddi_intr_handle_impl_t)); 156*0Sstevel@tonic-gate hdl.ih_dip = dip; 157*0Sstevel@tonic-gate hdl.ih_type = type; 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate ret = i_ddi_handle_intr_ops(dip, dip, 160*0Sstevel@tonic-gate DDI_INTROP_NAVAIL, &hdl, (void *)navailp); 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate return (ret == DDI_SUCCESS ? DDI_SUCCESS : DDI_INTR_NOTFOUND); 163*0Sstevel@tonic-gate } 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate /* 167*0Sstevel@tonic-gate * Interrupt allocate/free functions 168*0Sstevel@tonic-gate */ 169*0Sstevel@tonic-gate int 170*0Sstevel@tonic-gate ddi_intr_alloc(dev_info_t *dip, ddi_intr_handle_t *h_array, int type, int inum, 171*0Sstevel@tonic-gate int count, int *actualp, int behavior) 172*0Sstevel@tonic-gate { 173*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, tmp_hdl; 174*0Sstevel@tonic-gate int i, ret, cap = 0, intr_type, nintrs = 0; 175*0Sstevel@tonic-gate uint_t pri; 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: name %s dip 0x%p " 178*0Sstevel@tonic-gate "type %x inum %x count %x behavior %x\n", ddi_driver_name(dip), 179*0Sstevel@tonic-gate (void *)dip, type, inum, count, behavior)); 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate /* Validate parameters */ 182*0Sstevel@tonic-gate if (dip == NULL || h_array == NULL || count < 1) { 183*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Invalid args\n")); 184*0Sstevel@tonic-gate return (DDI_EINVAL); 185*0Sstevel@tonic-gate } 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate /* Validate interrupt type */ 188*0Sstevel@tonic-gate if (!(i_ddi_intr_get_supported_types(dip) & type)) { 189*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x not " 190*0Sstevel@tonic-gate "supported\n", type)); 191*0Sstevel@tonic-gate return (DDI_EINVAL); 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate /* First, get how many interrupts the device supports */ 195*0Sstevel@tonic-gate if (!(nintrs = i_ddi_intr_get_supported_nintrs(dip, type))) { 196*0Sstevel@tonic-gate if (ddi_intr_get_nintrs(dip, type, &nintrs) != DDI_SUCCESS) { 197*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no " 198*0Sstevel@tonic-gate "interrupts found of type %d\n", type)); 199*0Sstevel@tonic-gate return (DDI_INTR_NOTFOUND); 200*0Sstevel@tonic-gate } 201*0Sstevel@tonic-gate } 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate /* Is this function invoked with more interrupt than device supports? */ 204*0Sstevel@tonic-gate if (count > nintrs) { 205*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no of interrupts " 206*0Sstevel@tonic-gate "requested %d is more than supported %d\n", count, nintrs)); 207*0Sstevel@tonic-gate return (DDI_EINVAL); 208*0Sstevel@tonic-gate } 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate /* 211*0Sstevel@tonic-gate * Check if requested interrupt type is not same as interrupt 212*0Sstevel@tonic-gate * type is in use if any. 213*0Sstevel@tonic-gate */ 214*0Sstevel@tonic-gate if (((intr_type = i_ddi_intr_get_current_type(dip)) != 0) && 215*0Sstevel@tonic-gate (intr_type != type)) { 216*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Requested " 217*0Sstevel@tonic-gate "interrupt type %x is different from interrupt type %x" 218*0Sstevel@tonic-gate "already in use\n", type, intr_type)); 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate return (DDI_EINVAL); 221*0Sstevel@tonic-gate } 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate /* 224*0Sstevel@tonic-gate * Check if requested interrupt type is in use and requested number 225*0Sstevel@tonic-gate * of interrupts and number of interrupts already in use exceeds the 226*0Sstevel@tonic-gate * number of interrupts supported by this device. 227*0Sstevel@tonic-gate */ 228*0Sstevel@tonic-gate if (intr_type) { 229*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x " 230*0Sstevel@tonic-gate "is already being used\n", type)); 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate if ((count + i_ddi_intr_get_current_nintrs(dip)) > nintrs) { 233*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: count %d " 234*0Sstevel@tonic-gate "+ intrs in use %d exceeds supported %d intrs\n", 235*0Sstevel@tonic-gate count, i_ddi_intr_get_current_nintrs(dip), nintrs)); 236*0Sstevel@tonic-gate return (DDI_EINVAL); 237*0Sstevel@tonic-gate } 238*0Sstevel@tonic-gate } 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate /* 241*0Sstevel@tonic-gate * For MSI, ensure that the requested interrupt count is a power of 2 242*0Sstevel@tonic-gate */ 243*0Sstevel@tonic-gate if (type == DDI_INTR_TYPE_MSI && !ISP2(count)) { 244*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: " 245*0Sstevel@tonic-gate "MSI count %d is not a power of two\n", count)); 246*0Sstevel@tonic-gate return (DDI_EINVAL); 247*0Sstevel@tonic-gate } 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate /* 250*0Sstevel@tonic-gate * Limit max MSI/X allocation to ddi_msix_alloc_limit. 251*0Sstevel@tonic-gate * This limit will change with Resource Management support. 252*0Sstevel@tonic-gate */ 253*0Sstevel@tonic-gate if (DDI_INTR_IS_MSI_OR_MSIX(type) && (count > ddi_msix_alloc_limit)) { 254*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Requested MSI/Xs %d" 255*0Sstevel@tonic-gate "Max MSI/Xs limit %d\n", count, ddi_msix_alloc_limit)); 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate if (behavior == DDI_INTR_ALLOC_STRICT) { 258*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: " 259*0Sstevel@tonic-gate "DDI_INTR_ALLOC_STRICT flag is passed, " 260*0Sstevel@tonic-gate "return failure\n")); 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate return (DDI_EAGAIN); 263*0Sstevel@tonic-gate } 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate count = ddi_msix_alloc_limit; 266*0Sstevel@tonic-gate } 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate /* Now allocate required number of interrupts */ 269*0Sstevel@tonic-gate bzero(&tmp_hdl, sizeof (ddi_intr_handle_impl_t)); 270*0Sstevel@tonic-gate tmp_hdl.ih_type = type; 271*0Sstevel@tonic-gate tmp_hdl.ih_inum = inum; 272*0Sstevel@tonic-gate tmp_hdl.ih_scratch1 = count; 273*0Sstevel@tonic-gate tmp_hdl.ih_scratch2 = behavior; 274*0Sstevel@tonic-gate tmp_hdl.ih_dip = dip; 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate if (i_ddi_handle_intr_ops(dip, dip, DDI_INTROP_ALLOC, 277*0Sstevel@tonic-gate &tmp_hdl, (void *)actualp) != DDI_SUCCESS) { 278*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: allocation " 279*0Sstevel@tonic-gate "failed\n")); 280*0Sstevel@tonic-gate return (*actualp ? DDI_EAGAIN : DDI_INTR_NOTFOUND); 281*0Sstevel@tonic-gate } 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate if ((ret = i_ddi_handle_intr_ops(dip, dip, DDI_INTROP_GETPRI, 284*0Sstevel@tonic-gate &tmp_hdl, (void *)&pri)) != DDI_SUCCESS) { 285*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get priority " 286*0Sstevel@tonic-gate "failed\n")); 287*0Sstevel@tonic-gate return (ret); 288*0Sstevel@tonic-gate } 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: getting capability\n")); 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate if ((ret = i_ddi_handle_intr_ops(dip, dip, DDI_INTROP_GETCAP, 293*0Sstevel@tonic-gate &tmp_hdl, (void *)&cap)) != DDI_SUCCESS) { 294*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get capability " 295*0Sstevel@tonic-gate "failed\n")); 296*0Sstevel@tonic-gate return (ret); 297*0Sstevel@tonic-gate } 298*0Sstevel@tonic-gate 299*0Sstevel@tonic-gate /* Save current interrupt type, supported and current intr count */ 300*0Sstevel@tonic-gate i_ddi_intr_devi_init(dip); 301*0Sstevel@tonic-gate i_ddi_intr_set_current_type(dip, type); 302*0Sstevel@tonic-gate i_ddi_intr_set_supported_nintrs(dip, nintrs); 303*0Sstevel@tonic-gate i_ddi_intr_set_current_nintrs(dip, 304*0Sstevel@tonic-gate i_ddi_intr_get_current_nintrs(dip) + *actualp); 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate /* Now, go and handle each "handle" */ 307*0Sstevel@tonic-gate for (i = 0; i < *actualp; i++) { 308*0Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)kmem_zalloc( 309*0Sstevel@tonic-gate (sizeof (ddi_intr_handle_impl_t)), KM_SLEEP); 310*0Sstevel@tonic-gate rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL); 311*0Sstevel@tonic-gate h_array[i] = (struct __ddi_intr_handle *)hdlp; 312*0Sstevel@tonic-gate hdlp->ih_type = type; 313*0Sstevel@tonic-gate hdlp->ih_pri = pri; 314*0Sstevel@tonic-gate hdlp->ih_cap = cap; 315*0Sstevel@tonic-gate hdlp->ih_ver = DDI_INTR_VERSION; 316*0Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ALLOC; 317*0Sstevel@tonic-gate hdlp->ih_dip = dip; 318*0Sstevel@tonic-gate hdlp->ih_inum = inum + i; 319*0Sstevel@tonic-gate if (type & DDI_INTR_TYPE_FIXED) 320*0Sstevel@tonic-gate i_ddi_set_intr_handle(dip, i, &h_array[i]); 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: hdlp = 0x%p\n", 323*0Sstevel@tonic-gate (void *)h_array[i])); 324*0Sstevel@tonic-gate } 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate return (DDI_SUCCESS); 327*0Sstevel@tonic-gate } 328*0Sstevel@tonic-gate 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate int 331*0Sstevel@tonic-gate ddi_intr_free(ddi_intr_handle_t h) 332*0Sstevel@tonic-gate { 333*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 334*0Sstevel@tonic-gate int ret; 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_free: hdlp = %p\n", (void *)hdlp)); 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate if (hdlp == NULL) 339*0Sstevel@tonic-gate return (DDI_EINVAL); 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 342*0Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) { 343*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 344*0Sstevel@tonic-gate return (DDI_EINVAL); 345*0Sstevel@tonic-gate } 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 348*0Sstevel@tonic-gate DDI_INTROP_FREE, hdlp, NULL); 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 351*0Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 352*0Sstevel@tonic-gate if ((i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1) == 0) 353*0Sstevel@tonic-gate /* Reset current interrupt type and count used */ 354*0Sstevel@tonic-gate i_ddi_intr_set_current_type(hdlp->ih_dip, 0); 355*0Sstevel@tonic-gate 356*0Sstevel@tonic-gate i_ddi_intr_set_current_nintrs(hdlp->ih_dip, 357*0Sstevel@tonic-gate i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1); 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate if (hdlp->ih_type & DDI_INTR_TYPE_FIXED) 360*0Sstevel@tonic-gate i_ddi_set_intr_handle(hdlp->ih_dip, 361*0Sstevel@tonic-gate hdlp->ih_inum, NULL); 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate rw_destroy(&hdlp->ih_rwlock); 364*0Sstevel@tonic-gate kmem_free(hdlp, sizeof (ddi_intr_handle_impl_t)); 365*0Sstevel@tonic-gate } 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate return (ret); 368*0Sstevel@tonic-gate } 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate /* 371*0Sstevel@tonic-gate * Interrupt get/set capacity functions 372*0Sstevel@tonic-gate * 373*0Sstevel@tonic-gate * The logic used to figure this out is shown here: 374*0Sstevel@tonic-gate * 375*0Sstevel@tonic-gate * Device level Platform level Intr source 376*0Sstevel@tonic-gate * 1. Fixed interrupts 377*0Sstevel@tonic-gate * (non-PCI) 378*0Sstevel@tonic-gate * o Flags supported N/A Maskable/Pending/ rootnex 379*0Sstevel@tonic-gate * No Block Enable 380*0Sstevel@tonic-gate * o navail 1 381*0Sstevel@tonic-gate * 382*0Sstevel@tonic-gate * 2. PCI Fixed interrupts 383*0Sstevel@tonic-gate * o Flags supported pending/Maskable Maskable/pending/ pci 384*0Sstevel@tonic-gate * No Block enable 385*0Sstevel@tonic-gate * o navail N/A 1 386*0Sstevel@tonic-gate * 387*0Sstevel@tonic-gate * 3. PCI MSI 388*0Sstevel@tonic-gate * o Flags supported Maskable/Pending Maskable/Pending pci 389*0Sstevel@tonic-gate * Block Enable (if drvr doesn't) Block Enable 390*0Sstevel@tonic-gate * o navail N/A #vectors - #used N/A 391*0Sstevel@tonic-gate * 392*0Sstevel@tonic-gate * 4. PCI MSI-X 393*0Sstevel@tonic-gate * o Flags supported Maskable/Pending Maskable/Pending pci 394*0Sstevel@tonic-gate * Block Enable Block Enable 395*0Sstevel@tonic-gate * o navail N/A #vectors - #used N/A 396*0Sstevel@tonic-gate * 397*0Sstevel@tonic-gate * where: 398*0Sstevel@tonic-gate * #vectors - Total numbers of vectors available 399*0Sstevel@tonic-gate * #used - Total numbers of vectors currently being used 400*0Sstevel@tonic-gate * 401*0Sstevel@tonic-gate * For devices complying to PCI2.3 or greater, see bit10 of Command Register 402*0Sstevel@tonic-gate * 0 - enables assertion of INTx 403*0Sstevel@tonic-gate * 1 - disables assertion of INTx 404*0Sstevel@tonic-gate * 405*0Sstevel@tonic-gate * For non MSI/X interrupts; if the IRQ is shared then all ddi_intr_set_*() 406*0Sstevel@tonic-gate * operations return failure. 407*0Sstevel@tonic-gate */ 408*0Sstevel@tonic-gate int 409*0Sstevel@tonic-gate ddi_intr_get_cap(ddi_intr_handle_t h, int *flagsp) 410*0Sstevel@tonic-gate { 411*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 412*0Sstevel@tonic-gate int ret; 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_cap: hdlp = %p\n", 415*0Sstevel@tonic-gate (void *)hdlp)); 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate *flagsp = 0; 418*0Sstevel@tonic-gate if (hdlp == NULL) 419*0Sstevel@tonic-gate return (DDI_EINVAL); 420*0Sstevel@tonic-gate 421*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 422*0Sstevel@tonic-gate 423*0Sstevel@tonic-gate if (hdlp->ih_cap) { 424*0Sstevel@tonic-gate *flagsp = hdlp->ih_cap & ~DDI_INTR_FLAG_MSI64; 425*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 426*0Sstevel@tonic-gate return (DDI_SUCCESS); 427*0Sstevel@tonic-gate } 428*0Sstevel@tonic-gate 429*0Sstevel@tonic-gate ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 430*0Sstevel@tonic-gate DDI_INTROP_GETCAP, hdlp, (void *)flagsp); 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 433*0Sstevel@tonic-gate hdlp->ih_cap = *flagsp; 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate /* Mask out MSI/X 64-bit support to the consumer */ 436*0Sstevel@tonic-gate *flagsp &= ~DDI_INTR_FLAG_MSI64; 437*0Sstevel@tonic-gate } 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 440*0Sstevel@tonic-gate return (ret); 441*0Sstevel@tonic-gate } 442*0Sstevel@tonic-gate 443*0Sstevel@tonic-gate int 444*0Sstevel@tonic-gate ddi_intr_set_cap(ddi_intr_handle_t h, int flags) 445*0Sstevel@tonic-gate { 446*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 447*0Sstevel@tonic-gate int ret; 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_cap: hdlp = %p", (void *)hdlp)); 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate if (hdlp == NULL) 452*0Sstevel@tonic-gate return (DDI_EINVAL); 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 455*0Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) { 456*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 457*0Sstevel@tonic-gate return (DDI_EINVAL); 458*0Sstevel@tonic-gate } 459*0Sstevel@tonic-gate 460*0Sstevel@tonic-gate /* Only DDI_INTR_FLAG_LEVEL or DDI_INTR_FLAG_EDGE are allowed */ 461*0Sstevel@tonic-gate if (!(flags & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) { 462*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "%s%d: only LEVEL or EDGE capability " 463*0Sstevel@tonic-gate "can be set\n", ddi_driver_name(hdlp->ih_dip), 464*0Sstevel@tonic-gate ddi_get_instance(hdlp->ih_dip))); 465*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 466*0Sstevel@tonic-gate return (DDI_EINVAL); 467*0Sstevel@tonic-gate } 468*0Sstevel@tonic-gate 469*0Sstevel@tonic-gate /* Both level/edge flags must be currently supported */ 470*0Sstevel@tonic-gate if (!(hdlp->ih_cap & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) { 471*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "%s%d: Both LEVEL and EDGE capability" 472*0Sstevel@tonic-gate " must be supported\n", ddi_driver_name(hdlp->ih_dip), 473*0Sstevel@tonic-gate ddi_get_instance(hdlp->ih_dip))); 474*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 475*0Sstevel@tonic-gate return (DDI_ENOTSUP); 476*0Sstevel@tonic-gate } 477*0Sstevel@tonic-gate 478*0Sstevel@tonic-gate ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 479*0Sstevel@tonic-gate DDI_INTROP_SETCAP, hdlp, &flags); 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 482*0Sstevel@tonic-gate return (ret); 483*0Sstevel@tonic-gate } 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate /* 486*0Sstevel@tonic-gate * Priority related functions 487*0Sstevel@tonic-gate */ 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate /* 490*0Sstevel@tonic-gate * ddi_intr_get_hilevel_pri: 491*0Sstevel@tonic-gate * Returns the minimum priority level for a 492*0Sstevel@tonic-gate * high-level interrupt on a platform. 493*0Sstevel@tonic-gate */ 494*0Sstevel@tonic-gate uint_t 495*0Sstevel@tonic-gate ddi_intr_get_hilevel_pri(void) 496*0Sstevel@tonic-gate { 497*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_hilevel_pri:\n")); 498*0Sstevel@tonic-gate return (LOCK_LEVEL + 1); 499*0Sstevel@tonic-gate } 500*0Sstevel@tonic-gate 501*0Sstevel@tonic-gate int 502*0Sstevel@tonic-gate ddi_intr_get_pri(ddi_intr_handle_t h, uint_t *prip) 503*0Sstevel@tonic-gate { 504*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 505*0Sstevel@tonic-gate int ret; 506*0Sstevel@tonic-gate 507*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pri: hdlp = %p\n", 508*0Sstevel@tonic-gate (void *)hdlp)); 509*0Sstevel@tonic-gate 510*0Sstevel@tonic-gate *prip = 0; 511*0Sstevel@tonic-gate if (hdlp == NULL) 512*0Sstevel@tonic-gate return (DDI_EINVAL); 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 515*0Sstevel@tonic-gate /* Already initialized, just return that */ 516*0Sstevel@tonic-gate if (hdlp->ih_pri) { 517*0Sstevel@tonic-gate *prip = hdlp->ih_pri; 518*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 519*0Sstevel@tonic-gate return (DDI_SUCCESS); 520*0Sstevel@tonic-gate } 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 523*0Sstevel@tonic-gate DDI_INTROP_GETPRI, hdlp, (void *)prip); 524*0Sstevel@tonic-gate 525*0Sstevel@tonic-gate if (ret == DDI_SUCCESS) 526*0Sstevel@tonic-gate hdlp->ih_pri = *prip; 527*0Sstevel@tonic-gate 528*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 529*0Sstevel@tonic-gate return (ret); 530*0Sstevel@tonic-gate } 531*0Sstevel@tonic-gate 532*0Sstevel@tonic-gate int 533*0Sstevel@tonic-gate ddi_intr_set_pri(ddi_intr_handle_t h, uint_t pri) 534*0Sstevel@tonic-gate { 535*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 536*0Sstevel@tonic-gate int ret; 537*0Sstevel@tonic-gate 538*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: hdlp = %p", (void *)hdlp)); 539*0Sstevel@tonic-gate 540*0Sstevel@tonic-gate if (hdlp == NULL) 541*0Sstevel@tonic-gate return (DDI_EINVAL); 542*0Sstevel@tonic-gate 543*0Sstevel@tonic-gate /* Validate priority argument */ 544*0Sstevel@tonic-gate if (pri < DDI_INTR_PRI_MIN || pri > DDI_INTR_PRI_MAX) { 545*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: invalid priority " 546*0Sstevel@tonic-gate "specified = %x\n", pri)); 547*0Sstevel@tonic-gate return (DDI_EINVAL); 548*0Sstevel@tonic-gate } 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 551*0Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) { 552*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 553*0Sstevel@tonic-gate return (DDI_EINVAL); 554*0Sstevel@tonic-gate } 555*0Sstevel@tonic-gate 556*0Sstevel@tonic-gate /* If the passed priority is same as existing priority; do nothing */ 557*0Sstevel@tonic-gate if (pri == hdlp->ih_pri) { 558*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 559*0Sstevel@tonic-gate return (DDI_SUCCESS); 560*0Sstevel@tonic-gate } 561*0Sstevel@tonic-gate 562*0Sstevel@tonic-gate ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 563*0Sstevel@tonic-gate DDI_INTROP_SETPRI, hdlp, &pri); 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate if (ret == DDI_SUCCESS) 566*0Sstevel@tonic-gate hdlp->ih_pri = pri; 567*0Sstevel@tonic-gate 568*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 569*0Sstevel@tonic-gate return (ret); 570*0Sstevel@tonic-gate } 571*0Sstevel@tonic-gate 572*0Sstevel@tonic-gate /* 573*0Sstevel@tonic-gate * Interrupt add/duplicate/remove handlers 574*0Sstevel@tonic-gate */ 575*0Sstevel@tonic-gate int 576*0Sstevel@tonic-gate ddi_intr_add_handler(ddi_intr_handle_t h, ddi_intr_handler_t inthandler, 577*0Sstevel@tonic-gate void *arg1, void *arg2) 578*0Sstevel@tonic-gate { 579*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 580*0Sstevel@tonic-gate int ret; 581*0Sstevel@tonic-gate 582*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_handler: hdlp = 0x%p\n", 583*0Sstevel@tonic-gate (void *)hdlp)); 584*0Sstevel@tonic-gate 585*0Sstevel@tonic-gate if ((hdlp == NULL) || (inthandler == NULL)) 586*0Sstevel@tonic-gate return (DDI_EINVAL); 587*0Sstevel@tonic-gate 588*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 589*0Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) { 590*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 591*0Sstevel@tonic-gate return (DDI_EINVAL); 592*0Sstevel@tonic-gate } 593*0Sstevel@tonic-gate 594*0Sstevel@tonic-gate hdlp->ih_cb_func = inthandler; 595*0Sstevel@tonic-gate hdlp->ih_cb_arg1 = arg1; 596*0Sstevel@tonic-gate hdlp->ih_cb_arg2 = arg2; 597*0Sstevel@tonic-gate 598*0Sstevel@tonic-gate ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 599*0Sstevel@tonic-gate DDI_INTROP_ADDISR, hdlp, NULL); 600*0Sstevel@tonic-gate 601*0Sstevel@tonic-gate if (ret != DDI_SUCCESS) { 602*0Sstevel@tonic-gate hdlp->ih_cb_func = NULL; 603*0Sstevel@tonic-gate hdlp->ih_cb_arg1 = NULL; 604*0Sstevel@tonic-gate hdlp->ih_cb_arg2 = NULL; 605*0Sstevel@tonic-gate } else 606*0Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ADDED; 607*0Sstevel@tonic-gate 608*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 609*0Sstevel@tonic-gate return (ret); 610*0Sstevel@tonic-gate } 611*0Sstevel@tonic-gate 612*0Sstevel@tonic-gate int 613*0Sstevel@tonic-gate ddi_intr_dup_handler(ddi_intr_handle_t org, int vector, ddi_intr_handle_t *dup) 614*0Sstevel@tonic-gate { 615*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)org; 616*0Sstevel@tonic-gate ddi_intr_handle_impl_t *dup_hdlp; 617*0Sstevel@tonic-gate int ret; 618*0Sstevel@tonic-gate 619*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_dup_handler: hdlp = 0x%p\n", 620*0Sstevel@tonic-gate (void *)hdlp)); 621*0Sstevel@tonic-gate 622*0Sstevel@tonic-gate /* Do some input argument checking ("dup" is not allocated) */ 623*0Sstevel@tonic-gate if ((hdlp == NULL) || (dup != NULL)) 624*0Sstevel@tonic-gate return (DDI_EINVAL); 625*0Sstevel@tonic-gate 626*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate /* Do some input argument checking */ 629*0Sstevel@tonic-gate if ((hdlp->ih_state == DDI_IHDL_STATE_ALLOC) || /* intr handle alloc? */ 630*0Sstevel@tonic-gate (hdlp->ih_type != DDI_INTR_TYPE_MSIX)) { /* only MSI-X allowed */ 631*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 632*0Sstevel@tonic-gate return (DDI_EINVAL); 633*0Sstevel@tonic-gate } 634*0Sstevel@tonic-gate 635*0Sstevel@tonic-gate ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 636*0Sstevel@tonic-gate DDI_INTROP_DUPVEC, hdlp, (void *)&vector); 637*0Sstevel@tonic-gate 638*0Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 639*0Sstevel@tonic-gate dup_hdlp = (ddi_intr_handle_impl_t *) 640*0Sstevel@tonic-gate kmem_zalloc(sizeof (ddi_intr_handle_impl_t), KM_SLEEP); 641*0Sstevel@tonic-gate 642*0Sstevel@tonic-gate dup = (ddi_intr_handle_t *)dup_hdlp; 643*0Sstevel@tonic-gate rw_init(&dup_hdlp->ih_rwlock, NULL, RW_DRIVER, NULL); 644*0Sstevel@tonic-gate rw_enter(&dup_hdlp->ih_rwlock, RW_WRITER); 645*0Sstevel@tonic-gate dup_hdlp->ih_ver = DDI_INTR_VERSION; 646*0Sstevel@tonic-gate dup_hdlp->ih_state = DDI_IHDL_STATE_ADDED; 647*0Sstevel@tonic-gate dup_hdlp->ih_dip = hdlp->ih_dip; 648*0Sstevel@tonic-gate dup_hdlp->ih_type = hdlp->ih_type; 649*0Sstevel@tonic-gate dup_hdlp->ih_pri = hdlp->ih_pri; 650*0Sstevel@tonic-gate dup_hdlp->ih_cap = hdlp->ih_cap; 651*0Sstevel@tonic-gate dup_hdlp->ih_inum = hdlp->ih_inum; 652*0Sstevel@tonic-gate /* What about MSI-X vector */ 653*0Sstevel@tonic-gate 654*0Sstevel@tonic-gate dup_hdlp->ih_cb_func = hdlp->ih_cb_func; 655*0Sstevel@tonic-gate dup_hdlp->ih_cb_arg1 = hdlp->ih_cb_arg1; 656*0Sstevel@tonic-gate dup_hdlp->ih_cb_arg2 = hdlp->ih_cb_arg2; 657*0Sstevel@tonic-gate rw_exit(&dup_hdlp->ih_rwlock); 658*0Sstevel@tonic-gate } 659*0Sstevel@tonic-gate 660*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 661*0Sstevel@tonic-gate return (ret); 662*0Sstevel@tonic-gate } 663*0Sstevel@tonic-gate 664*0Sstevel@tonic-gate int 665*0Sstevel@tonic-gate ddi_intr_remove_handler(ddi_intr_handle_t h) 666*0Sstevel@tonic-gate { 667*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 668*0Sstevel@tonic-gate int ret; 669*0Sstevel@tonic-gate 670*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_handler: hdlp = %p\n", 671*0Sstevel@tonic-gate (void *)hdlp)); 672*0Sstevel@tonic-gate 673*0Sstevel@tonic-gate if (hdlp == NULL) 674*0Sstevel@tonic-gate return (DDI_EINVAL); 675*0Sstevel@tonic-gate 676*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 677*0Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ADDED) { 678*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 679*0Sstevel@tonic-gate return (DDI_EINVAL); 680*0Sstevel@tonic-gate } 681*0Sstevel@tonic-gate 682*0Sstevel@tonic-gate ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 683*0Sstevel@tonic-gate DDI_INTROP_REMISR, hdlp, NULL); 684*0Sstevel@tonic-gate 685*0Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 686*0Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ALLOC; 687*0Sstevel@tonic-gate hdlp->ih_cb_func = NULL; 688*0Sstevel@tonic-gate hdlp->ih_cb_arg1 = NULL; 689*0Sstevel@tonic-gate hdlp->ih_cb_arg2 = NULL; 690*0Sstevel@tonic-gate } 691*0Sstevel@tonic-gate 692*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 693*0Sstevel@tonic-gate return (ret); 694*0Sstevel@tonic-gate } 695*0Sstevel@tonic-gate 696*0Sstevel@tonic-gate /* 697*0Sstevel@tonic-gate * Interrupt enable/disable/block_enable/block_disable handlers 698*0Sstevel@tonic-gate */ 699*0Sstevel@tonic-gate int 700*0Sstevel@tonic-gate ddi_intr_enable(ddi_intr_handle_t h) 701*0Sstevel@tonic-gate { 702*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 703*0Sstevel@tonic-gate int ret; 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_enable: hdlp = %p\n", 706*0Sstevel@tonic-gate (void *)hdlp)); 707*0Sstevel@tonic-gate 708*0Sstevel@tonic-gate if (hdlp == NULL) 709*0Sstevel@tonic-gate return (DDI_EINVAL); 710*0Sstevel@tonic-gate 711*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 712*0Sstevel@tonic-gate if ((hdlp->ih_state != DDI_IHDL_STATE_ADDED) || 713*0Sstevel@tonic-gate ((hdlp->ih_type == DDI_INTR_TYPE_MSI) && 714*0Sstevel@tonic-gate (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) { 715*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 716*0Sstevel@tonic-gate return (DDI_EINVAL); 717*0Sstevel@tonic-gate } 718*0Sstevel@tonic-gate 719*0Sstevel@tonic-gate ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 720*0Sstevel@tonic-gate DDI_INTROP_ENABLE, hdlp, NULL); 721*0Sstevel@tonic-gate 722*0Sstevel@tonic-gate if (ret == DDI_SUCCESS) 723*0Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ENABLE; 724*0Sstevel@tonic-gate 725*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 726*0Sstevel@tonic-gate return (ret); 727*0Sstevel@tonic-gate } 728*0Sstevel@tonic-gate 729*0Sstevel@tonic-gate int 730*0Sstevel@tonic-gate ddi_intr_disable(ddi_intr_handle_t h) 731*0Sstevel@tonic-gate { 732*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 733*0Sstevel@tonic-gate int ret; 734*0Sstevel@tonic-gate 735*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_disable: hdlp = %p\n", 736*0Sstevel@tonic-gate (void *)hdlp)); 737*0Sstevel@tonic-gate 738*0Sstevel@tonic-gate if (hdlp == NULL) 739*0Sstevel@tonic-gate return (DDI_EINVAL); 740*0Sstevel@tonic-gate 741*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 742*0Sstevel@tonic-gate if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) || 743*0Sstevel@tonic-gate ((hdlp->ih_type == DDI_INTR_TYPE_MSI) && 744*0Sstevel@tonic-gate (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) { 745*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 746*0Sstevel@tonic-gate return (DDI_EINVAL); 747*0Sstevel@tonic-gate } 748*0Sstevel@tonic-gate 749*0Sstevel@tonic-gate ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 750*0Sstevel@tonic-gate DDI_INTROP_DISABLE, hdlp, NULL); 751*0Sstevel@tonic-gate 752*0Sstevel@tonic-gate if (ret == DDI_SUCCESS) 753*0Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ADDED; 754*0Sstevel@tonic-gate 755*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 756*0Sstevel@tonic-gate return (ret); 757*0Sstevel@tonic-gate } 758*0Sstevel@tonic-gate 759*0Sstevel@tonic-gate int 760*0Sstevel@tonic-gate ddi_intr_block_enable(ddi_intr_handle_t *h_array, int count) 761*0Sstevel@tonic-gate { 762*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp; 763*0Sstevel@tonic-gate int i, ret; 764*0Sstevel@tonic-gate 765*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_enable: h_array = %p\n", 766*0Sstevel@tonic-gate (void *)h_array)); 767*0Sstevel@tonic-gate 768*0Sstevel@tonic-gate if (h_array == NULL) 769*0Sstevel@tonic-gate return (DDI_EINVAL); 770*0Sstevel@tonic-gate 771*0Sstevel@tonic-gate for (i = 0; i < count; i++) { 772*0Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 773*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 774*0Sstevel@tonic-gate 775*0Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ADDED || 776*0Sstevel@tonic-gate hdlp->ih_type != DDI_INTR_TYPE_MSI || 777*0Sstevel@tonic-gate !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) { 778*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 779*0Sstevel@tonic-gate return (DDI_EINVAL); 780*0Sstevel@tonic-gate } 781*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 782*0Sstevel@tonic-gate } 783*0Sstevel@tonic-gate 784*0Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[0]; 785*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 786*0Sstevel@tonic-gate hdlp->ih_scratch1 = count; 787*0Sstevel@tonic-gate 788*0Sstevel@tonic-gate ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 789*0Sstevel@tonic-gate DDI_INTROP_BLOCKENABLE, hdlp, NULL); 790*0Sstevel@tonic-gate 791*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 792*0Sstevel@tonic-gate 793*0Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 794*0Sstevel@tonic-gate for (i = 0; i < count; i++) { 795*0Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 796*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 797*0Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ENABLE; 798*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 799*0Sstevel@tonic-gate } 800*0Sstevel@tonic-gate } 801*0Sstevel@tonic-gate 802*0Sstevel@tonic-gate return (ret); 803*0Sstevel@tonic-gate } 804*0Sstevel@tonic-gate 805*0Sstevel@tonic-gate int 806*0Sstevel@tonic-gate ddi_intr_block_disable(ddi_intr_handle_t *h_array, int count) 807*0Sstevel@tonic-gate { 808*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp; 809*0Sstevel@tonic-gate int i, ret; 810*0Sstevel@tonic-gate 811*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_disable: h_array = %p\n", 812*0Sstevel@tonic-gate (void *)h_array)); 813*0Sstevel@tonic-gate 814*0Sstevel@tonic-gate if (h_array == NULL) 815*0Sstevel@tonic-gate return (DDI_EINVAL); 816*0Sstevel@tonic-gate 817*0Sstevel@tonic-gate for (i = 0; i < count; i++) { 818*0Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 819*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 820*0Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ENABLE || 821*0Sstevel@tonic-gate hdlp->ih_type != DDI_INTR_TYPE_MSI || 822*0Sstevel@tonic-gate !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) { 823*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 824*0Sstevel@tonic-gate return (DDI_EINVAL); 825*0Sstevel@tonic-gate } 826*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 827*0Sstevel@tonic-gate } 828*0Sstevel@tonic-gate 829*0Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[0]; 830*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 831*0Sstevel@tonic-gate hdlp->ih_scratch1 = count; 832*0Sstevel@tonic-gate 833*0Sstevel@tonic-gate ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 834*0Sstevel@tonic-gate DDI_INTROP_BLOCKDISABLE, hdlp, NULL); 835*0Sstevel@tonic-gate 836*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 837*0Sstevel@tonic-gate 838*0Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 839*0Sstevel@tonic-gate for (i = 0; i < count; i++) { 840*0Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 841*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 842*0Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ADDED; 843*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 844*0Sstevel@tonic-gate } 845*0Sstevel@tonic-gate } 846*0Sstevel@tonic-gate 847*0Sstevel@tonic-gate return (ret); 848*0Sstevel@tonic-gate } 849*0Sstevel@tonic-gate 850*0Sstevel@tonic-gate /* 851*0Sstevel@tonic-gate * Interrupt set/clr mask handlers 852*0Sstevel@tonic-gate */ 853*0Sstevel@tonic-gate int 854*0Sstevel@tonic-gate ddi_intr_set_mask(ddi_intr_handle_t h) 855*0Sstevel@tonic-gate { 856*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 857*0Sstevel@tonic-gate int ret; 858*0Sstevel@tonic-gate 859*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_mask: hdlp = %p\n", 860*0Sstevel@tonic-gate (void *)hdlp)); 861*0Sstevel@tonic-gate 862*0Sstevel@tonic-gate if (hdlp == NULL) 863*0Sstevel@tonic-gate return (DDI_EINVAL); 864*0Sstevel@tonic-gate 865*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 866*0Sstevel@tonic-gate if (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE)) { 867*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 868*0Sstevel@tonic-gate return (DDI_EINVAL); 869*0Sstevel@tonic-gate } 870*0Sstevel@tonic-gate 871*0Sstevel@tonic-gate ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 872*0Sstevel@tonic-gate DDI_INTROP_SETMASK, hdlp, NULL); 873*0Sstevel@tonic-gate 874*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 875*0Sstevel@tonic-gate return (ret); 876*0Sstevel@tonic-gate } 877*0Sstevel@tonic-gate 878*0Sstevel@tonic-gate int 879*0Sstevel@tonic-gate ddi_intr_clr_mask(ddi_intr_handle_t h) 880*0Sstevel@tonic-gate { 881*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 882*0Sstevel@tonic-gate int ret; 883*0Sstevel@tonic-gate 884*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_clr_mask: hdlp = %p\n", 885*0Sstevel@tonic-gate (void *)hdlp)); 886*0Sstevel@tonic-gate 887*0Sstevel@tonic-gate if (hdlp == NULL) 888*0Sstevel@tonic-gate return (DDI_EINVAL); 889*0Sstevel@tonic-gate 890*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 891*0Sstevel@tonic-gate if (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE)) { 892*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 893*0Sstevel@tonic-gate return (DDI_EINVAL); 894*0Sstevel@tonic-gate } 895*0Sstevel@tonic-gate 896*0Sstevel@tonic-gate ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 897*0Sstevel@tonic-gate DDI_INTROP_CLRMASK, hdlp, NULL); 898*0Sstevel@tonic-gate 899*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 900*0Sstevel@tonic-gate return (ret); 901*0Sstevel@tonic-gate } 902*0Sstevel@tonic-gate 903*0Sstevel@tonic-gate /* 904*0Sstevel@tonic-gate * Interrupt get_pending handler 905*0Sstevel@tonic-gate */ 906*0Sstevel@tonic-gate int 907*0Sstevel@tonic-gate ddi_intr_get_pending(ddi_intr_handle_t h, int *pendingp) 908*0Sstevel@tonic-gate { 909*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 910*0Sstevel@tonic-gate int ret; 911*0Sstevel@tonic-gate 912*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pending: hdlp = %p\n", 913*0Sstevel@tonic-gate (void *)hdlp)); 914*0Sstevel@tonic-gate 915*0Sstevel@tonic-gate if (hdlp == NULL) 916*0Sstevel@tonic-gate return (DDI_EINVAL); 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 919*0Sstevel@tonic-gate if (!(hdlp->ih_cap & DDI_INTR_FLAG_PENDING)) { 920*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 921*0Sstevel@tonic-gate return (DDI_EINVAL); 922*0Sstevel@tonic-gate } 923*0Sstevel@tonic-gate 924*0Sstevel@tonic-gate ret = i_ddi_handle_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 925*0Sstevel@tonic-gate DDI_INTROP_GETPENDING, hdlp, (void *)pendingp); 926*0Sstevel@tonic-gate 927*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 928*0Sstevel@tonic-gate return (ret); 929*0Sstevel@tonic-gate } 930*0Sstevel@tonic-gate 931*0Sstevel@tonic-gate /* 932*0Sstevel@tonic-gate * Soft interrupt handlers 933*0Sstevel@tonic-gate */ 934*0Sstevel@tonic-gate /* 935*0Sstevel@tonic-gate * Add a soft interrupt and register its handler 936*0Sstevel@tonic-gate */ 937*0Sstevel@tonic-gate /* ARGSUSED */ 938*0Sstevel@tonic-gate int 939*0Sstevel@tonic-gate ddi_intr_add_softint(dev_info_t *dip, ddi_softint_handle_t *h_p, int soft_pri, 940*0Sstevel@tonic-gate ddi_intr_handler_t handler, void *arg1) 941*0Sstevel@tonic-gate { 942*0Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp; 943*0Sstevel@tonic-gate int ret; 944*0Sstevel@tonic-gate 945*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: dip = %p, " 946*0Sstevel@tonic-gate "softpri = 0x%x\n", (void *)dip, soft_pri)); 947*0Sstevel@tonic-gate 948*0Sstevel@tonic-gate if ((dip == NULL) || (h_p == NULL) || (handler == NULL)) { 949*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: " 950*0Sstevel@tonic-gate "invalid arguments")); 951*0Sstevel@tonic-gate 952*0Sstevel@tonic-gate return (DDI_EINVAL); 953*0Sstevel@tonic-gate } 954*0Sstevel@tonic-gate 955*0Sstevel@tonic-gate /* Validate input arguments */ 956*0Sstevel@tonic-gate if (soft_pri < DDI_INTR_SOFTPRI_MIN || 957*0Sstevel@tonic-gate soft_pri > DDI_INTR_SOFTPRI_MAX) { 958*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: invalid " 959*0Sstevel@tonic-gate "soft_pri input given = %x\n", soft_pri)); 960*0Sstevel@tonic-gate return (DDI_EINVAL); 961*0Sstevel@tonic-gate } 962*0Sstevel@tonic-gate 963*0Sstevel@tonic-gate hdlp = (ddi_softint_hdl_impl_t *)kmem_zalloc( 964*0Sstevel@tonic-gate sizeof (ddi_softint_hdl_impl_t), KM_SLEEP); 965*0Sstevel@tonic-gate 966*0Sstevel@tonic-gate /* fill up internally */ 967*0Sstevel@tonic-gate rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL); 968*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 969*0Sstevel@tonic-gate hdlp->ih_pri = soft_pri; 970*0Sstevel@tonic-gate hdlp->ih_dip = dip; 971*0Sstevel@tonic-gate hdlp->ih_cb_func = handler; 972*0Sstevel@tonic-gate hdlp->ih_cb_arg1 = arg1; 973*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: hdlp = %p\n", 974*0Sstevel@tonic-gate (void *)hdlp)); 975*0Sstevel@tonic-gate 976*0Sstevel@tonic-gate /* do the platform specific calls */ 977*0Sstevel@tonic-gate if ((ret = i_ddi_add_softint(hdlp)) != DDI_SUCCESS) { 978*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 979*0Sstevel@tonic-gate rw_destroy(&hdlp->ih_rwlock); 980*0Sstevel@tonic-gate kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t)); 981*0Sstevel@tonic-gate return (ret); 982*0Sstevel@tonic-gate } 983*0Sstevel@tonic-gate 984*0Sstevel@tonic-gate *h_p = (ddi_softint_handle_t)hdlp; 985*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 986*0Sstevel@tonic-gate return (ret); 987*0Sstevel@tonic-gate } 988*0Sstevel@tonic-gate 989*0Sstevel@tonic-gate /* 990*0Sstevel@tonic-gate * Remove the soft interrupt 991*0Sstevel@tonic-gate */ 992*0Sstevel@tonic-gate int 993*0Sstevel@tonic-gate ddi_intr_remove_softint(ddi_softint_handle_t h) 994*0Sstevel@tonic-gate { 995*0Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h; 996*0Sstevel@tonic-gate 997*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_softint: hdlp = %p\n", 998*0Sstevel@tonic-gate (void *)hdlp)); 999*0Sstevel@tonic-gate 1000*0Sstevel@tonic-gate if (hdlp == NULL) 1001*0Sstevel@tonic-gate return (DDI_EINVAL); 1002*0Sstevel@tonic-gate 1003*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 1004*0Sstevel@tonic-gate i_ddi_remove_softint(hdlp); 1005*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 1006*0Sstevel@tonic-gate rw_destroy(&hdlp->ih_rwlock); 1007*0Sstevel@tonic-gate 1008*0Sstevel@tonic-gate /* kmem_free the hdl impl_t structure allocated earlier */ 1009*0Sstevel@tonic-gate kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t)); 1010*0Sstevel@tonic-gate return (DDI_SUCCESS); 1011*0Sstevel@tonic-gate } 1012*0Sstevel@tonic-gate 1013*0Sstevel@tonic-gate /* 1014*0Sstevel@tonic-gate * Trigger a soft interrupt 1015*0Sstevel@tonic-gate */ 1016*0Sstevel@tonic-gate /* ARGSUSED */ 1017*0Sstevel@tonic-gate int 1018*0Sstevel@tonic-gate ddi_intr_trigger_softint(ddi_softint_handle_t h, void *arg2) 1019*0Sstevel@tonic-gate { 1020*0Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h; 1021*0Sstevel@tonic-gate caddr_t orig_arg2; 1022*0Sstevel@tonic-gate int ret; 1023*0Sstevel@tonic-gate 1024*0Sstevel@tonic-gate if (hdlp == NULL) 1025*0Sstevel@tonic-gate return (DDI_EINVAL); 1026*0Sstevel@tonic-gate 1027*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 1028*0Sstevel@tonic-gate 1029*0Sstevel@tonic-gate /* 1030*0Sstevel@tonic-gate * Need to reset "arg2" everytime. 1031*0Sstevel@tonic-gate * Multiple invocations of trigger_softint() are blocked 1032*0Sstevel@tonic-gate */ 1033*0Sstevel@tonic-gate orig_arg2 = hdlp->ih_cb_arg2; 1034*0Sstevel@tonic-gate hdlp->ih_cb_arg2 = arg2; 1035*0Sstevel@tonic-gate 1036*0Sstevel@tonic-gate if ((ret = i_ddi_trigger_softint(hdlp)) != DDI_SUCCESS) { 1037*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_trigger_softint: failed, " 1038*0Sstevel@tonic-gate " ret 0%x\n", ret)); 1039*0Sstevel@tonic-gate hdlp->ih_cb_arg2 = orig_arg2; 1040*0Sstevel@tonic-gate } 1041*0Sstevel@tonic-gate 1042*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 1043*0Sstevel@tonic-gate return (ret); 1044*0Sstevel@tonic-gate } 1045*0Sstevel@tonic-gate 1046*0Sstevel@tonic-gate /* 1047*0Sstevel@tonic-gate * Get the soft interrupt priority 1048*0Sstevel@tonic-gate */ 1049*0Sstevel@tonic-gate int 1050*0Sstevel@tonic-gate ddi_intr_get_softint_pri(ddi_softint_handle_t h, uint_t *soft_prip) 1051*0Sstevel@tonic-gate { 1052*0Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h; 1053*0Sstevel@tonic-gate 1054*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_softint_pri: h = %p\n", 1055*0Sstevel@tonic-gate (void *)h)); 1056*0Sstevel@tonic-gate 1057*0Sstevel@tonic-gate if (hdlp == NULL) 1058*0Sstevel@tonic-gate return (DDI_EINVAL); 1059*0Sstevel@tonic-gate 1060*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 1061*0Sstevel@tonic-gate *soft_prip = hdlp->ih_pri; 1062*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 1063*0Sstevel@tonic-gate return (DDI_SUCCESS); 1064*0Sstevel@tonic-gate } 1065*0Sstevel@tonic-gate 1066*0Sstevel@tonic-gate /* 1067*0Sstevel@tonic-gate * Set the soft interrupt priority 1068*0Sstevel@tonic-gate */ 1069*0Sstevel@tonic-gate int 1070*0Sstevel@tonic-gate ddi_intr_set_softint_pri(ddi_softint_handle_t h, uint_t soft_pri) 1071*0Sstevel@tonic-gate { 1072*0Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h; 1073*0Sstevel@tonic-gate int ret; 1074*0Sstevel@tonic-gate uint_t orig_soft_pri; 1075*0Sstevel@tonic-gate 1076*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: h = %p\n", 1077*0Sstevel@tonic-gate (void *)h)); 1078*0Sstevel@tonic-gate 1079*0Sstevel@tonic-gate if (hdlp == NULL) 1080*0Sstevel@tonic-gate return (DDI_EINVAL); 1081*0Sstevel@tonic-gate 1082*0Sstevel@tonic-gate /* Validate priority argument */ 1083*0Sstevel@tonic-gate if (soft_pri < DDI_INTR_SOFTPRI_MIN || 1084*0Sstevel@tonic-gate soft_pri > DDI_INTR_SOFTPRI_MAX) { 1085*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: invalid " 1086*0Sstevel@tonic-gate "soft_pri input given = %x\n", soft_pri)); 1087*0Sstevel@tonic-gate return (DDI_EINVAL); 1088*0Sstevel@tonic-gate } 1089*0Sstevel@tonic-gate 1090*0Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 1091*0Sstevel@tonic-gate orig_soft_pri = hdlp->ih_pri; 1092*0Sstevel@tonic-gate hdlp->ih_pri = soft_pri; 1093*0Sstevel@tonic-gate 1094*0Sstevel@tonic-gate if ((ret = i_ddi_set_softint_pri(hdlp, orig_soft_pri)) != DDI_SUCCESS) { 1095*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: failed, " 1096*0Sstevel@tonic-gate " ret 0%x\n", ret)); 1097*0Sstevel@tonic-gate hdlp->ih_pri = orig_soft_pri; 1098*0Sstevel@tonic-gate } 1099*0Sstevel@tonic-gate 1100*0Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 1101*0Sstevel@tonic-gate return (ret); 1102*0Sstevel@tonic-gate } 1103*0Sstevel@tonic-gate 1104*0Sstevel@tonic-gate /* 1105*0Sstevel@tonic-gate * Old DDI interrupt framework 1106*0Sstevel@tonic-gate */ 1107*0Sstevel@tonic-gate 1108*0Sstevel@tonic-gate int 1109*0Sstevel@tonic-gate ddi_intr_hilevel(dev_info_t *dip, uint_t inumber) 1110*0Sstevel@tonic-gate { 1111*0Sstevel@tonic-gate ddi_intr_handle_t hdl, *existing_hdlp; 1112*0Sstevel@tonic-gate int actual, ret; 1113*0Sstevel@tonic-gate uint_t high_pri, pri; 1114*0Sstevel@tonic-gate 1115*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: name=%s%d dip=0x%p " 1116*0Sstevel@tonic-gate "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 1117*0Sstevel@tonic-gate (void *)dip, inumber)); 1118*0Sstevel@tonic-gate 1119*0Sstevel@tonic-gate /* 1120*0Sstevel@tonic-gate * The device driver may have already registed with the 1121*0Sstevel@tonic-gate * framework. If so, first try to get the existing interrupt handle 1122*0Sstevel@tonic-gate * for that given inumber and use that handle. 1123*0Sstevel@tonic-gate */ 1124*0Sstevel@tonic-gate existing_hdlp = i_ddi_get_intr_handle(dip, inumber); 1125*0Sstevel@tonic-gate if (existing_hdlp) { 1126*0Sstevel@tonic-gate hdl = existing_hdlp[0]; /* Use existing handle */ 1127*0Sstevel@tonic-gate } else { 1128*0Sstevel@tonic-gate if ((ret = ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED, 1129*0Sstevel@tonic-gate inumber, 1, &actual, 0)) != DDI_SUCCESS) { 1130*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: " 1131*0Sstevel@tonic-gate "ddi_intr_alloc failed, ret 0x%x\n", ret)); 1132*0Sstevel@tonic-gate return (0); 1133*0Sstevel@tonic-gate } 1134*0Sstevel@tonic-gate } 1135*0Sstevel@tonic-gate 1136*0Sstevel@tonic-gate if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) { 1137*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: " 1138*0Sstevel@tonic-gate "ddi_intr_get_pri failed, ret 0x%x\n", ret)); 1139*0Sstevel@tonic-gate (void) ddi_intr_free(hdl); 1140*0Sstevel@tonic-gate return (0); 1141*0Sstevel@tonic-gate } 1142*0Sstevel@tonic-gate 1143*0Sstevel@tonic-gate high_pri = ddi_intr_get_hilevel_pri(); 1144*0Sstevel@tonic-gate 1145*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: pri = %x, " 1146*0Sstevel@tonic-gate "high_pri = %x\n", pri, high_pri)); 1147*0Sstevel@tonic-gate 1148*0Sstevel@tonic-gate /* Free the handle allocated here only if no existing handle exists */ 1149*0Sstevel@tonic-gate if (existing_hdlp == NULL) 1150*0Sstevel@tonic-gate (void) ddi_intr_free(hdl); 1151*0Sstevel@tonic-gate 1152*0Sstevel@tonic-gate return (pri >= high_pri); 1153*0Sstevel@tonic-gate } 1154*0Sstevel@tonic-gate 1155*0Sstevel@tonic-gate int 1156*0Sstevel@tonic-gate ddi_dev_nintrs(dev_info_t *dip, int *result) 1157*0Sstevel@tonic-gate { 1158*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: name=%s%d dip=0x%p\n", 1159*0Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), (void *)dip)); 1160*0Sstevel@tonic-gate 1161*0Sstevel@tonic-gate if (ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED, 1162*0Sstevel@tonic-gate result) != DDI_SUCCESS) { 1163*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: " 1164*0Sstevel@tonic-gate "ddi_intr_get_nintrs failed\n")); 1165*0Sstevel@tonic-gate *result = 0; 1166*0Sstevel@tonic-gate } 1167*0Sstevel@tonic-gate 1168*0Sstevel@tonic-gate return (DDI_SUCCESS); 1169*0Sstevel@tonic-gate } 1170*0Sstevel@tonic-gate 1171*0Sstevel@tonic-gate int 1172*0Sstevel@tonic-gate ddi_get_iblock_cookie(dev_info_t *dip, uint_t inumber, 1173*0Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep) 1174*0Sstevel@tonic-gate { 1175*0Sstevel@tonic-gate ddi_intr_handle_t hdl, *existing_hdlp; 1176*0Sstevel@tonic-gate int actual, ret; 1177*0Sstevel@tonic-gate uint_t pri; 1178*0Sstevel@tonic-gate 1179*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: name=%s%d dip=0x%p " 1180*0Sstevel@tonic-gate "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 1181*0Sstevel@tonic-gate (void *)dip, inumber)); 1182*0Sstevel@tonic-gate 1183*0Sstevel@tonic-gate ASSERT(iblock_cookiep != NULL); 1184*0Sstevel@tonic-gate 1185*0Sstevel@tonic-gate /* 1186*0Sstevel@tonic-gate * The device driver may have already registed with the 1187*0Sstevel@tonic-gate * framework. If so, first try to get the existing interrupt handle 1188*0Sstevel@tonic-gate * for that given inumber and use that handle. 1189*0Sstevel@tonic-gate */ 1190*0Sstevel@tonic-gate existing_hdlp = i_ddi_get_intr_handle(dip, inumber); 1191*0Sstevel@tonic-gate if (existing_hdlp) { 1192*0Sstevel@tonic-gate hdl = existing_hdlp[0]; /* Use existing handle */ 1193*0Sstevel@tonic-gate } else { 1194*0Sstevel@tonic-gate if ((ret = ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED, 1195*0Sstevel@tonic-gate inumber, 1, &actual, 0)) != DDI_SUCCESS) { 1196*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: " 1197*0Sstevel@tonic-gate "ddi_intr_alloc failed, ret 0x%x\n", ret)); 1198*0Sstevel@tonic-gate return (DDI_INTR_NOTFOUND); 1199*0Sstevel@tonic-gate } 1200*0Sstevel@tonic-gate } 1201*0Sstevel@tonic-gate 1202*0Sstevel@tonic-gate if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) { 1203*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: " 1204*0Sstevel@tonic-gate "ddi_intr_get_pri failed, ret 0x%x\n", ret)); 1205*0Sstevel@tonic-gate 1206*0Sstevel@tonic-gate (void) ddi_intr_free(hdl); 1207*0Sstevel@tonic-gate return (DDI_FAILURE); 1208*0Sstevel@tonic-gate } 1209*0Sstevel@tonic-gate 1210*0Sstevel@tonic-gate *iblock_cookiep = (ddi_iblock_cookie_t)(uint64_t)pri; 1211*0Sstevel@tonic-gate /* Free the handle allocated here only if no existing handle exists */ 1212*0Sstevel@tonic-gate if (existing_hdlp == NULL) 1213*0Sstevel@tonic-gate (void) ddi_intr_free(hdl); 1214*0Sstevel@tonic-gate 1215*0Sstevel@tonic-gate return (DDI_SUCCESS); 1216*0Sstevel@tonic-gate } 1217*0Sstevel@tonic-gate 1218*0Sstevel@tonic-gate int 1219*0Sstevel@tonic-gate ddi_add_intr(dev_info_t *dip, uint_t inumber, 1220*0Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep, 1221*0Sstevel@tonic-gate ddi_idevice_cookie_t *idevice_cookiep, 1222*0Sstevel@tonic-gate uint_t (*int_handler)(caddr_t int_handler_arg), 1223*0Sstevel@tonic-gate caddr_t int_handler_arg) 1224*0Sstevel@tonic-gate { 1225*0Sstevel@tonic-gate ddi_intr_handle_t *hdl_p; 1226*0Sstevel@tonic-gate int actual, ret; 1227*0Sstevel@tonic-gate uint_t pri; 1228*0Sstevel@tonic-gate 1229*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: name=%s%d dip=0x%p " 1230*0Sstevel@tonic-gate "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 1231*0Sstevel@tonic-gate (void *)dip, inumber)); 1232*0Sstevel@tonic-gate 1233*0Sstevel@tonic-gate hdl_p = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP); 1234*0Sstevel@tonic-gate 1235*0Sstevel@tonic-gate if ((ret = ddi_intr_alloc(dip, hdl_p, DDI_INTR_TYPE_FIXED, 1236*0Sstevel@tonic-gate inumber, 1, &actual, 0)) != DDI_SUCCESS) { 1237*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: " 1238*0Sstevel@tonic-gate "ddi_intr_alloc failed, ret 0x%x\n", ret)); 1239*0Sstevel@tonic-gate kmem_free(hdl_p, sizeof (ddi_intr_handle_t)); 1240*0Sstevel@tonic-gate return (DDI_INTR_NOTFOUND); 1241*0Sstevel@tonic-gate } 1242*0Sstevel@tonic-gate 1243*0Sstevel@tonic-gate if ((ret = ddi_intr_get_pri(hdl_p[0], &pri)) != DDI_SUCCESS) { 1244*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: " 1245*0Sstevel@tonic-gate "ddi_intr_get_pri failed, ret 0x%x\n", ret)); 1246*0Sstevel@tonic-gate (void) ddi_intr_free(hdl_p[0]); 1247*0Sstevel@tonic-gate kmem_free(hdl_p, sizeof (ddi_intr_handle_t)); 1248*0Sstevel@tonic-gate return (DDI_FAILURE); 1249*0Sstevel@tonic-gate } 1250*0Sstevel@tonic-gate 1251*0Sstevel@tonic-gate if ((ret = ddi_intr_add_handler(hdl_p[0], (ddi_intr_handler_t *) 1252*0Sstevel@tonic-gate int_handler, int_handler_arg, NULL)) != DDI_SUCCESS) { 1253*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: " 1254*0Sstevel@tonic-gate "ddi_intr_add_handler failed, ret 0x%x\n", ret)); 1255*0Sstevel@tonic-gate (void) ddi_intr_free(hdl_p[0]); 1256*0Sstevel@tonic-gate kmem_free(hdl_p, sizeof (ddi_intr_handle_t)); 1257*0Sstevel@tonic-gate return (DDI_FAILURE); 1258*0Sstevel@tonic-gate } 1259*0Sstevel@tonic-gate 1260*0Sstevel@tonic-gate if ((ret = ddi_intr_enable(hdl_p[0])) != DDI_SUCCESS) { 1261*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: " 1262*0Sstevel@tonic-gate "ddi_intr_enable failed, ret 0x%x\n", ret)); 1263*0Sstevel@tonic-gate (void) ddi_intr_remove_handler(hdl_p[0]); 1264*0Sstevel@tonic-gate (void) ddi_intr_free(hdl_p[0]); 1265*0Sstevel@tonic-gate kmem_free(hdl_p, sizeof (ddi_intr_handle_t)); 1266*0Sstevel@tonic-gate return (DDI_FAILURE); 1267*0Sstevel@tonic-gate } 1268*0Sstevel@tonic-gate 1269*0Sstevel@tonic-gate if (iblock_cookiep) 1270*0Sstevel@tonic-gate *iblock_cookiep = (ddi_iblock_cookie_t)(uint64_t)pri; 1271*0Sstevel@tonic-gate 1272*0Sstevel@tonic-gate if (idevice_cookiep) { 1273*0Sstevel@tonic-gate idevice_cookiep->idev_vector = 0; 1274*0Sstevel@tonic-gate idevice_cookiep->idev_priority = pri; 1275*0Sstevel@tonic-gate } 1276*0Sstevel@tonic-gate 1277*0Sstevel@tonic-gate /* this line may be removed in near future */ 1278*0Sstevel@tonic-gate i_ddi_set_intr_handle(dip, inumber, hdl_p); 1279*0Sstevel@tonic-gate 1280*0Sstevel@tonic-gate return (DDI_SUCCESS); 1281*0Sstevel@tonic-gate } 1282*0Sstevel@tonic-gate 1283*0Sstevel@tonic-gate /* ARGSUSED */ 1284*0Sstevel@tonic-gate int 1285*0Sstevel@tonic-gate ddi_add_fastintr(dev_info_t *dip, uint_t inumber, 1286*0Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep, 1287*0Sstevel@tonic-gate ddi_idevice_cookie_t *idevice_cookiep, 1288*0Sstevel@tonic-gate uint_t (*hi_int_handler)(void)) 1289*0Sstevel@tonic-gate { 1290*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_fastintr: name=%s%d dip=0x%p " 1291*0Sstevel@tonic-gate "inum=0x%x: Not supported, return failure\n", ddi_driver_name(dip), 1292*0Sstevel@tonic-gate ddi_get_instance(dip), (void *)dip, inumber)); 1293*0Sstevel@tonic-gate 1294*0Sstevel@tonic-gate return (DDI_FAILURE); 1295*0Sstevel@tonic-gate } 1296*0Sstevel@tonic-gate 1297*0Sstevel@tonic-gate /* ARGSUSED */ 1298*0Sstevel@tonic-gate void 1299*0Sstevel@tonic-gate ddi_remove_intr(dev_info_t *dip, uint_t inum, ddi_iblock_cookie_t iblock_cookie) 1300*0Sstevel@tonic-gate { 1301*0Sstevel@tonic-gate ddi_intr_handle_t *hdl_p; 1302*0Sstevel@tonic-gate int ret; 1303*0Sstevel@tonic-gate 1304*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: name=%s%d dip=0x%p " 1305*0Sstevel@tonic-gate "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 1306*0Sstevel@tonic-gate (void *)dip, inum)); 1307*0Sstevel@tonic-gate 1308*0Sstevel@tonic-gate if ((hdl_p = i_ddi_get_intr_handle(dip, inum)) == NULL) { 1309*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: no handle " 1310*0Sstevel@tonic-gate "found\n")); 1311*0Sstevel@tonic-gate return; 1312*0Sstevel@tonic-gate } 1313*0Sstevel@tonic-gate 1314*0Sstevel@tonic-gate if ((ret = ddi_intr_disable(hdl_p[0])) != DDI_SUCCESS) { 1315*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: " 1316*0Sstevel@tonic-gate "ddi_intr_disable failed, ret 0x%x\n", ret)); 1317*0Sstevel@tonic-gate return; 1318*0Sstevel@tonic-gate } 1319*0Sstevel@tonic-gate 1320*0Sstevel@tonic-gate if ((ret = ddi_intr_remove_handler(hdl_p[0])) != DDI_SUCCESS) { 1321*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: " 1322*0Sstevel@tonic-gate "ddi_intr_remove_handler failed, ret 0x%x\n", ret)); 1323*0Sstevel@tonic-gate return; 1324*0Sstevel@tonic-gate } 1325*0Sstevel@tonic-gate 1326*0Sstevel@tonic-gate if ((ret = ddi_intr_free(hdl_p[0])) != DDI_SUCCESS) { 1327*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: " 1328*0Sstevel@tonic-gate "ddi_intr_free failed, ret 0x%x\n", ret)); 1329*0Sstevel@tonic-gate return; 1330*0Sstevel@tonic-gate } 1331*0Sstevel@tonic-gate 1332*0Sstevel@tonic-gate kmem_free(hdl_p, sizeof (ddi_intr_handle_t)); 1333*0Sstevel@tonic-gate 1334*0Sstevel@tonic-gate /* this line may be removed in near future */ 1335*0Sstevel@tonic-gate i_ddi_set_intr_handle(dip, inum, NULL); 1336*0Sstevel@tonic-gate } 1337*0Sstevel@tonic-gate 1338*0Sstevel@tonic-gate /* ARGSUSED */ 1339*0Sstevel@tonic-gate int 1340*0Sstevel@tonic-gate ddi_get_soft_iblock_cookie(dev_info_t *dip, int preference, 1341*0Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep) 1342*0Sstevel@tonic-gate { 1343*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_get_soft_iblock_cookie: name=%s%d " 1344*0Sstevel@tonic-gate "dip=0x%p pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 1345*0Sstevel@tonic-gate (void *)dip, preference)); 1346*0Sstevel@tonic-gate 1347*0Sstevel@tonic-gate ASSERT(iblock_cookiep != NULL); 1348*0Sstevel@tonic-gate 1349*0Sstevel@tonic-gate if (preference == DDI_SOFTINT_FIXED) 1350*0Sstevel@tonic-gate return (DDI_FAILURE); 1351*0Sstevel@tonic-gate 1352*0Sstevel@tonic-gate *iblock_cookiep = (ddi_iblock_cookie_t)((uint64_t) 1353*0Sstevel@tonic-gate ((preference > DDI_SOFTINT_MED) ? DDI_SOFT_INTR_PRI_H : 1354*0Sstevel@tonic-gate DDI_SOFT_INTR_PRI_M)); 1355*0Sstevel@tonic-gate 1356*0Sstevel@tonic-gate return (DDI_SUCCESS); 1357*0Sstevel@tonic-gate } 1358*0Sstevel@tonic-gate 1359*0Sstevel@tonic-gate int 1360*0Sstevel@tonic-gate ddi_add_softintr(dev_info_t *dip, int preference, ddi_softintr_t *idp, 1361*0Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep, 1362*0Sstevel@tonic-gate ddi_idevice_cookie_t *idevice_cookiep, 1363*0Sstevel@tonic-gate uint_t (*int_handler)(caddr_t int_handler_arg), 1364*0Sstevel@tonic-gate caddr_t int_handler_arg) 1365*0Sstevel@tonic-gate { 1366*0Sstevel@tonic-gate ddi_softint_handle_t *hdl_p; 1367*0Sstevel@tonic-gate uint64_t softpri; 1368*0Sstevel@tonic-gate int ret; 1369*0Sstevel@tonic-gate 1370*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: name=%s%d dip=0x%p " 1371*0Sstevel@tonic-gate "pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 1372*0Sstevel@tonic-gate (void *)dip, preference)); 1373*0Sstevel@tonic-gate 1374*0Sstevel@tonic-gate if ((idp == NULL) || ((preference == DDI_SOFTINT_FIXED) && 1375*0Sstevel@tonic-gate (iblock_cookiep == NULL))) 1376*0Sstevel@tonic-gate return (DDI_FAILURE); 1377*0Sstevel@tonic-gate 1378*0Sstevel@tonic-gate /* Translate the priority preference */ 1379*0Sstevel@tonic-gate if (preference == DDI_SOFTINT_FIXED) { 1380*0Sstevel@tonic-gate softpri = (uint64_t)*iblock_cookiep; 1381*0Sstevel@tonic-gate softpri = MIN(softpri, DDI_SOFT_INTR_PRI_H); 1382*0Sstevel@tonic-gate } else { 1383*0Sstevel@tonic-gate softpri = (uint64_t)((preference > DDI_SOFTINT_MED) ? 1384*0Sstevel@tonic-gate DDI_SOFT_INTR_PRI_H : DDI_SOFT_INTR_PRI_M); 1385*0Sstevel@tonic-gate } 1386*0Sstevel@tonic-gate 1387*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: preference 0x%x " 1388*0Sstevel@tonic-gate "softpri 0x%lx\n", preference, (long)softpri)); 1389*0Sstevel@tonic-gate 1390*0Sstevel@tonic-gate hdl_p = kmem_zalloc(sizeof (ddi_softint_handle_t), KM_SLEEP); 1391*0Sstevel@tonic-gate if ((ret = ddi_intr_add_softint(dip, hdl_p, softpri, 1392*0Sstevel@tonic-gate (ddi_intr_handler_t *)int_handler, int_handler_arg)) != 1393*0Sstevel@tonic-gate DDI_SUCCESS) { 1394*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: " 1395*0Sstevel@tonic-gate "ddi_intr_add_softint failed, ret 0x%x\n", ret)); 1396*0Sstevel@tonic-gate 1397*0Sstevel@tonic-gate kmem_free(hdl_p, sizeof (ddi_softint_handle_t)); 1398*0Sstevel@tonic-gate return (DDI_FAILURE); 1399*0Sstevel@tonic-gate } 1400*0Sstevel@tonic-gate 1401*0Sstevel@tonic-gate if (iblock_cookiep) 1402*0Sstevel@tonic-gate *iblock_cookiep = (ddi_iblock_cookie_t)softpri; 1403*0Sstevel@tonic-gate 1404*0Sstevel@tonic-gate if (idevice_cookiep) { 1405*0Sstevel@tonic-gate idevice_cookiep->idev_vector = 0; 1406*0Sstevel@tonic-gate idevice_cookiep->idev_priority = softpri; 1407*0Sstevel@tonic-gate } 1408*0Sstevel@tonic-gate 1409*0Sstevel@tonic-gate *idp = (ddi_softintr_t)hdl_p; 1410*0Sstevel@tonic-gate 1411*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: dip = 0x%p, " 1412*0Sstevel@tonic-gate "idp = 0x%p, ret = %x\n", (void *)dip, (void *)*idp, ret)); 1413*0Sstevel@tonic-gate 1414*0Sstevel@tonic-gate return (DDI_SUCCESS); 1415*0Sstevel@tonic-gate } 1416*0Sstevel@tonic-gate 1417*0Sstevel@tonic-gate void 1418*0Sstevel@tonic-gate ddi_remove_softintr(ddi_softintr_t id) 1419*0Sstevel@tonic-gate { 1420*0Sstevel@tonic-gate ddi_softint_handle_t *h_p = (ddi_softint_handle_t *)id; 1421*0Sstevel@tonic-gate 1422*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: id=0x%p\n", 1423*0Sstevel@tonic-gate (void *)id)); 1424*0Sstevel@tonic-gate 1425*0Sstevel@tonic-gate if (h_p == NULL) 1426*0Sstevel@tonic-gate return; 1427*0Sstevel@tonic-gate 1428*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: handle 0x%p\n", 1429*0Sstevel@tonic-gate (void *)h_p)); 1430*0Sstevel@tonic-gate 1431*0Sstevel@tonic-gate (void) ddi_intr_remove_softint(*h_p); 1432*0Sstevel@tonic-gate kmem_free(h_p, sizeof (ddi_softint_handle_t)); 1433*0Sstevel@tonic-gate } 1434*0Sstevel@tonic-gate 1435*0Sstevel@tonic-gate void 1436*0Sstevel@tonic-gate ddi_trigger_softintr(ddi_softintr_t id) 1437*0Sstevel@tonic-gate { 1438*0Sstevel@tonic-gate ddi_softint_handle_t *h_p = (ddi_softint_handle_t *)id; 1439*0Sstevel@tonic-gate int ret; 1440*0Sstevel@tonic-gate 1441*0Sstevel@tonic-gate if (h_p == NULL) 1442*0Sstevel@tonic-gate return; 1443*0Sstevel@tonic-gate 1444*0Sstevel@tonic-gate if ((ret = ddi_intr_trigger_softint(*h_p, NULL)) != DDI_SUCCESS) { 1445*0Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_trigger_softintr: " 1446*0Sstevel@tonic-gate "ddi_intr_trigger_softint failed, hdlp 0x%p " 1447*0Sstevel@tonic-gate "ret 0x%x\n", (void *)h_p, ret)); 1448*0Sstevel@tonic-gate } 1449*0Sstevel@tonic-gate } 1450