1*a25c7806Smickey /* $OpenBSD: pci_intr_fixup.c,v 1.49 2005/11/23 09:24:57 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> 104*a25c7806Smickey #include <machine/i82093var.h> 1056661564bSmickey 1066661564bSmickey #include <dev/pci/pcireg.h> 1076661564bSmickey #include <dev/pci/pcivar.h> 1086661564bSmickey #include <dev/pci/pcidevs.h> 1096661564bSmickey 110e2331c6cSderaadt #include <i386/pci/pcibiosvar.h> 1116661564bSmickey 1126661564bSmickey struct pciintr_link_map { 11364f0e01bSmickey int link, clink, irq, fixup_stage; 1146661564bSmickey u_int16_t bitmap; 1156661564bSmickey SIMPLEQ_ENTRY(pciintr_link_map) list; 1166661564bSmickey }; 1176661564bSmickey 118b25264e3Smickey pciintr_icu_tag_t pciintr_icu_tag = NULL; 1196661564bSmickey pciintr_icu_handle_t pciintr_icu_handle; 1206661564bSmickey 1210edf2c54Smickey #ifdef PCIBIOS_IRQS_HINT 1220edf2c54Smickey int pcibios_irqs_hint = PCIBIOS_IRQS_HINT; 1230edf2c54Smickey #endif 1240edf2c54Smickey 125c4071fd1Smillert struct pciintr_link_map *pciintr_link_lookup(int); 126c4071fd1Smillert struct pcibios_intr_routing *pciintr_pir_lookup(int, int); 127c4071fd1Smillert int pciintr_bitmap_count_irq(int, int *); 1286661564bSmickey 1296661564bSmickey SIMPLEQ_HEAD(, pciintr_link_map) pciintr_link_map_list; 1306661564bSmickey 1316661564bSmickey const struct pciintr_icu_table { 1326661564bSmickey pci_vendor_id_t piit_vendor; 1336661564bSmickey pci_product_id_t piit_product; 134c4071fd1Smillert int (*piit_init)(pci_chipset_tag_t, 1356661564bSmickey bus_space_tag_t, pcitag_t, pciintr_icu_tag_t *, 136c4071fd1Smillert pciintr_icu_handle_t *); 1376661564bSmickey } pciintr_icu_table[] = { 13823f11131Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6300ESB_LPC, 13923f11131Sbrad piix_init }, 1406661564bSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371MX, 1416661564bSmickey piix_init }, 1426661564bSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371AB_ISA, 1436661564bSmickey piix_init }, 1446661564bSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371FB_ISA, 1456661564bSmickey piix_init }, 1466661564bSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371SB_ISA, 1476661564bSmickey piix_init }, 14823f11131Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82440MX_ISA, 14923f11131Sbrad piix_init }, 150ea8e013cSho { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AA_LPC, 151ea8e013cSho piix_init }, 15223f11131Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AB_LPC, 15323f11131Sbrad piix_init }, 15453003c45Smickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_LPC, 15553003c45Smickey piix_init }, 15653003c45Smickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BAM_LPC, 15753003c45Smickey piix_init }, 158b9a626b7Smickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801CA_LPC, 159b9a626b7Smickey piix_init }, 1606d805c04Smickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801CAM_LPC, 1616d805c04Smickey piix_init }, 1626d805c04Smickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801DB_LPC, 1636d805c04Smickey piix_init }, 16423f11131Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801E_LPC, 16523f11131Sbrad piix_init }, 1665b6ecbecSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801EB_LPC, 1675b6ecbecSmickey piix_init }, 1686eced139Sbeck { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801FB_LPC, 1696eced139Sbeck piix_init }, 17023f11131Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801FBM_LPC, 17123f11131Sbrad piix_init }, 172d984c6bdSmickey { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GB_LPC, 173d984c6bdSmickey piix_init }, 17423f11131Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GBM_LPC, 17523f11131Sbrad piix_init }, 17623f11131Sbrad { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GH_LPC, 177aa5f4fe6Sbrad piix_init }, 1786661564bSmickey 1796661564bSmickey { PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C558, 1806661564bSmickey opti82c558_init }, 1816661564bSmickey { PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C700, 1826661564bSmickey opti82c700_init }, 1836661564bSmickey 1848a1eb7fcSbrad { PCI_VENDOR_RCC, PCI_PRODUCT_RCC_OSB4, 185bd25a23dSmickey osb4_init }, 186bd25a23dSmickey { PCI_VENDOR_RCC, PCI_PRODUCT_RCC_CSB5, 187bd25a23dSmickey osb4_init }, 188bd25a23dSmickey 18964f0e01bSmickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C596A, 19064f0e01bSmickey via82c586_init, }, 1916661564bSmickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C586_ISA, 1926661564bSmickey via82c586_init, }, 19364f0e01bSmickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C686A_ISA, 19492598216Smickey via82c586_init }, 195eedf424eSmickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8366_ISA, 196eedf424eSmickey via82c586_init }, 19792598216Smickey 19892598216Smickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8231_ISA, 19992598216Smickey via8231_init }, 20024996536Smickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8233_ISA, 20124996536Smickey via8231_init }, 20224996536Smickey { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8235_ISA, 20324996536Smickey via8231_init }, 204bc465bf0Shenning { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237_ISA, 205bc465bf0Shenning via8231_init }, 2066661564bSmickey 2076661564bSmickey { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_85C503, 2086661564bSmickey sis85c503_init }, 2096661564bSmickey 210cc48d299Smickey { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC756_PMC, 21167218ad0Smickey amd756_init }, 21264c49bbaSmickey { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_766_ISA, 21364c49bbaSmickey amd756_init }, 21467218ad0Smickey 2152766fe41Smillert { PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M1533, 2162766fe41Smillert ali1543_init }, 2172766fe41Smillert 2187853e030Smickey { PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M1543, 2197853e030Smickey ali1543_init }, 2207853e030Smickey 2216661564bSmickey { 0, 0, 2226661564bSmickey NULL }, 2236661564bSmickey }; 2246661564bSmickey 225c4071fd1Smillert const struct pciintr_icu_table *pciintr_icu_lookup(pcireg_t); 2266661564bSmickey 2276661564bSmickey const struct pciintr_icu_table * 2286661564bSmickey pciintr_icu_lookup(id) 2296661564bSmickey pcireg_t id; 2306661564bSmickey { 2316661564bSmickey const struct pciintr_icu_table *piit; 2326661564bSmickey 23364f0e01bSmickey for (piit = pciintr_icu_table; piit->piit_init != NULL; piit++) 2346661564bSmickey if (PCI_VENDOR(id) == piit->piit_vendor && 2356661564bSmickey PCI_PRODUCT(id) == piit->piit_product) 2366661564bSmickey return (piit); 2376661564bSmickey 2386661564bSmickey return (NULL); 2396661564bSmickey } 2406661564bSmickey 2416661564bSmickey struct pciintr_link_map * 2420edf2c54Smickey pciintr_link_lookup(link) 2436661564bSmickey int link; 2446661564bSmickey { 2456661564bSmickey struct pciintr_link_map *l; 2466661564bSmickey 2476661564bSmickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 24864f0e01bSmickey l = SIMPLEQ_NEXT(l, list)) 2496661564bSmickey if (l->link == link) 2506661564bSmickey return (l); 2516661564bSmickey 2526661564bSmickey return (NULL); 2536661564bSmickey } 2546661564bSmickey 25564f0e01bSmickey static __inline struct pciintr_link_map * 25664f0e01bSmickey pciintr_link_alloc(pci_chipset_tag_t pc, struct pcibios_intr_routing *pir, int pin) 2576661564bSmickey { 2580edf2c54Smickey int link = pir->linkmap[pin].link, clink, irq; 2596661564bSmickey struct pciintr_link_map *l, *lstart; 2606661564bSmickey 261b25264e3Smickey if (pciintr_icu_tag != NULL) { 2620edf2c54Smickey /* 2630edf2c54Smickey * Get the canonical link value for this entry. 2640edf2c54Smickey */ 265b25264e3Smickey if (pciintr_icu_getclink(pciintr_icu_tag, pciintr_icu_handle, 266b25264e3Smickey link, &clink) != 0) { 2670edf2c54Smickey /* 2680edf2c54Smickey * ICU doesn't understand the link value. 2690edf2c54Smickey * Just ignore this PIR entry. 2700edf2c54Smickey */ 27164f0e01bSmickey PCIBIOS_PRINTV(("pciintr_link_alloc: bus %d device %d: " 27264f0e01bSmickey "ignoring link 0x%02x\n", pir->bus, 27364f0e01bSmickey PIR_DEVFUNC_DEVICE(pir->device), link)); 2740edf2c54Smickey return (NULL); 2750edf2c54Smickey } 2760edf2c54Smickey 2770edf2c54Smickey /* 278b25264e3Smickey * Check the link value by asking the ICU for the 279b25264e3Smickey * canonical link value. 2800edf2c54Smickey * Also, determine if this PIRQ is mapped to an IRQ. 2810edf2c54Smickey */ 282b25264e3Smickey if (pciintr_icu_get_intr(pciintr_icu_tag, pciintr_icu_handle, 283b25264e3Smickey clink, &irq) != 0) { 2840edf2c54Smickey /* 2850edf2c54Smickey * ICU doesn't understand the canonical link value. 2860edf2c54Smickey * Just ignore this PIR entry. 2870edf2c54Smickey */ 28864f0e01bSmickey PCIBIOS_PRINTV(("pciintr_link_alloc: " 289b25264e3Smickey "bus %d device %d link 0x%02x: " 290b25264e3Smickey "ignoring PIRQ 0x%02x\n", pir->bus, 29164f0e01bSmickey PIR_DEVFUNC_DEVICE(pir->device), link, clink)); 2920edf2c54Smickey return (NULL); 2930edf2c54Smickey } 294b25264e3Smickey } 2950edf2c54Smickey 29664f0e01bSmickey if ((l = malloc(sizeof(*l), M_DEVBUF, M_NOWAIT)) == NULL) 2970edf2c54Smickey return (NULL); 2986661564bSmickey 2996661564bSmickey memset(l, 0, sizeof(*l)); 3006661564bSmickey 3010edf2c54Smickey l->link = link; 3026661564bSmickey l->bitmap = pir->linkmap[pin].bitmap; 303b25264e3Smickey if (pciintr_icu_tag != NULL) { /* compatible PCI ICU found */ 3040edf2c54Smickey l->clink = clink; 3050edf2c54Smickey l->irq = irq; /* maybe I386_PCI_INTERRUPT_LINE_NO_CONNECTION */ 306b25264e3Smickey } else { 30764f0e01bSmickey l->clink = link; 308b25264e3Smickey l->irq = I386_PCI_INTERRUPT_LINE_NO_CONNECTION; 309b25264e3Smickey } 3106661564bSmickey 3116661564bSmickey lstart = SIMPLEQ_FIRST(&pciintr_link_map_list); 3126661564bSmickey if (lstart == NULL || lstart->link < l->link) 3136661564bSmickey SIMPLEQ_INSERT_TAIL(&pciintr_link_map_list, l, list); 3146661564bSmickey else 3156661564bSmickey SIMPLEQ_INSERT_HEAD(&pciintr_link_map_list, l, list); 3166661564bSmickey 3176661564bSmickey return (l); 3186661564bSmickey } 3196661564bSmickey 3206661564bSmickey struct pcibios_intr_routing * 3216661564bSmickey pciintr_pir_lookup(bus, device) 3226661564bSmickey int bus, device; 3236661564bSmickey { 3246661564bSmickey struct pcibios_intr_routing *pir; 3256661564bSmickey int entry; 3266661564bSmickey 3276661564bSmickey if (pcibios_pir_table == NULL) 3286661564bSmickey return (NULL); 3296661564bSmickey 3306661564bSmickey for (entry = 0; entry < pcibios_pir_table_nentries; entry++) { 3316661564bSmickey pir = &pcibios_pir_table[entry]; 3320edf2c54Smickey if (pir->bus == bus && 3330edf2c54Smickey PIR_DEVFUNC_DEVICE(pir->device) == device) 3346661564bSmickey return (pir); 3356661564bSmickey } 3366661564bSmickey 3376661564bSmickey return (NULL); 3386661564bSmickey } 3396661564bSmickey 34064f0e01bSmickey int 3410edf2c54Smickey pciintr_bitmap_count_irq(irq_bitmap, irqp) 3420edf2c54Smickey int irq_bitmap, *irqp; 3430edf2c54Smickey { 3440edf2c54Smickey int i, bit, count = 0, irq = I386_PCI_INTERRUPT_LINE_NO_CONNECTION; 3450edf2c54Smickey 34664f0e01bSmickey if (irq_bitmap != 0) 34764f0e01bSmickey for (i = 0, bit = 1; i < 16; i++, bit <<= 1) 3480edf2c54Smickey if (irq_bitmap & bit) { 3490edf2c54Smickey irq = i; 3500edf2c54Smickey count++; 3510edf2c54Smickey } 35264f0e01bSmickey 3530edf2c54Smickey *irqp = irq; 3540edf2c54Smickey return (count); 3550edf2c54Smickey } 3560edf2c54Smickey 35764f0e01bSmickey static __inline int 35864f0e01bSmickey pciintr_link_init(pci_chipset_tag_t pc) 3596661564bSmickey { 360b25264e3Smickey int entry, pin, link; 3616661564bSmickey struct pcibios_intr_routing *pir; 3626661564bSmickey struct pciintr_link_map *l; 3636661564bSmickey 3646661564bSmickey if (pcibios_pir_table == NULL) { 3656661564bSmickey /* No PIR table; can't do anything. */ 3666661564bSmickey printf("pciintr_link_init: no PIR table\n"); 3676661564bSmickey return (1); 3686661564bSmickey } 3696661564bSmickey 3706661564bSmickey SIMPLEQ_INIT(&pciintr_link_map_list); 3716661564bSmickey 3726661564bSmickey for (entry = 0; entry < pcibios_pir_table_nentries; entry++) { 3736661564bSmickey pir = &pcibios_pir_table[entry]; 3740edf2c54Smickey for (pin = 0; pin < PCI_INTERRUPT_PIN_MAX; pin++) { 37564f0e01bSmickey if ((link = pir->linkmap[pin].link) == 0) 3766661564bSmickey /* No connection for this pin. */ 3776661564bSmickey continue; 37864f0e01bSmickey 3796661564bSmickey /* 3806661564bSmickey * Multiple devices may be wired to the same 3816661564bSmickey * interrupt; check to see if we've seen this 3826661564bSmickey * one already. If not, allocate a new link 3836661564bSmickey * map entry and stuff it in the map. 3846661564bSmickey */ 38564f0e01bSmickey if ((l = pciintr_link_lookup(link)) == NULL) 38664f0e01bSmickey pciintr_link_alloc(pc, pir, pin); 38764f0e01bSmickey else if (pir->linkmap[pin].bitmap != l->bitmap) { 3880edf2c54Smickey /* 3890edf2c54Smickey * violates PCI IRQ Routing Table Specification 3900edf2c54Smickey */ 39164f0e01bSmickey PCIBIOS_PRINTV(("pciintr_link_init: " 3920edf2c54Smickey "bus %d device %d link 0x%02x: " 3930edf2c54Smickey "bad irq bitmap 0x%04x, " 39464f0e01bSmickey "should be 0x%04x\n", pir->bus, 39564f0e01bSmickey PIR_DEVFUNC_DEVICE(pir->device), link, 39664f0e01bSmickey pir->linkmap[pin].bitmap, l->bitmap)); 3970edf2c54Smickey /* safer value. */ 3980edf2c54Smickey l->bitmap &= pir->linkmap[pin].bitmap; 3990edf2c54Smickey /* XXX - or, should ignore this entry? */ 4000edf2c54Smickey } 4016661564bSmickey } 4026661564bSmickey } 4036661564bSmickey 404b25264e3Smickey return (0); 405b25264e3Smickey } 406b25264e3Smickey 407b25264e3Smickey /* 408b25264e3Smickey * No compatible PCI ICU found. 409b25264e3Smickey * Hopes the BIOS already setup the ICU. 410b25264e3Smickey */ 41164f0e01bSmickey static __inline int 41264f0e01bSmickey pciintr_guess_irq(void) 413b25264e3Smickey { 414b25264e3Smickey struct pciintr_link_map *l; 415b25264e3Smickey int irq, guessed = 0; 416b25264e3Smickey 417b25264e3Smickey /* 418b25264e3Smickey * Stage 1: If only one IRQ is available for the link, use it. 419b25264e3Smickey */ 420b25264e3Smickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 421b25264e3Smickey l = SIMPLEQ_NEXT(l, list)) { 422b25264e3Smickey if (l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) 423b25264e3Smickey continue; 424b25264e3Smickey if (pciintr_bitmap_count_irq(l->bitmap, &irq) == 1) { 425b25264e3Smickey l->irq = irq; 426b25264e3Smickey l->fixup_stage = 1; 42764f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 428b25264e3Smickey printf("pciintr_guess_irq (stage 1): " 429b25264e3Smickey "guessing PIRQ 0x%02x to be IRQ %d\n", 430b25264e3Smickey l->clink, l->irq); 431b25264e3Smickey guessed = 1; 432b25264e3Smickey } 433b25264e3Smickey } 434b25264e3Smickey 435b25264e3Smickey return (guessed ? 0 : -1); 4366661564bSmickey } 4376661564bSmickey 43864f0e01bSmickey static __inline int 43964f0e01bSmickey pciintr_link_fixup(void) 4406661564bSmickey { 4416661564bSmickey struct pciintr_link_map *l; 4420edf2c54Smickey u_int16_t pciirq = 0; 44364f0e01bSmickey int irq; 4446661564bSmickey 4456661564bSmickey /* 4466661564bSmickey * First stage: Attempt to connect PIRQs which aren't 4476661564bSmickey * yet connected. 4486661564bSmickey */ 4496661564bSmickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 4506661564bSmickey l = SIMPLEQ_NEXT(l, list)) { 4510edf2c54Smickey if (l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 4526661564bSmickey /* 4530edf2c54Smickey * Interrupt is already connected. Don't do 4540edf2c54Smickey * anything to it. 4550edf2c54Smickey * In this case, l->fixup_stage == 0. 4566661564bSmickey */ 4570edf2c54Smickey pciirq |= 1 << l->irq; 45864f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 45964f0e01bSmickey printf("pciintr_link_fixup: PIRQ 0x%02x is " 46064f0e01bSmickey "already connected to IRQ %d\n", 46164f0e01bSmickey l->clink, l->irq); 4626661564bSmickey continue; 4636661564bSmickey } 4646661564bSmickey /* 4650edf2c54Smickey * Interrupt isn't connected. Attempt to assign it to an IRQ. 4666661564bSmickey */ 46764f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 4680edf2c54Smickey printf("pciintr_link_fixup: PIRQ 0x%02x not connected", 4696661564bSmickey l->clink); 47064f0e01bSmickey 4716661564bSmickey /* 4720edf2c54Smickey * Just do the easy case now; we'll defer the harder ones 4730edf2c54Smickey * to Stage 2. 4746661564bSmickey */ 4750edf2c54Smickey if (pciintr_bitmap_count_irq(l->bitmap, &irq) == 1) { 4760edf2c54Smickey l->irq = irq; 4776661564bSmickey l->fixup_stage = 1; 4780edf2c54Smickey pciirq |= 1 << irq; 47964f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 4806661564bSmickey printf(", assigning IRQ %d", l->irq); 4816661564bSmickey } 48264f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 4836661564bSmickey printf("\n"); 4846661564bSmickey } 4856661564bSmickey 4866661564bSmickey /* 4876661564bSmickey * Stage 2: Attempt to connect PIRQs which we didn't 4886661564bSmickey * connect in Stage 1. 4896661564bSmickey */ 4906661564bSmickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 49164f0e01bSmickey l = SIMPLEQ_NEXT(l, list)) 49264f0e01bSmickey if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION && 49364f0e01bSmickey (irq = ffs(l->bitmap & pciirq)) > 0) { 4946661564bSmickey /* 4950edf2c54Smickey * This IRQ is a valid PCI IRQ already 4960edf2c54Smickey * connected to another PIRQ, and also an 4970edf2c54Smickey * IRQ our PIRQ can use; connect it up! 4986661564bSmickey */ 4996661564bSmickey l->fixup_stage = 2; 50064f0e01bSmickey l->irq = irq - 1; 50164f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 5020edf2c54Smickey printf("pciintr_link_fixup (stage 2): " 5030edf2c54Smickey "assigning IRQ %d to PIRQ 0x%02x\n", 5040edf2c54Smickey l->irq, l->clink); 5056661564bSmickey } 5066661564bSmickey 5070edf2c54Smickey #ifdef PCIBIOS_IRQS_HINT 5086661564bSmickey /* 5090edf2c54Smickey * Stage 3: The worst case. I need configuration hint that 5100edf2c54Smickey * user supplied a mask for the PCI irqs 5116661564bSmickey */ 5120edf2c54Smickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; 5130edf2c54Smickey l = SIMPLEQ_NEXT(l, list)) { 51464f0e01bSmickey if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION && 51564f0e01bSmickey (irq = ffs(l->bitmap & pcibios_irqs_hint)) > 0) { 5160edf2c54Smickey l->fixup_stage = 3; 51764f0e01bSmickey l->irq = irq - 1; 51864f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 5190edf2c54Smickey printf("pciintr_link_fixup (stage 3): " 5200edf2c54Smickey "assigning IRQ %d to PIRQ 0x%02x\n", 5210edf2c54Smickey l->irq, l->clink); 5220edf2c54Smickey } 5230edf2c54Smickey } 5240edf2c54Smickey #endif /* PCIBIOS_IRQS_HINT */ 5256661564bSmickey 52664f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 52764f0e01bSmickey printf("pciintr_link_fixup: piirq 0x%04x\n", pciirq); 52864f0e01bSmickey 5296661564bSmickey return (0); 5306661564bSmickey } 5316661564bSmickey 5326661564bSmickey int 53364f0e01bSmickey pci_intr_route_link(pc, ihp) 53464f0e01bSmickey pci_chipset_tag_t pc; 53564f0e01bSmickey pci_intr_handle_t *ihp; 5366661564bSmickey { 5376661564bSmickey struct pciintr_link_map *l; 53864f0e01bSmickey pcireg_t intr; 539*a25c7806Smickey int irq, rv = 1; 54064f0e01bSmickey char *p = NULL; 5416661564bSmickey 5428b0f2e63Smickey if (pcibios_flags & PCIBIOS_INTR_FIXUP) 5438b0f2e63Smickey return 1; 5448b0f2e63Smickey 545*a25c7806Smickey irq = ihp->line & APIC_INT_LINE_MASK; 546*a25c7806Smickey if (irq != 0 && irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) 547*a25c7806Smickey pcibios_pir_header.exclusive_irq |= 1 << irq; 548ff51c22aSmickey 54964f0e01bSmickey l = ihp->link; 55064f0e01bSmickey if (!l || pciintr_icu_tag == NULL) 55164f0e01bSmickey return (1); 5526661564bSmickey 5530edf2c54Smickey if (l->fixup_stage == 0) { 5540edf2c54Smickey if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 5550edf2c54Smickey /* Appropriate interrupt was not found. */ 55664f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 55764f0e01bSmickey printf("pci_intr_route_link: PIRQ 0x%02x: " 55864f0e01bSmickey "no IRQ, try " 55964f0e01bSmickey "\"option PCIBIOS_IRQS_HINT=0x%04x\"\n", 5600edf2c54Smickey l->clink, 5610edf2c54Smickey /* suggest irq 9/10/11, if possible */ 5620edf2c54Smickey (l->bitmap & 0x0e00) ? (l->bitmap & 0x0e00) 5630edf2c54Smickey : l->bitmap); 56464f0e01bSmickey } else 56564f0e01bSmickey p = " preserved BIOS setting"; 5660edf2c54Smickey } else { 5670edf2c54Smickey 5686661564bSmickey if (pciintr_icu_set_intr(pciintr_icu_tag, pciintr_icu_handle, 5696661564bSmickey l->clink, l->irq) != 0 || 57064f0e01bSmickey pciintr_icu_set_trigger(pciintr_icu_tag, pciintr_icu_handle, 5716661564bSmickey l->irq, IST_LEVEL) != 0) { 57264f0e01bSmickey p = " failed"; 57364f0e01bSmickey rv = 0; 57464f0e01bSmickey } else 57564f0e01bSmickey p = ""; 5766661564bSmickey } 57764f0e01bSmickey if (p && pcibios_flags & PCIBIOS_INTRDEBUG) 57864f0e01bSmickey printf("pci_intr_route_link: route PIRQ 0x%02x -> IRQ %d%s\n", 57964f0e01bSmickey l->clink, l->irq, p); 5806661564bSmickey 58164f0e01bSmickey if (!rv) 5826661564bSmickey return (0); 5830edf2c54Smickey 5846661564bSmickey /* 5850edf2c54Smickey * IRQs 14 and 15 are reserved for PCI IDE interrupts; don't muck 5866661564bSmickey * with them. 5876661564bSmickey */ 588*a25c7806Smickey if (irq == 14 || irq == 15) 58964f0e01bSmickey return (1); 59064f0e01bSmickey 59164f0e01bSmickey intr = pci_conf_read(pc, ihp->tag, PCI_INTERRUPT_REG); 592*a25c7806Smickey if (irq != PCI_INTERRUPT_LINE(intr)) { 59364f0e01bSmickey intr &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT); 594*a25c7806Smickey intr |= irq << PCI_INTERRUPT_LINE_SHIFT; 59564f0e01bSmickey pci_conf_write(pc, ihp->tag, PCI_INTERRUPT_REG, intr); 5960edf2c54Smickey } 5976661564bSmickey 59864f0e01bSmickey return (1); 59964f0e01bSmickey } 60064f0e01bSmickey 60164f0e01bSmickey int 60264f0e01bSmickey pci_intr_post_fixup() 60364f0e01bSmickey { 60464f0e01bSmickey struct pciintr_link_map *l; 60564f0e01bSmickey int i, pciirq; 60664f0e01bSmickey 6078b0f2e63Smickey if (pcibios_flags & PCIBIOS_INTR_FIXUP) 6088b0f2e63Smickey return 1; 6098b0f2e63Smickey 61064f0e01bSmickey if (!pciintr_icu_handle) 61164f0e01bSmickey return 0; 61264f0e01bSmickey 61364f0e01bSmickey pciirq = pcibios_pir_header.exclusive_irq; 61464f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 61564f0e01bSmickey printf("pci_intr_post_fixup: PCI IRQs:"); 61664f0e01bSmickey for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); 61764f0e01bSmickey l != NULL; l = SIMPLEQ_NEXT(l, list)) 618ff51c22aSmickey if (l->fixup_stage == 0 && l->irq != 0 && 61964f0e01bSmickey l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 62064f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 62164f0e01bSmickey printf(" %d", l->irq); 62264f0e01bSmickey pciirq |= (1 << l->irq); 62364f0e01bSmickey } 62464f0e01bSmickey 62564f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 62664f0e01bSmickey printf("; ISA IRQs:"); 62764f0e01bSmickey for (i = 0; i < 16; i++) 62864f0e01bSmickey if (!(pciirq & (1 << i))) { 62964f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 63064f0e01bSmickey printf(" %d", i); 63164f0e01bSmickey pciintr_icu_set_trigger(pciintr_icu_tag, 63264f0e01bSmickey pciintr_icu_handle, i, IST_EDGE); 63364f0e01bSmickey } 63464f0e01bSmickey 63564f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 63664f0e01bSmickey printf("\n"); 63764f0e01bSmickey 63864f0e01bSmickey return (0); 63964f0e01bSmickey } 64064f0e01bSmickey 64164f0e01bSmickey int 64264f0e01bSmickey pci_intr_header_fixup(pc, tag, ihp) 64364f0e01bSmickey pci_chipset_tag_t pc; 64464f0e01bSmickey pcitag_t tag; 64564f0e01bSmickey pci_intr_handle_t *ihp; 64664f0e01bSmickey { 64764f0e01bSmickey struct pcibios_intr_routing *pir; 64864f0e01bSmickey struct pciintr_link_map *l; 64964f0e01bSmickey int irq, link, bus, device, function; 65064f0e01bSmickey char *p = NULL; 65164f0e01bSmickey 6528b0f2e63Smickey if (pcibios_flags & PCIBIOS_INTR_FIXUP) 6538b0f2e63Smickey return 1; 6548b0f2e63Smickey 655*a25c7806Smickey irq = ihp->line & APIC_INT_LINE_MASK; 65664f0e01bSmickey ihp->link = NULL; 65764f0e01bSmickey ihp->tag = tag; 65864f0e01bSmickey pci_decompose_tag(pc, tag, &bus, &device, &function); 65964f0e01bSmickey 66064f0e01bSmickey if ((pir = pciintr_pir_lookup(bus, device)) == NULL || 66164f0e01bSmickey (link = pir->linkmap[ihp->pin - 1].link) == 0) { 66264f0e01bSmickey PCIBIOS_PRINTV(("Interrupt not connected; no need to change.")); 66364f0e01bSmickey return 1; 66464f0e01bSmickey } 66564f0e01bSmickey 66664f0e01bSmickey if ((l = pciintr_link_lookup(link)) == NULL) { 66764f0e01bSmickey /* 66864f0e01bSmickey * No link map entry. 66964f0e01bSmickey * Probably pciintr_icu_getclink() or pciintr_icu_get_intr() 670*a25c7806Smickey * has failed. 67164f0e01bSmickey */ 67264f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) 67364f0e01bSmickey printf("pci_intr_header_fixup: no entry for link " 67464f0e01bSmickey "0x%02x (%d:%d:%d:%c)\n", 67564f0e01bSmickey link, bus, device, function, '@' + ihp->pin); 67664f0e01bSmickey return 1; 67764f0e01bSmickey } 67864f0e01bSmickey 6791120a2ccSmarkus ihp->link = l; 6801120a2ccSmarkus if (irq == 14 || irq == 15) { 68164f0e01bSmickey p = " WARNING: ignored"; 6821120a2ccSmarkus ihp->link = NULL; 6831120a2ccSmarkus } else if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 68464f0e01bSmickey 6850edf2c54Smickey /* Appropriate interrupt was not found. */ 686*a25c7806Smickey if (pciintr_icu_tag == NULL && irq != 0 && 687*a25c7806Smickey irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) 688b25264e3Smickey /* 689b25264e3Smickey * Do not print warning, 690b25264e3Smickey * if no compatible PCI ICU found, 691b25264e3Smickey * but the irq is already assigned by BIOS. 692b25264e3Smickey */ 69364f0e01bSmickey p = ""; 69464f0e01bSmickey else 69564f0e01bSmickey p = " WARNING: missing"; 69664f0e01bSmickey } else if (irq == 0 || irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { 6970edf2c54Smickey 69864f0e01bSmickey p = " fixed up"; 699*a25c7806Smickey ihp->line = irq = l->irq; 7000edf2c54Smickey 701a003464cSmickey } else if (pcibios_flags & PCIBIOS_FIXUP_FORCE) { 7020edf2c54Smickey /* routed by BIOS, but inconsistent */ 7030edf2c54Smickey /* believe PCI IRQ Routing table */ 70464f0e01bSmickey p = " WARNING: overriding"; 705*a25c7806Smickey ihp->line = irq = l->irq; 70678b5d43cSmickey } else { 7070edf2c54Smickey /* believe PCI Interrupt Configuration Register (default) */ 70864f0e01bSmickey p = " WARNING: preserving"; 709*a25c7806Smickey ihp->line = (l->irq = irq) | (l->clink & PCI_INT_VIA_ISA); 71078b5d43cSmickey } 7116661564bSmickey 71264f0e01bSmickey if (pcibios_flags & PCIBIOS_INTRDEBUG) { 71364f0e01bSmickey register pcireg_t id = pci_conf_read(pc, tag, PCI_ID_REG); 71464f0e01bSmickey 71578b5d43cSmickey printf("\n%d:%d:%d %04x:%04x pin %c clink 0x%02x irq %d " 71678b5d43cSmickey "stage %d %s irq %d\n", bus, device, function, 71764f0e01bSmickey PCI_VENDOR(id), PCI_PRODUCT(id), '@' + ihp->pin, l->clink, 71864f0e01bSmickey ((l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION)? 71964f0e01bSmickey -1 : l->irq), l->fixup_stage, p, irq); 72064f0e01bSmickey } 72164f0e01bSmickey 72264f0e01bSmickey return (1); 7236661564bSmickey } 7246661564bSmickey 7256661564bSmickey int 726df73a7d0Smickey pci_intr_fixup(sc, pc, iot) 727df73a7d0Smickey struct pcibios_softc *sc; 7286661564bSmickey pci_chipset_tag_t pc; 7296661564bSmickey bus_space_tag_t iot; 7306661564bSmickey { 731df73a7d0Smickey struct pcibios_pir_header *pirh = &pcibios_pir_header; 7326661564bSmickey const struct pciintr_icu_table *piit = NULL; 7336661564bSmickey pcitag_t icutag; 7346661564bSmickey 7356661564bSmickey /* 7366661564bSmickey * Attempt to initialize our PCI interrupt router. If 7376661564bSmickey * the PIR Table is present in ROM, use the location 7386661564bSmickey * specified by the PIR Table, and use the compat ID, 7396661564bSmickey * if present. Otherwise, we have to look for the router 7406661564bSmickey * ourselves (the PCI-ISA bridge). 741911088d6Smickey * 742911088d6Smickey * A number of buggy BIOS implementations leave the router 743911088d6Smickey * entry as 000:00:0, which is typically not the correct 744911088d6Smickey * device/function. If the router device address is set to 745911088d6Smickey * this value, and the compatible router entry is undefined 746911088d6Smickey * (zero is the correct value to indicate undefined), then we 747911088d6Smickey * work on the basis it is most likely an error, and search 748911088d6Smickey * the entire device-space of bus 0 (but obviously starting 749911088d6Smickey * with 000:00:0, in case that really is the right one). 7506661564bSmickey */ 751911088d6Smickey if (pirh->signature != 0 && (pirh->router_bus != 0 || 752911088d6Smickey pirh->router_devfunc != 0 || pirh->compat_router != 0)) { 753911088d6Smickey 7546c0a4d12Smickey icutag = pci_make_tag(pc, pirh->router_bus, 7556c0a4d12Smickey PIR_DEVFUNC_DEVICE(pirh->router_devfunc), 7566c0a4d12Smickey PIR_DEVFUNC_FUNCTION(pirh->router_devfunc)); 757911088d6Smickey if (pirh->compat_router == 0 || 758911088d6Smickey (piit = pciintr_icu_lookup(pirh->compat_router)) == NULL) { 7596661564bSmickey /* 7606661564bSmickey * No compat ID, or don't know the compat ID? Read 7616661564bSmickey * it from the configuration header. 7626661564bSmickey */ 7636c0a4d12Smickey pirh->compat_router = pci_conf_read(pc, icutag, 764911088d6Smickey PCI_ID_REG); 7656661564bSmickey } 7666661564bSmickey if (piit == NULL) 767911088d6Smickey piit = pciintr_icu_lookup(pirh->compat_router); 7686661564bSmickey } else { 7696661564bSmickey int device, maxdevs = pci_bus_maxdevs(pc, 0); 7706661564bSmickey 7716661564bSmickey /* 7726661564bSmickey * Search configuration space for a known interrupt 7736661564bSmickey * router. 7746661564bSmickey */ 7756661564bSmickey for (device = 0; device < maxdevs; device++) { 776911088d6Smickey const struct pci_quirkdata *qd; 777911088d6Smickey int function, nfuncs; 778911088d6Smickey pcireg_t icuid; 779911088d6Smickey pcireg_t bhlcr; 780911088d6Smickey 7816661564bSmickey icutag = pci_make_tag(pc, 0, device, 0); 7826661564bSmickey icuid = pci_conf_read(pc, icutag, PCI_ID_REG); 7836661564bSmickey 7846661564bSmickey /* Invalid vendor ID value? */ 7856661564bSmickey if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID) 7866661564bSmickey continue; 7876661564bSmickey /* XXX Not invalid, but we've done this ~forever. */ 7886661564bSmickey if (PCI_VENDOR(icuid) == 0) 7896661564bSmickey continue; 7906661564bSmickey 791911088d6Smickey qd = pci_lookup_quirkdata(PCI_VENDOR(icuid), 792911088d6Smickey PCI_PRODUCT(icuid)); 793911088d6Smickey 794911088d6Smickey bhlcr = pci_conf_read(pc, icutag, PCI_BHLC_REG); 795911088d6Smickey if (PCI_HDRTYPE_MULTIFN(bhlcr) || (qd != NULL && 796911088d6Smickey (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0)) 797911088d6Smickey nfuncs = 8; 798911088d6Smickey else 799911088d6Smickey nfuncs = 1; 800911088d6Smickey 801911088d6Smickey for (function = 0; function < nfuncs; function++) { 802911088d6Smickey icutag = pci_make_tag(pc, 0, device, function); 803911088d6Smickey icuid = pci_conf_read(pc, icutag, PCI_ID_REG); 804911088d6Smickey 805911088d6Smickey /* Invalid vendor ID value? */ 806911088d6Smickey if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID) 807911088d6Smickey continue; 808911088d6Smickey /* Not invalid, but we've done this ~forever. */ 809911088d6Smickey if (PCI_VENDOR(icuid) == 0) 810911088d6Smickey continue; 811911088d6Smickey 812df73a7d0Smickey if ((piit = pciintr_icu_lookup(icuid))) { 813df73a7d0Smickey pirh->compat_router = icuid; 814df73a7d0Smickey pirh->router_bus = 0; 815df73a7d0Smickey pirh->router_devfunc = 816df73a7d0Smickey PIR_DEVFUNC_COMPOSE(device, 0); 8176661564bSmickey break; 8186661564bSmickey } 8196661564bSmickey } 820911088d6Smickey 821911088d6Smickey if (piit != NULL) 822911088d6Smickey break; 823911088d6Smickey } 824df73a7d0Smickey } 8256661564bSmickey 8266661564bSmickey if (piit == NULL) { 827df73a7d0Smickey printf("%s: no compatible PCI ICU found", sc->sc_dev.dv_xname); 828911088d6Smickey if (pirh->signature != 0 && pirh->compat_router != 0) 829b25264e3Smickey printf(": ICU vendor 0x%04x product 0x%04x", 830911088d6Smickey PCI_VENDOR(pirh->compat_router), 831911088d6Smickey PCI_PRODUCT(pirh->compat_router)); 832b25264e3Smickey printf("\n"); 833b25264e3Smickey if (!(pcibios_flags & PCIBIOS_INTR_GUESS)) { 83464f0e01bSmickey if (pciintr_link_init(pc)) 835b25264e3Smickey return (-1); /* non-fatal */ 836b25264e3Smickey if (pciintr_guess_irq()) 837b25264e3Smickey return (-1); /* non-fatal */ 838bb701a32Smickey } 839bb701a32Smickey return (0); 840df73a7d0Smickey } else { 841df73a7d0Smickey char devinfo[256]; 842df73a7d0Smickey 843df73a7d0Smickey printf("%s: PCI Interrupt Router at %03d:%02d:%01d", 844df73a7d0Smickey sc->sc_dev.dv_xname, pirh->router_bus, 845df73a7d0Smickey PIR_DEVFUNC_DEVICE(pirh->router_devfunc), 846df73a7d0Smickey PIR_DEVFUNC_FUNCTION(pirh->router_devfunc)); 847df73a7d0Smickey if (pirh->compat_router != 0) { 8482627362dSho pci_devinfo(pirh->compat_router, 0, 0, devinfo, 8492627362dSho sizeof devinfo); 850df73a7d0Smickey printf(" (%s)", devinfo); 851df73a7d0Smickey } 852df73a7d0Smickey printf("\n"); 8536661564bSmickey } 8546661564bSmickey 8556661564bSmickey /* 8566661564bSmickey * Initialize the PCI ICU. 8576661564bSmickey */ 8586661564bSmickey if ((*piit->piit_init)(pc, iot, icutag, &pciintr_icu_tag, 8596661564bSmickey &pciintr_icu_handle) != 0) 8606661564bSmickey return (-1); /* non-fatal */ 8616661564bSmickey 8626661564bSmickey /* 8636661564bSmickey * Initialize the PCI interrupt link map. 8646661564bSmickey */ 86564f0e01bSmickey if (pciintr_link_init(pc)) 8666661564bSmickey return (-1); /* non-fatal */ 8676661564bSmickey 8686661564bSmickey /* 8696661564bSmickey * Fix up the link->IRQ mappings. 8706661564bSmickey */ 8716661564bSmickey if (pciintr_link_fixup() != 0) 8726661564bSmickey return (-1); /* non-fatal */ 8736661564bSmickey 87464f0e01bSmickey return (0); 8756661564bSmickey } 876