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
5d48713b8Sesolom * Common Development and Distribution License (the "License").
6d48713b8Sesolom * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22614edcaeSEvan Yan * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate * PCI nexus interrupt handling:
287c478bd9Sstevel@tonic-gate * PCI device interrupt handler wrapper
297c478bd9Sstevel@tonic-gate * pil lookup routine
307c478bd9Sstevel@tonic-gate * PCI device interrupt related initchild code
317c478bd9Sstevel@tonic-gate */
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
357c478bd9Sstevel@tonic-gate #include <sys/async.h>
367c478bd9Sstevel@tonic-gate #include <sys/spl.h>
377c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
387c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> /* e_ddi_nodeid_to_dip() */
397c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
407c478bd9Sstevel@tonic-gate #include <sys/pci/pci_obj.h>
417c478bd9Sstevel@tonic-gate #include <sys/sdt.h>
426d44af1bSesolom #include <sys/clock.h>
437c478bd9Sstevel@tonic-gate
447c478bd9Sstevel@tonic-gate #ifdef _STARFIRE
457c478bd9Sstevel@tonic-gate #include <sys/starfire.h>
467c478bd9Sstevel@tonic-gate #endif /* _STARFIRE */
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate /*
497c478bd9Sstevel@tonic-gate * interrupt jabber:
507c478bd9Sstevel@tonic-gate *
517c478bd9Sstevel@tonic-gate * When an interrupt line is jabbering, every time the state machine for the
527c478bd9Sstevel@tonic-gate * associated ino is idled, a new mondo will be sent and the ino will go into
537c478bd9Sstevel@tonic-gate * the pending state again. The mondo will cause a new call to
547c478bd9Sstevel@tonic-gate * pci_intr_wrapper() which normally idles the ino's state machine which would
557c478bd9Sstevel@tonic-gate * precipitate another trip round the loop.
567c478bd9Sstevel@tonic-gate * The loop can be broken by preventing the ino's state machine from being
577c478bd9Sstevel@tonic-gate * idled when an interrupt line is jabbering. See the comment at the
587c478bd9Sstevel@tonic-gate * beginning of pci_intr_wrapper() explaining how the 'interrupt jabber
597c478bd9Sstevel@tonic-gate * protection' code does this.
607c478bd9Sstevel@tonic-gate */
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/
637c478bd9Sstevel@tonic-gate
647c478bd9Sstevel@tonic-gate #ifdef NOT_DEFINED
657c478bd9Sstevel@tonic-gate /*
667c478bd9Sstevel@tonic-gate * This array is used to determine the sparc PIL at the which the
677c478bd9Sstevel@tonic-gate * handler for a given INO will execute. This table is for onboard
687c478bd9Sstevel@tonic-gate * devices only. A different scheme will be used for plug-in cards.
697c478bd9Sstevel@tonic-gate */
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate uint_t ino_to_pil[] = {
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate /* pil */ /* ino */
747c478bd9Sstevel@tonic-gate
757c478bd9Sstevel@tonic-gate 0, 0, 0, 0, /* 0x00 - 0x03: bus A slot 0 int#A, B, C, D */
767c478bd9Sstevel@tonic-gate 0, 0, 0, 0, /* 0x04 - 0x07: bus A slot 1 int#A, B, C, D */
777c478bd9Sstevel@tonic-gate 0, 0, 0, 0, /* 0x08 - 0x0B: unused */
787c478bd9Sstevel@tonic-gate 0, 0, 0, 0, /* 0x0C - 0x0F: unused */
797c478bd9Sstevel@tonic-gate
807c478bd9Sstevel@tonic-gate 0, 0, 0, 0, /* 0x10 - 0x13: bus B slot 0 int#A, B, C, D */
817c478bd9Sstevel@tonic-gate 0, 0, 0, 0, /* 0x14 - 0x17: bus B slot 1 int#A, B, C, D */
827c478bd9Sstevel@tonic-gate 0, 0, 0, 0, /* 0x18 - 0x1B: bus B slot 2 int#A, B, C, D */
837c478bd9Sstevel@tonic-gate 4, 0, 0, 0, /* 0x1C - 0x1F: bus B slot 3 int#A, B, C, D */
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate 4, /* 0x20: SCSI */
867c478bd9Sstevel@tonic-gate 6, /* 0x21: ethernet */
877c478bd9Sstevel@tonic-gate 3, /* 0x22: parallel port */
887c478bd9Sstevel@tonic-gate 9, /* 0x23: audio record */
897c478bd9Sstevel@tonic-gate 9, /* 0x24: audio playback */
907c478bd9Sstevel@tonic-gate 14, /* 0x25: power fail */
917c478bd9Sstevel@tonic-gate 4, /* 0x26: 2nd SCSI */
927c478bd9Sstevel@tonic-gate 8, /* 0x27: floppy */
937c478bd9Sstevel@tonic-gate 14, /* 0x28: thermal warning */
947c478bd9Sstevel@tonic-gate 12, /* 0x29: keyboard */
957c478bd9Sstevel@tonic-gate 12, /* 0x2A: mouse */
967c478bd9Sstevel@tonic-gate 12, /* 0x2B: serial */
977c478bd9Sstevel@tonic-gate 0, /* 0x2C: timer/counter 0 */
987c478bd9Sstevel@tonic-gate 0, /* 0x2D: timer/counter 1 */
997c478bd9Sstevel@tonic-gate 14, /* 0x2E: uncorrectable ECC errors */
1007c478bd9Sstevel@tonic-gate 14, /* 0x2F: correctable ECC errors */
1017c478bd9Sstevel@tonic-gate 14, /* 0x30: PCI bus A error */
1027c478bd9Sstevel@tonic-gate 14, /* 0x31: PCI bus B error */
1037c478bd9Sstevel@tonic-gate 14, /* 0x32: power management wakeup */
1047c478bd9Sstevel@tonic-gate 14, /* 0x33 */
1057c478bd9Sstevel@tonic-gate 14, /* 0x34 */
1067c478bd9Sstevel@tonic-gate 14, /* 0x35 */
1077c478bd9Sstevel@tonic-gate 14, /* 0x36 */
1087c478bd9Sstevel@tonic-gate 14, /* 0x37 */
1097c478bd9Sstevel@tonic-gate 14, /* 0x38 */
1107c478bd9Sstevel@tonic-gate 14, /* 0x39 */
1117c478bd9Sstevel@tonic-gate 14, /* 0x3a */
1127c478bd9Sstevel@tonic-gate 14, /* 0x3b */
1137c478bd9Sstevel@tonic-gate 14, /* 0x3c */
1147c478bd9Sstevel@tonic-gate 14, /* 0x3d */
1157c478bd9Sstevel@tonic-gate 14, /* 0x3e */
1167c478bd9Sstevel@tonic-gate 14, /* 0x3f */
1177c478bd9Sstevel@tonic-gate 14 /* 0x40 */
1187c478bd9Sstevel@tonic-gate };
1197c478bd9Sstevel@tonic-gate #endif /* NOT_DEFINED */
1207c478bd9Sstevel@tonic-gate
1217c478bd9Sstevel@tonic-gate
1227c478bd9Sstevel@tonic-gate #define PCI_SIMBA_VENID 0x108e /* vendor id for simba */
1237c478bd9Sstevel@tonic-gate #define PCI_SIMBA_DEVID 0x5000 /* device id for simba */
1247c478bd9Sstevel@tonic-gate
1257c478bd9Sstevel@tonic-gate /*
1267c478bd9Sstevel@tonic-gate * map_pcidev_cfg_reg - create mapping to pci device configuration registers
1277c478bd9Sstevel@tonic-gate * if we have a simba AND a pci to pci bridge along the
1287c478bd9Sstevel@tonic-gate * device path.
1297c478bd9Sstevel@tonic-gate * Called with corresponding mutexes held!!
1307c478bd9Sstevel@tonic-gate *
1317c478bd9Sstevel@tonic-gate * XXX XXX XXX The purpose of this routine is to overcome a hardware
1327c478bd9Sstevel@tonic-gate * defect in Sabre CPU and Simba bridge configuration
1337c478bd9Sstevel@tonic-gate * which does not drain DMA write data stalled in
1347c478bd9Sstevel@tonic-gate * PCI to PCI bridges (such as the DEC bridge) beyond
1357c478bd9Sstevel@tonic-gate * Simba. This routine will setup the data structures
1367c478bd9Sstevel@tonic-gate * to allow the pci_intr_wrapper to perform a manual
1377c478bd9Sstevel@tonic-gate * drain data operation before passing the control to
1387c478bd9Sstevel@tonic-gate * interrupt handlers of device drivers.
1397c478bd9Sstevel@tonic-gate * return value:
1407c478bd9Sstevel@tonic-gate * DDI_SUCCESS
1417c478bd9Sstevel@tonic-gate * DDI_FAILURE if unable to create mapping
1427c478bd9Sstevel@tonic-gate */
1437c478bd9Sstevel@tonic-gate static int
map_pcidev_cfg_reg(dev_info_t * dip,dev_info_t * rdip,ddi_acc_handle_t * hdl_p)1447c478bd9Sstevel@tonic-gate map_pcidev_cfg_reg(dev_info_t *dip, dev_info_t *rdip, ddi_acc_handle_t *hdl_p)
1457c478bd9Sstevel@tonic-gate {
1467c478bd9Sstevel@tonic-gate dev_info_t *cdip;
1477c478bd9Sstevel@tonic-gate dev_info_t *pci_dip = NULL;
1487c478bd9Sstevel@tonic-gate pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip));
1497c478bd9Sstevel@tonic-gate int simba_found = 0, pci_bridge_found = 0;
1507c478bd9Sstevel@tonic-gate
1517c478bd9Sstevel@tonic-gate for (cdip = rdip; cdip && cdip != dip; cdip = ddi_get_parent(cdip)) {
1527c478bd9Sstevel@tonic-gate ddi_acc_handle_t config_handle;
1537c478bd9Sstevel@tonic-gate uint32_t vendor_id = ddi_getprop(DDI_DEV_T_ANY, cdip,
1547c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "vendor-id", 0xffff);
1557c478bd9Sstevel@tonic-gate
1567c478bd9Sstevel@tonic-gate DEBUG4(DBG_A_INTX, pci_p->pci_dip,
1577c478bd9Sstevel@tonic-gate "map dev cfg reg for %s%d: @%s%d\n",
1587c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip),
1597c478bd9Sstevel@tonic-gate ddi_driver_name(cdip), ddi_get_instance(cdip));
1607c478bd9Sstevel@tonic-gate
1617c478bd9Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
1627c478bd9Sstevel@tonic-gate "no-dma-interrupt-sync"))
1637c478bd9Sstevel@tonic-gate continue;
1647c478bd9Sstevel@tonic-gate
1657c478bd9Sstevel@tonic-gate /* continue to search up-stream if not a PCI device */
1667c478bd9Sstevel@tonic-gate if (vendor_id == 0xffff)
1677c478bd9Sstevel@tonic-gate continue;
1687c478bd9Sstevel@tonic-gate
1697c478bd9Sstevel@tonic-gate /* record the deepest pci device */
1707c478bd9Sstevel@tonic-gate if (!pci_dip)
1717c478bd9Sstevel@tonic-gate pci_dip = cdip;
1727c478bd9Sstevel@tonic-gate
1737c478bd9Sstevel@tonic-gate /* look for simba */
1747c478bd9Sstevel@tonic-gate if (vendor_id == PCI_SIMBA_VENID) {
1757c478bd9Sstevel@tonic-gate uint32_t device_id = ddi_getprop(DDI_DEV_T_ANY,
1767c478bd9Sstevel@tonic-gate cdip, DDI_PROP_DONTPASS, "device-id", -1);
1777c478bd9Sstevel@tonic-gate if (device_id == PCI_SIMBA_DEVID) {
1787c478bd9Sstevel@tonic-gate simba_found = 1;
1797c478bd9Sstevel@tonic-gate DEBUG0(DBG_A_INTX, pci_p->pci_dip,
1807c478bd9Sstevel@tonic-gate "\tFound simba\n");
1817c478bd9Sstevel@tonic-gate continue; /* do not check bridge if simba */
1827c478bd9Sstevel@tonic-gate }
1837c478bd9Sstevel@tonic-gate }
1847c478bd9Sstevel@tonic-gate
1857c478bd9Sstevel@tonic-gate /* look for pci to pci bridge */
1867c478bd9Sstevel@tonic-gate if (pci_config_setup(cdip, &config_handle) != DDI_SUCCESS) {
1877c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
1887c478bd9Sstevel@tonic-gate "%s%d: can't get brdg cfg space for %s%d\n",
1897c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip),
1907c478bd9Sstevel@tonic-gate ddi_driver_name(cdip), ddi_get_instance(cdip));
1917c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
1927c478bd9Sstevel@tonic-gate }
1937c478bd9Sstevel@tonic-gate if (pci_config_get8(config_handle, PCI_CONF_BASCLASS)
1947c478bd9Sstevel@tonic-gate == PCI_CLASS_BRIDGE) {
1957c478bd9Sstevel@tonic-gate DEBUG0(DBG_A_INTX, pci_p->pci_dip,
1967c478bd9Sstevel@tonic-gate "\tFound PCI to xBus bridge\n");
1977c478bd9Sstevel@tonic-gate pci_bridge_found = 1;
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate pci_config_teardown(&config_handle);
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate if (!pci_bridge_found)
2037c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
2047c478bd9Sstevel@tonic-gate if (!simba_found && (CHIP_TYPE(pci_p) < PCI_CHIP_SCHIZO))
2057c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
2067c478bd9Sstevel@tonic-gate if (pci_config_setup(pci_dip, hdl_p) != DDI_SUCCESS) {
2077c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: can not get config space for %s%d\n",
2087c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip),
2097c478bd9Sstevel@tonic-gate ddi_driver_name(cdip), ddi_get_instance(cdip));
2107c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
2137c478bd9Sstevel@tonic-gate }
2147c478bd9Sstevel@tonic-gate
2157c478bd9Sstevel@tonic-gate /*
2167c478bd9Sstevel@tonic-gate * If the unclaimed interrupt count has reached the limit set by
2177c478bd9Sstevel@tonic-gate * pci_unclaimed_intr_max within the time limit, then all interrupts
2187c478bd9Sstevel@tonic-gate * on this ino is blocked by not idling the interrupt state machine.
2197c478bd9Sstevel@tonic-gate */
2207c478bd9Sstevel@tonic-gate static int
pci_spurintr(ib_ino_pil_t * ipil_p)221b0fc0e77Sgovinda pci_spurintr(ib_ino_pil_t *ipil_p) {
222b0fc0e77Sgovinda ib_ino_info_t *ino_p = ipil_p->ipil_ino_p;
223b0fc0e77Sgovinda ih_t *ih_p = ipil_p->ipil_ih_start;
2247c478bd9Sstevel@tonic-gate pci_t *pci_p = ino_p->ino_ib_p->ib_pci_p;
2257c478bd9Sstevel@tonic-gate char *err_fmt_str;
226aa01ff85Sdanice boolean_t blocked = B_FALSE;
227b0fc0e77Sgovinda int i;
2287c478bd9Sstevel@tonic-gate
229b0fc0e77Sgovinda if (ino_p->ino_unclaimed_intrs > pci_unclaimed_intr_max)
2307c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED);
2317c478bd9Sstevel@tonic-gate
232b0fc0e77Sgovinda if (!ino_p->ino_unclaimed_intrs)
2337c478bd9Sstevel@tonic-gate ino_p->ino_spurintr_begin = ddi_get_lbolt();
2347c478bd9Sstevel@tonic-gate
235b0fc0e77Sgovinda ino_p->ino_unclaimed_intrs++;
2367c478bd9Sstevel@tonic-gate
237b0fc0e77Sgovinda if (ino_p->ino_unclaimed_intrs <= pci_unclaimed_intr_max)
2387c478bd9Sstevel@tonic-gate goto clear;
2397c478bd9Sstevel@tonic-gate
2407c478bd9Sstevel@tonic-gate if (drv_hztousec(ddi_get_lbolt() - ino_p->ino_spurintr_begin)
2417c478bd9Sstevel@tonic-gate > pci_spurintr_duration) {
242b0fc0e77Sgovinda ino_p->ino_unclaimed_intrs = 0;
2437c478bd9Sstevel@tonic-gate goto clear;
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate err_fmt_str = "%s%d: ino 0x%x blocked";
246aa01ff85Sdanice blocked = B_TRUE;
2477c478bd9Sstevel@tonic-gate goto warn;
2487c478bd9Sstevel@tonic-gate clear:
249aa01ff85Sdanice if (!pci_spurintr_msgs) { /* tomatillo errata #71 spurious mondo */
250aa01ff85Sdanice /* clear the pending state */
251aa01ff85Sdanice IB_INO_INTR_CLEAR(ino_p->ino_clr_reg);
2527c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED);
253aa01ff85Sdanice }
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate err_fmt_str = "!%s%d: spurious interrupt from ino 0x%x";
2567c478bd9Sstevel@tonic-gate warn:
2577c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, err_fmt_str, NAMEINST(pci_p->pci_dip), ino_p->ino_ino);
258b0fc0e77Sgovinda for (i = 0; i < ipil_p->ipil_ih_size; i++, ih_p = ih_p->ih_next)
2597c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "!%s-%d#%x ", NAMEINST(ih_p->ih_dip),
2607c478bd9Sstevel@tonic-gate ih_p->ih_inum);
2617c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "!\n");
262aa01ff85Sdanice if (blocked == B_FALSE) /* clear the pending state */
263aa01ff85Sdanice IB_INO_INTR_CLEAR(ino_p->ino_clr_reg);
264aa01ff85Sdanice
2657c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED);
2667c478bd9Sstevel@tonic-gate }
2677c478bd9Sstevel@tonic-gate
2687c478bd9Sstevel@tonic-gate /*
2697c478bd9Sstevel@tonic-gate * pci_intr_wrapper
2707c478bd9Sstevel@tonic-gate *
2717c478bd9Sstevel@tonic-gate * This routine is used as wrapper around interrupt handlers installed by child
2727c478bd9Sstevel@tonic-gate * device drivers. This routine invokes the driver interrupt handlers and
2737c478bd9Sstevel@tonic-gate * examines the return codes.
2747c478bd9Sstevel@tonic-gate * There is a count of unclaimed interrupts kept on a per-ino basis. If at
2757c478bd9Sstevel@tonic-gate * least one handler claims the interrupt then the counter is halved and the
2767c478bd9Sstevel@tonic-gate * interrupt state machine is idled. If no handler claims the interrupt then
2777c478bd9Sstevel@tonic-gate * the counter is incremented by one and the state machine is idled.
2787c478bd9Sstevel@tonic-gate * If the count ever reaches the limit value set by pci_unclaimed_intr_max
2797c478bd9Sstevel@tonic-gate * then the interrupt state machine is not idled thus preventing any further
2807c478bd9Sstevel@tonic-gate * interrupts on that ino. The state machine will only be idled again if a
2817c478bd9Sstevel@tonic-gate * handler is subsequently added or removed.
2827c478bd9Sstevel@tonic-gate *
2837c478bd9Sstevel@tonic-gate * return value: DDI_INTR_CLAIMED if any handlers claimed the interrupt,
2847c478bd9Sstevel@tonic-gate * DDI_INTR_UNCLAIMED otherwise.
2857c478bd9Sstevel@tonic-gate */
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate extern uint64_t intr_get_time(void);
2887c478bd9Sstevel@tonic-gate
2897c478bd9Sstevel@tonic-gate uint_t
pci_intr_wrapper(caddr_t arg)2907c478bd9Sstevel@tonic-gate pci_intr_wrapper(caddr_t arg)
2917c478bd9Sstevel@tonic-gate {
292b0fc0e77Sgovinda ib_ino_pil_t *ipil_p = (ib_ino_pil_t *)arg;
293b0fc0e77Sgovinda ib_ino_info_t *ino_p = ipil_p->ipil_ino_p;
294b0fc0e77Sgovinda uint_t result = 0, r = DDI_INTR_UNCLAIMED;
2957c478bd9Sstevel@tonic-gate pci_t *pci_p = ino_p->ino_ib_p->ib_pci_p;
2967c478bd9Sstevel@tonic-gate pbm_t *pbm_p = pci_p->pci_pbm_p;
297b0fc0e77Sgovinda ih_t *ih_p = ipil_p->ipil_ih_start;
2987c478bd9Sstevel@tonic-gate int i;
2997c478bd9Sstevel@tonic-gate
300b0fc0e77Sgovinda for (i = 0; i < ipil_p->ipil_ih_size; i++, ih_p = ih_p->ih_next) {
3017c478bd9Sstevel@tonic-gate dev_info_t *dip = ih_p->ih_dip;
3027c478bd9Sstevel@tonic-gate uint_t (*handler)() = ih_p->ih_handler;
3037c478bd9Sstevel@tonic-gate caddr_t arg1 = ih_p->ih_handler_arg1;
3047c478bd9Sstevel@tonic-gate caddr_t arg2 = ih_p->ih_handler_arg2;
3057c478bd9Sstevel@tonic-gate ddi_acc_handle_t cfg_hdl = ih_p->ih_config_handle;
3067c478bd9Sstevel@tonic-gate
3077c478bd9Sstevel@tonic-gate if (pci_intr_dma_sync && cfg_hdl && pbm_p->pbm_sync_reg_pa) {
3087c478bd9Sstevel@tonic-gate (void) pci_config_get16(cfg_hdl, PCI_CONF_VENID);
3097c478bd9Sstevel@tonic-gate pci_pbm_dma_sync(pbm_p, ino_p->ino_ino);
3107c478bd9Sstevel@tonic-gate }
3117c478bd9Sstevel@tonic-gate
3127c478bd9Sstevel@tonic-gate if (ih_p->ih_intr_state == PCI_INTR_STATE_DISABLE) {
3137c478bd9Sstevel@tonic-gate DEBUG3(DBG_INTR, pci_p->pci_dip,
3147c478bd9Sstevel@tonic-gate "pci_intr_wrapper: %s%d interrupt %d is disabled\n",
3157c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip),
3167c478bd9Sstevel@tonic-gate ino_p->ino_ino);
3177c478bd9Sstevel@tonic-gate
3187c478bd9Sstevel@tonic-gate continue;
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate
3217c478bd9Sstevel@tonic-gate DTRACE_PROBE4(interrupt__start, dev_info_t, dip,
3227c478bd9Sstevel@tonic-gate void *, handler, caddr_t, arg1, caddr_t, arg2);
3237c478bd9Sstevel@tonic-gate
3247c478bd9Sstevel@tonic-gate r = (*handler)(arg1, arg2);
3257c478bd9Sstevel@tonic-gate
3267c478bd9Sstevel@tonic-gate /*
3277c478bd9Sstevel@tonic-gate * Account for time used by this interrupt. Protect against
3287c478bd9Sstevel@tonic-gate * conflicting writes to ih_ticks from ib_intr_dist_all() by
3297c478bd9Sstevel@tonic-gate * using atomic ops.
3307c478bd9Sstevel@tonic-gate */
3317c478bd9Sstevel@tonic-gate
332b0fc0e77Sgovinda if (ipil_p->ipil_pil <= LOCK_LEVEL)
3337c478bd9Sstevel@tonic-gate atomic_add_64(&ih_p->ih_ticks, intr_get_time());
3347c478bd9Sstevel@tonic-gate
3357c478bd9Sstevel@tonic-gate DTRACE_PROBE4(interrupt__complete, dev_info_t, dip,
3367c478bd9Sstevel@tonic-gate void *, handler, caddr_t, arg1, int, r);
3377c478bd9Sstevel@tonic-gate
3387c478bd9Sstevel@tonic-gate result += r;
3397c478bd9Sstevel@tonic-gate
3407c478bd9Sstevel@tonic-gate if (pci_check_all_handlers)
3417c478bd9Sstevel@tonic-gate continue;
3427c478bd9Sstevel@tonic-gate if (result)
3437c478bd9Sstevel@tonic-gate break;
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate
346b0fc0e77Sgovinda if (result)
347b0fc0e77Sgovinda ino_p->ino_claimed |= (1 << ipil_p->ipil_pil);
3487c478bd9Sstevel@tonic-gate
349b0fc0e77Sgovinda /* Interrupt can only be cleared after all pil levels are handled */
350b0fc0e77Sgovinda if (ipil_p->ipil_pil != ino_p->ino_lopil)
351b0fc0e77Sgovinda return (DDI_INTR_CLAIMED);
352b0fc0e77Sgovinda
353b0fc0e77Sgovinda if (!ino_p->ino_claimed)
354b0fc0e77Sgovinda return (pci_spurintr(ipil_p));
355b0fc0e77Sgovinda
356b0fc0e77Sgovinda ino_p->ino_unclaimed_intrs = 0;
357b0fc0e77Sgovinda ino_p->ino_claimed = 0;
358b0fc0e77Sgovinda
359b0fc0e77Sgovinda /* Clear the pending state */
360b0fc0e77Sgovinda IB_INO_INTR_CLEAR(ino_p->ino_clr_reg);
3617c478bd9Sstevel@tonic-gate
3627c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED);
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate
3657c478bd9Sstevel@tonic-gate dev_info_t *
get_my_childs_dip(dev_info_t * dip,dev_info_t * rdip)3667c478bd9Sstevel@tonic-gate get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip)
3677c478bd9Sstevel@tonic-gate {
3687c478bd9Sstevel@tonic-gate dev_info_t *cdip = rdip;
3697c478bd9Sstevel@tonic-gate
3707c478bd9Sstevel@tonic-gate for (; ddi_get_parent(cdip) != dip; cdip = ddi_get_parent(cdip))
3717c478bd9Sstevel@tonic-gate ;
3727c478bd9Sstevel@tonic-gate
3737c478bd9Sstevel@tonic-gate return (cdip);
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate
3766d44af1bSesolom static struct {
3776d44af1bSesolom kstat_named_t pciintr_ks_name;
3786d44af1bSesolom kstat_named_t pciintr_ks_type;
3796d44af1bSesolom kstat_named_t pciintr_ks_cpu;
3806d44af1bSesolom kstat_named_t pciintr_ks_pil;
3816d44af1bSesolom kstat_named_t pciintr_ks_time;
3826d44af1bSesolom kstat_named_t pciintr_ks_ino;
3836d44af1bSesolom kstat_named_t pciintr_ks_cookie;
3846d44af1bSesolom kstat_named_t pciintr_ks_devpath;
3856d44af1bSesolom kstat_named_t pciintr_ks_buspath;
3866d44af1bSesolom } pciintr_ks_template = {
3876d44af1bSesolom { "name", KSTAT_DATA_CHAR },
3886d44af1bSesolom { "type", KSTAT_DATA_CHAR },
3896d44af1bSesolom { "cpu", KSTAT_DATA_UINT64 },
3906d44af1bSesolom { "pil", KSTAT_DATA_UINT64 },
3916d44af1bSesolom { "time", KSTAT_DATA_UINT64 },
3926d44af1bSesolom { "ino", KSTAT_DATA_UINT64 },
3936d44af1bSesolom { "cookie", KSTAT_DATA_UINT64 },
3946d44af1bSesolom { "devpath", KSTAT_DATA_STRING },
3956d44af1bSesolom { "buspath", KSTAT_DATA_STRING },
3966d44af1bSesolom };
3976d44af1bSesolom static uint32_t pciintr_ks_instance;
398d48713b8Sesolom static char ih_devpath[MAXPATHLEN];
399d48713b8Sesolom static char ih_buspath[MAXPATHLEN];
4006d44af1bSesolom
4016d44af1bSesolom kmutex_t pciintr_ks_template_lock;
4026d44af1bSesolom
4036d44af1bSesolom int
pci_ks_update(kstat_t * ksp,int rw)4046d44af1bSesolom pci_ks_update(kstat_t *ksp, int rw)
4056d44af1bSesolom {
4066d44af1bSesolom ih_t *ih_p = ksp->ks_private;
4076d44af1bSesolom int maxlen = sizeof (pciintr_ks_template.pciintr_ks_name.value.c);
408b0fc0e77Sgovinda ib_ino_pil_t *ipil_p = ih_p->ih_ipil_p;
409b0fc0e77Sgovinda ib_ino_info_t *ino_p = ipil_p->ipil_ino_p;
410b0fc0e77Sgovinda ib_t *ib_p = ino_p->ino_ib_p;
4116d44af1bSesolom pci_t *pci_p = ib_p->ib_pci_p;
4126d44af1bSesolom ib_ino_t ino;
4136d44af1bSesolom
414b0fc0e77Sgovinda ino = ino_p->ino_ino;
4156d44af1bSesolom
4166d44af1bSesolom (void) snprintf(pciintr_ks_template.pciintr_ks_name.value.c, maxlen,
4176d44af1bSesolom "%s%d", ddi_driver_name(ih_p->ih_dip),
4186d44af1bSesolom ddi_get_instance(ih_p->ih_dip));
4196d44af1bSesolom
4206d44af1bSesolom (void) ddi_pathname(ih_p->ih_dip, ih_devpath);
4216d44af1bSesolom (void) ddi_pathname(pci_p->pci_dip, ih_buspath);
4226d44af1bSesolom kstat_named_setstr(&pciintr_ks_template.pciintr_ks_devpath, ih_devpath);
4236d44af1bSesolom kstat_named_setstr(&pciintr_ks_template.pciintr_ks_buspath, ih_buspath);
4246d44af1bSesolom
425e1d9f4e6Sschwartz if (ih_p->ih_intr_state == PCI_INTR_STATE_ENABLE) {
426e1d9f4e6Sschwartz (void) strcpy(pciintr_ks_template.pciintr_ks_type.value.c,
427e1d9f4e6Sschwartz "fixed");
428e1d9f4e6Sschwartz pciintr_ks_template.pciintr_ks_cpu.value.ui64 =
429b0fc0e77Sgovinda ino_p->ino_cpuid;
430e1d9f4e6Sschwartz pciintr_ks_template.pciintr_ks_pil.value.ui64 =
431b0fc0e77Sgovinda ipil_p->ipil_pil;
432e1d9f4e6Sschwartz pciintr_ks_template.pciintr_ks_time.value.ui64 = ih_p->ih_nsec +
433e1d9f4e6Sschwartz (uint64_t)tick2ns((hrtime_t)ih_p->ih_ticks,
434b0fc0e77Sgovinda ino_p->ino_cpuid);
435e1d9f4e6Sschwartz pciintr_ks_template.pciintr_ks_ino.value.ui64 = ino;
436e1d9f4e6Sschwartz pciintr_ks_template.pciintr_ks_cookie.value.ui64 =
437e1d9f4e6Sschwartz IB_INO_TO_MONDO(ib_p, ino);
438e1d9f4e6Sschwartz } else {
439e1d9f4e6Sschwartz (void) strcpy(pciintr_ks_template.pciintr_ks_type.value.c,
440e1d9f4e6Sschwartz "disabled");
441e1d9f4e6Sschwartz pciintr_ks_template.pciintr_ks_cpu.value.ui64 = 0;
442e1d9f4e6Sschwartz pciintr_ks_template.pciintr_ks_pil.value.ui64 = 0;
443e1d9f4e6Sschwartz pciintr_ks_template.pciintr_ks_time.value.ui64 = 0;
444e1d9f4e6Sschwartz pciintr_ks_template.pciintr_ks_ino.value.ui64 = 0;
445e1d9f4e6Sschwartz pciintr_ks_template.pciintr_ks_cookie.value.ui64 = 0;
446e1d9f4e6Sschwartz }
447e1d9f4e6Sschwartz
4486d44af1bSesolom return (0);
4496d44af1bSesolom }
4506d44af1bSesolom
4517c478bd9Sstevel@tonic-gate int
pci_add_intr(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)4527c478bd9Sstevel@tonic-gate pci_add_intr(dev_info_t *dip, dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp)
4537c478bd9Sstevel@tonic-gate {
4547c478bd9Sstevel@tonic-gate pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip));
4557c478bd9Sstevel@tonic-gate ib_t *ib_p = pci_p->pci_ib_p;
4567c478bd9Sstevel@tonic-gate cb_t *cb_p = pci_p->pci_cb_p;
4577c478bd9Sstevel@tonic-gate ih_t *ih_p;
4587c478bd9Sstevel@tonic-gate ib_ino_t ino;
4597c478bd9Sstevel@tonic-gate ib_ino_info_t *ino_p; /* pulse interrupts have no ino */
460b0fc0e77Sgovinda ib_ino_pil_t *ipil_p, *ipil_list;
4617c478bd9Sstevel@tonic-gate ib_mondo_t mondo;
4627c478bd9Sstevel@tonic-gate uint32_t cpu_id;
4637c478bd9Sstevel@tonic-gate int ret;
4647c478bd9Sstevel@tonic-gate int32_t weight;
4657c478bd9Sstevel@tonic-gate
4667c478bd9Sstevel@tonic-gate ino = IB_MONDO_TO_INO(hdlp->ih_vector);
4677c478bd9Sstevel@tonic-gate
4687c478bd9Sstevel@tonic-gate DEBUG3(DBG_A_INTX, dip, "pci_add_intr: rdip=%s%d ino=%x\n",
4697c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), ino);
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate if (ino > ib_p->ib_max_ino) {
4727c478bd9Sstevel@tonic-gate DEBUG1(DBG_A_INTX, dip, "ino %x is invalid\n", ino);
4737c478bd9Sstevel@tonic-gate return (DDI_INTR_NOTFOUND);
4747c478bd9Sstevel@tonic-gate }
4757c478bd9Sstevel@tonic-gate
4767c478bd9Sstevel@tonic-gate if (hdlp->ih_vector & PCI_PULSE_INO) {
4777c478bd9Sstevel@tonic-gate volatile uint64_t *map_reg_addr;
4787c478bd9Sstevel@tonic-gate map_reg_addr = ib_intr_map_reg_addr(ib_p, ino);
4797c478bd9Sstevel@tonic-gate
4807c478bd9Sstevel@tonic-gate mondo = pci_xlate_intr(dip, rdip, ib_p, ino);
4817c478bd9Sstevel@tonic-gate if (mondo == 0)
4827c478bd9Sstevel@tonic-gate goto fail1;
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate hdlp->ih_vector = CB_MONDO_TO_XMONDO(cb_p, mondo);
4857c478bd9Sstevel@tonic-gate
4867c478bd9Sstevel@tonic-gate if (i_ddi_add_ivintr(hdlp) != DDI_SUCCESS)
4877c478bd9Sstevel@tonic-gate goto fail1;
4887c478bd9Sstevel@tonic-gate
4897c478bd9Sstevel@tonic-gate /*
4907c478bd9Sstevel@tonic-gate * Select cpu and program.
4917c478bd9Sstevel@tonic-gate *
4927c478bd9Sstevel@tonic-gate * Since there is no good way to always derive cpuid in
4937c478bd9Sstevel@tonic-gate * pci_remove_intr for PCI_PULSE_INO (esp. for STARFIRE), we
4947c478bd9Sstevel@tonic-gate * don't add (or remove) device weight for pulsed interrupt
4957c478bd9Sstevel@tonic-gate * sources.
4967c478bd9Sstevel@tonic-gate */
4977c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_intr_lock);
4987c478bd9Sstevel@tonic-gate cpu_id = intr_dist_cpuid();
4997c478bd9Sstevel@tonic-gate *map_reg_addr = ib_get_map_reg(mondo, cpu_id);
5007c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_intr_lock);
5017c478bd9Sstevel@tonic-gate *map_reg_addr; /* flush previous write */
5027c478bd9Sstevel@tonic-gate goto done;
5037c478bd9Sstevel@tonic-gate }
5047c478bd9Sstevel@tonic-gate
5057c478bd9Sstevel@tonic-gate if ((mondo = pci_xlate_intr(dip, rdip, pci_p->pci_ib_p, ino)) == 0)
5067c478bd9Sstevel@tonic-gate goto fail1;
5077c478bd9Sstevel@tonic-gate
5087c478bd9Sstevel@tonic-gate ino = IB_MONDO_TO_INO(mondo);
5097c478bd9Sstevel@tonic-gate
5107c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex);
5117c478bd9Sstevel@tonic-gate ih_p = ib_alloc_ih(rdip, hdlp->ih_inum,
5127c478bd9Sstevel@tonic-gate hdlp->ih_cb_func, hdlp->ih_cb_arg1, hdlp->ih_cb_arg2);
5137c478bd9Sstevel@tonic-gate if (map_pcidev_cfg_reg(dip, rdip, &ih_p->ih_config_handle))
5147c478bd9Sstevel@tonic-gate goto fail2;
5157c478bd9Sstevel@tonic-gate
516b0fc0e77Sgovinda ino_p = ib_locate_ino(ib_p, ino);
517b0fc0e77Sgovinda ipil_list = ino_p ? ino_p->ino_ipil_p:NULL;
518b0fc0e77Sgovinda
519b0fc0e77Sgovinda /* Sharing ino */
520b0fc0e77Sgovinda if (ino_p && (ipil_p = ib_ino_locate_ipil(ino_p, hdlp->ih_pri))) {
521b0fc0e77Sgovinda if (ib_intr_locate_ih(ipil_p, rdip, hdlp->ih_inum)) {
522b0fc0e77Sgovinda DEBUG1(DBG_A_INTX, dip, "dup intr #%d\n",
523b0fc0e77Sgovinda hdlp->ih_inum);
5247c478bd9Sstevel@tonic-gate goto fail3;
5257c478bd9Sstevel@tonic-gate }
5267c478bd9Sstevel@tonic-gate
5277c478bd9Sstevel@tonic-gate /* add weight to the cpu that we are already targeting */
5287c478bd9Sstevel@tonic-gate cpu_id = ino_p->ino_cpuid;
5297c478bd9Sstevel@tonic-gate weight = pci_class_to_intr_weight(rdip);
5307c478bd9Sstevel@tonic-gate intr_dist_cpuid_add_device_weight(cpu_id, rdip, weight);
5317c478bd9Sstevel@tonic-gate
532b0fc0e77Sgovinda ib_ino_add_intr(pci_p, ipil_p, ih_p);
5337c478bd9Sstevel@tonic-gate goto ino_done;
5347c478bd9Sstevel@tonic-gate }
5357c478bd9Sstevel@tonic-gate
5367c478bd9Sstevel@tonic-gate if (hdlp->ih_pri == 0)
5377c478bd9Sstevel@tonic-gate hdlp->ih_pri = pci_class_to_pil(rdip);
5387c478bd9Sstevel@tonic-gate
539b0fc0e77Sgovinda ipil_p = ib_new_ino_pil(ib_p, ino, hdlp->ih_pri, ih_p);
540b0fc0e77Sgovinda ino_p = ipil_p->ipil_ino_p;
541b0fc0e77Sgovinda
5427c478bd9Sstevel@tonic-gate hdlp->ih_vector = CB_MONDO_TO_XMONDO(cb_p, mondo);
5437c478bd9Sstevel@tonic-gate
54436fe4a92Segillett /* Store this global mondo */
54536fe4a92Segillett ino_p->ino_mondo = hdlp->ih_vector;
54636fe4a92Segillett
5477c478bd9Sstevel@tonic-gate DEBUG2(DBG_A_INTX, dip, "pci_add_intr: pil=0x%x mondo=0x%x\n",
5487c478bd9Sstevel@tonic-gate hdlp->ih_pri, hdlp->ih_vector);
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp,
551b0fc0e77Sgovinda (ddi_intr_handler_t *)pci_intr_wrapper, (caddr_t)ipil_p, NULL);
5527c478bd9Sstevel@tonic-gate
5537c478bd9Sstevel@tonic-gate ret = i_ddi_add_ivintr(hdlp);
5547c478bd9Sstevel@tonic-gate
5557c478bd9Sstevel@tonic-gate /*
5567c478bd9Sstevel@tonic-gate * Restore original interrupt handler
5577c478bd9Sstevel@tonic-gate * and arguments in interrupt handle.
5587c478bd9Sstevel@tonic-gate */
5597c478bd9Sstevel@tonic-gate DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_handler,
5607c478bd9Sstevel@tonic-gate ih_p->ih_handler_arg1, ih_p->ih_handler_arg2);
5617c478bd9Sstevel@tonic-gate
5627c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS)
5637c478bd9Sstevel@tonic-gate goto fail4;
5647c478bd9Sstevel@tonic-gate
5657c478bd9Sstevel@tonic-gate /* Save the pil for this ino */
566b0fc0e77Sgovinda ipil_p->ipil_pil = hdlp->ih_pri;
5677c478bd9Sstevel@tonic-gate
5687c478bd9Sstevel@tonic-gate /* clear and enable interrupt */
5697c478bd9Sstevel@tonic-gate IB_INO_INTR_CLEAR(ino_p->ino_clr_reg);
5707c478bd9Sstevel@tonic-gate
571b0fc0e77Sgovinda /*
572b0fc0e77Sgovinda * Select cpu and compute weight, saving both for sharing and removal.
573b0fc0e77Sgovinda */
574b0fc0e77Sgovinda if (ipil_list == NULL)
575b0fc0e77Sgovinda ino_p->ino_cpuid = pci_intr_dist_cpuid(ib_p, ino_p);
576b0fc0e77Sgovinda
577b0fc0e77Sgovinda cpu_id = ino_p->ino_cpuid;
5787c478bd9Sstevel@tonic-gate ino_p->ino_established = 1;
5797c478bd9Sstevel@tonic-gate weight = pci_class_to_intr_weight(rdip);
5807c478bd9Sstevel@tonic-gate intr_dist_cpuid_add_device_weight(cpu_id, rdip, weight);
5817c478bd9Sstevel@tonic-gate
5827c478bd9Sstevel@tonic-gate #ifdef _STARFIRE
5837c478bd9Sstevel@tonic-gate cpu_id = pc_translate_tgtid(cb_p->cb_ittrans_cookie, cpu_id,
5847c478bd9Sstevel@tonic-gate IB_GET_MAPREG_INO(ino));
5857c478bd9Sstevel@tonic-gate #endif /* _STARFIRE */
586b0fc0e77Sgovinda if (!ipil_list) {
5877c478bd9Sstevel@tonic-gate *ino_p->ino_map_reg = ib_get_map_reg(mondo, cpu_id);
5887c478bd9Sstevel@tonic-gate *ino_p->ino_map_reg;
589b0fc0e77Sgovinda }
5907c478bd9Sstevel@tonic-gate ino_done:
591*09b1eac2SEvan Yan hdlp->ih_target = ino_p->ino_cpuid;
592b0fc0e77Sgovinda ih_p->ih_ipil_p = ipil_p;
5936d44af1bSesolom ih_p->ih_ksp = kstat_create("pci_intrs",
5946d44af1bSesolom atomic_inc_32_nv(&pciintr_ks_instance), "config", "interrupts",
5956d44af1bSesolom KSTAT_TYPE_NAMED,
5966d44af1bSesolom sizeof (pciintr_ks_template) / sizeof (kstat_named_t),
5976d44af1bSesolom KSTAT_FLAG_VIRTUAL);
5986d44af1bSesolom if (ih_p->ih_ksp != NULL) {
5996d44af1bSesolom ih_p->ih_ksp->ks_data_size += MAXPATHLEN * 2;
6006d44af1bSesolom ih_p->ih_ksp->ks_lock = &pciintr_ks_template_lock;
6016d44af1bSesolom ih_p->ih_ksp->ks_data = &pciintr_ks_template;
6026d44af1bSesolom ih_p->ih_ksp->ks_private = ih_p;
6036d44af1bSesolom ih_p->ih_ksp->ks_update = pci_ks_update;
6047c478bd9Sstevel@tonic-gate kstat_install(ih_p->ih_ksp);
6056d44af1bSesolom }
6067c478bd9Sstevel@tonic-gate ib_ino_map_reg_share(ib_p, ino, ino_p);
6077c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex);
6087c478bd9Sstevel@tonic-gate done:
6097c478bd9Sstevel@tonic-gate DEBUG2(DBG_A_INTX, dip, "done! Interrupt 0x%x pil=%x\n",
6107c478bd9Sstevel@tonic-gate hdlp->ih_vector, hdlp->ih_pri);
6117c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
6127c478bd9Sstevel@tonic-gate fail4:
613b0fc0e77Sgovinda ib_delete_ino_pil(ib_p, ipil_p);
6147c478bd9Sstevel@tonic-gate fail3:
6157c478bd9Sstevel@tonic-gate if (ih_p->ih_config_handle)
6167c478bd9Sstevel@tonic-gate pci_config_teardown(&ih_p->ih_config_handle);
6177c478bd9Sstevel@tonic-gate fail2:
6187c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex);
6197c478bd9Sstevel@tonic-gate kmem_free(ih_p, sizeof (ih_t));
6207c478bd9Sstevel@tonic-gate fail1:
6217c478bd9Sstevel@tonic-gate DEBUG2(DBG_A_INTX, dip, "Failed! Interrupt 0x%x pil=%x\n",
6227c478bd9Sstevel@tonic-gate hdlp->ih_vector, hdlp->ih_pri);
6237c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6247c478bd9Sstevel@tonic-gate }
6257c478bd9Sstevel@tonic-gate
6267c478bd9Sstevel@tonic-gate int
pci_remove_intr(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)6277c478bd9Sstevel@tonic-gate pci_remove_intr(dev_info_t *dip, dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp)
6287c478bd9Sstevel@tonic-gate {
6297c478bd9Sstevel@tonic-gate pci_t *pci_p = get_pci_soft_state(ddi_get_instance(dip));
6307c478bd9Sstevel@tonic-gate ib_t *ib_p = pci_p->pci_ib_p;
6317c478bd9Sstevel@tonic-gate cb_t *cb_p = pci_p->pci_cb_p;
6327c478bd9Sstevel@tonic-gate ib_ino_t ino;
6337c478bd9Sstevel@tonic-gate ib_mondo_t mondo;
6347c478bd9Sstevel@tonic-gate ib_ino_info_t *ino_p; /* non-pulse only */
635b0fc0e77Sgovinda ib_ino_pil_t *ipil_p; /* non-pulse only */
6367c478bd9Sstevel@tonic-gate ih_t *ih_p; /* non-pulse only */
6377c478bd9Sstevel@tonic-gate
6387c478bd9Sstevel@tonic-gate ino = IB_MONDO_TO_INO(hdlp->ih_vector);
6397c478bd9Sstevel@tonic-gate
6407c478bd9Sstevel@tonic-gate DEBUG3(DBG_R_INTX, dip, "pci_rem_intr: rdip=%s%d ino=%x\n",
6417c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), ino);
6427c478bd9Sstevel@tonic-gate
6437c478bd9Sstevel@tonic-gate if (hdlp->ih_vector & PCI_PULSE_INO) { /* pulse interrupt */
6447c478bd9Sstevel@tonic-gate volatile uint64_t *map_reg_addr;
6457c478bd9Sstevel@tonic-gate
6467c478bd9Sstevel@tonic-gate /*
6477c478bd9Sstevel@tonic-gate * No weight was added by pci_add_intr for PCI_PULSE_INO
6487c478bd9Sstevel@tonic-gate * because it is difficult to determine cpuid here.
6497c478bd9Sstevel@tonic-gate */
6507c478bd9Sstevel@tonic-gate map_reg_addr = ib_intr_map_reg_addr(ib_p, ino);
6517c478bd9Sstevel@tonic-gate IB_INO_INTR_RESET(map_reg_addr); /* disable intr */
6527c478bd9Sstevel@tonic-gate *map_reg_addr;
6537c478bd9Sstevel@tonic-gate
6547c478bd9Sstevel@tonic-gate mondo = pci_xlate_intr(dip, rdip, ib_p, ino);
6557c478bd9Sstevel@tonic-gate if (mondo == 0) {
6567c478bd9Sstevel@tonic-gate DEBUG1(DBG_R_INTX, dip,
6577c478bd9Sstevel@tonic-gate "can't get mondo for ino %x\n", ino);
6587c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6597c478bd9Sstevel@tonic-gate }
6607c478bd9Sstevel@tonic-gate
6617c478bd9Sstevel@tonic-gate if (hdlp->ih_pri == 0)
6627c478bd9Sstevel@tonic-gate hdlp->ih_pri = pci_class_to_pil(rdip);
6637c478bd9Sstevel@tonic-gate
6647c478bd9Sstevel@tonic-gate hdlp->ih_vector = CB_MONDO_TO_XMONDO(cb_p, mondo);
6657c478bd9Sstevel@tonic-gate
6667c478bd9Sstevel@tonic-gate DEBUG2(DBG_R_INTX, dip, "pci_rem_intr: pil=0x%x mondo=0x%x\n",
6677c478bd9Sstevel@tonic-gate hdlp->ih_pri, hdlp->ih_vector);
6687c478bd9Sstevel@tonic-gate
6697c478bd9Sstevel@tonic-gate i_ddi_rem_ivintr(hdlp);
6707c478bd9Sstevel@tonic-gate
6717c478bd9Sstevel@tonic-gate DEBUG2(DBG_R_INTX, dip, "pulse success mondo=%x reg=%p\n",
6727c478bd9Sstevel@tonic-gate mondo, map_reg_addr);
6737c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
6747c478bd9Sstevel@tonic-gate }
6757c478bd9Sstevel@tonic-gate
6767c478bd9Sstevel@tonic-gate /* Translate the interrupt property */
6777c478bd9Sstevel@tonic-gate mondo = pci_xlate_intr(dip, rdip, pci_p->pci_ib_p, ino);
6787c478bd9Sstevel@tonic-gate if (mondo == 0) {
6797c478bd9Sstevel@tonic-gate DEBUG1(DBG_R_INTX, dip, "can't get mondo for ino %x\n", ino);
6807c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
6817c478bd9Sstevel@tonic-gate }
6827c478bd9Sstevel@tonic-gate ino = IB_MONDO_TO_INO(mondo);
6837c478bd9Sstevel@tonic-gate
6847c478bd9Sstevel@tonic-gate mutex_enter(&ib_p->ib_ino_lst_mutex);
6857c478bd9Sstevel@tonic-gate ino_p = ib_locate_ino(ib_p, ino);
6867c478bd9Sstevel@tonic-gate if (!ino_p) {
6877c478bd9Sstevel@tonic-gate int r = cb_remove_xintr(pci_p, dip, rdip, ino, mondo);
6887c478bd9Sstevel@tonic-gate if (r != DDI_SUCCESS)
6897c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d-xintr: ino %x is invalid",
6907c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), ino);
6917c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex);
6927c478bd9Sstevel@tonic-gate return (r);
6937c478bd9Sstevel@tonic-gate }
6947c478bd9Sstevel@tonic-gate
695b0fc0e77Sgovinda ipil_p = ib_ino_locate_ipil(ino_p, hdlp->ih_pri);
696b0fc0e77Sgovinda ih_p = ib_intr_locate_ih(ipil_p, rdip, hdlp->ih_inum);
697b0fc0e77Sgovinda ib_ino_rem_intr(pci_p, ipil_p, ih_p);
6987c478bd9Sstevel@tonic-gate intr_dist_cpuid_rem_device_weight(ino_p->ino_cpuid, rdip);
699b0fc0e77Sgovinda if (ipil_p->ipil_ih_size == 0) {
7007c478bd9Sstevel@tonic-gate IB_INO_INTR_PEND(ib_clear_intr_reg_addr(ib_p, ino));
7017c478bd9Sstevel@tonic-gate hdlp->ih_vector = CB_MONDO_TO_XMONDO(cb_p, mondo);
7027c478bd9Sstevel@tonic-gate
7037c478bd9Sstevel@tonic-gate i_ddi_rem_ivintr(hdlp);
704b0fc0e77Sgovinda ib_delete_ino_pil(ib_p, ipil_p);
7057c478bd9Sstevel@tonic-gate }
7067c478bd9Sstevel@tonic-gate
7077c478bd9Sstevel@tonic-gate /* re-enable interrupt only if mapping register still shared */
708b0fc0e77Sgovinda if (ib_ino_map_reg_unshare(ib_p, ino, ino_p) || ino_p->ino_ipil_size) {
7097c478bd9Sstevel@tonic-gate IB_INO_INTR_ON(ino_p->ino_map_reg);
7107c478bd9Sstevel@tonic-gate *ino_p->ino_map_reg;
7117c478bd9Sstevel@tonic-gate }
7127c478bd9Sstevel@tonic-gate mutex_exit(&ib_p->ib_ino_lst_mutex);
7137c478bd9Sstevel@tonic-gate
714b0fc0e77Sgovinda if (ino_p->ino_ipil_size == 0)
7157c478bd9Sstevel@tonic-gate kmem_free(ino_p, sizeof (ib_ino_info_t));
7167c478bd9Sstevel@tonic-gate
7177c478bd9Sstevel@tonic-gate DEBUG1(DBG_R_INTX, dip, "success! mondo=%x\n", mondo);
7187c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
7197c478bd9Sstevel@tonic-gate }
7207c478bd9Sstevel@tonic-gate
7217c478bd9Sstevel@tonic-gate /*
7227c478bd9Sstevel@tonic-gate * free the pci_inos array allocated during pci_intr_setup. the actual
7237c478bd9Sstevel@tonic-gate * interrupts are torn down by their respective block destroy routines:
7247c478bd9Sstevel@tonic-gate * cb_destroy, pbm_destroy, and ib_destroy.
7257c478bd9Sstevel@tonic-gate */
7267c478bd9Sstevel@tonic-gate void
pci_intr_teardown(pci_t * pci_p)7277c478bd9Sstevel@tonic-gate pci_intr_teardown(pci_t *pci_p)
7287c478bd9Sstevel@tonic-gate {
7297c478bd9Sstevel@tonic-gate kmem_free(pci_p->pci_inos, pci_p->pci_inos_len);
7307c478bd9Sstevel@tonic-gate pci_p->pci_inos = NULL;
7317c478bd9Sstevel@tonic-gate pci_p->pci_inos_len = 0;
7327c478bd9Sstevel@tonic-gate }
733