17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/note.h> 307c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 317c478bd9Sstevel@tonic-gate #include <sys/types.h> 327c478bd9Sstevel@tonic-gate #include <sys/param.h> 337c478bd9Sstevel@tonic-gate #include <sys/systm.h> 347c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 357c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 367c478bd9Sstevel@tonic-gate #include <sys/debug.h> 377c478bd9Sstevel@tonic-gate #include <sys/avintr.h> 387c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 397c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 407c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h> /* include prototypes */ 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate /* 437c478bd9Sstevel@tonic-gate * New DDI interrupt framework 447c478bd9Sstevel@tonic-gate */ 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate /* 477c478bd9Sstevel@tonic-gate * MSI/X allocation limit. 487c478bd9Sstevel@tonic-gate * This limit will change with Resource Management support. 497c478bd9Sstevel@tonic-gate */ 507c478bd9Sstevel@tonic-gate uint_t ddi_msix_alloc_limit = 2; 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate /* 537c478bd9Sstevel@tonic-gate * ddi_intr_get_supported_types: 547c478bd9Sstevel@tonic-gate * Return, as a bit mask, the hardware interrupt types supported by 557c478bd9Sstevel@tonic-gate * both the device and by the host in the integer pointed 567c478bd9Sstevel@tonic-gate * to be the 'typesp' argument. 577c478bd9Sstevel@tonic-gate */ 587c478bd9Sstevel@tonic-gate int 597c478bd9Sstevel@tonic-gate ddi_intr_get_supported_types(dev_info_t *dip, int *typesp) 607c478bd9Sstevel@tonic-gate { 617c478bd9Sstevel@tonic-gate int ret; 627c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t hdl; 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate if (dip == NULL) 657c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: dip %p\n", 687c478bd9Sstevel@tonic-gate (void *)dip)); 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate if (*typesp = i_ddi_intr_get_supported_types(dip)) 717c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate bzero(&hdl, sizeof (ddi_intr_handle_impl_t)); 747c478bd9Sstevel@tonic-gate hdl.ih_dip = dip; 757c478bd9Sstevel@tonic-gate 76*a195726fSgovinda ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_SUPPORTED_TYPES, &hdl, 777c478bd9Sstevel@tonic-gate (void *)typesp); 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) 807c478bd9Sstevel@tonic-gate return (DDI_INTR_NOTFOUND); 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: types %x\n", 837c478bd9Sstevel@tonic-gate *typesp)); 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate return (ret); 867c478bd9Sstevel@tonic-gate } 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate /* 907c478bd9Sstevel@tonic-gate * ddi_intr_get_nintrs: 917c478bd9Sstevel@tonic-gate * Return as an integer in the integer pointed to by the argument 927c478bd9Sstevel@tonic-gate * *nintrsp*, the number of interrupts the device supports for the 937c478bd9Sstevel@tonic-gate * given interrupt type. 947c478bd9Sstevel@tonic-gate */ 957c478bd9Sstevel@tonic-gate int 967c478bd9Sstevel@tonic-gate ddi_intr_get_nintrs(dev_info_t *dip, int type, int *nintrsp) 977c478bd9Sstevel@tonic-gate { 987c478bd9Sstevel@tonic-gate int ret; 997c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t hdl; 1007c478bd9Sstevel@tonic-gate 101*a195726fSgovinda DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs: dip %p, type: %d\n", 102*a195726fSgovinda (void *)dip, type)); 1037c478bd9Sstevel@tonic-gate 104*a195726fSgovinda if ((dip == NULL) || (type & ~(DDI_INTR_SUP_TYPES))) { 105*a195726fSgovinda *nintrsp = 0; 1067c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 107*a195726fSgovinda } 108*a195726fSgovinda 109*a195726fSgovinda if (!(i_ddi_intr_get_supported_types(dip) & type)) { 110*a195726fSgovinda *nintrsp = 0; 111*a195726fSgovinda return (DDI_EINVAL); 112*a195726fSgovinda } 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate if (*nintrsp = i_ddi_intr_get_supported_nintrs(dip, type)) 1157c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate bzero(&hdl, sizeof (ddi_intr_handle_impl_t)); 1187c478bd9Sstevel@tonic-gate hdl.ih_dip = dip; 1197c478bd9Sstevel@tonic-gate hdl.ih_type = type; 1207c478bd9Sstevel@tonic-gate 121*a195726fSgovinda ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_NINTRS, &hdl, 1227c478bd9Sstevel@tonic-gate (void *)nintrsp); 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs:: nintrs %x\n", 1257c478bd9Sstevel@tonic-gate *nintrsp)); 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate return (ret); 1287c478bd9Sstevel@tonic-gate } 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate /* 1327c478bd9Sstevel@tonic-gate * ddi_intr_get_navail: 1337c478bd9Sstevel@tonic-gate * Bus nexus driver will return availble interrupt count value for 1347c478bd9Sstevel@tonic-gate * a given interrupt type. 1357c478bd9Sstevel@tonic-gate * 1367c478bd9Sstevel@tonic-gate * Return as an integer in the integer pointed to by the argument 1377c478bd9Sstevel@tonic-gate * *navailp*, the number of interrupts currently available for the 1387c478bd9Sstevel@tonic-gate * given interrupt type. 1397c478bd9Sstevel@tonic-gate */ 1407c478bd9Sstevel@tonic-gate int 1417c478bd9Sstevel@tonic-gate ddi_intr_get_navail(dev_info_t *dip, int type, int *navailp) 1427c478bd9Sstevel@tonic-gate { 1437c478bd9Sstevel@tonic-gate int ret; 1447c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t hdl; 1457c478bd9Sstevel@tonic-gate 146*a195726fSgovinda DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_navail: dip %p, type: %d\n", 147*a195726fSgovinda (void *)dip, type)); 1487c478bd9Sstevel@tonic-gate 149*a195726fSgovinda if ((dip == NULL) || (type & ~(DDI_INTR_SUP_TYPES))) { 150*a195726fSgovinda *navailp = 0; 1517c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 152*a195726fSgovinda } 1537c478bd9Sstevel@tonic-gate 154*a195726fSgovinda if (!(i_ddi_intr_get_supported_types(dip) & type)) { 155*a195726fSgovinda *navailp = 0; 1567c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 157*a195726fSgovinda } 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate /* 1607c478bd9Sstevel@tonic-gate * In future, this interface implementation will change 1617c478bd9Sstevel@tonic-gate * with Resource Management support. 1627c478bd9Sstevel@tonic-gate */ 1637c478bd9Sstevel@tonic-gate bzero(&hdl, sizeof (ddi_intr_handle_impl_t)); 1647c478bd9Sstevel@tonic-gate hdl.ih_dip = dip; 1657c478bd9Sstevel@tonic-gate hdl.ih_type = type; 1667c478bd9Sstevel@tonic-gate 167*a195726fSgovinda ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_NAVAIL, &hdl, 168*a195726fSgovinda (void *)navailp); 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate return (ret == DDI_SUCCESS ? DDI_SUCCESS : DDI_INTR_NOTFOUND); 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate /* 1757c478bd9Sstevel@tonic-gate * Interrupt allocate/free functions 1767c478bd9Sstevel@tonic-gate */ 1777c478bd9Sstevel@tonic-gate int 1787c478bd9Sstevel@tonic-gate ddi_intr_alloc(dev_info_t *dip, ddi_intr_handle_t *h_array, int type, int inum, 1797c478bd9Sstevel@tonic-gate int count, int *actualp, int behavior) 1807c478bd9Sstevel@tonic-gate { 1817c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, tmp_hdl; 1827c478bd9Sstevel@tonic-gate int i, ret, cap = 0, intr_type, nintrs = 0; 1837c478bd9Sstevel@tonic-gate uint_t pri; 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: name %s dip 0x%p " 1867c478bd9Sstevel@tonic-gate "type %x inum %x count %x behavior %x\n", ddi_driver_name(dip), 1877c478bd9Sstevel@tonic-gate (void *)dip, type, inum, count, behavior)); 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate /* Validate parameters */ 1907c478bd9Sstevel@tonic-gate if (dip == NULL || h_array == NULL || count < 1) { 1917c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Invalid args\n")); 1927c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 1937c478bd9Sstevel@tonic-gate } 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate /* Validate interrupt type */ 1967c478bd9Sstevel@tonic-gate if (!(i_ddi_intr_get_supported_types(dip) & type)) { 1977c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x not " 1987c478bd9Sstevel@tonic-gate "supported\n", type)); 1997c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate /* First, get how many interrupts the device supports */ 2037c478bd9Sstevel@tonic-gate if (!(nintrs = i_ddi_intr_get_supported_nintrs(dip, type))) { 2047c478bd9Sstevel@tonic-gate if (ddi_intr_get_nintrs(dip, type, &nintrs) != DDI_SUCCESS) { 2057c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no " 2067c478bd9Sstevel@tonic-gate "interrupts found of type %d\n", type)); 2077c478bd9Sstevel@tonic-gate return (DDI_INTR_NOTFOUND); 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate /* Is this function invoked with more interrupt than device supports? */ 2127c478bd9Sstevel@tonic-gate if (count > nintrs) { 2137c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no of interrupts " 2147c478bd9Sstevel@tonic-gate "requested %d is more than supported %d\n", count, nintrs)); 2157c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate /* 2197c478bd9Sstevel@tonic-gate * Check if requested interrupt type is not same as interrupt 2207c478bd9Sstevel@tonic-gate * type is in use if any. 2217c478bd9Sstevel@tonic-gate */ 2227c478bd9Sstevel@tonic-gate if (((intr_type = i_ddi_intr_get_current_type(dip)) != 0) && 2237c478bd9Sstevel@tonic-gate (intr_type != type)) { 2247c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Requested " 2257c478bd9Sstevel@tonic-gate "interrupt type %x is different from interrupt type %x" 2267c478bd9Sstevel@tonic-gate "already in use\n", type, intr_type)); 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate /* 2327c478bd9Sstevel@tonic-gate * Check if requested interrupt type is in use and requested number 2337c478bd9Sstevel@tonic-gate * of interrupts and number of interrupts already in use exceeds the 2347c478bd9Sstevel@tonic-gate * number of interrupts supported by this device. 2357c478bd9Sstevel@tonic-gate */ 2367c478bd9Sstevel@tonic-gate if (intr_type) { 2377c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x " 2387c478bd9Sstevel@tonic-gate "is already being used\n", type)); 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate if ((count + i_ddi_intr_get_current_nintrs(dip)) > nintrs) { 2417c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: count %d " 2427c478bd9Sstevel@tonic-gate "+ intrs in use %d exceeds supported %d intrs\n", 2437c478bd9Sstevel@tonic-gate count, i_ddi_intr_get_current_nintrs(dip), nintrs)); 2447c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate /* 2497c478bd9Sstevel@tonic-gate * For MSI, ensure that the requested interrupt count is a power of 2 2507c478bd9Sstevel@tonic-gate */ 2517c478bd9Sstevel@tonic-gate if (type == DDI_INTR_TYPE_MSI && !ISP2(count)) { 2527c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: " 2537c478bd9Sstevel@tonic-gate "MSI count %d is not a power of two\n", count)); 2547c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate /* 2587c478bd9Sstevel@tonic-gate * Limit max MSI/X allocation to ddi_msix_alloc_limit. 2597c478bd9Sstevel@tonic-gate * This limit will change with Resource Management support. 2607c478bd9Sstevel@tonic-gate */ 2617c478bd9Sstevel@tonic-gate if (DDI_INTR_IS_MSI_OR_MSIX(type) && (count > ddi_msix_alloc_limit)) { 2627c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Requested MSI/Xs %d" 2637c478bd9Sstevel@tonic-gate "Max MSI/Xs limit %d\n", count, ddi_msix_alloc_limit)); 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate if (behavior == DDI_INTR_ALLOC_STRICT) { 2667c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: " 2677c478bd9Sstevel@tonic-gate "DDI_INTR_ALLOC_STRICT flag is passed, " 2687c478bd9Sstevel@tonic-gate "return failure\n")); 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate return (DDI_EAGAIN); 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate count = ddi_msix_alloc_limit; 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate /* Now allocate required number of interrupts */ 2777c478bd9Sstevel@tonic-gate bzero(&tmp_hdl, sizeof (ddi_intr_handle_impl_t)); 2787c478bd9Sstevel@tonic-gate tmp_hdl.ih_type = type; 2797c478bd9Sstevel@tonic-gate tmp_hdl.ih_inum = inum; 2807c478bd9Sstevel@tonic-gate tmp_hdl.ih_scratch1 = count; 2817c478bd9Sstevel@tonic-gate tmp_hdl.ih_scratch2 = behavior; 2827c478bd9Sstevel@tonic-gate tmp_hdl.ih_dip = dip; 2837c478bd9Sstevel@tonic-gate 284*a195726fSgovinda if (i_ddi_intr_ops(dip, dip, DDI_INTROP_ALLOC, 2857c478bd9Sstevel@tonic-gate &tmp_hdl, (void *)actualp) != DDI_SUCCESS) { 2867c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: allocation " 2877c478bd9Sstevel@tonic-gate "failed\n")); 2887c478bd9Sstevel@tonic-gate return (*actualp ? DDI_EAGAIN : DDI_INTR_NOTFOUND); 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate 291*a195726fSgovinda if ((ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_GETPRI, 2927c478bd9Sstevel@tonic-gate &tmp_hdl, (void *)&pri)) != DDI_SUCCESS) { 2937c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get priority " 2947c478bd9Sstevel@tonic-gate "failed\n")); 2957c478bd9Sstevel@tonic-gate return (ret); 2967c478bd9Sstevel@tonic-gate } 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: getting capability\n")); 2997c478bd9Sstevel@tonic-gate 300*a195726fSgovinda if ((ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_GETCAP, 3017c478bd9Sstevel@tonic-gate &tmp_hdl, (void *)&cap)) != DDI_SUCCESS) { 3027c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get capability " 3037c478bd9Sstevel@tonic-gate "failed\n")); 3047c478bd9Sstevel@tonic-gate return (ret); 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate /* Save current interrupt type, supported and current intr count */ 3087c478bd9Sstevel@tonic-gate i_ddi_intr_devi_init(dip); 3097c478bd9Sstevel@tonic-gate i_ddi_intr_set_current_type(dip, type); 3107c478bd9Sstevel@tonic-gate i_ddi_intr_set_supported_nintrs(dip, nintrs); 3117c478bd9Sstevel@tonic-gate i_ddi_intr_set_current_nintrs(dip, 3127c478bd9Sstevel@tonic-gate i_ddi_intr_get_current_nintrs(dip) + *actualp); 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate /* Now, go and handle each "handle" */ 3157c478bd9Sstevel@tonic-gate for (i = 0; i < *actualp; i++) { 3167c478bd9Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)kmem_zalloc( 3177c478bd9Sstevel@tonic-gate (sizeof (ddi_intr_handle_impl_t)), KM_SLEEP); 3187c478bd9Sstevel@tonic-gate rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL); 3197c478bd9Sstevel@tonic-gate h_array[i] = (struct __ddi_intr_handle *)hdlp; 3207c478bd9Sstevel@tonic-gate hdlp->ih_type = type; 3217c478bd9Sstevel@tonic-gate hdlp->ih_pri = pri; 3227c478bd9Sstevel@tonic-gate hdlp->ih_cap = cap; 3237c478bd9Sstevel@tonic-gate hdlp->ih_ver = DDI_INTR_VERSION; 3247c478bd9Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ALLOC; 3257c478bd9Sstevel@tonic-gate hdlp->ih_dip = dip; 3267c478bd9Sstevel@tonic-gate hdlp->ih_inum = inum + i; 3277c478bd9Sstevel@tonic-gate if (type & DDI_INTR_TYPE_FIXED) 328cfb1a455Segillett i_ddi_set_intr_handle(dip, hdlp->ih_inum, &h_array[i]); 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: hdlp = 0x%p\n", 3317c478bd9Sstevel@tonic-gate (void *)h_array[i])); 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate int 3397c478bd9Sstevel@tonic-gate ddi_intr_free(ddi_intr_handle_t h) 3407c478bd9Sstevel@tonic-gate { 3417c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 3427c478bd9Sstevel@tonic-gate int ret; 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_free: hdlp = %p\n", (void *)hdlp)); 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate if (hdlp == NULL) 3477c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 3507c478bd9Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) { 3517c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 3527c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate 355*a195726fSgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 3567c478bd9Sstevel@tonic-gate DDI_INTROP_FREE, hdlp, NULL); 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 3597c478bd9Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 3607c478bd9Sstevel@tonic-gate i_ddi_intr_set_current_nintrs(hdlp->ih_dip, 3617c478bd9Sstevel@tonic-gate i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1); 3627c478bd9Sstevel@tonic-gate 363*a195726fSgovinda if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) == 0) { 364*a195726fSgovinda i_ddi_intr_devi_fini(hdlp->ih_dip); 365*a195726fSgovinda } else { 3667c478bd9Sstevel@tonic-gate if (hdlp->ih_type & DDI_INTR_TYPE_FIXED) 3677c478bd9Sstevel@tonic-gate i_ddi_set_intr_handle(hdlp->ih_dip, 3687c478bd9Sstevel@tonic-gate hdlp->ih_inum, NULL); 369*a195726fSgovinda } 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate rw_destroy(&hdlp->ih_rwlock); 3727c478bd9Sstevel@tonic-gate kmem_free(hdlp, sizeof (ddi_intr_handle_impl_t)); 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate return (ret); 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate /* 3797c478bd9Sstevel@tonic-gate * Interrupt get/set capacity functions 3807c478bd9Sstevel@tonic-gate * 3817c478bd9Sstevel@tonic-gate * The logic used to figure this out is shown here: 3827c478bd9Sstevel@tonic-gate * 3837c478bd9Sstevel@tonic-gate * Device level Platform level Intr source 3847c478bd9Sstevel@tonic-gate * 1. Fixed interrupts 3857c478bd9Sstevel@tonic-gate * (non-PCI) 3867c478bd9Sstevel@tonic-gate * o Flags supported N/A Maskable/Pending/ rootnex 3877c478bd9Sstevel@tonic-gate * No Block Enable 3887c478bd9Sstevel@tonic-gate * o navail 1 3897c478bd9Sstevel@tonic-gate * 3907c478bd9Sstevel@tonic-gate * 2. PCI Fixed interrupts 3917c478bd9Sstevel@tonic-gate * o Flags supported pending/Maskable Maskable/pending/ pci 3927c478bd9Sstevel@tonic-gate * No Block enable 3937c478bd9Sstevel@tonic-gate * o navail N/A 1 3947c478bd9Sstevel@tonic-gate * 3957c478bd9Sstevel@tonic-gate * 3. PCI MSI 3967c478bd9Sstevel@tonic-gate * o Flags supported Maskable/Pending Maskable/Pending pci 3977c478bd9Sstevel@tonic-gate * Block Enable (if drvr doesn't) Block Enable 3987c478bd9Sstevel@tonic-gate * o navail N/A #vectors - #used N/A 3997c478bd9Sstevel@tonic-gate * 4007c478bd9Sstevel@tonic-gate * 4. PCI MSI-X 4017c478bd9Sstevel@tonic-gate * o Flags supported Maskable/Pending Maskable/Pending pci 4027c478bd9Sstevel@tonic-gate * Block Enable Block Enable 4037c478bd9Sstevel@tonic-gate * o navail N/A #vectors - #used N/A 4047c478bd9Sstevel@tonic-gate * 4057c478bd9Sstevel@tonic-gate * where: 4067c478bd9Sstevel@tonic-gate * #vectors - Total numbers of vectors available 4077c478bd9Sstevel@tonic-gate * #used - Total numbers of vectors currently being used 4087c478bd9Sstevel@tonic-gate * 4097c478bd9Sstevel@tonic-gate * For devices complying to PCI2.3 or greater, see bit10 of Command Register 4107c478bd9Sstevel@tonic-gate * 0 - enables assertion of INTx 4117c478bd9Sstevel@tonic-gate * 1 - disables assertion of INTx 4127c478bd9Sstevel@tonic-gate * 4137c478bd9Sstevel@tonic-gate * For non MSI/X interrupts; if the IRQ is shared then all ddi_intr_set_*() 4147c478bd9Sstevel@tonic-gate * operations return failure. 4157c478bd9Sstevel@tonic-gate */ 4167c478bd9Sstevel@tonic-gate int 4177c478bd9Sstevel@tonic-gate ddi_intr_get_cap(ddi_intr_handle_t h, int *flagsp) 4187c478bd9Sstevel@tonic-gate { 4197c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 4207c478bd9Sstevel@tonic-gate int ret; 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_cap: hdlp = %p\n", 4237c478bd9Sstevel@tonic-gate (void *)hdlp)); 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate *flagsp = 0; 4267c478bd9Sstevel@tonic-gate if (hdlp == NULL) 4277c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate if (hdlp->ih_cap) { 4327c478bd9Sstevel@tonic-gate *flagsp = hdlp->ih_cap & ~DDI_INTR_FLAG_MSI64; 4337c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 4347c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4357c478bd9Sstevel@tonic-gate } 4367c478bd9Sstevel@tonic-gate 437*a195726fSgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 4387c478bd9Sstevel@tonic-gate DDI_INTROP_GETCAP, hdlp, (void *)flagsp); 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 4417c478bd9Sstevel@tonic-gate hdlp->ih_cap = *flagsp; 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate /* Mask out MSI/X 64-bit support to the consumer */ 4447c478bd9Sstevel@tonic-gate *flagsp &= ~DDI_INTR_FLAG_MSI64; 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 4487c478bd9Sstevel@tonic-gate return (ret); 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate int 4527c478bd9Sstevel@tonic-gate ddi_intr_set_cap(ddi_intr_handle_t h, int flags) 4537c478bd9Sstevel@tonic-gate { 4547c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 4557c478bd9Sstevel@tonic-gate int ret; 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_cap: hdlp = %p", (void *)hdlp)); 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate if (hdlp == NULL) 4607c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 4637c478bd9Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) { 4647c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 4657c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate /* Only DDI_INTR_FLAG_LEVEL or DDI_INTR_FLAG_EDGE are allowed */ 4697c478bd9Sstevel@tonic-gate if (!(flags & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) { 4707c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "%s%d: only LEVEL or EDGE capability " 4717c478bd9Sstevel@tonic-gate "can be set\n", ddi_driver_name(hdlp->ih_dip), 4727c478bd9Sstevel@tonic-gate ddi_get_instance(hdlp->ih_dip))); 4737c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 4747c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate /* Both level/edge flags must be currently supported */ 4787c478bd9Sstevel@tonic-gate if (!(hdlp->ih_cap & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) { 4797c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "%s%d: Both LEVEL and EDGE capability" 4807c478bd9Sstevel@tonic-gate " must be supported\n", ddi_driver_name(hdlp->ih_dip), 4817c478bd9Sstevel@tonic-gate ddi_get_instance(hdlp->ih_dip))); 4827c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 4837c478bd9Sstevel@tonic-gate return (DDI_ENOTSUP); 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate 486*a195726fSgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 4877c478bd9Sstevel@tonic-gate DDI_INTROP_SETCAP, hdlp, &flags); 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 4907c478bd9Sstevel@tonic-gate return (ret); 4917c478bd9Sstevel@tonic-gate } 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate /* 4947c478bd9Sstevel@tonic-gate * Priority related functions 4957c478bd9Sstevel@tonic-gate */ 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate /* 4987c478bd9Sstevel@tonic-gate * ddi_intr_get_hilevel_pri: 4997c478bd9Sstevel@tonic-gate * Returns the minimum priority level for a 5007c478bd9Sstevel@tonic-gate * high-level interrupt on a platform. 5017c478bd9Sstevel@tonic-gate */ 5027c478bd9Sstevel@tonic-gate uint_t 5037c478bd9Sstevel@tonic-gate ddi_intr_get_hilevel_pri(void) 5047c478bd9Sstevel@tonic-gate { 5057c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_hilevel_pri:\n")); 5067c478bd9Sstevel@tonic-gate return (LOCK_LEVEL + 1); 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate int 5107c478bd9Sstevel@tonic-gate ddi_intr_get_pri(ddi_intr_handle_t h, uint_t *prip) 5117c478bd9Sstevel@tonic-gate { 5127c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 5137c478bd9Sstevel@tonic-gate int ret; 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pri: hdlp = %p\n", 5167c478bd9Sstevel@tonic-gate (void *)hdlp)); 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate *prip = 0; 5197c478bd9Sstevel@tonic-gate if (hdlp == NULL) 5207c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 5237c478bd9Sstevel@tonic-gate /* Already initialized, just return that */ 5247c478bd9Sstevel@tonic-gate if (hdlp->ih_pri) { 5257c478bd9Sstevel@tonic-gate *prip = hdlp->ih_pri; 5267c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 5277c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate 530*a195726fSgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 5317c478bd9Sstevel@tonic-gate DDI_INTROP_GETPRI, hdlp, (void *)prip); 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate if (ret == DDI_SUCCESS) 5347c478bd9Sstevel@tonic-gate hdlp->ih_pri = *prip; 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 5377c478bd9Sstevel@tonic-gate return (ret); 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate int 5417c478bd9Sstevel@tonic-gate ddi_intr_set_pri(ddi_intr_handle_t h, uint_t pri) 5427c478bd9Sstevel@tonic-gate { 5437c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 5447c478bd9Sstevel@tonic-gate int ret; 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: hdlp = %p", (void *)hdlp)); 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate if (hdlp == NULL) 5497c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate /* Validate priority argument */ 5527c478bd9Sstevel@tonic-gate if (pri < DDI_INTR_PRI_MIN || pri > DDI_INTR_PRI_MAX) { 5537c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: invalid priority " 5547c478bd9Sstevel@tonic-gate "specified = %x\n", pri)); 5557c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 5567c478bd9Sstevel@tonic-gate } 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 5597c478bd9Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) { 5607c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 5617c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 5627c478bd9Sstevel@tonic-gate } 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate /* If the passed priority is same as existing priority; do nothing */ 5657c478bd9Sstevel@tonic-gate if (pri == hdlp->ih_pri) { 5667c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 5677c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate 570*a195726fSgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 5717c478bd9Sstevel@tonic-gate DDI_INTROP_SETPRI, hdlp, &pri); 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate if (ret == DDI_SUCCESS) 5747c478bd9Sstevel@tonic-gate hdlp->ih_pri = pri; 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 5777c478bd9Sstevel@tonic-gate return (ret); 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate /* 5817c478bd9Sstevel@tonic-gate * Interrupt add/duplicate/remove handlers 5827c478bd9Sstevel@tonic-gate */ 5837c478bd9Sstevel@tonic-gate int 5847c478bd9Sstevel@tonic-gate ddi_intr_add_handler(ddi_intr_handle_t h, ddi_intr_handler_t inthandler, 5857c478bd9Sstevel@tonic-gate void *arg1, void *arg2) 5867c478bd9Sstevel@tonic-gate { 5877c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 5887c478bd9Sstevel@tonic-gate int ret; 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_handler: hdlp = 0x%p\n", 5917c478bd9Sstevel@tonic-gate (void *)hdlp)); 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate if ((hdlp == NULL) || (inthandler == NULL)) 5947c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 5977c478bd9Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) { 5987c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 5997c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 6007c478bd9Sstevel@tonic-gate } 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate hdlp->ih_cb_func = inthandler; 6037c478bd9Sstevel@tonic-gate hdlp->ih_cb_arg1 = arg1; 6047c478bd9Sstevel@tonic-gate hdlp->ih_cb_arg2 = arg2; 6057c478bd9Sstevel@tonic-gate 606*a195726fSgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 6077c478bd9Sstevel@tonic-gate DDI_INTROP_ADDISR, hdlp, NULL); 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) { 6107c478bd9Sstevel@tonic-gate hdlp->ih_cb_func = NULL; 6117c478bd9Sstevel@tonic-gate hdlp->ih_cb_arg1 = NULL; 6127c478bd9Sstevel@tonic-gate hdlp->ih_cb_arg2 = NULL; 6137c478bd9Sstevel@tonic-gate } else 6147c478bd9Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ADDED; 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 6177c478bd9Sstevel@tonic-gate return (ret); 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate int 6217c478bd9Sstevel@tonic-gate ddi_intr_dup_handler(ddi_intr_handle_t org, int vector, ddi_intr_handle_t *dup) 6227c478bd9Sstevel@tonic-gate { 6237c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)org; 6247c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *dup_hdlp; 6257c478bd9Sstevel@tonic-gate int ret; 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_dup_handler: hdlp = 0x%p\n", 6287c478bd9Sstevel@tonic-gate (void *)hdlp)); 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate /* Do some input argument checking ("dup" is not allocated) */ 6317c478bd9Sstevel@tonic-gate if ((hdlp == NULL) || (dup != NULL)) 6327c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate /* Do some input argument checking */ 6377c478bd9Sstevel@tonic-gate if ((hdlp->ih_state == DDI_IHDL_STATE_ALLOC) || /* intr handle alloc? */ 6387c478bd9Sstevel@tonic-gate (hdlp->ih_type != DDI_INTR_TYPE_MSIX)) { /* only MSI-X allowed */ 6397c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 6407c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate 643*a195726fSgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 6447c478bd9Sstevel@tonic-gate DDI_INTROP_DUPVEC, hdlp, (void *)&vector); 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 6477c478bd9Sstevel@tonic-gate dup_hdlp = (ddi_intr_handle_impl_t *) 6487c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (ddi_intr_handle_impl_t), KM_SLEEP); 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate dup = (ddi_intr_handle_t *)dup_hdlp; 6517c478bd9Sstevel@tonic-gate rw_init(&dup_hdlp->ih_rwlock, NULL, RW_DRIVER, NULL); 6527c478bd9Sstevel@tonic-gate rw_enter(&dup_hdlp->ih_rwlock, RW_WRITER); 6537c478bd9Sstevel@tonic-gate dup_hdlp->ih_ver = DDI_INTR_VERSION; 6547c478bd9Sstevel@tonic-gate dup_hdlp->ih_state = DDI_IHDL_STATE_ADDED; 6557c478bd9Sstevel@tonic-gate dup_hdlp->ih_dip = hdlp->ih_dip; 6567c478bd9Sstevel@tonic-gate dup_hdlp->ih_type = hdlp->ih_type; 6577c478bd9Sstevel@tonic-gate dup_hdlp->ih_pri = hdlp->ih_pri; 6587c478bd9Sstevel@tonic-gate dup_hdlp->ih_cap = hdlp->ih_cap; 6597c478bd9Sstevel@tonic-gate dup_hdlp->ih_inum = hdlp->ih_inum; 6607c478bd9Sstevel@tonic-gate /* What about MSI-X vector */ 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate dup_hdlp->ih_cb_func = hdlp->ih_cb_func; 6637c478bd9Sstevel@tonic-gate dup_hdlp->ih_cb_arg1 = hdlp->ih_cb_arg1; 6647c478bd9Sstevel@tonic-gate dup_hdlp->ih_cb_arg2 = hdlp->ih_cb_arg2; 6657c478bd9Sstevel@tonic-gate rw_exit(&dup_hdlp->ih_rwlock); 6667c478bd9Sstevel@tonic-gate } 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 6697c478bd9Sstevel@tonic-gate return (ret); 6707c478bd9Sstevel@tonic-gate } 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate int 6737c478bd9Sstevel@tonic-gate ddi_intr_remove_handler(ddi_intr_handle_t h) 6747c478bd9Sstevel@tonic-gate { 6757c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 6767c478bd9Sstevel@tonic-gate int ret; 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_handler: hdlp = %p\n", 6797c478bd9Sstevel@tonic-gate (void *)hdlp)); 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate if (hdlp == NULL) 6827c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 6857c478bd9Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ADDED) { 6867c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 6877c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 6887c478bd9Sstevel@tonic-gate } 6897c478bd9Sstevel@tonic-gate 690*a195726fSgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 6917c478bd9Sstevel@tonic-gate DDI_INTROP_REMISR, hdlp, NULL); 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 6947c478bd9Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ALLOC; 6957c478bd9Sstevel@tonic-gate hdlp->ih_cb_func = NULL; 6967c478bd9Sstevel@tonic-gate hdlp->ih_cb_arg1 = NULL; 6977c478bd9Sstevel@tonic-gate hdlp->ih_cb_arg2 = NULL; 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 7017c478bd9Sstevel@tonic-gate return (ret); 7027c478bd9Sstevel@tonic-gate } 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate /* 7057c478bd9Sstevel@tonic-gate * Interrupt enable/disable/block_enable/block_disable handlers 7067c478bd9Sstevel@tonic-gate */ 7077c478bd9Sstevel@tonic-gate int 7087c478bd9Sstevel@tonic-gate ddi_intr_enable(ddi_intr_handle_t h) 7097c478bd9Sstevel@tonic-gate { 7107c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 7117c478bd9Sstevel@tonic-gate int ret; 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_enable: hdlp = %p\n", 7147c478bd9Sstevel@tonic-gate (void *)hdlp)); 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate if (hdlp == NULL) 7177c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 7207c478bd9Sstevel@tonic-gate if ((hdlp->ih_state != DDI_IHDL_STATE_ADDED) || 7217c478bd9Sstevel@tonic-gate ((hdlp->ih_type == DDI_INTR_TYPE_MSI) && 7227c478bd9Sstevel@tonic-gate (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) { 7237c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 7247c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate 727*a195726fSgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 7287c478bd9Sstevel@tonic-gate DDI_INTROP_ENABLE, hdlp, NULL); 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate if (ret == DDI_SUCCESS) 7317c478bd9Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ENABLE; 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 7347c478bd9Sstevel@tonic-gate return (ret); 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate int 7387c478bd9Sstevel@tonic-gate ddi_intr_disable(ddi_intr_handle_t h) 7397c478bd9Sstevel@tonic-gate { 7407c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 7417c478bd9Sstevel@tonic-gate int ret; 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_disable: hdlp = %p\n", 7447c478bd9Sstevel@tonic-gate (void *)hdlp)); 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate if (hdlp == NULL) 7477c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 7507c478bd9Sstevel@tonic-gate if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) || 7517c478bd9Sstevel@tonic-gate ((hdlp->ih_type == DDI_INTR_TYPE_MSI) && 7527c478bd9Sstevel@tonic-gate (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) { 7537c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 7547c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 7557c478bd9Sstevel@tonic-gate } 7567c478bd9Sstevel@tonic-gate 757*a195726fSgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 7587c478bd9Sstevel@tonic-gate DDI_INTROP_DISABLE, hdlp, NULL); 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate if (ret == DDI_SUCCESS) 7617c478bd9Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ADDED; 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 7647c478bd9Sstevel@tonic-gate return (ret); 7657c478bd9Sstevel@tonic-gate } 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate int 7687c478bd9Sstevel@tonic-gate ddi_intr_block_enable(ddi_intr_handle_t *h_array, int count) 7697c478bd9Sstevel@tonic-gate { 7707c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp; 7717c478bd9Sstevel@tonic-gate int i, ret; 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_enable: h_array = %p\n", 7747c478bd9Sstevel@tonic-gate (void *)h_array)); 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate if (h_array == NULL) 7777c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) { 7807c478bd9Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 7817c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ADDED || 7847c478bd9Sstevel@tonic-gate hdlp->ih_type != DDI_INTR_TYPE_MSI || 7857c478bd9Sstevel@tonic-gate !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) { 7867c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 7877c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 7887c478bd9Sstevel@tonic-gate } 7897c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[0]; 7937c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 7947c478bd9Sstevel@tonic-gate hdlp->ih_scratch1 = count; 7957c478bd9Sstevel@tonic-gate 796*a195726fSgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 7977c478bd9Sstevel@tonic-gate DDI_INTROP_BLOCKENABLE, hdlp, NULL); 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 8027c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) { 8037c478bd9Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 8047c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 8057c478bd9Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ENABLE; 8067c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 8077c478bd9Sstevel@tonic-gate } 8087c478bd9Sstevel@tonic-gate } 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate return (ret); 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate int 8147c478bd9Sstevel@tonic-gate ddi_intr_block_disable(ddi_intr_handle_t *h_array, int count) 8157c478bd9Sstevel@tonic-gate { 8167c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp; 8177c478bd9Sstevel@tonic-gate int i, ret; 8187c478bd9Sstevel@tonic-gate 8197c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_disable: h_array = %p\n", 8207c478bd9Sstevel@tonic-gate (void *)h_array)); 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate if (h_array == NULL) 8237c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 8247c478bd9Sstevel@tonic-gate 8257c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) { 8267c478bd9Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 8277c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 8287c478bd9Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ENABLE || 8297c478bd9Sstevel@tonic-gate hdlp->ih_type != DDI_INTR_TYPE_MSI || 8307c478bd9Sstevel@tonic-gate !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) { 8317c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 8327c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 8337c478bd9Sstevel@tonic-gate } 8347c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 8357c478bd9Sstevel@tonic-gate } 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[0]; 8387c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 8397c478bd9Sstevel@tonic-gate hdlp->ih_scratch1 = count; 8407c478bd9Sstevel@tonic-gate 841*a195726fSgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 8427c478bd9Sstevel@tonic-gate DDI_INTROP_BLOCKDISABLE, hdlp, NULL); 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate if (ret == DDI_SUCCESS) { 8477c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) { 8487c478bd9Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 8497c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 8507c478bd9Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ADDED; 8517c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 8527c478bd9Sstevel@tonic-gate } 8537c478bd9Sstevel@tonic-gate } 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate return (ret); 8567c478bd9Sstevel@tonic-gate } 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate /* 8597c478bd9Sstevel@tonic-gate * Interrupt set/clr mask handlers 8607c478bd9Sstevel@tonic-gate */ 8617c478bd9Sstevel@tonic-gate int 8627c478bd9Sstevel@tonic-gate ddi_intr_set_mask(ddi_intr_handle_t h) 8637c478bd9Sstevel@tonic-gate { 8647c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 8657c478bd9Sstevel@tonic-gate int ret; 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_mask: hdlp = %p\n", 8687c478bd9Sstevel@tonic-gate (void *)hdlp)); 8697c478bd9Sstevel@tonic-gate 8707c478bd9Sstevel@tonic-gate if (hdlp == NULL) 8717c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 8747c478bd9Sstevel@tonic-gate if (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE)) { 8757c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 8767c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 8777c478bd9Sstevel@tonic-gate } 8787c478bd9Sstevel@tonic-gate 879*a195726fSgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 8807c478bd9Sstevel@tonic-gate DDI_INTROP_SETMASK, hdlp, NULL); 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 8837c478bd9Sstevel@tonic-gate return (ret); 8847c478bd9Sstevel@tonic-gate } 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate int 8877c478bd9Sstevel@tonic-gate ddi_intr_clr_mask(ddi_intr_handle_t h) 8887c478bd9Sstevel@tonic-gate { 8897c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 8907c478bd9Sstevel@tonic-gate int ret; 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_clr_mask: hdlp = %p\n", 8937c478bd9Sstevel@tonic-gate (void *)hdlp)); 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate if (hdlp == NULL) 8967c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 8997c478bd9Sstevel@tonic-gate if (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE)) { 9007c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 9017c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate 904*a195726fSgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 9057c478bd9Sstevel@tonic-gate DDI_INTROP_CLRMASK, hdlp, NULL); 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 9087c478bd9Sstevel@tonic-gate return (ret); 9097c478bd9Sstevel@tonic-gate } 9107c478bd9Sstevel@tonic-gate 9117c478bd9Sstevel@tonic-gate /* 9127c478bd9Sstevel@tonic-gate * Interrupt get_pending handler 9137c478bd9Sstevel@tonic-gate */ 9147c478bd9Sstevel@tonic-gate int 9157c478bd9Sstevel@tonic-gate ddi_intr_get_pending(ddi_intr_handle_t h, int *pendingp) 9167c478bd9Sstevel@tonic-gate { 9177c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h; 9187c478bd9Sstevel@tonic-gate int ret; 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pending: hdlp = %p\n", 9217c478bd9Sstevel@tonic-gate (void *)hdlp)); 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate if (hdlp == NULL) 9247c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 9277c478bd9Sstevel@tonic-gate if (!(hdlp->ih_cap & DDI_INTR_FLAG_PENDING)) { 9287c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 9297c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 9307c478bd9Sstevel@tonic-gate } 9317c478bd9Sstevel@tonic-gate 932*a195726fSgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip, 9337c478bd9Sstevel@tonic-gate DDI_INTROP_GETPENDING, hdlp, (void *)pendingp); 9347c478bd9Sstevel@tonic-gate 9357c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 9367c478bd9Sstevel@tonic-gate return (ret); 9377c478bd9Sstevel@tonic-gate } 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate /* 9407c478bd9Sstevel@tonic-gate * Soft interrupt handlers 9417c478bd9Sstevel@tonic-gate */ 9427c478bd9Sstevel@tonic-gate /* 9437c478bd9Sstevel@tonic-gate * Add a soft interrupt and register its handler 9447c478bd9Sstevel@tonic-gate */ 9457c478bd9Sstevel@tonic-gate /* ARGSUSED */ 9467c478bd9Sstevel@tonic-gate int 9477c478bd9Sstevel@tonic-gate ddi_intr_add_softint(dev_info_t *dip, ddi_softint_handle_t *h_p, int soft_pri, 9487c478bd9Sstevel@tonic-gate ddi_intr_handler_t handler, void *arg1) 9497c478bd9Sstevel@tonic-gate { 9507c478bd9Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp; 9517c478bd9Sstevel@tonic-gate int ret; 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: dip = %p, " 9547c478bd9Sstevel@tonic-gate "softpri = 0x%x\n", (void *)dip, soft_pri)); 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate if ((dip == NULL) || (h_p == NULL) || (handler == NULL)) { 9577c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: " 9587c478bd9Sstevel@tonic-gate "invalid arguments")); 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate /* Validate input arguments */ 9647c478bd9Sstevel@tonic-gate if (soft_pri < DDI_INTR_SOFTPRI_MIN || 9657c478bd9Sstevel@tonic-gate soft_pri > DDI_INTR_SOFTPRI_MAX) { 9667c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: invalid " 9677c478bd9Sstevel@tonic-gate "soft_pri input given = %x\n", soft_pri)); 9687c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 9697c478bd9Sstevel@tonic-gate } 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate hdlp = (ddi_softint_hdl_impl_t *)kmem_zalloc( 9727c478bd9Sstevel@tonic-gate sizeof (ddi_softint_hdl_impl_t), KM_SLEEP); 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate /* fill up internally */ 9757c478bd9Sstevel@tonic-gate rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL); 9767c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 9777c478bd9Sstevel@tonic-gate hdlp->ih_pri = soft_pri; 9787c478bd9Sstevel@tonic-gate hdlp->ih_dip = dip; 9797c478bd9Sstevel@tonic-gate hdlp->ih_cb_func = handler; 9807c478bd9Sstevel@tonic-gate hdlp->ih_cb_arg1 = arg1; 9817c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: hdlp = %p\n", 9827c478bd9Sstevel@tonic-gate (void *)hdlp)); 9837c478bd9Sstevel@tonic-gate 9847c478bd9Sstevel@tonic-gate /* do the platform specific calls */ 9857c478bd9Sstevel@tonic-gate if ((ret = i_ddi_add_softint(hdlp)) != DDI_SUCCESS) { 9867c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 9877c478bd9Sstevel@tonic-gate rw_destroy(&hdlp->ih_rwlock); 9887c478bd9Sstevel@tonic-gate kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t)); 9897c478bd9Sstevel@tonic-gate return (ret); 9907c478bd9Sstevel@tonic-gate } 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate *h_p = (ddi_softint_handle_t)hdlp; 9937c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 9947c478bd9Sstevel@tonic-gate return (ret); 9957c478bd9Sstevel@tonic-gate } 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate /* 9987c478bd9Sstevel@tonic-gate * Remove the soft interrupt 9997c478bd9Sstevel@tonic-gate */ 10007c478bd9Sstevel@tonic-gate int 10017c478bd9Sstevel@tonic-gate ddi_intr_remove_softint(ddi_softint_handle_t h) 10027c478bd9Sstevel@tonic-gate { 10037c478bd9Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h; 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_softint: hdlp = %p\n", 10067c478bd9Sstevel@tonic-gate (void *)hdlp)); 10077c478bd9Sstevel@tonic-gate 10087c478bd9Sstevel@tonic-gate if (hdlp == NULL) 10097c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 10107c478bd9Sstevel@tonic-gate 10117c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 10127c478bd9Sstevel@tonic-gate i_ddi_remove_softint(hdlp); 10137c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 10147c478bd9Sstevel@tonic-gate rw_destroy(&hdlp->ih_rwlock); 10157c478bd9Sstevel@tonic-gate 10167c478bd9Sstevel@tonic-gate /* kmem_free the hdl impl_t structure allocated earlier */ 10177c478bd9Sstevel@tonic-gate kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t)); 10187c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 10197c478bd9Sstevel@tonic-gate } 10207c478bd9Sstevel@tonic-gate 10217c478bd9Sstevel@tonic-gate /* 10227c478bd9Sstevel@tonic-gate * Trigger a soft interrupt 10237c478bd9Sstevel@tonic-gate */ 10247c478bd9Sstevel@tonic-gate int 10257c478bd9Sstevel@tonic-gate ddi_intr_trigger_softint(ddi_softint_handle_t h, void *arg2) 10267c478bd9Sstevel@tonic-gate { 10277c478bd9Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h; 10287c478bd9Sstevel@tonic-gate int ret; 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate if (hdlp == NULL) 10317c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 10327c478bd9Sstevel@tonic-gate 1033b08160e2Sgovinda if ((ret = i_ddi_trigger_softint(hdlp, arg2)) != DDI_SUCCESS) { 10347c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_trigger_softint: failed, " 10357c478bd9Sstevel@tonic-gate " ret 0%x\n", ret)); 1036b08160e2Sgovinda 1037b08160e2Sgovinda return (ret); 10387c478bd9Sstevel@tonic-gate } 10397c478bd9Sstevel@tonic-gate 1040b08160e2Sgovinda hdlp->ih_cb_arg2 = arg2; 1041b08160e2Sgovinda return (DDI_SUCCESS); 10427c478bd9Sstevel@tonic-gate } 10437c478bd9Sstevel@tonic-gate 10447c478bd9Sstevel@tonic-gate /* 10457c478bd9Sstevel@tonic-gate * Get the soft interrupt priority 10467c478bd9Sstevel@tonic-gate */ 10477c478bd9Sstevel@tonic-gate int 10487c478bd9Sstevel@tonic-gate ddi_intr_get_softint_pri(ddi_softint_handle_t h, uint_t *soft_prip) 10497c478bd9Sstevel@tonic-gate { 10507c478bd9Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h; 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_softint_pri: h = %p\n", 10537c478bd9Sstevel@tonic-gate (void *)h)); 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate if (hdlp == NULL) 10567c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER); 10597c478bd9Sstevel@tonic-gate *soft_prip = hdlp->ih_pri; 10607c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 10617c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 10627c478bd9Sstevel@tonic-gate } 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate /* 10657c478bd9Sstevel@tonic-gate * Set the soft interrupt priority 10667c478bd9Sstevel@tonic-gate */ 10677c478bd9Sstevel@tonic-gate int 10687c478bd9Sstevel@tonic-gate ddi_intr_set_softint_pri(ddi_softint_handle_t h, uint_t soft_pri) 10697c478bd9Sstevel@tonic-gate { 10707c478bd9Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h; 10717c478bd9Sstevel@tonic-gate int ret; 10727c478bd9Sstevel@tonic-gate uint_t orig_soft_pri; 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: h = %p\n", 10757c478bd9Sstevel@tonic-gate (void *)h)); 10767c478bd9Sstevel@tonic-gate 10777c478bd9Sstevel@tonic-gate if (hdlp == NULL) 10787c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate /* Validate priority argument */ 10817c478bd9Sstevel@tonic-gate if (soft_pri < DDI_INTR_SOFTPRI_MIN || 10827c478bd9Sstevel@tonic-gate soft_pri > DDI_INTR_SOFTPRI_MAX) { 10837c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: invalid " 10847c478bd9Sstevel@tonic-gate "soft_pri input given = %x\n", soft_pri)); 10857c478bd9Sstevel@tonic-gate return (DDI_EINVAL); 10867c478bd9Sstevel@tonic-gate } 10877c478bd9Sstevel@tonic-gate 10887c478bd9Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER); 10897c478bd9Sstevel@tonic-gate orig_soft_pri = hdlp->ih_pri; 10907c478bd9Sstevel@tonic-gate hdlp->ih_pri = soft_pri; 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate if ((ret = i_ddi_set_softint_pri(hdlp, orig_soft_pri)) != DDI_SUCCESS) { 10937c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: failed, " 10947c478bd9Sstevel@tonic-gate " ret 0%x\n", ret)); 10957c478bd9Sstevel@tonic-gate hdlp->ih_pri = orig_soft_pri; 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock); 10997c478bd9Sstevel@tonic-gate return (ret); 11007c478bd9Sstevel@tonic-gate } 11017c478bd9Sstevel@tonic-gate 11027c478bd9Sstevel@tonic-gate /* 11037c478bd9Sstevel@tonic-gate * Old DDI interrupt framework 1104*a195726fSgovinda * 1105*a195726fSgovinda * The following DDI interrupt interfaces are obsolete. 1106*a195726fSgovinda * Use the above new DDI interrupt interfaces instead. 11077c478bd9Sstevel@tonic-gate */ 11087c478bd9Sstevel@tonic-gate 11097c478bd9Sstevel@tonic-gate int 11107c478bd9Sstevel@tonic-gate ddi_intr_hilevel(dev_info_t *dip, uint_t inumber) 11117c478bd9Sstevel@tonic-gate { 11127c478bd9Sstevel@tonic-gate ddi_intr_handle_t hdl, *existing_hdlp; 11137c478bd9Sstevel@tonic-gate int actual, ret; 11147c478bd9Sstevel@tonic-gate uint_t high_pri, pri; 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: name=%s%d dip=0x%p " 11177c478bd9Sstevel@tonic-gate "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 11187c478bd9Sstevel@tonic-gate (void *)dip, inumber)); 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate /* 11217c478bd9Sstevel@tonic-gate * The device driver may have already registed with the 11227c478bd9Sstevel@tonic-gate * framework. If so, first try to get the existing interrupt handle 11237c478bd9Sstevel@tonic-gate * for that given inumber and use that handle. 11247c478bd9Sstevel@tonic-gate */ 11257c478bd9Sstevel@tonic-gate existing_hdlp = i_ddi_get_intr_handle(dip, inumber); 11267c478bd9Sstevel@tonic-gate if (existing_hdlp) { 11277c478bd9Sstevel@tonic-gate hdl = existing_hdlp[0]; /* Use existing handle */ 11287c478bd9Sstevel@tonic-gate } else { 11297c478bd9Sstevel@tonic-gate if ((ret = ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED, 11307c478bd9Sstevel@tonic-gate inumber, 1, &actual, 0)) != DDI_SUCCESS) { 11317c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: " 11327c478bd9Sstevel@tonic-gate "ddi_intr_alloc failed, ret 0x%x\n", ret)); 11337c478bd9Sstevel@tonic-gate return (0); 11347c478bd9Sstevel@tonic-gate } 11357c478bd9Sstevel@tonic-gate } 11367c478bd9Sstevel@tonic-gate 11377c478bd9Sstevel@tonic-gate if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) { 11387c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: " 11397c478bd9Sstevel@tonic-gate "ddi_intr_get_pri failed, ret 0x%x\n", ret)); 11407c478bd9Sstevel@tonic-gate (void) ddi_intr_free(hdl); 11417c478bd9Sstevel@tonic-gate return (0); 11427c478bd9Sstevel@tonic-gate } 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate high_pri = ddi_intr_get_hilevel_pri(); 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: pri = %x, " 11477c478bd9Sstevel@tonic-gate "high_pri = %x\n", pri, high_pri)); 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate /* Free the handle allocated here only if no existing handle exists */ 11507c478bd9Sstevel@tonic-gate if (existing_hdlp == NULL) 11517c478bd9Sstevel@tonic-gate (void) ddi_intr_free(hdl); 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate return (pri >= high_pri); 11547c478bd9Sstevel@tonic-gate } 11557c478bd9Sstevel@tonic-gate 11567c478bd9Sstevel@tonic-gate int 11577c478bd9Sstevel@tonic-gate ddi_dev_nintrs(dev_info_t *dip, int *result) 11587c478bd9Sstevel@tonic-gate { 11597c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: name=%s%d dip=0x%p\n", 11607c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), (void *)dip)); 11617c478bd9Sstevel@tonic-gate 11627c478bd9Sstevel@tonic-gate if (ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED, 11637c478bd9Sstevel@tonic-gate result) != DDI_SUCCESS) { 11647c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: " 11657c478bd9Sstevel@tonic-gate "ddi_intr_get_nintrs failed\n")); 11667c478bd9Sstevel@tonic-gate *result = 0; 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 11707c478bd9Sstevel@tonic-gate } 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate int 11737c478bd9Sstevel@tonic-gate ddi_get_iblock_cookie(dev_info_t *dip, uint_t inumber, 11747c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep) 11757c478bd9Sstevel@tonic-gate { 11767c478bd9Sstevel@tonic-gate ddi_intr_handle_t hdl, *existing_hdlp; 11777c478bd9Sstevel@tonic-gate int actual, ret; 11787c478bd9Sstevel@tonic-gate uint_t pri; 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: name=%s%d dip=0x%p " 11817c478bd9Sstevel@tonic-gate "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 11827c478bd9Sstevel@tonic-gate (void *)dip, inumber)); 11837c478bd9Sstevel@tonic-gate 11847c478bd9Sstevel@tonic-gate ASSERT(iblock_cookiep != NULL); 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate /* 11877c478bd9Sstevel@tonic-gate * The device driver may have already registed with the 11887c478bd9Sstevel@tonic-gate * framework. If so, first try to get the existing interrupt handle 11897c478bd9Sstevel@tonic-gate * for that given inumber and use that handle. 11907c478bd9Sstevel@tonic-gate */ 11917c478bd9Sstevel@tonic-gate existing_hdlp = i_ddi_get_intr_handle(dip, inumber); 11927c478bd9Sstevel@tonic-gate if (existing_hdlp) { 11937c478bd9Sstevel@tonic-gate hdl = existing_hdlp[0]; /* Use existing handle */ 11947c478bd9Sstevel@tonic-gate } else { 11957c478bd9Sstevel@tonic-gate if ((ret = ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED, 11967c478bd9Sstevel@tonic-gate inumber, 1, &actual, 0)) != DDI_SUCCESS) { 11977c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: " 11987c478bd9Sstevel@tonic-gate "ddi_intr_alloc failed, ret 0x%x\n", ret)); 11997c478bd9Sstevel@tonic-gate return (DDI_INTR_NOTFOUND); 12007c478bd9Sstevel@tonic-gate } 12017c478bd9Sstevel@tonic-gate } 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) { 12047c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: " 12057c478bd9Sstevel@tonic-gate "ddi_intr_get_pri failed, ret 0x%x\n", ret)); 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate (void) ddi_intr_free(hdl); 12087c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 12097c478bd9Sstevel@tonic-gate } 12107c478bd9Sstevel@tonic-gate 1211abdbd06dSagiri *iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)pri; 12127c478bd9Sstevel@tonic-gate /* Free the handle allocated here only if no existing handle exists */ 12137c478bd9Sstevel@tonic-gate if (existing_hdlp == NULL) 12147c478bd9Sstevel@tonic-gate (void) ddi_intr_free(hdl); 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 12177c478bd9Sstevel@tonic-gate } 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate int 12207c478bd9Sstevel@tonic-gate ddi_add_intr(dev_info_t *dip, uint_t inumber, 12217c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep, 12227c478bd9Sstevel@tonic-gate ddi_idevice_cookie_t *idevice_cookiep, 12237c478bd9Sstevel@tonic-gate uint_t (*int_handler)(caddr_t int_handler_arg), 12247c478bd9Sstevel@tonic-gate caddr_t int_handler_arg) 12257c478bd9Sstevel@tonic-gate { 12267c478bd9Sstevel@tonic-gate ddi_intr_handle_t *hdl_p; 12277c478bd9Sstevel@tonic-gate int actual, ret; 12287c478bd9Sstevel@tonic-gate uint_t pri; 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: name=%s%d dip=0x%p " 12317c478bd9Sstevel@tonic-gate "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 12327c478bd9Sstevel@tonic-gate (void *)dip, inumber)); 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate hdl_p = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP); 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate if ((ret = ddi_intr_alloc(dip, hdl_p, DDI_INTR_TYPE_FIXED, 12377c478bd9Sstevel@tonic-gate inumber, 1, &actual, 0)) != DDI_SUCCESS) { 12387c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: " 12397c478bd9Sstevel@tonic-gate "ddi_intr_alloc failed, ret 0x%x\n", ret)); 12407c478bd9Sstevel@tonic-gate kmem_free(hdl_p, sizeof (ddi_intr_handle_t)); 12417c478bd9Sstevel@tonic-gate return (DDI_INTR_NOTFOUND); 12427c478bd9Sstevel@tonic-gate } 12437c478bd9Sstevel@tonic-gate 12447c478bd9Sstevel@tonic-gate if ((ret = ddi_intr_get_pri(hdl_p[0], &pri)) != DDI_SUCCESS) { 12457c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: " 12467c478bd9Sstevel@tonic-gate "ddi_intr_get_pri failed, ret 0x%x\n", ret)); 12477c478bd9Sstevel@tonic-gate (void) ddi_intr_free(hdl_p[0]); 12487c478bd9Sstevel@tonic-gate kmem_free(hdl_p, sizeof (ddi_intr_handle_t)); 12497c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 12507c478bd9Sstevel@tonic-gate } 12517c478bd9Sstevel@tonic-gate 12527c478bd9Sstevel@tonic-gate if ((ret = ddi_intr_add_handler(hdl_p[0], (ddi_intr_handler_t *) 12537c478bd9Sstevel@tonic-gate int_handler, int_handler_arg, NULL)) != DDI_SUCCESS) { 12547c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: " 12557c478bd9Sstevel@tonic-gate "ddi_intr_add_handler failed, ret 0x%x\n", ret)); 12567c478bd9Sstevel@tonic-gate (void) ddi_intr_free(hdl_p[0]); 12577c478bd9Sstevel@tonic-gate kmem_free(hdl_p, sizeof (ddi_intr_handle_t)); 12587c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 12597c478bd9Sstevel@tonic-gate } 12607c478bd9Sstevel@tonic-gate 12617c478bd9Sstevel@tonic-gate if ((ret = ddi_intr_enable(hdl_p[0])) != DDI_SUCCESS) { 12627c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: " 12637c478bd9Sstevel@tonic-gate "ddi_intr_enable failed, ret 0x%x\n", ret)); 12647c478bd9Sstevel@tonic-gate (void) ddi_intr_remove_handler(hdl_p[0]); 12657c478bd9Sstevel@tonic-gate (void) ddi_intr_free(hdl_p[0]); 12667c478bd9Sstevel@tonic-gate kmem_free(hdl_p, sizeof (ddi_intr_handle_t)); 12677c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 12687c478bd9Sstevel@tonic-gate } 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate if (iblock_cookiep) 1271abdbd06dSagiri *iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)pri; 12727c478bd9Sstevel@tonic-gate 12737c478bd9Sstevel@tonic-gate if (idevice_cookiep) { 12747c478bd9Sstevel@tonic-gate idevice_cookiep->idev_vector = 0; 12757c478bd9Sstevel@tonic-gate idevice_cookiep->idev_priority = pri; 12767c478bd9Sstevel@tonic-gate } 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 12797c478bd9Sstevel@tonic-gate } 12807c478bd9Sstevel@tonic-gate 12817c478bd9Sstevel@tonic-gate /* ARGSUSED */ 12827c478bd9Sstevel@tonic-gate int 12837c478bd9Sstevel@tonic-gate ddi_add_fastintr(dev_info_t *dip, uint_t inumber, 12847c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep, 12857c478bd9Sstevel@tonic-gate ddi_idevice_cookie_t *idevice_cookiep, 12867c478bd9Sstevel@tonic-gate uint_t (*hi_int_handler)(void)) 12877c478bd9Sstevel@tonic-gate { 12887c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_fastintr: name=%s%d dip=0x%p " 12897c478bd9Sstevel@tonic-gate "inum=0x%x: Not supported, return failure\n", ddi_driver_name(dip), 12907c478bd9Sstevel@tonic-gate ddi_get_instance(dip), (void *)dip, inumber)); 12917c478bd9Sstevel@tonic-gate 12927c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 12937c478bd9Sstevel@tonic-gate } 12947c478bd9Sstevel@tonic-gate 12957c478bd9Sstevel@tonic-gate /* ARGSUSED */ 12967c478bd9Sstevel@tonic-gate void 12977c478bd9Sstevel@tonic-gate ddi_remove_intr(dev_info_t *dip, uint_t inum, ddi_iblock_cookie_t iblock_cookie) 12987c478bd9Sstevel@tonic-gate { 12997c478bd9Sstevel@tonic-gate ddi_intr_handle_t *hdl_p; 13007c478bd9Sstevel@tonic-gate int ret; 13017c478bd9Sstevel@tonic-gate 13027c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: name=%s%d dip=0x%p " 13037c478bd9Sstevel@tonic-gate "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 13047c478bd9Sstevel@tonic-gate (void *)dip, inum)); 13057c478bd9Sstevel@tonic-gate 13067c478bd9Sstevel@tonic-gate if ((hdl_p = i_ddi_get_intr_handle(dip, inum)) == NULL) { 13077c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: no handle " 13087c478bd9Sstevel@tonic-gate "found\n")); 13097c478bd9Sstevel@tonic-gate return; 13107c478bd9Sstevel@tonic-gate } 13117c478bd9Sstevel@tonic-gate 13127c478bd9Sstevel@tonic-gate if ((ret = ddi_intr_disable(hdl_p[0])) != DDI_SUCCESS) { 13137c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: " 13147c478bd9Sstevel@tonic-gate "ddi_intr_disable failed, ret 0x%x\n", ret)); 13157c478bd9Sstevel@tonic-gate return; 13167c478bd9Sstevel@tonic-gate } 13177c478bd9Sstevel@tonic-gate 13187c478bd9Sstevel@tonic-gate if ((ret = ddi_intr_remove_handler(hdl_p[0])) != DDI_SUCCESS) { 13197c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: " 13207c478bd9Sstevel@tonic-gate "ddi_intr_remove_handler failed, ret 0x%x\n", ret)); 13217c478bd9Sstevel@tonic-gate return; 13227c478bd9Sstevel@tonic-gate } 13237c478bd9Sstevel@tonic-gate 13247c478bd9Sstevel@tonic-gate if ((ret = ddi_intr_free(hdl_p[0])) != DDI_SUCCESS) { 13257c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: " 13267c478bd9Sstevel@tonic-gate "ddi_intr_free failed, ret 0x%x\n", ret)); 13277c478bd9Sstevel@tonic-gate return; 13287c478bd9Sstevel@tonic-gate } 13297c478bd9Sstevel@tonic-gate 13307c478bd9Sstevel@tonic-gate kmem_free(hdl_p, sizeof (ddi_intr_handle_t)); 13317c478bd9Sstevel@tonic-gate } 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate /* ARGSUSED */ 13347c478bd9Sstevel@tonic-gate int 13357c478bd9Sstevel@tonic-gate ddi_get_soft_iblock_cookie(dev_info_t *dip, int preference, 13367c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep) 13377c478bd9Sstevel@tonic-gate { 13387c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_get_soft_iblock_cookie: name=%s%d " 13397c478bd9Sstevel@tonic-gate "dip=0x%p pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 13407c478bd9Sstevel@tonic-gate (void *)dip, preference)); 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate ASSERT(iblock_cookiep != NULL); 13437c478bd9Sstevel@tonic-gate 13447c478bd9Sstevel@tonic-gate if (preference == DDI_SOFTINT_FIXED) 13457c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13467c478bd9Sstevel@tonic-gate 1347abdbd06dSagiri *iblock_cookiep = (ddi_iblock_cookie_t)((uintptr_t) 13487c478bd9Sstevel@tonic-gate ((preference > DDI_SOFTINT_MED) ? DDI_SOFT_INTR_PRI_H : 13497c478bd9Sstevel@tonic-gate DDI_SOFT_INTR_PRI_M)); 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 13527c478bd9Sstevel@tonic-gate } 13537c478bd9Sstevel@tonic-gate 13547c478bd9Sstevel@tonic-gate int 13557c478bd9Sstevel@tonic-gate ddi_add_softintr(dev_info_t *dip, int preference, ddi_softintr_t *idp, 13567c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep, 13577c478bd9Sstevel@tonic-gate ddi_idevice_cookie_t *idevice_cookiep, 13587c478bd9Sstevel@tonic-gate uint_t (*int_handler)(caddr_t int_handler_arg), 13597c478bd9Sstevel@tonic-gate caddr_t int_handler_arg) 13607c478bd9Sstevel@tonic-gate { 13617c478bd9Sstevel@tonic-gate ddi_softint_handle_t *hdl_p; 13627c478bd9Sstevel@tonic-gate uint64_t softpri; 13637c478bd9Sstevel@tonic-gate int ret; 13647c478bd9Sstevel@tonic-gate 13657c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: name=%s%d dip=0x%p " 13667c478bd9Sstevel@tonic-gate "pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), 13677c478bd9Sstevel@tonic-gate (void *)dip, preference)); 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate if ((idp == NULL) || ((preference == DDI_SOFTINT_FIXED) && 13707c478bd9Sstevel@tonic-gate (iblock_cookiep == NULL))) 13717c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate /* Translate the priority preference */ 13747c478bd9Sstevel@tonic-gate if (preference == DDI_SOFTINT_FIXED) { 1375b52a2671Seota softpri = (uint64_t)(uintptr_t)*iblock_cookiep; 13767c478bd9Sstevel@tonic-gate softpri = MIN(softpri, DDI_SOFT_INTR_PRI_H); 13777c478bd9Sstevel@tonic-gate } else { 13787c478bd9Sstevel@tonic-gate softpri = (uint64_t)((preference > DDI_SOFTINT_MED) ? 13797c478bd9Sstevel@tonic-gate DDI_SOFT_INTR_PRI_H : DDI_SOFT_INTR_PRI_M); 13807c478bd9Sstevel@tonic-gate } 13817c478bd9Sstevel@tonic-gate 13827c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: preference 0x%x " 13837c478bd9Sstevel@tonic-gate "softpri 0x%lx\n", preference, (long)softpri)); 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate hdl_p = kmem_zalloc(sizeof (ddi_softint_handle_t), KM_SLEEP); 13867c478bd9Sstevel@tonic-gate if ((ret = ddi_intr_add_softint(dip, hdl_p, softpri, 13877c478bd9Sstevel@tonic-gate (ddi_intr_handler_t *)int_handler, int_handler_arg)) != 13887c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 13897c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: " 13907c478bd9Sstevel@tonic-gate "ddi_intr_add_softint failed, ret 0x%x\n", ret)); 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate kmem_free(hdl_p, sizeof (ddi_softint_handle_t)); 13937c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13947c478bd9Sstevel@tonic-gate } 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate if (iblock_cookiep) 1397b52a2671Seota *iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)softpri; 13987c478bd9Sstevel@tonic-gate 13997c478bd9Sstevel@tonic-gate if (idevice_cookiep) { 14007c478bd9Sstevel@tonic-gate idevice_cookiep->idev_vector = 0; 14017c478bd9Sstevel@tonic-gate idevice_cookiep->idev_priority = softpri; 14027c478bd9Sstevel@tonic-gate } 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate *idp = (ddi_softintr_t)hdl_p; 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: dip = 0x%p, " 14077c478bd9Sstevel@tonic-gate "idp = 0x%p, ret = %x\n", (void *)dip, (void *)*idp, ret)); 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 14107c478bd9Sstevel@tonic-gate } 14117c478bd9Sstevel@tonic-gate 14127c478bd9Sstevel@tonic-gate void 14137c478bd9Sstevel@tonic-gate ddi_remove_softintr(ddi_softintr_t id) 14147c478bd9Sstevel@tonic-gate { 14157c478bd9Sstevel@tonic-gate ddi_softint_handle_t *h_p = (ddi_softint_handle_t *)id; 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: id=0x%p\n", 14187c478bd9Sstevel@tonic-gate (void *)id)); 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate if (h_p == NULL) 14217c478bd9Sstevel@tonic-gate return; 14227c478bd9Sstevel@tonic-gate 14237c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: handle 0x%p\n", 14247c478bd9Sstevel@tonic-gate (void *)h_p)); 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate (void) ddi_intr_remove_softint(*h_p); 14277c478bd9Sstevel@tonic-gate kmem_free(h_p, sizeof (ddi_softint_handle_t)); 14287c478bd9Sstevel@tonic-gate } 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate void 14317c478bd9Sstevel@tonic-gate ddi_trigger_softintr(ddi_softintr_t id) 14327c478bd9Sstevel@tonic-gate { 14337c478bd9Sstevel@tonic-gate ddi_softint_handle_t *h_p = (ddi_softint_handle_t *)id; 14347c478bd9Sstevel@tonic-gate int ret; 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate if (h_p == NULL) 14377c478bd9Sstevel@tonic-gate return; 14387c478bd9Sstevel@tonic-gate 14397c478bd9Sstevel@tonic-gate if ((ret = ddi_intr_trigger_softint(*h_p, NULL)) != DDI_SUCCESS) { 14407c478bd9Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_trigger_softintr: " 14417c478bd9Sstevel@tonic-gate "ddi_intr_trigger_softint failed, hdlp 0x%p " 14427c478bd9Sstevel@tonic-gate "ret 0x%x\n", (void *)h_p, ret)); 14437c478bd9Sstevel@tonic-gate } 14447c478bd9Sstevel@tonic-gate } 1445