diff options
author | Michael Shalayeff <mickey@cvs.openbsd.org> | 2000-03-26 22:38:40 +0000 |
---|---|---|
committer | Michael Shalayeff <mickey@cvs.openbsd.org> | 2000-03-26 22:38:40 +0000 |
commit | 971bb4bc1ce2f7f91c9871b0f50a68e39326fd1c (patch) | |
tree | 349aff69b835169acc1c72f4e2c4ad13c674fcbd /sys/arch | |
parent | 4a8a2378aeebf4afb7f090031193a8fc582384e2 (diff) |
from netbsd: pci interrupt routing code.
also, change a few pcidevs names to match netbsd (and more descriptive).
tested on a bunch of laptops, helps resolving 'pin X unmapped'
problems for (usually) usb and cardbus cntrollers.
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/i386/conf/GENERIC | 4 | ||||
-rw-r--r-- | sys/arch/i386/conf/files.i386 | 15 | ||||
-rw-r--r-- | sys/arch/i386/i386/autoconf.c | 13 | ||||
-rw-r--r-- | sys/arch/i386/i386/bios32.c | 180 | ||||
-rw-r--r-- | sys/arch/i386/include/biosvar.h | 25 | ||||
-rw-r--r-- | sys/arch/i386/pci/opti82c558.c | 248 | ||||
-rw-r--r-- | sys/arch/i386/pci/opti82c558reg.h | 65 | ||||
-rw-r--r-- | sys/arch/i386/pci/opti82c700.c | 290 | ||||
-rw-r--r-- | sys/arch/i386/pci/opti82c700reg.h | 71 | ||||
-rw-r--r-- | sys/arch/i386/pci/pci_bus_fixup.c | 135 | ||||
-rw-r--r-- | sys/arch/i386/pci/pci_bus_fixup.h | 28 | ||||
-rw-r--r-- | sys/arch/i386/pci/pci_intr_fixup.c | 696 | ||||
-rw-r--r-- | sys/arch/i386/pci/pci_intr_fixup.h | 65 | ||||
-rw-r--r-- | sys/arch/i386/pci/pcib.c | 2 | ||||
-rw-r--r-- | sys/arch/i386/pci/pcibios.c | 475 | ||||
-rw-r--r-- | sys/arch/i386/pci/pcibios.h | 87 | ||||
-rw-r--r-- | sys/arch/i386/pci/piix.c | 237 | ||||
-rw-r--r-- | sys/arch/i386/pci/piixreg.h | 55 | ||||
-rw-r--r-- | sys/arch/i386/pci/piixvar.h | 77 | ||||
-rw-r--r-- | sys/arch/i386/pci/sis85c503.c | 180 | ||||
-rw-r--r-- | sys/arch/i386/pci/sis85c503reg.h | 52 | ||||
-rw-r--r-- | sys/arch/i386/pci/via82c586.c | 270 | ||||
-rw-r--r-- | sys/arch/i386/pci/via82c586reg.h | 62 |
23 files changed, 3326 insertions, 6 deletions
diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC index 1d47e9180bb..b838ef7be8c 100644 --- a/sys/arch/i386/conf/GENERIC +++ b/sys/arch/i386/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.162 2000/03/26 18:49:43 aaron Exp $ +# $OpenBSD: GENERIC,v 1.163 2000/03/26 22:38:31 mickey Exp $ # $NetBSD: GENERIC,v 1.48 1996/05/20 18:17:23 mrg Exp $ # # GENERIC -- everything that's currently supported @@ -48,6 +48,8 @@ option EISAVERBOSE #option PCMCIAVERBOSE #option USBVERBOSE +option BIOS32,PCIBIOS,PCIBIOS_INTR_FIXUP + pchb* at pci? dev ? function ? # PCI-Host bridges ppb* at pci? dev ? function ? # PCI-PCI bridges pci* at ppb? bus ? diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386 index 8c17435b5cd..809930770b0 100644 --- a/sys/arch/i386/conf/files.i386 +++ b/sys/arch/i386/conf/files.i386 @@ -1,4 +1,4 @@ -# $OpenBSD: files.i386,v 1.62 2000/02/21 17:09:08 mickey Exp $ +# $OpenBSD: files.i386,v 1.63 2000/03/26 22:38:32 mickey Exp $ # $NetBSD: files.i386,v 1.73 1996/05/07 00:58:36 thorpej Exp $ # # new style config file for i386 architecture @@ -84,8 +84,17 @@ file arch/i386/i386/mainbus.c mainbus include "../../../dev/pci/files.pci" file arch/i386/pci/pci_machdep.c pci -file arch/i386/pci/pciide_machdep.c pciide file arch/i386/pci/pci_compat.c pci # XXX compatibility +file arch/i386/pci/pcibios.c pcibios +file arch/i386/pci/pci_intr_fixup.c pcibios & pcibios_intr_fixup +file arch/i386/pci/piix.c pcibios & pcibios_intr_fixup +file arch/i386/pci/opti82c558.c pcibios & pcibios_intr_fixup +file arch/i386/pci/opti82c700.c pcibios & pcibios_intr_fixup +file arch/i386/pci/sis85c503.c pcibios & pcibios_intr_fixup +file arch/i386/pci/via82c586.c pcibios & pcibios_intr_fixup +file arch/i386/pci/pci_bus_fixup.c pcibios & pcibios_bus_fixup +file arch/i386/pci/pciide_machdep.c pciide +file arch/i386/pci/pcic_pci_machdep.c pcic_pci # PCI-Host bridge chipsets device pchb: pcibus @@ -244,6 +253,8 @@ attach apm at bios file arch/i386/i386/apm.c apm needs-count file arch/i386/i386/apmcall.S apm +file arch/i386/i386/bios32.c bios32 + # XXXX pcic here because it needs to be late. The catch: pcic needs # to be late, so devices which attach to it are attached late. But it # needs to be before its isa and pci attachments. This answer is diff --git a/sys/arch/i386/i386/autoconf.c b/sys/arch/i386/i386/autoconf.c index 28c2a8ed743..bbff08f8189 100644 --- a/sys/arch/i386/i386/autoconf.c +++ b/sys/arch/i386/i386/autoconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: autoconf.c,v 1.30 1999/09/12 19:44:04 weingart Exp $ */ +/* $OpenBSD: autoconf.c,v 1.31 2000/03/26 22:38:32 mickey Exp $ */ /* $NetBSD: autoconf.c,v 1.20 1996/05/03 19:41:56 christos Exp $ */ /*- @@ -59,6 +59,9 @@ #include <machine/pte.h> #include <machine/cpu.h> +#include <machine/biosvar.h> + +#include <i386/pci/pcibios.h> #include <dev/cons.h> @@ -84,6 +87,14 @@ configure() startrtclock(); +#ifdef BIOS32 + bios32_init(); +#endif + +#ifdef PCIBIOS + pcibios_init(); +#endif + if (config_rootfound("mainbus", NULL) == NULL) panic("configure: mainbus not configured"); diff --git a/sys/arch/i386/i386/bios32.c b/sys/arch/i386/i386/bios32.c new file mode 100644 index 00000000000..75a0d47b239 --- /dev/null +++ b/sys/arch/i386/i386/bios32.c @@ -0,0 +1,180 @@ +/* $NetBSD: bios32.c,v 1.1 1999/11/17 00:55:50 thorpej Exp $ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Copyright (c) 1999, by UCHIYAMA Yasushi + * 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. 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. + */ + +/* + * Basic interface to BIOS32 services. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/malloc.h> + +#include <dev/isa/isareg.h> +#ifdef __NetBSD__ +#include <machine/isa_machdep.h> +#include <machine/bios32.h> +#elif defined(__OpenBSD__) +#include <i386/isa/isa_machdep.h> +#include <machine/biosvar.h> +#endif + +#include <machine/segments.h> + +#define BIOS32_START 0xe0000 +#define BIOS32_SIZE 0x20000 +#define BIOS32_END (BIOS32_START + BIOS32_SIZE - 0x10) + +struct bios32_entry bios32_entry; + +/* + * Initialize the BIOS32 interface. + */ +void +bios32_init() +{ + paddr_t entry = 0; + caddr_t p; + unsigned char cksum; + int i; + + for (p = (caddr_t)ISA_HOLE_VADDR(BIOS32_START); + p < (caddr_t)ISA_HOLE_VADDR(BIOS32_END); + p += 16) { + if (*(int *)p != BIOS32_MAKESIG('_', '3', '2', '_')) + continue; + + cksum = 0; + for (i = 0; i < 16; i++) + cksum += *(unsigned char *)(p + i); + if (cksum != 0) + continue; + + if (*(p + 9) != 1) + continue; + + entry = *(u_int32_t *)(p + 4); + + printf("BIOS32 rev. %d found at 0x%lx\n", + *(p + 8), entry); + + if (entry < BIOS32_START || + entry >= BIOS32_END) { + printf("BIOS32 entry point outside " + "allowable range\n"); + entry = 0; + } + break; + } + + if (entry != 0) { + bios32_entry.offset = (caddr_t)ISA_HOLE_VADDR(entry); + bios32_entry.segment = GSEL(GCODE_SEL, SEL_KPL); + } +} + +/* + * Call BIOS32 to locate the specified BIOS32 service, and fill + * in the entry point information. + */ +int +bios32_service(service, e, ei) + u_int32_t service; + bios32_entry_t e; + bios32_entry_info_t ei; +{ + u_int32_t eax, ebx, ecx, edx; + paddr_t entry; + + if (bios32_entry.offset == 0) + return (0); /* BIOS32 not present */ + + __asm __volatile("lcall (%%edi)" + : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) + : "0" (service), "1" (0), "D" (&bios32_entry)); + + if ((eax & 0xff) != 0) + return (0); /* service not found */ + + entry = ebx + edx; + + if (entry < BIOS32_START || entry >= BIOS32_END) { + printf("bios32: entry point for service %c%c%c%c is outside " + "allowable range\n", + service & 0xff, + (service >> 8) & 0xff, + (service >> 16) & 0xff, + (service >> 24) & 0xff); + return (0); + } + + e->offset = (caddr_t)ISA_HOLE_VADDR(entry); + e->segment = GSEL(GCODE_SEL, SEL_KPL); + + ei->bei_base = ebx; + ei->bei_size = ecx; + ei->bei_entry = entry; + + return (1); +} diff --git a/sys/arch/i386/include/biosvar.h b/sys/arch/i386/include/biosvar.h index 2b77643e0d5..a80bf2f4a2d 100644 --- a/sys/arch/i386/include/biosvar.h +++ b/sys/arch/i386/include/biosvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: biosvar.h,v 1.34 2000/03/05 19:07:43 mickey Exp $ */ +/* $OpenBSD: biosvar.h,v 1.35 2000/03/26 22:38:33 mickey Exp $ */ /* * Copyright (c) 1997-1999 Michael Shalayeff @@ -61,6 +61,25 @@ #define BIOS_MAP_NVS 0x04 /* ACPI NVS memory */ /* + * BIOS32 + */ +typedef +struct bios32_entry_info { + paddr_t bei_base; + psize_t bei_size; + paddr_t bei_entry; +} *bios32_entry_info_t; + +typedef +struct bios32_entry { + caddr_t offset; + u_int16_t segment; +} __attribute__((__packed__)) *bios32_entry_t; + +#define BIOS32_MAKESIG(a, b, c, d) \ + ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24)) + +/* * CTL_BIOS definitions. */ #define BIOS_DEV 1 /* int: BIOS boot device */ @@ -192,6 +211,10 @@ int bioscngetc __P((dev_t)); void bioscnpollc __P((dev_t, int)); void bios_getopt __P((void)); +/* bios32.c */ +void bios32_init __P((void)); +int bios32_service __P((u_int32_t, bios32_entry_t, bios32_entry_info_t)); + extern u_int bootapiver; extern bios_memmap_t *bios_memmap; extern bios_pciinfo_t *bios_pciinfo; diff --git a/sys/arch/i386/pci/opti82c558.c b/sys/arch/i386/pci/opti82c558.c new file mode 100644 index 00000000000..74fd3280e3b --- /dev/null +++ b/sys/arch/i386/pci/opti82c558.c @@ -0,0 +1,248 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Copyright (c) 1999, by UCHIYAMA Yasushi + * 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. 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. + */ + +/* + * Support for the Opti 82c558 PCI-ISA bridge interrupt controller. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/malloc.h> + +#include <machine/intr.h> +#include <machine/bus.h> + +#include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> +#include <dev/pci/pcidevs.h> + +#include <i386/pci/pci_intr_fixup.h> +#include <i386/pci/opti82c558reg.h> + +int opti82c558_getclink __P((pciintr_icu_handle_t, int, int *)); +int opti82c558_get_intr __P((pciintr_icu_handle_t, int, int *)); +int opti82c558_set_intr __P((pciintr_icu_handle_t, int, int)); +int opti82c558_get_trigger __P((pciintr_icu_handle_t, int, int *)); +int opti82c558_set_trigger __P((pciintr_icu_handle_t, int, int)); + +const struct pciintr_icu opti82c558_pci_icu = { + opti82c558_getclink, + opti82c558_get_intr, + opti82c558_set_intr, + opti82c558_get_trigger, + opti82c558_set_trigger, +}; + +struct opti82c558_handle { + pci_chipset_tag_t ph_pc; + pcitag_t ph_tag; +}; + +static const int viper_pirq_decode[] = { + -1, 5, 9, 10, 11, 12, 14, 15 +}; + +static const int viper_pirq_encode[] = { + -1, /* 0 */ + -1, /* 1 */ + -1, /* 2 */ + -1, /* 3 */ + -1, /* 4 */ + VIPER_PIRQ_5, /* 5 */ + -1, /* 6 */ + -1, /* 7 */ + -1, /* 8 */ + VIPER_PIRQ_9, /* 9 */ + VIPER_PIRQ_10, /* 10 */ + VIPER_PIRQ_11, /* 11 */ + VIPER_PIRQ_12, /* 12 */ + -1, /* 13 */ + VIPER_PIRQ_14, /* 14 */ + VIPER_PIRQ_15, /* 15 */ +}; + +int +opti82c558_init(pc, iot, tag, ptagp, phandp) + pci_chipset_tag_t pc; + bus_space_tag_t iot; + pcitag_t tag; + pciintr_icu_tag_t *ptagp; + pciintr_icu_handle_t *phandp; +{ + struct opti82c558_handle *ph; + + ph = malloc(sizeof(*ph), M_DEVBUF, M_NOWAIT); + if (ph == NULL) + return (1); + + ph->ph_pc = pc; + ph->ph_tag = tag; + + *ptagp = &opti82c558_pci_icu; + *phandp = ph; + return (0); +} + +int +opti82c558_getclink(v, link, clinkp) + pciintr_icu_handle_t v; + int link, *clinkp; +{ + + if (VIPER_LEGAL_LINK(link - 1)) { + *clinkp = link - 1; + return (0); + } + + return (1); +} + +int +opti82c558_get_intr(v, clink, irqp) + pciintr_icu_handle_t v; + int clink, *irqp; +{ + struct opti82c558_handle *ph = v; + pcireg_t reg; + int val; + + if (VIPER_LEGAL_LINK(clink) == 0) + return (1); + + reg = pci_conf_read(ph->ph_pc, ph->ph_tag, VIPER_CFG_PIRQ); + val = VIPER_PIRQ(reg, clink); + *irqp = (val == VIPER_PIRQ_NONE) ? 0xff : viper_pirq_decode[val]; + + return (0); +} + +int +opti82c558_set_intr(v, clink, irq) + pciintr_icu_handle_t v; + int clink, irq; +{ + struct opti82c558_handle *ph = v; + int shift; + pcireg_t reg; + + if (VIPER_LEGAL_LINK(clink) == 0 || VIPER_LEGAL_IRQ(irq) == 0) + return (1); + + reg = pci_conf_read(ph->ph_pc, ph->ph_tag, VIPER_CFG_PIRQ); + shift = VIPER_PIRQ_SELECT_SHIFT * clink; + reg &= ~(VIPER_PIRQ_SELECT_MASK << shift); + reg |= (viper_pirq_encode[irq] << shift); + pci_conf_write(ph->ph_pc, ph->ph_tag, VIPER_CFG_PIRQ, reg); + + return (0); +} + +int +opti82c558_get_trigger(v, irq, triggerp) + pciintr_icu_handle_t v; + int irq, *triggerp; +{ + struct opti82c558_handle *ph = v; + pcireg_t reg; + + if (VIPER_LEGAL_IRQ(irq) == 0) { + /* ISA IRQ? */ + *triggerp = IST_EDGE; + return (0); + } + + reg = pci_conf_read(ph->ph_pc, ph->ph_tag, VIPER_CFG_PIRQ); + if ((reg >> (VIPER_CFG_TRIGGER_SHIFT + viper_pirq_encode[irq])) & 1) + *triggerp = IST_LEVEL; + else + *triggerp = IST_EDGE; + + return (0); +} + +int +opti82c558_set_trigger(v, irq, trigger) + pciintr_icu_handle_t v; + int irq, trigger; +{ + struct opti82c558_handle *ph = v; + int shift; + pcireg_t reg; + + if (VIPER_LEGAL_IRQ(irq) == 0) { + /* ISA IRQ? */ + return ((trigger != IST_LEVEL) ? 0 : 1); + } + + reg = pci_conf_read(ph->ph_pc, ph->ph_tag, VIPER_CFG_PIRQ); + shift = (VIPER_CFG_TRIGGER_SHIFT + viper_pirq_encode[irq]); + if (trigger == IST_LEVEL) + reg |= (1 << shift); + else + reg &= ~(1 << shift); + pci_conf_write(ph->ph_pc, ph->ph_tag, VIPER_CFG_PIRQ, reg); + + return (0); +} diff --git a/sys/arch/i386/pci/opti82c558reg.h b/sys/arch/i386/pci/opti82c558reg.h new file mode 100644 index 00000000000..f1279fa1c15 --- /dev/null +++ b/sys/arch/i386/pci/opti82c558reg.h @@ -0,0 +1,65 @@ +/* $NetBSD$ */ + +/* + * Copyright (c) 1999, by UCHIYAMA Yasushi + * 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. 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. + */ + +/* + * Register definitions for the Opti 82c558 PCI-ISA bridge interrupt + * controller. + */ + +/* + * PCI IRQ Select Register + */ + +#define VIPER_CFG_PIRQ 0x40 /* PCI configuration space */ + +/* + * Trigger setting: + * + * [1:7]=>5,9,10,11,12,14,15 Edge = 0 Level = 1 + */ +#define VIPER_CFG_TRIGGER_SHIFT 16 + +#define VIPER_LEGAL_LINK(link) ((link) >= 0 && (link) <= 3) + +#define VIPER_PIRQ_MASK 0xde20 +#define VIPER_LEGAL_IRQ(irq) ((irq) >= 0 && (irq) <= 15 && \ + ((1 << (irq)) & VIPER_PIRQ_MASK) != 0) + +#define VIPER_PIRQ_NONE 0 +#define VIPER_PIRQ_5 1 +#define VIPER_PIRQ_9 2 +#define VIPER_PIRQ_10 3 +#define VIPER_PIRQ_11 4 +#define VIPER_PIRQ_12 5 +#define VIPER_PIRQ_14 6 +#define VIPER_PIRQ_15 7 + +#define VIPER_PIRQ_SELECT_MASK 0x07 +#define VIPER_PIRQ_SELECT_SHIFT 3 + +#define VIPER_PIRQ(reg, x) (((reg) >> ((x) * VIPER_PIRQ_SELECT_SHIFT)) \ + & VIPER_PIRQ_SELECT_MASK) diff --git a/sys/arch/i386/pci/opti82c700.c b/sys/arch/i386/pci/opti82c700.c new file mode 100644 index 00000000000..423796b0a19 --- /dev/null +++ b/sys/arch/i386/pci/opti82c700.c @@ -0,0 +1,290 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Copyright (c) 1999, by UCHIYAMA Yasushi + * 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. 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. + */ + +/* + * Support for the Opti 82c700 PCI-ISA bridge interrupt controller. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/malloc.h> + +#include <machine/intr.h> +#include <machine/bus.h> + +#include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> +#include <dev/pci/pcidevs.h> + +#include <i386/pci/pci_intr_fixup.h> +#include <i386/pci/opti82c700reg.h> + +int opti82c700_getclink __P((pciintr_icu_handle_t, int, int *)); +int opti82c700_get_intr __P((pciintr_icu_handle_t, int, int *)); +int opti82c700_set_intr __P((pciintr_icu_handle_t, int, int)); +int opti82c700_get_trigger __P((pciintr_icu_handle_t, int, int *)); +int opti82c700_set_trigger __P((pciintr_icu_handle_t, int, int)); + +const struct pciintr_icu opti82c700_pci_icu = { + opti82c700_getclink, + opti82c700_get_intr, + opti82c700_set_intr, + opti82c700_get_trigger, + opti82c700_set_trigger, +}; + +struct opti82c700_handle { + pci_chipset_tag_t ph_pc; + pcitag_t ph_tag; +}; + +int opti82c700_addr __P((int, int *, int *)); + +int +opti82c700_init(pc, iot, tag, ptagp, phandp) + pci_chipset_tag_t pc; + bus_space_tag_t iot; + pcitag_t tag; + pciintr_icu_tag_t *ptagp; + pciintr_icu_handle_t *phandp; +{ + struct opti82c700_handle *ph; + + ph = malloc(sizeof(*ph), M_DEVBUF, M_NOWAIT); + if (ph == NULL) + return (1); + + ph->ph_pc = pc; + ph->ph_tag = tag; + + *ptagp = &opti82c700_pci_icu; + *phandp = ph; + return (0); +} + +int +opti82c700_addr(link, addrofs, ofs) + int link, *addrofs, *ofs; +{ + int regofs, src; + + regofs = FIRESTAR_PIR_REGOFS(link); + src = FIRESTAR_PIR_SELECTSRC(link); + + switch (src) { + case FIRESTAR_PIR_SELECT_NONE: + return (1); + + case FIRESTAR_PIR_SELECT_IRQ: + if (regofs < 0 || regofs > 7) + return (1); + *addrofs = FIRESTAR_CFG_INTR_IRQ + (regofs >> 2); + *ofs = (regofs & 3) << 3; + break; + + case FIRESTAR_PIR_SELECT_PIRQ: + case FIRESTAR_PIR_SELECT_BRIDGE: + if (regofs < 0 || regofs > 3) + return (1); + *addrofs = FIRESTAR_CFG_INTR_PIRQ; + *ofs = regofs << 2; + break; + + default: + return (1); + } + + return (0); +} + +int +opti82c700_getclink(v, link, clinkp) + pciintr_icu_handle_t v; + int link, *clinkp; +{ + + if (FIRESTAR_LEGAL_LINK(link)) { + *clinkp = link; + return (0); + } + + return (1); +} + +int +opti82c700_get_intr(v, clink, irqp) + pciintr_icu_handle_t v; + int clink, *irqp; +{ + struct opti82c700_handle *ph = v; + pcireg_t reg; + int val, addrofs, ofs; + + if (FIRESTAR_LEGAL_LINK(clink) == 0) + return (1); + + if (opti82c700_addr(clink, &addrofs, &ofs)) + return (1); + + reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); + val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK; + *irqp = (val == FIRESTAR_PIRQ_NONE) ? 0xff : val; + + return (0); +} + +int +opti82c700_set_intr(v, clink, irq) + pciintr_icu_handle_t v; + int clink, irq; +{ + struct opti82c700_handle *ph = v; + int addrofs, ofs; + pcireg_t reg; + + if (FIRESTAR_LEGAL_LINK(clink) == 0 || FIRESTAR_LEGAL_IRQ(irq) == 0) + return (1); + + if (opti82c700_addr(clink, &addrofs, &ofs)) + return (1); + + reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); + reg &= ~(FIRESTAR_CFG_PIRQ_MASK << ofs); + reg |= (irq << ofs); + pci_conf_write(ph->ph_pc, ph->ph_tag, addrofs, reg); + + return (0); +} + +int +opti82c700_get_trigger(v, irq, triggerp) + pciintr_icu_handle_t v; + int irq, *triggerp; +{ + struct opti82c700_handle *ph = v; + int i, val, addrofs, ofs; + pcireg_t reg; + + if (FIRESTAR_LEGAL_IRQ(irq) == 0) { + /* ISA IRQ? */ + *triggerp = IST_EDGE; + return (0); + } + + /* + * Search PCIDV1 registers. + */ + for (i = 0; i < 8; i++) { + opti82c700_addr(FIRESTAR_PIR_MAKELINK(FIRESTAR_PIR_SELECT_IRQ, + i), &addrofs, &ofs); + reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); + val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK; + if (val != irq) + continue; + val = ((reg >> ofs) >> FIRESTAR_TRIGGER_SHIFT) & + FIRESTAR_TRIGGER_MASK; + *triggerp = val ? IST_LEVEL : IST_EDGE; + return (0); + } + + return (1); +} + +int +opti82c700_set_trigger(v, irq, trigger) + pciintr_icu_handle_t v; + int irq, trigger; +{ + struct opti82c700_handle *ph = v; + int i, val, addrofs, ofs; + pcireg_t reg; + + if (FIRESTAR_LEGAL_IRQ(irq) == 0) { + /* ISA IRQ? */ + return ((trigger != IST_LEVEL) ? 0 : 1); + } + + /* + * Search PCIDV1 registers. + */ + for (i = 0; i < 8; i++) { + opti82c700_addr(FIRESTAR_PIR_MAKELINK(FIRESTAR_PIR_SELECT_IRQ, + i), &addrofs, &ofs); + reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs); + val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK; + if (val != irq) + continue; + if (trigger == IST_LEVEL) + reg |= (FIRESTAR_TRIGGER_MASK << + (FIRESTAR_TRIGGER_SHIFT + ofs)); + else + reg &= ~(FIRESTAR_TRIGGER_MASK << + (FIRESTAR_TRIGGER_SHIFT + ofs)); + pci_conf_write(ph->ph_pc, ph->ph_tag, addrofs, reg); + return (0); + } + + return (1); +} diff --git a/sys/arch/i386/pci/opti82c700reg.h b/sys/arch/i386/pci/opti82c700reg.h new file mode 100644 index 00000000000..21d0b3a45a4 --- /dev/null +++ b/sys/arch/i386/pci/opti82c700reg.h @@ -0,0 +1,71 @@ +/* $NetBSD$ */ + +/* + * Copyright (c) 1999, by UCHIYAMA Yasushi + * 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. 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. + */ + +/* + * Register definitions for the Opti 82c700 PCI-ISA bridge interrupt + * controller. + */ + +#define FIRESTAR_CFG_INTR_IRQ 0xb0 /* PCI configuration space */ +#define FIRESTAR_CFG_INTR_PIRQ 0xb8 /* PCI configuration space */ + +#define FIRESTAR_PIRQ_NONE 0 +#define FIRESTAR_PIRQ_MIN FIRESTAR_CFG_INTR_IRQ +#define FIRESTAR_PIRQ_MAX (FIRESTAR_CFG_INTR_PIRQ + 1) +#define FIRESTAR_LEGAL_LINK(link) ((link) >= FIRESTAR_PIRQ_MIN && \ + (link) <= FIRESTAR_PIRQ_MAX) + +#define FIRESTAR_PIRQ_MASK 0xdffa +#define FIRESTAR_LEGAL_IRQ(irq) ((irq) >= 0 && (irq) <= 15 && \ + ((1 << (irq)) & FIRESTAR_PIRQ_MASK) != 0) + +#define FIRESTAR_CFG_PIRQ_MASK 0x0f + +#define FIRESTAR_TRIGGER_MASK 0x01 +#define FIRESTAR_TRIGGER_SHIFT 4 + +/* + * Opti's suggested Link values. + */ +#define FIRESTAR_PIR_REGOFS_MASK 0x07 +#define FIRESTAR_PIR_REGOFS_SHIFT 4 +#define FIRESTAR_PIR_REGOFS(link) \ + (((link) >> FIRESTAR_PIR_REGOFS_SHIFT) & FIRESTAR_PIR_REGOFS_MASK) + +#define FIRESTAR_PIR_SELECTSRC_MASK 0x07 +#define FIRESTAR_PIR_SELECTSRC_SHIFT 0 +#define FIRESTAR_PIR_SELECTSRC(link) \ + (((link) >> FIRESTAR_PIR_SELECTSRC_SHIFT) & FIRESTAR_PIR_SELECTSRC_MASK) + +#define FIRESTAR_PIR_SELECT_NONE 0 +#define FIRESTAR_PIR_SELECT_IRQ 1 +#define FIRESTAR_PIR_SELECT_PIRQ 2 +#define FIRESTAR_PIR_SELECT_BRIDGE 3 + +#define FIRESTAR_PIR_MAKELINK(src, ofs) \ + (((src) << FIRESTAR_PIR_SELECTSRC_SHIFT) | \ + ((ofs) << FIRESTAR_PIR_REGOFS_SHIFT)) diff --git a/sys/arch/i386/pci/pci_bus_fixup.c b/sys/arch/i386/pci/pci_bus_fixup.c new file mode 100644 index 00000000000..57b7d0cfaa1 --- /dev/null +++ b/sys/arch/i386/pci/pci_bus_fixup.c @@ -0,0 +1,135 @@ +/* $NetBSD$ */ + +/* + * Copyright (c) 1999, by UCHIYAMA Yasushi + * 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. 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. + */ + +/* + * PCI bus renumbering support. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> + +#include <machine/bus.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> +#include <dev/pci/ppbreg.h> + +#include <i386/pci/pci_bus_fixup.h> +#include <i386/pci/pcibios.h> + +int +pci_bus_fixup(pc, bus) + pci_chipset_tag_t pc; + int bus; +{ + static int bus_total; + static int bridge_cnt; + int device, maxdevs, function, nfuncs, bridge, bus_max, bus_sub; + const struct pci_quirkdata *qd; + pcireg_t reg; + pcitag_t tag; + + bus_max = bus; + bus_sub = 0; + + if (++bus_total > 256) + panic("pci_bus_fixup: more than 256 PCI busses?"); + + maxdevs = pci_bus_maxdevs(pc, bus); + + for (device = 0; device < maxdevs; device++) { + tag = pci_make_tag(pc, bus, device, 0); + reg = pci_conf_read(pc, tag, PCI_ID_REG); + + /* Invalid vendor ID value? */ + if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID) + continue; + /* XXX Not invalid, but we've done this ~forever. */ + if (PCI_VENDOR(reg) == 0) + continue; + + qd = pci_lookup_quirkdata(PCI_VENDOR(reg), PCI_PRODUCT(reg)); + + reg = pci_conf_read(pc, tag, PCI_BHLC_REG); + if (PCI_HDRTYPE_MULTIFN(reg) || + (qd != NULL && + (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0)) + nfuncs = 8; + else + nfuncs = 1; + + for (function = 0; function < nfuncs; function++) { + tag = pci_make_tag(pc, bus, device, function); + reg = pci_conf_read(pc, tag, PCI_ID_REG); + + /* Invalid vendor ID value? */ + if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID) + continue; + /* XXX Not invalid, but we've done this ~forever. */ + if (PCI_VENDOR(reg) == 0) + continue; + + reg = pci_conf_read(pc, tag, PCI_CLASS_REG); + if (PCI_CLASS(reg) == PCI_CLASS_BRIDGE && + (PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_PCI || + PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_CARDBUS)) { + /* Assign the bridge #. */ + bridge = bridge_cnt++; + + /* Assign the bridge's secondary bus #. */ + bus_max++; + + reg = pci_conf_read(pc, tag, PPB_REG_BUSINFO); + reg &= 0xff000000; + reg |= bus | (bus_max << 8) | (0xff << 16); + pci_conf_write(pc, tag, PPB_REG_BUSINFO, reg); + + /* Scan subordinate bus. */ + bus_sub = pci_bus_fixup(pc, bus_max); + + /* Configure the bridge. */ + reg &= 0xff000000; + reg |= bus | (bus_max << 8) | (bus_sub << 16); + pci_conf_write(pc, tag, PPB_REG_BUSINFO, reg); + +#ifdef PCIBIOSVERBOSE + printf("PCI bridge %d: primary %d, " + "secondary %d, subordinate %d\n", + bridge, bus, bus_max, bus_sub); +#endif + + /* Next bridge's secondary bus #. */ + bus_max = (bus_sub > bus_max) ? + bus_sub : bus_max; + } + } + } + + return (bus_max); /* last # of subordinate bus */ +} diff --git a/sys/arch/i386/pci/pci_bus_fixup.h b/sys/arch/i386/pci/pci_bus_fixup.h new file mode 100644 index 00000000000..d93a3ac3427 --- /dev/null +++ b/sys/arch/i386/pci/pci_bus_fixup.h @@ -0,0 +1,28 @@ +/* $NetBSD$ */ + +/* + * Copyright (c) 1999, by UCHIYAMA Yasushi + * 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. 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. + */ + +int pci_bus_fixup __P((pci_chipset_tag_t, int)); diff --git a/sys/arch/i386/pci/pci_intr_fixup.c b/sys/arch/i386/pci/pci_intr_fixup.c new file mode 100644 index 00000000000..22f354f6887 --- /dev/null +++ b/sys/arch/i386/pci/pci_intr_fixup.c @@ -0,0 +1,696 @@ +/* $NetBSD: pci_intr_fixup.c,v 1.3 1999/12/13 15:42:05 uch Exp $ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Copyright (c) 1999, by UCHIYAMA Yasushi + * 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. 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. + */ + +/* + * PCI Interrupt Router support. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/queue.h> +#include <sys/device.h> + +#include <machine/bus.h> +#include <machine/intr.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> + +#include <i386/isa/icu.h> +#include <i386/pci/pci_intr_fixup.h> +#include <i386/pci/pcibios.h> + +struct pciintr_link_map { + int link; + int clink; + int irq; + u_int16_t bitmap; + int fixup_stage; + int old_irq; + SIMPLEQ_ENTRY(pciintr_link_map) list; +}; + +pciintr_icu_tag_t pciintr_icu_tag; +pciintr_icu_handle_t pciintr_icu_handle; + +struct pciintr_link_map *pciintr_link_lookup_pin + __P((struct pcibios_intr_routing *, int)); +struct pciintr_link_map *pciintr_link_lookup_link __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)); +int pciintr_link_init __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)); + +SIMPLEQ_HEAD(, pciintr_link_map) pciintr_link_map_list; + +const struct pciintr_icu_table { + pci_vendor_id_t piit_vendor; + pci_product_id_t piit_product; + int (*piit_init) __P((pci_chipset_tag_t, + bus_space_tag_t, pcitag_t, pciintr_icu_tag_t *, + pciintr_icu_handle_t *)); +} pciintr_icu_table[] = { + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371MX, + piix_init }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371AB_ISA, + piix_init }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371FB_ISA, + piix_init }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371SB_ISA, + piix_init }, + + { PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C558, + opti82c558_init }, + { PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C700, + opti82c700_init }, + + { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C586_ISA, + via82c586_init, }, + + { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_85C503, + sis85c503_init }, + + { 0, 0, + NULL }, +}; + +const struct pciintr_icu_table *pciintr_icu_lookup __P((pcireg_t)); + +const struct pciintr_icu_table * +pciintr_icu_lookup(id) + pcireg_t id; +{ + const struct pciintr_icu_table *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); +} + +struct pciintr_link_map * +pciintr_link_lookup_pin(pir, pin) + struct pcibios_intr_routing *pir; + int pin; +{ + + return (pciintr_link_lookup_link(pir->linkmap[pin].link)); +} + +struct pciintr_link_map * +pciintr_link_lookup_link(link) + int link; +{ + struct pciintr_link_map *l; + + for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; + 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; +{ + struct pciintr_link_map *l, *lstart; + + l = malloc(sizeof(*l), M_DEVBUF, M_NOWAIT); + if (l == NULL) + panic("pciintr_link_alloc"); + + memset(l, 0, sizeof(*l)); + + l->link = pir->linkmap[pin].link; + l->bitmap = pir->linkmap[pin].bitmap; + + lstart = SIMPLEQ_FIRST(&pciintr_link_map_list); + if (lstart == NULL || lstart->link < l->link) + SIMPLEQ_INSERT_TAIL(&pciintr_link_map_list, l, list); + else + SIMPLEQ_INSERT_HEAD(&pciintr_link_map_list, l, list); + + return (l); +} + +struct pcibios_intr_routing * +pciintr_pir_lookup(bus, device) + int bus, device; +{ + struct pcibios_intr_routing *pir; + int entry; + + if (pcibios_pir_table == NULL) + return (NULL); + + for (entry = 0; entry < pcibios_pir_table_nentries; entry++) { + pir = &pcibios_pir_table[entry]; + if (pir->bus == bus && ((pir->device >> 3) & 0x1f) == device) + return (pir); + } + + return (NULL); +} + +int +pciintr_link_init() +{ + int entry, pin, error, link, clink; + struct pcibios_intr_routing *pir; + struct pciintr_link_map *l; + + if (pcibios_pir_table == NULL) { + /* No PIR table; can't do anything. */ + printf("pciintr_link_init: no PIR table\n"); + return (1); + } + + error = 0; + SIMPLEQ_INIT(&pciintr_link_map_list); + + for (entry = 0; entry < pcibios_pir_table_nentries; entry++) { + pir = &pcibios_pir_table[entry]; + for (pin = 0; pin < 4; pin++) { + link = pir->linkmap[pin].link; + if (link == 0) { + /* No connection for this pin. */ + continue; + } + + /* + * Check the link value by asking the ICU for + * the canonical link value. + */ + if (pciintr_icu_getclink(pciintr_icu_tag, + pciintr_icu_handle, link, &clink) != 0) { + /* + * Table entry is bogus. Just ignore it. + */ +#ifdef PCIINTR_DEBUG + printf("pciintr_link_init: bad table entry: " + "bus %d device %d link 0x%02x\n", + pir->bus, (pir->device >> 3 & 0x1f), link); +#endif + 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_pin(pir, pin); + if (l == NULL) + (void) pciintr_link_alloc(pir, pin); + } + } + + return (error); +} + +int +pciintr_link_fixup() +{ + struct pciintr_link_map *l; + u_int16_t pciirq, bitmap; + int i, j, cnt, irq; + + /* + * First stage: Attempt to connect PIRQs which aren't + * yet connected. + */ + pciirq = 0; + + for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; + l = SIMPLEQ_NEXT(l, list)) { + /* + * Get the canonical link value for this entry. + */ + if (pciintr_icu_getclink(pciintr_icu_tag, pciintr_icu_handle, + l->link, &l->clink) != 0) { + /* + * ICU doesn't understand this link value. + */ +#ifdef PCIINTR_DEBUG + printf("pciintr_link_fixup: link 0x%02x invalid\n", + l->link); +#endif + l->clink = -1; + continue; + } + + /* + * Determine if this PIRQ is mapped to an IRQ. + */ + if (pciintr_icu_get_intr(pciintr_icu_tag, pciintr_icu_handle, + l->clink, &irq) != 0) { + /* + * ICU doesn't understand this PIRQ value. + */ + l->clink = -1; +#ifdef PCIINTR_DEBUG + printf("pciintr_link_fixup: PIRQ %d invalid\n", + l->clink); +#endif + continue; + } + + if (irq == 0xff) { + /* + * Interrupt isn't connected. Attempt to assign + * it to an IRQ. + */ +#ifdef PCIINTR_DEBUG + printf("pciintr_link_fixup: PIRQ %d not connected", + l->clink); +#endif + bitmap = l->bitmap; + for (i = 0, j = 0xff, cnt = 0; i < 16; i++) + if (bitmap & (1 << i)) + j = i, cnt++; + /* + * Just do the easy case now; we'll defer the + * harder ones to Stage 2. + */ + if (cnt == 1) { + l->irq = j; + l->old_irq = irq; + l->fixup_stage = 1; + pciirq |= 1 << j; +#ifdef PCIINTR_DEBUG + printf(", assigning IRQ %d", l->irq); +#endif + } +#ifdef PCIINTR_DEBUG + printf("\n"); +#endif + } else { + /* + * Interrupt is already connected. Don't do + * anything to it. + */ + l->irq = irq; + pciirq |= 1 << irq; +#ifdef PCIINTR_DEBUG + printf("pciintr_link_fixup: PIRQ %d already connected " + "to IRQ %d\n", l->clink, l->irq); +#endif + } + } + +#ifdef PCIBIOS_IRQS + /* In case the user supplied a mask for the PCI irqs we use it. */ + pciirq = PCIBIOS_IRQS; +#endif + + /* + * Stage 2: Attempt to connect PIRQs which we didn't + * connect in Stage 1. + */ + for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; + l = SIMPLEQ_NEXT(l, list)) { + if (l->irq == 0) { + bitmap = l->bitmap; + for (i = 0; i < 16; i++) { + if ((pciirq & (1 << i)) != 0 && + (bitmap & (1 << i)) != 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->irq = i; + l->old_irq = 0xff; + l->fixup_stage = 2; +#ifdef PCIINTR_DEBUG + printf("pciintr_link_fixup: assigning " + "IRQ %d to PIRQ %d\n", l->irq, + l->clink); +#endif + break; + } + } + } + } + + /* + * Stage 3: Allow the user to specify interrupt routing + * information, overriding what we've done above. + */ + /* XXX Not implemented. */ + + return (0); +} + +int +pciintr_link_route(pciirq) + u_int16_t *pciirq; +{ + struct pciintr_link_map *l; + int rv = 0; + + *pciirq = 0; + + for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL; + l = SIMPLEQ_NEXT(l, list)) { + 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 %d -> IRQ %d" + " failed\n", l->clink, l->irq); + rv = 1; + } else { + /* + * Succssfully routed interrupt. Mark this as + * a PCI interrupt. + */ + *pciirq |= (1 << l->irq); + } + } + + return (rv); +} + +int +pciintr_irq_release(pciirq) + u_int16_t *pciirq; +{ + int i; + + for (i = 0; i < 16; i++) { + if ((*pciirq & (1 << i)) == 0) + (void) pciintr_icu_set_trigger(pciintr_icu_tag, + pciintr_icu_handle, i, IST_EDGE); + } + + return (0); +} + +int +pciintr_header_fixup(pc) + pci_chipset_tag_t pc; +{ + const struct pci_quirkdata *qd; + struct pcibios_intr_routing *pir; + struct pciintr_link_map *l; + int pin, bus, device, function, maxdevs, nfuncs, irq, link; + pcireg_t id, bhlcr, intr; + pcitag_t tag; + +#ifdef PCIBIOSVERBOSE + printf("--------------------------------------------\n"); + printf(" device vendor product pin PIRQ IRQ stage\n"); + printf("--------------------------------------------\n"); +#endif + + for (bus = 0; bus <= pcibios_max_bus; bus++) { + maxdevs = pci_bus_maxdevs(pc, bus); + for (device = 0; device < maxdevs; device++) { + tag = pci_make_tag(pc, bus, device, 0); + id = pci_conf_read(pc, tag, PCI_ID_REG); + + /* Invalid vendor ID value? */ + if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) + continue; + /* XXX Not invalid, but we've done this ~forever. */ + if (PCI_VENDOR(id) == 0) + continue; + + qd = pci_lookup_quirkdata(PCI_VENDOR(id), + PCI_PRODUCT(id)); + + bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); + if (PCI_HDRTYPE_MULTIFN(bhlcr) || + (qd != NULL && + (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0)) + nfuncs = 8; + else + nfuncs = 1; + + for (function = 0; function < nfuncs; function++) { + tag = pci_make_tag(pc, bus, device, function); + id = pci_conf_read(pc, tag, PCI_ID_REG); + intr = pci_conf_read(pc, tag, + PCI_INTERRUPT_REG); + + /* Invalid vendor ID value? */ + if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) + continue; + /* + * XXX Not invalid, but we've done this + * ~forever. + */ + if (PCI_VENDOR(id) == 0) + continue; + + pin = PCI_INTERRUPT_PIN(intr); + irq = PCI_INTERRUPT_LINE(intr); + + if (pin == 0) { + /* + * No interrupt used. + */ + continue; + } + + pir = pciintr_pir_lookup(bus, device); + if (pir == NULL || + (link = pir->linkmap[pin - 1].link) == 0) { + /* + * Interrupt not connected; no + * need to change. + */ + continue; + } + + l = pciintr_link_lookup_link(link); + if (l == NULL) { + /* + * No link map entry?! + */ + printf("pciintr_header_fixup: no entry " + "for link 0x%02x (%d:%d:%d:%c)\n", + link, bus, device, function, + '@' + pin); + continue; + } + + /* + * IRQs 14 and 15 are reserved for + * PCI IDE interrupts; don't muck + * with them. + */ + if (irq == 14 || irq == 15) + continue; + +#ifdef PCIBIOSVERBOSE + printf("%03d:%02d:%d 0x%04x 0x%04x %c " + "0x%02x %02d %d\n", + bus, device, function, + PCI_VENDOR(id), PCI_PRODUCT(id), + '@' + pin, l->clink, l->irq, + l->fixup_stage); +#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); + } + } + } + +#ifdef PCIBIOSVERBOSE + printf("--------------------------------------------\n"); +#endif + + return (0); +} + +int +pci_intr_fixup(pc, iot, pciirq) + pci_chipset_tag_t pc; + bus_space_tag_t iot; + u_int16_t *pciirq; +{ + const struct pciintr_icu_table *piit = NULL; + pcitag_t icutag; + pcireg_t icuid; + + /* + * Attempt to initialize our PCI interrupt router. If + * the PIR Table is present in ROM, use the location + * specified by the PIR Table, and use the compat ID, + * if present. Otherwise, we have to look for the router + * ourselves (the PCI-ISA bridge). + */ + if (pcibios_pir_header.signature != 0) { + icutag = pci_make_tag(pc, pcibios_pir_header.router_bus, + (pcibios_pir_header.router_devfunc >> 3) & 0x1f, + pcibios_pir_header.router_devfunc & 7); + icuid = pcibios_pir_header.compat_router; + if (icuid == 0 || + (piit = pciintr_icu_lookup(icuid)) == NULL) { + /* + * No compat ID, or don't know the compat ID? Read + * it from the configuration header. + */ + icuid = pci_conf_read(pc, icutag, PCI_ID_REG); + } + if (piit == NULL) + piit = pciintr_icu_lookup(icuid); + } else { + int device, maxdevs = pci_bus_maxdevs(pc, 0); + + /* + * Search configuration space for a known interrupt + * router. + */ + for (device = 0; device < maxdevs; device++) { + icutag = pci_make_tag(pc, 0, device, 0); + icuid = pci_conf_read(pc, icutag, PCI_ID_REG); + + /* Invalid vendor ID value? */ + if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID) + continue; + /* XXX Not invalid, but we've done this ~forever. */ + if (PCI_VENDOR(icuid) == 0) + continue; + + piit = pciintr_icu_lookup(icuid); + if (piit != NULL) + break; + } + } + + if (piit == NULL) { + printf("pci_intr_fixup: no compatible PCI ICU found\n"); + return (-1); /* non-fatal */ + } + + /* + * Initialize the PCI ICU. + */ + if ((*piit->piit_init)(pc, iot, icutag, &pciintr_icu_tag, + &pciintr_icu_handle) != 0) + return (-1); /* non-fatal */ + + /* + * Initialize the PCI interrupt link map. + */ + if (pciintr_link_init()) + return (-1); /* non-fatal */ + + /* + * Fix up the link->IRQ mappings. + */ + 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! */ +} diff --git a/sys/arch/i386/pci/pci_intr_fixup.h b/sys/arch/i386/pci/pci_intr_fixup.h new file mode 100644 index 00000000000..feebdfb47f0 --- /dev/null +++ b/sys/arch/i386/pci/pci_intr_fixup.h @@ -0,0 +1,65 @@ +/* $NetBSD$ */ + +/* + * Copyright (c) 1999, by UCHIYAMA Yasushi + * 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. 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. + */ + +typedef void *pciintr_icu_handle_t; + +struct pciintr_icu { + int (*pi_getclink) __P((pciintr_icu_handle_t, int, int *)); + int (*pi_get_intr) __P((pciintr_icu_handle_t, int, int *)); + int (*pi_set_intr) __P((pciintr_icu_handle_t, int, int)); + int (*pi_get_trigger) __P((pciintr_icu_handle_t, int, int *)); + int (*pi_set_trigger) __P((pciintr_icu_handle_t, int, int)); +}; + +typedef const struct pciintr_icu *pciintr_icu_tag_t; + +#define pciintr_icu_getclink(t, h, link, pirqp) \ + (*(t)->pi_getclink)((h), (link), (pirqp)) +#define pciintr_icu_get_intr(t, h, pirq, irqp) \ + (*(t)->pi_get_intr)((h), (pirq), (irqp)) +#define pciintr_icu_set_intr(t, h, pirq, irq) \ + (*(t)->pi_set_intr)((h), (pirq), (irq)) +#define pciintr_icu_get_trigger(t, h, irq, triggerp) \ + (*(t)->pi_get_trigger)((h), (irq), (triggerp)) +#define pciintr_icu_set_trigger(t, h, irq, trigger) \ + (*(t)->pi_set_trigger)((h), (irq), (trigger)) + +int pci_intr_fixup __P((pci_chipset_tag_t, bus_space_tag_t, u_int16_t *)); + +/* + * Init functions for our known PCI ICUs. + */ +int piix_init __P((pci_chipset_tag_t, bus_space_tag_t, pcitag_t, + pciintr_icu_tag_t *, pciintr_icu_handle_t *)); +int opti82c558_init __P((pci_chipset_tag_t, bus_space_tag_t, pcitag_t, + pciintr_icu_tag_t *, pciintr_icu_handle_t *)); +int opti82c700_init __P((pci_chipset_tag_t, bus_space_tag_t, pcitag_t, + pciintr_icu_tag_t *, pciintr_icu_handle_t *)); +int via82c586_init __P((pci_chipset_tag_t, bus_space_tag_t, pcitag_t, + pciintr_icu_tag_t *, pciintr_icu_handle_t *)); +int sis85c503_init __P((pci_chipset_tag_t, bus_space_tag_t, pcitag_t, + pciintr_icu_tag_t *, pciintr_icu_handle_t *)); diff --git a/sys/arch/i386/pci/pcib.c b/sys/arch/i386/pci/pcib.c index ac3f00f9325..3004c1ef20a 100644 --- a/sys/arch/i386/pci/pcib.c +++ b/sys/arch/i386/pci/pcib.c @@ -80,7 +80,7 @@ pcibmatch(parent, match, aux) switch (PCI_PRODUCT(pa->pa_id)) { case PCI_PRODUCT_INTEL_SIO: case PCI_PRODUCT_INTEL_82371MX: - case PCI_PRODUCT_INTEL_82371AB: + case PCI_PRODUCT_INTEL_82371AB_ISA: /* The above bridges mis-identify themselves */ return (1); } diff --git a/sys/arch/i386/pci/pcibios.c b/sys/arch/i386/pci/pcibios.c new file mode 100644 index 00000000000..70e6b6a187b --- /dev/null +++ b/sys/arch/i386/pci/pcibios.c @@ -0,0 +1,475 @@ +/* $NetBSD: pcibios.c,v 1.1 1999/11/17 01:16:37 thorpej Exp $ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Copyright (c) 1999, by UCHIYAMA Yasushi + * 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. 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. + */ + +/* + * Interface to the PCI BIOS and PCI Interrupt Routing table. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/malloc.h> + +#include <dev/isa/isareg.h> +#include <i386/isa/isa_machdep.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> + +#include <i386/pci/pcibios.h> +#ifdef PCIBIOS_INTR_FIXUP +#include <i386/pci/pci_intr_fixup.h> +#endif +#ifdef PCIBIOS_BUS_FIXUP +#include <i386/pci/pci_bus_fixup.h> +#endif + +#ifdef __NetBSD__ +#include <machine/bios32.h> +#elif __OpenBSD__ +#include <machine/biosvar.h> +#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; + +void pcibios_pir_init __P((void)); + +int pcibios_get_status __P((u_int32_t *, u_int32_t *, u_int32_t *, + u_int32_t *, u_int32_t *, u_int32_t *, u_int32_t *)); +int pcibios_get_intr_routing __P((struct pcibios_intr_routing *, + int *, u_int16_t *)); + +int pcibios_return_code __P((u_int16_t, const char *)); + +void pcibios_print_exclirq __P((void)); +#ifdef PCIINTR_DEBUG +void pcibios_print_pir_table __P((void)); +#endif + +#define PCI_IRQ_TABLE_START 0xf0000 +#define PCI_IRQ_TABLE_END 0xfffff + +void +pcibios_init() +{ + struct bios32_entry_info ei; + u_int32_t rev_maj, rev_min, mech1, mech2, scmech1, scmech2; + + if (bios32_service(BIOS32_MAKESIG('$', 'P', 'C', 'I'), + &pcibios_entry, &ei) == 0) { + /* + * No PCI BIOS found; will fall back on old + * mechanism. + */ + return; + } + + /* + * We've located the PCI BIOS service; get some information + * about it. + */ + if (pcibios_get_status(&rev_maj, &rev_min, &mech1, &mech2, + &scmech1, &scmech2, &pcibios_max_bus) != PCIBIOS_SUCCESS) { + /* + * We can't use the PCI BIOS; will fall back on old + * mechanism. + */ + return; + } + + printf("PCI BIOS rev. %d.%d found at 0x%lx\n", rev_maj, rev_min >> 4, + ei.bei_entry); +#ifdef PCIBIOSVERBOSE + printf("pcibios: config mechanism %s%s, special cycles %s%s, " + "last bus %d\n", + mech1 ? "[1]" : "[x]", + mech2 ? "[2]" : "[x]", + scmech1 ? "[1]" : "[x]", + scmech2 ? "[2]" : "[x]", + pcibios_max_bus); + +#endif + + /* + * The PCI BIOS tells us the config mechanism; fill it in now + * so that pci_mode_detect() doesn't have to look for it. + */ + pci_mode = mech1 ? 1 : 2; + + pcibios_present = 1; + + /* + * Find the PCI IRQ Routing table. + */ + pcibios_pir_init(); + +#ifdef PCIBIOS_INTR_FIXUP + if (pcibios_pir_table != NULL) { + int rv; + u_int16_t pciirq; + + /* + * Fixup interrupt routing. + */ + rv = pci_intr_fixup(NULL, I386_BUS_SPACE_IO, &pciirq); + switch (rv) { + case -1: + /* Non-fatal error. */ + printf("Warning: unable to fix up PCI interrupt " + "routing\n"); + break; + + case 1: + /* Fatal error. */ + panic("pcibios_init: interrupt fixup failed"); + break; + } + + /* + * XXX Clear `pciirq' from the ISA interrupt allocation + * XXX mask. + */ + } +#endif + +#ifdef PCIBIOS_BUS_FIXUP + pcibios_max_bus = pci_bus_fixup(NULL, 0); +#ifdef PCIBIOSVERBOSE + printf("PCI bus #%d is the last bus\n", pcibios_max_bus); +#endif +#endif +} + +void +pcibios_pir_init() +{ + char devinfo[256]; + paddr_t pa; + caddr_t p; + unsigned char cksum; + u_int16_t tablesize; + u_int8_t rev_maj, rev_min; + int i; + + for (pa = PCI_IRQ_TABLE_START; pa < PCI_IRQ_TABLE_END; pa += 16) { + p = (caddr_t)ISA_HOLE_VADDR(pa); + if (*(int *)p != BIOS32_MAKESIG('$', 'P', 'I', 'R')) + continue; + + rev_min = *(p + 4); + rev_maj = *(p + 5); + tablesize = *(u_int16_t *)(p + 6); + + cksum = 0; + for (i = 0; i < tablesize; i++) + cksum += *(unsigned char *)(p + i); + + printf("PCI IRQ Routing Table rev. %d.%d found at 0x%lx, " + "size %d bytes (%d entries)\n", rev_maj, rev_min, pa, + tablesize, (tablesize - 32) / 16); + + if (cksum != 0) { + printf("pcibios_pir_init: bad IRQ table checksum\n"); + continue; + } + + if (tablesize < 32 || (tablesize % 16) != 0) { + printf("pcibios_pir_init: bad IRQ table size\n"); + continue; + } + + if (rev_maj != 1 || rev_min != 0) { + printf("pcibios_pir_init: unsupported IRQ table " + "version\n"); + continue; + } + + /* + * We can handle this table! Make a copy of it. + */ + bcopy(p, &pcibios_pir_header, 32); + pcibios_pir_table = malloc(tablesize - 32, M_DEVBUF, + M_NOWAIT); + if (pcibios_pir_table == NULL) { + printf("pcibios_pir_init: no memory for $PIR\n"); + return; + } + bcopy(p + 32, pcibios_pir_table, tablesize - 32); + pcibios_pir_table_nentries = (tablesize - 32) / 16; + + printf("PCI Interrupt Router at %03d:%02d:%01d", + pcibios_pir_header.router_bus, + (pcibios_pir_header.router_devfunc >> 3) & 0x1f, + pcibios_pir_header.router_devfunc & 7); + if (pcibios_pir_header.compat_router != 0) { + pci_devinfo(pcibios_pir_header.compat_router, 0, 0, + devinfo); + printf(" (%s)", devinfo); + } + printf("\n"); + pcibios_print_exclirq(); +#ifdef PCIINTR_DEBUG + pcibios_print_pir_table(); +#endif + return; + } + + /* + * If there was no PIR table found, try using the PCI BIOS + * Get Interrupt Routing call. + * + * XXX The interface to this call sucks; just allocate enough + * XXX room for 32 entries. + */ + pcibios_pir_table_nentries = 32; + pcibios_pir_table = malloc(pcibios_pir_table_nentries * + sizeof(*pcibios_pir_table), M_DEVBUF, M_NOWAIT); + if (pcibios_pir_table == NULL) { + printf("pcibios_pir_init: no memory for $PIR\n"); + return; + } + if (pcibios_get_intr_routing(pcibios_pir_table, + &pcibios_pir_table_nentries, + &pcibios_pir_header.exclusive_irq) != PCIBIOS_SUCCESS) { + printf("No PCI IRQ Routing information available.\n"); + free(pcibios_pir_table, M_DEVBUF); + pcibios_pir_table = NULL; + pcibios_pir_table_nentries = 0; + return; + } + printf("PCI BIOS has %d Interrupt Routing table entries\n", + pcibios_pir_table_nentries); + pcibios_print_exclirq(); +#ifdef PCIINTR_DEBUG + pcibios_print_pir_table(); +#endif +} + +int +pcibios_get_status(rev_maj, rev_min, mech1, mech2, scmech1, scmech2, maxbus) + u_int32_t *rev_maj, *rev_min, *mech1, *mech2, *scmech1, *scmech2, + *maxbus; +{ + u_int16_t ax, bx, cx; + u_int32_t edx; + int rv; + + __asm __volatile("lcall (%%edi) ; \ + jc 1f ; \ + xor %%ah, %%ah ; \ + 1:" + : "=a" (ax), "=b" (bx), "=c" (cx), "=d" (edx) + : "0" (0xb101), "D" (&pcibios_entry)); + + rv = pcibios_return_code(ax, "pcibios_get_status"); + if (rv != PCIBIOS_SUCCESS) + return (rv); + + if (edx != BIOS32_MAKESIG('P', 'C', 'I', ' ')) + return (PCIBIOS_SERVICE_NOT_PRESENT); /* XXX */ + + /* + * Fill in the various pieces if info we're looking for. + */ + *mech1 = ax & 1; + *mech2 = ax & (1 << 1); + *scmech1 = ax & (1 << 4); + *scmech2 = ax & (1 << 5); + *rev_maj = (bx >> 8) & 0xff; + *rev_min = bx & 0xff; + *maxbus = cx & 0xff; + + return (PCIBIOS_SUCCESS); +} + +int +pcibios_get_intr_routing(table, nentries, exclirq) + struct pcibios_intr_routing *table; + int *nentries; + u_int16_t *exclirq; +{ + u_int16_t ax, bx; + int rv; + struct { + u_int16_t size; + caddr_t offset; + u_int16_t segment; + } __attribute__((__packed__)) args; + + args.size = *nentries * sizeof(*table); + args.offset = (caddr_t)table; + args.segment = GSEL(GDATA_SEL, SEL_KPL); + + memset(table, 0, args.size); + + __asm __volatile("lcall (%%esi) ; \ + jc 1f ; \ + xor %%ah, %%ah ; \ + 1: movw %w2, %%ds ; \ + movw %w2, %%es" + : "=a" (ax), "=b" (bx) + : "r" GSEL(GDATA_SEL, SEL_KPL), "0" (0xb10e), "1" (0), + "D" (&args), "S" (&pcibios_entry)); + + rv = pcibios_return_code(ax, "pcibios_get_intr_routing"); + if (rv != PCIBIOS_SUCCESS) + return (rv); + + *nentries = args.size / sizeof(*table); + *exclirq = bx; + + return (PCIBIOS_SUCCESS); +} + +int +pcibios_return_code(ax, func) + u_int16_t ax; + const char *func; +{ + const char *errstr; + int rv = ax >> 8; + + switch (rv) { + case PCIBIOS_SUCCESS: + return (PCIBIOS_SUCCESS); + + case PCIBIOS_SERVICE_NOT_PRESENT: + errstr = "service not present"; + break; + + case PCIBIOS_FUNCTION_NOT_SUPPORTED: + errstr = "function not supported"; + break; + + case PCIBIOS_BAD_VENDOR_ID: + errstr = "bad vendor ID"; + break; + + case PCIBIOS_DEVICE_NOT_FOUND: + errstr = "device not found"; + break; + + case PCIBIOS_BAD_REGISTER_NUMBER: + errstr = "bad register number"; + break; + + case PCIBIOS_SET_FAILED: + errstr = "set failed"; + break; + + case PCIBIOS_BUFFER_TOO_SMALL: + errstr = "buffer too small"; + break; + + default: + printf("%s: unknown return code 0x%x\n", func, rv); + return (rv); + } + + printf("%s: %s\n", func, errstr); + return (rv); +} + +void +pcibios_print_exclirq() +{ + int i; + + if (pcibios_pir_header.exclusive_irq) { + printf("PCI Exclusive IRQs:"); + for (i = 0; i < 16; i++) { + if (pcibios_pir_header.exclusive_irq & (1 << i)) + printf(" %d", i); + } + printf("\n"); + } +} + +#ifdef PCIINTR_DEBUG +void +pcibios_print_pir_table() +{ + int i, j; + + for (i = 0; i < pcibios_pir_table_nentries; i++) { + printf("PIR Entry %d:\n", i); + printf("\tBus: %d Device: %d\n", + pcibios_pir_table[i].bus, + pcibios_pir_table[i].device >> 3); + for (j = 0; j < 4; j++) { + printf("\t\tINT%c: link 0x%02x bitmap 0x%04x\n", + 'A' + j, + pcibios_pir_table[i].linkmap[j].link, + pcibios_pir_table[i].linkmap[j].bitmap); + } + } +} +#endif diff --git a/sys/arch/i386/pci/pcibios.h b/sys/arch/i386/pci/pcibios.h new file mode 100644 index 00000000000..6b584c9c5ac --- /dev/null +++ b/sys/arch/i386/pci/pcibios.h @@ -0,0 +1,87 @@ +/* $NetBSD$ */ + +/* + * Copyright (c) 1999, by UCHIYAMA Yasushi + * 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. 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. + */ + +/* + * Data structure definitions for the PCI BIOS interface. + */ + +/* + * PCI BIOS return codes. + */ +#define PCIBIOS_SUCCESS 0x00 +#define PCIBIOS_SERVICE_NOT_PRESENT 0x80 +#define PCIBIOS_FUNCTION_NOT_SUPPORTED 0x81 +#define PCIBIOS_BAD_VENDOR_ID 0x83 +#define PCIBIOS_DEVICE_NOT_FOUND 0x86 +#define PCIBIOS_BAD_REGISTER_NUMBER 0x87 +#define PCIBIOS_SET_FAILED 0x88 +#define PCIBIOS_BUFFER_TOO_SMALL 0x89 + +/* + * PCI IRQ Routing Table definitions. + */ + +/* + * Slot entry (per PCI 2.1) + */ +struct pcibios_linkmap { + u_int8_t link; + u_int16_t bitmap; +} __attribute__((__packed__)); + +struct pcibios_intr_routing { + u_int8_t bus; + u_int8_t device; + struct pcibios_linkmap linkmap[4]; /* INT[A:D]# */ + u_int8_t slot; + u_int8_t reserved; +} __attribute__((__packed__)); + +/* + * $PIR header. Reference: + * + * http://www.microsoft.com/HWDEV/busbios/PCIIRQ.htm + */ +struct pcibios_pir_header { + u_int32_t signature; /* $PIR */ + u_int16_t version; + u_int16_t tablesize; + u_int8_t router_bus; + u_int8_t router_devfunc; + u_int16_t exclusive_irq; + u_int32_t compat_router; /* PCI vendor/product */ + u_int32_t miniport; + u_int8_t reserved[11]; + u_int8_t checksum; +} __attribute__((__packed__)); + +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; diff --git a/sys/arch/i386/pci/piix.c b/sys/arch/i386/pci/piix.c new file mode 100644 index 00000000000..19cbded0860 --- /dev/null +++ b/sys/arch/i386/pci/piix.c @@ -0,0 +1,237 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Copyright (c) 1999, by UCHIYAMA Yasushi + * 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. 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. + */ + +/* + * Support for the Intel PIIX PCI-ISA bridge interrupt controller. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/malloc.h> + +#include <machine/intr.h> +#include <machine/bus.h> + +#include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> +#include <dev/pci/pcidevs.h> + +#include <i386/pci/pci_intr_fixup.h> +#include <i386/pci/piixreg.h> +#include <i386/pci/piixvar.h> + +int piix_getclink __P((pciintr_icu_handle_t, int, int *)); +int piix_get_intr __P((pciintr_icu_handle_t, int, int *)); +int piix_set_intr __P((pciintr_icu_handle_t, int, int)); + +const struct pciintr_icu piix_pci_icu = { + piix_getclink, + piix_get_intr, + piix_set_intr, + piix_get_trigger, + piix_set_trigger, +}; + +int +piix_init(pc, iot, tag, ptagp, phandp) + pci_chipset_tag_t pc; + bus_space_tag_t iot; + pcitag_t tag; + pciintr_icu_tag_t *ptagp; + pciintr_icu_handle_t *phandp; +{ + struct piix_handle *ph; + + ph = malloc(sizeof(*ph), M_DEVBUF, M_NOWAIT); + if (ph == NULL) + return (1); + + ph->ph_iot = iot; + ph->ph_pc = pc; + ph->ph_tag = tag; + + if (bus_space_map(iot, PIIX_REG_ELCR, PIIX_REG_ELCR_SIZE, 0, + &ph->ph_elcr_ioh) != 0) { + free(ph, M_DEVBUF); + return (1); + } + + *ptagp = &piix_pci_icu; + *phandp = ph; + return (0); +} + +int +piix_getclink(v, link, clinkp) + pciintr_icu_handle_t v; + int link, *clinkp; +{ + + /* Pattern 1: simple. */ + if (PIIX_LEGAL_LINK(link - 1)) { + *clinkp = link - 1; + return (0); + } + + /* Pattern 2: configuration register offset */ + if (link >= 0x60 && link <= 0x63) { + *clinkp = link - 0x60; + return (0); + } + + return (1); +} + +int +piix_get_intr(v, clink, irqp) + pciintr_icu_handle_t v; + int clink, *irqp; +{ + struct piix_handle *ph = v; + int shift; + pcireg_t reg; + + if (PIIX_LEGAL_LINK(clink) == 0) + return (1); + + reg = pci_conf_read(ph->ph_pc, ph->ph_tag, PIIX_CFG_PIRQ); + shift = clink << 3; + if ((reg >> shift) & PIIX_CFG_PIRQ_NONE) + *irqp = 0xff; + else + *irqp = PIIX_PIRQ(reg, clink); + + return (0); +} + +int +piix_set_intr(v, clink, irq) + pciintr_icu_handle_t v; + int clink, irq; +{ + struct piix_handle *ph = v; + int shift; + pcireg_t reg; + + if (PIIX_LEGAL_LINK(clink) == 0 || PIIX_LEGAL_IRQ(irq) == 0) + return (1); + + reg = pci_conf_read(ph->ph_pc, ph->ph_tag, PIIX_CFG_PIRQ); + shift = clink << 3; + reg &= ~((PIIX_CFG_PIRQ_NONE | PIIX_CFG_PIRQ_MASK) << shift); + reg |= irq << shift; + pci_conf_write(ph->ph_pc, ph->ph_tag, PIIX_CFG_PIRQ, reg); + + return (0); +} + +int +piix_get_trigger(v, irq, triggerp) + pciintr_icu_handle_t v; + int irq, *triggerp; +{ + struct piix_handle *ph = v; + int off, bit; + u_int8_t elcr; + + if (PIIX_LEGAL_IRQ(irq) == 0) + return (1); + + off = (irq > 7) ? 1 : 0; + bit = irq & 7; + + elcr = bus_space_read_1(ph->ph_iot, ph->ph_elcr_ioh, off); + if (elcr & (1 << bit)) + *triggerp = IST_LEVEL; + else + *triggerp = IST_EDGE; + + return (0); +} + +int +piix_set_trigger(v, irq, trigger) + pciintr_icu_handle_t v; + int irq, trigger; +{ + struct piix_handle *ph = v; + int off, bit; + u_int8_t elcr; + + if (PIIX_LEGAL_IRQ(irq) == 0) + return (1); + + off = (irq > 7) ? 1 : 0; + bit = irq & 7; + + elcr = bus_space_read_1(ph->ph_iot, ph->ph_elcr_ioh, off); + if (trigger == IST_LEVEL) + elcr |= (1 << bit); + else + elcr &= ~(1 << bit); + bus_space_write_1(ph->ph_iot, ph->ph_elcr_ioh, off, elcr); + + return (0); +} diff --git a/sys/arch/i386/pci/piixreg.h b/sys/arch/i386/pci/piixreg.h new file mode 100644 index 00000000000..36f18b8eb73 --- /dev/null +++ b/sys/arch/i386/pci/piixreg.h @@ -0,0 +1,55 @@ +/* $NetBSD$ */ + +/* + * Copyright (c) 1999, by UCHIYAMA Yasushi + * 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. 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. + */ + +/* + * Register definitions for the Intel PIIX PCI-ISA bridge interrupt controller. + */ + +/* + * PIRQ[3:0]# - PIRQ ROUTE CONTROL REGISTERS + * + * PCI Configuration registers 0x60, 0x61, 0x62, 0x63 + */ + +#define PIIX_LEGAL_LINK(link) ((link) >= 0 && (link) <= 3) + +#define PIIX_PIRQ_MASK 0xdef8 +#define PIIX_LEGAL_IRQ(irq) ((irq) >= 0 && (irq) <= 15 && \ + ((1 << (irq)) & PIIX_PIRQ_MASK) != 0) + +#define PIIX_CFG_PIRQ 0x60 /* PCI configuration space */ +#define PIIX_CFG_PIRQ_NONE 0x80 +#define PIIX_CFG_PIRQ_MASK 0x0f +#define PIIX_PIRQ(reg, x) (((reg) >> ((x) << 3)) & 0xff) + +/* + * ELCR - EDGE/LEVEL CONTROL REGISTER + * + * PCI I/O registers 0x4d0, 0x4d1 + */ +#define PIIX_REG_ELCR 0x4d0 +#define PIIX_REG_ELCR_SIZE 2 diff --git a/sys/arch/i386/pci/piixvar.h b/sys/arch/i386/pci/piixvar.h new file mode 100644 index 00000000000..64b192cc513 --- /dev/null +++ b/sys/arch/i386/pci/piixvar.h @@ -0,0 +1,77 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Copyright (c) 1999, by UCHIYAMA Yasushi + * 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. 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. + */ + +/* + * Support for the Intel PIIX PCI-ISA bridge interrupt controller. + */ + +int piix_get_trigger __P((pciintr_icu_handle_t, int, int *)); +int piix_set_trigger __P((pciintr_icu_handle_t, int, int)); + +struct piix_handle { + bus_space_tag_t ph_iot; + bus_space_handle_t ph_elcr_ioh; + pci_chipset_tag_t ph_pc; + pcitag_t ph_tag; +}; diff --git a/sys/arch/i386/pci/sis85c503.c b/sys/arch/i386/pci/sis85c503.c new file mode 100644 index 00000000000..50c5fbf4357 --- /dev/null +++ b/sys/arch/i386/pci/sis85c503.c @@ -0,0 +1,180 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Copyright (c) 1999, by UCHIYAMA Yasushi + * 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. 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. + */ + +/* + * Support for the SiS 85c503 PCI-ISA bridge interrupt controller. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/intr.h> +#include <machine/bus.h> + +#include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> +#include <dev/pci/pcidevs.h> + +#include <i386/pci/pci_intr_fixup.h> +#include <i386/pci/sis85c503reg.h> +#include <i386/pci/piixvar.h> + +int sis85c503_getclink __P((pciintr_icu_handle_t, int, int *)); +int sis85c503_get_intr __P((pciintr_icu_handle_t, int, int *)); +int sis85c503_set_intr __P((pciintr_icu_handle_t, int, int)); + +const struct pciintr_icu sis85c503_pci_icu = { + sis85c503_getclink, + sis85c503_get_intr, + sis85c503_set_intr, + piix_get_trigger, + piix_set_trigger, +}; + +int +sis85c503_init(pc, iot, tag, ptagp, phandp) + pci_chipset_tag_t pc; + bus_space_tag_t iot; + pcitag_t tag; + pciintr_icu_tag_t *ptagp; + pciintr_icu_handle_t *phandp; +{ + + if (piix_init(pc, iot, tag, ptagp, phandp) == 0) { + *ptagp = &sis85c503_pci_icu; + return (0); + } + + return (1); +} + +int +sis85c503_getclink(v, link, clinkp) + pciintr_icu_handle_t v; + int link, *clinkp; +{ + + /* Pattern 1: simple. */ + if (link >= 1 && link <= 4) { + *clinkp = SIS85C503_CFG_PIRQ_REGSTART + link - 1; + return (0); + } + + /* Pattern 2: configuration register offset */ + if (link >= SIS85C503_CFG_PIRQ_REGSTART && + link <= SIS85C503_CFG_PIRQ_REGEND) { + *clinkp = link; + return (0); + } + + return (1); +} + +int +sis85c503_get_intr(v, clink, irqp) + pciintr_icu_handle_t v; + int clink, *irqp; +{ + struct piix_handle *ph = v; + pcireg_t reg; + + if (SIS85C503_LEGAL_LINK(clink) == 0) + return (1); + + reg = pci_conf_read(ph->ph_pc, ph->ph_tag, + SIS85C503_CFG_PIRQ_REGOFS(clink)); + reg = SIS85C503_CFG_PIRQ_REG(reg, clink); + + if (reg & SIS85C503_CFG_PIRQ_ROUTE_DISABLE) + *irqp = 0xff; + else + *irqp = reg & SIS85C503_CFG_PIRQ_INTR_MASK; + + return (0); +} + +int +sis85c503_set_intr(v, clink, irq) + pciintr_icu_handle_t v; + int clink, irq; +{ + struct piix_handle *ph = v; + int shift; + pcireg_t reg; + + if (SIS85C503_LEGAL_LINK(clink) == 0 || SIS85C503_LEGAL_IRQ(irq) == 0) + return (1); + + reg = pci_conf_read(ph->ph_pc, ph->ph_tag, + SIS85C503_CFG_PIRQ_REGOFS(clink)); + shift = SIS85C503_CFG_PIRQ_SHIFT(clink); + reg &= ~((SIS85C503_CFG_PIRQ_ROUTE_DISABLE | + SIS85C503_CFG_PIRQ_INTR_MASK) << shift); + reg |= (irq << shift); + pci_conf_write(ph->ph_pc, ph->ph_tag, SIS85C503_CFG_PIRQ_REGOFS(clink), + reg); + + return (0); +} diff --git a/sys/arch/i386/pci/sis85c503reg.h b/sys/arch/i386/pci/sis85c503reg.h new file mode 100644 index 00000000000..a96ef90836e --- /dev/null +++ b/sys/arch/i386/pci/sis85c503reg.h @@ -0,0 +1,52 @@ +/* $NetBSD$ */ + +/* + * Copyright (c) 1999, by UCHIYAMA Yasushi + * 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. 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. + */ + +/* + * Register definitions for the SiS 85c503 PCI-ISA bridge interrupt controller. + */ + +#define SIS85C503_CFG_PIRQ_REGSTART 0x41 /* PCI configuration space */ +#define SIS85C503_CFG_PIRQ_REGEND 0x44 + +#define SIS85C503_LEGAL_LINK(link) ((link) >= SIS85C503_CFG_PIRQ_REGSTART && \ + (link) <= SIS85C503_CFG_PIRQ_REGEND) + +#define SIS85C503_CFG_PIRQ_REGOFS(regofs) (((regofs) >> 2) << 2) +#define SIS85C503_CFG_PIRQ_SHIFT(regofs) \ + (((regofs) - SIS85C503_CFG_PIRQ_REGOFS(regofs)) << 3) + +#define SIS85C503_CFG_PIRQ_MASK 0xff +#define SIS85C503_CFG_PIRQ_INTR_MASK 0x0f + +#define SIS85C503_CFG_PIRQ_REG(reg, regofs) \ + (((reg) >> SIS85C503_CFG_PIRQ_SHIFT(regofs)) & SIS85C503_CFG_PIRQ_MASK) + +#define SIS85C503_CFG_PIRQ_ROUTE_DISABLE 0x80 + +#define SIS85C503_PIRQ_MASK 0xdef8 +#define SIS85C503_LEGAL_IRQ(irq) ((irq) >= 0 && (irq) <= 15 && \ + ((1 << (irq)) & SIS85C503_PIRQ_MASK) != 0) diff --git a/sys/arch/i386/pci/via82c586.c b/sys/arch/i386/pci/via82c586.c new file mode 100644 index 00000000000..021eaa2ff0c --- /dev/null +++ b/sys/arch/i386/pci/via82c586.c @@ -0,0 +1,270 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Copyright (c) 1999, by UCHIYAMA Yasushi + * 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. 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. + */ + +/* + * Support for the VIA 82c586 PCI-ISA bridge interrupt controller. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/intr.h> +#include <machine/bus.h> + +#include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> +#include <dev/pci/pcidevs.h> + +#include <i386/pci/pci_intr_fixup.h> +#include <i386/pci/via82c586reg.h> +#include <i386/pci/piixvar.h> + +int via82c586_getclink __P((pciintr_icu_handle_t, int, int *)); +int via82c586_get_intr __P((pciintr_icu_handle_t, int, int *)); +int via82c586_set_intr __P((pciintr_icu_handle_t, int, int)); +int via82c586_get_trigger __P((pciintr_icu_handle_t, int, int *)); +int via82c586_set_trigger __P((pciintr_icu_handle_t, int, int)); + +const struct pciintr_icu via82c586_pci_icu = { + via82c586_getclink, + via82c586_get_intr, + via82c586_set_intr, + via82c586_get_trigger, + via82c586_set_trigger, +}; + +const int vp3_cfg_trigger_shift[] = { + VP3_CFG_TRIGGER_SHIFT_PIRQA, + VP3_CFG_TRIGGER_SHIFT_PIRQB, + VP3_CFG_TRIGGER_SHIFT_PIRQC, + VP3_CFG_TRIGGER_SHIFT_PIRQD, +}; + +#define VP3_TRIGGER(reg, pirq) (((reg) >> vp3_cfg_trigger_shift[(pirq)]) & \ + VP3_CFG_TRIGGER_MASK) + +const int vp3_cfg_intr_shift[] = { + VP3_CFG_INTR_SHIFT_PIRQA, + VP3_CFG_INTR_SHIFT_PIRQB, + VP3_CFG_INTR_SHIFT_PIRQC, + VP3_CFG_INTR_SHIFT_PIRQD, +}; + +#define VP3_PIRQ(req, pirq) (((reg) >> vp3_cfg_intr_shift[(pirq)]) & \ + VP3_CFG_INTR_MASK) + +int +via82c586_init(pc, iot, tag, ptagp, phandp) + pci_chipset_tag_t pc; + bus_space_tag_t iot; + pcitag_t tag; + pciintr_icu_tag_t *ptagp; + pciintr_icu_handle_t *phandp; +{ + pcireg_t reg; + + if (piix_init(pc, iot, tag, ptagp, phandp) == 0) { + *ptagp = &via82c586_pci_icu; + + /* + * Enable EISA ELCR. + */ + reg = pci_conf_read(pc, tag, VP3_CFG_KBDMISCCTRL12_REG); + reg |= VP3_CFG_MISCCTRL2_EISA4D04D1PORT_ENABLE << + VP3_CFG_MISCCTRL2_SHIFT; + pci_conf_write(pc, tag, VP3_CFG_KBDMISCCTRL12_REG, reg); + + return (0); + } + + return (1); +} + +int +via82c586_getclink(v, link, clinkp) + pciintr_icu_handle_t v; + int link, *clinkp; +{ + + if (VP3_LEGAL_LINK(link - 1)) { + *clinkp = link - 1; + return (0); + } + + return (1); +} + +int +via82c586_get_intr(v, clink, irqp) + pciintr_icu_handle_t v; + int clink, *irqp; +{ + struct piix_handle *ph = v; + pcireg_t reg; + int val; + + if (VP3_LEGAL_LINK(clink) == 0) + return (1); + + reg = pci_conf_read(ph->ph_pc, ph->ph_tag, VP3_CFG_PIRQ_REG); + val = VP3_PIRQ(reg, clink); + *irqp = (val == VP3_PIRQ_NONE) ? 0xff : val; + + return (0); +} + +int +via82c586_set_intr(v, clink, irq) + pciintr_icu_handle_t v; + int clink, irq; +{ + struct piix_handle *ph = v; + int shift, val; + pcireg_t reg; + + if (VP3_LEGAL_LINK(clink) == 0 || VP3_LEGAL_IRQ(irq) == 0) + return (1); + + reg = pci_conf_read(ph->ph_pc, ph->ph_tag, VP3_CFG_PIRQ_REG); + via82c586_get_intr(v, clink, &val); + shift = vp3_cfg_intr_shift[clink]; + reg &= ~(VP3_CFG_INTR_MASK << shift); + reg |= (irq << shift); + pci_conf_write(ph->ph_pc, ph->ph_tag, VP3_CFG_PIRQ_REG, reg); + if (via82c586_get_intr(v, clink, &val) != 0 || + val != irq) + return (1); + + return (0); +} + +int +via82c586_get_trigger(v, irq, triggerp) + pciintr_icu_handle_t v; + int irq, *triggerp; +{ + struct piix_handle *ph = v; + int i, error, check_consistency, pciirq, pcitrigger = IST_NONE; + pcireg_t reg; + + if (VP3_LEGAL_IRQ(irq) == 0) + return (1); + + check_consistency = 0; + for (i = 0; i <= 3; i++) { + via82c586_get_intr(v, i, &pciirq); + if (pciirq == irq) { + reg = pci_conf_read(ph->ph_pc, ph->ph_tag, + VP3_CFG_PIRQ_REG); + if (VP3_TRIGGER(reg, i) == VP3_CFG_TRIGGER_EDGE) + pcitrigger = IST_EDGE; + else + pcitrigger = IST_LEVEL; + check_consistency = 1; + break; + } + } + + error = piix_get_trigger(v, irq, triggerp); + if (error == 0 && check_consistency && pcitrigger != *triggerp) + return (1); + return (error); +} + +int +via82c586_set_trigger(v, irq, trigger) + pciintr_icu_handle_t v; + int irq, trigger; +{ + struct piix_handle *ph = v; + int i, pciirq, shift, testtrig; + pcireg_t reg; + + if (VP3_LEGAL_IRQ(irq) == 0) + return (1); + + for (i = 0; i <= 3; i++) { + via82c586_get_intr(v, i, &pciirq); + if (pciirq == irq) { + reg = pci_conf_read(ph->ph_pc, ph->ph_tag, + VP3_CFG_PIRQ_REG); + shift = vp3_cfg_trigger_shift[i]; + if (trigger == IST_LEVEL) + reg &= ~(VP3_CFG_TRIGGER_MASK << shift); + else + reg |= (VP3_CFG_TRIGGER_EDGE << shift); + pci_conf_write(ph->ph_pc, ph->ph_tag, + VP3_CFG_PIRQ_REG, reg); + break; + } + } + + if (piix_set_trigger(v, irq, trigger) != 0 || + via82c586_get_trigger(v, irq, &testtrig) != 0 || + testtrig != trigger) + return (1); + + return (0); +} diff --git a/sys/arch/i386/pci/via82c586reg.h b/sys/arch/i386/pci/via82c586reg.h new file mode 100644 index 00000000000..fa812d1b1b8 --- /dev/null +++ b/sys/arch/i386/pci/via82c586reg.h @@ -0,0 +1,62 @@ +/* $NetBSD$ */ + +/* + * Copyright (c) 1999, by UCHIYAMA Yasushi + * 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. 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. + */ + +/* + * Register definitions for the VIA 82c586 PCI-ISA bridge interrupt controller. + */ + +#define VP3_CFG_PIRQ_REG 0x54 /* PCI configuration space */ +#define VP3_CFG_KBDMISCCTRL12_REG 0x44 +#define VP3_CFG_IDEMISCCTRL3_REG 0x48 + +#define VP3_CFG_MISCCTRL2_SHIFT 24 +#define VP3_CFG_MISCCTRL2_MASK 0x0f +#define VP3_CFG_MISCCTRL2_EISA4D04D1PORT_ENABLE 0x20 +#define VP3_CFG_MISCCTRL2_REG(reg) \ + (((reg) >> VP3_CFG_MISCCTRL2_SHIFT) & VP3_CFG_MISCCTRL2_MASK) + +#define VP3_CFG_TRIGGER_LEVEL 0 +#define VP3_CFG_TRIGGER_EDGE 1 + +#define VP3_CFG_TRIGGER_MASK 0x01 +#define VP3_CFG_TRIGGER_SHIFT_PIRQA 3 +#define VP3_CFG_TRIGGER_SHIFT_PIRQB 2 +#define VP3_CFG_TRIGGER_SHIFT_PIRQC 1 +#define VP3_CFG_TRIGGER_SHIFT_PIRQD 0 + +#define VP3_CFG_INTR_MASK 0x04 +#define VP3_PIRQ_MASK 0xdefa + +#define VP3_CFG_INTR_SHIFT_PIRQA 0x14 +#define VP3_CFG_INTR_SHIFT_PIRQB 0x10 +#define VP3_CFG_INTR_SHIFT_PIRQC 0x1c +#define VP3_CFG_INTR_SHIFT_PIRQD 0x0c + +#define VP3_PIRQ_NONE 0 +#define VP3_LEGAL_LINK(link) ((link) >= 0 && (link) <= 3) +#define VP3_LEGAL_IRQ(irq) ((irq) >= 0 && (irq) <= 15 && \ + ((1 << (irq)) & VP3_PIRQ_MASK) != 0) |