10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51542Sjohnny * Common Development and Distribution License (the "License").
61542Sjohnny * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*12473SScott.Carter@Oracle.COM * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate #include <sys/note.h>
260Sstevel@tonic-gate #include <sys/sysmacros.h>
270Sstevel@tonic-gate #include <sys/types.h>
280Sstevel@tonic-gate #include <sys/param.h>
290Sstevel@tonic-gate #include <sys/systm.h>
300Sstevel@tonic-gate #include <sys/kmem.h>
310Sstevel@tonic-gate #include <sys/cmn_err.h>
320Sstevel@tonic-gate #include <sys/debug.h>
330Sstevel@tonic-gate #include <sys/avintr.h>
340Sstevel@tonic-gate #include <sys/autoconf.h>
350Sstevel@tonic-gate #include <sys/sunndi.h>
360Sstevel@tonic-gate #include <sys/ndi_impldefs.h> /* include prototypes */
371725Segillett #include <sys/atomic.h>
380Sstevel@tonic-gate
390Sstevel@tonic-gate /*
400Sstevel@tonic-gate * New DDI interrupt framework
410Sstevel@tonic-gate */
420Sstevel@tonic-gate
430Sstevel@tonic-gate /*
440Sstevel@tonic-gate * ddi_intr_get_supported_types:
450Sstevel@tonic-gate * Return, as a bit mask, the hardware interrupt types supported by
460Sstevel@tonic-gate * both the device and by the host in the integer pointed
470Sstevel@tonic-gate * to be the 'typesp' argument.
480Sstevel@tonic-gate */
490Sstevel@tonic-gate int
ddi_intr_get_supported_types(dev_info_t * dip,int * typesp)500Sstevel@tonic-gate ddi_intr_get_supported_types(dev_info_t *dip, int *typesp)
510Sstevel@tonic-gate {
520Sstevel@tonic-gate int ret;
530Sstevel@tonic-gate ddi_intr_handle_impl_t hdl;
540Sstevel@tonic-gate
550Sstevel@tonic-gate if (dip == NULL)
560Sstevel@tonic-gate return (DDI_EINVAL);
570Sstevel@tonic-gate
580Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: dip %p\n",
590Sstevel@tonic-gate (void *)dip));
600Sstevel@tonic-gate
610Sstevel@tonic-gate if (*typesp = i_ddi_intr_get_supported_types(dip))
620Sstevel@tonic-gate return (DDI_SUCCESS);
630Sstevel@tonic-gate
640Sstevel@tonic-gate bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
650Sstevel@tonic-gate hdl.ih_dip = dip;
660Sstevel@tonic-gate
67693Sgovinda ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_SUPPORTED_TYPES, &hdl,
680Sstevel@tonic-gate (void *)typesp);
690Sstevel@tonic-gate
700Sstevel@tonic-gate if (ret != DDI_SUCCESS)
710Sstevel@tonic-gate return (DDI_INTR_NOTFOUND);
720Sstevel@tonic-gate
730Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_supported_types: types %x\n",
740Sstevel@tonic-gate *typesp));
750Sstevel@tonic-gate
760Sstevel@tonic-gate return (ret);
770Sstevel@tonic-gate }
780Sstevel@tonic-gate
790Sstevel@tonic-gate /*
800Sstevel@tonic-gate * ddi_intr_get_nintrs:
810Sstevel@tonic-gate * Return as an integer in the integer pointed to by the argument
820Sstevel@tonic-gate * *nintrsp*, the number of interrupts the device supports for the
830Sstevel@tonic-gate * given interrupt type.
840Sstevel@tonic-gate */
850Sstevel@tonic-gate int
ddi_intr_get_nintrs(dev_info_t * dip,int type,int * nintrsp)860Sstevel@tonic-gate ddi_intr_get_nintrs(dev_info_t *dip, int type, int *nintrsp)
870Sstevel@tonic-gate {
880Sstevel@tonic-gate int ret;
890Sstevel@tonic-gate ddi_intr_handle_impl_t hdl;
900Sstevel@tonic-gate
91693Sgovinda DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs: dip %p, type: %d\n",
92693Sgovinda (void *)dip, type));
930Sstevel@tonic-gate
948561SScott.Carter@Sun.COM if ((dip == NULL) || (nintrsp == NULL) ||
958561SScott.Carter@Sun.COM !DDI_INTR_TYPE_FLAG_VALID(type) ||
962433Sanish !(i_ddi_intr_get_supported_types(dip) & type)) {
978561SScott.Carter@Sun.COM DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs: "
988561SScott.Carter@Sun.COM "Invalid input args\n"));
990Sstevel@tonic-gate return (DDI_EINVAL);
100693Sgovinda }
1010Sstevel@tonic-gate
1020Sstevel@tonic-gate if (*nintrsp = i_ddi_intr_get_supported_nintrs(dip, type))
1030Sstevel@tonic-gate return (DDI_SUCCESS);
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
1060Sstevel@tonic-gate hdl.ih_dip = dip;
1070Sstevel@tonic-gate hdl.ih_type = type;
1080Sstevel@tonic-gate
109693Sgovinda ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_NINTRS, &hdl,
1100Sstevel@tonic-gate (void *)nintrsp);
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_nintrs:: nintrs %x\n",
1130Sstevel@tonic-gate *nintrsp));
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate return (ret);
1160Sstevel@tonic-gate }
1170Sstevel@tonic-gate
1180Sstevel@tonic-gate /*
1190Sstevel@tonic-gate * ddi_intr_get_navail:
1200Sstevel@tonic-gate * Bus nexus driver will return availble interrupt count value for
1210Sstevel@tonic-gate * a given interrupt type.
1220Sstevel@tonic-gate *
1230Sstevel@tonic-gate * Return as an integer in the integer pointed to by the argument
1240Sstevel@tonic-gate * *navailp*, the number of interrupts currently available for the
1250Sstevel@tonic-gate * given interrupt type.
1260Sstevel@tonic-gate */
1270Sstevel@tonic-gate int
ddi_intr_get_navail(dev_info_t * dip,int type,int * navailp)1280Sstevel@tonic-gate ddi_intr_get_navail(dev_info_t *dip, int type, int *navailp)
1290Sstevel@tonic-gate {
130693Sgovinda DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_navail: dip %p, type: %d\n",
131693Sgovinda (void *)dip, type));
1320Sstevel@tonic-gate
1338561SScott.Carter@Sun.COM if ((dip == NULL) || (navailp == NULL) ||
1348561SScott.Carter@Sun.COM !DDI_INTR_TYPE_FLAG_VALID(type) ||
1352433Sanish !(i_ddi_intr_get_supported_types(dip) & type)) {
1368561SScott.Carter@Sun.COM DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_navail: "
1378561SScott.Carter@Sun.COM "Invalid input args\n"));
1380Sstevel@tonic-gate return (DDI_EINVAL);
139693Sgovinda }
1400Sstevel@tonic-gate
1418561SScott.Carter@Sun.COM if ((*navailp = i_ddi_intr_get_current_navail(dip, type)) == 0)
1428561SScott.Carter@Sun.COM return (DDI_INTR_NOTFOUND);
1430Sstevel@tonic-gate
1448561SScott.Carter@Sun.COM return (DDI_SUCCESS);
1450Sstevel@tonic-gate }
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate /*
1480Sstevel@tonic-gate * Interrupt allocate/free functions
1490Sstevel@tonic-gate */
1500Sstevel@tonic-gate int
ddi_intr_alloc(dev_info_t * dip,ddi_intr_handle_t * h_array,int type,int inum,int count,int * actualp,int behavior)1510Sstevel@tonic-gate ddi_intr_alloc(dev_info_t *dip, ddi_intr_handle_t *h_array, int type, int inum,
1520Sstevel@tonic-gate int count, int *actualp, int behavior)
1530Sstevel@tonic-gate {
1540Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, tmp_hdl;
1558561SScott.Carter@Sun.COM int i, ret, cap = 0, curr_type, nintrs;
1568561SScott.Carter@Sun.COM uint_t pri, navail, curr_nintrs = 0;
1570Sstevel@tonic-gate
1580Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: name %s dip 0x%p "
1590Sstevel@tonic-gate "type %x inum %x count %x behavior %x\n", ddi_driver_name(dip),
1600Sstevel@tonic-gate (void *)dip, type, inum, count, behavior));
1610Sstevel@tonic-gate
1620Sstevel@tonic-gate /* Validate parameters */
1638561SScott.Carter@Sun.COM if ((dip == NULL) || (h_array == NULL) || (inum < 0) || (count < 1) ||
1648561SScott.Carter@Sun.COM (actualp == NULL) || !DDI_INTR_BEHAVIOR_FLAG_VALID(behavior)) {
1658561SScott.Carter@Sun.COM DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: "
1668561SScott.Carter@Sun.COM "Invalid input args\n"));
1670Sstevel@tonic-gate return (DDI_EINVAL);
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate /* Validate interrupt type */
1712433Sanish if (!DDI_INTR_TYPE_FLAG_VALID(type) ||
1722433Sanish !(i_ddi_intr_get_supported_types(dip) & type)) {
1730Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x not "
1740Sstevel@tonic-gate "supported\n", type));
1750Sstevel@tonic-gate return (DDI_EINVAL);
1760Sstevel@tonic-gate }
1770Sstevel@tonic-gate
1788561SScott.Carter@Sun.COM /* Validate inum not previously allocated */
1792433Sanish if ((type == DDI_INTR_TYPE_FIXED) &&
1802433Sanish (i_ddi_get_intr_handle(dip, inum) != NULL)) {
1812433Sanish DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: inum %d is already "
1828561SScott.Carter@Sun.COM "in use, cannot allocate again!!\n", inum));
1832433Sanish return (DDI_EINVAL);
1842433Sanish }
1852433Sanish
1868561SScott.Carter@Sun.COM /* Get how many interrupts the device supports */
1878561SScott.Carter@Sun.COM if ((nintrs = i_ddi_intr_get_supported_nintrs(dip, type)) == 0) {
1880Sstevel@tonic-gate if (ddi_intr_get_nintrs(dip, type, &nintrs) != DDI_SUCCESS) {
1890Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no "
1900Sstevel@tonic-gate "interrupts found of type %d\n", type));
1910Sstevel@tonic-gate return (DDI_INTR_NOTFOUND);
1920Sstevel@tonic-gate }
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate
1958561SScott.Carter@Sun.COM /* Get how many interrupts the device is already using */
1968561SScott.Carter@Sun.COM if ((curr_type = i_ddi_intr_get_current_type(dip)) != 0) {
1978561SScott.Carter@Sun.COM DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: type %x "
1988561SScott.Carter@Sun.COM "is already being used\n", curr_type));
1998561SScott.Carter@Sun.COM curr_nintrs = i_ddi_intr_get_current_nintrs(dip);
2008561SScott.Carter@Sun.COM }
2018561SScott.Carter@Sun.COM
2028561SScott.Carter@Sun.COM /* Validate interrupt type consistency */
2038561SScott.Carter@Sun.COM if ((curr_type != 0) && (type != curr_type)) {
2048561SScott.Carter@Sun.COM DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: Requested "
2058561SScott.Carter@Sun.COM "interrupt type %x is different from interrupt type %x"
2068561SScott.Carter@Sun.COM "already in use\n", type, curr_type));
2078561SScott.Carter@Sun.COM return (DDI_EINVAL);
2088561SScott.Carter@Sun.COM }
2098561SScott.Carter@Sun.COM
2108561SScott.Carter@Sun.COM /* Validate count does not exceed what device supports */
2110Sstevel@tonic-gate if (count > nintrs) {
2120Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: no of interrupts "
2130Sstevel@tonic-gate "requested %d is more than supported %d\n", count, nintrs));
2140Sstevel@tonic-gate return (DDI_EINVAL);
2158561SScott.Carter@Sun.COM } else if ((count + curr_nintrs) > nintrs) {
2168561SScott.Carter@Sun.COM DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: count %d "
2178561SScott.Carter@Sun.COM "+ intrs in use %d exceeds supported %d intrs\n",
2188561SScott.Carter@Sun.COM count, curr_nintrs, nintrs));
2190Sstevel@tonic-gate return (DDI_EINVAL);
2200Sstevel@tonic-gate }
2210Sstevel@tonic-gate
2228561SScott.Carter@Sun.COM /* Validate power of 2 requirements for MSI */
2238561SScott.Carter@Sun.COM if ((type == DDI_INTR_TYPE_MSI) && !ISP2(curr_nintrs + count)) {
2240Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: "
2250Sstevel@tonic-gate "MSI count %d is not a power of two\n", count));
2260Sstevel@tonic-gate return (DDI_EINVAL);
2270Sstevel@tonic-gate }
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate /*
2308561SScott.Carter@Sun.COM * Initialize the device's interrupt information structure,
2318561SScott.Carter@Sun.COM * and establish an association with IRM if it is supported.
2324974Segillett *
2338561SScott.Carter@Sun.COM * NOTE: IRM checks minimum support, and can return DDI_EAGAIN.
2340Sstevel@tonic-gate */
2358561SScott.Carter@Sun.COM if (curr_nintrs == 0) {
2368561SScott.Carter@Sun.COM i_ddi_intr_devi_init(dip);
2378561SScott.Carter@Sun.COM if (i_ddi_irm_insert(dip, type, count) == DDI_EAGAIN) {
2388561SScott.Carter@Sun.COM cmn_err(CE_WARN, "ddi_intr_alloc: "
2398561SScott.Carter@Sun.COM "cannot fit into interrupt pool\n");
2408561SScott.Carter@Sun.COM return (DDI_EAGAIN);
2418561SScott.Carter@Sun.COM }
2428561SScott.Carter@Sun.COM }
2438561SScott.Carter@Sun.COM
244*12473SScott.Carter@Oracle.COM /* Synchronously adjust IRM associations for non-IRM aware drivers */
245*12473SScott.Carter@Oracle.COM if (curr_nintrs && (i_ddi_irm_supported(dip, type) != DDI_SUCCESS))
246*12473SScott.Carter@Oracle.COM (void) i_ddi_irm_modify(dip, count + curr_nintrs);
247*12473SScott.Carter@Oracle.COM
2488561SScott.Carter@Sun.COM /* Get how many interrupts are currently available */
2498561SScott.Carter@Sun.COM navail = i_ddi_intr_get_current_navail(dip, type);
2504974Segillett
2518561SScott.Carter@Sun.COM /* Validate that requested number of interrupts are available */
2528561SScott.Carter@Sun.COM if (curr_nintrs == navail) {
2538561SScott.Carter@Sun.COM DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: max # of intrs %d "
2548561SScott.Carter@Sun.COM "already allocated\n", navail));
2558561SScott.Carter@Sun.COM return (DDI_EAGAIN);
2568561SScott.Carter@Sun.COM }
2578561SScott.Carter@Sun.COM if ((count + curr_nintrs) > navail) {
2588561SScott.Carter@Sun.COM DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: requested # of "
2598561SScott.Carter@Sun.COM "intrs %d exceeds # of available intrs %d\n", count,
2608561SScott.Carter@Sun.COM navail - curr_nintrs));
2618561SScott.Carter@Sun.COM if (behavior == DDI_INTR_ALLOC_STRICT) {
2620Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: "
2638561SScott.Carter@Sun.COM "DDI_INTR_ALLOC_STRICT flag is passed, "
2648561SScott.Carter@Sun.COM "return failure\n"));
265*12473SScott.Carter@Oracle.COM if (curr_nintrs == 0)
266*12473SScott.Carter@Oracle.COM i_ddi_intr_devi_fini(dip);
267*12473SScott.Carter@Oracle.COM else if (i_ddi_irm_supported(dip, type) != DDI_SUCCESS)
268*12473SScott.Carter@Oracle.COM (void) i_ddi_irm_modify(dip, curr_nintrs);
2698561SScott.Carter@Sun.COM return (DDI_EAGAIN);
2703625Segillett }
2718561SScott.Carter@Sun.COM count = navail - curr_nintrs;
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate /* Now allocate required number of interrupts */
2750Sstevel@tonic-gate bzero(&tmp_hdl, sizeof (ddi_intr_handle_impl_t));
2760Sstevel@tonic-gate tmp_hdl.ih_type = type;
2770Sstevel@tonic-gate tmp_hdl.ih_inum = inum;
2780Sstevel@tonic-gate tmp_hdl.ih_scratch1 = count;
2791717Swesolows tmp_hdl.ih_scratch2 = (void *)(uintptr_t)behavior;
2800Sstevel@tonic-gate tmp_hdl.ih_dip = dip;
2810Sstevel@tonic-gate
282693Sgovinda if (i_ddi_intr_ops(dip, dip, DDI_INTROP_ALLOC,
2830Sstevel@tonic-gate &tmp_hdl, (void *)actualp) != DDI_SUCCESS) {
2840Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: allocation "
2850Sstevel@tonic-gate "failed\n"));
2861725Segillett i_ddi_intr_devi_fini(dip);
2870Sstevel@tonic-gate return (*actualp ? DDI_EAGAIN : DDI_INTR_NOTFOUND);
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate
290693Sgovinda if ((ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_GETPRI,
2910Sstevel@tonic-gate &tmp_hdl, (void *)&pri)) != DDI_SUCCESS) {
2920Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get priority "
2930Sstevel@tonic-gate "failed\n"));
2941725Segillett goto fail;
2950Sstevel@tonic-gate }
2960Sstevel@tonic-gate
2970Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: getting capability\n"));
2980Sstevel@tonic-gate
299693Sgovinda if ((ret = i_ddi_intr_ops(dip, dip, DDI_INTROP_GETCAP,
3000Sstevel@tonic-gate &tmp_hdl, (void *)&cap)) != DDI_SUCCESS) {
3010Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: get capability "
3020Sstevel@tonic-gate "failed\n"));
3031725Segillett goto fail;
3040Sstevel@tonic-gate }
3050Sstevel@tonic-gate
3061725Segillett /*
3071725Segillett * Save current interrupt type, supported and current intr count.
3081725Segillett */
3090Sstevel@tonic-gate i_ddi_intr_set_current_type(dip, type);
3100Sstevel@tonic-gate i_ddi_intr_set_supported_nintrs(dip, nintrs);
3110Sstevel@tonic-gate i_ddi_intr_set_current_nintrs(dip,
3120Sstevel@tonic-gate i_ddi_intr_get_current_nintrs(dip) + *actualp);
3130Sstevel@tonic-gate
3140Sstevel@tonic-gate /* Now, go and handle each "handle" */
3158561SScott.Carter@Sun.COM for (i = inum; i < (inum + *actualp); i++) {
3160Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)kmem_zalloc(
3170Sstevel@tonic-gate (sizeof (ddi_intr_handle_impl_t)), KM_SLEEP);
3180Sstevel@tonic-gate rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
3190Sstevel@tonic-gate h_array[i] = (struct __ddi_intr_handle *)hdlp;
3200Sstevel@tonic-gate hdlp->ih_type = type;
3210Sstevel@tonic-gate hdlp->ih_pri = pri;
3220Sstevel@tonic-gate hdlp->ih_cap = cap;
3230Sstevel@tonic-gate hdlp->ih_ver = DDI_INTR_VERSION;
3240Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ALLOC;
3250Sstevel@tonic-gate hdlp->ih_dip = dip;
3268561SScott.Carter@Sun.COM hdlp->ih_inum = i;
327916Sschwartz i_ddi_alloc_intr_phdl(hdlp);
3280Sstevel@tonic-gate if (type & DDI_INTR_TYPE_FIXED)
3298561SScott.Carter@Sun.COM i_ddi_set_intr_handle(dip, hdlp->ih_inum,
3308561SScott.Carter@Sun.COM (ddi_intr_handle_t)hdlp);
3310Sstevel@tonic-gate
3320Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_alloc: hdlp = 0x%p\n",
3330Sstevel@tonic-gate (void *)h_array[i]));
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate return (DDI_SUCCESS);
3371725Segillett
3381725Segillett fail:
3391725Segillett (void) i_ddi_intr_ops(tmp_hdl.ih_dip, tmp_hdl.ih_dip,
3401725Segillett DDI_INTROP_FREE, &tmp_hdl, NULL);
3411725Segillett i_ddi_intr_devi_fini(dip);
3421725Segillett
3431725Segillett return (ret);
3440Sstevel@tonic-gate }
3450Sstevel@tonic-gate
3460Sstevel@tonic-gate int
ddi_intr_free(ddi_intr_handle_t h)3470Sstevel@tonic-gate ddi_intr_free(ddi_intr_handle_t h)
3480Sstevel@tonic-gate {
3490Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
3500Sstevel@tonic-gate int ret;
3510Sstevel@tonic-gate
3520Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_free: hdlp = %p\n", (void *)hdlp));
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate if (hdlp == NULL)
3550Sstevel@tonic-gate return (DDI_EINVAL);
3560Sstevel@tonic-gate
3570Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER);
3581725Segillett if (((hdlp->ih_flags & DDI_INTR_MSIX_DUP) &&
3591725Segillett (hdlp->ih_state != DDI_IHDL_STATE_ADDED)) ||
3601725Segillett ((hdlp->ih_state != DDI_IHDL_STATE_ALLOC) &&
3611725Segillett (!(hdlp->ih_flags & DDI_INTR_MSIX_DUP)))) {
3620Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
3630Sstevel@tonic-gate return (DDI_EINVAL);
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate
3662588Segillett /* Set the number of interrupts to free */
3672588Segillett hdlp->ih_scratch1 = 1;
3682588Segillett
369693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
3700Sstevel@tonic-gate DDI_INTROP_FREE, hdlp, NULL);
3710Sstevel@tonic-gate
3720Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
3730Sstevel@tonic-gate if (ret == DDI_SUCCESS) {
3741725Segillett /* This would be the dup vector */
3751725Segillett if (hdlp->ih_flags & DDI_INTR_MSIX_DUP)
3761725Segillett atomic_dec_32(&hdlp->ih_main->ih_dup_cnt);
3771725Segillett else {
378*12473SScott.Carter@Oracle.COM int n, curr_type;
379*12473SScott.Carter@Oracle.COM
380*12473SScott.Carter@Oracle.COM n = i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1;
381*12473SScott.Carter@Oracle.COM curr_type = i_ddi_intr_get_current_type(hdlp->ih_dip);
382*12473SScott.Carter@Oracle.COM
383*12473SScott.Carter@Oracle.COM i_ddi_intr_set_current_nintrs(hdlp->ih_dip, n);
384*12473SScott.Carter@Oracle.COM
385*12473SScott.Carter@Oracle.COM if ((i_ddi_irm_supported(hdlp->ih_dip, curr_type)
386*12473SScott.Carter@Oracle.COM != DDI_SUCCESS) && (n > 0))
387*12473SScott.Carter@Oracle.COM (void) i_ddi_irm_modify(hdlp->ih_dip, n);
3880Sstevel@tonic-gate
3892588Segillett if (hdlp->ih_type & DDI_INTR_TYPE_FIXED)
3902588Segillett i_ddi_set_intr_handle(hdlp->ih_dip,
3912588Segillett hdlp->ih_inum, NULL);
3921725Segillett
3932588Segillett i_ddi_intr_devi_fini(hdlp->ih_dip);
3941725Segillett i_ddi_free_intr_phdl(hdlp);
395693Sgovinda }
3960Sstevel@tonic-gate rw_destroy(&hdlp->ih_rwlock);
3970Sstevel@tonic-gate kmem_free(hdlp, sizeof (ddi_intr_handle_impl_t));
3980Sstevel@tonic-gate }
3990Sstevel@tonic-gate
4000Sstevel@tonic-gate return (ret);
4010Sstevel@tonic-gate }
4020Sstevel@tonic-gate
4030Sstevel@tonic-gate /*
4040Sstevel@tonic-gate * Interrupt get/set capacity functions
4050Sstevel@tonic-gate *
4060Sstevel@tonic-gate * The logic used to figure this out is shown here:
4070Sstevel@tonic-gate *
4080Sstevel@tonic-gate * Device level Platform level Intr source
4090Sstevel@tonic-gate * 1. Fixed interrupts
4100Sstevel@tonic-gate * (non-PCI)
4110Sstevel@tonic-gate * o Flags supported N/A Maskable/Pending/ rootnex
4120Sstevel@tonic-gate * No Block Enable
4130Sstevel@tonic-gate * o navail 1
4140Sstevel@tonic-gate *
4150Sstevel@tonic-gate * 2. PCI Fixed interrupts
4160Sstevel@tonic-gate * o Flags supported pending/Maskable Maskable/pending/ pci
4170Sstevel@tonic-gate * No Block enable
4180Sstevel@tonic-gate * o navail N/A 1
4190Sstevel@tonic-gate *
4200Sstevel@tonic-gate * 3. PCI MSI
4210Sstevel@tonic-gate * o Flags supported Maskable/Pending Maskable/Pending pci
4220Sstevel@tonic-gate * Block Enable (if drvr doesn't) Block Enable
4230Sstevel@tonic-gate * o navail N/A #vectors - #used N/A
4240Sstevel@tonic-gate *
4250Sstevel@tonic-gate * 4. PCI MSI-X
4260Sstevel@tonic-gate * o Flags supported Maskable/Pending Maskable/Pending pci
4270Sstevel@tonic-gate * Block Enable Block Enable
4280Sstevel@tonic-gate * o navail N/A #vectors - #used N/A
4290Sstevel@tonic-gate *
4300Sstevel@tonic-gate * where:
4310Sstevel@tonic-gate * #vectors - Total numbers of vectors available
4320Sstevel@tonic-gate * #used - Total numbers of vectors currently being used
4330Sstevel@tonic-gate *
4340Sstevel@tonic-gate * For devices complying to PCI2.3 or greater, see bit10 of Command Register
4350Sstevel@tonic-gate * 0 - enables assertion of INTx
4360Sstevel@tonic-gate * 1 - disables assertion of INTx
4370Sstevel@tonic-gate *
4380Sstevel@tonic-gate * For non MSI/X interrupts; if the IRQ is shared then all ddi_intr_set_*()
4390Sstevel@tonic-gate * operations return failure.
4400Sstevel@tonic-gate */
4410Sstevel@tonic-gate int
ddi_intr_get_cap(ddi_intr_handle_t h,int * flagsp)4420Sstevel@tonic-gate ddi_intr_get_cap(ddi_intr_handle_t h, int *flagsp)
4430Sstevel@tonic-gate {
4440Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
4450Sstevel@tonic-gate int ret;
4460Sstevel@tonic-gate
4470Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_cap: hdlp = %p\n",
4480Sstevel@tonic-gate (void *)hdlp));
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate *flagsp = 0;
4510Sstevel@tonic-gate if (hdlp == NULL)
4520Sstevel@tonic-gate return (DDI_EINVAL);
4530Sstevel@tonic-gate
4540Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER);
4550Sstevel@tonic-gate
4560Sstevel@tonic-gate if (hdlp->ih_cap) {
4570Sstevel@tonic-gate *flagsp = hdlp->ih_cap & ~DDI_INTR_FLAG_MSI64;
4580Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
4590Sstevel@tonic-gate return (DDI_SUCCESS);
4600Sstevel@tonic-gate }
4610Sstevel@tonic-gate
462693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
4630Sstevel@tonic-gate DDI_INTROP_GETCAP, hdlp, (void *)flagsp);
4640Sstevel@tonic-gate
4650Sstevel@tonic-gate if (ret == DDI_SUCCESS) {
4660Sstevel@tonic-gate hdlp->ih_cap = *flagsp;
4670Sstevel@tonic-gate
4680Sstevel@tonic-gate /* Mask out MSI/X 64-bit support to the consumer */
4690Sstevel@tonic-gate *flagsp &= ~DDI_INTR_FLAG_MSI64;
4700Sstevel@tonic-gate }
4710Sstevel@tonic-gate
4720Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
4730Sstevel@tonic-gate return (ret);
4740Sstevel@tonic-gate }
4750Sstevel@tonic-gate
4760Sstevel@tonic-gate int
ddi_intr_set_cap(ddi_intr_handle_t h,int flags)4770Sstevel@tonic-gate ddi_intr_set_cap(ddi_intr_handle_t h, int flags)
4780Sstevel@tonic-gate {
4790Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
4800Sstevel@tonic-gate int ret;
4810Sstevel@tonic-gate
4820Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_cap: hdlp = %p", (void *)hdlp));
4830Sstevel@tonic-gate
4840Sstevel@tonic-gate if (hdlp == NULL)
4850Sstevel@tonic-gate return (DDI_EINVAL);
4860Sstevel@tonic-gate
4870Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER);
4880Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
4890Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
4900Sstevel@tonic-gate return (DDI_EINVAL);
4910Sstevel@tonic-gate }
4920Sstevel@tonic-gate
4930Sstevel@tonic-gate /* Only DDI_INTR_FLAG_LEVEL or DDI_INTR_FLAG_EDGE are allowed */
4940Sstevel@tonic-gate if (!(flags & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) {
4950Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "%s%d: only LEVEL or EDGE capability "
4960Sstevel@tonic-gate "can be set\n", ddi_driver_name(hdlp->ih_dip),
4970Sstevel@tonic-gate ddi_get_instance(hdlp->ih_dip)));
4980Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
4990Sstevel@tonic-gate return (DDI_EINVAL);
5000Sstevel@tonic-gate }
5010Sstevel@tonic-gate
5020Sstevel@tonic-gate /* Both level/edge flags must be currently supported */
5030Sstevel@tonic-gate if (!(hdlp->ih_cap & (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_LEVEL))) {
5040Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "%s%d: Both LEVEL and EDGE capability"
5050Sstevel@tonic-gate " must be supported\n", ddi_driver_name(hdlp->ih_dip),
5060Sstevel@tonic-gate ddi_get_instance(hdlp->ih_dip)));
5070Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
5080Sstevel@tonic-gate return (DDI_ENOTSUP);
5090Sstevel@tonic-gate }
5100Sstevel@tonic-gate
511693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
5120Sstevel@tonic-gate DDI_INTROP_SETCAP, hdlp, &flags);
5130Sstevel@tonic-gate
5140Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
5150Sstevel@tonic-gate return (ret);
5160Sstevel@tonic-gate }
5170Sstevel@tonic-gate
5180Sstevel@tonic-gate /*
5190Sstevel@tonic-gate * Priority related functions
5200Sstevel@tonic-gate */
5210Sstevel@tonic-gate
5220Sstevel@tonic-gate /*
5230Sstevel@tonic-gate * ddi_intr_get_hilevel_pri:
5240Sstevel@tonic-gate * Returns the minimum priority level for a
5250Sstevel@tonic-gate * high-level interrupt on a platform.
5260Sstevel@tonic-gate */
5270Sstevel@tonic-gate uint_t
ddi_intr_get_hilevel_pri(void)5280Sstevel@tonic-gate ddi_intr_get_hilevel_pri(void)
5290Sstevel@tonic-gate {
5300Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_hilevel_pri:\n"));
5310Sstevel@tonic-gate return (LOCK_LEVEL + 1);
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate int
ddi_intr_get_pri(ddi_intr_handle_t h,uint_t * prip)5350Sstevel@tonic-gate ddi_intr_get_pri(ddi_intr_handle_t h, uint_t *prip)
5360Sstevel@tonic-gate {
5370Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
5380Sstevel@tonic-gate int ret;
5390Sstevel@tonic-gate
5400Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pri: hdlp = %p\n",
5410Sstevel@tonic-gate (void *)hdlp));
5420Sstevel@tonic-gate
5430Sstevel@tonic-gate *prip = 0;
5440Sstevel@tonic-gate if (hdlp == NULL)
5450Sstevel@tonic-gate return (DDI_EINVAL);
5460Sstevel@tonic-gate
5470Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER);
5480Sstevel@tonic-gate /* Already initialized, just return that */
5490Sstevel@tonic-gate if (hdlp->ih_pri) {
5500Sstevel@tonic-gate *prip = hdlp->ih_pri;
5510Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
5520Sstevel@tonic-gate return (DDI_SUCCESS);
5530Sstevel@tonic-gate }
5540Sstevel@tonic-gate
555693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
5560Sstevel@tonic-gate DDI_INTROP_GETPRI, hdlp, (void *)prip);
5570Sstevel@tonic-gate
5580Sstevel@tonic-gate if (ret == DDI_SUCCESS)
5590Sstevel@tonic-gate hdlp->ih_pri = *prip;
5600Sstevel@tonic-gate
5610Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
5620Sstevel@tonic-gate return (ret);
5630Sstevel@tonic-gate }
5640Sstevel@tonic-gate
5650Sstevel@tonic-gate int
ddi_intr_set_pri(ddi_intr_handle_t h,uint_t pri)5660Sstevel@tonic-gate ddi_intr_set_pri(ddi_intr_handle_t h, uint_t pri)
5670Sstevel@tonic-gate {
5680Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
5690Sstevel@tonic-gate int ret;
5700Sstevel@tonic-gate
5710Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: hdlp = %p", (void *)hdlp));
5720Sstevel@tonic-gate
5730Sstevel@tonic-gate if (hdlp == NULL)
5740Sstevel@tonic-gate return (DDI_EINVAL);
5750Sstevel@tonic-gate
5760Sstevel@tonic-gate /* Validate priority argument */
5770Sstevel@tonic-gate if (pri < DDI_INTR_PRI_MIN || pri > DDI_INTR_PRI_MAX) {
5780Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_pri: invalid priority "
5790Sstevel@tonic-gate "specified = %x\n", pri));
5800Sstevel@tonic-gate return (DDI_EINVAL);
5810Sstevel@tonic-gate }
5820Sstevel@tonic-gate
5830Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER);
5840Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
5850Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
5860Sstevel@tonic-gate return (DDI_EINVAL);
5870Sstevel@tonic-gate }
5880Sstevel@tonic-gate
5890Sstevel@tonic-gate /* If the passed priority is same as existing priority; do nothing */
5900Sstevel@tonic-gate if (pri == hdlp->ih_pri) {
5910Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
5920Sstevel@tonic-gate return (DDI_SUCCESS);
5930Sstevel@tonic-gate }
5940Sstevel@tonic-gate
595693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
5960Sstevel@tonic-gate DDI_INTROP_SETPRI, hdlp, &pri);
5970Sstevel@tonic-gate
5980Sstevel@tonic-gate if (ret == DDI_SUCCESS)
5990Sstevel@tonic-gate hdlp->ih_pri = pri;
6000Sstevel@tonic-gate
6010Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
6020Sstevel@tonic-gate return (ret);
6030Sstevel@tonic-gate }
6040Sstevel@tonic-gate
6050Sstevel@tonic-gate /*
6060Sstevel@tonic-gate * Interrupt add/duplicate/remove handlers
6070Sstevel@tonic-gate */
6080Sstevel@tonic-gate int
ddi_intr_add_handler(ddi_intr_handle_t h,ddi_intr_handler_t inthandler,void * arg1,void * arg2)6090Sstevel@tonic-gate ddi_intr_add_handler(ddi_intr_handle_t h, ddi_intr_handler_t inthandler,
6100Sstevel@tonic-gate void *arg1, void *arg2)
6110Sstevel@tonic-gate {
6120Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
6130Sstevel@tonic-gate int ret;
6140Sstevel@tonic-gate
6150Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_handler: hdlp = 0x%p\n",
6160Sstevel@tonic-gate (void *)hdlp));
6170Sstevel@tonic-gate
6180Sstevel@tonic-gate if ((hdlp == NULL) || (inthandler == NULL))
6190Sstevel@tonic-gate return (DDI_EINVAL);
6200Sstevel@tonic-gate
6210Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER);
6220Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ALLOC) {
6230Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
6240Sstevel@tonic-gate return (DDI_EINVAL);
6250Sstevel@tonic-gate }
6260Sstevel@tonic-gate
6270Sstevel@tonic-gate hdlp->ih_cb_func = inthandler;
6280Sstevel@tonic-gate hdlp->ih_cb_arg1 = arg1;
6290Sstevel@tonic-gate hdlp->ih_cb_arg2 = arg2;
6300Sstevel@tonic-gate
631693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
6320Sstevel@tonic-gate DDI_INTROP_ADDISR, hdlp, NULL);
6330Sstevel@tonic-gate
6340Sstevel@tonic-gate if (ret != DDI_SUCCESS) {
6350Sstevel@tonic-gate hdlp->ih_cb_func = NULL;
6360Sstevel@tonic-gate hdlp->ih_cb_arg1 = NULL;
6370Sstevel@tonic-gate hdlp->ih_cb_arg2 = NULL;
6380Sstevel@tonic-gate } else
6390Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ADDED;
6400Sstevel@tonic-gate
6410Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
6420Sstevel@tonic-gate return (ret);
6430Sstevel@tonic-gate }
6440Sstevel@tonic-gate
6450Sstevel@tonic-gate int
ddi_intr_dup_handler(ddi_intr_handle_t org,int dup_inum,ddi_intr_handle_t * dup)6461725Segillett ddi_intr_dup_handler(ddi_intr_handle_t org, int dup_inum,
6471725Segillett ddi_intr_handle_t *dup)
6480Sstevel@tonic-gate {
6490Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)org;
6500Sstevel@tonic-gate ddi_intr_handle_impl_t *dup_hdlp;
6510Sstevel@tonic-gate int ret;
6520Sstevel@tonic-gate
6530Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_dup_handler: hdlp = 0x%p\n",
6540Sstevel@tonic-gate (void *)hdlp));
6550Sstevel@tonic-gate
6561725Segillett /* Do some input argument checking ("dup" handle is not allocated) */
6572433Sanish if ((hdlp == NULL) || (*dup != NULL) || (dup_inum < 0)) {
6582433Sanish DDI_INTR_APIDBG((CE_CONT, "ddi_intr_dup_handler: Invalid "
6592433Sanish "input args\n"));
6600Sstevel@tonic-gate return (DDI_EINVAL);
6612433Sanish }
6620Sstevel@tonic-gate
6630Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER);
6640Sstevel@tonic-gate
6650Sstevel@tonic-gate /* Do some input argument checking */
6660Sstevel@tonic-gate if ((hdlp->ih_state == DDI_IHDL_STATE_ALLOC) || /* intr handle alloc? */
6671725Segillett (hdlp->ih_type != DDI_INTR_TYPE_MSIX) || /* only MSI-X allowed */
6681725Segillett (hdlp->ih_flags & DDI_INTR_MSIX_DUP)) { /* only dup original */
6690Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
6700Sstevel@tonic-gate return (DDI_EINVAL);
6710Sstevel@tonic-gate }
6720Sstevel@tonic-gate
6731725Segillett hdlp->ih_scratch1 = dup_inum;
674693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
6751725Segillett DDI_INTROP_DUPVEC, hdlp, NULL);
6760Sstevel@tonic-gate
6770Sstevel@tonic-gate if (ret == DDI_SUCCESS) {
6780Sstevel@tonic-gate dup_hdlp = (ddi_intr_handle_impl_t *)
6791725Segillett kmem_alloc(sizeof (ddi_intr_handle_impl_t), KM_SLEEP);
6801725Segillett
6811725Segillett atomic_add_32(&hdlp->ih_dup_cnt, 1);
6820Sstevel@tonic-gate
6831725Segillett *dup = (ddi_intr_handle_t)dup_hdlp;
6841725Segillett bcopy(hdlp, dup_hdlp, sizeof (ddi_intr_handle_impl_t));
6851725Segillett
6861725Segillett /* These fields are unique to each dupped msi-x vector */
6870Sstevel@tonic-gate rw_init(&dup_hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
6880Sstevel@tonic-gate dup_hdlp->ih_state = DDI_IHDL_STATE_ADDED;
6891725Segillett dup_hdlp->ih_inum = dup_inum;
6901725Segillett dup_hdlp->ih_flags |= DDI_INTR_MSIX_DUP;
6911725Segillett dup_hdlp->ih_dup_cnt = 0;
6920Sstevel@tonic-gate
6931725Segillett /* Point back to original vector */
6941725Segillett dup_hdlp->ih_main = hdlp;
6950Sstevel@tonic-gate }
6960Sstevel@tonic-gate
6970Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
6980Sstevel@tonic-gate return (ret);
6990Sstevel@tonic-gate }
7000Sstevel@tonic-gate
7010Sstevel@tonic-gate int
ddi_intr_remove_handler(ddi_intr_handle_t h)7020Sstevel@tonic-gate ddi_intr_remove_handler(ddi_intr_handle_t h)
7030Sstevel@tonic-gate {
7040Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
7051725Segillett int ret = DDI_SUCCESS;
7060Sstevel@tonic-gate
7070Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_handler: hdlp = %p\n",
7080Sstevel@tonic-gate (void *)hdlp));
7090Sstevel@tonic-gate
7100Sstevel@tonic-gate if (hdlp == NULL)
7110Sstevel@tonic-gate return (DDI_EINVAL);
7120Sstevel@tonic-gate
7130Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER);
7141725Segillett
7150Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ADDED) {
7161725Segillett ret = DDI_EINVAL;
7171725Segillett goto done;
7181725Segillett } else if (hdlp->ih_flags & DDI_INTR_MSIX_DUP)
7191725Segillett goto done;
7201725Segillett
7211725Segillett ASSERT(hdlp->ih_dup_cnt == 0);
7221725Segillett if (hdlp->ih_dup_cnt > 0) {
7231725Segillett DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_handler: MSI-X "
7241725Segillett "dup_cnt %d is not 0\n", hdlp->ih_dup_cnt));
7251725Segillett ret = DDI_FAILURE;
7261725Segillett goto done;
7270Sstevel@tonic-gate }
7280Sstevel@tonic-gate
729693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
7300Sstevel@tonic-gate DDI_INTROP_REMISR, hdlp, NULL);
7310Sstevel@tonic-gate
7320Sstevel@tonic-gate if (ret == DDI_SUCCESS) {
7330Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ALLOC;
7340Sstevel@tonic-gate hdlp->ih_cb_func = NULL;
7350Sstevel@tonic-gate hdlp->ih_cb_arg1 = NULL;
7360Sstevel@tonic-gate hdlp->ih_cb_arg2 = NULL;
7370Sstevel@tonic-gate }
7380Sstevel@tonic-gate
7391725Segillett done:
7400Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
7410Sstevel@tonic-gate return (ret);
7420Sstevel@tonic-gate }
7430Sstevel@tonic-gate
74410053SEvan.Yan@Sun.COM
74510053SEvan.Yan@Sun.COM /*
7460Sstevel@tonic-gate * Interrupt enable/disable/block_enable/block_disable handlers
7470Sstevel@tonic-gate */
7480Sstevel@tonic-gate int
ddi_intr_enable(ddi_intr_handle_t h)7490Sstevel@tonic-gate ddi_intr_enable(ddi_intr_handle_t h)
7500Sstevel@tonic-gate {
7510Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
7520Sstevel@tonic-gate int ret;
7530Sstevel@tonic-gate
7540Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_enable: hdlp = %p\n",
7550Sstevel@tonic-gate (void *)hdlp));
7560Sstevel@tonic-gate
7570Sstevel@tonic-gate if (hdlp == NULL)
7580Sstevel@tonic-gate return (DDI_EINVAL);
7590Sstevel@tonic-gate
7600Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER);
7610Sstevel@tonic-gate if ((hdlp->ih_state != DDI_IHDL_STATE_ADDED) ||
7620Sstevel@tonic-gate ((hdlp->ih_type == DDI_INTR_TYPE_MSI) &&
7630Sstevel@tonic-gate (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) {
7640Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
7650Sstevel@tonic-gate return (DDI_EINVAL);
7660Sstevel@tonic-gate }
7670Sstevel@tonic-gate
7681725Segillett I_DDI_VERIFY_MSIX_HANDLE(hdlp);
7691725Segillett
770693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
7710Sstevel@tonic-gate DDI_INTROP_ENABLE, hdlp, NULL);
7720Sstevel@tonic-gate
7738817SKerry.Shu@Sun.COM if (ret == DDI_SUCCESS) {
7740Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ENABLE;
7758817SKerry.Shu@Sun.COM i_ddi_intr_set_current_nenables(hdlp->ih_dip,
7768817SKerry.Shu@Sun.COM i_ddi_intr_get_current_nenables(hdlp->ih_dip) + 1);
7778817SKerry.Shu@Sun.COM }
7780Sstevel@tonic-gate
7790Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
7800Sstevel@tonic-gate return (ret);
7810Sstevel@tonic-gate }
7820Sstevel@tonic-gate
7830Sstevel@tonic-gate int
ddi_intr_disable(ddi_intr_handle_t h)7840Sstevel@tonic-gate ddi_intr_disable(ddi_intr_handle_t h)
7850Sstevel@tonic-gate {
7860Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
7870Sstevel@tonic-gate int ret;
7880Sstevel@tonic-gate
7890Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_disable: hdlp = %p\n",
7900Sstevel@tonic-gate (void *)hdlp));
7910Sstevel@tonic-gate
7920Sstevel@tonic-gate if (hdlp == NULL)
7930Sstevel@tonic-gate return (DDI_EINVAL);
7940Sstevel@tonic-gate
7950Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER);
7960Sstevel@tonic-gate if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
7970Sstevel@tonic-gate ((hdlp->ih_type == DDI_INTR_TYPE_MSI) &&
7980Sstevel@tonic-gate (hdlp->ih_cap & DDI_INTR_FLAG_BLOCK))) {
7990Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
8000Sstevel@tonic-gate return (DDI_EINVAL);
8010Sstevel@tonic-gate }
8020Sstevel@tonic-gate
8031725Segillett I_DDI_VERIFY_MSIX_HANDLE(hdlp);
8041725Segillett
805693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
8060Sstevel@tonic-gate DDI_INTROP_DISABLE, hdlp, NULL);
8070Sstevel@tonic-gate
8088817SKerry.Shu@Sun.COM if (ret == DDI_SUCCESS) {
8090Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ADDED;
8108817SKerry.Shu@Sun.COM i_ddi_intr_set_current_nenables(hdlp->ih_dip,
8118817SKerry.Shu@Sun.COM i_ddi_intr_get_current_nenables(hdlp->ih_dip) - 1);
8128817SKerry.Shu@Sun.COM }
8130Sstevel@tonic-gate
8140Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
8150Sstevel@tonic-gate return (ret);
8160Sstevel@tonic-gate }
8170Sstevel@tonic-gate
8180Sstevel@tonic-gate int
ddi_intr_block_enable(ddi_intr_handle_t * h_array,int count)8190Sstevel@tonic-gate ddi_intr_block_enable(ddi_intr_handle_t *h_array, int count)
8200Sstevel@tonic-gate {
8210Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp;
8220Sstevel@tonic-gate int i, ret;
8230Sstevel@tonic-gate
8240Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_enable: h_array = %p\n",
8250Sstevel@tonic-gate (void *)h_array));
8260Sstevel@tonic-gate
8270Sstevel@tonic-gate if (h_array == NULL)
8280Sstevel@tonic-gate return (DDI_EINVAL);
8290Sstevel@tonic-gate
8300Sstevel@tonic-gate for (i = 0; i < count; i++) {
8310Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[i];
8320Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER);
8330Sstevel@tonic-gate
8340Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ADDED ||
8350Sstevel@tonic-gate hdlp->ih_type != DDI_INTR_TYPE_MSI ||
8360Sstevel@tonic-gate !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) {
8370Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
8380Sstevel@tonic-gate return (DDI_EINVAL);
8390Sstevel@tonic-gate }
8400Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
8410Sstevel@tonic-gate }
8420Sstevel@tonic-gate
8430Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[0];
8440Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER);
8450Sstevel@tonic-gate hdlp->ih_scratch1 = count;
8461542Sjohnny hdlp->ih_scratch2 = (void *)h_array;
8470Sstevel@tonic-gate
848693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
8490Sstevel@tonic-gate DDI_INTROP_BLOCKENABLE, hdlp, NULL);
8500Sstevel@tonic-gate
8510Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
8520Sstevel@tonic-gate
8530Sstevel@tonic-gate if (ret == DDI_SUCCESS) {
8540Sstevel@tonic-gate for (i = 0; i < count; i++) {
8550Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[i];
8560Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER);
8570Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ENABLE;
8580Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
8590Sstevel@tonic-gate }
8608817SKerry.Shu@Sun.COM i_ddi_intr_set_current_nenables(hdlp->ih_dip, 1);
8610Sstevel@tonic-gate }
8620Sstevel@tonic-gate
8630Sstevel@tonic-gate return (ret);
8640Sstevel@tonic-gate }
8650Sstevel@tonic-gate
8660Sstevel@tonic-gate int
ddi_intr_block_disable(ddi_intr_handle_t * h_array,int count)8670Sstevel@tonic-gate ddi_intr_block_disable(ddi_intr_handle_t *h_array, int count)
8680Sstevel@tonic-gate {
8690Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp;
8700Sstevel@tonic-gate int i, ret;
8710Sstevel@tonic-gate
8720Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_block_disable: h_array = %p\n",
8730Sstevel@tonic-gate (void *)h_array));
8740Sstevel@tonic-gate
8750Sstevel@tonic-gate if (h_array == NULL)
8760Sstevel@tonic-gate return (DDI_EINVAL);
8770Sstevel@tonic-gate
8780Sstevel@tonic-gate for (i = 0; i < count; i++) {
8790Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[i];
8800Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER);
8810Sstevel@tonic-gate if (hdlp->ih_state != DDI_IHDL_STATE_ENABLE ||
8820Sstevel@tonic-gate hdlp->ih_type != DDI_INTR_TYPE_MSI ||
8830Sstevel@tonic-gate !(hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) {
8840Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
8850Sstevel@tonic-gate return (DDI_EINVAL);
8860Sstevel@tonic-gate }
8870Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
8880Sstevel@tonic-gate }
8890Sstevel@tonic-gate
8900Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[0];
8910Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER);
8920Sstevel@tonic-gate hdlp->ih_scratch1 = count;
8931542Sjohnny hdlp->ih_scratch2 = (void *)h_array;
8940Sstevel@tonic-gate
895693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
8960Sstevel@tonic-gate DDI_INTROP_BLOCKDISABLE, hdlp, NULL);
8970Sstevel@tonic-gate
8980Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
8990Sstevel@tonic-gate
9000Sstevel@tonic-gate if (ret == DDI_SUCCESS) {
9010Sstevel@tonic-gate for (i = 0; i < count; i++) {
9020Sstevel@tonic-gate hdlp = (ddi_intr_handle_impl_t *)h_array[i];
9030Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER);
9040Sstevel@tonic-gate hdlp->ih_state = DDI_IHDL_STATE_ADDED;
9050Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
9060Sstevel@tonic-gate }
9078817SKerry.Shu@Sun.COM i_ddi_intr_set_current_nenables(hdlp->ih_dip, 0);
9080Sstevel@tonic-gate }
9090Sstevel@tonic-gate
9100Sstevel@tonic-gate return (ret);
9110Sstevel@tonic-gate }
9120Sstevel@tonic-gate
9130Sstevel@tonic-gate /*
9140Sstevel@tonic-gate * Interrupt set/clr mask handlers
9150Sstevel@tonic-gate */
9160Sstevel@tonic-gate int
ddi_intr_set_mask(ddi_intr_handle_t h)9170Sstevel@tonic-gate ddi_intr_set_mask(ddi_intr_handle_t h)
9180Sstevel@tonic-gate {
9190Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
9200Sstevel@tonic-gate int ret;
9210Sstevel@tonic-gate
9220Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_mask: hdlp = %p\n",
9230Sstevel@tonic-gate (void *)hdlp));
9240Sstevel@tonic-gate
9250Sstevel@tonic-gate if (hdlp == NULL)
9260Sstevel@tonic-gate return (DDI_EINVAL);
9270Sstevel@tonic-gate
9280Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER);
9291653Sgovinda if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
9301653Sgovinda (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE))) {
9310Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
9320Sstevel@tonic-gate return (DDI_EINVAL);
9330Sstevel@tonic-gate }
9340Sstevel@tonic-gate
935693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
9360Sstevel@tonic-gate DDI_INTROP_SETMASK, hdlp, NULL);
9370Sstevel@tonic-gate
9380Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
9390Sstevel@tonic-gate return (ret);
9400Sstevel@tonic-gate }
9410Sstevel@tonic-gate
9420Sstevel@tonic-gate int
ddi_intr_clr_mask(ddi_intr_handle_t h)9430Sstevel@tonic-gate ddi_intr_clr_mask(ddi_intr_handle_t h)
9440Sstevel@tonic-gate {
9450Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
9460Sstevel@tonic-gate int ret;
9470Sstevel@tonic-gate
9480Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_clr_mask: hdlp = %p\n",
9490Sstevel@tonic-gate (void *)hdlp));
9500Sstevel@tonic-gate
9510Sstevel@tonic-gate if (hdlp == NULL)
9520Sstevel@tonic-gate return (DDI_EINVAL);
9530Sstevel@tonic-gate
9540Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER);
9551653Sgovinda if ((hdlp->ih_state != DDI_IHDL_STATE_ENABLE) ||
9561653Sgovinda (!(hdlp->ih_cap & DDI_INTR_FLAG_MASKABLE))) {
9570Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
9580Sstevel@tonic-gate return (DDI_EINVAL);
9590Sstevel@tonic-gate }
9600Sstevel@tonic-gate
961693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
9620Sstevel@tonic-gate DDI_INTROP_CLRMASK, hdlp, NULL);
9630Sstevel@tonic-gate
9640Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
9650Sstevel@tonic-gate return (ret);
9660Sstevel@tonic-gate }
9670Sstevel@tonic-gate
9680Sstevel@tonic-gate /*
9690Sstevel@tonic-gate * Interrupt get_pending handler
9700Sstevel@tonic-gate */
9710Sstevel@tonic-gate int
ddi_intr_get_pending(ddi_intr_handle_t h,int * pendingp)9720Sstevel@tonic-gate ddi_intr_get_pending(ddi_intr_handle_t h, int *pendingp)
9730Sstevel@tonic-gate {
9740Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp = (ddi_intr_handle_impl_t *)h;
9750Sstevel@tonic-gate int ret;
9760Sstevel@tonic-gate
9770Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_pending: hdlp = %p\n",
9780Sstevel@tonic-gate (void *)hdlp));
9790Sstevel@tonic-gate
9800Sstevel@tonic-gate if (hdlp == NULL)
9810Sstevel@tonic-gate return (DDI_EINVAL);
9820Sstevel@tonic-gate
9830Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER);
9840Sstevel@tonic-gate if (!(hdlp->ih_cap & DDI_INTR_FLAG_PENDING)) {
9850Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
9860Sstevel@tonic-gate return (DDI_EINVAL);
9870Sstevel@tonic-gate }
9880Sstevel@tonic-gate
989693Sgovinda ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
9900Sstevel@tonic-gate DDI_INTROP_GETPENDING, hdlp, (void *)pendingp);
9910Sstevel@tonic-gate
9920Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
9930Sstevel@tonic-gate return (ret);
9940Sstevel@tonic-gate }
9950Sstevel@tonic-gate
9960Sstevel@tonic-gate /*
99710053SEvan.Yan@Sun.COM * Set the number of interrupts requested from IRM
99810053SEvan.Yan@Sun.COM */
99910053SEvan.Yan@Sun.COM int
ddi_intr_set_nreq(dev_info_t * dip,int nreq)100010053SEvan.Yan@Sun.COM ddi_intr_set_nreq(dev_info_t *dip, int nreq)
100110053SEvan.Yan@Sun.COM {
1002*12473SScott.Carter@Oracle.COM int curr_type, nintrs;
1003*12473SScott.Carter@Oracle.COM
100410053SEvan.Yan@Sun.COM DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_nreq: dip %p, nreq %d\n",
100510053SEvan.Yan@Sun.COM (void *)dip, nreq));
100610053SEvan.Yan@Sun.COM
1007*12473SScott.Carter@Oracle.COM ASSERT(dip != NULL);
1008*12473SScott.Carter@Oracle.COM ASSERT(nreq > 0);
1009*12473SScott.Carter@Oracle.COM
1010*12473SScott.Carter@Oracle.COM /* Sanity check inputs */
1011*12473SScott.Carter@Oracle.COM if ((dip == NULL) || (nreq < 1))
1012*12473SScott.Carter@Oracle.COM return (DDI_EINVAL);
1013*12473SScott.Carter@Oracle.COM
1014*12473SScott.Carter@Oracle.COM curr_type = i_ddi_intr_get_current_type(dip);
1015*12473SScott.Carter@Oracle.COM
1016*12473SScott.Carter@Oracle.COM /* Only valid for IRM drivers actively using interrupts */
1017*12473SScott.Carter@Oracle.COM if ((curr_type == 0) ||
1018*12473SScott.Carter@Oracle.COM (i_ddi_irm_supported(dip, curr_type) != DDI_SUCCESS))
1019*12473SScott.Carter@Oracle.COM return (DDI_ENOTSUP);
1020*12473SScott.Carter@Oracle.COM
1021*12473SScott.Carter@Oracle.COM /* Range check */
1022*12473SScott.Carter@Oracle.COM if (ddi_intr_get_nintrs(dip, curr_type, &nintrs) != DDI_SUCCESS)
1023*12473SScott.Carter@Oracle.COM return (DDI_FAILURE);
1024*12473SScott.Carter@Oracle.COM if (nreq > nintrs)
102510053SEvan.Yan@Sun.COM return (DDI_EINVAL);
102610053SEvan.Yan@Sun.COM
102710053SEvan.Yan@Sun.COM return (i_ddi_irm_modify(dip, nreq));
102810053SEvan.Yan@Sun.COM }
102910053SEvan.Yan@Sun.COM
103010053SEvan.Yan@Sun.COM /*
10310Sstevel@tonic-gate * Soft interrupt handlers
10320Sstevel@tonic-gate */
10330Sstevel@tonic-gate /*
10340Sstevel@tonic-gate * Add a soft interrupt and register its handler
10350Sstevel@tonic-gate */
10360Sstevel@tonic-gate /* ARGSUSED */
10370Sstevel@tonic-gate int
ddi_intr_add_softint(dev_info_t * dip,ddi_softint_handle_t * h_p,int soft_pri,ddi_intr_handler_t handler,void * arg1)10380Sstevel@tonic-gate ddi_intr_add_softint(dev_info_t *dip, ddi_softint_handle_t *h_p, int soft_pri,
10390Sstevel@tonic-gate ddi_intr_handler_t handler, void *arg1)
10400Sstevel@tonic-gate {
10410Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp;
10420Sstevel@tonic-gate int ret;
10430Sstevel@tonic-gate
10440Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: dip = %p, "
10450Sstevel@tonic-gate "softpri = 0x%x\n", (void *)dip, soft_pri));
10460Sstevel@tonic-gate
10470Sstevel@tonic-gate if ((dip == NULL) || (h_p == NULL) || (handler == NULL)) {
10480Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: "
10490Sstevel@tonic-gate "invalid arguments"));
10500Sstevel@tonic-gate
10510Sstevel@tonic-gate return (DDI_EINVAL);
10520Sstevel@tonic-gate }
10530Sstevel@tonic-gate
10540Sstevel@tonic-gate /* Validate input arguments */
10550Sstevel@tonic-gate if (soft_pri < DDI_INTR_SOFTPRI_MIN ||
10560Sstevel@tonic-gate soft_pri > DDI_INTR_SOFTPRI_MAX) {
10570Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: invalid "
10580Sstevel@tonic-gate "soft_pri input given = %x\n", soft_pri));
10590Sstevel@tonic-gate return (DDI_EINVAL);
10600Sstevel@tonic-gate }
10610Sstevel@tonic-gate
10620Sstevel@tonic-gate hdlp = (ddi_softint_hdl_impl_t *)kmem_zalloc(
10630Sstevel@tonic-gate sizeof (ddi_softint_hdl_impl_t), KM_SLEEP);
10640Sstevel@tonic-gate
10650Sstevel@tonic-gate /* fill up internally */
10660Sstevel@tonic-gate rw_init(&hdlp->ih_rwlock, NULL, RW_DRIVER, NULL);
10670Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER);
10680Sstevel@tonic-gate hdlp->ih_pri = soft_pri;
10690Sstevel@tonic-gate hdlp->ih_dip = dip;
10700Sstevel@tonic-gate hdlp->ih_cb_func = handler;
10710Sstevel@tonic-gate hdlp->ih_cb_arg1 = arg1;
10720Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_add_softint: hdlp = %p\n",
10730Sstevel@tonic-gate (void *)hdlp));
10740Sstevel@tonic-gate
10750Sstevel@tonic-gate /* do the platform specific calls */
10760Sstevel@tonic-gate if ((ret = i_ddi_add_softint(hdlp)) != DDI_SUCCESS) {
10770Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
10780Sstevel@tonic-gate rw_destroy(&hdlp->ih_rwlock);
10790Sstevel@tonic-gate kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t));
10800Sstevel@tonic-gate return (ret);
10810Sstevel@tonic-gate }
10820Sstevel@tonic-gate
10830Sstevel@tonic-gate *h_p = (ddi_softint_handle_t)hdlp;
10840Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
10850Sstevel@tonic-gate return (ret);
10860Sstevel@tonic-gate }
10870Sstevel@tonic-gate
10880Sstevel@tonic-gate /*
10890Sstevel@tonic-gate * Remove the soft interrupt
10900Sstevel@tonic-gate */
10910Sstevel@tonic-gate int
ddi_intr_remove_softint(ddi_softint_handle_t h)10920Sstevel@tonic-gate ddi_intr_remove_softint(ddi_softint_handle_t h)
10930Sstevel@tonic-gate {
10940Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h;
10950Sstevel@tonic-gate
10960Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_remove_softint: hdlp = %p\n",
10970Sstevel@tonic-gate (void *)hdlp));
10980Sstevel@tonic-gate
10990Sstevel@tonic-gate if (hdlp == NULL)
11000Sstevel@tonic-gate return (DDI_EINVAL);
11010Sstevel@tonic-gate
11020Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER);
11030Sstevel@tonic-gate i_ddi_remove_softint(hdlp);
11040Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
11050Sstevel@tonic-gate rw_destroy(&hdlp->ih_rwlock);
11060Sstevel@tonic-gate
11070Sstevel@tonic-gate /* kmem_free the hdl impl_t structure allocated earlier */
11080Sstevel@tonic-gate kmem_free(hdlp, sizeof (ddi_softint_hdl_impl_t));
11090Sstevel@tonic-gate return (DDI_SUCCESS);
11100Sstevel@tonic-gate }
11110Sstevel@tonic-gate
11120Sstevel@tonic-gate /*
11130Sstevel@tonic-gate * Trigger a soft interrupt
11140Sstevel@tonic-gate */
11150Sstevel@tonic-gate int
ddi_intr_trigger_softint(ddi_softint_handle_t h,void * arg2)11160Sstevel@tonic-gate ddi_intr_trigger_softint(ddi_softint_handle_t h, void *arg2)
11170Sstevel@tonic-gate {
11180Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h;
11190Sstevel@tonic-gate int ret;
11200Sstevel@tonic-gate
11210Sstevel@tonic-gate if (hdlp == NULL)
11220Sstevel@tonic-gate return (DDI_EINVAL);
11230Sstevel@tonic-gate
1124278Sgovinda if ((ret = i_ddi_trigger_softint(hdlp, arg2)) != DDI_SUCCESS) {
11250Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_trigger_softint: failed, "
11260Sstevel@tonic-gate " ret 0%x\n", ret));
1127278Sgovinda
1128278Sgovinda return (ret);
11290Sstevel@tonic-gate }
11300Sstevel@tonic-gate
1131278Sgovinda hdlp->ih_cb_arg2 = arg2;
1132278Sgovinda return (DDI_SUCCESS);
11330Sstevel@tonic-gate }
11340Sstevel@tonic-gate
11350Sstevel@tonic-gate /*
11360Sstevel@tonic-gate * Get the soft interrupt priority
11370Sstevel@tonic-gate */
11380Sstevel@tonic-gate int
ddi_intr_get_softint_pri(ddi_softint_handle_t h,uint_t * soft_prip)11390Sstevel@tonic-gate ddi_intr_get_softint_pri(ddi_softint_handle_t h, uint_t *soft_prip)
11400Sstevel@tonic-gate {
11410Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h;
11420Sstevel@tonic-gate
11430Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_get_softint_pri: h = %p\n",
11440Sstevel@tonic-gate (void *)h));
11450Sstevel@tonic-gate
11460Sstevel@tonic-gate if (hdlp == NULL)
11470Sstevel@tonic-gate return (DDI_EINVAL);
11480Sstevel@tonic-gate
11490Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_READER);
11500Sstevel@tonic-gate *soft_prip = hdlp->ih_pri;
11510Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
11520Sstevel@tonic-gate return (DDI_SUCCESS);
11530Sstevel@tonic-gate }
11540Sstevel@tonic-gate
11550Sstevel@tonic-gate /*
11560Sstevel@tonic-gate * Set the soft interrupt priority
11570Sstevel@tonic-gate */
11580Sstevel@tonic-gate int
ddi_intr_set_softint_pri(ddi_softint_handle_t h,uint_t soft_pri)11590Sstevel@tonic-gate ddi_intr_set_softint_pri(ddi_softint_handle_t h, uint_t soft_pri)
11600Sstevel@tonic-gate {
11610Sstevel@tonic-gate ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)h;
11620Sstevel@tonic-gate int ret;
11630Sstevel@tonic-gate uint_t orig_soft_pri;
11640Sstevel@tonic-gate
11650Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: h = %p\n",
11660Sstevel@tonic-gate (void *)h));
11670Sstevel@tonic-gate
11680Sstevel@tonic-gate if (hdlp == NULL)
11690Sstevel@tonic-gate return (DDI_EINVAL);
11700Sstevel@tonic-gate
11710Sstevel@tonic-gate /* Validate priority argument */
11720Sstevel@tonic-gate if (soft_pri < DDI_INTR_SOFTPRI_MIN ||
11730Sstevel@tonic-gate soft_pri > DDI_INTR_SOFTPRI_MAX) {
11740Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: invalid "
11750Sstevel@tonic-gate "soft_pri input given = %x\n", soft_pri));
11760Sstevel@tonic-gate return (DDI_EINVAL);
11770Sstevel@tonic-gate }
11780Sstevel@tonic-gate
11790Sstevel@tonic-gate rw_enter(&hdlp->ih_rwlock, RW_WRITER);
11800Sstevel@tonic-gate orig_soft_pri = hdlp->ih_pri;
11810Sstevel@tonic-gate hdlp->ih_pri = soft_pri;
11820Sstevel@tonic-gate
11830Sstevel@tonic-gate if ((ret = i_ddi_set_softint_pri(hdlp, orig_soft_pri)) != DDI_SUCCESS) {
11840Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_set_softint_pri: failed, "
11850Sstevel@tonic-gate " ret 0%x\n", ret));
11860Sstevel@tonic-gate hdlp->ih_pri = orig_soft_pri;
11870Sstevel@tonic-gate }
11880Sstevel@tonic-gate
11890Sstevel@tonic-gate rw_exit(&hdlp->ih_rwlock);
11900Sstevel@tonic-gate return (ret);
11910Sstevel@tonic-gate }
11920Sstevel@tonic-gate
11930Sstevel@tonic-gate /*
11940Sstevel@tonic-gate * Old DDI interrupt framework
1195693Sgovinda *
1196693Sgovinda * The following DDI interrupt interfaces are obsolete.
1197693Sgovinda * Use the above new DDI interrupt interfaces instead.
11980Sstevel@tonic-gate */
11990Sstevel@tonic-gate
12000Sstevel@tonic-gate int
ddi_intr_hilevel(dev_info_t * dip,uint_t inumber)12010Sstevel@tonic-gate ddi_intr_hilevel(dev_info_t *dip, uint_t inumber)
12020Sstevel@tonic-gate {
12038561SScott.Carter@Sun.COM ddi_intr_handle_t hdl;
12048561SScott.Carter@Sun.COM ddi_intr_handle_t *hdl_p;
12058561SScott.Carter@Sun.COM size_t hdl_sz = 0;
12060Sstevel@tonic-gate int actual, ret;
12070Sstevel@tonic-gate uint_t high_pri, pri;
12080Sstevel@tonic-gate
12090Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: name=%s%d dip=0x%p "
12100Sstevel@tonic-gate "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
12110Sstevel@tonic-gate (void *)dip, inumber));
12120Sstevel@tonic-gate
12130Sstevel@tonic-gate /*
12140Sstevel@tonic-gate * The device driver may have already registed with the
12150Sstevel@tonic-gate * framework. If so, first try to get the existing interrupt handle
12160Sstevel@tonic-gate * for that given inumber and use that handle.
12170Sstevel@tonic-gate */
12188561SScott.Carter@Sun.COM if ((hdl = i_ddi_get_intr_handle(dip, inumber)) == NULL) {
12198561SScott.Carter@Sun.COM hdl_sz = sizeof (ddi_intr_handle_t) * (inumber + 1);
12208561SScott.Carter@Sun.COM hdl_p = kmem_zalloc(hdl_sz, KM_SLEEP);
12218561SScott.Carter@Sun.COM if ((ret = ddi_intr_alloc(dip, hdl_p, DDI_INTR_TYPE_FIXED,
1222965Sgovinda inumber, 1, &actual,
1223965Sgovinda DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) {
12240Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: "
12250Sstevel@tonic-gate "ddi_intr_alloc failed, ret 0x%x\n", ret));
12268561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz);
12270Sstevel@tonic-gate return (0);
12280Sstevel@tonic-gate }
12298561SScott.Carter@Sun.COM hdl = hdl_p[inumber];
12300Sstevel@tonic-gate }
12310Sstevel@tonic-gate
12320Sstevel@tonic-gate if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) {
12330Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: "
12340Sstevel@tonic-gate "ddi_intr_get_pri failed, ret 0x%x\n", ret));
12350Sstevel@tonic-gate (void) ddi_intr_free(hdl);
12368561SScott.Carter@Sun.COM if (hdl_sz)
12378561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz);
12380Sstevel@tonic-gate return (0);
12390Sstevel@tonic-gate }
12400Sstevel@tonic-gate
12410Sstevel@tonic-gate high_pri = ddi_intr_get_hilevel_pri();
12420Sstevel@tonic-gate
12430Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_intr_hilevel: pri = %x, "
12440Sstevel@tonic-gate "high_pri = %x\n", pri, high_pri));
12450Sstevel@tonic-gate
12460Sstevel@tonic-gate /* Free the handle allocated here only if no existing handle exists */
12478561SScott.Carter@Sun.COM if (hdl_sz) {
12480Sstevel@tonic-gate (void) ddi_intr_free(hdl);
12498561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz);
12508561SScott.Carter@Sun.COM }
12510Sstevel@tonic-gate
12520Sstevel@tonic-gate return (pri >= high_pri);
12530Sstevel@tonic-gate }
12540Sstevel@tonic-gate
12550Sstevel@tonic-gate int
ddi_dev_nintrs(dev_info_t * dip,int * result)12560Sstevel@tonic-gate ddi_dev_nintrs(dev_info_t *dip, int *result)
12570Sstevel@tonic-gate {
12580Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: name=%s%d dip=0x%p\n",
12590Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), (void *)dip));
12600Sstevel@tonic-gate
12610Sstevel@tonic-gate if (ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED,
12620Sstevel@tonic-gate result) != DDI_SUCCESS) {
12630Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_dev_nintrs: "
12640Sstevel@tonic-gate "ddi_intr_get_nintrs failed\n"));
12650Sstevel@tonic-gate *result = 0;
12660Sstevel@tonic-gate }
12670Sstevel@tonic-gate
12680Sstevel@tonic-gate return (DDI_SUCCESS);
12690Sstevel@tonic-gate }
12700Sstevel@tonic-gate
12710Sstevel@tonic-gate int
ddi_get_iblock_cookie(dev_info_t * dip,uint_t inumber,ddi_iblock_cookie_t * iblock_cookiep)12720Sstevel@tonic-gate ddi_get_iblock_cookie(dev_info_t *dip, uint_t inumber,
12730Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep)
12740Sstevel@tonic-gate {
12758561SScott.Carter@Sun.COM ddi_intr_handle_t hdl;
12768561SScott.Carter@Sun.COM ddi_intr_handle_t *hdl_p;
12778561SScott.Carter@Sun.COM size_t hdl_sz = 0;
12780Sstevel@tonic-gate int actual, ret;
12790Sstevel@tonic-gate uint_t pri;
12800Sstevel@tonic-gate
12810Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: name=%s%d dip=0x%p "
12820Sstevel@tonic-gate "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
12830Sstevel@tonic-gate (void *)dip, inumber));
12840Sstevel@tonic-gate
12850Sstevel@tonic-gate ASSERT(iblock_cookiep != NULL);
12860Sstevel@tonic-gate
12870Sstevel@tonic-gate /*
12880Sstevel@tonic-gate * The device driver may have already registed with the
12890Sstevel@tonic-gate * framework. If so, first try to get the existing interrupt handle
12900Sstevel@tonic-gate * for that given inumber and use that handle.
12910Sstevel@tonic-gate */
12928561SScott.Carter@Sun.COM if ((hdl = i_ddi_get_intr_handle(dip, inumber)) == NULL) {
12938561SScott.Carter@Sun.COM hdl_sz = sizeof (ddi_intr_handle_t) * (inumber + 1);
12948561SScott.Carter@Sun.COM hdl_p = kmem_zalloc(hdl_sz, KM_SLEEP);
12958561SScott.Carter@Sun.COM if ((ret = ddi_intr_alloc(dip, hdl_p,
12968561SScott.Carter@Sun.COM DDI_INTR_TYPE_FIXED, inumber, 1, &actual,
1297965Sgovinda DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) {
12980Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: "
12990Sstevel@tonic-gate "ddi_intr_alloc failed, ret 0x%x\n", ret));
13008561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz);
13010Sstevel@tonic-gate return (DDI_INTR_NOTFOUND);
13020Sstevel@tonic-gate }
13038561SScott.Carter@Sun.COM hdl = hdl_p[inumber];
13040Sstevel@tonic-gate }
13050Sstevel@tonic-gate
13060Sstevel@tonic-gate if ((ret = ddi_intr_get_pri(hdl, &pri)) != DDI_SUCCESS) {
13070Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_get_iblock_cookie: "
13080Sstevel@tonic-gate "ddi_intr_get_pri failed, ret 0x%x\n", ret));
13090Sstevel@tonic-gate (void) ddi_intr_free(hdl);
13108561SScott.Carter@Sun.COM if (hdl_sz)
13118561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz);
13120Sstevel@tonic-gate return (DDI_FAILURE);
13130Sstevel@tonic-gate }
13140Sstevel@tonic-gate
131542Sagiri *iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)pri;
13160Sstevel@tonic-gate /* Free the handle allocated here only if no existing handle exists */
13178561SScott.Carter@Sun.COM if (hdl_sz) {
13180Sstevel@tonic-gate (void) ddi_intr_free(hdl);
13198561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz);
13208561SScott.Carter@Sun.COM }
13210Sstevel@tonic-gate
13220Sstevel@tonic-gate return (DDI_SUCCESS);
13230Sstevel@tonic-gate }
13240Sstevel@tonic-gate
13250Sstevel@tonic-gate int
ddi_add_intr(dev_info_t * dip,uint_t inumber,ddi_iblock_cookie_t * iblock_cookiep,ddi_idevice_cookie_t * idevice_cookiep,uint_t (* int_handler)(caddr_t int_handler_arg),caddr_t int_handler_arg)13260Sstevel@tonic-gate ddi_add_intr(dev_info_t *dip, uint_t inumber,
13270Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep,
13280Sstevel@tonic-gate ddi_idevice_cookie_t *idevice_cookiep,
13290Sstevel@tonic-gate uint_t (*int_handler)(caddr_t int_handler_arg),
13300Sstevel@tonic-gate caddr_t int_handler_arg)
13310Sstevel@tonic-gate {
13320Sstevel@tonic-gate ddi_intr_handle_t *hdl_p;
13338561SScott.Carter@Sun.COM size_t hdl_sz;
13340Sstevel@tonic-gate int actual, ret;
13350Sstevel@tonic-gate uint_t pri;
13360Sstevel@tonic-gate
13370Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: name=%s%d dip=0x%p "
13380Sstevel@tonic-gate "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
13390Sstevel@tonic-gate (void *)dip, inumber));
13400Sstevel@tonic-gate
13418561SScott.Carter@Sun.COM hdl_sz = sizeof (ddi_intr_handle_t) * (inumber + 1);
13428561SScott.Carter@Sun.COM hdl_p = kmem_zalloc(hdl_sz, KM_SLEEP);
13430Sstevel@tonic-gate
13440Sstevel@tonic-gate if ((ret = ddi_intr_alloc(dip, hdl_p, DDI_INTR_TYPE_FIXED,
1345965Sgovinda inumber, 1, &actual, DDI_INTR_ALLOC_NORMAL)) != DDI_SUCCESS) {
13460Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
13470Sstevel@tonic-gate "ddi_intr_alloc failed, ret 0x%x\n", ret));
13488561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz);
13490Sstevel@tonic-gate return (DDI_INTR_NOTFOUND);
13500Sstevel@tonic-gate }
13510Sstevel@tonic-gate
13528561SScott.Carter@Sun.COM if ((ret = ddi_intr_get_pri(hdl_p[inumber], &pri)) != DDI_SUCCESS) {
13530Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
13540Sstevel@tonic-gate "ddi_intr_get_pri failed, ret 0x%x\n", ret));
13558561SScott.Carter@Sun.COM (void) ddi_intr_free(hdl_p[inumber]);
13568561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz);
13570Sstevel@tonic-gate return (DDI_FAILURE);
13580Sstevel@tonic-gate }
13590Sstevel@tonic-gate
13608561SScott.Carter@Sun.COM if ((ret = ddi_intr_add_handler(hdl_p[inumber], (ddi_intr_handler_t *)
13610Sstevel@tonic-gate int_handler, int_handler_arg, NULL)) != DDI_SUCCESS) {
13620Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
13630Sstevel@tonic-gate "ddi_intr_add_handler failed, ret 0x%x\n", ret));
13648561SScott.Carter@Sun.COM (void) ddi_intr_free(hdl_p[inumber]);
13658561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz);
13660Sstevel@tonic-gate return (DDI_FAILURE);
13670Sstevel@tonic-gate }
13680Sstevel@tonic-gate
13698561SScott.Carter@Sun.COM if ((ret = ddi_intr_enable(hdl_p[inumber])) != DDI_SUCCESS) {
13700Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_intr: "
13710Sstevel@tonic-gate "ddi_intr_enable failed, ret 0x%x\n", ret));
13728561SScott.Carter@Sun.COM (void) ddi_intr_remove_handler(hdl_p[inumber]);
13738561SScott.Carter@Sun.COM (void) ddi_intr_free(hdl_p[inumber]);
13748561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz);
13750Sstevel@tonic-gate return (DDI_FAILURE);
13760Sstevel@tonic-gate }
13770Sstevel@tonic-gate
13780Sstevel@tonic-gate if (iblock_cookiep)
137942Sagiri *iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)pri;
13800Sstevel@tonic-gate
13810Sstevel@tonic-gate if (idevice_cookiep) {
13820Sstevel@tonic-gate idevice_cookiep->idev_vector = 0;
13830Sstevel@tonic-gate idevice_cookiep->idev_priority = pri;
13840Sstevel@tonic-gate }
13850Sstevel@tonic-gate
13868561SScott.Carter@Sun.COM kmem_free(hdl_p, hdl_sz);
13878561SScott.Carter@Sun.COM
13880Sstevel@tonic-gate return (DDI_SUCCESS);
13890Sstevel@tonic-gate }
13900Sstevel@tonic-gate
13910Sstevel@tonic-gate /* ARGSUSED */
13920Sstevel@tonic-gate int
ddi_add_fastintr(dev_info_t * dip,uint_t inumber,ddi_iblock_cookie_t * iblock_cookiep,ddi_idevice_cookie_t * idevice_cookiep,uint_t (* hi_int_handler)(void))13930Sstevel@tonic-gate ddi_add_fastintr(dev_info_t *dip, uint_t inumber,
13940Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep,
13950Sstevel@tonic-gate ddi_idevice_cookie_t *idevice_cookiep,
13960Sstevel@tonic-gate uint_t (*hi_int_handler)(void))
13970Sstevel@tonic-gate {
13980Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_fastintr: name=%s%d dip=0x%p "
13990Sstevel@tonic-gate "inum=0x%x: Not supported, return failure\n", ddi_driver_name(dip),
14000Sstevel@tonic-gate ddi_get_instance(dip), (void *)dip, inumber));
14010Sstevel@tonic-gate
14020Sstevel@tonic-gate return (DDI_FAILURE);
14030Sstevel@tonic-gate }
14040Sstevel@tonic-gate
14050Sstevel@tonic-gate /* ARGSUSED */
14060Sstevel@tonic-gate void
ddi_remove_intr(dev_info_t * dip,uint_t inum,ddi_iblock_cookie_t iblock_cookie)14070Sstevel@tonic-gate ddi_remove_intr(dev_info_t *dip, uint_t inum, ddi_iblock_cookie_t iblock_cookie)
14080Sstevel@tonic-gate {
14098561SScott.Carter@Sun.COM ddi_intr_handle_t hdl;
14100Sstevel@tonic-gate int ret;
14110Sstevel@tonic-gate
14120Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: name=%s%d dip=0x%p "
14130Sstevel@tonic-gate "inum=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
14140Sstevel@tonic-gate (void *)dip, inum));
14150Sstevel@tonic-gate
14168561SScott.Carter@Sun.COM if ((hdl = i_ddi_get_intr_handle(dip, inum)) == NULL) {
14170Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: no handle "
14180Sstevel@tonic-gate "found\n"));
14190Sstevel@tonic-gate return;
14200Sstevel@tonic-gate }
14210Sstevel@tonic-gate
14228561SScott.Carter@Sun.COM if ((ret = ddi_intr_disable(hdl)) != DDI_SUCCESS) {
14230Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
14240Sstevel@tonic-gate "ddi_intr_disable failed, ret 0x%x\n", ret));
14250Sstevel@tonic-gate return;
14260Sstevel@tonic-gate }
14270Sstevel@tonic-gate
14288561SScott.Carter@Sun.COM if ((ret = ddi_intr_remove_handler(hdl)) != DDI_SUCCESS) {
14290Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
14300Sstevel@tonic-gate "ddi_intr_remove_handler failed, ret 0x%x\n", ret));
14310Sstevel@tonic-gate return;
14320Sstevel@tonic-gate }
14330Sstevel@tonic-gate
14348561SScott.Carter@Sun.COM if ((ret = ddi_intr_free(hdl)) != DDI_SUCCESS) {
14350Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_intr: "
14360Sstevel@tonic-gate "ddi_intr_free failed, ret 0x%x\n", ret));
14370Sstevel@tonic-gate return;
14380Sstevel@tonic-gate }
14390Sstevel@tonic-gate }
14400Sstevel@tonic-gate
14410Sstevel@tonic-gate /* ARGSUSED */
14420Sstevel@tonic-gate int
ddi_get_soft_iblock_cookie(dev_info_t * dip,int preference,ddi_iblock_cookie_t * iblock_cookiep)14430Sstevel@tonic-gate ddi_get_soft_iblock_cookie(dev_info_t *dip, int preference,
14440Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep)
14450Sstevel@tonic-gate {
14460Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_get_soft_iblock_cookie: name=%s%d "
14470Sstevel@tonic-gate "dip=0x%p pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
14480Sstevel@tonic-gate (void *)dip, preference));
14490Sstevel@tonic-gate
14500Sstevel@tonic-gate ASSERT(iblock_cookiep != NULL);
14510Sstevel@tonic-gate
14520Sstevel@tonic-gate if (preference == DDI_SOFTINT_FIXED)
14530Sstevel@tonic-gate return (DDI_FAILURE);
14540Sstevel@tonic-gate
145542Sagiri *iblock_cookiep = (ddi_iblock_cookie_t)((uintptr_t)
14560Sstevel@tonic-gate ((preference > DDI_SOFTINT_MED) ? DDI_SOFT_INTR_PRI_H :
14570Sstevel@tonic-gate DDI_SOFT_INTR_PRI_M));
14580Sstevel@tonic-gate
14590Sstevel@tonic-gate return (DDI_SUCCESS);
14600Sstevel@tonic-gate }
14610Sstevel@tonic-gate
14620Sstevel@tonic-gate int
ddi_add_softintr(dev_info_t * dip,int preference,ddi_softintr_t * idp,ddi_iblock_cookie_t * iblock_cookiep,ddi_idevice_cookie_t * idevice_cookiep,uint_t (* int_handler)(caddr_t int_handler_arg),caddr_t int_handler_arg)14630Sstevel@tonic-gate ddi_add_softintr(dev_info_t *dip, int preference, ddi_softintr_t *idp,
14640Sstevel@tonic-gate ddi_iblock_cookie_t *iblock_cookiep,
14650Sstevel@tonic-gate ddi_idevice_cookie_t *idevice_cookiep,
14660Sstevel@tonic-gate uint_t (*int_handler)(caddr_t int_handler_arg),
14670Sstevel@tonic-gate caddr_t int_handler_arg)
14680Sstevel@tonic-gate {
14690Sstevel@tonic-gate ddi_softint_handle_t *hdl_p;
14700Sstevel@tonic-gate uint64_t softpri;
14710Sstevel@tonic-gate int ret;
14720Sstevel@tonic-gate
14730Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: name=%s%d dip=0x%p "
14740Sstevel@tonic-gate "pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip),
14750Sstevel@tonic-gate (void *)dip, preference));
14760Sstevel@tonic-gate
14770Sstevel@tonic-gate if ((idp == NULL) || ((preference == DDI_SOFTINT_FIXED) &&
14780Sstevel@tonic-gate (iblock_cookiep == NULL)))
14790Sstevel@tonic-gate return (DDI_FAILURE);
14800Sstevel@tonic-gate
14810Sstevel@tonic-gate /* Translate the priority preference */
14820Sstevel@tonic-gate if (preference == DDI_SOFTINT_FIXED) {
1483190Seota softpri = (uint64_t)(uintptr_t)*iblock_cookiep;
14840Sstevel@tonic-gate softpri = MIN(softpri, DDI_SOFT_INTR_PRI_H);
14850Sstevel@tonic-gate } else {
14860Sstevel@tonic-gate softpri = (uint64_t)((preference > DDI_SOFTINT_MED) ?
14870Sstevel@tonic-gate DDI_SOFT_INTR_PRI_H : DDI_SOFT_INTR_PRI_M);
14880Sstevel@tonic-gate }
14890Sstevel@tonic-gate
14900Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: preference 0x%x "
14910Sstevel@tonic-gate "softpri 0x%lx\n", preference, (long)softpri));
14920Sstevel@tonic-gate
14930Sstevel@tonic-gate hdl_p = kmem_zalloc(sizeof (ddi_softint_handle_t), KM_SLEEP);
14940Sstevel@tonic-gate if ((ret = ddi_intr_add_softint(dip, hdl_p, softpri,
14950Sstevel@tonic-gate (ddi_intr_handler_t *)int_handler, int_handler_arg)) !=
14960Sstevel@tonic-gate DDI_SUCCESS) {
14970Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: "
14980Sstevel@tonic-gate "ddi_intr_add_softint failed, ret 0x%x\n", ret));
14990Sstevel@tonic-gate
15000Sstevel@tonic-gate kmem_free(hdl_p, sizeof (ddi_softint_handle_t));
15010Sstevel@tonic-gate return (DDI_FAILURE);
15020Sstevel@tonic-gate }
15030Sstevel@tonic-gate
15040Sstevel@tonic-gate if (iblock_cookiep)
1505190Seota *iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)softpri;
15060Sstevel@tonic-gate
15070Sstevel@tonic-gate if (idevice_cookiep) {
15080Sstevel@tonic-gate idevice_cookiep->idev_vector = 0;
15090Sstevel@tonic-gate idevice_cookiep->idev_priority = softpri;
15100Sstevel@tonic-gate }
15110Sstevel@tonic-gate
15120Sstevel@tonic-gate *idp = (ddi_softintr_t)hdl_p;
15130Sstevel@tonic-gate
15140Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: dip = 0x%p, "
15150Sstevel@tonic-gate "idp = 0x%p, ret = %x\n", (void *)dip, (void *)*idp, ret));
15160Sstevel@tonic-gate
15170Sstevel@tonic-gate return (DDI_SUCCESS);
15180Sstevel@tonic-gate }
15190Sstevel@tonic-gate
15200Sstevel@tonic-gate void
ddi_remove_softintr(ddi_softintr_t id)15210Sstevel@tonic-gate ddi_remove_softintr(ddi_softintr_t id)
15220Sstevel@tonic-gate {
15230Sstevel@tonic-gate ddi_softint_handle_t *h_p = (ddi_softint_handle_t *)id;
15240Sstevel@tonic-gate
15250Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: id=0x%p\n",
15260Sstevel@tonic-gate (void *)id));
15270Sstevel@tonic-gate
15280Sstevel@tonic-gate if (h_p == NULL)
15290Sstevel@tonic-gate return;
15300Sstevel@tonic-gate
15310Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_remove_softintr: handle 0x%p\n",
15320Sstevel@tonic-gate (void *)h_p));
15330Sstevel@tonic-gate
15340Sstevel@tonic-gate (void) ddi_intr_remove_softint(*h_p);
15350Sstevel@tonic-gate kmem_free(h_p, sizeof (ddi_softint_handle_t));
15360Sstevel@tonic-gate }
15370Sstevel@tonic-gate
15380Sstevel@tonic-gate void
ddi_trigger_softintr(ddi_softintr_t id)15390Sstevel@tonic-gate ddi_trigger_softintr(ddi_softintr_t id)
15400Sstevel@tonic-gate {
15410Sstevel@tonic-gate ddi_softint_handle_t *h_p = (ddi_softint_handle_t *)id;
15420Sstevel@tonic-gate int ret;
15430Sstevel@tonic-gate
15440Sstevel@tonic-gate if (h_p == NULL)
15450Sstevel@tonic-gate return;
15460Sstevel@tonic-gate
15470Sstevel@tonic-gate if ((ret = ddi_intr_trigger_softint(*h_p, NULL)) != DDI_SUCCESS) {
15480Sstevel@tonic-gate DDI_INTR_APIDBG((CE_CONT, "ddi_trigger_softintr: "
15490Sstevel@tonic-gate "ddi_intr_trigger_softint failed, hdlp 0x%p "
15500Sstevel@tonic-gate "ret 0x%x\n", (void *)h_p, ret));
15510Sstevel@tonic-gate }
15520Sstevel@tonic-gate }
1553