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