1*aa5f4fe6Sbrad /* $OpenBSD: pci_intr_fixup.c,v 1.45 2005/10/24 22:10:51 brad 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 }, 163*aa5f4fe6Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6300ESB_LPC, 164*aa5f4fe6Sbrad 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 }, 1876661564bSmickey 1886661564bSmickey { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_85C503, 1896661564bSmickey sis85c503_init }, 1906661564bSmickey 191cc48d299Smickey { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC756_PMC, 19267218ad0Smickey amd756_init }, 19364c49bbaSmickey { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_766_ISA, 19464c49bbaSmickey amd756_init }, 19567218ad0Smickey 1962766fe41Smillert { PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M1533, 1972766fe41Smillert ali1543_init }, 1982766fe41Smillert 1997853e030Smickey { PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M1543, 2007853e030Smickey ali1543_init }, 2017853e030Smickey 2026661564bSmickey { 0, 0, 2036661564bSmickey NULL }, 2046661564bSmickey }; 2056661564bSmickey 206c4071fd1Smillert const struct pciintr_icu_table *pciintr_icu_lookup(pcireg_t); 2076661564bSmickey 2086661564bSmickey const struct pciintr_icu_table * 2096661564bSmickey pciintr_icu_lookup(id) 2106661564bSmickey pcireg_t id; 2116661564bSmickey { 2126661564bSmickey const struct pciintr_icu_table *piit; 2136661564bSmickey 21464f0e01bSmickey for (piit = pciintr_icu_table; piit->piit_init != NULL; piit++) 2156661564bSmickey if (PCI_VENDOR(id) == piit->piit_vendor && 2166661564bSmickey PCI_PRODUCT(id) == piit->piit_product) 2176661564bSmickey return (piit); 2186661564bSmickey 2196661564bSmickey return (NULL); 2206661564bSmickey } 2216661564bSmickey 2226661564bSmickey struct pciintr_link_map * 2230edf2c54Smickey pciintr_link_lookup(link) 2246661564bSmickey int link; 2256661564bSmickey { 2266661564bSmickey struct pciintr_link_map *l; 2276661564bSmickey 2286661564bSmickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 22964f0e01bSmickey l = SIMPLEQ_NEXT(l, list)) 2306661564bSmickey if (l->link == link) 2316661564bSmickey return (l); 2326661564bSmickey 2336661564bSmickey return (NULL); 2346661564bSmickey } 2356661564bSmickey 23664f0e01bSmickey static __inline struct pciintr_link_map * 23764f0e01bSmickey pciintr_link_alloc(pci_chipset_tag_t pc, struct pcibios_intr_routing *pir, int pin) 2386661564bSmickey { 2390edf2c54Smickey int link = pir->linkmap[pin].link, clink, irq; 2406661564bSmickey struct pciintr_link_map *l, *lstart; 2416661564bSmickey 242b25264e3Smickey if (pciintr_icu_tag != NULL) { 2430edf2c54Smickey /* 2440edf2c54Smickey * Get the canonical link value for this entry. 2450edf2c54Smickey */ 246b25264e3Smickey if (pciintr_icu_getclink(pciintr_icu_tag, pciintr_icu_handle, 247b25264e3Smickey link, &clink) != 0) { 2480edf2c54Smickey /* 2490edf2c54Smickey * ICU doesn't understand the link value. 2500edf2c54Smickey * Just ignore this PIR entry. 2510edf2c54Smickey */ 25264f0e01bSmickey PCIBIOS_PRINTV(("pciintr_link_alloc: bus %d device %d: " 25364f0e01bSmickey "ignoring link 0x%02x\n", pir->bus, 25464f0e01bSmickey PIR_DEVFUNC_DEVICE(pir->device), link)); 2550edf2c54Smickey return (NULL); 2560edf2c54Smickey } 2570edf2c54Smickey 2580edf2c54Smickey /* 259b25264e3Smickey * Check the link value by asking the ICU for the 260b25264e3Smickey * canonical link value. 2610edf2c54Smickey * Also, determine if this PIRQ is mapped to an IRQ. 2620edf2c54Smickey */ 263b25264e3Smickey if (pciintr_icu_get_intr(pciintr_icu_tag, pciintr_icu_handle, 264b25264e3Smickey clink, &irq) != 0) { 2650edf2c54Smickey /* 2660edf2c54Smickey * ICU doesn't understand the canonical link value. 2670edf2c54Smickey * Just ignore this PIR entry. 2680edf2c54Smickey */ 26964f0e01bSmickey PCIBIOS_PRINTV(("pciintr_link_alloc: " 270b25264e3Smickey "bus %d device %d link 0x%02x: " 271b25264e3Smickey "ignoring PIRQ 0x%02x\n", pir->bus, 27264f0e01bSmickey PIR_DEVFUNC_DEVICE(pir->device), link, clink)); 2730edf2c54Smickey return (NULL); 2740edf2c54Smickey } 275b25264e3Smickey } 2760edf2c54Smickey 27764f0e01bSmickey if ((l = malloc(sizeof(*l), M_DEVBUF, M_NOWAIT)) == NULL) 2780edf2c54Smickey return (NULL); 2796661564bSmickey 2806661564bSmickey memset(l, 0, sizeof(*l)); 2816661564bSmickey 2820edf2c54Smickey l->link = link; 2836661564bSmickey l->bitmap = pir->linkmap[pin].bitmap; 284b25264e3Smickey if (pciintr_icu_tag != NULL) { /* compatible PCI ICU found */ 2850edf2c54Smickey l->clink = clink; 2860edf2c54Smickey l->irq = irq; /* maybe I386_PCI_INTERRUPT_LINE_NO_CONNECTION */ 287b25264e3Smickey } else { 28864f0e01bSmickey l->clink = link; 289b25264e3Smickey l->irq = I386_PCI_INTERRUPT_LINE_NO_CONNECTION; 290b25264e3Smickey } 2916661564bSmickey 2926661564bSmickey lstart = SIMPLEQ_FIRST(&pciintr_link_map_list); 2936661564bSmickey if (lstart == NULL || lstart->link < l->link) 2946661564bSmickey SIMPLEQ_INSERT_TAIL(&pciintr_link_map_list, l, list); 2956661564bSmickey else 2966661564bSmickey SIMPLEQ_INSERT_HEAD(&pciintr_link_map_list, l, list); 2976661564bSmickey 2986661564bSmickey return (l); 2996661564bSmickey } 3006661564bSmickey 3016661564bSmickey struct pcibios_intr_routing * 3026661564bSmickey pciintr_pir_lookup(bus, device) 3036661564bSmickey int bus, device; 3046661564bSmickey { 3056661564bSmickey struct pcibios_intr_routing *pir; 3066661564bSmickey int entry; 3076661564bSmickey 3086661564bSmickey if (pcibios_pir_table == NULL) 3096661564bSmickey return (NULL); 3106661564bSmickey 3116661564bSmickey for (entry = 0; entry < pcibios_pir_table_nentries; entry++) { 3126661564bSmickey pir = &pcibios_pir_table[entry]; 3130edf2c54Smickey if (pir->bus == bus && 3140edf2c54Smickey PIR_DEVFUNC_DEVICE(pir->device) == device) 3156661564bSmickey return (pir); 3166661564bSmickey } 3176661564bSmickey 3186661564bSmickey return (NULL); 3196661564bSmickey } 3206661564bSmickey 32164f0e01bSmickey int 3220edf2c54Smickey pciintr_bitmap_count_irq(irq_bitmap, irqp) 3230edf2c54Smickey int irq_bitmap, *irqp; 3240edf2c54Smickey { 3250edf2c54Smickey int i, bit, count = 0, irq = I386_PCI_INTERRUPT_LINE_NO_CONNECTION; 3260edf2c54Smickey 32764f0e01bSmickey if (irq_bitmap != 0) 32864f0e01bSmickey for (i = 0, bit = 1; i < 16; i++, bit <<= 1) 3290edf2c54Smickey if (irq_bitmap & bit) { 3300edf2c54Smickey irq = i; 3310edf2c54Smickey count++; 3320edf2c54Smickey } 33364f0e01bSmickey 3340edf2c54Smickey *irqp = irq; 3350edf2c54Smickey return (count); 3360edf2c54Smickey } 3370edf2c54Smickey 33864f0e01bSmickey static __inline int 33964f0e01bSmickey pciintr_link_init(pci_chipset_tag_t pc) 3406661564bSmickey { 341b25264e3Smickey int entry, pin, link; 3426661564bSmickey struct pcibios_intr_routing *pir; 3436661564bSmickey struct pciintr_link_map *l; 3446661564bSmickey 3456661564bSmickey if (pcibios_pir_table == NULL) { 3466661564bSmickey /* No PIR table; can't do anything. */ 3476661564bSmickey printf("pciintr_link_init: no PIR table\n"); 3486661564bSmickey return (1); 3496661564bSmickey } 3506661564bSmickey 3516661564bSmickey SIMPLEQ_INIT(&pciintr_link_map_list); 3526661564bSmickey 3536661564bSmickey for (entry = 0; entry < pcibios_pir_table_nentries; entry++) { 3546661564bSmickey pir = &pcibios_pir_table[entry]; 3550edf2c54Smickey for (pin = 0; pin < PCI_INTERRUPT_PIN_MAX; pin++) { 35664f0e01bSmickey if ((link = pir->linkmap[pin].link) == 0) 3576661564bSmickey /* No connection for this pin. */ 3586661564bSmickey continue; 35964f0e01bSmickey 3606661564bSmickey /* 3616661564bSmickey * Multiple devices may be wired to the same 3626661564bSmickey * interrupt; check to see if we've seen this 3636661564bSmickey * one already. If not, allocate a new link 3646661564bSmickey * map entry and stuff it in the map. 3656661564bSmickey */ 36664f0e01bSmickey if ((l = pciintr_link_lookup(link)) == NULL) 36764f0e01bSmickey pciintr_link_alloc(pc, pir, pin); 36864f0e01bSmickey else if (pir->linkmap[pin].bitmap != l->bitmap) { 3690edf2c54Smickey /* 3700edf2c54Smickey * violates PCI IRQ Routing Table Specification 3710edf2c54Smickey */ 37264f0e01bSmickey PCIBIOS_PRINTV(("pciintr_link_init: " 3730edf2c54Smickey "bus %d device %d link 0x%02x: " 3740edf2c54Smickey "bad irq bitmap 0x%04x, " 37564f0e01bSmickey "should be 0x%04x\n", pir->bus, 37664f0e01bSmickey PIR_DEVFUNC_DEVICE(pir->device), link, 37764f0e01bSmickey pir->linkmap[pin].bitmap, l->bitmap)); 3780edf2c54Smickey /* safer value. */ 3790edf2c54Smickey l->bitmap &= pir->linkmap[pin].bitmap; 3800edf2c54Smickey /* XXX - or, should ignore this entry? */ 3810edf2c54Smickey } 3826661564bSmickey } 3836661564bSmickey } 3846661564bSmickey 385b25264e3Smickey return (0); 386b25264e3Smickey } 387b25264e3Smickey 388b25264e3Smickey /* 389b25264e3Smickey * No compatible PCI ICU found. 390b25264e3Smickey * Hopes the BIOS already setup the ICU. 391b25264e3Smickey */ 39264f0e01bSmickey static __inline int 39364f0e01bSmickey pciintr_guess_irq(void) 394b25264e3Smickey { 395b25264e3Smickey struct pciintr_link_map *l; 396b25264e3Smickey int irq, guessed = 0; 397b25264e3Smickey 398b25264e3Smickey /* 399b25264e3Smickey * Stage 1: If only one IRQ is available for the link, use it. 400b25264e3Smickey */ 401b25264e3Smickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 402b25264e3Smickey l = SIMPLEQ_NEXT(l, list)) { 403b25264e3Smickey if (l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) 404b25264e3Smickey continue; 405b25264e3Smickey if (pciintr_bitmap_count_irq(l->bitmap, &irq) == 1) { 406b25264e3Smickey l->irq = irq; 407b25264e3Smickey l->fixup_stage = 1; 40864f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 409b25264e3Smickey printf("pciintr_guess_irq (stage 1): " 410b25264e3Smickey "guessing PIRQ 0x%02x to be IRQ %d\n", 411b25264e3Smickey l->clink, l->irq); 412b25264e3Smickey guessed = 1; 413b25264e3Smickey } 414b25264e3Smickey } 415b25264e3Smickey 416b25264e3Smickey return (guessed ? 0 : -1); 4176661564bSmickey } 4186661564bSmickey 41964f0e01bSmickey static __inline int 42064f0e01bSmickey pciintr_link_fixup(void) 4216661564bSmickey { 4226661564bSmickey struct pciintr_link_map *l; 4230edf2c54Smickey u_int16_t pciirq = 0; 42464f0e01bSmickey int irq; 4256661564bSmickey 4266661564bSmickey /* 4276661564bSmickey * First stage: Attempt to connect PIRQs which aren't 4286661564bSmickey * yet connected. 4296661564bSmickey */ 4306661564bSmickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 4316661564bSmickey l = SIMPLEQ_NEXT(l, list)) { 4320edf2c54Smickey if (l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 4336661564bSmickey /* 4340edf2c54Smickey * Interrupt is already connected. Don't do 4350edf2c54Smickey * anything to it. 4360edf2c54Smickey * In this case, l->fixup_stage == 0. 4376661564bSmickey */ 4380edf2c54Smickey pciirq |= 1 << l->irq; 43964f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 44064f0e01bSmickey printf("pciintr_link_fixup: PIRQ 0x%02x is " 44164f0e01bSmickey "already connected to IRQ %d\n", 44264f0e01bSmickey l->clink, l->irq); 4436661564bSmickey continue; 4446661564bSmickey } 4456661564bSmickey /* 4460edf2c54Smickey * Interrupt isn't connected. Attempt to assign it to an IRQ. 4476661564bSmickey */ 44864f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 4490edf2c54Smickey printf("pciintr_link_fixup: PIRQ 0x%02x not connected", 4506661564bSmickey l->clink); 45164f0e01bSmickey 4526661564bSmickey /* 4530edf2c54Smickey * Just do the easy case now; we'll defer the harder ones 4540edf2c54Smickey * to Stage 2. 4556661564bSmickey */ 4560edf2c54Smickey if (pciintr_bitmap_count_irq(l->bitmap, &irq) == 1) { 4570edf2c54Smickey l->irq = irq; 4586661564bSmickey l->fixup_stage = 1; 4590edf2c54Smickey pciirq |= 1 << irq; 46064f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 4616661564bSmickey printf(", assigning IRQ %d", l->irq); 4626661564bSmickey } 46364f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 4646661564bSmickey printf("\n"); 4656661564bSmickey } 4666661564bSmickey 4676661564bSmickey /* 4686661564bSmickey * Stage 2: Attempt to connect PIRQs which we didn't 4696661564bSmickey * connect in Stage 1. 4706661564bSmickey */ 4716661564bSmickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 47264f0e01bSmickey l = SIMPLEQ_NEXT(l, list)) 47364f0e01bSmickey if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION && 47464f0e01bSmickey (irq = ffs(l->bitmap & pciirq)) > 0) { 4756661564bSmickey /* 4760edf2c54Smickey * This IRQ is a valid PCI IRQ already 4770edf2c54Smickey * connected to another PIRQ, and also an 4780edf2c54Smickey * IRQ our PIRQ can use; connect it up! 4796661564bSmickey */ 4806661564bSmickey l->fixup_stage = 2; 48164f0e01bSmickey l->irq = irq - 1; 48264f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 4830edf2c54Smickey printf("pciintr_link_fixup (stage 2): " 4840edf2c54Smickey "assigning IRQ %d to PIRQ 0x%02x\n", 4850edf2c54Smickey l->irq, l->clink); 4866661564bSmickey } 4876661564bSmickey 4880edf2c54Smickey #ifdef PCIBIOS_IRQS_HINT 4896661564bSmickey /* 4900edf2c54Smickey * Stage 3: The worst case. I need configuration hint that 4910edf2c54Smickey * user supplied a mask for the PCI irqs 4926661564bSmickey */ 4930edf2c54Smickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 4940edf2c54Smickey l = SIMPLEQ_NEXT(l, list)) { 49564f0e01bSmickey if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION && 49664f0e01bSmickey (irq = ffs(l->bitmap & pcibios_irqs_hint)) > 0) { 4970edf2c54Smickey l->fixup_stage = 3; 49864f0e01bSmickey l->irq = irq - 1; 49964f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 5000edf2c54Smickey printf("pciintr_link_fixup (stage 3): " 5010edf2c54Smickey "assigning IRQ %d to PIRQ 0x%02x\n", 5020edf2c54Smickey l->irq, l->clink); 5030edf2c54Smickey } 5040edf2c54Smickey } 5050edf2c54Smickey #endif /* PCIBIOS_IRQS_HINT */ 5066661564bSmickey 50764f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 50864f0e01bSmickey printf("pciintr_link_fixup: piirq 0x%04x\n", pciirq); 50964f0e01bSmickey 5106661564bSmickey return (0); 5116661564bSmickey } 5126661564bSmickey 5136661564bSmickey int 51464f0e01bSmickey pci_intr_route_link(pc, ihp) 51564f0e01bSmickey pci_chipset_tag_t pc; 51664f0e01bSmickey pci_intr_handle_t *ihp; 5176661564bSmickey { 5186661564bSmickey struct pciintr_link_map *l; 51964f0e01bSmickey pcireg_t intr; 52064f0e01bSmickey int rv = 1; 52164f0e01bSmickey char *p = NULL; 5226661564bSmickey 5238b0f2e63Smickey if (pcibios_flags & PCIBIOS_INTR_FIXUP) 5248b0f2e63Smickey return 1; 5258b0f2e63Smickey 526ff51c22aSmickey if (ihp->line != 0 && 527ff51c22aSmickey ihp->line != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) 528ff51c22aSmickey pcibios_pir_header.exclusive_irq |= (1 << ihp->line); 529ff51c22aSmickey 53064f0e01bSmickey l = ihp->link; 53164f0e01bSmickey if (!l || pciintr_icu_tag == NULL) 53264f0e01bSmickey return (1); 5336661564bSmickey 5340edf2c54Smickey if (l->fixup_stage == 0) { 5350edf2c54Smickey if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 5360edf2c54Smickey /* Appropriate interrupt was not found. */ 53764f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 53864f0e01bSmickey printf("pci_intr_route_link: PIRQ 0x%02x: " 53964f0e01bSmickey "no IRQ, try " 54064f0e01bSmickey "\"option PCIBIOS_IRQS_HINT=0x%04x\"\n", 5410edf2c54Smickey l->clink, 5420edf2c54Smickey /* suggest irq 9/10/11, if possible */ 5430edf2c54Smickey (l->bitmap & 0x0e00) ? (l->bitmap & 0x0e00) 5440edf2c54Smickey : l->bitmap); 54564f0e01bSmickey } else 54664f0e01bSmickey p = " preserved BIOS setting"; 5470edf2c54Smickey } else { 5480edf2c54Smickey 5496661564bSmickey if (pciintr_icu_set_intr(pciintr_icu_tag, pciintr_icu_handle, 5506661564bSmickey l->clink, l->irq) != 0 || 55164f0e01bSmickey pciintr_icu_set_trigger(pciintr_icu_tag, pciintr_icu_handle, 5526661564bSmickey l->irq, IST_LEVEL) != 0) { 55364f0e01bSmickey p = " failed"; 55464f0e01bSmickey rv = 0; 55564f0e01bSmickey } else 55664f0e01bSmickey p = ""; 5576661564bSmickey } 55864f0e01bSmickey if (p && pcibios_flags & PCIBIOS_INTRDEBUG) 55964f0e01bSmickey printf("pci_intr_route_link: route PIRQ 0x%02x -> IRQ %d%s\n", 56064f0e01bSmickey l->clink, l->irq, p); 5616661564bSmickey 56264f0e01bSmickey if (!rv) 5636661564bSmickey return (0); 5640edf2c54Smickey 5656661564bSmickey /* 5660edf2c54Smickey * IRQs 14 and 15 are reserved for PCI IDE interrupts; don't muck 5676661564bSmickey * with them. 5686661564bSmickey */ 56964f0e01bSmickey if (ihp->line == 14 || ihp->line == 15) 57064f0e01bSmickey return (1); 57164f0e01bSmickey 57264f0e01bSmickey intr = pci_conf_read(pc, ihp->tag, PCI_INTERRUPT_REG); 57364f0e01bSmickey if (ihp->line != PCI_INTERRUPT_LINE(intr)) { 57464f0e01bSmickey intr &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT); 57564f0e01bSmickey intr |= (ihp->line << PCI_INTERRUPT_LINE_SHIFT); 57664f0e01bSmickey pci_conf_write(pc, ihp->tag, PCI_INTERRUPT_REG, intr); 5770edf2c54Smickey } 5786661564bSmickey 57964f0e01bSmickey return (1); 58064f0e01bSmickey } 58164f0e01bSmickey 58264f0e01bSmickey int 58364f0e01bSmickey pci_intr_post_fixup() 58464f0e01bSmickey { 58564f0e01bSmickey struct pciintr_link_map *l; 58664f0e01bSmickey int i, pciirq; 58764f0e01bSmickey 5888b0f2e63Smickey if (pcibios_flags & PCIBIOS_INTR_FIXUP) 5898b0f2e63Smickey return 1; 5908b0f2e63Smickey 59164f0e01bSmickey if (!pciintr_icu_handle) 59264f0e01bSmickey return 0; 59364f0e01bSmickey 59464f0e01bSmickey pciirq = pcibios_pir_header.exclusive_irq; 59564f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 59664f0e01bSmickey printf("pci_intr_post_fixup: PCI IRQs:"); 59764f0e01bSmickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); 59864f0e01bSmickey l != NULL; l = SIMPLEQ_NEXT(l, list)) 599ff51c22aSmickey if (l->fixup_stage == 0 && l->irq != 0 && 60064f0e01bSmickey l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 60164f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 60264f0e01bSmickey printf(" %d", l->irq); 60364f0e01bSmickey pciirq |= (1 << l->irq); 60464f0e01bSmickey } 60564f0e01bSmickey 60664f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 60764f0e01bSmickey printf("; ISA IRQs:"); 60864f0e01bSmickey for (i = 0; i < 16; i++) 60964f0e01bSmickey if (!(pciirq & (1 << i))) { 61064f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 61164f0e01bSmickey printf(" %d", i); 61264f0e01bSmickey pciintr_icu_set_trigger(pciintr_icu_tag, 61364f0e01bSmickey pciintr_icu_handle, i, IST_EDGE); 61464f0e01bSmickey } 61564f0e01bSmickey 61664f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 61764f0e01bSmickey printf("\n"); 61864f0e01bSmickey 61964f0e01bSmickey return (0); 62064f0e01bSmickey } 62164f0e01bSmickey 62264f0e01bSmickey int 62364f0e01bSmickey pci_intr_header_fixup(pc, tag, ihp) 62464f0e01bSmickey pci_chipset_tag_t pc; 62564f0e01bSmickey pcitag_t tag; 62664f0e01bSmickey pci_intr_handle_t *ihp; 62764f0e01bSmickey { 62864f0e01bSmickey struct pcibios_intr_routing *pir; 62964f0e01bSmickey struct pciintr_link_map *l; 63064f0e01bSmickey int irq, link, bus, device, function; 63164f0e01bSmickey char *p = NULL; 63264f0e01bSmickey 6338b0f2e63Smickey if (pcibios_flags & PCIBIOS_INTR_FIXUP) 6348b0f2e63Smickey return 1; 6358b0f2e63Smickey 63664f0e01bSmickey irq = ihp->line; 63764f0e01bSmickey ihp->link = NULL; 63864f0e01bSmickey ihp->tag = tag; 63964f0e01bSmickey pci_decompose_tag(pc, tag, &bus, &device, &function); 64064f0e01bSmickey 64164f0e01bSmickey if ((pir = pciintr_pir_lookup(bus, device)) == NULL || 64264f0e01bSmickey (link = pir->linkmap[ihp->pin - 1].link) == 0) { 64364f0e01bSmickey PCIBIOS_PRINTV(("Interrupt not connected; no need to change.")); 64464f0e01bSmickey return 1; 64564f0e01bSmickey } 64664f0e01bSmickey 64764f0e01bSmickey if ((l = pciintr_link_lookup(link)) == NULL) { 64864f0e01bSmickey /* 64964f0e01bSmickey * No link map entry. 65064f0e01bSmickey * Probably pciintr_icu_getclink() or pciintr_icu_get_intr() 65164f0e01bSmickey * was failed. 65264f0e01bSmickey */ 65364f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 65464f0e01bSmickey printf("pci_intr_header_fixup: no entry for link " 65564f0e01bSmickey "0x%02x (%d:%d:%d:%c)\n", 65664f0e01bSmickey link, bus, device, function, '@' + ihp->pin); 65764f0e01bSmickey return 1; 65864f0e01bSmickey } 65964f0e01bSmickey 6601120a2ccSmarkus ihp->link = l; 6611120a2ccSmarkus if (irq == 14 || irq == 15) { 66264f0e01bSmickey p = " WARNING: ignored"; 6631120a2ccSmarkus ihp->link = NULL; 6641120a2ccSmarkus } else if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 66564f0e01bSmickey 6660edf2c54Smickey /* Appropriate interrupt was not found. */ 66764f0e01bSmickey if (pciintr_icu_tag == NULL && ihp->line != 0 && 66864f0e01bSmickey ihp->line != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) 669b25264e3Smickey /* 670b25264e3Smickey * Do not print warning, 671b25264e3Smickey * if no compatible PCI ICU found, 672b25264e3Smickey * but the irq is already assigned by BIOS. 673b25264e3Smickey */ 67464f0e01bSmickey p = ""; 67564f0e01bSmickey else 67664f0e01bSmickey p = " WARNING: missing"; 67764f0e01bSmickey } else if (irq == 0 || irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 6780edf2c54Smickey 67964f0e01bSmickey p = " fixed up"; 68064f0e01bSmickey ihp->line = l->irq; 6810edf2c54Smickey 682a003464cSmickey } else if (pcibios_flags & PCIBIOS_FIXUP_FORCE) { 6830edf2c54Smickey /* routed by BIOS, but inconsistent */ 6840edf2c54Smickey /* believe PCI IRQ Routing table */ 68564f0e01bSmickey p = " WARNING: overriding"; 68664f0e01bSmickey ihp->line = l->irq; 68778b5d43cSmickey } else { 6880edf2c54Smickey /* believe PCI Interrupt Configuration Register (default) */ 68964f0e01bSmickey p = " WARNING: preserving"; 69078b5d43cSmickey ihp->line = l->irq = irq; 69178b5d43cSmickey } 6926661564bSmickey 69364f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) { 69464f0e01bSmickey register pcireg_t id = pci_conf_read(pc, tag, PCI_ID_REG); 69564f0e01bSmickey 69678b5d43cSmickey printf("\n%d:%d:%d %04x:%04x pin %c clink 0x%02x irq %d " 69778b5d43cSmickey "stage %d %s irq %d\n", bus, device, function, 69864f0e01bSmickey PCI_VENDOR(id), PCI_PRODUCT(id), '@' + ihp->pin, l->clink, 69964f0e01bSmickey ((l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION)? 70064f0e01bSmickey -1 : l->irq), l->fixup_stage, p, irq); 70164f0e01bSmickey } 70264f0e01bSmickey 70364f0e01bSmickey return (1); 7046661564bSmickey } 7056661564bSmickey 7066661564bSmickey int 707df73a7d0Smickey pci_intr_fixup(sc, pc, iot) 708df73a7d0Smickey struct pcibios_softc *sc; 7096661564bSmickey pci_chipset_tag_t pc; 7106661564bSmickey bus_space_tag_t iot; 7116661564bSmickey { 712df73a7d0Smickey struct pcibios_pir_header *pirh = &pcibios_pir_header; 7136661564bSmickey const struct pciintr_icu_table *piit = NULL; 7146661564bSmickey pcitag_t icutag; 7156661564bSmickey 7166661564bSmickey /* 7176661564bSmickey * Attempt to initialize our PCI interrupt router. If 7186661564bSmickey * the PIR Table is present in ROM, use the location 7196661564bSmickey * specified by the PIR Table, and use the compat ID, 7206661564bSmickey * if present. Otherwise, we have to look for the router 7216661564bSmickey * ourselves (the PCI-ISA bridge). 722911088d6Smickey * 723911088d6Smickey * A number of buggy BIOS implementations leave the router 724911088d6Smickey * entry as 000:00:0, which is typically not the correct 725911088d6Smickey * device/function. If the router device address is set to 726911088d6Smickey * this value, and the compatible router entry is undefined 727911088d6Smickey * (zero is the correct value to indicate undefined), then we 728911088d6Smickey * work on the basis it is most likely an error, and search 729911088d6Smickey * the entire device-space of bus 0 (but obviously starting 730911088d6Smickey * with 000:00:0, in case that really is the right one). 7316661564bSmickey */ 732911088d6Smickey if (pirh->signature != 0 && (pirh->router_bus != 0 || 733911088d6Smickey pirh->router_devfunc != 0 || pirh->compat_router != 0)) { 734911088d6Smickey 7356c0a4d12Smickey icutag = pci_make_tag(pc, pirh->router_bus, 7366c0a4d12Smickey PIR_DEVFUNC_DEVICE(pirh->router_devfunc), 7376c0a4d12Smickey PIR_DEVFUNC_FUNCTION(pirh->router_devfunc)); 738911088d6Smickey if (pirh->compat_router == 0 || 739911088d6Smickey (piit = pciintr_icu_lookup(pirh->compat_router)) == NULL) { 7406661564bSmickey /* 7416661564bSmickey * No compat ID, or don't know the compat ID? Read 7426661564bSmickey * it from the configuration header. 7436661564bSmickey */ 7446c0a4d12Smickey pirh->compat_router = pci_conf_read(pc, icutag, 745911088d6Smickey PCI_ID_REG); 7466661564bSmickey } 7476661564bSmickey if (piit == NULL) 748911088d6Smickey piit = pciintr_icu_lookup(pirh->compat_router); 7496661564bSmickey } else { 7506661564bSmickey int device, maxdevs = pci_bus_maxdevs(pc, 0); 7516661564bSmickey 7526661564bSmickey /* 7536661564bSmickey * Search configuration space for a known interrupt 7546661564bSmickey * router. 7556661564bSmickey */ 7566661564bSmickey for (device = 0; device < maxdevs; device++) { 757911088d6Smickey const struct pci_quirkdata *qd; 758911088d6Smickey int function, nfuncs; 759911088d6Smickey pcireg_t icuid; 760911088d6Smickey pcireg_t bhlcr; 761911088d6Smickey 7626661564bSmickey icutag = pci_make_tag(pc, 0, device, 0); 7636661564bSmickey icuid = pci_conf_read(pc, icutag, PCI_ID_REG); 7646661564bSmickey 7656661564bSmickey /* Invalid vendor ID value? */ 7666661564bSmickey if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID) 7676661564bSmickey continue; 7686661564bSmickey /* XXX Not invalid, but we've done this ~forever. */ 7696661564bSmickey if (PCI_VENDOR(icuid) == 0) 7706661564bSmickey continue; 7716661564bSmickey 772911088d6Smickey qd = pci_lookup_quirkdata(PCI_VENDOR(icuid), 773911088d6Smickey PCI_PRODUCT(icuid)); 774911088d6Smickey 775911088d6Smickey bhlcr = pci_conf_read(pc, icutag, PCI_BHLC_REG); 776911088d6Smickey if (PCI_HDRTYPE_MULTIFN(bhlcr) || (qd != NULL && 777911088d6Smickey (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0)) 778911088d6Smickey nfuncs = 8; 779911088d6Smickey else 780911088d6Smickey nfuncs = 1; 781911088d6Smickey 782911088d6Smickey for (function = 0; function < nfuncs; function++) { 783911088d6Smickey icutag = pci_make_tag(pc, 0, device, function); 784911088d6Smickey icuid = pci_conf_read(pc, icutag, PCI_ID_REG); 785911088d6Smickey 786911088d6Smickey /* Invalid vendor ID value? */ 787911088d6Smickey if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID) 788911088d6Smickey continue; 789911088d6Smickey /* Not invalid, but we've done this ~forever. */ 790911088d6Smickey if (PCI_VENDOR(icuid) == 0) 791911088d6Smickey continue; 792911088d6Smickey 793df73a7d0Smickey if ((piit = pciintr_icu_lookup(icuid))) { 794df73a7d0Smickey pirh->compat_router = icuid; 795df73a7d0Smickey pirh->router_bus = 0; 796df73a7d0Smickey pirh->router_devfunc = 797df73a7d0Smickey PIR_DEVFUNC_COMPOSE(device, 0); 7986661564bSmickey break; 7996661564bSmickey } 8006661564bSmickey } 801911088d6Smickey 802911088d6Smickey if (piit != NULL) 803911088d6Smickey break; 804911088d6Smickey } 805df73a7d0Smickey } 8066661564bSmickey 8076661564bSmickey if (piit == NULL) { 808df73a7d0Smickey printf("%s: no compatible PCI ICU found", sc->sc_dev.dv_xname); 809911088d6Smickey if (pirh->signature != 0 && pirh->compat_router != 0) 810b25264e3Smickey printf(": ICU vendor 0x%04x product 0x%04x", 811911088d6Smickey PCI_VENDOR(pirh->compat_router), 812911088d6Smickey PCI_PRODUCT(pirh->compat_router)); 813b25264e3Smickey printf("\n"); 814b25264e3Smickey if (!(pcibios_flags & PCIBIOS_INTR_GUESS)) { 81564f0e01bSmickey if (pciintr_link_init(pc)) 816b25264e3Smickey return (-1); /* non-fatal */ 817b25264e3Smickey if (pciintr_guess_irq()) 818b25264e3Smickey return (-1); /* non-fatal */ 819bb701a32Smickey } 820bb701a32Smickey return (0); 821df73a7d0Smickey } else { 822df73a7d0Smickey char devinfo[256]; 823df73a7d0Smickey 824df73a7d0Smickey printf("%s: PCI Interrupt Router at %03d:%02d:%01d", 825df73a7d0Smickey sc->sc_dev.dv_xname, pirh->router_bus, 826df73a7d0Smickey PIR_DEVFUNC_DEVICE(pirh->router_devfunc), 827df73a7d0Smickey PIR_DEVFUNC_FUNCTION(pirh->router_devfunc)); 828df73a7d0Smickey if (pirh->compat_router != 0) { 8292627362dSho pci_devinfo(pirh->compat_router, 0, 0, devinfo, 8302627362dSho sizeof devinfo); 831df73a7d0Smickey printf(" (%s)", devinfo); 832df73a7d0Smickey } 833df73a7d0Smickey printf("\n"); 8346661564bSmickey } 8356661564bSmickey 8366661564bSmickey /* 8376661564bSmickey * Initialize the PCI ICU. 8386661564bSmickey */ 8396661564bSmickey if ((*piit->piit_init)(pc, iot, icutag, &pciintr_icu_tag, 8406661564bSmickey &pciintr_icu_handle) != 0) 8416661564bSmickey return (-1); /* non-fatal */ 8426661564bSmickey 8436661564bSmickey /* 8446661564bSmickey * Initialize the PCI interrupt link map. 8456661564bSmickey */ 84664f0e01bSmickey if (pciintr_link_init(pc)) 8476661564bSmickey return (-1); /* non-fatal */ 8486661564bSmickey 8496661564bSmickey /* 8506661564bSmickey * Fix up the link->IRQ mappings. 8516661564bSmickey */ 8526661564bSmickey if (pciintr_link_fixup() != 0) 8536661564bSmickey return (-1); /* non-fatal */ 8546661564bSmickey 85564f0e01bSmickey return (0); 8566661564bSmickey } 857