diff options
author | Michael Shalayeff <mickey@cvs.openbsd.org> | 2001-01-27 04:59:41 +0000 |
---|---|---|
committer | Michael Shalayeff <mickey@cvs.openbsd.org> | 2001-01-27 04:59:41 +0000 |
commit | 5c57fe9fedb6369715d919d0344f713e6fb24bbb (patch) | |
tree | e0c60f0edcd71325f7e72c710edff8dad38ee6d0 /sys/arch/i386/pci | |
parent | 3c7b4c90f16918cee171cdce87a4fd2caba5078b (diff) |
change interrupt routing strategy from simple
run through the devices and programming the icu
and pci headers before real pci bus autoconf starts
and include all devices present on all pci busses,
to a per attached device routing in pci_intr_map().
this solves several cases of premature interrupts hanging
system due to absent interrupt handlers during autoconf.
10x for testing: millert@ krw@ aaron@ chris@ tholo@ brad@ jason@ deraadt@
Diffstat (limited to 'sys/arch/i386/pci')
-rw-r--r-- | sys/arch/i386/pci/pci_addr_fixup.c | 156 | ||||
-rw-r--r-- | sys/arch/i386/pci/pci_bus_fixup.c | 21 | ||||
-rw-r--r-- | sys/arch/i386/pci/pci_intr_fixup.c | 511 | ||||
-rw-r--r-- | sys/arch/i386/pci/pci_machdep.c | 39 | ||||
-rw-r--r-- | sys/arch/i386/pci/pci_machdep.h | 10 | ||||
-rw-r--r-- | sys/arch/i386/pci/pcib.c | 10 | ||||
-rw-r--r-- | sys/arch/i386/pci/pcibios.c | 65 | ||||
-rw-r--r-- | sys/arch/i386/pci/pcibiosvar.h | 81 |
8 files changed, 410 insertions, 483 deletions
diff --git a/sys/arch/i386/pci/pci_addr_fixup.c b/sys/arch/i386/pci/pci_addr_fixup.c index 71afb374439..66f4324a0e4 100644 --- a/sys/arch/i386/pci/pci_addr_fixup.c +++ b/sys/arch/i386/pci/pci_addr_fixup.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pci_addr_fixup.c,v 1.7 2001/01/25 01:00:58 mickey Exp $ */ +/* $OpenBSD: pci_addr_fixup.c,v 1.8 2001/01/27 04:59:39 mickey Exp $ */ /* $NetBSD: pci_addr_fixup.c,v 1.7 2000/08/03 20:10:45 nathanw Exp $ */ /*- @@ -42,21 +42,21 @@ #include <i386/pci/pcibiosvar.h> -struct pciaddr pciaddr; - typedef int (*pciaddr_resource_manage_func_t) - (pci_chipset_tag_t, pcitag_t, int, struct extent *, int, - bus_addr_t *, bus_size_t); -void pciaddr_resource_manage __P((pci_chipset_tag_t, pcitag_t, - pciaddr_resource_manage_func_t)); -void pciaddr_resource_reserve __P((pci_chipset_tag_t, pcitag_t)); -int pciaddr_do_resource_reserve __P((pci_chipset_tag_t, pcitag_t, int, - struct extent *, int, bus_addr_t *, - bus_size_t)); -void pciaddr_resource_allocate __P((pci_chipset_tag_t, pcitag_t)); -int pciaddr_do_resource_allocate __P((pci_chipset_tag_t, pcitag_t, int, - struct extent *, int, bus_addr_t *, - bus_size_t)); + __P((struct pcibios_softc *, pci_chipset_tag_t, pcitag_t, int, + struct extent *, int, bus_addr_t *, bus_size_t)); +void pciaddr_resource_manage __P((struct pcibios_softc *, + pci_chipset_tag_t, pcitag_t, pciaddr_resource_manage_func_t)); +void pciaddr_resource_reserve __P((struct pcibios_softc *, + pci_chipset_tag_t, pcitag_t)); +int pciaddr_do_resource_reserve __P((struct pcibios_softc *, + pci_chipset_tag_t, pcitag_t, int, struct extent *, int, + bus_addr_t *, bus_size_t)); +void pciaddr_resource_allocate __P((struct pcibios_softc *, + pci_chipset_tag_t, pcitag_t)); +int pciaddr_do_resource_allocate __P((struct pcibios_softc *, + pci_chipset_tag_t, pcitag_t, int, struct extent *, int, bus_addr_t *, + bus_size_t)); bus_addr_t pciaddr_ioaddr __P((u_int32_t)); void pciaddr_print_devid __P((pci_chipset_tag_t, pcitag_t)); @@ -70,12 +70,12 @@ void pciaddr_print_devid __P((pci_chipset_tag_t, pcitag_t)); #define PCIADDR_ISAMEM_RESERVE (16 * 1024 * 1024) void -pci_addr_fixup(pc, maxbus) +pci_addr_fixup(sc, pc, maxbus) + struct pcibios_softc *sc; pci_chipset_tag_t pc; int maxbus; { extern paddr_t avail_end; -#ifdef PCIBIOSVERBOSE const char *verbose_header = "[%s]-----------------------\n" " device vendor product\n" @@ -83,7 +83,7 @@ pci_addr_fixup(pc, maxbus) "--------------------------------------------\n"; const char *verbose_footer = "--------------------------[%3d devices bogus]\n"; -#endif + const struct { bus_addr_t start; bus_size_t size; @@ -97,35 +97,29 @@ pci_addr_fixup(pc, maxbus) paddr_t start; int error; - pciaddr.extent_mem = extent_create("PCI I/O memory space", - PCIADDR_MEM_START, - PCIADDR_MEM_END, - M_DEVBUF, 0, 0, EX_NOWAIT); - KASSERT(pciaddr.extent_mem); - pciaddr.extent_port = extent_create("PCI I/O port space", - PCIADDR_PORT_START, - PCIADDR_PORT_END, - M_DEVBUF, 0, 0, EX_NOWAIT); - KASSERT(pciaddr.extent_port); + sc->extent_mem = extent_create("PCI I/O memory space", + PCIADDR_MEM_START, PCIADDR_MEM_END, M_DEVBUF, 0, 0, EX_NOWAIT); + KASSERT(sc->extent_mem); + sc->extent_port = extent_create("PCI I/O port space", + PCIADDR_PORT_START, PCIADDR_PORT_END, M_DEVBUF, 0, 0, EX_NOWAIT); + KASSERT(sc->extent_port); /* * 1. check & reserve system BIOS setting. */ PCIBIOS_PRINTV((verbose_header, "System BIOS Setting")); - pci_device_foreach(pc, maxbus, pciaddr_resource_reserve); - PCIBIOS_PRINTV((verbose_footer, pciaddr.nbogus)); + pci_device_foreach(sc, pc, maxbus, pciaddr_resource_reserve); + PCIBIOS_PRINTV((verbose_footer, sc->nbogus)); /* * 2. reserve non-PCI area. */ for (srp = system_reserve; srp->size; srp++) { - error = extent_alloc_region(pciaddr.extent_mem, srp->start, - srp->size, - EX_NOWAIT| EX_MALLOCOK); - if (error != 0) { + error = extent_alloc_region(sc->extent_mem, srp->start, + srp->size, EX_NOWAIT| EX_MALLOCOK); + if (error != 0) printf("WARNING: can't reserve area for %s.\n", srp->name); - } } /* @@ -134,52 +128,49 @@ pci_addr_fixup(pc, maxbus) start = i386_round_page(avail_end + 1); if (start < PCIADDR_ISAMEM_RESERVE) start = PCIADDR_ISAMEM_RESERVE; - pciaddr.mem_alloc_start = (start + 0x100000 + 1) & ~(0x100000 - 1); - pciaddr.port_alloc_start = PCIADDR_ISAPORT_RESERVE; + sc->mem_alloc_start = (start + 0x100000 + 1) & ~(0x100000 - 1); + sc->port_alloc_start = PCIADDR_ISAPORT_RESERVE; PCIBIOS_PRINTV((" Physical memory end: 0x%08x\n PCI memory mapped I/O " - "space start: 0x%08x\n", (unsigned)avail_end, - (unsigned)pciaddr.mem_alloc_start)); + "space start: 0x%08x\n", avail_end, sc->mem_alloc_start)); - if (pciaddr.nbogus == 0) + if (sc->nbogus == 0) return; /* no need to fixup */ /* * 4. do fixup */ PCIBIOS_PRINTV((verbose_header, "PCIBIOS fixup stage")); - pciaddr.nbogus = 0; - /* XXX bus #0 only */ - pci_device_foreach(pc, 0, pciaddr_resource_allocate); - PCIBIOS_PRINTV((verbose_footer, pciaddr.nbogus)); + sc->nbogus = 0; + pci_device_foreach(sc, pc, maxbus, pciaddr_resource_allocate); + PCIBIOS_PRINTV((verbose_footer, sc->nbogus)); } void -pciaddr_resource_reserve(pc, tag) +pciaddr_resource_reserve(sc, pc, tag) + struct pcibios_softc *sc; pci_chipset_tag_t pc; pcitag_t tag; { -#ifdef PCIBIOSVERBOSE - if (pcibiosverbose) + if (pcibios_flags & PCIBIOS_VERBOSE) pciaddr_print_devid(pc, tag); -#endif - pciaddr_resource_manage(pc, tag, pciaddr_do_resource_reserve); + pciaddr_resource_manage(sc, pc, tag, pciaddr_do_resource_reserve); } void -pciaddr_resource_allocate(pc, tag) +pciaddr_resource_allocate(sc, pc, tag) + struct pcibios_softc *sc; pci_chipset_tag_t pc; pcitag_t tag; { -#ifdef PCIBIOSVERBOSE - if (pcibiosverbose) + if (pcibios_flags & PCIBIOS_VERBOSE) pciaddr_print_devid(pc, tag); -#endif - pciaddr_resource_manage(pc, tag, pciaddr_do_resource_allocate); + pciaddr_resource_manage(sc, pc, tag, pciaddr_do_resource_allocate); } void -pciaddr_resource_manage(pc, tag, func) +pciaddr_resource_manage(sc, pc, tag, func) + struct pcibios_softc *sc; pci_chipset_tag_t pc; pcitag_t tag; pciaddr_resource_manage_func_t func; @@ -188,13 +179,13 @@ pciaddr_resource_manage(pc, tag, func) pcireg_t val, mask; bus_addr_t addr; bus_size_t size; - int error, useport, usemem, mapreg, type, reg_start, reg_end, width; + int error, mapreg, type, reg_start, reg_end, width; val = pci_conf_read(pc, tag, PCI_BHLC_REG); switch (PCI_HDRTYPE_TYPE(val)) { default: printf("WARNING: unknown PCI device header."); - pciaddr.nbogus++; + sc->nbogus++; return; case 0: reg_start = PCI_MAPREG_START; @@ -209,7 +200,7 @@ pciaddr_resource_manage(pc, tag, func) reg_end = PCI_MAPREG_PCB_END; break; } - error = useport = usemem = 0; + error = 0; for (mapreg = reg_start; mapreg < reg_end; mapreg += width) { /* inquire PCI device bus space requirement */ @@ -235,24 +226,21 @@ pciaddr_resource_manage(pc, tag, func) */ width = 8; } + addr = PCI_MAPREG_MEM_ADDR(val); size = PCI_MAPREG_MEM_SIZE(mask); - ex = pciaddr.extent_mem; + ex = sc->extent_mem; } else { + /* XXX some devices give 32bit value */ + addr = PCI_MAPREG_IO_ADDR(val) & PCIADDR_PORT_END; size = PCI_MAPREG_IO_SIZE(mask); - ex = pciaddr.extent_port; + ex = sc->extent_port; } - addr = pciaddr_ioaddr(val); if (!size) /* unused register */ continue; - if (type == PCI_MAPREG_TYPE_MEM) - ++usemem; - else - ++useport; - /* reservation/allocation phase */ - error += (*func) (pc, tag, mapreg, ex, type, &addr, size); + error += (*func) (sc, pc, tag, mapreg, ex, type, &addr, size); PCIBIOS_PRINTV(("\t%02xh %s 0x%08x 0x%08x\n", mapreg, type ? "port" : "mem ", @@ -270,13 +258,14 @@ pciaddr_resource_manage(pc, tag, func) pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, val); if (error) - pciaddr.nbogus++; + sc->nbogus++; PCIBIOS_PRINTV(("\t\t[%s]\n", error ? "NG" : "OK")); } int -pciaddr_do_resource_allocate(pc, tag, mapreg, ex, type, addr, size) +pciaddr_do_resource_allocate(sc, pc, tag, mapreg, ex, type, addr, size) + struct pcibios_softc *sc; pci_chipset_tag_t pc; pcitag_t tag; struct extent *ex; @@ -290,8 +279,8 @@ pciaddr_do_resource_allocate(pc, tag, mapreg, ex, type, addr, size) if (*addr) /* no need to allocate */ return (0); - start = type == PCI_MAPREG_TYPE_MEM ? pciaddr.mem_alloc_start - : pciaddr.port_alloc_start; + start = (type == PCI_MAPREG_TYPE_MEM ? sc->mem_alloc_start + : sc->port_alloc_start); if (start < ex->ex_start || start + size - 1 >= ex->ex_end) { PCIBIOS_PRINTV(("No available resources. fixup failed\n")); return (1); @@ -306,9 +295,7 @@ pciaddr_do_resource_allocate(pc, tag, mapreg, ex, type, addr, size) /* write new address to PCI device configuration header */ pci_conf_write(pc, tag, mapreg, *addr); /* check */ -#ifdef PCIBIOSVERBOSE - if (!pcibiosverbose) -#endif + if (!pcibios_flags & PCIBIOS_VERBOSE) { printf("pci_addr_fixup: "); pciaddr_print_devid(pc, tag); @@ -316,19 +303,18 @@ pciaddr_do_resource_allocate(pc, tag, mapreg, ex, type, addr, size) if (pciaddr_ioaddr(pci_conf_read(pc, tag, mapreg)) != *addr) { pci_conf_write(pc, tag, mapreg, 0); /* clear */ - printf("fixup failed. (new address=%#x)\n", (unsigned)*addr); + printf("fixup failed. (new address=%#x)\n", *addr); return (1); } -#ifdef PCIBIOSVERBOSE - if (!pcibiosverbose) -#endif + if (!pcibios_flags & PCIBIOS_VERBOSE) printf("new address 0x%08x\n", *addr); return (0); } int -pciaddr_do_resource_reserve(pc, tag, mapreg, ex, type, addr, size) +pciaddr_do_resource_reserve(sc, pc, tag, mapreg, ex, type, addr, size) + struct pcibios_softc *sc; pci_chipset_tag_t pc; pcitag_t tag; struct extent *ex; @@ -357,7 +343,7 @@ pciaddr_ioaddr(val) { return ((PCI_MAPREG_TYPE(val) == PCI_MAPREG_TYPE_MEM) ? PCI_MAPREG_MEM_ADDR(val) - : PCI_MAPREG_IO_ADDR(val)); + : (PCI_MAPREG_IO_ADDR(val) & PCIADDR_PORT_END)); } void @@ -370,7 +356,7 @@ pciaddr_print_devid(pc, tag) id = pci_conf_read(pc, tag, PCI_ID_REG); pci_decompose_tag(pc, tag, &bus, &device, &function); - printf("%03d:%02d:%d 0x%04x 0x%04x ", bus, device, function, + printf("%03d:%02d:%d %04x:%04x\n", bus, device, function, PCI_VENDOR(id), PCI_PRODUCT(id)); } @@ -380,10 +366,14 @@ pciaddr_search(mem_port, startp, size) bus_addr_t *startp; bus_size_t size; { + extern struct cfdriver pcibios_cd; + struct pcibios_softc *sc; + + sc = pcibios_cd.cd_devs[0]; + if (!(pcibios_flags & PCIBIOS_ADDR_FIXUP)) { struct extent_region *rp; - struct extent *ex = mem_port? - pciaddr.extent_mem : pciaddr.extent_port; + struct extent *ex = mem_port? sc->extent_mem : sc->extent_port; /* Search the PCI I/O memory space extent for free * space that will accomodate size. Remember that the diff --git a/sys/arch/i386/pci/pci_bus_fixup.c b/sys/arch/i386/pci/pci_bus_fixup.c index 965ce6dc28a..80e4579cd35 100644 --- a/sys/arch/i386/pci/pci_bus_fixup.c +++ b/sys/arch/i386/pci/pci_bus_fixup.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pci_bus_fixup.c,v 1.7 2001/01/24 23:16:14 mickey Exp $ */ +/* $OpenBSD: pci_bus_fixup.c,v 1.8 2001/01/27 04:59:40 mickey Exp $ */ /* $NetBSD: pci_bus_fixup.c,v 1.1 1999/11/17 07:32:58 thorpej Exp $ */ /* @@ -49,11 +49,8 @@ pci_bus_fixup(pc, bus) pci_chipset_tag_t pc; int bus; { -#ifdef PCIBIOSVERBOSE static int bridge_cnt; - int bridge; -#endif - int device, maxdevs, function, nfuncs, bus_max, bus_sub; + int bridge, device, maxdevs, function, nfuncs, bus_max, bus_sub; const struct pci_quirkdata *qd; pcireg_t reg; pcitag_t tag; @@ -119,14 +116,14 @@ pci_bus_fixup(pc, bus) reg |= bus | (bus_max << 8) | (bus_sub << 16); pci_conf_write(pc, tag, PPB_REG_BUSINFO, reg); -#ifdef PCIBIOSVERBOSE - /* Assign the bridge #. */ - bridge = bridge_cnt++; + if (pcibios_flags & PCIBIOS_VERBOSE) { + /* Assign the bridge #. */ + bridge = bridge_cnt++; - printf("PCI bridge %d: primary %d, " - "secondary %d, subordinate %d\n", - bridge, bus, bus_max, bus_sub); -#endif + printf("PCI bridge %d: primary %d, " + "secondary %d, subordinate %d\n", + bridge, bus, bus_max, bus_sub); + } /* Next bridge's secondary bus #. */ bus_max = (bus_sub > bus_max) ? diff --git a/sys/arch/i386/pci/pci_intr_fixup.c b/sys/arch/i386/pci/pci_intr_fixup.c index 4a9bc997305..dd5c6b26760 100644 --- a/sys/arch/i386/pci/pci_intr_fixup.c +++ b/sys/arch/i386/pci/pci_intr_fixup.c @@ -1,6 +1,36 @@ -/* $OpenBSD: pci_intr_fixup.c,v 1.11 2001/01/25 00:07:40 mickey Exp $ */ +/* $OpenBSD: pci_intr_fixup.c,v 1.12 2001/01/27 04:59:40 mickey Exp $ */ /* $NetBSD: pci_intr_fixup.c,v 1.10 2000/08/10 21:18:27 soda Exp $ */ +/* + * Copyright (c) 2001 Michael Shalayeff + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Michael Shalayeff. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. * All rights reserved. @@ -37,7 +67,6 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ - /* * Copyright (c) 1999, by UCHIYAMA Yasushi * All rights reserved. @@ -85,11 +114,8 @@ #include <i386/pci/pcibiosvar.h> struct pciintr_link_map { - int link; - int clink; - int irq; + int link, clink, irq, fixup_stage; u_int16_t bitmap; - int fixup_stage; SIMPLEQ_ENTRY(pciintr_link_map) list; }; @@ -101,18 +127,8 @@ int pcibios_irqs_hint = PCIBIOS_IRQS_HINT; #endif struct pciintr_link_map *pciintr_link_lookup __P((int)); -struct pciintr_link_map *pciintr_link_alloc __P((struct pcibios_intr_routing *, - int)); struct pcibios_intr_routing *pciintr_pir_lookup __P((int, int)); -static int pciintr_bitmap_count_irq __P((int, int *)); -static int pciintr_bitmap_find_lowest_irq __P((int, int *)); -int pciintr_link_init __P((void)); -int pciintr_guess_irq __P((void)); -int pciintr_link_fixup __P((void)); -int pciintr_link_route __P((u_int16_t *)); -int pciintr_irq_release __P((u_int16_t *)); -int pciintr_header_fixup __P((pci_chipset_tag_t)); -void pciintr_do_header_fixup __P((pci_chipset_tag_t, pcitag_t)); +int pciintr_bitmap_count_irq __P((int, int *)); SIMPLEQ_HEAD(, pciintr_link_map) pciintr_link_map_list; @@ -139,8 +155,12 @@ const struct pciintr_icu_table { { PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C700, opti82c700_init }, + { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C596A, + via82c586_init, }, { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C586_ISA, via82c586_init, }, + { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C686A_ISA, + via82c586_init, }, { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_85C503, sis85c503_init }, @@ -160,13 +180,10 @@ pciintr_icu_lookup(id) { const struct pciintr_icu_table *piit; - for (piit = pciintr_icu_table; - piit->piit_init != NULL; - piit++) { + for (piit = pciintr_icu_table; piit->piit_init != NULL; piit++) if (PCI_VENDOR(id) == piit->piit_vendor && PCI_PRODUCT(id) == piit->piit_product) return (piit); - } return (NULL); } @@ -178,18 +195,15 @@ pciintr_link_lookup(link) struct pciintr_link_map *l; for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; - l = SIMPLEQ_NEXT(l, list)) { + l = SIMPLEQ_NEXT(l, list)) if (l->link == link) return (l); - } return (NULL); } -struct pciintr_link_map * -pciintr_link_alloc(pir, pin) - struct pcibios_intr_routing *pir; - int pin; +static __inline struct pciintr_link_map * +pciintr_link_alloc(pci_chipset_tag_t pc, struct pcibios_intr_routing *pir, int pin) { int link = pir->linkmap[pin].link, clink, irq; struct pciintr_link_map *l, *lstart; @@ -204,11 +218,9 @@ pciintr_link_alloc(pir, pin) * ICU doesn't understand the link value. * Just ignore this PIR entry. */ -#ifdef PCIBIOSVERBOSE - printf("pciintr_link_alloc: bus %d device %d: " - "ignoring link 0x%02x\n", - pir->bus, PIR_DEVFUNC_DEVICE(pir->device), link); -#endif + PCIBIOS_PRINTV(("pciintr_link_alloc: bus %d device %d: " + "ignoring link 0x%02x\n", pir->bus, + PIR_DEVFUNC_DEVICE(pir->device), link)); return (NULL); } @@ -223,18 +235,15 @@ pciintr_link_alloc(pir, pin) * ICU doesn't understand the canonical link value. * Just ignore this PIR entry. */ -#ifdef PCIBIOSVERBOSE - printf("pciintr_link_alloc: " + PCIBIOS_PRINTV(("pciintr_link_alloc: " "bus %d device %d link 0x%02x: " "ignoring PIRQ 0x%02x\n", pir->bus, - PIR_DEVFUNC_DEVICE(pir->device), link, clink); -#endif + PIR_DEVFUNC_DEVICE(pir->device), link, clink)); return (NULL); } } - l = malloc(sizeof(*l), M_DEVBUF, M_NOWAIT); - if (l == NULL) + if ((l = malloc(sizeof(*l), M_DEVBUF, M_NOWAIT)) == NULL) return (NULL); memset(l, 0, sizeof(*l)); @@ -245,7 +254,7 @@ pciintr_link_alloc(pir, pin) l->clink = clink; l->irq = irq; /* maybe I386_PCI_INTERRUPT_LINE_NO_CONNECTION */ } else { - l->clink = link; /* only for PCIBIOSVERBOSE diagnostic */ + l->clink = link; l->irq = I386_PCI_INTERRUPT_LINE_NO_CONNECTION; } @@ -278,43 +287,25 @@ pciintr_pir_lookup(bus, device) return (NULL); } -static int +int pciintr_bitmap_count_irq(irq_bitmap, irqp) int irq_bitmap, *irqp; { int i, bit, count = 0, irq = I386_PCI_INTERRUPT_LINE_NO_CONNECTION; - if (irq_bitmap != 0) { - for (i = 0, bit = 1; i < 16; i++, bit <<= 1) { + if (irq_bitmap != 0) + for (i = 0, bit = 1; i < 16; i++, bit <<= 1) if (irq_bitmap & bit) { irq = i; count++; } - } - } + *irqp = irq; return (count); } -static int -pciintr_bitmap_find_lowest_irq(irq_bitmap, irqp) - int irq_bitmap, *irqp; -{ - int i, bit; - - if (irq_bitmap != 0) { - for (i = 0, bit = 1; i < 16; i++, bit <<= 1) { - if (irq_bitmap & bit) { - *irqp = i; - return (1); /* found */ - } - } - } - return (0); /* not found */ -} - -int -pciintr_link_init() +static __inline int +pciintr_link_init(pci_chipset_tag_t pc) { int entry, pin, link; struct pcibios_intr_routing *pir; @@ -331,32 +322,28 @@ pciintr_link_init() for (entry = 0; entry < pcibios_pir_table_nentries; entry++) { pir = &pcibios_pir_table[entry]; for (pin = 0; pin < PCI_INTERRUPT_PIN_MAX; pin++) { - link = pir->linkmap[pin].link; - if (link == 0) { + if ((link = pir->linkmap[pin].link) == 0) /* No connection for this pin. */ continue; - } + /* * Multiple devices may be wired to the same * interrupt; check to see if we've seen this * one already. If not, allocate a new link * map entry and stuff it in the map. */ - l = pciintr_link_lookup(link); - if (l == NULL) { - (void) pciintr_link_alloc(pir, pin); - } else if (pir->linkmap[pin].bitmap != l->bitmap) { + if ((l = pciintr_link_lookup(link)) == NULL) + pciintr_link_alloc(pc, pir, pin); + else if (pir->linkmap[pin].bitmap != l->bitmap) { /* * violates PCI IRQ Routing Table Specification */ -#ifdef PCIBIOSVERBOSE - printf("pciintr_link_init: " + PCIBIOS_PRINTV(("pciintr_link_init: " "bus %d device %d link 0x%02x: " "bad irq bitmap 0x%04x, " - "should be 0x%04x\n", - pir->bus, PIR_DEVFUNC_DEVICE(pir->device), - link, pir->linkmap[pin].bitmap, l->bitmap); -#endif + "should be 0x%04x\n", pir->bus, + PIR_DEVFUNC_DEVICE(pir->device), link, + pir->linkmap[pin].bitmap, l->bitmap)); /* safer value. */ l->bitmap &= pir->linkmap[pin].bitmap; /* XXX - or, should ignore this entry? */ @@ -371,8 +358,8 @@ pciintr_link_init() * No compatible PCI ICU found. * Hopes the BIOS already setup the ICU. */ -int -pciintr_guess_irq() +static __inline int +pciintr_guess_irq(void) { struct pciintr_link_map *l; int irq, guessed = 0; @@ -387,11 +374,10 @@ pciintr_guess_irq() if (pciintr_bitmap_count_irq(l->bitmap, &irq) == 1) { l->irq = irq; l->fixup_stage = 1; -#ifdef PCIINTR_DEBUG - printf("pciintr_guess_irq (stage 1): " - "guessing PIRQ 0x%02x to be IRQ %d\n", - l->clink, l->irq); -#endif + if (pcibios_flags & PCIBIOS_INTRDEBUG) + printf("pciintr_guess_irq (stage 1): " + "guessing PIRQ 0x%02x to be IRQ %d\n", + l->clink, l->irq); guessed = 1; } } @@ -399,12 +385,12 @@ pciintr_guess_irq() return (guessed ? 0 : -1); } -int -pciintr_link_fixup() +static __inline int +pciintr_link_fixup(void) { struct pciintr_link_map *l; - int irq; u_int16_t pciirq = 0; + int irq; /* * First stage: Attempt to connect PIRQs which aren't @@ -419,19 +405,19 @@ pciintr_link_fixup() * In this case, l->fixup_stage == 0. */ pciirq |= 1 << l->irq; -#ifdef PCIINTR_DEBUG - printf("pciintr_link_fixup: PIRQ 0x%02x already " - "connected to IRQ %d\n", l->clink, l->irq); -#endif + if (pcibios_flags & PCIBIOS_INTRDEBUG) + printf("pciintr_link_fixup: PIRQ 0x%02x is " + "already connected to IRQ %d\n", + l->clink, l->irq); continue; } /* * Interrupt isn't connected. Attempt to assign it to an IRQ. */ -#ifdef PCIINTR_DEBUG - printf("pciintr_link_fixup: PIRQ 0x%02x not connected", - l->clink); -#endif + if (pcibios_flags & PCIBIOS_INTRDEBUG) + printf("pciintr_link_fixup: PIRQ 0x%02x not connected", + l->clink); + /* * Just do the easy case now; we'll defer the harder ones * to Stage 2. @@ -440,13 +426,11 @@ pciintr_link_fixup() l->irq = irq; l->fixup_stage = 1; pciirq |= 1 << irq; -#ifdef PCIINTR_DEBUG - printf(", assigning IRQ %d", l->irq); -#endif + if (pcibios_flags & PCIBIOS_INTRDEBUG) + printf(", assigning IRQ %d", l->irq); } -#ifdef PCIINTR_DEBUG - printf("\n"); -#endif + if (pcibios_flags & PCIBIOS_INTRDEBUG) + printf("\n"); } /* @@ -454,24 +438,21 @@ pciintr_link_fixup() * connect in Stage 1. */ for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; - l = SIMPLEQ_NEXT(l, list)) { - if (l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) - continue; - if (pciintr_bitmap_find_lowest_irq(l->bitmap & pciirq, - &l->irq)) { + l = SIMPLEQ_NEXT(l, list)) + if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION && + (irq = ffs(l->bitmap & pciirq)) > 0) { /* * This IRQ is a valid PCI IRQ already * connected to another PIRQ, and also an * IRQ our PIRQ can use; connect it up! */ l->fixup_stage = 2; -#ifdef PCIINTR_DEBUG - printf("pciintr_link_fixup (stage 2): " - "assigning IRQ %d to PIRQ 0x%02x\n", - l->irq, l->clink); -#endif + l->irq = irq - 1; + if (pcibios_flags & PCIBIOS_INTRDEBUG) + printf("pciintr_link_fixup (stage 2): " + "assigning IRQ %d to PIRQ 0x%02x\n", + l->irq, l->clink); } - } #ifdef PCIBIOS_IRQS_HINT /* @@ -480,224 +461,208 @@ pciintr_link_fixup() */ for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; l = SIMPLEQ_NEXT(l, list)) { - if (l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) - continue; - if (pciintr_bitmap_find_lowest_irq( - l->bitmap & pcibios_irqs_hint, &l->irq)) { + if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION && + (irq = ffs(l->bitmap & pcibios_irqs_hint)) > 0) { l->fixup_stage = 3; -#ifdef PCIINTR_DEBUG - printf("pciintr_link_fixup (stage 3): " - "assigning IRQ %d to PIRQ 0x%02x\n", - l->irq, l->clink); -#endif + l->irq = irq - 1; + if (pcibios_flags & PCIBIOS_INTRDEBUG) + printf("pciintr_link_fixup (stage 3): " + "assigning IRQ %d to PIRQ 0x%02x\n", + l->irq, l->clink); } } #endif /* PCIBIOS_IRQS_HINT */ + if (pcibios_flags & PCIBIOS_INTRDEBUG) + printf("pciintr_link_fixup: piirq 0x%04x\n", pciirq); + return (0); } int -pciintr_link_route(pciirq) - u_int16_t *pciirq; +pci_intr_route_link(pc, ihp) + pci_chipset_tag_t pc; + pci_intr_handle_t *ihp; { struct pciintr_link_map *l; - int rv = 0; + pcireg_t intr; + int rv = 1; + char *p = NULL; - *pciirq = 0; + l = ihp->link; + if (!l || pciintr_icu_tag == NULL) + return (1); - for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; - l = SIMPLEQ_NEXT(l, list)) { - if (l->fixup_stage == 0) { - if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { - /* Appropriate interrupt was not found. */ -#ifdef PCIBIOSVERBOSE - printf("pciintr_link_route: " - "PIRQ 0x%02x: no IRQ, try " - "\"options PCIBIOS_IRQS_HINT=0x%04x\"\n", + if (l->fixup_stage == 0) { + if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { + /* Appropriate interrupt was not found. */ + if (pcibios_flags & PCIBIOS_INTRDEBUG) + printf("pci_intr_route_link: PIRQ 0x%02x: " + "no IRQ, try " + "\"option PCIBIOS_IRQS_HINT=0x%04x\"\n", l->clink, /* suggest irq 9/10/11, if possible */ (l->bitmap & 0x0e00) ? (l->bitmap & 0x0e00) : l->bitmap); -#endif - } else { - /* BIOS setting has no problem */ -#ifdef PCIINTR_DEBUG - printf("pciintr_link_route: " - "route of PIRQ 0x%02x -> " - "IRQ %d preserved BIOS setting\n", - l->clink, l->irq); -#endif - *pciirq |= (1 << l->irq); - } - continue; /* nothing to do. */ - } + } else + p = " preserved BIOS setting"; + } else { if (pciintr_icu_set_intr(pciintr_icu_tag, pciintr_icu_handle, - l->clink, l->irq) != 0 || - pciintr_icu_set_trigger(pciintr_icu_tag, - pciintr_icu_handle, - l->irq, IST_LEVEL) != 0) { - printf("pciintr_link_route: route of PIRQ 0x%02x -> " - "IRQ %d failed\n", l->clink, l->irq); - rv = 1; - } else { - /* - * Succssfully routed interrupt. Mark this as - * a PCI interrupt. - */ - *pciirq |= (1 << l->irq); - } + l->clink, l->irq) != 0 || + pciintr_icu_set_trigger(pciintr_icu_tag, pciintr_icu_handle, + l->irq, IST_LEVEL) != 0) { + p = " failed"; + rv = 0; + } else + p = ""; } + if (p && pcibios_flags & PCIBIOS_INTRDEBUG) + printf("pci_intr_route_link: route PIRQ 0x%02x -> IRQ %d%s\n", + l->clink, l->irq, p); - return (rv); -} + if (!rv) + return (0); -int -pciintr_irq_release(pciirq) - u_int16_t *pciirq; -{ - int i, bit; + /* + * IRQs 14 and 15 are reserved for PCI IDE interrupts; don't muck + * with them. + */ + if (ihp->line == 14 || ihp->line == 15) + return (1); - for (i = 0, bit = 1; i < 16; i++, bit <<= 1) { - if ((*pciirq & bit) == 0) - (void) pciintr_icu_set_trigger(pciintr_icu_tag, - pciintr_icu_handle, i, IST_EDGE); + intr = pci_conf_read(pc, ihp->tag, PCI_INTERRUPT_REG); + if (ihp->line != PCI_INTERRUPT_LINE(intr)) { + intr &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT); + intr |= (ihp->line << PCI_INTERRUPT_LINE_SHIFT); + pci_conf_write(pc, ihp->tag, PCI_INTERRUPT_REG, intr); } - return (0); + return (1); } int -pciintr_header_fixup(pc) - pci_chipset_tag_t pc; +pci_intr_post_fixup() { - PCIBIOS_PRINTV(("------------------------------------------\n")); - PCIBIOS_PRINTV((" device vendor product pin PIRQ IRQ stage\n")); - PCIBIOS_PRINTV(("------------------------------------------\n")); - pci_device_foreach(pc, pcibios_max_bus, pciintr_do_header_fixup); - PCIBIOS_PRINTV(("------------------------------------------\n")); + struct pciintr_link_map *l; + int i, pciirq; + + if (!pciintr_icu_handle) + return 0; + + pciirq = pcibios_pir_header.exclusive_irq; + if (pcibios_flags & PCIBIOS_INTRDEBUG) + printf("pci_intr_post_fixup: PCI IRQs:"); + for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); + l != NULL; l = SIMPLEQ_NEXT(l, list)) + if (l->fixup_stage == 0 && + l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { + if (pcibios_flags & PCIBIOS_INTRDEBUG) + printf(" %d", l->irq); + pciirq |= (1 << l->irq); + } + + if (pcibios_flags & PCIBIOS_INTRDEBUG) + printf("; ISA IRQs:"); + for (i = 0; i < 16; i++) + if (!(pciirq & (1 << i))) { + if (pcibios_flags & PCIBIOS_INTRDEBUG) + printf(" %d", i); + pciintr_icu_set_trigger(pciintr_icu_tag, + pciintr_icu_handle, i, IST_EDGE); + } + + if (pcibios_flags & PCIBIOS_INTRDEBUG) + printf("\n"); return (0); } -void -pciintr_do_header_fixup(pc, tag) +int +pci_intr_header_fixup(pc, tag, ihp) pci_chipset_tag_t pc; pcitag_t tag; + pci_intr_handle_t *ihp; { struct pcibios_intr_routing *pir; struct pciintr_link_map *l; - int pin, irq, link; - int bus, device, function; - pcireg_t intr, id; + int irq, link, bus, device, function; + char *p = NULL; + irq = ihp->line; + ihp->link = NULL; + ihp->tag = tag; pci_decompose_tag(pc, tag, &bus, &device, &function); - id = pci_conf_read(pc, tag, PCI_ID_REG); - intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); - pin = PCI_INTERRUPT_PIN(intr); - irq = PCI_INTERRUPT_LINE(intr); - - if (pin == 0) { - /* - * No interrupt used. - */ - return; + if ((pir = pciintr_pir_lookup(bus, device)) == NULL || + (link = pir->linkmap[ihp->pin - 1].link) == 0) { + PCIBIOS_PRINTV(("Interrupt not connected; no need to change.")); + return 1; } - pir = pciintr_pir_lookup(bus, device); - if (pir == NULL || (link = pir->linkmap[pin - 1].link) == 0) { - /* - * Interrupt not connected; no - * need to change. - */ - return; - } - - l = pciintr_link_lookup(link); - if (l == NULL) { -#ifdef PCIINTR_DEBUG + if ((l = pciintr_link_lookup(link)) == NULL) { /* * No link map entry. * Probably pciintr_icu_getclink() or pciintr_icu_get_intr() * was failed. */ - printf("pciintr_header_fixup: no entry for link 0x%02x " - "(%d:%d:%d:%c)\n", link, bus, device, function, - '@' + pin); -#endif - return; + if (pcibios_flags & PCIBIOS_INTRDEBUG) + printf("pci_intr_header_fixup: no entry for link " + "0x%02x (%d:%d:%d:%c)\n", + link, bus, device, function, '@' + ihp->pin); + return 1; } -#ifdef PCIBIOSVERBOSE - if (pcibiosverbose) { - printf("%03d:%02d:%d 0x%04x 0x%04x %c 0x%02x", - bus, device, function, PCI_VENDOR(id), PCI_PRODUCT(id), - '@' + pin, l->clink); - if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) - printf(" -"); - else - printf(" %3d", l->irq); - printf(" %d ", l->fixup_stage); - } -#endif + ihp->link = l; + if (irq == 14 || irq == 15) + p = " WARNING: ignored"; + else if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { - /* - * IRQs 14 and 15 are reserved for PCI IDE interrupts; don't muck - * with them. - */ - if (irq == 14 || irq == 15) { - PCIBIOS_PRINTV((" WARNING: ignored\n")); - return; - } - - if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { /* Appropriate interrupt was not found. */ - if (pciintr_icu_tag == NULL && - irq != 0 && irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { + if (pciintr_icu_tag == NULL && ihp->line != 0 && + ihp->line != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) /* * Do not print warning, * if no compatible PCI ICU found, * but the irq is already assigned by BIOS. */ - PCIBIOS_PRINTV(("\n")); - } else { - PCIBIOS_PRINTV((" WARNING: missing IRQ\n")); - } - return; - } + p = ""; + else + p = " WARNING: missing"; + } else if (irq == 0 || irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { - if (l->irq == irq) { - /* don't have to reconfigure */ - PCIBIOS_PRINTV((" already assigned\n")); - return; - } + p = " fixed up"; + ihp->line = l->irq; - if (irq == 0 || irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) { - PCIBIOS_PRINTV((" fixed up\n")); } else { /* routed by BIOS, but inconsistent */ #ifdef PCIBIOS_INTR_FIXUP_FORCE /* believe PCI IRQ Routing table */ - PCIBIOS_PRINTV((" WARNING: overriding irq %d\n", irq)); + p = " WARNING: overriding"; + ihp->line = l->irq; #else /* believe PCI Interrupt Configuration Register (default) */ - PCIBIOS_PRINTV((" WARNING: preserving irq %d\n", irq)); - return; + p = " WARNING: preserving"; #endif } - intr &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT); - intr |= (l->irq << PCI_INTERRUPT_LINE_SHIFT); - pci_conf_write(pc, tag, PCI_INTERRUPT_REG, intr); + if (pcibios_flags & PCIBIOS_INTRDEBUG) { + register pcireg_t id = pci_conf_read(pc, tag, PCI_ID_REG); + + printf("%d:%d:%d %04x:%04x pin %c clink 0x%02x irq %d stage %d" + "%s irq %d\n", bus, device, function, + PCI_VENDOR(id), PCI_PRODUCT(id), '@' + ihp->pin, l->clink, + ((l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION)? + -1 : l->irq), l->fixup_stage, p, irq); + } + + return (1); } int -pci_intr_fixup(pc, iot, pciirq) +pci_intr_fixup(pc, iot) pci_chipset_tag_t pc; bus_space_tag_t iot; - u_int16_t *pciirq; { const struct pciintr_icu_table *piit = NULL; pcitag_t icutag; @@ -743,8 +708,7 @@ pci_intr_fixup(pc, iot, pciirq) if (PCI_VENDOR(icuid) == 0) continue; - piit = pciintr_icu_lookup(icuid); - if (piit != NULL) + if ((piit = pciintr_icu_lookup(icuid))) break; } } @@ -756,12 +720,10 @@ pci_intr_fixup(pc, iot, pciirq) PCI_VENDOR(icuid), PCI_PRODUCT(icuid)); printf("\n"); if (!(pcibios_flags & PCIBIOS_INTR_GUESS)) { - if (pciintr_link_init()) + if (pciintr_link_init(pc)) return (-1); /* non-fatal */ if (pciintr_guess_irq()) return (-1); /* non-fatal */ - if (pciintr_header_fixup(pc)) - return (1); /* fatal */ return (0); /* success! */ } else return (-1); /* non-fatal */ @@ -777,7 +739,7 @@ pci_intr_fixup(pc, iot, pciirq) /* * Initialize the PCI interrupt link map. */ - if (pciintr_link_init()) + if (pciintr_link_init(pc)) return (-1); /* non-fatal */ /* @@ -786,28 +748,5 @@ pci_intr_fixup(pc, iot, pciirq) if (pciintr_link_fixup() != 0) return (-1); /* non-fatal */ - /* - * Now actually program the PCI ICU with the new - * routing information. - */ - if (pciintr_link_route(pciirq) != 0) - return (1); /* fatal */ - - /* - * Now that we've routed all of the PIRQs, rewrite the PCI - * configuration headers to reflect the new mapping. - */ - if (pciintr_header_fixup(pc) != 0) - return (1); /* fatal */ - - /* - * Free any unused PCI IRQs for ISA devices. - */ - if (pciintr_irq_release(pciirq) != 0) - return (-1); /* non-fatal */ - - /* - * All done! - */ - return (0); /* success! */ + return (0); } diff --git a/sys/arch/i386/pci/pci_machdep.c b/sys/arch/i386/pci/pci_machdep.c index 58231fa1032..de242832c0a 100644 --- a/sys/arch/i386/pci/pci_machdep.c +++ b/sys/arch/i386/pci/pci_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pci_machdep.c,v 1.17 2000/10/25 19:13:12 mickey Exp $ */ +/* $OpenBSD: pci_machdep.c,v 1.18 2001/01/27 04:59:40 mickey Exp $ */ /* $NetBSD: pci_machdep.c,v 1.28 1997/06/06 23:29:17 thorpej Exp $ */ /*- @@ -105,6 +105,11 @@ extern bios_pciinfo_t *bios_pciinfo; #include <dev/pci/pcivar.h> #include <dev/pci/pcireg.h> +#include "pcibios.h" +#if NPCIBIOS > 0 +#include <i386/pci/pcibiosvar.h> +#endif + int pci_mode = -1; #define PCI_MODE1_ENABLE 0x80000000UL @@ -406,7 +411,6 @@ pci_intr_map(pc, intrtag, pin, line, ihp) int pin, line; pci_intr_handle_t *ihp; { - if (pin == 0) { /* No IRQ used. */ goto bad; @@ -417,6 +421,13 @@ pci_intr_map(pc, intrtag, pin, line, ihp) goto bad; } + ihp->line = line; + ihp->pin = pin; +#if NPCIBIOS > 0 + pci_intr_header_fixup(pc, intrtag, ihp); + line = ihp->line; +#endif + /* * Section 6.2.4, `Miscellaneous Functions', says that 255 means * `unknown' or `no connection' on a PC. We assume that a device with @@ -445,11 +456,10 @@ pci_intr_map(pc, intrtag, pin, line, ihp) } } - *ihp = line; return 0; bad: - *ihp = -1; + ihp->line = -1; return 1; } @@ -460,10 +470,10 @@ pci_intr_string(pc, ih) { static char irqstr[8]; /* 4 + 2 + NULL + sanity */ - if (ih == 0 || ih >= ICU_LEN || ih == 2) - panic("pci_intr_string: bogus handle 0x%x", ih); + if (ih.line == 0 || ih.line >= ICU_LEN || ih.line == 2) + panic("pci_intr_string: bogus handle 0x%x", ih.line); - sprintf(irqstr, "irq %d", ih); + sprintf(irqstr, "irq %d", ih.line); return (irqstr); } @@ -476,11 +486,18 @@ pci_intr_establish(pc, ih, level, func, arg, what) void *arg; char *what; { + void *ret; - if (ih == 0 || ih >= ICU_LEN || ih == 2) - panic("pci_intr_establish: bogus handle 0x%x", ih); + if (ih.line == 0 || ih.line >= ICU_LEN || ih.line == 2) + panic("pci_intr_establish: bogus handle 0x%x", ih.line); - return isa_intr_establish(NULL, ih, IST_LEVEL, level, func, arg, what); + ret = isa_intr_establish(NULL, ih.line, + IST_LEVEL, level, func, arg, what); +#if NPCIBIOS > 0 + if (ret) + pci_intr_route_link(pc, &ih); +#endif + return ret; } void @@ -488,6 +505,6 @@ pci_intr_disestablish(pc, cookie) pci_chipset_tag_t pc; void *cookie; { - + /* XXX oh, unroute the pci int link? */ return isa_intr_disestablish(NULL, cookie); } diff --git a/sys/arch/i386/pci/pci_machdep.h b/sys/arch/i386/pci/pci_machdep.h index 166c959cb40..a3769766052 100644 --- a/sys/arch/i386/pci/pci_machdep.h +++ b/sys/arch/i386/pci/pci_machdep.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pci_machdep.h,v 1.6 2000/08/08 19:12:48 mickey Exp $ */ +/* $OpenBSD: pci_machdep.h,v 1.7 2001/01/27 04:59:40 mickey Exp $ */ /* $NetBSD: pci_machdep.h,v 1.7 1997/06/06 23:29:18 thorpej Exp $ */ /* @@ -62,7 +62,13 @@ extern struct i386_bus_dma_tag pci_bus_dma_tag; */ typedef void *pci_chipset_tag_t; typedef union i386_pci_tag_u pcitag_t; -typedef int pci_intr_handle_t; + +typedef +struct { + pcitag_t tag; + int line, pin; + void *link; +} pci_intr_handle_t; /* * i386-specific PCI variables and functions. diff --git a/sys/arch/i386/pci/pcib.c b/sys/arch/i386/pci/pcib.c index 81785b6044a..be4ef0b37b5 100644 --- a/sys/arch/i386/pci/pcib.c +++ b/sys/arch/i386/pci/pcib.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pcib.c,v 1.7 2000/03/27 08:35:22 brad Exp $ */ +/* $OpenBSD: pcib.c,v 1.8 2001/01/27 04:59:40 mickey Exp $ */ /* $NetBSD: pcib.c,v 1.6 1997/06/06 23:29:16 thorpej Exp $ */ /*- @@ -51,6 +51,10 @@ #include <dev/pci/pcidevs.h> #include "isa.h" +#include "pcibios.h" +#if NPCIBIOS > 0 +#include <i386/pci/pcibiosvar.h> +#endif int pcibmatch __P((struct device *, void *, void *)); void pcibattach __P((struct device *, struct device *, void *)); @@ -115,6 +119,10 @@ pcib_callback(self) { struct isabus_attach_args iba; +#if NPCIBIOS > 0 + pci_intr_post_fixup(); +#endif + /* * Attach the ISA bus behind this bridge. */ diff --git a/sys/arch/i386/pci/pcibios.c b/sys/arch/i386/pci/pcibios.c index 07f2319b723..38dbb2fd0c3 100644 --- a/sys/arch/i386/pci/pcibios.c +++ b/sys/arch/i386/pci/pcibios.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pcibios.c,v 1.20 2001/01/25 00:07:40 mickey Exp $ */ +/* $OpenBSD: pcibios.c,v 1.21 2001/01/27 04:59:40 mickey Exp $ */ /* $NetBSD: pcibios.c,v 1.5 2000/08/01 05:23:59 uch Exp $ */ /* @@ -67,7 +67,6 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ - /* * Copyright (c) 1999, by UCHIYAMA Yasushi * All rights reserved. @@ -113,24 +112,15 @@ #include <machine/biosvar.h> -#ifdef PCIBIOSVERBOSE -int pcibiosverbose = 1; -#endif - int pcibios_present; struct pcibios_pir_header pcibios_pir_header; struct pcibios_intr_routing *pcibios_pir_table; int pcibios_pir_table_nentries; -int pcibios_max_bus; struct bios32_entry pcibios_entry; struct bios32_entry_info pcibios_entry_info; -struct pcibios_softc { - struct device sc_dev; -}; - struct pcibios_intr_routing *pcibios_pir_init __P((struct pcibios_softc *)); int pcibios_get_status __P((struct pcibios_softc *, @@ -142,9 +132,7 @@ int pcibios_get_intr_routing __P((struct pcibios_softc *, int pcibios_return_code __P((struct pcibios_softc *, u_int16_t, const char *)); void pcibios_print_exclirq __P((struct pcibios_softc *)); -#ifdef PCIINTR_DEBUG void pcibios_print_pir_table __P((void)); -#endif #define PCI_IRQ_TABLE_START 0xf0000 #define PCI_IRQ_TABLE_END 0xfffff @@ -175,13 +163,9 @@ pcibiosprobe(parent, match, aux) rv = bios32_service(PCIBIOS_SIGNATURE, &pcibios_entry, &pcibios_entry_info); -#ifdef PCIBIOSVERBOSE - printf("pcibiosprobe: 0x%lx:0x%lx at 0x%lx[0x%lx]\n", - pcibios_entry.segment, - pcibios_entry.offset, - pcibios_entry_info.bei_base, - pcibios_entry_info.bei_size); -#endif + PCIBIOS_PRINTV(("pcibiosprobe: 0x%lx:0x%lx at 0x%lx[0x%lx]\n", + pcibios_entry.segment, pcibios_entry.offset, + pcibios_entry_info.bei_base, pcibios_entry_info.bei_size)); return rv && pcibios_get_status(NULL, &rev_maj, &rev_min, &mech1, &mech2, @@ -202,20 +186,16 @@ pcibiosattach(parent, self, aux) pcibios_get_status((struct pcibios_softc *)self, &rev_maj, &rev_min, &mech1, &mech2, - &scmech1, &scmech2, &pcibios_max_bus); + &scmech1, &scmech2, &sc->max_bus); printf(": rev. %d.%d found at 0x%lx[0x%lx]\n", rev_maj, rev_min >> 4, pcibios_entry_info.bei_base, pcibios_entry_info.bei_size); -#ifdef PCIBIOSVERBOSE - printf("%s: config mechanism %s%s, special cycles %s%s, last bus %d\n", - sc->sc_dev.dv_xname, - mech1 ? "[1]" : "[x]", - mech2 ? "[2]" : "[x]", - scmech1 ? "[1]" : "[x]", - scmech2 ? "[2]" : "[x]", - pcibios_max_bus); -#endif + + PCIBIOS_PRINTV(("%s: config mechanism %s%s, special cycles %s%s, " + "last bus %d\n", sc->sc_dev.dv_xname, + mech1 ? "[1]" : "[x]", mech2 ? "[2]" : "[x]", + scmech1 ? "[1]" : "[x]", scmech2 ? "[2]" : "[x]", sc->max_bus)); /* * The PCI BIOS tells us the config mechanism; fill it in now @@ -232,12 +212,11 @@ pcibiosattach(parent, self, aux) if (!(pcibios_flags & PCIBIOS_INTR_FIXUP) && pcibios_pir_init((struct pcibios_softc *)self) != NULL) { int rv; - u_int16_t pciirq; /* * Fixup interrupt routing. */ - rv = pci_intr_fixup(NULL, I386_BUS_SPACE_IO, &pciirq); + rv = pci_intr_fixup(NULL, I386_BUS_SPACE_IO); switch (rv) { case -1: /* Non-fatal error. */ @@ -258,13 +237,13 @@ pcibiosattach(parent, self, aux) } if (!(pcibios_flags & PCIBIOS_BUS_FIXUP)) { - pcibios_max_bus = pci_bus_fixup(NULL, 0); + sc->max_bus = pci_bus_fixup(NULL, 0); printf("%s: PCI bus #%d is the last bus\n", - sc->sc_dev.dv_xname, pcibios_max_bus); + sc->sc_dev.dv_xname, sc->max_bus); } if (!(pcibios_flags & PCIBIOS_ADDR_FIXUP)) - pci_addr_fixup(NULL, pcibios_max_bus); + pci_addr_fixup(sc, NULL, sc->max_bus); } struct pcibios_intr_routing * @@ -365,9 +344,8 @@ pcibios_pir_init(sc) } pcibios_print_exclirq(sc); -#ifdef PCIINTR_DEBUG - pcibios_print_pir_table(); -#endif + if (pcibios_flags & PCIBIOS_INTRDEBUG) + pcibios_print_pir_table(); return pcibios_pir_table; } @@ -455,7 +433,7 @@ pcibios_get_intr_routing(sc, table, nentries, exclirq) return (rv); *nentries = args.size / sizeof(*table); - *exclirq = bx; + *exclirq |= bx; return (PCIBIOS_SUCCESS); } @@ -533,7 +511,6 @@ pcibios_print_exclirq(sc) } } -#ifdef PCIINTR_DEBUG void pcibios_print_pir_table() { @@ -552,13 +529,13 @@ pcibios_print_pir_table() } } } -#endif void -pci_device_foreach(pc, maxbus, func) +pci_device_foreach(sc, pc, maxbus, func) + struct pcibios_softc *sc; pci_chipset_tag_t pc; int maxbus; - void (*func) __P((pci_chipset_tag_t, pcitag_t)); + void (*func) __P((struct pcibios_softc *, pci_chipset_tag_t, pcitag_t)); { const struct pci_quirkdata *qd; int bus, device, function, maxdevs, nfuncs; @@ -602,7 +579,7 @@ pci_device_foreach(pc, maxbus, func) */ if (PCI_VENDOR(id) == 0) continue; - (*func)(pc, tag); + (*func)(sc, pc, tag); } } } diff --git a/sys/arch/i386/pci/pcibiosvar.h b/sys/arch/i386/pci/pcibiosvar.h index 9764ea2232e..a74bc33e6f7 100644 --- a/sys/arch/i386/pci/pcibiosvar.h +++ b/sys/arch/i386/pci/pcibiosvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pcibiosvar.h,v 1.5 2001/01/25 01:00:59 mickey Exp $ */ +/* $OpenBSD: pcibiosvar.h,v 1.6 2001/01/27 04:59:40 mickey Exp $ */ /* $NetBSD: pcibios.h,v 1.2 2000/04/28 17:15:16 uch Exp $ */ /* @@ -12,18 +12,18 @@ * notice, this list of conditions and the following disclaimer. * 2. The name of the developer may NOT be used to endorse or promote products * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ /* @@ -34,6 +34,8 @@ #define PCIBIOS_BUS_FIXUP 0x002 #define PCIBIOS_INTR_FIXUP 0x004 #define PCIBIOS_INTR_GUESS 0x008 +#define PCIBIOS_VERBOSE 0x010 +#define PCIBIOS_INTRDEBUG 0x020 /* * PCI BIOS return codes. @@ -47,6 +49,19 @@ #define PCIBIOS_SET_FAILED 0x88 #define PCIBIOS_BUFFER_TOO_SMALL 0x89 +struct pcibios_softc { + struct device sc_dev; + + int max_bus; + + /* address fixup guts */ + struct extent *extent_mem; + struct extent *extent_port; + bus_addr_t mem_alloc_start; + bus_addr_t port_alloc_start; + int nbogus; +}; + /* * PCI IRQ Routing Table definitions. */ @@ -93,17 +108,8 @@ void pcibios_init __P((void)); extern struct pcibios_pir_header pcibios_pir_header; extern struct pcibios_intr_routing *pcibios_pir_table; extern int pcibios_pir_table_nentries; -extern int pcibios_max_bus; - -struct pciaddr { - struct extent *extent_mem; - struct extent *extent_port; - bus_addr_t mem_alloc_start; - bus_addr_t port_alloc_start; - int nbogus; -}; -extern struct pciaddr pciaddr; +int pcibios_flags; typedef void *pciintr_icu_handle_t; @@ -128,36 +134,24 @@ typedef const struct pciintr_icu *pciintr_icu_tag_t; #define pciintr_icu_set_trigger(t, h, irq, trigger) \ (*(t)->pi_set_trigger)((h), (irq), (trigger)) - -int pcibios_flags; - -#ifdef PCIBIOSVERBOSE -extern int pcibiosverbose; - #define PCIBIOS_PRINTV(arg) \ do { \ - if (pcibiosverbose) \ - printf arg; \ - } while (0) -#define PCIBIOS_PRINTVN(n, arg) \ - do { \ - if (pcibiosverbose > (n)) \ + if (pcibios_flags & PCIBIOS_VERBOSE) \ printf arg; \ } while (0) -#else -#define PCIBIOS_PRINTV(arg) -#define PCIBIOS_PRINTVN(n, arg) -#endif #define PCIADDR_SEARCH_IO 0 #define PCIADDR_SEARCH_MEM 1 struct extent *pciaddr_search __P((int, bus_addr_t *, bus_size_t)); -int pci_intr_fixup __P((pci_chipset_tag_t, bus_space_tag_t, u_int16_t *)); +int pci_intr_fixup __P((pci_chipset_tag_t, bus_space_tag_t)); int pci_bus_fixup __P((pci_chipset_tag_t, int)); -void pci_addr_fixup __P((pci_chipset_tag_t, int)); -void pci_device_foreach __P((pci_chipset_tag_t, int, - void (*) __P((pci_chipset_tag_t, pcitag_t)))); +void pci_addr_fixup __P((struct pcibios_softc *, pci_chipset_tag_t, int)); +void pci_device_foreach __P((struct pcibios_softc *, pci_chipset_tag_t, int, + void (*) __P((struct pcibios_softc *, pci_chipset_tag_t, pcitag_t)))); +int pci_intr_header_fixup __P((pci_chipset_tag_t, pcitag_t, pci_intr_handle_t *)); +int pci_intr_route_link __P((pci_chipset_tag_t, pci_intr_handle_t *)); +int pci_intr_post_fixup __P((void)); /* * Init functions for our known PCI ICUs. @@ -174,4 +168,3 @@ int sis85c503_init __P((pci_chipset_tag_t, bus_space_tag_t, pcitag_t, pciintr_icu_tag_t *, pciintr_icu_handle_t *)); int amd756_init __P((pci_chipset_tag_t, bus_space_tag_t, pcitag_t, pciintr_icu_tag_t *, pciintr_icu_handle_t *)); - |