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 /* 22*12473SScott.Carter@Oracle.COM * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 230Sstevel@tonic-gate */ 240Sstevel@tonic-gate 250Sstevel@tonic-gate #include <sys/note.h> 260Sstevel@tonic-gate #include <sys/sysmacros.h> 270Sstevel@tonic-gate #include <sys/types.h> 280Sstevel@tonic-gate #include <sys/param.h> 290Sstevel@tonic-gate #include <sys/systm.h> 300Sstevel@tonic-gate #include <sys/kmem.h> 310Sstevel@tonic-gate #include <sys/cmn_err.h> 320Sstevel@tonic-gate #include <sys/debug.h> 330Sstevel@tonic-gate #include <sys/avintr.h> 340Sstevel@tonic-gate #include <sys/autoconf.h> 350Sstevel@tonic-gate #include <sys/sunndi.h> 360Sstevel@tonic-gate #include <sys/ndi_impldefs.h> /* include prototypes */ 371725Segillett #include <sys/atomic.h> 380Sstevel@tonic-gate 390Sstevel@tonic-gate /* 400Sstevel@tonic-gate * New DDI interrupt framework 410Sstevel@tonic-gate */ 420Sstevel@tonic-gate 430Sstevel@tonic-gate /* 440Sstevel@tonic-gate * ddi_intr_get_supported_types: 450Sstevel@tonic-gate * Return, as a bit mask, the hardware interrupt types supported by 460Sstevel@tonic-gate * both the device and by the host in the integer pointed 470Sstevel@tonic-gate * to be the 'typesp' argument. 480Sstevel@tonic-gate */ 490Sstevel@tonic-gate int 500Sstevel@tonic-gate ddi_intr_get_supported_types(dev_info_t *dip, int *typesp) 510Sstevel@tonic-gate { 520Sstevel@tonic-gate int ret; 530Sstevel@tonic-gate ddi_intr_handle_impl_t hdl; 540Sstevel@tonic-gate 550Sstevel@tonic-gate if (dip == NULL) 560Sstevel@tonic-gate return (DDI_EINVAL); 570Sstevel@tonic-gate 580Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: dip %p\n", 590Sstevel@tonic-gate (void *)dip)); 600Sstevel@tonic-gate 610Sstevel@tonic-gate if (*typesp = i_ddi_intr_get_supported_types(dip)) 620Sstevel@tonic-gate return (DDI_SUCCESS); 630Sstevel@tonic-gate 640Sstevel@tonic-gate bzero(&hdl, sizeof (ddi_intr_handle_impl_t)); 650Sstevel@tonic-gate hdl.ih_dip = dip; 660Sstevel@tonic-gate 67693Sgovinda ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_SUPPORTED_TYPES, &hdl, 680Sstevel@tonic-gate (void *)typesp); 690Sstevel@tonic-gate 700Sstevel@tonic-gate if (ret != DDI_SUCCESS) 710Sstevel@tonic-gate return (DDI_INTR_NOTFOUND); 720Sstevel@tonic-gate 730Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: types %x\n", 740Sstevel@tonic-gate *typesp)); 750Sstevel@tonic-gate 760Sstevel@tonic-gate return (ret); 770Sstevel@tonic-gate } 780Sstevel@tonic-gate 790Sstevel@tonic-gate /* 800Sstevel@tonic-gate * ddi_intr_get_nintrs: 810Sstevel@tonic-gate * Return as an integer in the integer pointed to by the argument 820Sstevel@tonic-gate * *nintrsp*, the number of interrupts the device supports for the 830Sstevel@tonic-gate * given interrupt type. 840Sstevel@tonic-gate */ 850Sstevel@tonic-gate int 860Sstevel@tonic-gate ddi_intr_get_nintrs(dev_info_t *dip, int type, int *nintrsp) 870Sstevel@tonic-gate { 880Sstevel@tonic-gate int ret; 890Sstevel@tonic-gate ddi_intr_handle_impl_t hdl; 900Sstevel@tonic-gate 91693Sgovinda DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs: dip %p, type: %d\n", 92693Sgovinda (void *)dip, type)); 930Sstevel@tonic-gate 948561SScott.Carter@Sun.COM if ((dip == NULL) || (nintrsp == NULL) || 958561SScott.Carter@Sun.COM !DDI_INTR_TYPE_FLAG_VALID(type) || 962433Sanish !(i_ddi_intr_get_supported_types(dip) & type)) { 978561SScott.Carter@Sun.COM DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs: " 988561SScott.Carter@Sun.COM "Invalid input args\n")); 990Sstevel@tonic-gate return (DDI_EINVAL); 100693Sgovinda } 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate if (*nintrsp = i_ddi_intr_get_supported_nintrs(dip, type)) 1030Sstevel@tonic-gate return (DDI_SUCCESS); 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate bzero(&hdl, sizeof (ddi_intr_handle_impl_t)); 1060Sstevel@tonic-gate hdl.ih_dip = dip; 1070Sstevel@tonic-gate hdl.ih_type = type; 1080Sstevel@tonic-gate 109693Sgovinda ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_NINTRS, &hdl, 1100Sstevel@tonic-gate (void *)nintrsp); 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs:: nintrs %x\n", 1130Sstevel@tonic-gate *nintrsp)); 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate return (ret); 1160Sstevel@tonic-gate } 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate /* 1190Sstevel@tonic-gate * ddi_intr_get_navail: 1200Sstevel@tonic-gate * Bus nexus driver will return availble interrupt count value for 1210Sstevel@tonic-gate * a given interrupt type. 1220Sstevel@tonic-gate * 1230Sstevel@tonic-gate * Return as an integer in the integer pointed to by the argument 1240Sstevel@tonic-gate * *navailp*, the number of interrupts currently available for the 1250Sstevel@tonic-gate * given interrupt type. 1260Sstevel@tonic-gate */ 1270Sstevel@tonic-gate int 1280Sstevel@tonic-gate ddi_intr_get_navail(dev_info_t *dip, int type, int *navailp) 1290Sstevel@tonic-gate { 130693Sgovinda DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_navail: dip %p, type: %d\n", 131693Sgovinda (void *)dip, type)); 1320Sstevel@tonic-gate 1338561SScott.Carter@Sun.COM if ((dip == NULL) || (navailp == NULL) || 1348561SScott.Carter@Sun.COM !DDI_INTR_TYPE_FLAG_VALID(type) || 1352433Sanish !(i_ddi_intr_get_supported_types(dip) & type)) { 1368561SScott.Carter@Sun.COM DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_navail: " 1378561SScott.Carter@Sun.COM "Invalid input args\n")); 1380Sstevel@tonic-gate return (DDI_EINVAL); 139693Sgovinda } 1400Sstevel@tonic-gate 1418561SScott.Carter@Sun.COM if ((*navailp = i_ddi_intr_get_current_navail(dip, type)) == 0) 1428561SScott.Carter@Sun.COM return (DDI_INTR_NOTFOUND); 1430Sstevel@tonic-gate 1448561SScott.Carter@Sun.COM return (DDI_SUCCESS); 1450Sstevel@tonic-gate } 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate /* 1480Sstevel@tonic-gate * Interrupt allocate/free functions 1490Sstevel@tonic-gate */ 1500Sstevel@tonic-gate int 1510Sstevel@tonic-gate ddi_intr_alloc(dev_info_t *dip, ddi_intr_handle_t *h_array, int type, int inum, 1520Sstevel@tonic-gate int count, int *actualp, int behavior) 1530Sstevel@tonic-gate { 1540Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, tmp_hdl; 1558561SScott.Carter@Sun.COM int i, ret, cap = 0, curr_type, nintrs; 1568561SScott.Carter@Sun.COM uint_t pri, navail, curr_nintrs = 0; 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: name %s dip 0x%p " 1590Sstevel@tonic-gate "type %x inum %x count %x behavior %x\n", ddi_driver_name(dip), 1600Sstevel@tonic-gate (void *)dip, type, inum, count, behavior)); 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate /* Validate parameters */ 1638561SScott.Carter@Sun.COM if ((dip == NULL) || (h_array == NULL) || (inum < 0) || (count < 1) || 1648561SScott.Carter@Sun.COM (actualp == NULL) || !DDI_INTR_BEHAVIOR_FLAG_VALID(behavior)) { 1658561SScott.Carter@Sun.COM DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: " 1668561SScott.Carter@Sun.COM "Invalid input args\n")); 1670Sstevel@tonic-gate return (DDI_EINVAL); 1680Sstevel@tonic-gate } 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate /* Validate interrupt type */ 1712433Sanish if (!DDI_INTR_TYPE_FLAG_VALID(type) || 1722433Sanish !(i_ddi_intr_get_supported_types(dip) & type)) { 1730Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x not " 1740Sstevel@tonic-gate "supported\n", type)); 1750Sstevel@tonic-gate return (DDI_EINVAL); 1760Sstevel@tonic-gate } 1770Sstevel@tonic-gate 1788561SScott.Carter@Sun.COM /* Validate inum not previously allocated */ 1792433Sanish if ((type == DDI_INTR_TYPE_FIXED) && 1802433Sanish (i_ddi_get_intr_handle(dip, inum) != NULL)) { 1812433Sanish DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: inum %d is already " 1828561SScott.Carter@Sun.COM "in use, cannot allocate again!!\n", inum)); 1832433Sanish return (DDI_EINVAL); 1842433Sanish } 1852433Sanish 1868561SScott.Carter@Sun.COM /* Get how many interrupts the device supports */ 1878561SScott.Carter@Sun.COM if ((nintrs = i_ddi_intr_get_supported_nintrs(dip, type)) == 0) { 1880Sstevel@tonic-gate if (ddi_intr_get_nintrs(dip, type, &nintrs) != DDI_SUCCESS) { 1890Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no " 1900Sstevel@tonic-gate "interrupts found of type %d\n", type)); 1910Sstevel@tonic-gate return (DDI_INTR_NOTFOUND); 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate 1958561SScott.Carter@Sun.COM /* Get how many interrupts the device is already using */ 1968561SScott.Carter@Sun.COM if ((curr_type = i_ddi_intr_get_current_type(dip)) != 0) { 1978561SScott.Carter@Sun.COM DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x " 1988561SScott.Carter@Sun.COM "is already being used\n", curr_type)); 1998561SScott.Carter@Sun.COM curr_nintrs = i_ddi_intr_get_current_nintrs(dip); 2008561SScott.Carter@Sun.COM } 2018561SScott.Carter@Sun.COM 2028561SScott.Carter@Sun.COM /* Validate interrupt type consistency */ 2038561SScott.Carter@Sun.COM if ((curr_type != 0) && (type != curr_type)) { 2048561SScott.Carter@Sun.COM DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Requested " 2058561SScott.Carter@Sun.COM "interrupt type %x is different from interrupt type %x" 2068561SScott.Carter@Sun.COM "already in use\n", type, curr_type)); 2078561SScott.Carter@Sun.COM return (DDI_EINVAL); 2088561SScott.Carter@Sun.COM } 2098561SScott.Carter@Sun.COM 2108561SScott.Carter@Sun.COM /* Validate count does not exceed what device supports */ 2110Sstevel@tonic-gate if (count > nintrs) { 2120Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no of interrupts " 2130Sstevel@tonic-gate "requested %d is more than supported %d\n", count, nintrs)); 2140Sstevel@tonic-gate return (DDI_EINVAL); 2158561SScott.Carter@Sun.COM } else if ((count + curr_nintrs) > nintrs) { 2168561SScott.Carter@Sun.COM DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: count %d " 2178561SScott.Carter@Sun.COM "+ intrs in use %d exceeds supported %d intrs\n", 2188561SScott.Carter@Sun.COM count, curr_nintrs, nintrs)); 2190Sstevel@tonic-gate return (DDI_EINVAL); 2200Sstevel@tonic-gate } 2210Sstevel@tonic-gate 2228561SScott.Carter@Sun.COM /* Validate power of 2 requirements for MSI */ 2238561SScott.Carter@Sun.COM if ((type == DDI_INTR_TYPE_MSI) && !ISP2(curr_nintrs + count)) { 2240Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: " 2250Sstevel@tonic-gate "MSI count %d is not a power of two\n", count)); 2260Sstevel@tonic-gate return (DDI_EINVAL); 2270Sstevel@tonic-gate } 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate /* 2308561SScott.Carter@Sun.COM * Initialize the device's interrupt information structure, 2318561SScott.Carter@Sun.COM * and establish an association with IRM if it is supported. 2324974Segillett * 2338561SScott.Carter@Sun.COM * NOTE: IRM checks minimum support, and can return DDI_EAGAIN. 2340Sstevel@tonic-gate */ 2358561SScott.Carter@Sun.COM if (curr_nintrs == 0) { 2368561SScott.Carter@Sun.COM i_ddi_intr_devi_init(dip); 2378561SScott.Carter@Sun.COM if (i_ddi_irm_insert(dip, type, count) == DDI_EAGAIN) { 2388561SScott.Carter@Sun.COM cmn_err(CE_WARN, "ddi_intr_alloc: " 2398561SScott.Carter@Sun.COM "cannot fit into interrupt pool\n"); 2408561SScott.Carter@Sun.COM return (DDI_EAGAIN); 2418561SScott.Carter@Sun.COM } 2428561SScott.Carter@Sun.COM } 2438561SScott.Carter@Sun.COM 244*12473SScott.Carter@Oracle.COM /* Synchronously adjust IRM associations for non-IRM aware drivers */ 245*12473SScott.Carter@Oracle.COM if (curr_nintrs && (i_ddi_irm_supported(dip, type) != DDI_SUCCESS)) 246*12473SScott.Carter@Oracle.COM (void) i_ddi_irm_modify(dip, count + curr_nintrs); 247*12473SScott.Carter@Oracle.COM 2488561SScott.Carter@Sun.COM /* Get how many interrupts are currently available */ 2498561SScott.Carter@Sun.COM navail = i_ddi_intr_get_current_navail(dip, type); 2504974Segillett 2518561SScott.Carter@Sun.COM /* Validate that requested number of interrupts are available */ 2528561SScott.Carter@Sun.COM if (curr_nintrs == navail) { 2538561SScott.Carter@Sun.COM DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: max # of intrs %d " 2548561SScott.Carter@Sun.COM "already allocated\n", navail)); 2558561SScott.Carter@Sun.COM return (DDI_EAGAIN); 2568561SScott.Carter@Sun.COM } 2578561SScott.Carter@Sun.COM if ((count + curr_nintrs) > navail) { 2588561SScott.Carter@Sun.COM DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: requested # of " 2598561SScott.Carter@Sun.COM "intrs %d exceeds # of available intrs %d\n", count, 2608561SScott.Carter@Sun.COM navail - curr_nintrs)); 2618561SScott.Carter@Sun.COM if (behavior == DDI_INTR_ALLOC_STRICT) { 2620Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: " 2638561SScott.Carter@Sun.COM "DDI_INTR_ALLOC_STRICT flag is passed, " 2648561SScott.Carter@Sun.COM "return failure\n")); 265*12473SScott.Carter@Oracle.COM if (curr_nintrs == 0) 266*12473SScott.Carter@Oracle.COM i_ddi_intr_devi_fini(dip); 267*12473SScott.Carter@Oracle.COM else if (i_ddi_irm_supported(dip, type) != DDI_SUCCESS) 268*12473SScott.Carter@Oracle.COM (void) i_ddi_irm_modify(dip, curr_nintrs); 2698561SScott.Carter@Sun.COM return (DDI_EAGAIN); 2703625Segillett } 2718561SScott.Carter@Sun.COM count = navail - curr_nintrs; 2720Sstevel@tonic-gate } 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate /* Now allocate required number of interrupts */ 2750Sstevel@tonic-gate bzero(&tmp_hdl, sizeof (ddi_intr_handle_impl_t)); 2760Sstevel@tonic-gate tmp_hdl.ih_type = type; 2770Sstevel@tonic-gate tmp_hdl.ih_inum = inum; 2780Sstevel@tonic-gate tmp_hdl.ih_scratch1 = count; 2791717Swesolows tmp_hdl.ih_scratch2 = (void *)(uintptr_t)behavior; 2800Sstevel@tonic-gate tmp_hdl.ih_dip = dip; 2810Sstevel@tonic-gate 282693Sgovinda if (i_ddi_intr_ops(dip, dip, DDI_INTROP_ALLOC, 2830Sstevel@tonic-gate &tmp_hdl, (void *)actualp) != DDI_SUCCESS) { 2840Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: allocation " 2850Sstevel@tonic-gate "failed\n")); 2861725Segillett i_ddi_intr_devi_fini(dip); 2870Sstevel@tonic-gate return (*actualp ? DDI_EAGAIN : DDI_INTR_NOTFOUND); 2880Sstevel@tonic-gate } 2890Sstevel@tonic-gate 290693Sgovinda if ((ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_GETPRI, 2910Sstevel@tonic-gate &tmp_hdl, (void *)&pri)) != DDI_SUCCESS) { 2920Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get priority " 2930Sstevel@tonic-gate "failed\n")); 2941725Segillett goto fail; 2950Sstevel@tonic-gate } 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: getting capability\n")); 2980Sstevel@tonic-gate 299693Sgovinda if ((ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_GETCAP, 3000Sstevel@tonic-gate &tmp_hdl, (void *)&cap)) != DDI_SUCCESS) { 3010Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get capability " 3020Sstevel@tonic-gate "failed\n")); 3031725Segillett goto fail; 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate 3061725Segillett /* 3071725Segillett * Save current interrupt type, supported and current intr count. 3081725Segillett */ 3090Sstevel@tonic-gate i_ddi_intr_set_current_type(dip, type); 3100Sstevel@tonic-gate i_ddi_intr_set_supported_nintrs(dip, nintrs); 3110Sstevel@tonic-gate i_ddi_intr_set_current_nintrs(dip, 3120Sstevel@tonic-gate i_ddi_intr_get_current_nintrs(dip) + *actualp); 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate /* Now, go and handle each "handle" */ 3158561SScott.Carter@Sun.COM for (i = inum; i < (inum + *actualp); i++) { 3160Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)kmem_zalloc( 3170Sstevel@tonic-gate (sizeof (ddi_intr_handle_impl_t)), KM_SLEEP); 3180Sstevel@tonic-gate rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL); 3190Sstevel@tonic-gate h_array[i] = (struct __ddi_intr_handle *)hdlp; 3200Sstevel@tonic-gate hdlp->ih_type = type; 3210Sstevel@tonic-gate hdlp->ih_pri = pri; 3220Sstevel@tonic-gate hdlp->ih_cap = cap; 3230Sstevel@tonic-gate hdlp->ih_ver = DDI_INTR_VERSION; 3240Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ALLOC; 3250Sstevel@tonic-gate hdlp->ih_dip = dip; 3268561SScott.Carter@Sun.COM hdlp->ih_inum = i; 327916Sschwartz i_ddi_alloc_intr_phdl(hdlp); 3280Sstevel@tonic-gate if (type & DDI_INTR_TYPE_FIXED) 3298561SScott.Carter@Sun.COM i_ddi_set_intr_handle(dip, hdlp->ih_inum, 3308561SScott.Carter@Sun.COM (ddi_intr_handle_t)hdlp); 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: hdlp = 0x%p\n", 3330Sstevel@tonic-gate (void *)h_array[i])); 3340Sstevel@tonic-gate } 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate return (DDI_SUCCESS); 3371725Segillett 3381725Segillett fail: 3391725Segillett (void) i_ddi_intr_ops(tmp_hdl.ih_dip, tmp_hdl.ih_dip, 3401725Segillett DDI_INTROP_FREE, &tmp_hdl, NULL); 3411725Segillett i_ddi_intr_devi_fini(dip); 3421725Segillett 3431725Segillett return (ret); 3440Sstevel@tonic-gate } 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate int 3470Sstevel@tonic-gate ddi_intr_free(ddi_intr_handle_t h) 3480Sstevel@tonic-gate { 3490Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 3500Sstevel@tonic-gate int ret; 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_free: hdlp = %p\n", (void *)hdlp)); 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate if (hdlp == NULL) 3550Sstevel@tonic-gate return (DDI_EINVAL); 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 3581725Segillett if (((hdlp->ih_flags & DDI_INTR_MSIX_DUP) && 3591725Segillett (hdlp->ih_state != DDI_IHDL_STATE_ADDED)) || 3601725Segillett ((hdlp->ih_state != DDI_IHDL_STATE_ALLOC) && 3611725Segillett (!(hdlp->ih_flags & DDI_INTR_MSIX_DUP)))) { 3620Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 3630Sstevel@tonic-gate return (DDI_EINVAL); 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate 3662588Segillett /* Set the number of interrupts to free */ 3672588Segillett hdlp->ih_scratch1 = 1; 3682588Segillett 369693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 3700Sstevel@tonic-gate DDI_INTROP_FREE, hdlp, NULL); 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 3730Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 3741725Segillett /* This would be the dup vector */ 3751725Segillett if (hdlp->ih_flags & DDI_INTR_MSIX_DUP) 3761725Segillett atomic_dec_32(&hdlp->ih_main->ih_dup_cnt); 3771725Segillett else { 378*12473SScott.Carter@Oracle.COM int n, curr_type; 379*12473SScott.Carter@Oracle.COM 380*12473SScott.Carter@Oracle.COM n = i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1; 381*12473SScott.Carter@Oracle.COM curr_type = i_ddi_intr_get_current_type(hdlp->ih_dip); 382*12473SScott.Carter@Oracle.COM 383*12473SScott.Carter@Oracle.COM i_ddi_intr_set_current_nintrs(hdlp->ih_dip, n); 384*12473SScott.Carter@Oracle.COM 385*12473SScott.Carter@Oracle.COM if ((i_ddi_irm_supported(hdlp->ih_dip, curr_type) 386*12473SScott.Carter@Oracle.COM != DDI_SUCCESS) && (n > 0)) 387*12473SScott.Carter@Oracle.COM (void) i_ddi_irm_modify(hdlp->ih_dip, n); 3880Sstevel@tonic-gate 3892588Segillett if (hdlp->ih_type & DDI_INTR_TYPE_FIXED) 3902588Segillett i_ddi_set_intr_handle(hdlp->ih_dip, 3912588Segillett hdlp->ih_inum, NULL); 3921725Segillett 3932588Segillett i_ddi_intr_devi_fini(hdlp->ih_dip); 3941725Segillett i_ddi_free_intr_phdl(hdlp); 395693Sgovinda } 3960Sstevel@tonic-gate rw_destroy(&hdlp->ih_rwlock); 3970Sstevel@tonic-gate kmem_free(hdlp, sizeof (ddi_intr_handle_impl_t)); 3980Sstevel@tonic-gate } 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate return (ret); 4010Sstevel@tonic-gate } 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate /* 4040Sstevel@tonic-gate * Interrupt get/set capacity functions 4050Sstevel@tonic-gate * 4060Sstevel@tonic-gate * The logic used to figure this out is shown here: 4070Sstevel@tonic-gate * 4080Sstevel@tonic-gate * Device level Platform level Intr source 4090Sstevel@tonic-gate * 1. Fixed interrupts 4100Sstevel@tonic-gate * (non-PCI) 4110Sstevel@tonic-gate * o Flags supported N/A Maskable/Pending/ rootnex 4120Sstevel@tonic-gate * No Block Enable 4130Sstevel@tonic-gate * o navail 1 4140Sstevel@tonic-gate * 4150Sstevel@tonic-gate * 2. PCI Fixed interrupts 4160Sstevel@tonic-gate * o Flags supported pending/Maskable Maskable/pending/ pci 4170Sstevel@tonic-gate * No Block enable 4180Sstevel@tonic-gate * o navail N/A 1 4190Sstevel@tonic-gate * 4200Sstevel@tonic-gate * 3. PCI MSI 4210Sstevel@tonic-gate * o Flags supported Maskable/Pending Maskable/Pending pci 4220Sstevel@tonic-gate * Block Enable (if drvr doesn't) Block Enable 4230Sstevel@tonic-gate * o navail N/A #vectors - #used N/A 4240Sstevel@tonic-gate * 4250Sstevel@tonic-gate * 4. PCI MSI-X 4260Sstevel@tonic-gate * o Flags supported Maskable/Pending Maskable/Pending pci 4270Sstevel@tonic-gate * Block Enable Block Enable 4280Sstevel@tonic-gate * o navail N/A #vectors - #used N/A 4290Sstevel@tonic-gate * 4300Sstevel@tonic-gate * where: 4310Sstevel@tonic-gate * #vectors - Total numbers of vectors available 4320Sstevel@tonic-gate * #used - Total numbers of vectors currently being used 4330Sstevel@tonic-gate * 4340Sstevel@tonic-gate * For devices complying to PCI2.3 or greater, see bit10 of Command Register 4350Sstevel@tonic-gate * 0 - enables assertion of INTx 4360Sstevel@tonic-gate * 1 - disables assertion of INTx 4370Sstevel@tonic-gate * 4380Sstevel@tonic-gate * For non MSI/X interrupts; if the IRQ is shared then all ddi_intr_set_*() 4390Sstevel@tonic-gate * operations return failure. 4400Sstevel@tonic-gate */ 4410Sstevel@tonic-gate int 4420Sstevel@tonic-gate ddi_intr_get_cap(ddi_intr_handle_t h, int *flagsp) 4430Sstevel@tonic-gate { 4440Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 4450Sstevel@tonic-gate int ret; 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_cap: hdlp = %p\n", 4480Sstevel@tonic-gate (void *)hdlp)); 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate *flagsp = 0; 4510Sstevel@tonic-gate if (hdlp == NULL) 4520Sstevel@tonic-gate return (DDI_EINVAL); 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate if (hdlp->ih_cap) { 4570Sstevel@tonic-gate *flagsp = hdlp->ih_cap & ~DDI_INTR_FLAG_MSI64; 4580Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 4590Sstevel@tonic-gate return (DDI_SUCCESS); 4600Sstevel@tonic-gate } 4610Sstevel@tonic-gate 462693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 4630Sstevel@tonic-gate DDI_INTROP_GETCAP, hdlp, (void *)flagsp); 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 4660Sstevel@tonic-gate hdlp->ih_cap = *flagsp; 4670Sstevel@tonic-gate 4680Sstevel@tonic-gate /* Mask out MSI/X 64-bit support to the consumer */ 4690Sstevel@tonic-gate *flagsp &= ~DDI_INTR_FLAG_MSI64; 4700Sstevel@tonic-gate } 4710Sstevel@tonic-gate 4720Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 4730Sstevel@tonic-gate return (ret); 4740Sstevel@tonic-gate } 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate int 4770Sstevel@tonic-gate ddi_intr_set_cap(ddi_intr_handle_t h, int flags) 4780Sstevel@tonic-gate { 4790Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 4800Sstevel@tonic-gate int ret; 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_cap: hdlp = %p", (void *)hdlp)); 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate if (hdlp == NULL) 4850Sstevel@tonic-gate return (DDI_EINVAL); 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 4880Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) { 4890Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 4900Sstevel@tonic-gate return (DDI_EINVAL); 4910Sstevel@tonic-gate } 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate /* Only DDI_INTR_FLAG_LEVEL or DDI_INTR_FLAG_EDGE are allowed */ 4940Sstevel@tonic-gate if (!(flags & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) { 4950Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "%s%d: only LEVEL or EDGE capability " 4960Sstevel@tonic-gate "can be set\n", ddi_driver_name(hdlp->ih_dip), 4970Sstevel@tonic-gate ddi_get_instance(hdlp->ih_dip))); 4980Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 4990Sstevel@tonic-gate return (DDI_EINVAL); 5000Sstevel@tonic-gate } 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate /* Both level/edge flags must be currently supported */ 5030Sstevel@tonic-gate if (!(hdlp->ih_cap & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) { 5040Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "%s%d: Both LEVEL and EDGE capability" 5050Sstevel@tonic-gate " must be supported\n", ddi_driver_name(hdlp->ih_dip), 5060Sstevel@tonic-gate ddi_get_instance(hdlp->ih_dip))); 5070Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 5080Sstevel@tonic-gate return (DDI_ENOTSUP); 5090Sstevel@tonic-gate } 5100Sstevel@tonic-gate 511693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 5120Sstevel@tonic-gate DDI_INTROP_SETCAP, hdlp, &flags); 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 5150Sstevel@tonic-gate return (ret); 5160Sstevel@tonic-gate } 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate /* 5190Sstevel@tonic-gate * Priority related functions 5200Sstevel@tonic-gate */ 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate /* 5230Sstevel@tonic-gate * ddi_intr_get_hilevel_pri: 5240Sstevel@tonic-gate * Returns the minimum priority level for a 5250Sstevel@tonic-gate * high-level interrupt on a platform. 5260Sstevel@tonic-gate */ 5270Sstevel@tonic-gate uint_t 5280Sstevel@tonic-gate ddi_intr_get_hilevel_pri(void) 5290Sstevel@tonic-gate { 5300Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_hilevel_pri:\n")); 5310Sstevel@tonic-gate return (LOCK_LEVEL + 1); 5320Sstevel@tonic-gate } 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate int 5350Sstevel@tonic-gate ddi_intr_get_pri(ddi_intr_handle_t h, uint_t *prip) 5360Sstevel@tonic-gate { 5370Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 5380Sstevel@tonic-gate int ret; 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pri: hdlp = %p\n", 5410Sstevel@tonic-gate (void *)hdlp)); 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate *prip = 0; 5440Sstevel@tonic-gate if (hdlp == NULL) 5450Sstevel@tonic-gate return (DDI_EINVAL); 5460Sstevel@tonic-gate 5470Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 5480Sstevel@tonic-gate /* Already initialized, just return that */ 5490Sstevel@tonic-gate if (hdlp->ih_pri) { 5500Sstevel@tonic-gate *prip = hdlp->ih_pri; 5510Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 5520Sstevel@tonic-gate return (DDI_SUCCESS); 5530Sstevel@tonic-gate } 5540Sstevel@tonic-gate 555693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 5560Sstevel@tonic-gate DDI_INTROP_GETPRI, hdlp, (void *)prip); 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate if (ret == DDI_SUCCESS) 5590Sstevel@tonic-gate hdlp->ih_pri = *prip; 5600Sstevel@tonic-gate 5610Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 5620Sstevel@tonic-gate return (ret); 5630Sstevel@tonic-gate } 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate int 5660Sstevel@tonic-gate ddi_intr_set_pri(ddi_intr_handle_t h, uint_t pri) 5670Sstevel@tonic-gate { 5680Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 5690Sstevel@tonic-gate int ret; 5700Sstevel@tonic-gate 5710Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: hdlp = %p", (void *)hdlp)); 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate if (hdlp == NULL) 5740Sstevel@tonic-gate return (DDI_EINVAL); 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate /* Validate priority argument */ 5770Sstevel@tonic-gate if (pri < DDI_INTR_PRI_MIN || pri > DDI_INTR_PRI_MAX) { 5780Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: invalid priority " 5790Sstevel@tonic-gate "specified = %x\n", pri)); 5800Sstevel@tonic-gate return (DDI_EINVAL); 5810Sstevel@tonic-gate } 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 5840Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) { 5850Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 5860Sstevel@tonic-gate return (DDI_EINVAL); 5870Sstevel@tonic-gate } 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate /* If the passed priority is same as existing priority; do nothing */ 5900Sstevel@tonic-gate if (pri == hdlp->ih_pri) { 5910Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 5920Sstevel@tonic-gate return (DDI_SUCCESS); 5930Sstevel@tonic-gate } 5940Sstevel@tonic-gate 595693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 5960Sstevel@tonic-gate DDI_INTROP_SETPRI, hdlp, &pri); 5970Sstevel@tonic-gate 5980Sstevel@tonic-gate if (ret == DDI_SUCCESS) 5990Sstevel@tonic-gate hdlp->ih_pri = pri; 6000Sstevel@tonic-gate 6010Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 6020Sstevel@tonic-gate return (ret); 6030Sstevel@tonic-gate } 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate /* 6060Sstevel@tonic-gate * Interrupt add/duplicate/remove handlers 6070Sstevel@tonic-gate */ 6080Sstevel@tonic-gate int 6090Sstevel@tonic-gate ddi_intr_add_handler(ddi_intr_handle_t h, ddi_intr_handler_t inthandler, 6100Sstevel@tonic-gate void *arg1, void *arg2) 6110Sstevel@tonic-gate { 6120Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 6130Sstevel@tonic-gate int ret; 6140Sstevel@tonic-gate 6150Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_handler: hdlp = 0x%p\n", 6160Sstevel@tonic-gate (void *)hdlp)); 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate if ((hdlp == NULL) || (inthandler == NULL)) 6190Sstevel@tonic-gate return (DDI_EINVAL); 6200Sstevel@tonic-gate 6210Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 6220Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) { 6230Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 6240Sstevel@tonic-gate return (DDI_EINVAL); 6250Sstevel@tonic-gate } 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate hdlp->ih_cb_func = inthandler; 6280Sstevel@tonic-gate hdlp->ih_cb_arg1 = arg1; 6290Sstevel@tonic-gate hdlp->ih_cb_arg2 = arg2; 6300Sstevel@tonic-gate 631693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 6320Sstevel@tonic-gate DDI_INTROP_ADDISR, hdlp, NULL); 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate if (ret != DDI_SUCCESS) { 6350Sstevel@tonic-gate hdlp->ih_cb_func = NULL; 6360Sstevel@tonic-gate hdlp->ih_cb_arg1 = NULL; 6370Sstevel@tonic-gate hdlp->ih_cb_arg2 = NULL; 6380Sstevel@tonic-gate } else 6390Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ADDED; 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 6420Sstevel@tonic-gate return (ret); 6430Sstevel@tonic-gate } 6440Sstevel@tonic-gate 6450Sstevel@tonic-gate int 6461725Segillett ddi_intr_dup_handler(ddi_intr_handle_t org, int dup_inum, 6471725Segillett ddi_intr_handle_t *dup) 6480Sstevel@tonic-gate { 6490Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)org; 6500Sstevel@tonic-gate ddi_intr_handle_impl_t *dup_hdlp; 6510Sstevel@tonic-gate int ret; 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_dup_handler: hdlp = 0x%p\n", 6540Sstevel@tonic-gate (void *)hdlp)); 6550Sstevel@tonic-gate 6561725Segillett /* Do some input argument checking ("dup" handle is not allocated) */ 6572433Sanish if ((hdlp == NULL) || (*dup != NULL) || (dup_inum < 0)) { 6582433Sanish DDI_INTR_APIDBG((CE_CONT, "ddi_intr_dup_handler: Invalid " 6592433Sanish "input args\n")); 6600Sstevel@tonic-gate return (DDI_EINVAL); 6612433Sanish } 6620Sstevel@tonic-gate 6630Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate /* Do some input argument checking */ 6660Sstevel@tonic-gate if ((hdlp->ih_state == DDI_IHDL_STATE_ALLOC) || /* intr handle alloc? */ 6671725Segillett (hdlp->ih_type != DDI_INTR_TYPE_MSIX) || /* only MSI-X allowed */ 6681725Segillett (hdlp->ih_flags & DDI_INTR_MSIX_DUP)) { /* only dup original */ 6690Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 6700Sstevel@tonic-gate return (DDI_EINVAL); 6710Sstevel@tonic-gate } 6720Sstevel@tonic-gate 6731725Segillett hdlp->ih_scratch1 = dup_inum; 674693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 6751725Segillett DDI_INTROP_DUPVEC, hdlp, NULL); 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 6780Sstevel@tonic-gate dup_hdlp = (ddi_intr_handle_impl_t *) 6791725Segillett kmem_alloc(sizeof (ddi_intr_handle_impl_t), KM_SLEEP); 6801725Segillett 6811725Segillett atomic_add_32(&hdlp->ih_dup_cnt, 1); 6820Sstevel@tonic-gate 6831725Segillett *dup = (ddi_intr_handle_t)dup_hdlp; 6841725Segillett bcopy(hdlp, dup_hdlp, sizeof (ddi_intr_handle_impl_t)); 6851725Segillett 6861725Segillett /* These fields are unique to each dupped msi-x vector */ 6870Sstevel@tonic-gate rw_init(&dup_hdlp->ih_rwlock, NULL, RW_DRIVER, NULL); 6880Sstevel@tonic-gate dup_hdlp->ih_state = DDI_IHDL_STATE_ADDED; 6891725Segillett dup_hdlp->ih_inum = dup_inum; 6901725Segillett dup_hdlp->ih_flags |= DDI_INTR_MSIX_DUP; 6911725Segillett dup_hdlp->ih_dup_cnt = 0; 6920Sstevel@tonic-gate 6931725Segillett /* Point back to original vector */ 6941725Segillett dup_hdlp->ih_main = hdlp; 6950Sstevel@tonic-gate } 6960Sstevel@tonic-gate 6970Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 6980Sstevel@tonic-gate return (ret); 6990Sstevel@tonic-gate } 7000Sstevel@tonic-gate 7010Sstevel@tonic-gate int 7020Sstevel@tonic-gate ddi_intr_remove_handler(ddi_intr_handle_t h) 7030Sstevel@tonic-gate { 7040Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 7051725Segillett int ret = DDI_SUCCESS; 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_handler: hdlp = %p\n", 7080Sstevel@tonic-gate (void *)hdlp)); 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate if (hdlp == NULL) 7110Sstevel@tonic-gate return (DDI_EINVAL); 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 7141725Segillett 7150Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ADDED) { 7161725Segillett ret = DDI_EINVAL; 7171725Segillett goto done; 7181725Segillett } else if (hdlp->ih_flags & DDI_INTR_MSIX_DUP) 7191725Segillett goto done; 7201725Segillett 7211725Segillett ASSERT(hdlp->ih_dup_cnt == 0); 7221725Segillett if (hdlp->ih_dup_cnt > 0) { 7231725Segillett DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_handler: MSI-X " 7241725Segillett "dup_cnt %d is not 0\n", hdlp->ih_dup_cnt)); 7251725Segillett ret = DDI_FAILURE; 7261725Segillett goto done; 7270Sstevel@tonic-gate } 7280Sstevel@tonic-gate 729693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 7300Sstevel@tonic-gate DDI_INTROP_REMISR, hdlp, NULL); 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 7330Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ALLOC; 7340Sstevel@tonic-gate hdlp->ih_cb_func = NULL; 7350Sstevel@tonic-gate hdlp->ih_cb_arg1 = NULL; 7360Sstevel@tonic-gate hdlp->ih_cb_arg2 = NULL; 7370Sstevel@tonic-gate } 7380Sstevel@tonic-gate 7391725Segillett done: 7400Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 7410Sstevel@tonic-gate return (ret); 7420Sstevel@tonic-gate } 7430Sstevel@tonic-gate 7440Sstevel@tonic-gate /* 74510053SEvan.Yan@Sun.COM * Interrupt target get/set functions 74610053SEvan.Yan@Sun.COM */ 74710053SEvan.Yan@Sun.COM int 74810053SEvan.Yan@Sun.COM ddi_intr_get_affinity(ddi_intr_handle_t h, ddi_intr_target_t *tgt_p) 74910053SEvan.Yan@Sun.COM { 75010053SEvan.Yan@Sun.COM ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 75110053SEvan.Yan@Sun.COM int ret; 75210053SEvan.Yan@Sun.COM 75310053SEvan.Yan@Sun.COM DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_affinity: hdlp = %p\n", 75410053SEvan.Yan@Sun.COM (void *)hdlp)); 75510053SEvan.Yan@Sun.COM 75610053SEvan.Yan@Sun.COM if ((hdlp == NULL) || (tgt_p == NULL)) 75710053SEvan.Yan@Sun.COM return (DDI_EINVAL); 75810053SEvan.Yan@Sun.COM 75910053SEvan.Yan@Sun.COM rw_enter(&hdlp->ih_rwlock, RW_READER); 76010053SEvan.Yan@Sun.COM if (hdlp->ih_state != DDI_IHDL_STATE_ENABLE) { 76110053SEvan.Yan@Sun.COM rw_exit(&hdlp->ih_rwlock); 76210053SEvan.Yan@Sun.COM return (DDI_EINVAL); 76310053SEvan.Yan@Sun.COM } 76410053SEvan.Yan@Sun.COM 76510053SEvan.Yan@Sun.COM ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 76610053SEvan.Yan@Sun.COM DDI_INTROP_GETTARGET, hdlp, (void *)tgt_p); 76710053SEvan.Yan@Sun.COM 76810053SEvan.Yan@Sun.COM DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_affinity: target %x\n", 76910053SEvan.Yan@Sun.COM *tgt_p)); 77010053SEvan.Yan@Sun.COM 77110053SEvan.Yan@Sun.COM if (ret == DDI_SUCCESS) 77210053SEvan.Yan@Sun.COM hdlp->ih_target = *tgt_p; 77310053SEvan.Yan@Sun.COM 77410053SEvan.Yan@Sun.COM rw_exit(&hdlp->ih_rwlock); 77510053SEvan.Yan@Sun.COM return (ret); 77610053SEvan.Yan@Sun.COM } 77710053SEvan.Yan@Sun.COM 77810053SEvan.Yan@Sun.COM int 77910053SEvan.Yan@Sun.COM ddi_intr_set_affinity(ddi_intr_handle_t h, ddi_intr_target_t tgt) 78010053SEvan.Yan@Sun.COM { 78110053SEvan.Yan@Sun.COM ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 78210053SEvan.Yan@Sun.COM int ret; 78310053SEvan.Yan@Sun.COM 78410053SEvan.Yan@Sun.COM DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_affinity: hdlp = %p " 78510053SEvan.Yan@Sun.COM "target %x\n", (void *)hdlp, tgt)); 78610053SEvan.Yan@Sun.COM 78710053SEvan.Yan@Sun.COM if (hdlp == NULL) 78810053SEvan.Yan@Sun.COM return (DDI_EINVAL); 78910053SEvan.Yan@Sun.COM 79010053SEvan.Yan@Sun.COM rw_enter(&hdlp->ih_rwlock, RW_WRITER); 79110053SEvan.Yan@Sun.COM if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) || 79210053SEvan.Yan@Sun.COM !(hdlp->ih_cap & DDI_INTR_FLAG_RETARGETABLE)) { 79310053SEvan.Yan@Sun.COM rw_exit(&hdlp->ih_rwlock); 79410053SEvan.Yan@Sun.COM return (DDI_EINVAL); 79510053SEvan.Yan@Sun.COM } 79610053SEvan.Yan@Sun.COM 79710053SEvan.Yan@Sun.COM ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 79810053SEvan.Yan@Sun.COM DDI_INTROP_SETTARGET, hdlp, &tgt); 79910053SEvan.Yan@Sun.COM 80010053SEvan.Yan@Sun.COM if (ret == DDI_SUCCESS) 80110053SEvan.Yan@Sun.COM hdlp->ih_target = tgt; 80210053SEvan.Yan@Sun.COM 80310053SEvan.Yan@Sun.COM rw_exit(&hdlp->ih_rwlock); 80410053SEvan.Yan@Sun.COM return (ret); 80510053SEvan.Yan@Sun.COM } 80610053SEvan.Yan@Sun.COM 80710053SEvan.Yan@Sun.COM /* 8080Sstevel@tonic-gate * Interrupt enable/disable/block_enable/block_disable handlers 8090Sstevel@tonic-gate */ 8100Sstevel@tonic-gate int 8110Sstevel@tonic-gate ddi_intr_enable(ddi_intr_handle_t h) 8120Sstevel@tonic-gate { 8130Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 8140Sstevel@tonic-gate int ret; 8150Sstevel@tonic-gate 8160Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_enable: hdlp = %p\n", 8170Sstevel@tonic-gate (void *)hdlp)); 8180Sstevel@tonic-gate 8190Sstevel@tonic-gate if (hdlp == NULL) 8200Sstevel@tonic-gate return (DDI_EINVAL); 8210Sstevel@tonic-gate 8220Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 8230Sstevel@tonic-gate if ((hdlp->ih_state != DDI_IHDL_STATE_ADDED) || 8240Sstevel@tonic-gate ((hdlp->ih_type == DDI_INTR_TYPE_MSI) && 8250Sstevel@tonic-gate (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) { 8260Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 8270Sstevel@tonic-gate return (DDI_EINVAL); 8280Sstevel@tonic-gate } 8290Sstevel@tonic-gate 8301725Segillett I_DDI_VERIFY_MSIX_HANDLE(hdlp); 8311725Segillett 832693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 8330Sstevel@tonic-gate DDI_INTROP_ENABLE, hdlp, NULL); 8340Sstevel@tonic-gate 8358817SKerry.Shu@Sun.COM if (ret == DDI_SUCCESS) { 8360Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ENABLE; 8378817SKerry.Shu@Sun.COM i_ddi_intr_set_current_nenables(hdlp->ih_dip, 8388817SKerry.Shu@Sun.COM i_ddi_intr_get_current_nenables(hdlp->ih_dip) + 1); 8398817SKerry.Shu@Sun.COM } 8400Sstevel@tonic-gate 8410Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 8420Sstevel@tonic-gate return (ret); 8430Sstevel@tonic-gate } 8440Sstevel@tonic-gate 8450Sstevel@tonic-gate int 8460Sstevel@tonic-gate ddi_intr_disable(ddi_intr_handle_t h) 8470Sstevel@tonic-gate { 8480Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 8490Sstevel@tonic-gate int ret; 8500Sstevel@tonic-gate 8510Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_disable: hdlp = %p\n", 8520Sstevel@tonic-gate (void *)hdlp)); 8530Sstevel@tonic-gate 8540Sstevel@tonic-gate if (hdlp == NULL) 8550Sstevel@tonic-gate return (DDI_EINVAL); 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 8580Sstevel@tonic-gate if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) || 8590Sstevel@tonic-gate ((hdlp->ih_type == DDI_INTR_TYPE_MSI) && 8600Sstevel@tonic-gate (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) { 8610Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 8620Sstevel@tonic-gate return (DDI_EINVAL); 8630Sstevel@tonic-gate } 8640Sstevel@tonic-gate 8651725Segillett I_DDI_VERIFY_MSIX_HANDLE(hdlp); 8661725Segillett 867693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 8680Sstevel@tonic-gate DDI_INTROP_DISABLE, hdlp, NULL); 8690Sstevel@tonic-gate 8708817SKerry.Shu@Sun.COM if (ret == DDI_SUCCESS) { 8710Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ADDED; 8728817SKerry.Shu@Sun.COM i_ddi_intr_set_current_nenables(hdlp->ih_dip, 8738817SKerry.Shu@Sun.COM i_ddi_intr_get_current_nenables(hdlp->ih_dip) - 1); 8748817SKerry.Shu@Sun.COM } 8750Sstevel@tonic-gate 8760Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 8770Sstevel@tonic-gate return (ret); 8780Sstevel@tonic-gate } 8790Sstevel@tonic-gate 8800Sstevel@tonic-gate int 8810Sstevel@tonic-gate ddi_intr_block_enable(ddi_intr_handle_t *h_array, int count) 8820Sstevel@tonic-gate { 8830Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp; 8840Sstevel@tonic-gate int i, ret; 8850Sstevel@tonic-gate 8860Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_enable: h_array = %p\n", 8870Sstevel@tonic-gate (void *)h_array)); 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate if (h_array == NULL) 8900Sstevel@tonic-gate return (DDI_EINVAL); 8910Sstevel@tonic-gate 8920Sstevel@tonic-gate for (i = 0; i < count; i++) { 8930Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 8940Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 8950Sstevel@tonic-gate 8960Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ADDED || 8970Sstevel@tonic-gate hdlp->ih_type != DDI_INTR_TYPE_MSI || 8980Sstevel@tonic-gate !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) { 8990Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 9000Sstevel@tonic-gate return (DDI_EINVAL); 9010Sstevel@tonic-gate } 9020Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 9030Sstevel@tonic-gate } 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[0]; 9060Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 9070Sstevel@tonic-gate hdlp->ih_scratch1 = count; 9081542Sjohnny hdlp->ih_scratch2 = (void *)h_array; 9090Sstevel@tonic-gate 910693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 9110Sstevel@tonic-gate DDI_INTROP_BLOCKENABLE, hdlp, NULL); 9120Sstevel@tonic-gate 9130Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 9140Sstevel@tonic-gate 9150Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 9160Sstevel@tonic-gate for (i = 0; i < count; i++) { 9170Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 9180Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 9190Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ENABLE; 9200Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 9210Sstevel@tonic-gate } 9228817SKerry.Shu@Sun.COM i_ddi_intr_set_current_nenables(hdlp->ih_dip, 1); 9230Sstevel@tonic-gate } 9240Sstevel@tonic-gate 9250Sstevel@tonic-gate return (ret); 9260Sstevel@tonic-gate } 9270Sstevel@tonic-gate 9280Sstevel@tonic-gate int 9290Sstevel@tonic-gate ddi_intr_block_disable(ddi_intr_handle_t *h_array, int count) 9300Sstevel@tonic-gate { 9310Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp; 9320Sstevel@tonic-gate int i, ret; 9330Sstevel@tonic-gate 9340Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_disable: h_array = %p\n", 9350Sstevel@tonic-gate (void *)h_array)); 9360Sstevel@tonic-gate 9370Sstevel@tonic-gate if (h_array == NULL) 9380Sstevel@tonic-gate return (DDI_EINVAL); 9390Sstevel@tonic-gate 9400Sstevel@tonic-gate for (i = 0; i < count; i++) { 9410Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 9420Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 9430Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ENABLE || 9440Sstevel@tonic-gate hdlp->ih_type != DDI_INTR_TYPE_MSI || 9450Sstevel@tonic-gate !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) { 9460Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 9470Sstevel@tonic-gate return (DDI_EINVAL); 9480Sstevel@tonic-gate } 9490Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 9500Sstevel@tonic-gate } 9510Sstevel@tonic-gate 9520Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[0]; 9530Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 9540Sstevel@tonic-gate hdlp->ih_scratch1 = count; 9551542Sjohnny hdlp->ih_scratch2 = (void *)h_array; 9560Sstevel@tonic-gate 957693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 9580Sstevel@tonic-gate DDI_INTROP_BLOCKDISABLE, hdlp, NULL); 9590Sstevel@tonic-gate 9600Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 9610Sstevel@tonic-gate 9620Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 9630Sstevel@tonic-gate for (i = 0; i < count; i++) { 9640Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 9650Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 9660Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ADDED; 9670Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 9680Sstevel@tonic-gate } 9698817SKerry.Shu@Sun.COM i_ddi_intr_set_current_nenables(hdlp->ih_dip, 0); 9700Sstevel@tonic-gate } 9710Sstevel@tonic-gate 9720Sstevel@tonic-gate return (ret); 9730Sstevel@tonic-gate } 9740Sstevel@tonic-gate 9750Sstevel@tonic-gate /* 9760Sstevel@tonic-gate * Interrupt set/clr mask handlers 9770Sstevel@tonic-gate */ 9780Sstevel@tonic-gate int 9790Sstevel@tonic-gate ddi_intr_set_mask(ddi_intr_handle_t h) 9800Sstevel@tonic-gate { 9810Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 9820Sstevel@tonic-gate int ret; 9830Sstevel@tonic-gate 9840Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_mask: hdlp = %p\n", 9850Sstevel@tonic-gate (void *)hdlp)); 9860Sstevel@tonic-gate 9870Sstevel@tonic-gate if (hdlp == NULL) 9880Sstevel@tonic-gate return (DDI_EINVAL); 9890Sstevel@tonic-gate 9900Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 9911653Sgovinda if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) || 9921653Sgovinda (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE))) { 9930Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 9940Sstevel@tonic-gate return (DDI_EINVAL); 9950Sstevel@tonic-gate } 9960Sstevel@tonic-gate 997693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 9980Sstevel@tonic-gate DDI_INTROP_SETMASK, hdlp, NULL); 9990Sstevel@tonic-gate 10000Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 10010Sstevel@tonic-gate return (ret); 10020Sstevel@tonic-gate } 10030Sstevel@tonic-gate 10040Sstevel@tonic-gate int 10050Sstevel@tonic-gate ddi_intr_clr_mask(ddi_intr_handle_t h) 10060Sstevel@tonic-gate { 10070Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 10080Sstevel@tonic-gate int ret; 10090Sstevel@tonic-gate 10100Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_clr_mask: hdlp = %p\n", 10110Sstevel@tonic-gate (void *)hdlp)); 10120Sstevel@tonic-gate 10130Sstevel@tonic-gate if (hdlp == NULL) 10140Sstevel@tonic-gate return (DDI_EINVAL); 10150Sstevel@tonic-gate 10160Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 10171653Sgovinda if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) || 10181653Sgovinda (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE))) { 10190Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 10200Sstevel@tonic-gate return (DDI_EINVAL); 10210Sstevel@tonic-gate } 10220Sstevel@tonic-gate 1023693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 10240Sstevel@tonic-gate DDI_INTROP_CLRMASK, hdlp, NULL); 10250Sstevel@tonic-gate 10260Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 10270Sstevel@tonic-gate return (ret); 10280Sstevel@tonic-gate } 10290Sstevel@tonic-gate 10300Sstevel@tonic-gate /* 10310Sstevel@tonic-gate * Interrupt get_pending handler 10320Sstevel@tonic-gate */ 10330Sstevel@tonic-gate int 10340Sstevel@tonic-gate ddi_intr_get_pending(ddi_intr_handle_t h, int *pendingp) 10350Sstevel@tonic-gate { 10360Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 10370Sstevel@tonic-gate int ret; 10380Sstevel@tonic-gate 10390Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pending: hdlp = %p\n", 10400Sstevel@tonic-gate (void *)hdlp)); 10410Sstevel@tonic-gate 10420Sstevel@tonic-gate if (hdlp == NULL) 10430Sstevel@tonic-gate return (DDI_EINVAL); 10440Sstevel@tonic-gate 10450Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 10460Sstevel@tonic-gate if (!(hdlp->ih_cap & DDI_INTR_FLAG_PENDING)) { 10470Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 10480Sstevel@tonic-gate return (DDI_EINVAL); 10490Sstevel@tonic-gate } 10500Sstevel@tonic-gate 1051693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 10520Sstevel@tonic-gate DDI_INTROP_GETPENDING, hdlp, (void *)pendingp); 10530Sstevel@tonic-gate 10540Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 10550Sstevel@tonic-gate return (ret); 10560Sstevel@tonic-gate } 10570Sstevel@tonic-gate 10580Sstevel@tonic-gate /* 105910053SEvan.Yan@Sun.COM * Set the number of interrupts requested from IRM 106010053SEvan.Yan@Sun.COM */ 106110053SEvan.Yan@Sun.COM int 106210053SEvan.Yan@Sun.COM ddi_intr_set_nreq(dev_info_t *dip, int nreq) 106310053SEvan.Yan@Sun.COM { 1064*12473SScott.Carter@Oracle.COM int curr_type, nintrs; 1065*12473SScott.Carter@Oracle.COM 106610053SEvan.Yan@Sun.COM DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_nreq: dip %p, nreq %d\n", 106710053SEvan.Yan@Sun.COM (void *)dip, nreq)); 106810053SEvan.Yan@Sun.COM 1069*12473SScott.Carter@Oracle.COM ASSERT(dip != NULL); 1070*12473SScott.Carter@Oracle.COM ASSERT(nreq > 0); 1071*12473SScott.Carter@Oracle.COM 1072*12473SScott.Carter@Oracle.COM /* Sanity check inputs */ 1073*12473SScott.Carter@Oracle.COM if ((dip == NULL) || (nreq < 1)) 1074*12473SScott.Carter@Oracle.COM return (DDI_EINVAL); 1075*12473SScott.Carter@Oracle.COM 1076*12473SScott.Carter@Oracle.COM curr_type = i_ddi_intr_get_current_type(dip); 1077*12473SScott.Carter@Oracle.COM 1078*12473SScott.Carter@Oracle.COM /* Only valid for IRM drivers actively using interrupts */ 1079*12473SScott.Carter@Oracle.COM if ((curr_type == 0) || 1080*12473SScott.Carter@Oracle.COM (i_ddi_irm_supported(dip, curr_type) != DDI_SUCCESS)) 1081*12473SScott.Carter@Oracle.COM return (DDI_ENOTSUP); 1082*12473SScott.Carter@Oracle.COM 1083*12473SScott.Carter@Oracle.COM /* Range check */ 1084*12473SScott.Carter@Oracle.COM if (ddi_intr_get_nintrs(dip, curr_type, &nintrs) != DDI_SUCCESS) 1085*12473SScott.Carter@Oracle.COM return (DDI_FAILURE); 1086*12473SScott.Carter@Oracle.COM if (nreq > nintrs) 108710053SEvan.Yan@Sun.COM return (DDI_EINVAL); 108810053SEvan.Yan@Sun.COM 108910053SEvan.Yan@Sun.COM return (i_ddi_irm_modify(dip, nreq)); 109010053SEvan.Yan@Sun.COM } 109110053SEvan.Yan@Sun.COM 109210053SEvan.Yan@Sun.COM /* 10930Sstevel@tonic-gate * Soft interrupt handlers 10940Sstevel@tonic-gate */ 10950Sstevel@tonic-gate /* 10960Sstevel@tonic-gate * Add a soft interrupt and register its handler 10970Sstevel@tonic-gate */ 10980Sstevel@tonic-gate /* ARGSUSED */ 10990Sstevel@tonic-gate int 11000Sstevel@tonic-gate ddi_intr_add_softint(dev_info_t *dip, ddi_softint_handle_t *h_p, int soft_pri, 11010Sstevel@tonic-gate ddi_intr_handler_t handler, void *arg1) 11020Sstevel@tonic-gate { 11030Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp; 11040Sstevel@tonic-gate int ret; 11050Sstevel@tonic-gate 11060Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: dip = %p, " 11070Sstevel@tonic-gate "softpri = 0x%x\n", (void *)dip, soft_pri)); 11080Sstevel@tonic-gate 11090Sstevel@tonic-gate if ((dip == NULL) || (h_p == NULL) || (handler == NULL)) { 11100Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: " 11110Sstevel@tonic-gate "invalid arguments")); 11120Sstevel@tonic-gate 11130Sstevel@tonic-gate return (DDI_EINVAL); 11140Sstevel@tonic-gate } 11150Sstevel@tonic-gate 11160Sstevel@tonic-gate /* Validate input arguments */ 11170Sstevel@tonic-gate if (soft_pri < DDI_INTR_SOFTPRI_MIN || 11180Sstevel@tonic-gate soft_pri > DDI_INTR_SOFTPRI_MAX) { 11190Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: invalid " 11200Sstevel@tonic-gate "soft_pri input given = %x\n", soft_pri)); 11210Sstevel@tonic-gate return (DDI_EINVAL); 11220Sstevel@tonic-gate } 11230Sstevel@tonic-gate 11240Sstevel@tonic-gate hdlp = (ddi_softint_hdl_impl_t *)kmem_zalloc( 11250Sstevel@tonic-gate sizeof (ddi_softint_hdl_impl_t), KM_SLEEP); 11260Sstevel@tonic-gate 11270Sstevel@tonic-gate /* fill up internally */ 11280Sstevel@tonic-gate rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL); 11290Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 11300Sstevel@tonic-gate hdlp->ih_pri = soft_pri; 11310Sstevel@tonic-gate hdlp->ih_dip = dip; 11320Sstevel@tonic-gate hdlp->ih_cb_func = handler; 11330Sstevel@tonic-gate hdlp->ih_cb_arg1 = arg1; 11340Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: hdlp = %p\n", 11350Sstevel@tonic-gate (void *)hdlp)); 11360Sstevel@tonic-gate 11370Sstevel@tonic-gate /* do the platform specific calls */ 11380Sstevel@tonic-gate if ((ret = i_ddi_add_softint(hdlp)) != DDI_SUCCESS) { 11390Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 11400Sstevel@tonic-gate rw_destroy(&hdlp->ih_rwlock); 11410Sstevel@tonic-gate kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t)); 11420Sstevel@tonic-gate return (ret); 11430Sstevel@tonic-gate } 11440Sstevel@tonic-gate 11450Sstevel@tonic-gate *h_p = (ddi_softint_handle_t)hdlp; 11460Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 11470Sstevel@tonic-gate return (ret); 11480Sstevel@tonic-gate } 11490Sstevel@tonic-gate 11500Sstevel@tonic-gate /* 11510Sstevel@tonic-gate * Remove the soft interrupt 11520Sstevel@tonic-gate */ 11530Sstevel@tonic-gate int 11540Sstevel@tonic-gate ddi_intr_remove_softint(ddi_softint_handle_t h) 11550Sstevel@tonic-gate { 11560Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h; 11570Sstevel@tonic-gate 11580Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_softint: hdlp = %p\n", 11590Sstevel@tonic-gate (void *)hdlp)); 11600Sstevel@tonic-gate 11610Sstevel@tonic-gate if (hdlp == NULL) 11620Sstevel@tonic-gate return (DDI_EINVAL); 11630Sstevel@tonic-gate 11640Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 11650Sstevel@tonic-gate i_ddi_remove_softint(hdlp); 11660Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 11670Sstevel@tonic-gate rw_destroy(&hdlp->ih_rwlock); 11680Sstevel@tonic-gate 11690Sstevel@tonic-gate /* kmem_free the hdl impl_t structure allocated earlier */ 11700Sstevel@tonic-gate kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t)); 11710Sstevel@tonic-gate return (DDI_SUCCESS); 11720Sstevel@tonic-gate } 11730Sstevel@tonic-gate 11740Sstevel@tonic-gate /* 11750Sstevel@tonic-gate * Trigger a soft interrupt 11760Sstevel@tonic-gate */ 11770Sstevel@tonic-gate int 11780Sstevel@tonic-gate ddi_intr_trigger_softint(ddi_softint_handle_t h, void *arg2) 11790Sstevel@tonic-gate { 11800Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h; 11810Sstevel@tonic-gate int ret; 11820Sstevel@tonic-gate 11830Sstevel@tonic-gate if (hdlp == NULL) 11840Sstevel@tonic-gate return (DDI_EINVAL); 11850Sstevel@tonic-gate 1186278Sgovinda if ((ret = i_ddi_trigger_softint(hdlp, arg2)) != DDI_SUCCESS) { 11870Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_trigger_softint: failed, " 11880Sstevel@tonic-gate " ret 0%x\n", ret)); 1189278Sgovinda 1190278Sgovinda return (ret); 11910Sstevel@tonic-gate } 11920Sstevel@tonic-gate 1193278Sgovinda hdlp->ih_cb_arg2 = arg2; 1194278Sgovinda return (DDI_SUCCESS); 11950Sstevel@tonic-gate } 11960Sstevel@tonic-gate 11970Sstevel@tonic-gate /* 11980Sstevel@tonic-gate * Get the soft interrupt priority 11990Sstevel@tonic-gate */ 12000Sstevel@tonic-gate int 12010Sstevel@tonic-gate ddi_intr_get_softint_pri(ddi_softint_handle_t h, uint_t *soft_prip) 12020Sstevel@tonic-gate { 12030Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h; 12040Sstevel@tonic-gate 12050Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_softint_pri: h = %p\n", 12060Sstevel@tonic-gate (void *)h)); 12070Sstevel@tonic-gate 12080Sstevel@tonic-gate if (hdlp == NULL) 12090Sstevel@tonic-gate return (DDI_EINVAL); 12100Sstevel@tonic-gate 12110Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 12120Sstevel@tonic-gate *soft_prip = hdlp->ih_pri; 12130Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 12140Sstevel@tonic-gate return (DDI_SUCCESS); 12150Sstevel@tonic-gate } 12160Sstevel@tonic-gate 12170Sstevel@tonic-gate /* 12180Sstevel@tonic-gate * Set the soft interrupt priority 12190Sstevel@tonic-gate */ 12200Sstevel@tonic-gate int 12210Sstevel@tonic-gate ddi_intr_set_softint_pri(ddi_softint_handle_t h, uint_t soft_pri) 12220Sstevel@tonic-gate { 12230Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h; 12240Sstevel@tonic-gate int ret; 12250Sstevel@tonic-gate uint_t orig_soft_pri; 12260Sstevel@tonic-gate 12270Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: h = %p\n", 12280Sstevel@tonic-gate (void *)h)); 12290Sstevel@tonic-gate 12300Sstevel@tonic-gate if (hdlp == NULL) 12310Sstevel@tonic-gate return (DDI_EINVAL); 12320Sstevel@tonic-gate 12330Sstevel@tonic-gate /* Validate priority argument */ 12340Sstevel@tonic-gate if (soft_pri < DDI_INTR_SOFTPRI_MIN || 12350Sstevel@tonic-gate soft_pri > DDI_INTR_SOFTPRI_MAX) { 12360Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: invalid " 12370Sstevel@tonic-gate "soft_pri input given = %x\n", soft_pri)); 12380Sstevel@tonic-gate return (DDI_EINVAL); 12390Sstevel@tonic-gate } 12400Sstevel@tonic-gate 12410Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 12420Sstevel@tonic-gate orig_soft_pri = hdlp->ih_pri; 12430Sstevel@tonic-gate hdlp->ih_pri = soft_pri; 12440Sstevel@tonic-gate 12450Sstevel@tonic-gate if ((ret = i_ddi_set_softint_pri(hdlp, orig_soft_pri)) != DDI_SUCCESS) { 12460Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: failed, " 12470Sstevel@tonic-gate " ret 0%x\n", ret)); 12480Sstevel@tonic-gate hdlp->ih_pri = orig_soft_pri; 12490Sstevel@tonic-gate } 12500Sstevel@tonic-gate 12510Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 12520Sstevel@tonic-gate return (ret); 12530Sstevel@tonic-gate } 12540Sstevel@tonic-gate 12550Sstevel@tonic-gate /* 12560Sstevel@tonic-gate * Old DDI interrupt framework 1257693Sgovinda * 1258693Sgovinda * The following DDI interrupt interfaces are obsolete. 1259693Sgovinda * Use the above new DDI interrupt interfaces instead. 12600Sstevel@tonic-gate */ 12610Sstevel@tonic-gate 12620Sstevel@tonic-gate int 12630Sstevel@tonic-gate ddi_intr_hilevel(dev_info_t *dip, uint_t inumber) 12640Sstevel@tonic-gate { 12658561SScott.Carter@Sun.COM ddi_intr_handle_t hdl; 12668561SScott.Carter@Sun.COM ddi_intr_handle_t *hdl_p; 12678561SScott.Carter@Sun.COM size_t hdl_sz = 0; 12680Sstevel@tonic-gate int actual, ret; 12690Sstevel@tonic-gate uint_t high_pri, pri; 12700Sstevel@tonic-gate 12710Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: name=%s%d dip=0x%p " 12720Sstevel@tonic-gate "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 12730Sstevel@tonic-gate (void *)dip, inumber)); 12740Sstevel@tonic-gate 12750Sstevel@tonic-gate /* 12760Sstevel@tonic-gate * The device driver may have already registed with the 12770Sstevel@tonic-gate * framework. If so, first try to get the existing interrupt handle 12780Sstevel@tonic-gate * for that given inumber and use that handle. 12790Sstevel@tonic-gate */ 12808561SScott.Carter@Sun.COM if ((hdl = i_ddi_get_intr_handle(dip, inumber)) == NULL) { 12818561SScott.Carter@Sun.COM hdl_sz = sizeof (ddi_intr_handle_t) * (inumber + 1); 12828561SScott.Carter@Sun.COM hdl_p = kmem_zalloc(hdl_sz, KM_SLEEP); 12838561SScott.Carter@Sun.COM if ((ret = ddi_intr_alloc(dip, hdl_p, DDI_INTR_TYPE_FIXED, 1284965Sgovinda inumber, 1, &actual, 1285965Sgovinda DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) { 12860Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: " 12870Sstevel@tonic-gate "ddi_intr_alloc failed, ret 0x%x\n", ret)); 12888561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz); 12890Sstevel@tonic-gate return (0); 12900Sstevel@tonic-gate } 12918561SScott.Carter@Sun.COM hdl = hdl_p[inumber]; 12920Sstevel@tonic-gate } 12930Sstevel@tonic-gate 12940Sstevel@tonic-gate if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) { 12950Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: " 12960Sstevel@tonic-gate "ddi_intr_get_pri failed, ret 0x%x\n", ret)); 12970Sstevel@tonic-gate (void) ddi_intr_free(hdl); 12988561SScott.Carter@Sun.COM if (hdl_sz) 12998561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz); 13000Sstevel@tonic-gate return (0); 13010Sstevel@tonic-gate } 13020Sstevel@tonic-gate 13030Sstevel@tonic-gate high_pri = ddi_intr_get_hilevel_pri(); 13040Sstevel@tonic-gate 13050Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: pri = %x, " 13060Sstevel@tonic-gate "high_pri = %x\n", pri, high_pri)); 13070Sstevel@tonic-gate 13080Sstevel@tonic-gate /* Free the handle allocated here only if no existing handle exists */ 13098561SScott.Carter@Sun.COM if (hdl_sz) { 13100Sstevel@tonic-gate (void) ddi_intr_free(hdl); 13118561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz); 13128561SScott.Carter@Sun.COM } 13130Sstevel@tonic-gate 13140Sstevel@tonic-gate return (pri >= high_pri); 13150Sstevel@tonic-gate } 13160Sstevel@tonic-gate 13170Sstevel@tonic-gate int 13180Sstevel@tonic-gate ddi_dev_nintrs(dev_info_t *dip, int *result) 13190Sstevel@tonic-gate { 13200Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: name=%s%d dip=0x%p\n", 13210Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), (void *)dip)); 13220Sstevel@tonic-gate 13230Sstevel@tonic-gate if (ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED, 13240Sstevel@tonic-gate result) != DDI_SUCCESS) { 13250Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: " 13260Sstevel@tonic-gate "ddi_intr_get_nintrs failed\n")); 13270Sstevel@tonic-gate *result = 0; 13280Sstevel@tonic-gate } 13290Sstevel@tonic-gate 13300Sstevel@tonic-gate return (DDI_SUCCESS); 13310Sstevel@tonic-gate } 13320Sstevel@tonic-gate 13330Sstevel@tonic-gate int 13340Sstevel@tonic-gate ddi_get_iblock_cookie(dev_info_t *dip, uint_t inumber, 13350Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep) 13360Sstevel@tonic-gate { 13378561SScott.Carter@Sun.COM ddi_intr_handle_t hdl; 13388561SScott.Carter@Sun.COM ddi_intr_handle_t *hdl_p; 13398561SScott.Carter@Sun.COM size_t hdl_sz = 0; 13400Sstevel@tonic-gate int actual, ret; 13410Sstevel@tonic-gate uint_t pri; 13420Sstevel@tonic-gate 13430Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: name=%s%d dip=0x%p " 13440Sstevel@tonic-gate "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 13450Sstevel@tonic-gate (void *)dip, inumber)); 13460Sstevel@tonic-gate 13470Sstevel@tonic-gate ASSERT(iblock_cookiep != NULL); 13480Sstevel@tonic-gate 13490Sstevel@tonic-gate /* 13500Sstevel@tonic-gate * The device driver may have already registed with the 13510Sstevel@tonic-gate * framework. If so, first try to get the existing interrupt handle 13520Sstevel@tonic-gate * for that given inumber and use that handle. 13530Sstevel@tonic-gate */ 13548561SScott.Carter@Sun.COM if ((hdl = i_ddi_get_intr_handle(dip, inumber)) == NULL) { 13558561SScott.Carter@Sun.COM hdl_sz = sizeof (ddi_intr_handle_t) * (inumber + 1); 13568561SScott.Carter@Sun.COM hdl_p = kmem_zalloc(hdl_sz, KM_SLEEP); 13578561SScott.Carter@Sun.COM if ((ret = ddi_intr_alloc(dip, hdl_p, 13588561SScott.Carter@Sun.COM DDI_INTR_TYPE_FIXED, inumber, 1, &actual, 1359965Sgovinda DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) { 13600Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: " 13610Sstevel@tonic-gate "ddi_intr_alloc failed, ret 0x%x\n", ret)); 13628561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz); 13630Sstevel@tonic-gate return (DDI_INTR_NOTFOUND); 13640Sstevel@tonic-gate } 13658561SScott.Carter@Sun.COM hdl = hdl_p[inumber]; 13660Sstevel@tonic-gate } 13670Sstevel@tonic-gate 13680Sstevel@tonic-gate if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) { 13690Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: " 13700Sstevel@tonic-gate "ddi_intr_get_pri failed, ret 0x%x\n", ret)); 13710Sstevel@tonic-gate (void) ddi_intr_free(hdl); 13728561SScott.Carter@Sun.COM if (hdl_sz) 13738561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz); 13740Sstevel@tonic-gate return (DDI_FAILURE); 13750Sstevel@tonic-gate } 13760Sstevel@tonic-gate 137742Sagiri *iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)pri; 13780Sstevel@tonic-gate /* Free the handle allocated here only if no existing handle exists */ 13798561SScott.Carter@Sun.COM if (hdl_sz) { 13800Sstevel@tonic-gate (void) ddi_intr_free(hdl); 13818561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz); 13828561SScott.Carter@Sun.COM } 13830Sstevel@tonic-gate 13840Sstevel@tonic-gate return (DDI_SUCCESS); 13850Sstevel@tonic-gate } 13860Sstevel@tonic-gate 13870Sstevel@tonic-gate int 13880Sstevel@tonic-gate ddi_add_intr(dev_info_t *dip, uint_t inumber, 13890Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep, 13900Sstevel@tonic-gate ddi_idevice_cookie_t *idevice_cookiep, 13910Sstevel@tonic-gate uint_t (*int_handler)(caddr_t int_handler_arg), 13920Sstevel@tonic-gate caddr_t int_handler_arg) 13930Sstevel@tonic-gate { 13940Sstevel@tonic-gate ddi_intr_handle_t *hdl_p; 13958561SScott.Carter@Sun.COM size_t hdl_sz; 13960Sstevel@tonic-gate int actual, ret; 13970Sstevel@tonic-gate uint_t pri; 13980Sstevel@tonic-gate 13990Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: name=%s%d dip=0x%p " 14000Sstevel@tonic-gate "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 14010Sstevel@tonic-gate (void *)dip, inumber)); 14020Sstevel@tonic-gate 14038561SScott.Carter@Sun.COM hdl_sz = sizeof (ddi_intr_handle_t) * (inumber + 1); 14048561SScott.Carter@Sun.COM hdl_p = kmem_zalloc(hdl_sz, KM_SLEEP); 14050Sstevel@tonic-gate 14060Sstevel@tonic-gate if ((ret = ddi_intr_alloc(dip, hdl_p, DDI_INTR_TYPE_FIXED, 1407965Sgovinda inumber, 1, &actual, DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) { 14080Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: " 14090Sstevel@tonic-gate "ddi_intr_alloc failed, ret 0x%x\n", ret)); 14108561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz); 14110Sstevel@tonic-gate return (DDI_INTR_NOTFOUND); 14120Sstevel@tonic-gate } 14130Sstevel@tonic-gate 14148561SScott.Carter@Sun.COM if ((ret = ddi_intr_get_pri(hdl_p[inumber], &pri)) != DDI_SUCCESS) { 14150Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: " 14160Sstevel@tonic-gate "ddi_intr_get_pri failed, ret 0x%x\n", ret)); 14178561SScott.Carter@Sun.COM (void) ddi_intr_free(hdl_p[inumber]); 14188561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz); 14190Sstevel@tonic-gate return (DDI_FAILURE); 14200Sstevel@tonic-gate } 14210Sstevel@tonic-gate 14228561SScott.Carter@Sun.COM if ((ret = ddi_intr_add_handler(hdl_p[inumber], (ddi_intr_handler_t *) 14230Sstevel@tonic-gate int_handler, int_handler_arg, NULL)) != DDI_SUCCESS) { 14240Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: " 14250Sstevel@tonic-gate "ddi_intr_add_handler failed, ret 0x%x\n", ret)); 14268561SScott.Carter@Sun.COM (void) ddi_intr_free(hdl_p[inumber]); 14278561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz); 14280Sstevel@tonic-gate return (DDI_FAILURE); 14290Sstevel@tonic-gate } 14300Sstevel@tonic-gate 14318561SScott.Carter@Sun.COM if ((ret = ddi_intr_enable(hdl_p[inumber])) != DDI_SUCCESS) { 14320Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: " 14330Sstevel@tonic-gate "ddi_intr_enable failed, ret 0x%x\n", ret)); 14348561SScott.Carter@Sun.COM (void) ddi_intr_remove_handler(hdl_p[inumber]); 14358561SScott.Carter@Sun.COM (void) ddi_intr_free(hdl_p[inumber]); 14368561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz); 14370Sstevel@tonic-gate return (DDI_FAILURE); 14380Sstevel@tonic-gate } 14390Sstevel@tonic-gate 14400Sstevel@tonic-gate if (iblock_cookiep) 144142Sagiri *iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)pri; 14420Sstevel@tonic-gate 14430Sstevel@tonic-gate if (idevice_cookiep) { 14440Sstevel@tonic-gate idevice_cookiep->idev_vector = 0; 14450Sstevel@tonic-gate idevice_cookiep->idev_priority = pri; 14460Sstevel@tonic-gate } 14470Sstevel@tonic-gate 14488561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz); 14498561SScott.Carter@Sun.COM 14500Sstevel@tonic-gate return (DDI_SUCCESS); 14510Sstevel@tonic-gate } 14520Sstevel@tonic-gate 14530Sstevel@tonic-gate /* ARGSUSED */ 14540Sstevel@tonic-gate int 14550Sstevel@tonic-gate ddi_add_fastintr(dev_info_t *dip, uint_t inumber, 14560Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep, 14570Sstevel@tonic-gate ddi_idevice_cookie_t *idevice_cookiep, 14580Sstevel@tonic-gate uint_t (*hi_int_handler)(void)) 14590Sstevel@tonic-gate { 14600Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_fastintr: name=%s%d dip=0x%p " 14610Sstevel@tonic-gate "inum=0x%x: Not supported, return failure\n", ddi_driver_name(dip), 14620Sstevel@tonic-gate ddi_get_instance(dip), (void *)dip, inumber)); 14630Sstevel@tonic-gate 14640Sstevel@tonic-gate return (DDI_FAILURE); 14650Sstevel@tonic-gate } 14660Sstevel@tonic-gate 14670Sstevel@tonic-gate /* ARGSUSED */ 14680Sstevel@tonic-gate void 14690Sstevel@tonic-gate ddi_remove_intr(dev_info_t *dip, uint_t inum, ddi_iblock_cookie_t iblock_cookie) 14700Sstevel@tonic-gate { 14718561SScott.Carter@Sun.COM ddi_intr_handle_t hdl; 14720Sstevel@tonic-gate int ret; 14730Sstevel@tonic-gate 14740Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: name=%s%d dip=0x%p " 14750Sstevel@tonic-gate "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 14760Sstevel@tonic-gate (void *)dip, inum)); 14770Sstevel@tonic-gate 14788561SScott.Carter@Sun.COM if ((hdl = i_ddi_get_intr_handle(dip, inum)) == NULL) { 14790Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: no handle " 14800Sstevel@tonic-gate "found\n")); 14810Sstevel@tonic-gate return; 14820Sstevel@tonic-gate } 14830Sstevel@tonic-gate 14848561SScott.Carter@Sun.COM if ((ret = ddi_intr_disable(hdl)) != DDI_SUCCESS) { 14850Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: " 14860Sstevel@tonic-gate "ddi_intr_disable failed, ret 0x%x\n", ret)); 14870Sstevel@tonic-gate return; 14880Sstevel@tonic-gate } 14890Sstevel@tonic-gate 14908561SScott.Carter@Sun.COM if ((ret = ddi_intr_remove_handler(hdl)) != DDI_SUCCESS) { 14910Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: " 14920Sstevel@tonic-gate "ddi_intr_remove_handler failed, ret 0x%x\n", ret)); 14930Sstevel@tonic-gate return; 14940Sstevel@tonic-gate } 14950Sstevel@tonic-gate 14968561SScott.Carter@Sun.COM if ((ret = ddi_intr_free(hdl)) != DDI_SUCCESS) { 14970Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: " 14980Sstevel@tonic-gate "ddi_intr_free failed, ret 0x%x\n", ret)); 14990Sstevel@tonic-gate return; 15000Sstevel@tonic-gate } 15010Sstevel@tonic-gate } 15020Sstevel@tonic-gate 15030Sstevel@tonic-gate /* ARGSUSED */ 15040Sstevel@tonic-gate int 15050Sstevel@tonic-gate ddi_get_soft_iblock_cookie(dev_info_t *dip, int preference, 15060Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep) 15070Sstevel@tonic-gate { 15080Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_get_soft_iblock_cookie: name=%s%d " 15090Sstevel@tonic-gate "dip=0x%p pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 15100Sstevel@tonic-gate (void *)dip, preference)); 15110Sstevel@tonic-gate 15120Sstevel@tonic-gate ASSERT(iblock_cookiep != NULL); 15130Sstevel@tonic-gate 15140Sstevel@tonic-gate if (preference == DDI_SOFTINT_FIXED) 15150Sstevel@tonic-gate return (DDI_FAILURE); 15160Sstevel@tonic-gate 151742Sagiri *iblock_cookiep = (ddi_iblock_cookie_t)((uintptr_t) 15180Sstevel@tonic-gate ((preference > DDI_SOFTINT_MED) ? DDI_SOFT_INTR_PRI_H : 15190Sstevel@tonic-gate DDI_SOFT_INTR_PRI_M)); 15200Sstevel@tonic-gate 15210Sstevel@tonic-gate return (DDI_SUCCESS); 15220Sstevel@tonic-gate } 15230Sstevel@tonic-gate 15240Sstevel@tonic-gate int 15250Sstevel@tonic-gate ddi_add_softintr(dev_info_t *dip, int preference, ddi_softintr_t *idp, 15260Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep, 15270Sstevel@tonic-gate ddi_idevice_cookie_t *idevice_cookiep, 15280Sstevel@tonic-gate uint_t (*int_handler)(caddr_t int_handler_arg), 15290Sstevel@tonic-gate caddr_t int_handler_arg) 15300Sstevel@tonic-gate { 15310Sstevel@tonic-gate ddi_softint_handle_t *hdl_p; 15320Sstevel@tonic-gate uint64_t softpri; 15330Sstevel@tonic-gate int ret; 15340Sstevel@tonic-gate 15350Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: name=%s%d dip=0x%p " 15360Sstevel@tonic-gate "pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 15370Sstevel@tonic-gate (void *)dip, preference)); 15380Sstevel@tonic-gate 15390Sstevel@tonic-gate if ((idp == NULL) || ((preference == DDI_SOFTINT_FIXED) && 15400Sstevel@tonic-gate (iblock_cookiep == NULL))) 15410Sstevel@tonic-gate return (DDI_FAILURE); 15420Sstevel@tonic-gate 15430Sstevel@tonic-gate /* Translate the priority preference */ 15440Sstevel@tonic-gate if (preference == DDI_SOFTINT_FIXED) { 1545190Seota softpri = (uint64_t)(uintptr_t)*iblock_cookiep; 15460Sstevel@tonic-gate softpri = MIN(softpri, DDI_SOFT_INTR_PRI_H); 15470Sstevel@tonic-gate } else { 15480Sstevel@tonic-gate softpri = (uint64_t)((preference > DDI_SOFTINT_MED) ? 15490Sstevel@tonic-gate DDI_SOFT_INTR_PRI_H : DDI_SOFT_INTR_PRI_M); 15500Sstevel@tonic-gate } 15510Sstevel@tonic-gate 15520Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: preference 0x%x " 15530Sstevel@tonic-gate "softpri 0x%lx\n", preference, (long)softpri)); 15540Sstevel@tonic-gate 15550Sstevel@tonic-gate hdl_p = kmem_zalloc(sizeof (ddi_softint_handle_t), KM_SLEEP); 15560Sstevel@tonic-gate if ((ret = ddi_intr_add_softint(dip, hdl_p, softpri, 15570Sstevel@tonic-gate (ddi_intr_handler_t *)int_handler, int_handler_arg)) != 15580Sstevel@tonic-gate DDI_SUCCESS) { 15590Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: " 15600Sstevel@tonic-gate "ddi_intr_add_softint failed, ret 0x%x\n", ret)); 15610Sstevel@tonic-gate 15620Sstevel@tonic-gate kmem_free(hdl_p, sizeof (ddi_softint_handle_t)); 15630Sstevel@tonic-gate return (DDI_FAILURE); 15640Sstevel@tonic-gate } 15650Sstevel@tonic-gate 15660Sstevel@tonic-gate if (iblock_cookiep) 1567190Seota *iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)softpri; 15680Sstevel@tonic-gate 15690Sstevel@tonic-gate if (idevice_cookiep) { 15700Sstevel@tonic-gate idevice_cookiep->idev_vector = 0; 15710Sstevel@tonic-gate idevice_cookiep->idev_priority = softpri; 15720Sstevel@tonic-gate } 15730Sstevel@tonic-gate 15740Sstevel@tonic-gate *idp = (ddi_softintr_t)hdl_p; 15750Sstevel@tonic-gate 15760Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: dip = 0x%p, " 15770Sstevel@tonic-gate "idp = 0x%p, ret = %x\n", (void *)dip, (void *)*idp, ret)); 15780Sstevel@tonic-gate 15790Sstevel@tonic-gate return (DDI_SUCCESS); 15800Sstevel@tonic-gate } 15810Sstevel@tonic-gate 15820Sstevel@tonic-gate void 15830Sstevel@tonic-gate ddi_remove_softintr(ddi_softintr_t id) 15840Sstevel@tonic-gate { 15850Sstevel@tonic-gate ddi_softint_handle_t *h_p = (ddi_softint_handle_t *)id; 15860Sstevel@tonic-gate 15870Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: id=0x%p\n", 15880Sstevel@tonic-gate (void *)id)); 15890Sstevel@tonic-gate 15900Sstevel@tonic-gate if (h_p == NULL) 15910Sstevel@tonic-gate return; 15920Sstevel@tonic-gate 15930Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: handle 0x%p\n", 15940Sstevel@tonic-gate (void *)h_p)); 15950Sstevel@tonic-gate 15960Sstevel@tonic-gate (void) ddi_intr_remove_softint(*h_p); 15970Sstevel@tonic-gate kmem_free(h_p, sizeof (ddi_softint_handle_t)); 15980Sstevel@tonic-gate } 15990Sstevel@tonic-gate 16000Sstevel@tonic-gate void 16010Sstevel@tonic-gate ddi_trigger_softintr(ddi_softintr_t id) 16020Sstevel@tonic-gate { 16030Sstevel@tonic-gate ddi_softint_handle_t *h_p = (ddi_softint_handle_t *)id; 16040Sstevel@tonic-gate int ret; 16050Sstevel@tonic-gate 16060Sstevel@tonic-gate if (h_p == NULL) 16070Sstevel@tonic-gate return; 16080Sstevel@tonic-gate 16090Sstevel@tonic-gate if ((ret = ddi_intr_trigger_softint(*h_p, NULL)) != DDI_SUCCESS) { 16100Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_trigger_softintr: " 16110Sstevel@tonic-gate "ddi_intr_trigger_softint failed, hdlp 0x%p " 16120Sstevel@tonic-gate "ret 0x%x\n", (void *)h_p, ret)); 16130Sstevel@tonic-gate } 16140Sstevel@tonic-gate } 1615