1*24996536Smickey /* $OpenBSD: pci_intr_fixup.c,v 1.47 2005/10/26 22:10:00 mickey 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> 1046661564bSmickey 1056661564bSmickey #include <dev/pci/pcireg.h> 1066661564bSmickey #include <dev/pci/pcivar.h> 1076661564bSmickey #include <dev/pci/pcidevs.h> 1086661564bSmickey 109e2331c6cSderaadt #include <i386/pci/pcibiosvar.h> 1106661564bSmickey 1116661564bSmickey struct pciintr_link_map { 11264f0e01bSmickey int link, clink, irq, fixup_stage; 1136661564bSmickey u_int16_t bitmap; 1146661564bSmickey SIMPLEQ_ENTRY(pciintr_link_map) list; 1156661564bSmickey }; 1166661564bSmickey 117b25264e3Smickey pciintr_icu_tag_t pciintr_icu_tag = NULL; 1186661564bSmickey pciintr_icu_handle_t pciintr_icu_handle; 1196661564bSmickey 1200edf2c54Smickey #ifdef PCIBIOS_IRQS_HINT 1210edf2c54Smickey int pcibios_irqs_hint = PCIBIOS_IRQS_HINT; 1220edf2c54Smickey #endif 1230edf2c54Smickey 124c4071fd1Smillert struct pciintr_link_map *pciintr_link_lookup(int); 125c4071fd1Smillert struct pcibios_intr_routing *pciintr_pir_lookup(int, int); 126c4071fd1Smillert int pciintr_bitmap_count_irq(int, int *); 1276661564bSmickey 1286661564bSmickey SIMPLEQ_HEAD(, pciintr_link_map) pciintr_link_map_list; 1296661564bSmickey 1306661564bSmickey const struct pciintr_icu_table { 1316661564bSmickey pci_vendor_id_t piit_vendor; 1326661564bSmickey pci_product_id_t piit_product; 133c4071fd1Smillert int (*piit_init)(pci_chipset_tag_t, 1346661564bSmickey bus_space_tag_t, pcitag_t, pciintr_icu_tag_t *, 135c4071fd1Smillert pciintr_icu_handle_t *); 1366661564bSmickey } pciintr_icu_table[] = { 1376661564bSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371MX, 1386661564bSmickey piix_init }, 1396661564bSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371AB_ISA, 1406661564bSmickey piix_init }, 1416661564bSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371FB_ISA, 1426661564bSmickey piix_init }, 1436661564bSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371SB_ISA, 1446661564bSmickey piix_init }, 145ea8e013cSho { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AA_LPC, 146ea8e013cSho piix_init }, 14753003c45Smickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_LPC, 14853003c45Smickey piix_init }, 14953003c45Smickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BAM_LPC, 15053003c45Smickey piix_init }, 151b9a626b7Smickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801CA_LPC, 152b9a626b7Smickey piix_init }, 1536d805c04Smickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801CAM_LPC, 1546d805c04Smickey piix_init }, 1556d805c04Smickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801DB_LPC, 1566d805c04Smickey piix_init }, 1575b6ecbecSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801EB_LPC, 1585b6ecbecSmickey piix_init }, 1596eced139Sbeck { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801FB_LPC, 1606eced139Sbeck piix_init }, 161d984c6bdSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GB_LPC, 162d984c6bdSmickey piix_init }, 163aa5f4fe6Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6300ESB_LPC, 164aa5f4fe6Sbrad piix_init }, 1656661564bSmickey 1666661564bSmickey { PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C558, 1676661564bSmickey opti82c558_init }, 1686661564bSmickey { PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C700, 1696661564bSmickey opti82c700_init }, 1706661564bSmickey 1718a1eb7fcSbrad { PCI_VENDOR_RCC, PCI_PRODUCT_RCC_OSB4, 172bd25a23dSmickey osb4_init }, 173bd25a23dSmickey { PCI_VENDOR_RCC, PCI_PRODUCT_RCC_CSB5, 174bd25a23dSmickey osb4_init }, 175bd25a23dSmickey 17664f0e01bSmickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C596A, 17764f0e01bSmickey via82c586_init, }, 1786661564bSmickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C586_ISA, 1796661564bSmickey via82c586_init, }, 18064f0e01bSmickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C686A_ISA, 18192598216Smickey via82c586_init }, 182eedf424eSmickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8366_ISA, 183eedf424eSmickey via82c586_init }, 18492598216Smickey 18592598216Smickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8231_ISA, 18692598216Smickey via8231_init }, 187*24996536Smickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8233_ISA, 188*24996536Smickey via8231_init }, 189*24996536Smickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8235_ISA, 190*24996536Smickey via8231_init }, 191bc465bf0Shenning { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237_ISA, 192bc465bf0Shenning via8231_init }, 1936661564bSmickey 1946661564bSmickey { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_85C503, 1956661564bSmickey sis85c503_init }, 1966661564bSmickey 197cc48d299Smickey { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC756_PMC, 19867218ad0Smickey amd756_init }, 19964c49bbaSmickey { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_766_ISA, 20064c49bbaSmickey amd756_init }, 20167218ad0Smickey 2022766fe41Smillert { PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M1533, 2032766fe41Smillert ali1543_init }, 2042766fe41Smillert 2057853e030Smickey { PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M1543, 2067853e030Smickey ali1543_init }, 2077853e030Smickey 2086661564bSmickey { 0, 0, 2096661564bSmickey NULL }, 2106661564bSmickey }; 2116661564bSmickey 212c4071fd1Smillert const struct pciintr_icu_table *pciintr_icu_lookup(pcireg_t); 2136661564bSmickey 2146661564bSmickey const struct pciintr_icu_table * 2156661564bSmickey pciintr_icu_lookup(id) 2166661564bSmickey pcireg_t id; 2176661564bSmickey { 2186661564bSmickey const struct pciintr_icu_table *piit; 2196661564bSmickey 22064f0e01bSmickey for (piit = pciintr_icu_table; piit->piit_init != NULL; piit++) 2216661564bSmickey if (PCI_VENDOR(id) == piit->piit_vendor && 2226661564bSmickey PCI_PRODUCT(id) == piit->piit_product) 2236661564bSmickey return (piit); 2246661564bSmickey 2256661564bSmickey return (NULL); 2266661564bSmickey } 2276661564bSmickey 2286661564bSmickey struct pciintr_link_map * 2290edf2c54Smickey pciintr_link_lookup(link) 2306661564bSmickey int link; 2316661564bSmickey { 2326661564bSmickey struct pciintr_link_map *l; 2336661564bSmickey 2346661564bSmickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 23564f0e01bSmickey l = SIMPLEQ_NEXT(l, list)) 2366661564bSmickey if (l->link == link) 2376661564bSmickey return (l); 2386661564bSmickey 2396661564bSmickey return (NULL); 2406661564bSmickey } 2416661564bSmickey 24264f0e01bSmickey static __inline struct pciintr_link_map * 24364f0e01bSmickey pciintr_link_alloc(pci_chipset_tag_t pc, struct pcibios_intr_routing *pir, int pin) 2446661564bSmickey { 2450edf2c54Smickey int link = pir->linkmap[pin].link, clink, irq; 2466661564bSmickey struct pciintr_link_map *l, *lstart; 2476661564bSmickey 248b25264e3Smickey if (pciintr_icu_tag != NULL) { 2490edf2c54Smickey /* 2500edf2c54Smickey * Get the canonical link value for this entry. 2510edf2c54Smickey */ 252b25264e3Smickey if (pciintr_icu_getclink(pciintr_icu_tag, pciintr_icu_handle, 253b25264e3Smickey link, &clink) != 0) { 2540edf2c54Smickey /* 2550edf2c54Smickey * ICU doesn't understand the link value. 2560edf2c54Smickey * Just ignore this PIR entry. 2570edf2c54Smickey */ 25864f0e01bSmickey PCIBIOS_PRINTV(("pciintr_link_alloc: bus %d device %d: " 25964f0e01bSmickey "ignoring link 0x%02x\n", pir->bus, 26064f0e01bSmickey PIR_DEVFUNC_DEVICE(pir->device), link)); 2610edf2c54Smickey return (NULL); 2620edf2c54Smickey } 2630edf2c54Smickey 2640edf2c54Smickey /* 265b25264e3Smickey * Check the link value by asking the ICU for the 266b25264e3Smickey * canonical link value. 2670edf2c54Smickey * Also, determine if this PIRQ is mapped to an IRQ. 2680edf2c54Smickey */ 269b25264e3Smickey if (pciintr_icu_get_intr(pciintr_icu_tag, pciintr_icu_handle, 270b25264e3Smickey clink, &irq) != 0) { 2710edf2c54Smickey /* 2720edf2c54Smickey * ICU doesn't understand the canonical link value. 2730edf2c54Smickey * Just ignore this PIR entry. 2740edf2c54Smickey */ 27564f0e01bSmickey PCIBIOS_PRINTV(("pciintr_link_alloc: " 276b25264e3Smickey "bus %d device %d link 0x%02x: " 277b25264e3Smickey "ignoring PIRQ 0x%02x\n", pir->bus, 27864f0e01bSmickey PIR_DEVFUNC_DEVICE(pir->device), link, clink)); 2790edf2c54Smickey return (NULL); 2800edf2c54Smickey } 281b25264e3Smickey } 2820edf2c54Smickey 28364f0e01bSmickey if ((l = malloc(sizeof(*l), M_DEVBUF, M_NOWAIT)) == NULL) 2840edf2c54Smickey return (NULL); 2856661564bSmickey 2866661564bSmickey memset(l, 0, sizeof(*l)); 2876661564bSmickey 2880edf2c54Smickey l->link = link; 2896661564bSmickey l->bitmap = pir->linkmap[pin].bitmap; 290b25264e3Smickey if (pciintr_icu_tag != NULL) { /* compatible PCI ICU found */ 2910edf2c54Smickey l->clink = clink; 2920edf2c54Smickey l->irq = irq; /* maybe I386_PCI_INTERRUPT_LINE_NO_CONNECTION */ 293b25264e3Smickey } else { 29464f0e01bSmickey l->clink = link; 295b25264e3Smickey l->irq = I386_PCI_INTERRUPT_LINE_NO_CONNECTION; 296b25264e3Smickey } 2976661564bSmickey 2986661564bSmickey lstart = SIMPLEQ_FIRST(&pciintr_link_map_list); 2996661564bSmickey if (lstart == NULL || lstart->link < l->link) 3006661564bSmickey SIMPLEQ_INSERT_TAIL(&pciintr_link_map_list, l, list); 3016661564bSmickey else 3026661564bSmickey SIMPLEQ_INSERT_HEAD(&pciintr_link_map_list, l, list); 3036661564bSmickey 3046661564bSmickey return (l); 3056661564bSmickey } 3066661564bSmickey 3076661564bSmickey struct pcibios_intr_routing * 3086661564bSmickey pciintr_pir_lookup(bus, device) 3096661564bSmickey int bus, device; 3106661564bSmickey { 3116661564bSmickey struct pcibios_intr_routing *pir; 3126661564bSmickey int entry; 3136661564bSmickey 3146661564bSmickey if (pcibios_pir_table == NULL) 3156661564bSmickey return (NULL); 3166661564bSmickey 3176661564bSmickey for (entry = 0; entry < pcibios_pir_table_nentries; entry++) { 3186661564bSmickey pir = &pcibios_pir_table[entry]; 3190edf2c54Smickey if (pir->bus == bus && 3200edf2c54Smickey PIR_DEVFUNC_DEVICE(pir->device) == device) 3216661564bSmickey return (pir); 3226661564bSmickey } 3236661564bSmickey 3246661564bSmickey return (NULL); 3256661564bSmickey } 3266661564bSmickey 32764f0e01bSmickey int 3280edf2c54Smickey pciintr_bitmap_count_irq(irq_bitmap, irqp) 3290edf2c54Smickey int irq_bitmap, *irqp; 3300edf2c54Smickey { 3310edf2c54Smickey int i, bit, count = 0, irq = I386_PCI_INTERRUPT_LINE_NO_CONNECTION; 3320edf2c54Smickey 33364f0e01bSmickey if (irq_bitmap != 0) 33464f0e01bSmickey for (i = 0, bit = 1; i < 16; i++, bit <<= 1) 3350edf2c54Smickey if (irq_bitmap & bit) { 3360edf2c54Smickey irq = i; 3370edf2c54Smickey count++; 3380edf2c54Smickey } 33964f0e01bSmickey 3400edf2c54Smickey *irqp = irq; 3410edf2c54Smickey return (count); 3420edf2c54Smickey } 3430edf2c54Smickey 34464f0e01bSmickey static __inline int 34564f0e01bSmickey pciintr_link_init(pci_chipset_tag_t pc) 3466661564bSmickey { 347b25264e3Smickey int entry, pin, link; 3486661564bSmickey struct pcibios_intr_routing *pir; 3496661564bSmickey struct pciintr_link_map *l; 3506661564bSmickey 3516661564bSmickey if (pcibios_pir_table == NULL) { 3526661564bSmickey /* No PIR table; can't do anything. */ 3536661564bSmickey printf("pciintr_link_init: no PIR table\n"); 3546661564bSmickey return (1); 3556661564bSmickey } 3566661564bSmickey 3576661564bSmickey SIMPLEQ_INIT(&pciintr_link_map_list); 3586661564bSmickey 3596661564bSmickey for (entry = 0; entry < pcibios_pir_table_nentries; entry++) { 3606661564bSmickey pir = &pcibios_pir_table[entry]; 3610edf2c54Smickey for (pin = 0; pin < PCI_INTERRUPT_PIN_MAX; pin++) { 36264f0e01bSmickey if ((link = pir->linkmap[pin].link) == 0) 3636661564bSmickey /* No connection for this pin. */ 3646661564bSmickey continue; 36564f0e01bSmickey 3666661564bSmickey /* 3676661564bSmickey * Multiple devices may be wired to the same 3686661564bSmickey * interrupt; check to see if we've seen this 3696661564bSmickey * one already. If not, allocate a new link 3706661564bSmickey * map entry and stuff it in the map. 3716661564bSmickey */ 37264f0e01bSmickey if ((l = pciintr_link_lookup(link)) == NULL) 37364f0e01bSmickey pciintr_link_alloc(pc, pir, pin); 37464f0e01bSmickey else if (pir->linkmap[pin].bitmap != l->bitmap) { 3750edf2c54Smickey /* 3760edf2c54Smickey * violates PCI IRQ Routing Table Specification 3770edf2c54Smickey */ 37864f0e01bSmickey PCIBIOS_PRINTV(("pciintr_link_init: " 3790edf2c54Smickey "bus %d device %d link 0x%02x: " 3800edf2c54Smickey "bad irq bitmap 0x%04x, " 38164f0e01bSmickey "should be 0x%04x\n", pir->bus, 38264f0e01bSmickey PIR_DEVFUNC_DEVICE(pir->device), link, 38364f0e01bSmickey pir->linkmap[pin].bitmap, l->bitmap)); 3840edf2c54Smickey /* safer value. */ 3850edf2c54Smickey l->bitmap &= pir->linkmap[pin].bitmap; 3860edf2c54Smickey /* XXX - or, should ignore this entry? */ 3870edf2c54Smickey } 3886661564bSmickey } 3896661564bSmickey } 3906661564bSmickey 391b25264e3Smickey return (0); 392b25264e3Smickey } 393b25264e3Smickey 394b25264e3Smickey /* 395b25264e3Smickey * No compatible PCI ICU found. 396b25264e3Smickey * Hopes the BIOS already setup the ICU. 397b25264e3Smickey */ 39864f0e01bSmickey static __inline int 39964f0e01bSmickey pciintr_guess_irq(void) 400b25264e3Smickey { 401b25264e3Smickey struct pciintr_link_map *l; 402b25264e3Smickey int irq, guessed = 0; 403b25264e3Smickey 404b25264e3Smickey /* 405b25264e3Smickey * Stage 1: If only one IRQ is available for the link, use it. 406b25264e3Smickey */ 407b25264e3Smickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 408b25264e3Smickey l = SIMPLEQ_NEXT(l, list)) { 409b25264e3Smickey if (l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) 410b25264e3Smickey continue; 411b25264e3Smickey if (pciintr_bitmap_count_irq(l->bitmap, &irq) == 1) { 412b25264e3Smickey l->irq = irq; 413b25264e3Smickey l->fixup_stage = 1; 41464f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 415b25264e3Smickey printf("pciintr_guess_irq (stage 1): " 416b25264e3Smickey "guessing PIRQ 0x%02x to be IRQ %d\n", 417b25264e3Smickey l->clink, l->irq); 418b25264e3Smickey guessed = 1; 419b25264e3Smickey } 420b25264e3Smickey } 421b25264e3Smickey 422b25264e3Smickey return (guessed ? 0 : -1); 4236661564bSmickey } 4246661564bSmickey 42564f0e01bSmickey static __inline int 42664f0e01bSmickey pciintr_link_fixup(void) 4276661564bSmickey { 4286661564bSmickey struct pciintr_link_map *l; 4290edf2c54Smickey u_int16_t pciirq = 0; 43064f0e01bSmickey int irq; 4316661564bSmickey 4326661564bSmickey /* 4336661564bSmickey * First stage: Attempt to connect PIRQs which aren't 4346661564bSmickey * yet connected. 4356661564bSmickey */ 4366661564bSmickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 4376661564bSmickey l = SIMPLEQ_NEXT(l, list)) { 4380edf2c54Smickey if (l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 4396661564bSmickey /* 4400edf2c54Smickey * Interrupt is already connected. Don't do 4410edf2c54Smickey * anything to it. 4420edf2c54Smickey * In this case, l->fixup_stage == 0. 4436661564bSmickey */ 4440edf2c54Smickey pciirq |= 1 << l->irq; 44564f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 44664f0e01bSmickey printf("pciintr_link_fixup: PIRQ 0x%02x is " 44764f0e01bSmickey "already connected to IRQ %d\n", 44864f0e01bSmickey l->clink, l->irq); 4496661564bSmickey continue; 4506661564bSmickey } 4516661564bSmickey /* 4520edf2c54Smickey * Interrupt isn't connected. Attempt to assign it to an IRQ. 4536661564bSmickey */ 45464f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 4550edf2c54Smickey printf("pciintr_link_fixup: PIRQ 0x%02x not connected", 4566661564bSmickey l->clink); 45764f0e01bSmickey 4586661564bSmickey /* 4590edf2c54Smickey * Just do the easy case now; we'll defer the harder ones 4600edf2c54Smickey * to Stage 2. 4616661564bSmickey */ 4620edf2c54Smickey if (pciintr_bitmap_count_irq(l->bitmap, &irq) == 1) { 4630edf2c54Smickey l->irq = irq; 4646661564bSmickey l->fixup_stage = 1; 4650edf2c54Smickey pciirq |= 1 << irq; 46664f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 4676661564bSmickey printf(", assigning IRQ %d", l->irq); 4686661564bSmickey } 46964f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 4706661564bSmickey printf("\n"); 4716661564bSmickey } 4726661564bSmickey 4736661564bSmickey /* 4746661564bSmickey * Stage 2: Attempt to connect PIRQs which we didn't 4756661564bSmickey * connect in Stage 1. 4766661564bSmickey */ 4776661564bSmickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 47864f0e01bSmickey l = SIMPLEQ_NEXT(l, list)) 47964f0e01bSmickey if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION && 48064f0e01bSmickey (irq = ffs(l->bitmap & pciirq)) > 0) { 4816661564bSmickey /* 4820edf2c54Smickey * This IRQ is a valid PCI IRQ already 4830edf2c54Smickey * connected to another PIRQ, and also an 4840edf2c54Smickey * IRQ our PIRQ can use; connect it up! 4856661564bSmickey */ 4866661564bSmickey l->fixup_stage = 2; 48764f0e01bSmickey l->irq = irq - 1; 48864f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 4890edf2c54Smickey printf("pciintr_link_fixup (stage 2): " 4900edf2c54Smickey "assigning IRQ %d to PIRQ 0x%02x\n", 4910edf2c54Smickey l->irq, l->clink); 4926661564bSmickey } 4936661564bSmickey 4940edf2c54Smickey #ifdef PCIBIOS_IRQS_HINT 4956661564bSmickey /* 4960edf2c54Smickey * Stage 3: The worst case. I need configuration hint that 4970edf2c54Smickey * user supplied a mask for the PCI irqs 4986661564bSmickey */ 4990edf2c54Smickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 5000edf2c54Smickey l = SIMPLEQ_NEXT(l, list)) { 50164f0e01bSmickey if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION && 50264f0e01bSmickey (irq = ffs(l->bitmap & pcibios_irqs_hint)) > 0) { 5030edf2c54Smickey l->fixup_stage = 3; 50464f0e01bSmickey l->irq = irq - 1; 50564f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 5060edf2c54Smickey printf("pciintr_link_fixup (stage 3): " 5070edf2c54Smickey "assigning IRQ %d to PIRQ 0x%02x\n", 5080edf2c54Smickey l->irq, l->clink); 5090edf2c54Smickey } 5100edf2c54Smickey } 5110edf2c54Smickey #endif /* PCIBIOS_IRQS_HINT */ 5126661564bSmickey 51364f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 51464f0e01bSmickey printf("pciintr_link_fixup: piirq 0x%04x\n", pciirq); 51564f0e01bSmickey 5166661564bSmickey return (0); 5176661564bSmickey } 5186661564bSmickey 5196661564bSmickey int 52064f0e01bSmickey pci_intr_route_link(pc, ihp) 52164f0e01bSmickey pci_chipset_tag_t pc; 52264f0e01bSmickey pci_intr_handle_t *ihp; 5236661564bSmickey { 5246661564bSmickey struct pciintr_link_map *l; 52564f0e01bSmickey pcireg_t intr; 52664f0e01bSmickey int rv = 1; 52764f0e01bSmickey char *p = NULL; 5286661564bSmickey 5298b0f2e63Smickey if (pcibios_flags & PCIBIOS_INTR_FIXUP) 5308b0f2e63Smickey return 1; 5318b0f2e63Smickey 532ff51c22aSmickey if (ihp->line != 0 && 533ff51c22aSmickey ihp->line != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) 534ff51c22aSmickey pcibios_pir_header.exclusive_irq |= (1 << ihp->line); 535ff51c22aSmickey 53664f0e01bSmickey l = ihp->link; 53764f0e01bSmickey if (!l || pciintr_icu_tag == NULL) 53864f0e01bSmickey return (1); 5396661564bSmickey 5400edf2c54Smickey if (l->fixup_stage == 0) { 5410edf2c54Smickey if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 5420edf2c54Smickey /* Appropriate interrupt was not found. */ 54364f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 54464f0e01bSmickey printf("pci_intr_route_link: PIRQ 0x%02x: " 54564f0e01bSmickey "no IRQ, try " 54664f0e01bSmickey "\"option PCIBIOS_IRQS_HINT=0x%04x\"\n", 5470edf2c54Smickey l->clink, 5480edf2c54Smickey /* suggest irq 9/10/11, if possible */ 5490edf2c54Smickey (l->bitmap & 0x0e00) ? (l->bitmap & 0x0e00) 5500edf2c54Smickey : l->bitmap); 55164f0e01bSmickey } else 55264f0e01bSmickey p = " preserved BIOS setting"; 5530edf2c54Smickey } else { 5540edf2c54Smickey 5556661564bSmickey if (pciintr_icu_set_intr(pciintr_icu_tag, pciintr_icu_handle, 5566661564bSmickey l->clink, l->irq) != 0 || 55764f0e01bSmickey pciintr_icu_set_trigger(pciintr_icu_tag, pciintr_icu_handle, 5586661564bSmickey l->irq, IST_LEVEL) != 0) { 55964f0e01bSmickey p = " failed"; 56064f0e01bSmickey rv = 0; 56164f0e01bSmickey } else 56264f0e01bSmickey p = ""; 5636661564bSmickey } 56464f0e01bSmickey if (p && pcibios_flags & PCIBIOS_INTRDEBUG) 56564f0e01bSmickey printf("pci_intr_route_link: route PIRQ 0x%02x -> IRQ %d%s\n", 56664f0e01bSmickey l->clink, l->irq, p); 5676661564bSmickey 56864f0e01bSmickey if (!rv) 5696661564bSmickey return (0); 5700edf2c54Smickey 5716661564bSmickey /* 5720edf2c54Smickey * IRQs 14 and 15 are reserved for PCI IDE interrupts; don't muck 5736661564bSmickey * with them. 5746661564bSmickey */ 57564f0e01bSmickey if (ihp->line == 14 || ihp->line == 15) 57664f0e01bSmickey return (1); 57764f0e01bSmickey 57864f0e01bSmickey intr = pci_conf_read(pc, ihp->tag, PCI_INTERRUPT_REG); 57964f0e01bSmickey if (ihp->line != PCI_INTERRUPT_LINE(intr)) { 58064f0e01bSmickey intr &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT); 58164f0e01bSmickey intr |= (ihp->line << PCI_INTERRUPT_LINE_SHIFT); 58264f0e01bSmickey pci_conf_write(pc, ihp->tag, PCI_INTERRUPT_REG, intr); 5830edf2c54Smickey } 5846661564bSmickey 58564f0e01bSmickey return (1); 58664f0e01bSmickey } 58764f0e01bSmickey 58864f0e01bSmickey int 58964f0e01bSmickey pci_intr_post_fixup() 59064f0e01bSmickey { 59164f0e01bSmickey struct pciintr_link_map *l; 59264f0e01bSmickey int i, pciirq; 59364f0e01bSmickey 5948b0f2e63Smickey if (pcibios_flags & PCIBIOS_INTR_FIXUP) 5958b0f2e63Smickey return 1; 5968b0f2e63Smickey 59764f0e01bSmickey if (!pciintr_icu_handle) 59864f0e01bSmickey return 0; 59964f0e01bSmickey 60064f0e01bSmickey pciirq = pcibios_pir_header.exclusive_irq; 60164f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 60264f0e01bSmickey printf("pci_intr_post_fixup: PCI IRQs:"); 60364f0e01bSmickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); 60464f0e01bSmickey l != NULL; l = SIMPLEQ_NEXT(l, list)) 605ff51c22aSmickey if (l->fixup_stage == 0 && l->irq != 0 && 60664f0e01bSmickey l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 60764f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 60864f0e01bSmickey printf(" %d", l->irq); 60964f0e01bSmickey pciirq |= (1 << l->irq); 61064f0e01bSmickey } 61164f0e01bSmickey 61264f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 61364f0e01bSmickey printf("; ISA IRQs:"); 61464f0e01bSmickey for (i = 0; i < 16; i++) 61564f0e01bSmickey if (!(pciirq & (1 << i))) { 61664f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 61764f0e01bSmickey printf(" %d", i); 61864f0e01bSmickey pciintr_icu_set_trigger(pciintr_icu_tag, 61964f0e01bSmickey pciintr_icu_handle, i, IST_EDGE); 62064f0e01bSmickey } 62164f0e01bSmickey 62264f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 62364f0e01bSmickey printf("\n"); 62464f0e01bSmickey 62564f0e01bSmickey return (0); 62664f0e01bSmickey } 62764f0e01bSmickey 62864f0e01bSmickey int 62964f0e01bSmickey pci_intr_header_fixup(pc, tag, ihp) 63064f0e01bSmickey pci_chipset_tag_t pc; 63164f0e01bSmickey pcitag_t tag; 63264f0e01bSmickey pci_intr_handle_t *ihp; 63364f0e01bSmickey { 63464f0e01bSmickey struct pcibios_intr_routing *pir; 63564f0e01bSmickey struct pciintr_link_map *l; 63664f0e01bSmickey int irq, link, bus, device, function; 63764f0e01bSmickey char *p = NULL; 63864f0e01bSmickey 6398b0f2e63Smickey if (pcibios_flags & PCIBIOS_INTR_FIXUP) 6408b0f2e63Smickey return 1; 6418b0f2e63Smickey 64264f0e01bSmickey irq = ihp->line; 64364f0e01bSmickey ihp->link = NULL; 64464f0e01bSmickey ihp->tag = tag; 64564f0e01bSmickey pci_decompose_tag(pc, tag, &bus, &device, &function); 64664f0e01bSmickey 64764f0e01bSmickey if ((pir = pciintr_pir_lookup(bus, device)) == NULL || 64864f0e01bSmickey (link = pir->linkmap[ihp->pin - 1].link) == 0) { 64964f0e01bSmickey PCIBIOS_PRINTV(("Interrupt not connected; no need to change.")); 65064f0e01bSmickey return 1; 65164f0e01bSmickey } 65264f0e01bSmickey 65364f0e01bSmickey if ((l = pciintr_link_lookup(link)) == NULL) { 65464f0e01bSmickey /* 65564f0e01bSmickey * No link map entry. 65664f0e01bSmickey * Probably pciintr_icu_getclink() or pciintr_icu_get_intr() 65764f0e01bSmickey * was failed. 65864f0e01bSmickey */ 65964f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 66064f0e01bSmickey printf("pci_intr_header_fixup: no entry for link " 66164f0e01bSmickey "0x%02x (%d:%d:%d:%c)\n", 66264f0e01bSmickey link, bus, device, function, '@' + ihp->pin); 66364f0e01bSmickey return 1; 66464f0e01bSmickey } 66564f0e01bSmickey 6661120a2ccSmarkus ihp->link = l; 6671120a2ccSmarkus if (irq == 14 || irq == 15) { 66864f0e01bSmickey p = " WARNING: ignored"; 6691120a2ccSmarkus ihp->link = NULL; 6701120a2ccSmarkus } else if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 67164f0e01bSmickey 6720edf2c54Smickey /* Appropriate interrupt was not found. */ 67364f0e01bSmickey if (pciintr_icu_tag == NULL && ihp->line != 0 && 67464f0e01bSmickey ihp->line != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) 675b25264e3Smickey /* 676b25264e3Smickey * Do not print warning, 677b25264e3Smickey * if no compatible PCI ICU found, 678b25264e3Smickey * but the irq is already assigned by BIOS. 679b25264e3Smickey */ 68064f0e01bSmickey p = ""; 68164f0e01bSmickey else 68264f0e01bSmickey p = " WARNING: missing"; 68364f0e01bSmickey } else if (irq == 0 || irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 6840edf2c54Smickey 68564f0e01bSmickey p = " fixed up"; 68664f0e01bSmickey ihp->line = l->irq; 6870edf2c54Smickey 688a003464cSmickey } else if (pcibios_flags & PCIBIOS_FIXUP_FORCE) { 6890edf2c54Smickey /* routed by BIOS, but inconsistent */ 6900edf2c54Smickey /* believe PCI IRQ Routing table */ 69164f0e01bSmickey p = " WARNING: overriding"; 69264f0e01bSmickey ihp->line = l->irq; 69378b5d43cSmickey } else { 6940edf2c54Smickey /* believe PCI Interrupt Configuration Register (default) */ 69564f0e01bSmickey p = " WARNING: preserving"; 69678b5d43cSmickey ihp->line = l->irq = irq; 69778b5d43cSmickey } 6986661564bSmickey 69964f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) { 70064f0e01bSmickey register pcireg_t id = pci_conf_read(pc, tag, PCI_ID_REG); 70164f0e01bSmickey 70278b5d43cSmickey printf("\n%d:%d:%d %04x:%04x pin %c clink 0x%02x irq %d " 70378b5d43cSmickey "stage %d %s irq %d\n", bus, device, function, 70464f0e01bSmickey PCI_VENDOR(id), PCI_PRODUCT(id), '@' + ihp->pin, l->clink, 70564f0e01bSmickey ((l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION)? 70664f0e01bSmickey -1 : l->irq), l->fixup_stage, p, irq); 70764f0e01bSmickey } 70864f0e01bSmickey 70964f0e01bSmickey return (1); 7106661564bSmickey } 7116661564bSmickey 7126661564bSmickey int 713df73a7d0Smickey pci_intr_fixup(sc, pc, iot) 714df73a7d0Smickey struct pcibios_softc *sc; 7156661564bSmickey pci_chipset_tag_t pc; 7166661564bSmickey bus_space_tag_t iot; 7176661564bSmickey { 718df73a7d0Smickey struct pcibios_pir_header *pirh = &pcibios_pir_header; 7196661564bSmickey const struct pciintr_icu_table *piit = NULL; 7206661564bSmickey pcitag_t icutag; 7216661564bSmickey 7226661564bSmickey /* 7236661564bSmickey * Attempt to initialize our PCI interrupt router. If 7246661564bSmickey * the PIR Table is present in ROM, use the location 7256661564bSmickey * specified by the PIR Table, and use the compat ID, 7266661564bSmickey * if present. Otherwise, we have to look for the router 7276661564bSmickey * ourselves (the PCI-ISA bridge). 728911088d6Smickey * 729911088d6Smickey * A number of buggy BIOS implementations leave the router 730911088d6Smickey * entry as 000:00:0, which is typically not the correct 731911088d6Smickey * device/function. If the router device address is set to 732911088d6Smickey * this value, and the compatible router entry is undefined 733911088d6Smickey * (zero is the correct value to indicate undefined), then we 734911088d6Smickey * work on the basis it is most likely an error, and search 735911088d6Smickey * the entire device-space of bus 0 (but obviously starting 736911088d6Smickey * with 000:00:0, in case that really is the right one). 7376661564bSmickey */ 738911088d6Smickey if (pirh->signature != 0 && (pirh->router_bus != 0 || 739911088d6Smickey pirh->router_devfunc != 0 || pirh->compat_router != 0)) { 740911088d6Smickey 7416c0a4d12Smickey icutag = pci_make_tag(pc, pirh->router_bus, 7426c0a4d12Smickey PIR_DEVFUNC_DEVICE(pirh->router_devfunc), 7436c0a4d12Smickey PIR_DEVFUNC_FUNCTION(pirh->router_devfunc)); 744911088d6Smickey if (pirh->compat_router == 0 || 745911088d6Smickey (piit = pciintr_icu_lookup(pirh->compat_router)) == NULL) { 7466661564bSmickey /* 7476661564bSmickey * No compat ID, or don't know the compat ID? Read 7486661564bSmickey * it from the configuration header. 7496661564bSmickey */ 7506c0a4d12Smickey pirh->compat_router = pci_conf_read(pc, icutag, 751911088d6Smickey PCI_ID_REG); 7526661564bSmickey } 7536661564bSmickey if (piit == NULL) 754911088d6Smickey piit = pciintr_icu_lookup(pirh->compat_router); 7556661564bSmickey } else { 7566661564bSmickey int device, maxdevs = pci_bus_maxdevs(pc, 0); 7576661564bSmickey 7586661564bSmickey /* 7596661564bSmickey * Search configuration space for a known interrupt 7606661564bSmickey * router. 7616661564bSmickey */ 7626661564bSmickey for (device = 0; device < maxdevs; device++) { 763911088d6Smickey const struct pci_quirkdata *qd; 764911088d6Smickey int function, nfuncs; 765911088d6Smickey pcireg_t icuid; 766911088d6Smickey pcireg_t bhlcr; 767911088d6Smickey 7686661564bSmickey icutag = pci_make_tag(pc, 0, device, 0); 7696661564bSmickey icuid = pci_conf_read(pc, icutag, PCI_ID_REG); 7706661564bSmickey 7716661564bSmickey /* Invalid vendor ID value? */ 7726661564bSmickey if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID) 7736661564bSmickey continue; 7746661564bSmickey /* XXX Not invalid, but we've done this ~forever. */ 7756661564bSmickey if (PCI_VENDOR(icuid) == 0) 7766661564bSmickey continue; 7776661564bSmickey 778911088d6Smickey qd = pci_lookup_quirkdata(PCI_VENDOR(icuid), 779911088d6Smickey PCI_PRODUCT(icuid)); 780911088d6Smickey 781911088d6Smickey bhlcr = pci_conf_read(pc, icutag, PCI_BHLC_REG); 782911088d6Smickey if (PCI_HDRTYPE_MULTIFN(bhlcr) || (qd != NULL && 783911088d6Smickey (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0)) 784911088d6Smickey nfuncs = 8; 785911088d6Smickey else 786911088d6Smickey nfuncs = 1; 787911088d6Smickey 788911088d6Smickey for (function = 0; function < nfuncs; function++) { 789911088d6Smickey icutag = pci_make_tag(pc, 0, device, function); 790911088d6Smickey icuid = pci_conf_read(pc, icutag, PCI_ID_REG); 791911088d6Smickey 792911088d6Smickey /* Invalid vendor ID value? */ 793911088d6Smickey if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID) 794911088d6Smickey continue; 795911088d6Smickey /* Not invalid, but we've done this ~forever. */ 796911088d6Smickey if (PCI_VENDOR(icuid) == 0) 797911088d6Smickey continue; 798911088d6Smickey 799df73a7d0Smickey if ((piit = pciintr_icu_lookup(icuid))) { 800df73a7d0Smickey pirh->compat_router = icuid; 801df73a7d0Smickey pirh->router_bus = 0; 802df73a7d0Smickey pirh->router_devfunc = 803df73a7d0Smickey PIR_DEVFUNC_COMPOSE(device, 0); 8046661564bSmickey break; 8056661564bSmickey } 8066661564bSmickey } 807911088d6Smickey 808911088d6Smickey if (piit != NULL) 809911088d6Smickey break; 810911088d6Smickey } 811df73a7d0Smickey } 8126661564bSmickey 8136661564bSmickey if (piit == NULL) { 814df73a7d0Smickey printf("%s: no compatible PCI ICU found", sc->sc_dev.dv_xname); 815911088d6Smickey if (pirh->signature != 0 && pirh->compat_router != 0) 816b25264e3Smickey printf(": ICU vendor 0x%04x product 0x%04x", 817911088d6Smickey PCI_VENDOR(pirh->compat_router), 818911088d6Smickey PCI_PRODUCT(pirh->compat_router)); 819b25264e3Smickey printf("\n"); 820b25264e3Smickey if (!(pcibios_flags & PCIBIOS_INTR_GUESS)) { 82164f0e01bSmickey if (pciintr_link_init(pc)) 822b25264e3Smickey return (-1); /* non-fatal */ 823b25264e3Smickey if (pciintr_guess_irq()) 824b25264e3Smickey return (-1); /* non-fatal */ 825bb701a32Smickey } 826bb701a32Smickey return (0); 827df73a7d0Smickey } else { 828df73a7d0Smickey char devinfo[256]; 829df73a7d0Smickey 830df73a7d0Smickey printf("%s: PCI Interrupt Router at %03d:%02d:%01d", 831df73a7d0Smickey sc->sc_dev.dv_xname, pirh->router_bus, 832df73a7d0Smickey PIR_DEVFUNC_DEVICE(pirh->router_devfunc), 833df73a7d0Smickey PIR_DEVFUNC_FUNCTION(pirh->router_devfunc)); 834df73a7d0Smickey if (pirh->compat_router != 0) { 8352627362dSho pci_devinfo(pirh->compat_router, 0, 0, devinfo, 8362627362dSho sizeof devinfo); 837df73a7d0Smickey printf(" (%s)", devinfo); 838df73a7d0Smickey } 839df73a7d0Smickey printf("\n"); 8406661564bSmickey } 8416661564bSmickey 8426661564bSmickey /* 8436661564bSmickey * Initialize the PCI ICU. 8446661564bSmickey */ 8456661564bSmickey if ((*piit->piit_init)(pc, iot, icutag, &pciintr_icu_tag, 8466661564bSmickey &pciintr_icu_handle) != 0) 8476661564bSmickey return (-1); /* non-fatal */ 8486661564bSmickey 8496661564bSmickey /* 8506661564bSmickey * Initialize the PCI interrupt link map. 8516661564bSmickey */ 85264f0e01bSmickey if (pciintr_link_init(pc)) 8536661564bSmickey return (-1); /* non-fatal */ 8546661564bSmickey 8556661564bSmickey /* 8566661564bSmickey * Fix up the link->IRQ mappings. 8576661564bSmickey */ 8586661564bSmickey if (pciintr_link_fixup() != 0) 8596661564bSmickey return (-1); /* non-fatal */ 8606661564bSmickey 86164f0e01bSmickey return (0); 8626661564bSmickey } 863