1*0bca52fcSjsg /* $OpenBSD: pci_intr_fixup.c,v 1.63 2021/03/06 09:20:50 jsg 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 * 466661564bSmickey * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 476661564bSmickey * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 486661564bSmickey * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 496661564bSmickey * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 506661564bSmickey * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 516661564bSmickey * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 526661564bSmickey * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 536661564bSmickey * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 546661564bSmickey * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 556661564bSmickey * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 566661564bSmickey * POSSIBILITY OF SUCH DAMAGE. 576661564bSmickey */ 586661564bSmickey /* 596661564bSmickey * Copyright (c) 1999, by UCHIYAMA Yasushi 606661564bSmickey * All rights reserved. 616661564bSmickey * 626661564bSmickey * Redistribution and use in source and binary forms, with or without 636661564bSmickey * modification, are permitted provided that the following conditions 646661564bSmickey * are met: 656661564bSmickey * 1. Redistributions of source code must retain the above copyright 666661564bSmickey * notice, this list of conditions and the following disclaimer. 676661564bSmickey * 2. The name of the developer may NOT be used to endorse or promote products 686661564bSmickey * derived from this software without specific prior written permission. 696661564bSmickey * 706661564bSmickey * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 716661564bSmickey * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 726661564bSmickey * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 736661564bSmickey * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 746661564bSmickey * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 756661564bSmickey * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 766661564bSmickey * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 776661564bSmickey * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 786661564bSmickey * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 796661564bSmickey * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 806661564bSmickey * SUCH DAMAGE. 816661564bSmickey */ 826661564bSmickey 836661564bSmickey /* 846661564bSmickey * PCI Interrupt Router support. 856661564bSmickey */ 866661564bSmickey 876661564bSmickey #include <sys/param.h> 886661564bSmickey #include <sys/systm.h> 896661564bSmickey #include <sys/kernel.h> 906661564bSmickey #include <sys/malloc.h> 916661564bSmickey #include <sys/queue.h> 926661564bSmickey #include <sys/device.h> 936661564bSmickey 946661564bSmickey #include <machine/bus.h> 956661564bSmickey #include <machine/intr.h> 96012ea299Sniklas #include <machine/i8259.h> 97a25c7806Smickey #include <machine/i82093var.h> 986661564bSmickey 996661564bSmickey #include <dev/pci/pcireg.h> 1006661564bSmickey #include <dev/pci/pcivar.h> 1016661564bSmickey #include <dev/pci/pcidevs.h> 1026661564bSmickey 103e2331c6cSderaadt #include <i386/pci/pcibiosvar.h> 1046661564bSmickey 1056661564bSmickey struct pciintr_link_map { 10664f0e01bSmickey int link, clink, irq, fixup_stage; 1076661564bSmickey u_int16_t bitmap; 1086661564bSmickey SIMPLEQ_ENTRY(pciintr_link_map) list; 1096661564bSmickey }; 1106661564bSmickey 111b25264e3Smickey pciintr_icu_tag_t pciintr_icu_tag = NULL; 1126661564bSmickey pciintr_icu_handle_t pciintr_icu_handle; 1136661564bSmickey 1140edf2c54Smickey #ifdef PCIBIOS_IRQS_HINT 1150edf2c54Smickey int pcibios_irqs_hint = PCIBIOS_IRQS_HINT; 1160edf2c54Smickey #endif 1170edf2c54Smickey 118c4071fd1Smillert struct pciintr_link_map *pciintr_link_lookup(int); 119c4071fd1Smillert struct pcibios_intr_routing *pciintr_pir_lookup(int, int); 120c4071fd1Smillert int pciintr_bitmap_count_irq(int, int *); 1216661564bSmickey 1226661564bSmickey SIMPLEQ_HEAD(, pciintr_link_map) pciintr_link_map_list; 1236661564bSmickey 1246661564bSmickey const struct pciintr_icu_table { 1256661564bSmickey pci_vendor_id_t piit_vendor; 1266661564bSmickey pci_product_id_t piit_product; 127c4071fd1Smillert int (*piit_init)(pci_chipset_tag_t, 1286661564bSmickey bus_space_tag_t, pcitag_t, pciintr_icu_tag_t *, 129c4071fd1Smillert pciintr_icu_handle_t *); 1306661564bSmickey } pciintr_icu_table[] = { 13123f11131Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6300ESB_LPC, 13223f11131Sbrad piix_init }, 133b566768eSbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6321ESB_LPC, 134b566768eSbrad piix_init }, 1356661564bSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371MX, 1366661564bSmickey piix_init }, 1376661564bSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371AB_ISA, 1386661564bSmickey piix_init }, 1396661564bSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371FB_ISA, 1406661564bSmickey piix_init }, 1416661564bSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371SB_ISA, 1426661564bSmickey piix_init }, 14323f11131Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82440MX_ISA, 14423f11131Sbrad piix_init }, 145ea8e013cSho { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AA_LPC, 146ea8e013cSho piix_init }, 14723f11131Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AB_LPC, 14823f11131Sbrad piix_init }, 14953003c45Smickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_LPC, 15053003c45Smickey piix_init }, 15153003c45Smickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BAM_LPC, 15253003c45Smickey piix_init }, 153b9a626b7Smickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801CA_LPC, 154b9a626b7Smickey piix_init }, 1556d805c04Smickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801CAM_LPC, 1566d805c04Smickey piix_init }, 1576d805c04Smickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801DB_LPC, 1586d805c04Smickey piix_init }, 159aa7d4239Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801DBM_LPC, 160aa7d4239Sbrad piix_init }, 16123f11131Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801E_LPC, 16223f11131Sbrad piix_init }, 1635b6ecbecSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801EB_LPC, 1645b6ecbecSmickey piix_init }, 1656eced139Sbeck { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801FB_LPC, 1666eced139Sbeck piix_init }, 16723f11131Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801FBM_LPC, 16823f11131Sbrad piix_init }, 169d984c6bdSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GB_LPC, 170d984c6bdSmickey piix_init }, 17123f11131Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GBM_LPC, 17223f11131Sbrad piix_init }, 17323f11131Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GH_LPC, 174aa5f4fe6Sbrad piix_init }, 175b566768eSbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GHM_LPC, 176b566768eSbrad piix_init }, 17709e7fbc8Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801IB_LPC, 17809e7fbc8Sbrad piix_init }, 17909e7fbc8Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801IH_LPC, 18009e7fbc8Sbrad piix_init }, 18109e7fbc8Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801IO_LPC, 18209e7fbc8Sbrad piix_init }, 18309e7fbc8Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801IR_LPC, 18409e7fbc8Sbrad piix_init }, 1856661564bSmickey 1866661564bSmickey { PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C558, 1876661564bSmickey opti82c558_init }, 1886661564bSmickey { PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C700, 1896661564bSmickey opti82c700_init }, 1906661564bSmickey 1918a1eb7fcSbrad { PCI_VENDOR_RCC, PCI_PRODUCT_RCC_OSB4, 192bd25a23dSmickey osb4_init }, 193bd25a23dSmickey { PCI_VENDOR_RCC, PCI_PRODUCT_RCC_CSB5, 194bd25a23dSmickey osb4_init }, 195bd25a23dSmickey 1966661564bSmickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C586_ISA, 1976661564bSmickey via82c586_init, }, 198139f38fdSbrad { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C596A, 199139f38fdSbrad via82c586_init, }, 20064f0e01bSmickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C686A_ISA, 20192598216Smickey via82c586_init }, 20292598216Smickey 20392598216Smickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8231_ISA, 20492598216Smickey via8231_init }, 205139f38fdSbrad { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8233_ISA, 206139f38fdSbrad via8231_init }, 207275f08b3Skettenis { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8233A_ISA, 20824996536Smickey via8231_init }, 20924996536Smickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8235_ISA, 21024996536Smickey via8231_init }, 211bc465bf0Shenning { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237_ISA, 212bc465bf0Shenning via8231_init }, 2133bd326a1Sgrange { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237A_ISA, 2143bd326a1Sgrange via8231_init }, 21514516421Sjcs { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237S_ISA, 21614516421Sjcs via8231_init }, 2176661564bSmickey 2186661564bSmickey { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_85C503, 2196661564bSmickey sis85c503_init }, 220139f38fdSbrad { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_962, 221139f38fdSbrad sis85c503_init }, 2220d58a2caSjsg { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_963, 2230d58a2caSjsg sis85c503_init }, 2246661564bSmickey 225cc48d299Smickey { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC756_PMC, 22667218ad0Smickey amd756_init }, 2271b2c3d0dSbrad { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_766_PMC, 2281b2c3d0dSbrad amd756_init }, 2291b2c3d0dSbrad { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC768_PMC, 23064c49bbaSmickey amd756_init }, 23167218ad0Smickey 2322766fe41Smillert { PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M1533, 2332766fe41Smillert ali1543_init }, 2342766fe41Smillert 2357853e030Smickey { PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M1543, 2367853e030Smickey ali1543_init }, 2377853e030Smickey 2386661564bSmickey { 0, 0, 2396661564bSmickey NULL }, 2406661564bSmickey }; 2416661564bSmickey 242c4071fd1Smillert const struct pciintr_icu_table *pciintr_icu_lookup(pcireg_t); 2436661564bSmickey 2446661564bSmickey const struct pciintr_icu_table * 245*0bca52fcSjsg pciintr_icu_lookup(pcireg_t id) 2466661564bSmickey { 2476661564bSmickey const struct pciintr_icu_table *piit; 2486661564bSmickey 24964f0e01bSmickey for (piit = pciintr_icu_table; piit->piit_init != NULL; piit++) 2506661564bSmickey if (PCI_VENDOR(id) == piit->piit_vendor && 2516661564bSmickey PCI_PRODUCT(id) == piit->piit_product) 2526661564bSmickey return (piit); 2536661564bSmickey 2546661564bSmickey return (NULL); 2556661564bSmickey } 2566661564bSmickey 2576661564bSmickey struct pciintr_link_map * 25808f75f72Sjsg pciintr_link_lookup(int link) 2596661564bSmickey { 2606661564bSmickey struct pciintr_link_map *l; 2616661564bSmickey 2626661564bSmickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 26364f0e01bSmickey l = SIMPLEQ_NEXT(l, list)) 2646661564bSmickey if (l->link == link) 2656661564bSmickey return (l); 2666661564bSmickey 2676661564bSmickey return (NULL); 2686661564bSmickey } 2696661564bSmickey 27064f0e01bSmickey static __inline struct pciintr_link_map * 27164f0e01bSmickey pciintr_link_alloc(pci_chipset_tag_t pc, struct pcibios_intr_routing *pir, int pin) 2726661564bSmickey { 2730edf2c54Smickey int link = pir->linkmap[pin].link, clink, irq; 2746661564bSmickey struct pciintr_link_map *l, *lstart; 2756661564bSmickey 276b25264e3Smickey if (pciintr_icu_tag != NULL) { 2770edf2c54Smickey /* 2780edf2c54Smickey * Get the canonical link value for this entry. 2790edf2c54Smickey */ 280b25264e3Smickey if (pciintr_icu_getclink(pciintr_icu_tag, pciintr_icu_handle, 281b25264e3Smickey link, &clink) != 0) { 2820edf2c54Smickey /* 2830edf2c54Smickey * ICU doesn't understand the link value. 2840edf2c54Smickey * Just ignore this PIR entry. 2850edf2c54Smickey */ 28664f0e01bSmickey PCIBIOS_PRINTV(("pciintr_link_alloc: bus %d device %d: " 28764f0e01bSmickey "ignoring link 0x%02x\n", pir->bus, 28864f0e01bSmickey PIR_DEVFUNC_DEVICE(pir->device), link)); 2890edf2c54Smickey return (NULL); 2900edf2c54Smickey } 2910edf2c54Smickey 2920edf2c54Smickey /* 293b25264e3Smickey * Check the link value by asking the ICU for the 294b25264e3Smickey * canonical link value. 2950edf2c54Smickey * Also, determine if this PIRQ is mapped to an IRQ. 2960edf2c54Smickey */ 297b25264e3Smickey if (pciintr_icu_get_intr(pciintr_icu_tag, pciintr_icu_handle, 298b25264e3Smickey clink, &irq) != 0) { 2990edf2c54Smickey /* 3000edf2c54Smickey * ICU doesn't understand the canonical link value. 3010edf2c54Smickey * Just ignore this PIR entry. 3020edf2c54Smickey */ 30364f0e01bSmickey PCIBIOS_PRINTV(("pciintr_link_alloc: " 304b25264e3Smickey "bus %d device %d link 0x%02x: " 305b25264e3Smickey "ignoring PIRQ 0x%02x\n", pir->bus, 30664f0e01bSmickey PIR_DEVFUNC_DEVICE(pir->device), link, clink)); 3070edf2c54Smickey return (NULL); 3080edf2c54Smickey } 309b25264e3Smickey } 3100edf2c54Smickey 31128a8f404Sart if ((l = malloc(sizeof(*l), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 3120edf2c54Smickey return (NULL); 3136661564bSmickey 3140edf2c54Smickey l->link = link; 3156661564bSmickey l->bitmap = pir->linkmap[pin].bitmap; 316b25264e3Smickey if (pciintr_icu_tag != NULL) { /* compatible PCI ICU found */ 3170edf2c54Smickey l->clink = clink; 3180edf2c54Smickey l->irq = irq; /* maybe I386_PCI_INTERRUPT_LINE_NO_CONNECTION */ 319b25264e3Smickey } else { 32064f0e01bSmickey l->clink = link; 321b25264e3Smickey l->irq = I386_PCI_INTERRUPT_LINE_NO_CONNECTION; 322b25264e3Smickey } 3236661564bSmickey 3246661564bSmickey lstart = SIMPLEQ_FIRST(&pciintr_link_map_list); 3256661564bSmickey if (lstart == NULL || lstart->link < l->link) 3266661564bSmickey SIMPLEQ_INSERT_TAIL(&pciintr_link_map_list, l, list); 3276661564bSmickey else 3286661564bSmickey SIMPLEQ_INSERT_HEAD(&pciintr_link_map_list, l, list); 3296661564bSmickey 3306661564bSmickey return (l); 3316661564bSmickey } 3326661564bSmickey 3336661564bSmickey struct pcibios_intr_routing * 33408f75f72Sjsg pciintr_pir_lookup(int bus, int device) 3356661564bSmickey { 3366661564bSmickey struct pcibios_intr_routing *pir; 3376661564bSmickey int entry; 3386661564bSmickey 3396661564bSmickey if (pcibios_pir_table == NULL) 3406661564bSmickey return (NULL); 3416661564bSmickey 3426661564bSmickey for (entry = 0; entry < pcibios_pir_table_nentries; entry++) { 3436661564bSmickey pir = &pcibios_pir_table[entry]; 3440edf2c54Smickey if (pir->bus == bus && 3450edf2c54Smickey PIR_DEVFUNC_DEVICE(pir->device) == device) 3466661564bSmickey return (pir); 3476661564bSmickey } 3486661564bSmickey 3496661564bSmickey return (NULL); 3506661564bSmickey } 3516661564bSmickey 35264f0e01bSmickey int 35308f75f72Sjsg pciintr_bitmap_count_irq(int irq_bitmap, int *irqp) 3540edf2c54Smickey { 3550edf2c54Smickey int i, bit, count = 0, irq = I386_PCI_INTERRUPT_LINE_NO_CONNECTION; 3560edf2c54Smickey 35764f0e01bSmickey if (irq_bitmap != 0) 35864f0e01bSmickey for (i = 0, bit = 1; i < 16; i++, bit <<= 1) 3590edf2c54Smickey if (irq_bitmap & bit) { 3600edf2c54Smickey irq = i; 3610edf2c54Smickey count++; 3620edf2c54Smickey } 36364f0e01bSmickey 3640edf2c54Smickey *irqp = irq; 3650edf2c54Smickey return (count); 3660edf2c54Smickey } 3670edf2c54Smickey 36864f0e01bSmickey static __inline int 36964f0e01bSmickey pciintr_link_init(pci_chipset_tag_t pc) 3706661564bSmickey { 371b25264e3Smickey int entry, pin, link; 3726661564bSmickey struct pcibios_intr_routing *pir; 3736661564bSmickey struct pciintr_link_map *l; 3746661564bSmickey 3756661564bSmickey if (pcibios_pir_table == NULL) { 3766661564bSmickey /* No PIR table; can't do anything. */ 3776661564bSmickey printf("pciintr_link_init: no PIR table\n"); 3786661564bSmickey return (1); 3796661564bSmickey } 3806661564bSmickey 3816661564bSmickey SIMPLEQ_INIT(&pciintr_link_map_list); 3826661564bSmickey 3836661564bSmickey for (entry = 0; entry < pcibios_pir_table_nentries; entry++) { 3846661564bSmickey pir = &pcibios_pir_table[entry]; 3850edf2c54Smickey for (pin = 0; pin < PCI_INTERRUPT_PIN_MAX; pin++) { 38664f0e01bSmickey if ((link = pir->linkmap[pin].link) == 0) 3876661564bSmickey /* No connection for this pin. */ 3886661564bSmickey continue; 38964f0e01bSmickey 3906661564bSmickey /* 3916661564bSmickey * Multiple devices may be wired to the same 3926661564bSmickey * interrupt; check to see if we've seen this 3936661564bSmickey * one already. If not, allocate a new link 3946661564bSmickey * map entry and stuff it in the map. 3956661564bSmickey */ 39664f0e01bSmickey if ((l = pciintr_link_lookup(link)) == NULL) 39764f0e01bSmickey pciintr_link_alloc(pc, pir, pin); 39864f0e01bSmickey else if (pir->linkmap[pin].bitmap != l->bitmap) { 3990edf2c54Smickey /* 4000edf2c54Smickey * violates PCI IRQ Routing Table Specification 4010edf2c54Smickey */ 40264f0e01bSmickey PCIBIOS_PRINTV(("pciintr_link_init: " 4030edf2c54Smickey "bus %d device %d link 0x%02x: " 4040edf2c54Smickey "bad irq bitmap 0x%04x, " 40564f0e01bSmickey "should be 0x%04x\n", pir->bus, 40664f0e01bSmickey PIR_DEVFUNC_DEVICE(pir->device), link, 40764f0e01bSmickey pir->linkmap[pin].bitmap, l->bitmap)); 4080edf2c54Smickey /* safer value. */ 4090edf2c54Smickey l->bitmap &= pir->linkmap[pin].bitmap; 4100edf2c54Smickey /* XXX - or, should ignore this entry? */ 4110edf2c54Smickey } 4126661564bSmickey } 4136661564bSmickey } 4146661564bSmickey 415b25264e3Smickey return (0); 416b25264e3Smickey } 417b25264e3Smickey 418b25264e3Smickey /* 419b25264e3Smickey * No compatible PCI ICU found. 420b25264e3Smickey * Hopes the BIOS already setup the ICU. 421b25264e3Smickey */ 42264f0e01bSmickey static __inline int 42364f0e01bSmickey pciintr_guess_irq(void) 424b25264e3Smickey { 425b25264e3Smickey struct pciintr_link_map *l; 426b25264e3Smickey int irq, guessed = 0; 427b25264e3Smickey 428b25264e3Smickey /* 429b25264e3Smickey * Stage 1: If only one IRQ is available for the link, use it. 430b25264e3Smickey */ 431b25264e3Smickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 432b25264e3Smickey l = SIMPLEQ_NEXT(l, list)) { 433b25264e3Smickey if (l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) 434b25264e3Smickey continue; 435b25264e3Smickey if (pciintr_bitmap_count_irq(l->bitmap, &irq) == 1) { 436b25264e3Smickey l->irq = irq; 437b25264e3Smickey l->fixup_stage = 1; 43864f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 439b25264e3Smickey printf("pciintr_guess_irq (stage 1): " 440b25264e3Smickey "guessing PIRQ 0x%02x to be IRQ %d\n", 441b25264e3Smickey l->clink, l->irq); 442b25264e3Smickey guessed = 1; 443b25264e3Smickey } 444b25264e3Smickey } 445b25264e3Smickey 446b25264e3Smickey return (guessed ? 0 : -1); 4476661564bSmickey } 4486661564bSmickey 44964f0e01bSmickey static __inline int 45064f0e01bSmickey pciintr_link_fixup(void) 4516661564bSmickey { 4526661564bSmickey struct pciintr_link_map *l; 4530edf2c54Smickey u_int16_t pciirq = 0; 45464f0e01bSmickey int irq; 4556661564bSmickey 4566661564bSmickey /* 4576661564bSmickey * First stage: Attempt to connect PIRQs which aren't 4586661564bSmickey * yet connected. 4596661564bSmickey */ 4606661564bSmickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 4616661564bSmickey l = SIMPLEQ_NEXT(l, list)) { 4620edf2c54Smickey if (l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 4636661564bSmickey /* 4640edf2c54Smickey * Interrupt is already connected. Don't do 4650edf2c54Smickey * anything to it. 4660edf2c54Smickey * In this case, l->fixup_stage == 0. 4676661564bSmickey */ 4680edf2c54Smickey pciirq |= 1 << l->irq; 46964f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 47064f0e01bSmickey printf("pciintr_link_fixup: PIRQ 0x%02x is " 47164f0e01bSmickey "already connected to IRQ %d\n", 47264f0e01bSmickey l->clink, l->irq); 4736661564bSmickey continue; 4746661564bSmickey } 4756661564bSmickey /* 4760edf2c54Smickey * Interrupt isn't connected. Attempt to assign it to an IRQ. 4776661564bSmickey */ 47864f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 4790edf2c54Smickey printf("pciintr_link_fixup: PIRQ 0x%02x not connected", 4806661564bSmickey l->clink); 48164f0e01bSmickey 4826661564bSmickey /* 4830edf2c54Smickey * Just do the easy case now; we'll defer the harder ones 4840edf2c54Smickey * to Stage 2. 4856661564bSmickey */ 4860edf2c54Smickey if (pciintr_bitmap_count_irq(l->bitmap, &irq) == 1) { 4870edf2c54Smickey l->irq = irq; 4886661564bSmickey l->fixup_stage = 1; 4890edf2c54Smickey pciirq |= 1 << irq; 49064f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 4916661564bSmickey printf(", assigning IRQ %d", l->irq); 4926661564bSmickey } 49364f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 4946661564bSmickey printf("\n"); 4956661564bSmickey } 4966661564bSmickey 4976661564bSmickey /* 4986661564bSmickey * Stage 2: Attempt to connect PIRQs which we didn't 4996661564bSmickey * connect in Stage 1. 5006661564bSmickey */ 5016661564bSmickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 50264f0e01bSmickey l = SIMPLEQ_NEXT(l, list)) 50364f0e01bSmickey if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION && 50464f0e01bSmickey (irq = ffs(l->bitmap & pciirq)) > 0) { 5056661564bSmickey /* 5060edf2c54Smickey * This IRQ is a valid PCI IRQ already 5070edf2c54Smickey * connected to another PIRQ, and also an 5080edf2c54Smickey * IRQ our PIRQ can use; connect it up! 5096661564bSmickey */ 5106661564bSmickey l->fixup_stage = 2; 51164f0e01bSmickey l->irq = irq - 1; 51264f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 5130edf2c54Smickey printf("pciintr_link_fixup (stage 2): " 5140edf2c54Smickey "assigning IRQ %d to PIRQ 0x%02x\n", 5150edf2c54Smickey l->irq, l->clink); 5166661564bSmickey } 5176661564bSmickey 5180edf2c54Smickey #ifdef PCIBIOS_IRQS_HINT 5196661564bSmickey /* 5200edf2c54Smickey * Stage 3: The worst case. I need configuration hint that 5210edf2c54Smickey * user supplied a mask for the PCI irqs 5226661564bSmickey */ 5230edf2c54Smickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 5240edf2c54Smickey l = SIMPLEQ_NEXT(l, list)) { 52564f0e01bSmickey if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION && 52664f0e01bSmickey (irq = ffs(l->bitmap & pcibios_irqs_hint)) > 0) { 5270edf2c54Smickey l->fixup_stage = 3; 52864f0e01bSmickey l->irq = irq - 1; 52964f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 5300edf2c54Smickey printf("pciintr_link_fixup (stage 3): " 5310edf2c54Smickey "assigning IRQ %d to PIRQ 0x%02x\n", 5320edf2c54Smickey l->irq, l->clink); 5330edf2c54Smickey } 5340edf2c54Smickey } 5350edf2c54Smickey #endif /* PCIBIOS_IRQS_HINT */ 5366661564bSmickey 53764f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 53864f0e01bSmickey printf("pciintr_link_fixup: piirq 0x%04x\n", pciirq); 53964f0e01bSmickey 5406661564bSmickey return (0); 5416661564bSmickey } 5426661564bSmickey 5436661564bSmickey int 54408f75f72Sjsg pci_intr_route_link(pci_chipset_tag_t pc, pci_intr_handle_t *ihp) 5456661564bSmickey { 5466661564bSmickey struct pciintr_link_map *l; 54764f0e01bSmickey pcireg_t intr; 548a25c7806Smickey int irq, rv = 1; 54964f0e01bSmickey char *p = NULL; 5506661564bSmickey 5518b0f2e63Smickey if (pcibios_flags & PCIBIOS_INTR_FIXUP) 5528b0f2e63Smickey return 1; 5538b0f2e63Smickey 554a25c7806Smickey irq = ihp->line & APIC_INT_LINE_MASK; 555a25c7806Smickey if (irq != 0 && irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) 556a25c7806Smickey pcibios_pir_header.exclusive_irq |= 1 << irq; 557ff51c22aSmickey 55864f0e01bSmickey l = ihp->link; 55964f0e01bSmickey if (!l || pciintr_icu_tag == NULL) 56064f0e01bSmickey return (1); 5616661564bSmickey 5620edf2c54Smickey if (l->fixup_stage == 0) { 5630edf2c54Smickey if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 5640edf2c54Smickey /* Appropriate interrupt was not found. */ 56564f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 56664f0e01bSmickey printf("pci_intr_route_link: PIRQ 0x%02x: " 56764f0e01bSmickey "no IRQ, try " 56864f0e01bSmickey "\"option PCIBIOS_IRQS_HINT=0x%04x\"\n", 5690edf2c54Smickey l->clink, 5700edf2c54Smickey /* suggest irq 9/10/11, if possible */ 5710edf2c54Smickey (l->bitmap & 0x0e00) ? (l->bitmap & 0x0e00) 5720edf2c54Smickey : l->bitmap); 57364f0e01bSmickey } else 57464f0e01bSmickey p = " preserved BIOS setting"; 5750edf2c54Smickey } else { 5760edf2c54Smickey 5776661564bSmickey if (pciintr_icu_set_intr(pciintr_icu_tag, pciintr_icu_handle, 5786661564bSmickey l->clink, l->irq) != 0 || 57964f0e01bSmickey pciintr_icu_set_trigger(pciintr_icu_tag, pciintr_icu_handle, 5806661564bSmickey l->irq, IST_LEVEL) != 0) { 58164f0e01bSmickey p = " failed"; 58264f0e01bSmickey rv = 0; 58364f0e01bSmickey } else 58464f0e01bSmickey p = ""; 5856661564bSmickey } 58664f0e01bSmickey if (p && pcibios_flags & PCIBIOS_INTRDEBUG) 58764f0e01bSmickey printf("pci_intr_route_link: route PIRQ 0x%02x -> IRQ %d%s\n", 58864f0e01bSmickey l->clink, l->irq, p); 5896661564bSmickey 59064f0e01bSmickey if (!rv) 5916661564bSmickey return (0); 5920edf2c54Smickey 5936661564bSmickey /* 5940edf2c54Smickey * IRQs 14 and 15 are reserved for PCI IDE interrupts; don't muck 5956661564bSmickey * with them. 5966661564bSmickey */ 597a25c7806Smickey if (irq == 14 || irq == 15) 59864f0e01bSmickey return (1); 59964f0e01bSmickey 60064f0e01bSmickey intr = pci_conf_read(pc, ihp->tag, PCI_INTERRUPT_REG); 601a25c7806Smickey if (irq != PCI_INTERRUPT_LINE(intr)) { 60264f0e01bSmickey intr &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT); 603a25c7806Smickey intr |= irq << PCI_INTERRUPT_LINE_SHIFT; 60464f0e01bSmickey pci_conf_write(pc, ihp->tag, PCI_INTERRUPT_REG, intr); 6050edf2c54Smickey } 6066661564bSmickey 60764f0e01bSmickey return (1); 60864f0e01bSmickey } 60964f0e01bSmickey 61064f0e01bSmickey int 61108f75f72Sjsg pci_intr_post_fixup(void) 61264f0e01bSmickey { 61364f0e01bSmickey struct pciintr_link_map *l; 61464f0e01bSmickey int i, pciirq; 61564f0e01bSmickey 6168b0f2e63Smickey if (pcibios_flags & PCIBIOS_INTR_FIXUP) 6178b0f2e63Smickey return 1; 6188b0f2e63Smickey 61964f0e01bSmickey if (!pciintr_icu_handle) 62064f0e01bSmickey return 0; 62164f0e01bSmickey 62264f0e01bSmickey pciirq = pcibios_pir_header.exclusive_irq; 62364f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 62464f0e01bSmickey printf("pci_intr_post_fixup: PCI IRQs:"); 62564f0e01bSmickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); 62664f0e01bSmickey l != NULL; l = SIMPLEQ_NEXT(l, list)) 627ff51c22aSmickey if (l->fixup_stage == 0 && l->irq != 0 && 62864f0e01bSmickey l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 62964f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 63064f0e01bSmickey printf(" %d", l->irq); 63164f0e01bSmickey pciirq |= (1 << l->irq); 63264f0e01bSmickey } 63364f0e01bSmickey 63464f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 63564f0e01bSmickey printf("; ISA IRQs:"); 63664f0e01bSmickey for (i = 0; i < 16; i++) 63764f0e01bSmickey if (!(pciirq & (1 << i))) { 63864f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 63964f0e01bSmickey printf(" %d", i); 64064f0e01bSmickey pciintr_icu_set_trigger(pciintr_icu_tag, 64164f0e01bSmickey pciintr_icu_handle, i, IST_EDGE); 64264f0e01bSmickey } 64364f0e01bSmickey 64464f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 64564f0e01bSmickey printf("\n"); 64664f0e01bSmickey 64764f0e01bSmickey return (0); 64864f0e01bSmickey } 64964f0e01bSmickey 65064f0e01bSmickey int 65108f75f72Sjsg pci_intr_header_fixup(pci_chipset_tag_t pc, pcitag_t tag, 65208f75f72Sjsg pci_intr_handle_t *ihp) 65364f0e01bSmickey { 65464f0e01bSmickey struct pcibios_intr_routing *pir; 65564f0e01bSmickey struct pciintr_link_map *l; 65664f0e01bSmickey int irq, link, bus, device, function; 65764f0e01bSmickey char *p = NULL; 65864f0e01bSmickey 6598b0f2e63Smickey if (pcibios_flags & PCIBIOS_INTR_FIXUP) 6608b0f2e63Smickey return 1; 6618b0f2e63Smickey 662a25c7806Smickey irq = ihp->line & APIC_INT_LINE_MASK; 66364f0e01bSmickey ihp->link = NULL; 66464f0e01bSmickey pci_decompose_tag(pc, tag, &bus, &device, &function); 66564f0e01bSmickey 66664f0e01bSmickey if ((pir = pciintr_pir_lookup(bus, device)) == NULL || 66764f0e01bSmickey (link = pir->linkmap[ihp->pin - 1].link) == 0) { 66864f0e01bSmickey PCIBIOS_PRINTV(("Interrupt not connected; no need to change.")); 66964f0e01bSmickey return 1; 67064f0e01bSmickey } 67164f0e01bSmickey 67264f0e01bSmickey if ((l = pciintr_link_lookup(link)) == NULL) { 67364f0e01bSmickey /* 67464f0e01bSmickey * No link map entry. 67564f0e01bSmickey * Probably pciintr_icu_getclink() or pciintr_icu_get_intr() 676a25c7806Smickey * has failed. 67764f0e01bSmickey */ 67864f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 67964f0e01bSmickey printf("pci_intr_header_fixup: no entry for link " 68064f0e01bSmickey "0x%02x (%d:%d:%d:%c)\n", 68164f0e01bSmickey link, bus, device, function, '@' + ihp->pin); 68264f0e01bSmickey return 1; 68364f0e01bSmickey } 68464f0e01bSmickey 6851120a2ccSmarkus ihp->link = l; 6861120a2ccSmarkus if (irq == 14 || irq == 15) { 68764f0e01bSmickey p = " WARNING: ignored"; 6881120a2ccSmarkus ihp->link = NULL; 6891120a2ccSmarkus } else if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 69064f0e01bSmickey 6910edf2c54Smickey /* Appropriate interrupt was not found. */ 692a25c7806Smickey if (pciintr_icu_tag == NULL && irq != 0 && 693a25c7806Smickey irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) 694b25264e3Smickey /* 695b25264e3Smickey * Do not print warning, 696b25264e3Smickey * if no compatible PCI ICU found, 697b25264e3Smickey * but the irq is already assigned by BIOS. 698b25264e3Smickey */ 69964f0e01bSmickey p = ""; 70064f0e01bSmickey else 70164f0e01bSmickey p = " WARNING: missing"; 70264f0e01bSmickey } else if (irq == 0 || irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 7030edf2c54Smickey 70464f0e01bSmickey p = " fixed up"; 705a25c7806Smickey ihp->line = irq = l->irq; 7060edf2c54Smickey 707a003464cSmickey } else if (pcibios_flags & PCIBIOS_FIXUP_FORCE) { 7080edf2c54Smickey /* routed by BIOS, but inconsistent */ 7090edf2c54Smickey /* believe PCI IRQ Routing table */ 71064f0e01bSmickey p = " WARNING: overriding"; 711a25c7806Smickey ihp->line = irq = l->irq; 71278b5d43cSmickey } else { 7130edf2c54Smickey /* believe PCI Interrupt Configuration Register (default) */ 71464f0e01bSmickey p = " WARNING: preserving"; 715a25c7806Smickey ihp->line = (l->irq = irq) | (l->clink & PCI_INT_VIA_ISA); 71678b5d43cSmickey } 7176661564bSmickey 71864f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) { 71908f75f72Sjsg pcireg_t id = pci_conf_read(pc, tag, PCI_ID_REG); 72064f0e01bSmickey 72178b5d43cSmickey printf("\n%d:%d:%d %04x:%04x pin %c clink 0x%02x irq %d " 72278b5d43cSmickey "stage %d %s irq %d\n", bus, device, function, 72364f0e01bSmickey PCI_VENDOR(id), PCI_PRODUCT(id), '@' + ihp->pin, l->clink, 72464f0e01bSmickey ((l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION)? 72564f0e01bSmickey -1 : l->irq), l->fixup_stage, p, irq); 72664f0e01bSmickey } 72764f0e01bSmickey 72864f0e01bSmickey return (1); 7296661564bSmickey } 7306661564bSmickey 7316661564bSmickey int 73208f75f72Sjsg pci_intr_fixup(struct pcibios_softc *sc, pci_chipset_tag_t pc, 73308f75f72Sjsg bus_space_tag_t iot) 7346661564bSmickey { 735df73a7d0Smickey struct pcibios_pir_header *pirh = &pcibios_pir_header; 7366661564bSmickey const struct pciintr_icu_table *piit = NULL; 7376661564bSmickey pcitag_t icutag; 7386661564bSmickey 7396661564bSmickey /* 7406661564bSmickey * Attempt to initialize our PCI interrupt router. If 7416661564bSmickey * the PIR Table is present in ROM, use the location 7426661564bSmickey * specified by the PIR Table, and use the compat ID, 7436661564bSmickey * if present. Otherwise, we have to look for the router 7446661564bSmickey * ourselves (the PCI-ISA bridge). 745911088d6Smickey * 746911088d6Smickey * A number of buggy BIOS implementations leave the router 747911088d6Smickey * entry as 000:00:0, which is typically not the correct 748911088d6Smickey * device/function. If the router device address is set to 749911088d6Smickey * this value, and the compatible router entry is undefined 750911088d6Smickey * (zero is the correct value to indicate undefined), then we 751911088d6Smickey * work on the basis it is most likely an error, and search 752911088d6Smickey * the entire device-space of bus 0 (but obviously starting 753911088d6Smickey * with 000:00:0, in case that really is the right one). 7546661564bSmickey */ 755911088d6Smickey if (pirh->signature != 0 && (pirh->router_bus != 0 || 756911088d6Smickey pirh->router_devfunc != 0 || pirh->compat_router != 0)) { 757911088d6Smickey 7586c0a4d12Smickey icutag = pci_make_tag(pc, pirh->router_bus, 7596c0a4d12Smickey PIR_DEVFUNC_DEVICE(pirh->router_devfunc), 7606c0a4d12Smickey PIR_DEVFUNC_FUNCTION(pirh->router_devfunc)); 761911088d6Smickey if (pirh->compat_router == 0 || 762911088d6Smickey (piit = pciintr_icu_lookup(pirh->compat_router)) == NULL) { 7636661564bSmickey /* 7646661564bSmickey * No compat ID, or don't know the compat ID? Read 7656661564bSmickey * it from the configuration header. 7666661564bSmickey */ 7676c0a4d12Smickey pirh->compat_router = pci_conf_read(pc, icutag, 768911088d6Smickey PCI_ID_REG); 7696661564bSmickey } 7706661564bSmickey if (piit == NULL) 771911088d6Smickey piit = pciintr_icu_lookup(pirh->compat_router); 7726661564bSmickey } else { 7736661564bSmickey int device, maxdevs = pci_bus_maxdevs(pc, 0); 7746661564bSmickey 7756661564bSmickey /* 7766661564bSmickey * Search configuration space for a known interrupt 7776661564bSmickey * router. 7786661564bSmickey */ 7796661564bSmickey for (device = 0; device < maxdevs; device++) { 780911088d6Smickey const struct pci_quirkdata *qd; 781911088d6Smickey int function, nfuncs; 782911088d6Smickey pcireg_t icuid; 783911088d6Smickey pcireg_t bhlcr; 784911088d6Smickey 7856661564bSmickey icutag = pci_make_tag(pc, 0, device, 0); 7866661564bSmickey icuid = pci_conf_read(pc, icutag, PCI_ID_REG); 7876661564bSmickey 7886661564bSmickey /* Invalid vendor ID value? */ 7896661564bSmickey if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID) 7906661564bSmickey continue; 7916661564bSmickey /* XXX Not invalid, but we've done this ~forever. */ 7926661564bSmickey if (PCI_VENDOR(icuid) == 0) 7936661564bSmickey continue; 7946661564bSmickey 795911088d6Smickey qd = pci_lookup_quirkdata(PCI_VENDOR(icuid), 796911088d6Smickey PCI_PRODUCT(icuid)); 797911088d6Smickey 798911088d6Smickey bhlcr = pci_conf_read(pc, icutag, PCI_BHLC_REG); 799911088d6Smickey if (PCI_HDRTYPE_MULTIFN(bhlcr) || (qd != NULL && 800911088d6Smickey (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0)) 801911088d6Smickey nfuncs = 8; 802911088d6Smickey else 803911088d6Smickey nfuncs = 1; 804911088d6Smickey 805911088d6Smickey for (function = 0; function < nfuncs; function++) { 806911088d6Smickey icutag = pci_make_tag(pc, 0, device, function); 807911088d6Smickey icuid = pci_conf_read(pc, icutag, PCI_ID_REG); 808911088d6Smickey 809911088d6Smickey /* Invalid vendor ID value? */ 810911088d6Smickey if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID) 811911088d6Smickey continue; 812911088d6Smickey /* Not invalid, but we've done this ~forever. */ 813911088d6Smickey if (PCI_VENDOR(icuid) == 0) 814911088d6Smickey continue; 815911088d6Smickey 816df73a7d0Smickey if ((piit = pciintr_icu_lookup(icuid))) { 817df73a7d0Smickey pirh->compat_router = icuid; 818df73a7d0Smickey pirh->router_bus = 0; 819df73a7d0Smickey pirh->router_devfunc = 820df73a7d0Smickey PIR_DEVFUNC_COMPOSE(device, 0); 8216661564bSmickey break; 8226661564bSmickey } 8236661564bSmickey } 824911088d6Smickey 825911088d6Smickey if (piit != NULL) 826911088d6Smickey break; 827911088d6Smickey } 828df73a7d0Smickey } 8296661564bSmickey 8306661564bSmickey if (piit == NULL) { 831df73a7d0Smickey printf("%s: no compatible PCI ICU found", sc->sc_dev.dv_xname); 832911088d6Smickey if (pirh->signature != 0 && pirh->compat_router != 0) 833b25264e3Smickey printf(": ICU vendor 0x%04x product 0x%04x", 834911088d6Smickey PCI_VENDOR(pirh->compat_router), 835911088d6Smickey PCI_PRODUCT(pirh->compat_router)); 836b25264e3Smickey printf("\n"); 837b25264e3Smickey if (!(pcibios_flags & PCIBIOS_INTR_GUESS)) { 83864f0e01bSmickey if (pciintr_link_init(pc)) 839b25264e3Smickey return (-1); /* non-fatal */ 840b25264e3Smickey if (pciintr_guess_irq()) 841b25264e3Smickey return (-1); /* non-fatal */ 842bb701a32Smickey } 843bb701a32Smickey return (0); 844df73a7d0Smickey } else { 845df73a7d0Smickey char devinfo[256]; 846df73a7d0Smickey 847df73a7d0Smickey printf("%s: PCI Interrupt Router at %03d:%02d:%01d", 848df73a7d0Smickey sc->sc_dev.dv_xname, pirh->router_bus, 849df73a7d0Smickey PIR_DEVFUNC_DEVICE(pirh->router_devfunc), 850df73a7d0Smickey PIR_DEVFUNC_FUNCTION(pirh->router_devfunc)); 851df73a7d0Smickey if (pirh->compat_router != 0) { 8522627362dSho pci_devinfo(pirh->compat_router, 0, 0, devinfo, 8532627362dSho sizeof devinfo); 854df73a7d0Smickey printf(" (%s)", devinfo); 855df73a7d0Smickey } 856df73a7d0Smickey printf("\n"); 8576661564bSmickey } 8586661564bSmickey 8596661564bSmickey /* 8606661564bSmickey * Initialize the PCI ICU. 8616661564bSmickey */ 8626661564bSmickey if ((*piit->piit_init)(pc, iot, icutag, &pciintr_icu_tag, 8636661564bSmickey &pciintr_icu_handle) != 0) 8646661564bSmickey return (-1); /* non-fatal */ 8656661564bSmickey 8666661564bSmickey /* 8676661564bSmickey * Initialize the PCI interrupt link map. 8686661564bSmickey */ 86964f0e01bSmickey if (pciintr_link_init(pc)) 8706661564bSmickey return (-1); /* non-fatal */ 8716661564bSmickey 8726661564bSmickey /* 8736661564bSmickey * Fix up the link->IRQ mappings. 8746661564bSmickey */ 8756661564bSmickey if (pciintr_link_fixup() != 0) 8766661564bSmickey return (-1); /* non-fatal */ 8776661564bSmickey 87864f0e01bSmickey return (0); 8796661564bSmickey } 880