1*14516421Sjcs /* $OpenBSD: pci_intr_fixup.c,v 1.60 2008/05/17 18:35:12 jcs Exp $ */ 2b25264e3Smickey /* $NetBSD: pci_intr_fixup.c,v 1.10 2000/08/10 21:18:27 soda Exp $ */ 36661564bSmickey 464f0e01bSmickey /* 564f0e01bSmickey * Copyright (c) 2001 Michael Shalayeff 664f0e01bSmickey * All rights reserved. 764f0e01bSmickey * 864f0e01bSmickey * Redistribution and use in source and binary forms, with or without 964f0e01bSmickey * modification, are permitted provided that the following conditions 1064f0e01bSmickey * are met: 1164f0e01bSmickey * 1. Redistributions of source code must retain the above copyright 1264f0e01bSmickey * notice, this list of conditions and the following disclaimer. 1364f0e01bSmickey * 2. Redistributions in binary form must reproduce the above copyright 1464f0e01bSmickey * notice, this list of conditions and the following disclaimer in the 1564f0e01bSmickey * documentation and/or other materials provided with the distribution. 1664f0e01bSmickey * 1764f0e01bSmickey * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1864f0e01bSmickey * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1964f0e01bSmickey * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2064f0e01bSmickey * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 2164f0e01bSmickey * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2264f0e01bSmickey * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2364f0e01bSmickey * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2464f0e01bSmickey * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 2564f0e01bSmickey * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 2664f0e01bSmickey * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 2764f0e01bSmickey * THE POSSIBILITY OF SUCH DAMAGE. 2864f0e01bSmickey */ 296661564bSmickey /*- 306661564bSmickey * Copyright (c) 1999 The NetBSD Foundation, Inc. 316661564bSmickey * All rights reserved. 326661564bSmickey * 336661564bSmickey * This code is derived from software contributed to The NetBSD Foundation 346661564bSmickey * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 356661564bSmickey * NASA Ames Research Center. 366661564bSmickey * 376661564bSmickey * Redistribution and use in source and binary forms, with or without 386661564bSmickey * modification, are permitted provided that the following conditions 396661564bSmickey * are met: 406661564bSmickey * 1. Redistributions of source code must retain the above copyright 416661564bSmickey * notice, this list of conditions and the following disclaimer. 426661564bSmickey * 2. Redistributions in binary form must reproduce the above copyright 436661564bSmickey * notice, this list of conditions and the following disclaimer in the 446661564bSmickey * documentation and/or other materials provided with the distribution. 456661564bSmickey * 3. All advertising materials mentioning features or use of this software 466661564bSmickey * must display the following acknowledgement: 476661564bSmickey * This product includes software developed by the NetBSD 486661564bSmickey * Foundation, Inc. and its contributors. 496661564bSmickey * 4. Neither the name of The NetBSD Foundation nor the names of its 506661564bSmickey * contributors may be used to endorse or promote products derived 516661564bSmickey * from this software without specific prior written permission. 526661564bSmickey * 536661564bSmickey * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 546661564bSmickey * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 556661564bSmickey * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 566661564bSmickey * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 576661564bSmickey * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 586661564bSmickey * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 596661564bSmickey * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 606661564bSmickey * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 616661564bSmickey * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 626661564bSmickey * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 636661564bSmickey * POSSIBILITY OF SUCH DAMAGE. 646661564bSmickey */ 656661564bSmickey /* 666661564bSmickey * Copyright (c) 1999, by UCHIYAMA Yasushi 676661564bSmickey * All rights reserved. 686661564bSmickey * 696661564bSmickey * Redistribution and use in source and binary forms, with or without 706661564bSmickey * modification, are permitted provided that the following conditions 716661564bSmickey * are met: 726661564bSmickey * 1. Redistributions of source code must retain the above copyright 736661564bSmickey * notice, this list of conditions and the following disclaimer. 746661564bSmickey * 2. The name of the developer may NOT be used to endorse or promote products 756661564bSmickey * derived from this software without specific prior written permission. 766661564bSmickey * 776661564bSmickey * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 786661564bSmickey * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 796661564bSmickey * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 806661564bSmickey * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 816661564bSmickey * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 826661564bSmickey * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 836661564bSmickey * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 846661564bSmickey * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 856661564bSmickey * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 866661564bSmickey * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 876661564bSmickey * SUCH DAMAGE. 886661564bSmickey */ 896661564bSmickey 906661564bSmickey /* 916661564bSmickey * PCI Interrupt Router support. 926661564bSmickey */ 936661564bSmickey 946661564bSmickey #include <sys/param.h> 956661564bSmickey #include <sys/systm.h> 966661564bSmickey #include <sys/kernel.h> 976661564bSmickey #include <sys/malloc.h> 986661564bSmickey #include <sys/queue.h> 996661564bSmickey #include <sys/device.h> 1006661564bSmickey 1016661564bSmickey #include <machine/bus.h> 1026661564bSmickey #include <machine/intr.h> 103012ea299Sniklas #include <machine/i8259.h> 104a25c7806Smickey #include <machine/i82093var.h> 1056661564bSmickey 1066661564bSmickey #include <dev/pci/pcireg.h> 1076661564bSmickey #include <dev/pci/pcivar.h> 1086661564bSmickey #include <dev/pci/pcidevs.h> 1096661564bSmickey 110e2331c6cSderaadt #include <i386/pci/pcibiosvar.h> 1116661564bSmickey 1126661564bSmickey struct pciintr_link_map { 11364f0e01bSmickey int link, clink, irq, fixup_stage; 1146661564bSmickey u_int16_t bitmap; 1156661564bSmickey SIMPLEQ_ENTRY(pciintr_link_map) list; 1166661564bSmickey }; 1176661564bSmickey 118b25264e3Smickey pciintr_icu_tag_t pciintr_icu_tag = NULL; 1196661564bSmickey pciintr_icu_handle_t pciintr_icu_handle; 1206661564bSmickey 1210edf2c54Smickey #ifdef PCIBIOS_IRQS_HINT 1220edf2c54Smickey int pcibios_irqs_hint = PCIBIOS_IRQS_HINT; 1230edf2c54Smickey #endif 1240edf2c54Smickey 125c4071fd1Smillert struct pciintr_link_map *pciintr_link_lookup(int); 126c4071fd1Smillert struct pcibios_intr_routing *pciintr_pir_lookup(int, int); 127c4071fd1Smillert int pciintr_bitmap_count_irq(int, int *); 1286661564bSmickey 1296661564bSmickey SIMPLEQ_HEAD(, pciintr_link_map) pciintr_link_map_list; 1306661564bSmickey 1316661564bSmickey const struct pciintr_icu_table { 1326661564bSmickey pci_vendor_id_t piit_vendor; 1336661564bSmickey pci_product_id_t piit_product; 134c4071fd1Smillert int (*piit_init)(pci_chipset_tag_t, 1356661564bSmickey bus_space_tag_t, pcitag_t, pciintr_icu_tag_t *, 136c4071fd1Smillert pciintr_icu_handle_t *); 1376661564bSmickey } pciintr_icu_table[] = { 13823f11131Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6300ESB_LPC, 13923f11131Sbrad piix_init }, 140b566768eSbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6321ESB_LPC, 141b566768eSbrad piix_init }, 1426661564bSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371MX, 1436661564bSmickey piix_init }, 1446661564bSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371AB_ISA, 1456661564bSmickey piix_init }, 1466661564bSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371FB_ISA, 1476661564bSmickey piix_init }, 1486661564bSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371SB_ISA, 1496661564bSmickey piix_init }, 15023f11131Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82440MX_ISA, 15123f11131Sbrad piix_init }, 152ea8e013cSho { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AA_LPC, 153ea8e013cSho piix_init }, 15423f11131Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AB_LPC, 15523f11131Sbrad piix_init }, 15653003c45Smickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_LPC, 15753003c45Smickey piix_init }, 15853003c45Smickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BAM_LPC, 15953003c45Smickey piix_init }, 160b9a626b7Smickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801CA_LPC, 161b9a626b7Smickey piix_init }, 1626d805c04Smickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801CAM_LPC, 1636d805c04Smickey piix_init }, 1646d805c04Smickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801DB_LPC, 1656d805c04Smickey piix_init }, 166aa7d4239Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801DBM_LPC, 167aa7d4239Sbrad piix_init }, 16823f11131Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801E_LPC, 16923f11131Sbrad piix_init }, 1705b6ecbecSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801EB_LPC, 1715b6ecbecSmickey piix_init }, 1726eced139Sbeck { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801FB_LPC, 1736eced139Sbeck piix_init }, 17423f11131Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801FBM_LPC, 17523f11131Sbrad piix_init }, 176d984c6bdSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GB_LPC, 177d984c6bdSmickey piix_init }, 17823f11131Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GBM_LPC, 17923f11131Sbrad piix_init }, 18023f11131Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GH_LPC, 181aa5f4fe6Sbrad piix_init }, 182b566768eSbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GHM_LPC, 183b566768eSbrad piix_init }, 18409e7fbc8Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801IB_LPC, 18509e7fbc8Sbrad piix_init }, 18609e7fbc8Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801IH_LPC, 18709e7fbc8Sbrad piix_init }, 18809e7fbc8Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801IO_LPC, 18909e7fbc8Sbrad piix_init }, 19009e7fbc8Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801IR_LPC, 19109e7fbc8Sbrad piix_init }, 1926661564bSmickey 1936661564bSmickey { PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C558, 1946661564bSmickey opti82c558_init }, 1956661564bSmickey { PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C700, 1966661564bSmickey opti82c700_init }, 1976661564bSmickey 1988a1eb7fcSbrad { PCI_VENDOR_RCC, PCI_PRODUCT_RCC_OSB4, 199bd25a23dSmickey osb4_init }, 200bd25a23dSmickey { PCI_VENDOR_RCC, PCI_PRODUCT_RCC_CSB5, 201bd25a23dSmickey osb4_init }, 202bd25a23dSmickey 2036661564bSmickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C586_ISA, 2046661564bSmickey via82c586_init, }, 205139f38fdSbrad { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C596A, 206139f38fdSbrad via82c586_init, }, 20764f0e01bSmickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C686A_ISA, 20892598216Smickey via82c586_init }, 20992598216Smickey 21092598216Smickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8231_ISA, 21192598216Smickey via8231_init }, 212139f38fdSbrad { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8233_ISA, 213139f38fdSbrad via8231_init }, 214275f08b3Skettenis { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8233A_ISA, 21524996536Smickey via8231_init }, 21624996536Smickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8235_ISA, 21724996536Smickey via8231_init }, 218bc465bf0Shenning { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237_ISA, 219bc465bf0Shenning via8231_init }, 2203bd326a1Sgrange { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237A_ISA, 2213bd326a1Sgrange via8231_init }, 222*14516421Sjcs { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237S_ISA, 223*14516421Sjcs via8231_init }, 2246661564bSmickey 2256661564bSmickey { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_85C503, 2266661564bSmickey sis85c503_init }, 227139f38fdSbrad { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_962, 228139f38fdSbrad sis85c503_init }, 2290d58a2caSjsg { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_963, 2300d58a2caSjsg sis85c503_init }, 2316661564bSmickey 232cc48d299Smickey { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC756_PMC, 23367218ad0Smickey amd756_init }, 2341b2c3d0dSbrad { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_766_PMC, 2351b2c3d0dSbrad amd756_init }, 2361b2c3d0dSbrad { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC768_PMC, 23764c49bbaSmickey amd756_init }, 23867218ad0Smickey 2392766fe41Smillert { PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M1533, 2402766fe41Smillert ali1543_init }, 2412766fe41Smillert 2427853e030Smickey { PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M1543, 2437853e030Smickey ali1543_init }, 2447853e030Smickey 2456661564bSmickey { 0, 0, 2466661564bSmickey NULL }, 2476661564bSmickey }; 2486661564bSmickey 249c4071fd1Smillert const struct pciintr_icu_table *pciintr_icu_lookup(pcireg_t); 2506661564bSmickey 2516661564bSmickey const struct pciintr_icu_table * 2526661564bSmickey pciintr_icu_lookup(id) 2536661564bSmickey pcireg_t id; 2546661564bSmickey { 2556661564bSmickey const struct pciintr_icu_table *piit; 2566661564bSmickey 25764f0e01bSmickey for (piit = pciintr_icu_table; piit->piit_init != NULL; piit++) 2586661564bSmickey if (PCI_VENDOR(id) == piit->piit_vendor && 2596661564bSmickey PCI_PRODUCT(id) == piit->piit_product) 2606661564bSmickey return (piit); 2616661564bSmickey 2626661564bSmickey return (NULL); 2636661564bSmickey } 2646661564bSmickey 2656661564bSmickey struct pciintr_link_map * 26608f75f72Sjsg pciintr_link_lookup(int link) 2676661564bSmickey { 2686661564bSmickey struct pciintr_link_map *l; 2696661564bSmickey 2706661564bSmickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 27164f0e01bSmickey l = SIMPLEQ_NEXT(l, list)) 2726661564bSmickey if (l->link == link) 2736661564bSmickey return (l); 2746661564bSmickey 2756661564bSmickey return (NULL); 2766661564bSmickey } 2776661564bSmickey 27864f0e01bSmickey static __inline struct pciintr_link_map * 27964f0e01bSmickey pciintr_link_alloc(pci_chipset_tag_t pc, struct pcibios_intr_routing *pir, int pin) 2806661564bSmickey { 2810edf2c54Smickey int link = pir->linkmap[pin].link, clink, irq; 2826661564bSmickey struct pciintr_link_map *l, *lstart; 2836661564bSmickey 284b25264e3Smickey if (pciintr_icu_tag != NULL) { 2850edf2c54Smickey /* 2860edf2c54Smickey * Get the canonical link value for this entry. 2870edf2c54Smickey */ 288b25264e3Smickey if (pciintr_icu_getclink(pciintr_icu_tag, pciintr_icu_handle, 289b25264e3Smickey link, &clink) != 0) { 2900edf2c54Smickey /* 2910edf2c54Smickey * ICU doesn't understand the link value. 2920edf2c54Smickey * Just ignore this PIR entry. 2930edf2c54Smickey */ 29464f0e01bSmickey PCIBIOS_PRINTV(("pciintr_link_alloc: bus %d device %d: " 29564f0e01bSmickey "ignoring link 0x%02x\n", pir->bus, 29664f0e01bSmickey PIR_DEVFUNC_DEVICE(pir->device), link)); 2970edf2c54Smickey return (NULL); 2980edf2c54Smickey } 2990edf2c54Smickey 3000edf2c54Smickey /* 301b25264e3Smickey * Check the link value by asking the ICU for the 302b25264e3Smickey * canonical link value. 3030edf2c54Smickey * Also, determine if this PIRQ is mapped to an IRQ. 3040edf2c54Smickey */ 305b25264e3Smickey if (pciintr_icu_get_intr(pciintr_icu_tag, pciintr_icu_handle, 306b25264e3Smickey clink, &irq) != 0) { 3070edf2c54Smickey /* 3080edf2c54Smickey * ICU doesn't understand the canonical link value. 3090edf2c54Smickey * Just ignore this PIR entry. 3100edf2c54Smickey */ 31164f0e01bSmickey PCIBIOS_PRINTV(("pciintr_link_alloc: " 312b25264e3Smickey "bus %d device %d link 0x%02x: " 313b25264e3Smickey "ignoring PIRQ 0x%02x\n", pir->bus, 31464f0e01bSmickey PIR_DEVFUNC_DEVICE(pir->device), link, clink)); 3150edf2c54Smickey return (NULL); 3160edf2c54Smickey } 317b25264e3Smickey } 3180edf2c54Smickey 31928a8f404Sart if ((l = malloc(sizeof(*l), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 3200edf2c54Smickey return (NULL); 3216661564bSmickey 3220edf2c54Smickey l->link = link; 3236661564bSmickey l->bitmap = pir->linkmap[pin].bitmap; 324b25264e3Smickey if (pciintr_icu_tag != NULL) { /* compatible PCI ICU found */ 3250edf2c54Smickey l->clink = clink; 3260edf2c54Smickey l->irq = irq; /* maybe I386_PCI_INTERRUPT_LINE_NO_CONNECTION */ 327b25264e3Smickey } else { 32864f0e01bSmickey l->clink = link; 329b25264e3Smickey l->irq = I386_PCI_INTERRUPT_LINE_NO_CONNECTION; 330b25264e3Smickey } 3316661564bSmickey 3326661564bSmickey lstart = SIMPLEQ_FIRST(&pciintr_link_map_list); 3336661564bSmickey if (lstart == NULL || lstart->link < l->link) 3346661564bSmickey SIMPLEQ_INSERT_TAIL(&pciintr_link_map_list, l, list); 3356661564bSmickey else 3366661564bSmickey SIMPLEQ_INSERT_HEAD(&pciintr_link_map_list, l, list); 3376661564bSmickey 3386661564bSmickey return (l); 3396661564bSmickey } 3406661564bSmickey 3416661564bSmickey struct pcibios_intr_routing * 34208f75f72Sjsg pciintr_pir_lookup(int bus, int device) 3436661564bSmickey { 3446661564bSmickey struct pcibios_intr_routing *pir; 3456661564bSmickey int entry; 3466661564bSmickey 3476661564bSmickey if (pcibios_pir_table == NULL) 3486661564bSmickey return (NULL); 3496661564bSmickey 3506661564bSmickey for (entry = 0; entry < pcibios_pir_table_nentries; entry++) { 3516661564bSmickey pir = &pcibios_pir_table[entry]; 3520edf2c54Smickey if (pir->bus == bus && 3530edf2c54Smickey PIR_DEVFUNC_DEVICE(pir->device) == device) 3546661564bSmickey return (pir); 3556661564bSmickey } 3566661564bSmickey 3576661564bSmickey return (NULL); 3586661564bSmickey } 3596661564bSmickey 36064f0e01bSmickey int 36108f75f72Sjsg pciintr_bitmap_count_irq(int irq_bitmap, int *irqp) 3620edf2c54Smickey { 3630edf2c54Smickey int i, bit, count = 0, irq = I386_PCI_INTERRUPT_LINE_NO_CONNECTION; 3640edf2c54Smickey 36564f0e01bSmickey if (irq_bitmap != 0) 36664f0e01bSmickey for (i = 0, bit = 1; i < 16; i++, bit <<= 1) 3670edf2c54Smickey if (irq_bitmap & bit) { 3680edf2c54Smickey irq = i; 3690edf2c54Smickey count++; 3700edf2c54Smickey } 37164f0e01bSmickey 3720edf2c54Smickey *irqp = irq; 3730edf2c54Smickey return (count); 3740edf2c54Smickey } 3750edf2c54Smickey 37664f0e01bSmickey static __inline int 37764f0e01bSmickey pciintr_link_init(pci_chipset_tag_t pc) 3786661564bSmickey { 379b25264e3Smickey int entry, pin, link; 3806661564bSmickey struct pcibios_intr_routing *pir; 3816661564bSmickey struct pciintr_link_map *l; 3826661564bSmickey 3836661564bSmickey if (pcibios_pir_table == NULL) { 3846661564bSmickey /* No PIR table; can't do anything. */ 3856661564bSmickey printf("pciintr_link_init: no PIR table\n"); 3866661564bSmickey return (1); 3876661564bSmickey } 3886661564bSmickey 3896661564bSmickey SIMPLEQ_INIT(&pciintr_link_map_list); 3906661564bSmickey 3916661564bSmickey for (entry = 0; entry < pcibios_pir_table_nentries; entry++) { 3926661564bSmickey pir = &pcibios_pir_table[entry]; 3930edf2c54Smickey for (pin = 0; pin < PCI_INTERRUPT_PIN_MAX; pin++) { 39464f0e01bSmickey if ((link = pir->linkmap[pin].link) == 0) 3956661564bSmickey /* No connection for this pin. */ 3966661564bSmickey continue; 39764f0e01bSmickey 3986661564bSmickey /* 3996661564bSmickey * Multiple devices may be wired to the same 4006661564bSmickey * interrupt; check to see if we've seen this 4016661564bSmickey * one already. If not, allocate a new link 4026661564bSmickey * map entry and stuff it in the map. 4036661564bSmickey */ 40464f0e01bSmickey if ((l = pciintr_link_lookup(link)) == NULL) 40564f0e01bSmickey pciintr_link_alloc(pc, pir, pin); 40664f0e01bSmickey else if (pir->linkmap[pin].bitmap != l->bitmap) { 4070edf2c54Smickey /* 4080edf2c54Smickey * violates PCI IRQ Routing Table Specification 4090edf2c54Smickey */ 41064f0e01bSmickey PCIBIOS_PRINTV(("pciintr_link_init: " 4110edf2c54Smickey "bus %d device %d link 0x%02x: " 4120edf2c54Smickey "bad irq bitmap 0x%04x, " 41364f0e01bSmickey "should be 0x%04x\n", pir->bus, 41464f0e01bSmickey PIR_DEVFUNC_DEVICE(pir->device), link, 41564f0e01bSmickey pir->linkmap[pin].bitmap, l->bitmap)); 4160edf2c54Smickey /* safer value. */ 4170edf2c54Smickey l->bitmap &= pir->linkmap[pin].bitmap; 4180edf2c54Smickey /* XXX - or, should ignore this entry? */ 4190edf2c54Smickey } 4206661564bSmickey } 4216661564bSmickey } 4226661564bSmickey 423b25264e3Smickey return (0); 424b25264e3Smickey } 425b25264e3Smickey 426b25264e3Smickey /* 427b25264e3Smickey * No compatible PCI ICU found. 428b25264e3Smickey * Hopes the BIOS already setup the ICU. 429b25264e3Smickey */ 43064f0e01bSmickey static __inline int 43164f0e01bSmickey pciintr_guess_irq(void) 432b25264e3Smickey { 433b25264e3Smickey struct pciintr_link_map *l; 434b25264e3Smickey int irq, guessed = 0; 435b25264e3Smickey 436b25264e3Smickey /* 437b25264e3Smickey * Stage 1: If only one IRQ is available for the link, use it. 438b25264e3Smickey */ 439b25264e3Smickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 440b25264e3Smickey l = SIMPLEQ_NEXT(l, list)) { 441b25264e3Smickey if (l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) 442b25264e3Smickey continue; 443b25264e3Smickey if (pciintr_bitmap_count_irq(l->bitmap, &irq) == 1) { 444b25264e3Smickey l->irq = irq; 445b25264e3Smickey l->fixup_stage = 1; 44664f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 447b25264e3Smickey printf("pciintr_guess_irq (stage 1): " 448b25264e3Smickey "guessing PIRQ 0x%02x to be IRQ %d\n", 449b25264e3Smickey l->clink, l->irq); 450b25264e3Smickey guessed = 1; 451b25264e3Smickey } 452b25264e3Smickey } 453b25264e3Smickey 454b25264e3Smickey return (guessed ? 0 : -1); 4556661564bSmickey } 4566661564bSmickey 45764f0e01bSmickey static __inline int 45864f0e01bSmickey pciintr_link_fixup(void) 4596661564bSmickey { 4606661564bSmickey struct pciintr_link_map *l; 4610edf2c54Smickey u_int16_t pciirq = 0; 46264f0e01bSmickey int irq; 4636661564bSmickey 4646661564bSmickey /* 4656661564bSmickey * First stage: Attempt to connect PIRQs which aren't 4666661564bSmickey * yet connected. 4676661564bSmickey */ 4686661564bSmickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 4696661564bSmickey l = SIMPLEQ_NEXT(l, list)) { 4700edf2c54Smickey if (l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 4716661564bSmickey /* 4720edf2c54Smickey * Interrupt is already connected. Don't do 4730edf2c54Smickey * anything to it. 4740edf2c54Smickey * In this case, l->fixup_stage == 0. 4756661564bSmickey */ 4760edf2c54Smickey pciirq |= 1 << l->irq; 47764f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 47864f0e01bSmickey printf("pciintr_link_fixup: PIRQ 0x%02x is " 47964f0e01bSmickey "already connected to IRQ %d\n", 48064f0e01bSmickey l->clink, l->irq); 4816661564bSmickey continue; 4826661564bSmickey } 4836661564bSmickey /* 4840edf2c54Smickey * Interrupt isn't connected. Attempt to assign it to an IRQ. 4856661564bSmickey */ 48664f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 4870edf2c54Smickey printf("pciintr_link_fixup: PIRQ 0x%02x not connected", 4886661564bSmickey l->clink); 48964f0e01bSmickey 4906661564bSmickey /* 4910edf2c54Smickey * Just do the easy case now; we'll defer the harder ones 4920edf2c54Smickey * to Stage 2. 4936661564bSmickey */ 4940edf2c54Smickey if (pciintr_bitmap_count_irq(l->bitmap, &irq) == 1) { 4950edf2c54Smickey l->irq = irq; 4966661564bSmickey l->fixup_stage = 1; 4970edf2c54Smickey pciirq |= 1 << irq; 49864f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 4996661564bSmickey printf(", assigning IRQ %d", l->irq); 5006661564bSmickey } 50164f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 5026661564bSmickey printf("\n"); 5036661564bSmickey } 5046661564bSmickey 5056661564bSmickey /* 5066661564bSmickey * Stage 2: Attempt to connect PIRQs which we didn't 5076661564bSmickey * connect in Stage 1. 5086661564bSmickey */ 5096661564bSmickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 51064f0e01bSmickey l = SIMPLEQ_NEXT(l, list)) 51164f0e01bSmickey if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION && 51264f0e01bSmickey (irq = ffs(l->bitmap & pciirq)) > 0) { 5136661564bSmickey /* 5140edf2c54Smickey * This IRQ is a valid PCI IRQ already 5150edf2c54Smickey * connected to another PIRQ, and also an 5160edf2c54Smickey * IRQ our PIRQ can use; connect it up! 5176661564bSmickey */ 5186661564bSmickey l->fixup_stage = 2; 51964f0e01bSmickey l->irq = irq - 1; 52064f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 5210edf2c54Smickey printf("pciintr_link_fixup (stage 2): " 5220edf2c54Smickey "assigning IRQ %d to PIRQ 0x%02x\n", 5230edf2c54Smickey l->irq, l->clink); 5246661564bSmickey } 5256661564bSmickey 5260edf2c54Smickey #ifdef PCIBIOS_IRQS_HINT 5276661564bSmickey /* 5280edf2c54Smickey * Stage 3: The worst case. I need configuration hint that 5290edf2c54Smickey * user supplied a mask for the PCI irqs 5306661564bSmickey */ 5310edf2c54Smickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 5320edf2c54Smickey l = SIMPLEQ_NEXT(l, list)) { 53364f0e01bSmickey if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION && 53464f0e01bSmickey (irq = ffs(l->bitmap & pcibios_irqs_hint)) > 0) { 5350edf2c54Smickey l->fixup_stage = 3; 53664f0e01bSmickey l->irq = irq - 1; 53764f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 5380edf2c54Smickey printf("pciintr_link_fixup (stage 3): " 5390edf2c54Smickey "assigning IRQ %d to PIRQ 0x%02x\n", 5400edf2c54Smickey l->irq, l->clink); 5410edf2c54Smickey } 5420edf2c54Smickey } 5430edf2c54Smickey #endif /* PCIBIOS_IRQS_HINT */ 5446661564bSmickey 54564f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 54664f0e01bSmickey printf("pciintr_link_fixup: piirq 0x%04x\n", pciirq); 54764f0e01bSmickey 5486661564bSmickey return (0); 5496661564bSmickey } 5506661564bSmickey 5516661564bSmickey int 55208f75f72Sjsg pci_intr_route_link(pci_chipset_tag_t pc, pci_intr_handle_t *ihp) 5536661564bSmickey { 5546661564bSmickey struct pciintr_link_map *l; 55564f0e01bSmickey pcireg_t intr; 556a25c7806Smickey int irq, rv = 1; 55764f0e01bSmickey char *p = NULL; 5586661564bSmickey 5598b0f2e63Smickey if (pcibios_flags & PCIBIOS_INTR_FIXUP) 5608b0f2e63Smickey return 1; 5618b0f2e63Smickey 562a25c7806Smickey irq = ihp->line & APIC_INT_LINE_MASK; 563a25c7806Smickey if (irq != 0 && irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) 564a25c7806Smickey pcibios_pir_header.exclusive_irq |= 1 << irq; 565ff51c22aSmickey 56664f0e01bSmickey l = ihp->link; 56764f0e01bSmickey if (!l || pciintr_icu_tag == NULL) 56864f0e01bSmickey return (1); 5696661564bSmickey 5700edf2c54Smickey if (l->fixup_stage == 0) { 5710edf2c54Smickey if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 5720edf2c54Smickey /* Appropriate interrupt was not found. */ 57364f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 57464f0e01bSmickey printf("pci_intr_route_link: PIRQ 0x%02x: " 57564f0e01bSmickey "no IRQ, try " 57664f0e01bSmickey "\"option PCIBIOS_IRQS_HINT=0x%04x\"\n", 5770edf2c54Smickey l->clink, 5780edf2c54Smickey /* suggest irq 9/10/11, if possible */ 5790edf2c54Smickey (l->bitmap & 0x0e00) ? (l->bitmap & 0x0e00) 5800edf2c54Smickey : l->bitmap); 58164f0e01bSmickey } else 58264f0e01bSmickey p = " preserved BIOS setting"; 5830edf2c54Smickey } else { 5840edf2c54Smickey 5856661564bSmickey if (pciintr_icu_set_intr(pciintr_icu_tag, pciintr_icu_handle, 5866661564bSmickey l->clink, l->irq) != 0 || 58764f0e01bSmickey pciintr_icu_set_trigger(pciintr_icu_tag, pciintr_icu_handle, 5886661564bSmickey l->irq, IST_LEVEL) != 0) { 58964f0e01bSmickey p = " failed"; 59064f0e01bSmickey rv = 0; 59164f0e01bSmickey } else 59264f0e01bSmickey p = ""; 5936661564bSmickey } 59464f0e01bSmickey if (p && pcibios_flags & PCIBIOS_INTRDEBUG) 59564f0e01bSmickey printf("pci_intr_route_link: route PIRQ 0x%02x -> IRQ %d%s\n", 59664f0e01bSmickey l->clink, l->irq, p); 5976661564bSmickey 59864f0e01bSmickey if (!rv) 5996661564bSmickey return (0); 6000edf2c54Smickey 6016661564bSmickey /* 6020edf2c54Smickey * IRQs 14 and 15 are reserved for PCI IDE interrupts; don't muck 6036661564bSmickey * with them. 6046661564bSmickey */ 605a25c7806Smickey if (irq == 14 || irq == 15) 60664f0e01bSmickey return (1); 60764f0e01bSmickey 60864f0e01bSmickey intr = pci_conf_read(pc, ihp->tag, PCI_INTERRUPT_REG); 609a25c7806Smickey if (irq != PCI_INTERRUPT_LINE(intr)) { 61064f0e01bSmickey intr &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT); 611a25c7806Smickey intr |= irq << PCI_INTERRUPT_LINE_SHIFT; 61264f0e01bSmickey pci_conf_write(pc, ihp->tag, PCI_INTERRUPT_REG, intr); 6130edf2c54Smickey } 6146661564bSmickey 61564f0e01bSmickey return (1); 61664f0e01bSmickey } 61764f0e01bSmickey 61864f0e01bSmickey int 61908f75f72Sjsg pci_intr_post_fixup(void) 62064f0e01bSmickey { 62164f0e01bSmickey struct pciintr_link_map *l; 62264f0e01bSmickey int i, pciirq; 62364f0e01bSmickey 6248b0f2e63Smickey if (pcibios_flags & PCIBIOS_INTR_FIXUP) 6258b0f2e63Smickey return 1; 6268b0f2e63Smickey 62764f0e01bSmickey if (!pciintr_icu_handle) 62864f0e01bSmickey return 0; 62964f0e01bSmickey 63064f0e01bSmickey pciirq = pcibios_pir_header.exclusive_irq; 63164f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 63264f0e01bSmickey printf("pci_intr_post_fixup: PCI IRQs:"); 63364f0e01bSmickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); 63464f0e01bSmickey l != NULL; l = SIMPLEQ_NEXT(l, list)) 635ff51c22aSmickey if (l->fixup_stage == 0 && l->irq != 0 && 63664f0e01bSmickey l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 63764f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 63864f0e01bSmickey printf(" %d", l->irq); 63964f0e01bSmickey pciirq |= (1 << l->irq); 64064f0e01bSmickey } 64164f0e01bSmickey 64264f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 64364f0e01bSmickey printf("; ISA IRQs:"); 64464f0e01bSmickey for (i = 0; i < 16; i++) 64564f0e01bSmickey if (!(pciirq & (1 << i))) { 64664f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 64764f0e01bSmickey printf(" %d", i); 64864f0e01bSmickey pciintr_icu_set_trigger(pciintr_icu_tag, 64964f0e01bSmickey pciintr_icu_handle, i, IST_EDGE); 65064f0e01bSmickey } 65164f0e01bSmickey 65264f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 65364f0e01bSmickey printf("\n"); 65464f0e01bSmickey 65564f0e01bSmickey return (0); 65664f0e01bSmickey } 65764f0e01bSmickey 65864f0e01bSmickey int 65908f75f72Sjsg pci_intr_header_fixup(pci_chipset_tag_t pc, pcitag_t tag, 66008f75f72Sjsg pci_intr_handle_t *ihp) 66164f0e01bSmickey { 66264f0e01bSmickey struct pcibios_intr_routing *pir; 66364f0e01bSmickey struct pciintr_link_map *l; 66464f0e01bSmickey int irq, link, bus, device, function; 66564f0e01bSmickey char *p = NULL; 66664f0e01bSmickey 6678b0f2e63Smickey if (pcibios_flags & PCIBIOS_INTR_FIXUP) 6688b0f2e63Smickey return 1; 6698b0f2e63Smickey 670a25c7806Smickey irq = ihp->line & APIC_INT_LINE_MASK; 67164f0e01bSmickey ihp->link = NULL; 67264f0e01bSmickey ihp->tag = tag; 67364f0e01bSmickey pci_decompose_tag(pc, tag, &bus, &device, &function); 67464f0e01bSmickey 67564f0e01bSmickey if ((pir = pciintr_pir_lookup(bus, device)) == NULL || 67664f0e01bSmickey (link = pir->linkmap[ihp->pin - 1].link) == 0) { 67764f0e01bSmickey PCIBIOS_PRINTV(("Interrupt not connected; no need to change.")); 67864f0e01bSmickey return 1; 67964f0e01bSmickey } 68064f0e01bSmickey 68164f0e01bSmickey if ((l = pciintr_link_lookup(link)) == NULL) { 68264f0e01bSmickey /* 68364f0e01bSmickey * No link map entry. 68464f0e01bSmickey * Probably pciintr_icu_getclink() or pciintr_icu_get_intr() 685a25c7806Smickey * has failed. 68664f0e01bSmickey */ 68764f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 68864f0e01bSmickey printf("pci_intr_header_fixup: no entry for link " 68964f0e01bSmickey "0x%02x (%d:%d:%d:%c)\n", 69064f0e01bSmickey link, bus, device, function, '@' + ihp->pin); 69164f0e01bSmickey return 1; 69264f0e01bSmickey } 69364f0e01bSmickey 6941120a2ccSmarkus ihp->link = l; 6951120a2ccSmarkus if (irq == 14 || irq == 15) { 69664f0e01bSmickey p = " WARNING: ignored"; 6971120a2ccSmarkus ihp->link = NULL; 6981120a2ccSmarkus } else if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 69964f0e01bSmickey 7000edf2c54Smickey /* Appropriate interrupt was not found. */ 701a25c7806Smickey if (pciintr_icu_tag == NULL && irq != 0 && 702a25c7806Smickey irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) 703b25264e3Smickey /* 704b25264e3Smickey * Do not print warning, 705b25264e3Smickey * if no compatible PCI ICU found, 706b25264e3Smickey * but the irq is already assigned by BIOS. 707b25264e3Smickey */ 70864f0e01bSmickey p = ""; 70964f0e01bSmickey else 71064f0e01bSmickey p = " WARNING: missing"; 71164f0e01bSmickey } else if (irq == 0 || irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 7120edf2c54Smickey 71364f0e01bSmickey p = " fixed up"; 714a25c7806Smickey ihp->line = irq = l->irq; 7150edf2c54Smickey 716a003464cSmickey } else if (pcibios_flags & PCIBIOS_FIXUP_FORCE) { 7170edf2c54Smickey /* routed by BIOS, but inconsistent */ 7180edf2c54Smickey /* believe PCI IRQ Routing table */ 71964f0e01bSmickey p = " WARNING: overriding"; 720a25c7806Smickey ihp->line = irq = l->irq; 72178b5d43cSmickey } else { 7220edf2c54Smickey /* believe PCI Interrupt Configuration Register (default) */ 72364f0e01bSmickey p = " WARNING: preserving"; 724a25c7806Smickey ihp->line = (l->irq = irq) | (l->clink & PCI_INT_VIA_ISA); 72578b5d43cSmickey } 7266661564bSmickey 72764f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) { 72808f75f72Sjsg pcireg_t id = pci_conf_read(pc, tag, PCI_ID_REG); 72964f0e01bSmickey 73078b5d43cSmickey printf("\n%d:%d:%d %04x:%04x pin %c clink 0x%02x irq %d " 73178b5d43cSmickey "stage %d %s irq %d\n", bus, device, function, 73264f0e01bSmickey PCI_VENDOR(id), PCI_PRODUCT(id), '@' + ihp->pin, l->clink, 73364f0e01bSmickey ((l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION)? 73464f0e01bSmickey -1 : l->irq), l->fixup_stage, p, irq); 73564f0e01bSmickey } 73664f0e01bSmickey 73764f0e01bSmickey return (1); 7386661564bSmickey } 7396661564bSmickey 7406661564bSmickey int 74108f75f72Sjsg pci_intr_fixup(struct pcibios_softc *sc, pci_chipset_tag_t pc, 74208f75f72Sjsg bus_space_tag_t iot) 7436661564bSmickey { 744df73a7d0Smickey struct pcibios_pir_header *pirh = &pcibios_pir_header; 7456661564bSmickey const struct pciintr_icu_table *piit = NULL; 7466661564bSmickey pcitag_t icutag; 7476661564bSmickey 7486661564bSmickey /* 7496661564bSmickey * Attempt to initialize our PCI interrupt router. If 7506661564bSmickey * the PIR Table is present in ROM, use the location 7516661564bSmickey * specified by the PIR Table, and use the compat ID, 7526661564bSmickey * if present. Otherwise, we have to look for the router 7536661564bSmickey * ourselves (the PCI-ISA bridge). 754911088d6Smickey * 755911088d6Smickey * A number of buggy BIOS implementations leave the router 756911088d6Smickey * entry as 000:00:0, which is typically not the correct 757911088d6Smickey * device/function. If the router device address is set to 758911088d6Smickey * this value, and the compatible router entry is undefined 759911088d6Smickey * (zero is the correct value to indicate undefined), then we 760911088d6Smickey * work on the basis it is most likely an error, and search 761911088d6Smickey * the entire device-space of bus 0 (but obviously starting 762911088d6Smickey * with 000:00:0, in case that really is the right one). 7636661564bSmickey */ 764911088d6Smickey if (pirh->signature != 0 && (pirh->router_bus != 0 || 765911088d6Smickey pirh->router_devfunc != 0 || pirh->compat_router != 0)) { 766911088d6Smickey 7676c0a4d12Smickey icutag = pci_make_tag(pc, pirh->router_bus, 7686c0a4d12Smickey PIR_DEVFUNC_DEVICE(pirh->router_devfunc), 7696c0a4d12Smickey PIR_DEVFUNC_FUNCTION(pirh->router_devfunc)); 770911088d6Smickey if (pirh->compat_router == 0 || 771911088d6Smickey (piit = pciintr_icu_lookup(pirh->compat_router)) == NULL) { 7726661564bSmickey /* 7736661564bSmickey * No compat ID, or don't know the compat ID? Read 7746661564bSmickey * it from the configuration header. 7756661564bSmickey */ 7766c0a4d12Smickey pirh->compat_router = pci_conf_read(pc, icutag, 777911088d6Smickey PCI_ID_REG); 7786661564bSmickey } 7796661564bSmickey if (piit == NULL) 780911088d6Smickey piit = pciintr_icu_lookup(pirh->compat_router); 7816661564bSmickey } else { 7826661564bSmickey int device, maxdevs = pci_bus_maxdevs(pc, 0); 7836661564bSmickey 7846661564bSmickey /* 7856661564bSmickey * Search configuration space for a known interrupt 7866661564bSmickey * router. 7876661564bSmickey */ 7886661564bSmickey for (device = 0; device < maxdevs; device++) { 789911088d6Smickey const struct pci_quirkdata *qd; 790911088d6Smickey int function, nfuncs; 791911088d6Smickey pcireg_t icuid; 792911088d6Smickey pcireg_t bhlcr; 793911088d6Smickey 7946661564bSmickey icutag = pci_make_tag(pc, 0, device, 0); 7956661564bSmickey icuid = pci_conf_read(pc, icutag, PCI_ID_REG); 7966661564bSmickey 7976661564bSmickey /* Invalid vendor ID value? */ 7986661564bSmickey if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID) 7996661564bSmickey continue; 8006661564bSmickey /* XXX Not invalid, but we've done this ~forever. */ 8016661564bSmickey if (PCI_VENDOR(icuid) == 0) 8026661564bSmickey continue; 8036661564bSmickey 804911088d6Smickey qd = pci_lookup_quirkdata(PCI_VENDOR(icuid), 805911088d6Smickey PCI_PRODUCT(icuid)); 806911088d6Smickey 807911088d6Smickey bhlcr = pci_conf_read(pc, icutag, PCI_BHLC_REG); 808911088d6Smickey if (PCI_HDRTYPE_MULTIFN(bhlcr) || (qd != NULL && 809911088d6Smickey (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0)) 810911088d6Smickey nfuncs = 8; 811911088d6Smickey else 812911088d6Smickey nfuncs = 1; 813911088d6Smickey 814911088d6Smickey for (function = 0; function < nfuncs; function++) { 815911088d6Smickey icutag = pci_make_tag(pc, 0, device, function); 816911088d6Smickey icuid = pci_conf_read(pc, icutag, PCI_ID_REG); 817911088d6Smickey 818911088d6Smickey /* Invalid vendor ID value? */ 819911088d6Smickey if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID) 820911088d6Smickey continue; 821911088d6Smickey /* Not invalid, but we've done this ~forever. */ 822911088d6Smickey if (PCI_VENDOR(icuid) == 0) 823911088d6Smickey continue; 824911088d6Smickey 825df73a7d0Smickey if ((piit = pciintr_icu_lookup(icuid))) { 826df73a7d0Smickey pirh->compat_router = icuid; 827df73a7d0Smickey pirh->router_bus = 0; 828df73a7d0Smickey pirh->router_devfunc = 829df73a7d0Smickey PIR_DEVFUNC_COMPOSE(device, 0); 8306661564bSmickey break; 8316661564bSmickey } 8326661564bSmickey } 833911088d6Smickey 834911088d6Smickey if (piit != NULL) 835911088d6Smickey break; 836911088d6Smickey } 837df73a7d0Smickey } 8386661564bSmickey 8396661564bSmickey if (piit == NULL) { 840df73a7d0Smickey printf("%s: no compatible PCI ICU found", sc->sc_dev.dv_xname); 841911088d6Smickey if (pirh->signature != 0 && pirh->compat_router != 0) 842b25264e3Smickey printf(": ICU vendor 0x%04x product 0x%04x", 843911088d6Smickey PCI_VENDOR(pirh->compat_router), 844911088d6Smickey PCI_PRODUCT(pirh->compat_router)); 845b25264e3Smickey printf("\n"); 846b25264e3Smickey if (!(pcibios_flags & PCIBIOS_INTR_GUESS)) { 84764f0e01bSmickey if (pciintr_link_init(pc)) 848b25264e3Smickey return (-1); /* non-fatal */ 849b25264e3Smickey if (pciintr_guess_irq()) 850b25264e3Smickey return (-1); /* non-fatal */ 851bb701a32Smickey } 852bb701a32Smickey return (0); 853df73a7d0Smickey } else { 854df73a7d0Smickey char devinfo[256]; 855df73a7d0Smickey 856df73a7d0Smickey printf("%s: PCI Interrupt Router at %03d:%02d:%01d", 857df73a7d0Smickey sc->sc_dev.dv_xname, pirh->router_bus, 858df73a7d0Smickey PIR_DEVFUNC_DEVICE(pirh->router_devfunc), 859df73a7d0Smickey PIR_DEVFUNC_FUNCTION(pirh->router_devfunc)); 860df73a7d0Smickey if (pirh->compat_router != 0) { 8612627362dSho pci_devinfo(pirh->compat_router, 0, 0, devinfo, 8622627362dSho sizeof devinfo); 863df73a7d0Smickey printf(" (%s)", devinfo); 864df73a7d0Smickey } 865df73a7d0Smickey printf("\n"); 8666661564bSmickey } 8676661564bSmickey 8686661564bSmickey /* 8696661564bSmickey * Initialize the PCI ICU. 8706661564bSmickey */ 8716661564bSmickey if ((*piit->piit_init)(pc, iot, icutag, &pciintr_icu_tag, 8726661564bSmickey &pciintr_icu_handle) != 0) 8736661564bSmickey return (-1); /* non-fatal */ 8746661564bSmickey 8756661564bSmickey /* 8766661564bSmickey * Initialize the PCI interrupt link map. 8776661564bSmickey */ 87864f0e01bSmickey if (pciintr_link_init(pc)) 8796661564bSmickey return (-1); /* non-fatal */ 8806661564bSmickey 8816661564bSmickey /* 8826661564bSmickey * Fix up the link->IRQ mappings. 8836661564bSmickey */ 8846661564bSmickey if (pciintr_link_fixup() != 0) 8856661564bSmickey return (-1); /* non-fatal */ 8866661564bSmickey 88764f0e01bSmickey return (0); 8886661564bSmickey } 889