diff options
-rw-r--r-- | sys/amd64/include/pci_cfgreg.h | 48 | ||||
-rw-r--r-- | sys/amd64/pci/pci_bus.c | 653 | ||||
-rw-r--r-- | sys/amd64/pci/pci_cfgreg.c | 653 | ||||
-rw-r--r-- | sys/conf/files | 1 | ||||
-rw-r--r-- | sys/dev/pci/pci.c | 2181 | ||||
-rw-r--r-- | sys/dev/pci/pcireg.h | 446 | ||||
-rw-r--r-- | sys/dev/pci/pcivar.h | 406 | ||||
-rw-r--r-- | sys/i386/include/pci_cfgreg.h | 48 | ||||
-rw-r--r-- | sys/i386/isa/pcibus.c | 653 | ||||
-rw-r--r-- | sys/i386/isa/pcibus.h | 48 | ||||
-rw-r--r-- | sys/i386/pci/pci_bus.c | 653 | ||||
-rw-r--r-- | sys/i386/pci/pci_cfgreg.c | 653 | ||||
-rw-r--r-- | sys/i386/pci/pci_pir.c | 653 | ||||
-rw-r--r-- | sys/pci/pci.c | 2181 | ||||
-rw-r--r-- | sys/pci/pci_compat.c | 351 | ||||
-rw-r--r-- | sys/pci/pcireg.h | 446 | ||||
-rw-r--r-- | sys/pci/pcisupport.c | 28 | ||||
-rw-r--r-- | sys/pci/pcivar.h | 406 | ||||
-rw-r--r-- | sys/pci/tek390.c | 15 |
19 files changed, 3252 insertions, 7271 deletions
diff --git a/sys/amd64/include/pci_cfgreg.h b/sys/amd64/include/pci_cfgreg.h new file mode 100644 index 0000000..44556e7 --- /dev/null +++ b/sys/amd64/include/pci_cfgreg.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR 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. + * + * $Id$ + * + */ + +#define CONF1_ADDR_PORT 0x0cf8 +#define CONF1_DATA_PORT 0x0cfc + +#define CONF1_ENABLE 0x80000000ul +#define CONF1_ENABLE_CHK 0x80000000ul +#define CONF1_ENABLE_MSK 0x7ff00000ul +#define CONF1_ENABLE_CHK1 0xff000001ul +#define CONF1_ENABLE_MSK1 0x80000001ul +#define CONF1_ENABLE_RES1 0x80000000ul + +#define CONF2_ENABLE_PORT 0x0cf8 +#ifdef PC98 +#define CONF2_FORWARD_PORT 0x0cf9 +#else +#define CONF2_FORWARD_PORT 0x0cfa +#endif + +#define CONF2_ENABLE_CHK 0x0e +#define CONF2_ENABLE_RES 0x0e diff --git a/sys/amd64/pci/pci_bus.c b/sys/amd64/pci/pci_bus.c index 31de543..df84794 100644 --- a/sys/amd64/pci/pci_bus.c +++ b/sys/amd64/pci/pci_bus.c @@ -1,538 +1,265 @@ -/************************************************************************** -** -** $Id: pcibus.c,v 1.34 1997/04/09 09:16:27 se Exp $ -** -** pci bus subroutines for i386 architecture. -** -** FreeBSD -** -**------------------------------------------------------------------------- -** -** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR 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. -** -*************************************************************************** -*/ - -#include "vector.h" - -#include <sys/param.h> +/* + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR 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. + * + * $Id$ + * + */ + +#include <sys/types.h> #include <sys/systm.h> -#include <sys/kernel.h> - -#include <i386/isa/icu.h> -#include <i386/isa/isa_device.h> -#include <pci/pcivar.h> #include <pci/pcireg.h> -#include <pci/pcibus.h> - -/*----------------------------------------------------------------- -** -** The following functions are provided by the pci bios. -** They are used only by the pci configuration. -** -** pcibus_setup(): -** Probes for a pci system. -** Sets pci_maxdevice and pci_mechanism. -** -** pcibus_tag(): -** Creates a handle for pci configuration space access. -** This handle is given to the read/write functions. -** -** pcibus_ftag(): -** Creates a modified handle. -** -** pcibus_read(): -** Read a long word from the pci configuration space. -** Requires a tag (from pcitag) and the register -** number (should be a long word aligned one). -** -** pcibus_write(): -** Writes a long word to the pci configuration space. -** Requires a tag (from pcitag), the register number -** (should be a long word aligned one), and a value. -** -** pcibus_regirq(): -** Register an interrupt handler for a pci device. -** Requires a tag (from pcitag), the register number -** (should be a long word aligned one), and a value. -** -**----------------------------------------------------------------- -*/ - -static int -pcibus_check (void); - -static void -pcibus_setup (void); - -static pcici_t -pcibus_tag (u_char bus, u_char device, u_char func); - -static pcici_t -pcibus_ftag (pcici_t tag, u_char func); - -static u_long -pcibus_read (pcici_t tag, u_long reg); +#include <pci/pcivar.h> +#include <i386/isa/pcibus.h> -static void -pcibus_write (pcici_t tag, u_long reg, u_long data); +#ifdef PCI_COMPAT +/* XXX this is a terrible hack, which keeps the Tekram AMD SCSI driver happy */ +#define cfgmech pci_mechanism +int cfgmech; +#else +static int cfgmech; +#endif /* PCI_COMPAT */ +static int devmax; -static int -pcibus_ihandler_attach (int irq, inthand2_t *func, int arg, unsigned* maskptr); +/* enable configuration space accesses and return data port address */ static int -pcibus_ihandler_detach (int irq, inthand2_t *func); +pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) +{ + int dataport = 0; + + if (bus <= PCI_BUSMAX + && slot < devmax + && func <= PCI_FUNCMAX + && reg <= PCI_REGMAX + && bytes != 3 + && (unsigned) bytes <= 4 + && (reg & (bytes -1)) == 0) { + switch (cfgmech) { + case 1: + outl(CONF1_ADDR_PORT, + (bus << 16) | (slot << 11) | (func << 8) | reg); + dataport = CONF1_DATA_PORT; + break; + case 2: + outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); + outb(CONF2_FORWARD_PORT, bus); + dataport = 0xc000 | (slot << 8) | reg; + break; + } + } + return (dataport); +} -static int -pcibus_imask_include (int irq, unsigned* maskptr); +/* disable configuration space accesses */ -static int -pcibus_imask_exclude (int irq, unsigned* maskptr); - -static struct pcibus i386pci = { - "pci", - pcibus_setup, - pcibus_tag, - pcibus_ftag, - pcibus_read, - pcibus_write, - pcibus_ihandler_attach, - pcibus_ihandler_detach, - pcibus_imask_include, - pcibus_imask_exclude, -}; +static void +pci_cfgdisable(void) +{ + switch (cfgmech) { + case 1: + outl(CONF1_ADDR_PORT, 0); + break; + case 2: + outb(CONF2_ENABLE_PORT, 0); + outb(CONF2_FORWARD_PORT, 0); + break; + } +} -/* -** Announce structure to generic driver -*/ +/* read configuration space register */ -DATA_SET (pcibus_set, i386pci); +int +pci_cfgread(pcicfgregs *cfg, int reg, int bytes) +{ + int data = -1; + int port; -/*-------------------------------------------------------------------- -** -** Determine configuration mode -** -**-------------------------------------------------------------------- -*/ + port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); + if (port != 0) { + switch (bytes) { + case 1: + data = inb(port); + break; + case 2: + data = inw(port); + break; + case 4: + data = inl(port); + break; + } + pci_cfgdisable(); + } + return (data); +} -#define CONF1_ADDR_PORT 0x0cf8 -#define CONF1_DATA_PORT 0x0cfc +/* write configuration space register */ -#define CONF1_ENABLE 0x80000000ul -#define CONF1_ENABLE_CHK 0x80000000ul -#define CONF1_ENABLE_MSK 0x7ff00000ul -#define CONF1_ENABLE_CHK1 0xff000001ul -#define CONF1_ENABLE_MSK1 0x80000001ul -#define CONF1_ENABLE_RES1 0x80000000ul +void +pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) +{ + int port; -#define CONF2_ENABLE_PORT 0x0cf8 -#ifdef PC98 -#define CONF2_FORWARD_PORT 0x0cf9 -#else -#define CONF2_FORWARD_PORT 0x0cfa -#endif + port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); + if (port != 0) { + switch (bytes) { + case 1: + outb(port, data); + break; + case 2: + outw(port, data); + break; + case 4: + outl(port, data); + break; + } + pci_cfgdisable(); + } +} -#define CONF2_ENABLE_CHK 0x0e -#define CONF2_ENABLE_RES 0x0e +/* check whether the configuration mechanism has been correct identified */ static int -pcibus_check (void) +pci_cfgcheck(int maxdev) { u_char device; - if (bootverbose) printf ("pcibus_check:\tdevice "); + if (bootverbose) + printf("pci_cfgcheck:\tdevice "); - for (device = 0; device < pci_maxdevice; device++) { - unsigned long id, class, header; + for (device = 0; device < maxdev; device++) { + unsigned id, class, header; if (bootverbose) - printf ("%d ", device); - id = pcibus_read (pcibus_tag (0,device,0), 0); - if ((id == 0) || (id == 0xfffffffful)) + printf("%d ", device); + + id = inl(pci_cfgenable(0, device, 0, 0, 4)); + if (id == 0 || id == -1) continue; - class = pcibus_read (pcibus_tag (0,device,0), 8); + class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8; if (bootverbose) - printf ("[class=%x] ", class >> 8); - if ((class & 0xffffff00) == 0 || (class & 0xf8f0ff00) != 0) + printf("[class=%06x] ", class); + if (class == 0 || (class & 0xf8f0ff) != 0) continue; - header = pcibus_read (pcibus_tag (0,device,0), 12); + header = inb(pci_cfgenable(0, device, 0, 14, 1)); if (bootverbose) - printf ("[hdr=%x] ", (header >> 16) & 0xff); - if ((header & 0x007e0000) != 0) + printf("[hdr=%02x] ", header); + if ((header & 0x7e) != 0) continue; - if (bootverbose) printf ("is there (id=%08lx)\n", id); - return 1; + if (bootverbose) + printf("is there (id=%08x)\n", id); + + pci_cfgdisable(); + return (1); } if (bootverbose) - printf ("-- nothing found\n"); - return 0; + printf("-- nothing found\n"); + + pci_cfgdisable(); + return (0); } -static void -pcibus_setup (void) +int +pci_cfgopen(void) { unsigned long mode1res,oldval1; unsigned char mode2res,oldval2; - oldval1 = inl (CONF1_ADDR_PORT); + oldval1 = inl(CONF1_ADDR_PORT); if (bootverbose) { - printf ("pcibus_setup(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", oldval1); + printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", + oldval1); } - /*--------------------------------------- - ** Assume configuration mechanism 1 for now ... - **--------------------------------------- - */ - if ((oldval1 & CONF1_ENABLE_MSK) == 0) { - pci_mechanism = 1; - pci_maxdevice = 32; + cfgmech = 1; + devmax = 32; - outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK); - outb (CONF1_ADDR_PORT +3, 0); - mode1res = inl (CONF1_ADDR_PORT); - outl (CONF1_ADDR_PORT, oldval1); + outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); + outb(CONF1_ADDR_PORT +3, 0); + mode1res = inl(CONF1_ADDR_PORT); + outl(CONF1_ADDR_PORT, oldval1); if (bootverbose) - printf ("pcibus_setup(1a):\tmode1res=0x%08lx (0x%08lx)\n", - mode1res, CONF1_ENABLE_CHK); + printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", + mode1res, CONF1_ENABLE_CHK); if (mode1res) { - if (pcibus_check()) - return; - }; + if (pci_cfgcheck(32)) + return (cfgmech); + } - outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); + outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); mode1res = inl(CONF1_ADDR_PORT); - outl (CONF1_ADDR_PORT, oldval1); + outl(CONF1_ADDR_PORT, oldval1); if (bootverbose) - printf ("pcibus_setup(1b):\tmode1res=0x%08lx (0x%08lx)\n", - mode1res, CONF1_ENABLE_CHK1); + printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", + mode1res, CONF1_ENABLE_CHK1); if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { - if (pcibus_check()) - return; - }; + if (pci_cfgcheck(32)) + return (cfgmech); + } } - /*--------------------------------------- - ** Try configuration mechanism 2 ... - **--------------------------------------- - */ - - oldval2 = inb (CONF2_ENABLE_PORT); + oldval2 = inb(CONF2_ENABLE_PORT); if (bootverbose) { - printf ("pcibus_setup(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", oldval2); + printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", + oldval2); } if ((oldval2 & 0xf0) == 0) { - pci_mechanism = 2; - pci_maxdevice = 16; - - outb (CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); + cfgmech = 2; + devmax = 16; + + outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); mode2res = inb(CONF2_ENABLE_PORT); - outb (CONF2_ENABLE_PORT, oldval2); + outb(CONF2_ENABLE_PORT, oldval2); if (bootverbose) - printf ("pcibus_setup(2a):\tmode2res=0x%02x (0x%02x)\n", - mode2res, CONF2_ENABLE_CHK); + printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", + mode2res, CONF2_ENABLE_CHK); if (mode2res == CONF2_ENABLE_RES) { - if (bootverbose) - printf ("pcibus_setup(2a):\tnow trying mechanism 2\n"); - - if (pcibus_check()) - return; - } - } - - /*--------------------------------------- - ** No PCI bus host bridge found - **--------------------------------------- - */ - - pci_mechanism = 0; - pci_maxdevice = 0; -} - -/*-------------------------------------------------------------------- -** -** Build a pcitag from bus, device and function number -** -**-------------------------------------------------------------------- -*/ - -static pcici_t -pcibus_tag (unsigned char bus, unsigned char device, unsigned char func) -{ - pcici_t tag; - - tag.cfg1 = 0; - if (func >= 8) return tag; - - switch (pci_mechanism) { - - case 1: - if (device < 32) { - tag.cfg1 = CONF1_ENABLE - | (((u_long) bus ) << 16ul) - | (((u_long) device) << 11ul) - | (((u_long) func ) << 8ul); - } - break; - case 2: - if (device < 16) { - tag.cfg2.port = 0xc000 | (device << 8ul); - tag.cfg2.enable = 0xf0 | (func << 1ul); - tag.cfg2.forward = bus; - } - break; - }; - return tag; -} - -static pcici_t -pcibus_ftag (pcici_t tag, u_char func) -{ - switch (pci_mechanism) { - - case 1: - tag.cfg1 &= ~0x700ul; - tag.cfg1 |= (((u_long) func) << 8ul); - break; - case 2: - tag.cfg2.enable = 0xf0 | (func << 1ul); - break; - }; - return tag; -} - -/*-------------------------------------------------------------------- -** -** Read register from configuration space. -** -**-------------------------------------------------------------------- -*/ - -static u_long -pcibus_read (pcici_t tag, u_long reg) -{ - u_long addr, data = 0; - - if (!tag.cfg1) return (0xfffffffful); - - switch (pci_mechanism) { - - case 1: - addr = tag.cfg1 | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_read(1): addr=%x ", addr); -#endif - outl (CONF1_ADDR_PORT, addr); - data = inl (CONF1_DATA_PORT); - outl (CONF1_ADDR_PORT, 0 ); - break; - - case 2: - addr = tag.cfg2.port | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_read(2): addr=%x ", addr); -#endif - outb (CONF2_ENABLE_PORT , tag.cfg2.enable ); - outb (CONF2_FORWARD_PORT, tag.cfg2.forward); - - data = inl ((u_short) addr); - - outb (CONF2_ENABLE_PORT, 0); - outb (CONF2_FORWARD_PORT, 0); - break; - }; - -#ifdef PCI_DEBUG - printf ("data=%x\n", data); -#endif - - return (data); -} - -/*-------------------------------------------------------------------- -** -** Write register into configuration space. -** -**-------------------------------------------------------------------- -*/ - -static void -pcibus_write (pcici_t tag, u_long reg, u_long data) -{ - u_long addr; - - if (!tag.cfg1) return; - - switch (pci_mechanism) { - - case 1: - addr = tag.cfg1 | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_write(1): addr=%x data=%x\n", - addr, data); -#endif - outl (CONF1_ADDR_PORT, addr); - outl (CONF1_DATA_PORT, data); - outl (CONF1_ADDR_PORT, 0 ); - break; - - case 2: - addr = tag.cfg2.port | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_write(2): addr=%x data=%x\n", - addr, data); -#endif - outb (CONF2_ENABLE_PORT, tag.cfg2.enable); - outb (CONF2_FORWARD_PORT, tag.cfg2.forward); - - outl ((u_short) addr, data); - - outb (CONF2_ENABLE_PORT, 0); - outb (CONF2_FORWARD_PORT, 0); - break; - }; -} - -/*----------------------------------------------------------------------- -** -** Register an interrupt handler for a pci device. -** -**----------------------------------------------------------------------- -*/ - -static int -pcibus_ihandler_attach (int irq, inthand2_t *func, int arg, unsigned * maskptr) -{ - char buf[16]; - char *cp; - int free_id, id, result; + if (bootverbose) + printf("pci_open(2a):\tnow trying mechanism 2\n"); - sprintf(buf, "pci irq%d", irq); - for (cp = intrnames, free_id = 0, id = 0; id < NR_DEVICES; id++) { - if (strcmp(cp, buf) == 0) - break; - if (free_id <= 0 && strcmp(cp, "pci irqnn") == 0) - free_id = id; - while (*cp++ != '\0') - ; - } - if (id == NR_DEVICES) { - id = free_id; - if (id == 0) { - /* - * All pci irq counters are in use, perhaps because - * config is old so there aren't any. Abuse the - * clk0 counter. - */ - printf ( - "pcibus_ihandler_attach: counting pci irq%d's as clk0 irqs\n", - irq); + if (pci_cfgcheck(16)) + return (cfgmech); } } - result = register_intr( - irq, /* isa irq */ - id, /* device id */ - 0, /* flags? */ - func, /* handler */ - maskptr, /* mask pointer */ - arg); /* handler arg */ - - if (result) { - printf ("@@@ pcibus_ihandler_attach: result=%d\n", result); - return (result); - }; - update_intr_masks(); - - INTREN ((1ul<<irq)); - return (0); -} - -static int -pcibus_ihandler_detach (int irq, inthand2_t *func) -{ - int result; - - INTRDIS ((1ul<<irq)); - - result = unregister_intr (irq, func); - - if (result) - printf ("@@@ pcibus_ihandler_detach: result=%d\n", result); - - update_intr_masks(); - - return (result); -} - -static int -pcibus_imask_include (int irq, unsigned* maskptr) -{ - unsigned mask; - - if (!maskptr) return (0); - mask = 1ul << irq; - - if (*maskptr & mask) - return (-1); - - INTRMASK (*maskptr, mask); - update_intr_masks(); - - return (0); -} - -static int -pcibus_imask_exclude (int irq, unsigned* maskptr) -{ - unsigned mask; - - if (!maskptr) return (0); - - mask = 1ul << irq; - - if (! (*maskptr & mask)) - return (-1); - - INTRUNMASK (*maskptr, mask); - update_intr_masks(); - - return (0); + cfgmech = 0; + devmax = 0; + return (cfgmech); } diff --git a/sys/amd64/pci/pci_cfgreg.c b/sys/amd64/pci/pci_cfgreg.c index 31de543..df84794 100644 --- a/sys/amd64/pci/pci_cfgreg.c +++ b/sys/amd64/pci/pci_cfgreg.c @@ -1,538 +1,265 @@ -/************************************************************************** -** -** $Id: pcibus.c,v 1.34 1997/04/09 09:16:27 se Exp $ -** -** pci bus subroutines for i386 architecture. -** -** FreeBSD -** -**------------------------------------------------------------------------- -** -** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR 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. -** -*************************************************************************** -*/ - -#include "vector.h" - -#include <sys/param.h> +/* + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR 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. + * + * $Id$ + * + */ + +#include <sys/types.h> #include <sys/systm.h> -#include <sys/kernel.h> - -#include <i386/isa/icu.h> -#include <i386/isa/isa_device.h> -#include <pci/pcivar.h> #include <pci/pcireg.h> -#include <pci/pcibus.h> - -/*----------------------------------------------------------------- -** -** The following functions are provided by the pci bios. -** They are used only by the pci configuration. -** -** pcibus_setup(): -** Probes for a pci system. -** Sets pci_maxdevice and pci_mechanism. -** -** pcibus_tag(): -** Creates a handle for pci configuration space access. -** This handle is given to the read/write functions. -** -** pcibus_ftag(): -** Creates a modified handle. -** -** pcibus_read(): -** Read a long word from the pci configuration space. -** Requires a tag (from pcitag) and the register -** number (should be a long word aligned one). -** -** pcibus_write(): -** Writes a long word to the pci configuration space. -** Requires a tag (from pcitag), the register number -** (should be a long word aligned one), and a value. -** -** pcibus_regirq(): -** Register an interrupt handler for a pci device. -** Requires a tag (from pcitag), the register number -** (should be a long word aligned one), and a value. -** -**----------------------------------------------------------------- -*/ - -static int -pcibus_check (void); - -static void -pcibus_setup (void); - -static pcici_t -pcibus_tag (u_char bus, u_char device, u_char func); - -static pcici_t -pcibus_ftag (pcici_t tag, u_char func); - -static u_long -pcibus_read (pcici_t tag, u_long reg); +#include <pci/pcivar.h> +#include <i386/isa/pcibus.h> -static void -pcibus_write (pcici_t tag, u_long reg, u_long data); +#ifdef PCI_COMPAT +/* XXX this is a terrible hack, which keeps the Tekram AMD SCSI driver happy */ +#define cfgmech pci_mechanism +int cfgmech; +#else +static int cfgmech; +#endif /* PCI_COMPAT */ +static int devmax; -static int -pcibus_ihandler_attach (int irq, inthand2_t *func, int arg, unsigned* maskptr); +/* enable configuration space accesses and return data port address */ static int -pcibus_ihandler_detach (int irq, inthand2_t *func); +pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) +{ + int dataport = 0; + + if (bus <= PCI_BUSMAX + && slot < devmax + && func <= PCI_FUNCMAX + && reg <= PCI_REGMAX + && bytes != 3 + && (unsigned) bytes <= 4 + && (reg & (bytes -1)) == 0) { + switch (cfgmech) { + case 1: + outl(CONF1_ADDR_PORT, + (bus << 16) | (slot << 11) | (func << 8) | reg); + dataport = CONF1_DATA_PORT; + break; + case 2: + outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); + outb(CONF2_FORWARD_PORT, bus); + dataport = 0xc000 | (slot << 8) | reg; + break; + } + } + return (dataport); +} -static int -pcibus_imask_include (int irq, unsigned* maskptr); +/* disable configuration space accesses */ -static int -pcibus_imask_exclude (int irq, unsigned* maskptr); - -static struct pcibus i386pci = { - "pci", - pcibus_setup, - pcibus_tag, - pcibus_ftag, - pcibus_read, - pcibus_write, - pcibus_ihandler_attach, - pcibus_ihandler_detach, - pcibus_imask_include, - pcibus_imask_exclude, -}; +static void +pci_cfgdisable(void) +{ + switch (cfgmech) { + case 1: + outl(CONF1_ADDR_PORT, 0); + break; + case 2: + outb(CONF2_ENABLE_PORT, 0); + outb(CONF2_FORWARD_PORT, 0); + break; + } +} -/* -** Announce structure to generic driver -*/ +/* read configuration space register */ -DATA_SET (pcibus_set, i386pci); +int +pci_cfgread(pcicfgregs *cfg, int reg, int bytes) +{ + int data = -1; + int port; -/*-------------------------------------------------------------------- -** -** Determine configuration mode -** -**-------------------------------------------------------------------- -*/ + port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); + if (port != 0) { + switch (bytes) { + case 1: + data = inb(port); + break; + case 2: + data = inw(port); + break; + case 4: + data = inl(port); + break; + } + pci_cfgdisable(); + } + return (data); +} -#define CONF1_ADDR_PORT 0x0cf8 -#define CONF1_DATA_PORT 0x0cfc +/* write configuration space register */ -#define CONF1_ENABLE 0x80000000ul -#define CONF1_ENABLE_CHK 0x80000000ul -#define CONF1_ENABLE_MSK 0x7ff00000ul -#define CONF1_ENABLE_CHK1 0xff000001ul -#define CONF1_ENABLE_MSK1 0x80000001ul -#define CONF1_ENABLE_RES1 0x80000000ul +void +pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) +{ + int port; -#define CONF2_ENABLE_PORT 0x0cf8 -#ifdef PC98 -#define CONF2_FORWARD_PORT 0x0cf9 -#else -#define CONF2_FORWARD_PORT 0x0cfa -#endif + port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); + if (port != 0) { + switch (bytes) { + case 1: + outb(port, data); + break; + case 2: + outw(port, data); + break; + case 4: + outl(port, data); + break; + } + pci_cfgdisable(); + } +} -#define CONF2_ENABLE_CHK 0x0e -#define CONF2_ENABLE_RES 0x0e +/* check whether the configuration mechanism has been correct identified */ static int -pcibus_check (void) +pci_cfgcheck(int maxdev) { u_char device; - if (bootverbose) printf ("pcibus_check:\tdevice "); + if (bootverbose) + printf("pci_cfgcheck:\tdevice "); - for (device = 0; device < pci_maxdevice; device++) { - unsigned long id, class, header; + for (device = 0; device < maxdev; device++) { + unsigned id, class, header; if (bootverbose) - printf ("%d ", device); - id = pcibus_read (pcibus_tag (0,device,0), 0); - if ((id == 0) || (id == 0xfffffffful)) + printf("%d ", device); + + id = inl(pci_cfgenable(0, device, 0, 0, 4)); + if (id == 0 || id == -1) continue; - class = pcibus_read (pcibus_tag (0,device,0), 8); + class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8; if (bootverbose) - printf ("[class=%x] ", class >> 8); - if ((class & 0xffffff00) == 0 || (class & 0xf8f0ff00) != 0) + printf("[class=%06x] ", class); + if (class == 0 || (class & 0xf8f0ff) != 0) continue; - header = pcibus_read (pcibus_tag (0,device,0), 12); + header = inb(pci_cfgenable(0, device, 0, 14, 1)); if (bootverbose) - printf ("[hdr=%x] ", (header >> 16) & 0xff); - if ((header & 0x007e0000) != 0) + printf("[hdr=%02x] ", header); + if ((header & 0x7e) != 0) continue; - if (bootverbose) printf ("is there (id=%08lx)\n", id); - return 1; + if (bootverbose) + printf("is there (id=%08x)\n", id); + + pci_cfgdisable(); + return (1); } if (bootverbose) - printf ("-- nothing found\n"); - return 0; + printf("-- nothing found\n"); + + pci_cfgdisable(); + return (0); } -static void -pcibus_setup (void) +int +pci_cfgopen(void) { unsigned long mode1res,oldval1; unsigned char mode2res,oldval2; - oldval1 = inl (CONF1_ADDR_PORT); + oldval1 = inl(CONF1_ADDR_PORT); if (bootverbose) { - printf ("pcibus_setup(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", oldval1); + printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", + oldval1); } - /*--------------------------------------- - ** Assume configuration mechanism 1 for now ... - **--------------------------------------- - */ - if ((oldval1 & CONF1_ENABLE_MSK) == 0) { - pci_mechanism = 1; - pci_maxdevice = 32; + cfgmech = 1; + devmax = 32; - outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK); - outb (CONF1_ADDR_PORT +3, 0); - mode1res = inl (CONF1_ADDR_PORT); - outl (CONF1_ADDR_PORT, oldval1); + outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); + outb(CONF1_ADDR_PORT +3, 0); + mode1res = inl(CONF1_ADDR_PORT); + outl(CONF1_ADDR_PORT, oldval1); if (bootverbose) - printf ("pcibus_setup(1a):\tmode1res=0x%08lx (0x%08lx)\n", - mode1res, CONF1_ENABLE_CHK); + printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", + mode1res, CONF1_ENABLE_CHK); if (mode1res) { - if (pcibus_check()) - return; - }; + if (pci_cfgcheck(32)) + return (cfgmech); + } - outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); + outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); mode1res = inl(CONF1_ADDR_PORT); - outl (CONF1_ADDR_PORT, oldval1); + outl(CONF1_ADDR_PORT, oldval1); if (bootverbose) - printf ("pcibus_setup(1b):\tmode1res=0x%08lx (0x%08lx)\n", - mode1res, CONF1_ENABLE_CHK1); + printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", + mode1res, CONF1_ENABLE_CHK1); if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { - if (pcibus_check()) - return; - }; + if (pci_cfgcheck(32)) + return (cfgmech); + } } - /*--------------------------------------- - ** Try configuration mechanism 2 ... - **--------------------------------------- - */ - - oldval2 = inb (CONF2_ENABLE_PORT); + oldval2 = inb(CONF2_ENABLE_PORT); if (bootverbose) { - printf ("pcibus_setup(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", oldval2); + printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", + oldval2); } if ((oldval2 & 0xf0) == 0) { - pci_mechanism = 2; - pci_maxdevice = 16; - - outb (CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); + cfgmech = 2; + devmax = 16; + + outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); mode2res = inb(CONF2_ENABLE_PORT); - outb (CONF2_ENABLE_PORT, oldval2); + outb(CONF2_ENABLE_PORT, oldval2); if (bootverbose) - printf ("pcibus_setup(2a):\tmode2res=0x%02x (0x%02x)\n", - mode2res, CONF2_ENABLE_CHK); + printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", + mode2res, CONF2_ENABLE_CHK); if (mode2res == CONF2_ENABLE_RES) { - if (bootverbose) - printf ("pcibus_setup(2a):\tnow trying mechanism 2\n"); - - if (pcibus_check()) - return; - } - } - - /*--------------------------------------- - ** No PCI bus host bridge found - **--------------------------------------- - */ - - pci_mechanism = 0; - pci_maxdevice = 0; -} - -/*-------------------------------------------------------------------- -** -** Build a pcitag from bus, device and function number -** -**-------------------------------------------------------------------- -*/ - -static pcici_t -pcibus_tag (unsigned char bus, unsigned char device, unsigned char func) -{ - pcici_t tag; - - tag.cfg1 = 0; - if (func >= 8) return tag; - - switch (pci_mechanism) { - - case 1: - if (device < 32) { - tag.cfg1 = CONF1_ENABLE - | (((u_long) bus ) << 16ul) - | (((u_long) device) << 11ul) - | (((u_long) func ) << 8ul); - } - break; - case 2: - if (device < 16) { - tag.cfg2.port = 0xc000 | (device << 8ul); - tag.cfg2.enable = 0xf0 | (func << 1ul); - tag.cfg2.forward = bus; - } - break; - }; - return tag; -} - -static pcici_t -pcibus_ftag (pcici_t tag, u_char func) -{ - switch (pci_mechanism) { - - case 1: - tag.cfg1 &= ~0x700ul; - tag.cfg1 |= (((u_long) func) << 8ul); - break; - case 2: - tag.cfg2.enable = 0xf0 | (func << 1ul); - break; - }; - return tag; -} - -/*-------------------------------------------------------------------- -** -** Read register from configuration space. -** -**-------------------------------------------------------------------- -*/ - -static u_long -pcibus_read (pcici_t tag, u_long reg) -{ - u_long addr, data = 0; - - if (!tag.cfg1) return (0xfffffffful); - - switch (pci_mechanism) { - - case 1: - addr = tag.cfg1 | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_read(1): addr=%x ", addr); -#endif - outl (CONF1_ADDR_PORT, addr); - data = inl (CONF1_DATA_PORT); - outl (CONF1_ADDR_PORT, 0 ); - break; - - case 2: - addr = tag.cfg2.port | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_read(2): addr=%x ", addr); -#endif - outb (CONF2_ENABLE_PORT , tag.cfg2.enable ); - outb (CONF2_FORWARD_PORT, tag.cfg2.forward); - - data = inl ((u_short) addr); - - outb (CONF2_ENABLE_PORT, 0); - outb (CONF2_FORWARD_PORT, 0); - break; - }; - -#ifdef PCI_DEBUG - printf ("data=%x\n", data); -#endif - - return (data); -} - -/*-------------------------------------------------------------------- -** -** Write register into configuration space. -** -**-------------------------------------------------------------------- -*/ - -static void -pcibus_write (pcici_t tag, u_long reg, u_long data) -{ - u_long addr; - - if (!tag.cfg1) return; - - switch (pci_mechanism) { - - case 1: - addr = tag.cfg1 | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_write(1): addr=%x data=%x\n", - addr, data); -#endif - outl (CONF1_ADDR_PORT, addr); - outl (CONF1_DATA_PORT, data); - outl (CONF1_ADDR_PORT, 0 ); - break; - - case 2: - addr = tag.cfg2.port | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_write(2): addr=%x data=%x\n", - addr, data); -#endif - outb (CONF2_ENABLE_PORT, tag.cfg2.enable); - outb (CONF2_FORWARD_PORT, tag.cfg2.forward); - - outl ((u_short) addr, data); - - outb (CONF2_ENABLE_PORT, 0); - outb (CONF2_FORWARD_PORT, 0); - break; - }; -} - -/*----------------------------------------------------------------------- -** -** Register an interrupt handler for a pci device. -** -**----------------------------------------------------------------------- -*/ - -static int -pcibus_ihandler_attach (int irq, inthand2_t *func, int arg, unsigned * maskptr) -{ - char buf[16]; - char *cp; - int free_id, id, result; + if (bootverbose) + printf("pci_open(2a):\tnow trying mechanism 2\n"); - sprintf(buf, "pci irq%d", irq); - for (cp = intrnames, free_id = 0, id = 0; id < NR_DEVICES; id++) { - if (strcmp(cp, buf) == 0) - break; - if (free_id <= 0 && strcmp(cp, "pci irqnn") == 0) - free_id = id; - while (*cp++ != '\0') - ; - } - if (id == NR_DEVICES) { - id = free_id; - if (id == 0) { - /* - * All pci irq counters are in use, perhaps because - * config is old so there aren't any. Abuse the - * clk0 counter. - */ - printf ( - "pcibus_ihandler_attach: counting pci irq%d's as clk0 irqs\n", - irq); + if (pci_cfgcheck(16)) + return (cfgmech); } } - result = register_intr( - irq, /* isa irq */ - id, /* device id */ - 0, /* flags? */ - func, /* handler */ - maskptr, /* mask pointer */ - arg); /* handler arg */ - - if (result) { - printf ("@@@ pcibus_ihandler_attach: result=%d\n", result); - return (result); - }; - update_intr_masks(); - - INTREN ((1ul<<irq)); - return (0); -} - -static int -pcibus_ihandler_detach (int irq, inthand2_t *func) -{ - int result; - - INTRDIS ((1ul<<irq)); - - result = unregister_intr (irq, func); - - if (result) - printf ("@@@ pcibus_ihandler_detach: result=%d\n", result); - - update_intr_masks(); - - return (result); -} - -static int -pcibus_imask_include (int irq, unsigned* maskptr) -{ - unsigned mask; - - if (!maskptr) return (0); - mask = 1ul << irq; - - if (*maskptr & mask) - return (-1); - - INTRMASK (*maskptr, mask); - update_intr_masks(); - - return (0); -} - -static int -pcibus_imask_exclude (int irq, unsigned* maskptr) -{ - unsigned mask; - - if (!maskptr) return (0); - - mask = 1ul << irq; - - if (! (*maskptr & mask)) - return (-1); - - INTRUNMASK (*maskptr, mask); - update_intr_masks(); - - return (0); + cfgmech = 0; + devmax = 0; + return (cfgmech); } diff --git a/sys/conf/files b/sys/conf/files index f1b650f..0361768 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -343,6 +343,7 @@ pci/if_vx_pci.c optional vx device-driver pci/meteor.c optional meteor device-driver pci/ncr.c optional ncr device-driver pci/pci.c optional pci device-driver +pci/pci_compat.c optional pci pci/pcisupport.c optional pci pci/tek390.c optional amd device-driver pci/wdc_p.c optional wdc device-driver diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 4456fe6..b6f056e 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -1,1893 +1,459 @@ -/************************************************************************** -** -** $Id: pci.c,v 1.70 1997/04/26 11:46:18 peter Exp $ -** -** General subroutines for the PCI bus. -** pci_configure () -** -** FreeBSD -** -**------------------------------------------------------------------------- -** -** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR 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) 1997, Stefan Esser <se@freebsd.org> + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR 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. + * + * $Id$ + * + */ #include "pci.h" #if NPCI > 0 -/*======================================================== -** -** #includes and declarations -** -**======================================================== -*/ - -#include "opt_smp.h" +#include <stddef.h> +#include <sys/types.h> #include <sys/param.h> +#include <sys/time.h> #include <sys/systm.h> #include <sys/malloc.h> -#include <sys/errno.h> -#include <sys/kernel.h> -#include <sys/proc.h> /* declaration of wakeup(), used by vm.h */ +#include <sys/fcntl.h> #include <sys/conf.h> +#include <sys/kernel.h> #ifdef DEVFS #include <sys/devfsext.h> #endif /* DEVFS */ -#include <sys/fcntl.h> #include <vm/vm.h> -#include <vm/vm_param.h> #include <vm/pmap.h> - -#include <i386/isa/isa_device.h> /* XXX inthand2_t */ - -#include <pci/pcivar.h> #include <pci/pcireg.h> -#include <pci/pcibus.h> +#include <pci/pcivar.h> #include <pci/pci_ioctl.h> -/*======================================================== -** -** Structs and Functions -** -**======================================================== -*/ - -struct pcicb { - struct pcicb *pcicb_next; - struct pcicb *pcicb_up; - struct pcicb *pcicb_down; - pcici_t pcicb_bridge; - - u_char pcicb_bus; - u_char pcicb_subordinate; - u_int pcicb_mfrom; - u_int pcicb_mupto; - u_int pcicb_mamount; - u_short pcicb_pfrom; - u_short pcicb_pupto; - u_short pcicb_pamount; - u_char pcicb_bfrom; - u_char pcicb_bupto; - - u_long pcicb_iobase; - u_long pcicb_iolimit; - u_long pcicb_membase; - u_long pcicb_memlimit; - u_long pcicb_p_membase; - u_long pcicb_p_memlimit; -}; - -struct pci_lkm { - struct pci_device *dvp; - struct pci_lkm *next; -}; - -static void -not_supported (pcici_t tag, u_long type); - -static void -pci_bus_config (void); - -static void -pci_rescan (void); - -static void pci_attach (int bus, int dev, int func, - struct pci_device *dvp, const char *name); - -static int -pci_bridge_config (void); +/* return highest PCI bus number known to be used, or -1 if none */ static int -pci_mfdev (int bus, int device); - -static void pci_remember (int bus, int dev, int func, struct pci_device *dvp); - -/*======================================================== -** -** Variables -** -**======================================================== -*/ - -/* -** log2 of safe burst len (in words) -*/ - -unsigned pci_max_burst_len = 3; /* 2=16Byte, 3=32Byte, 4=64Byte, ... */ -unsigned pci_mechanism = 0; -unsigned pci_maxdevice = 0; -unsigned pciroots = 0; /* XXX pcisupport.c increments this - * for the Orion host to PCI bridge - * UGLY hack ... :( Will be changed :) - */ -/*-------------------------------------------------------- -** -** Local variables. -** -**-------------------------------------------------------- -*/ - -static struct pcibus *pcibus; - -static int pci_conf_count; -static int pci_info_done; -static int pcibusmax; -static struct pcicb *pcicb; - -static struct pci_conf *pci_dev_list; -static unsigned pci_dev_list_count; -static unsigned pci_dev_list_size; - -static struct pci_lkm *pci_lkm_head; - -/*----------------------------------------------------------------- -** -** The following functions are provided for the device driver -** to read/write the configuration space. -** -** pci_conf_read(): -** Read a long word from the pci configuration space. -** Requires a tag (from pcitag) and the register -** number (should be a long word alligned one). -** -** pci_conf_write(): -** Writes a long word to the pci configuration space. -** Requires a tag (from pcitag), the register number -** (should be a long word alligned one), and a value. -** -**----------------------------------------------------------------- -*/ - -u_long -pci_conf_read (pcici_t tag, u_long reg) -{ - return (pcibus->pb_read (tag, reg)); -} - -void -pci_conf_write (pcici_t tag, u_long reg, u_long data) -{ - pcibus->pb_write (tag, reg, data); -} - -/*======================================================== -** -** Subroutines for configuration. -** -**======================================================== -*/ - -static void -pci_register_io (struct pcicb * cb, u_int base, u_int limit) +pci_bushigh(void) { -#ifdef PCI_BRIDGE_DEBUG - if (bootverbose) - printf ("register_io: bus=%d base=%x limit=%x\n", - cb->pcicb_bus, base, limit); -#endif - - if (!cb->pcicb_pfrom || base < cb->pcicb_pfrom) - cb->pcicb_pfrom = base; - if (limit > cb->pcicb_pupto) - cb->pcicb_pupto = limit; - - /* - ** XXX should set bridge io mapping here - ** but it can be mapped in 4k blocks only, - ** leading to conflicts with isa/eisa .. - */ + if (pci_cfgopen() == 0) + return (-1); + return (0); } -static void -pci_register_memory (struct pcicb * cb, u_int base, u_int limit) -{ -#ifdef PCI_BRIDGE_DEBUG - if (bootverbose) - printf ("register_mem: bus=%d base=%x limit=%x\n", - cb->pcicb_bus, base, limit); -#endif +/* return base address of memory or port map */ - if (!cb->pcicb_mfrom || base < cb->pcicb_mfrom) - cb->pcicb_mfrom = base; - if (limit > cb->pcicb_mupto) - cb->pcicb_mupto = limit; - /* - ** set the bridges mapping - ** - ** XXX should handle the 1Mb granularity. - */ - if (cb->pcicb_bridge.tag) { - pci_conf_write(cb->pcicb_bridge, - PCI_PCI_BRIDGE_MEM_REG, - (cb->pcicb_memlimit & 0xffff0000) | - (cb->pcicb_membase >> 16)); - if (bootverbose) - printf ("\t[pci%d uses memory from %x to %x]\n", - cb->pcicb_bus, - (unsigned) cb->pcicb_membase, - (unsigned) cb->pcicb_memlimit); - } -} - -/* -** XXX This function is neither complete nor tested. -** It's only used if the bios hasn't done it's job -** of mapping the pci devices in the physical memory. -*/ - -static u_int -pci_memalloc (struct pcicb * cb, u_int addr, u_int size) +static int +pci_mapbase(unsigned mapreg) { - u_int result = 0, limit=0, newbase=0; -#ifdef PCI_BRIDGE_DEBUG - if (bootverbose) - printf ("memalloc: bus=%d addr=%x size=%x ..\n", - cb->pcicb_bus, addr, size); -#endif - - if (!cb) goto done; - - if (!cb->pcicb_membase) { - printf ("memalloc: bus%d: membase not set.\n", - cb->pcicb_bus); - goto done; - } - - /* - ** get upper allocation limit - */ - limit = cb->pcicb_memlimit; - if (cb->pcicb_mfrom && cb->pcicb_mfrom <= limit) - limit = cb->pcicb_mfrom-1; - - /* - ** address fixed, and impossible to allocate ? - */ - if (addr && addr+size-1 > limit) - goto done; - - /* - ** get possible address - */ - - result = addr; - if (!result) result = ((limit + 1) / size - 1) * size; - - /* - ** if not local available, request from parent. - */ - - if (result < cb->pcicb_membase) { - newbase = pci_memalloc (cb->pcicb_up, result, size); - if (newbase) cb->pcicb_membase = result; - else result=0; - } -done: - if (result) - pci_register_memory (cb, result, result+size-1); - -#ifdef PCI_BRIDGE_DEBUG - printf ("memalloc: bus=%d addr=%x size=%x --> %x (limit=%x).\n", - cb->pcicb_bus, addr, size, result, limit); -#endif - - return (result); + int mask = 0x03; + if ((mapreg & 0x01) == 0) + mask = 0x0f; + return (mapreg & ~mask); } -/*======================================================== -** -** pci_bridge_config() -** -** Configuration of a pci bridge. -** -**======================================================== -*/ +/* return map type of memory or port map */ static int -pci_bridge_config (void) -{ - pcici_t tag; - struct pcicb* parent; - - tag = pcicb->pcicb_bridge; - if (tag.tag) { - - if (!pcicb->pcicb_bus) { - u_int data; - /* - ** Get the lowest available bus number. - */ - pcicb->pcicb_bus = ++pcibusmax; - - /* - ** and configure the bridge - */ - data = pci_conf_read (tag, PCI_PCI_BRIDGE_BUS_REG); - data = PCI_PRIMARY_BUS_INSERT(data, pcicb->pcicb_up->pcicb_bus); - data = PCI_SECONDARY_BUS_INSERT(data, pcicb->pcicb_bus); - data = PCI_SUBORDINATE_BUS_INSERT(data, pcicb->pcicb_bus); - pci_conf_write (tag, PCI_PCI_BRIDGE_BUS_REG, data); - - /* - ** Propagate the new upper bus number limit. - */ - for (parent = pcicb->pcicb_up; parent != NULL; - parent = parent->pcicb_up) - { - if (parent->pcicb_subordinate >= pcicb->pcicb_bus) - continue; - parent->pcicb_subordinate = pcicb->pcicb_bus; - if (!parent->pcicb_bridge.tag) - continue; - data = pci_conf_read - (parent->pcicb_bridge, PCI_PCI_BRIDGE_BUS_REG); - data = PCI_SUBORDINATE_BUS_INSERT - (data, pcicb->pcicb_bus); - pci_conf_write (parent->pcicb_bridge, - PCI_PCI_BRIDGE_BUS_REG, data); - } - } - - if (!pcicb->pcicb_membase) { - u_int size = 0x100000; - pcicb->pcicb_membase = pci_memalloc (pcicb->pcicb_up, 0, size); - if (pcicb->pcicb_membase) - pcicb->pcicb_memlimit = pcicb->pcicb_membase+size-1; - } - } - return pcicb->pcicb_bus; -} - -/*======================================================== -** -** pci_attach() -** -** Attach one device -** -**======================================================== -*/ - -static void pci_attach (int bus, int dev, int func, - struct pci_device *dvp, const char *name) -{ - u_long data; - int unit; - u_char reg; - u_char pciint; - int irq; -#if defined(APIC_IO) - u_char airq = 0xff; - u_char rirq = 0xff; -#endif /* APIC_IO */ - pcici_t tag = pcibus->pb_tag (bus, dev, func); - - /* - ** Get and increment the unit. - */ - - unit = (*dvp->pd_count)++; - - /* - ** Announce this device - */ - - printf ("%s%d <%s> rev %d", dvp->pd_name, unit, name, - (unsigned) pci_conf_read (tag, PCI_CLASS_REG) & 0xff); - - /* - ** Get the int pin number (pci interrupt number a-d) - ** from the pci configuration space. - */ - - data = pci_conf_read (tag, PCI_INTERRUPT_REG); - pciint = PCI_INTERRUPT_PIN_EXTRACT(data); - - if (pciint) { - - printf (" int %c irq ", 0x60+pciint); - - irq = PCI_INTERRUPT_LINE_EXTRACT(data); - - /* - ** If it's zero, the isa irq number is unknown, - ** and we cannot bind the pci interrupt. - */ - -#if defined(APIC_IO) - if (irq && (irq != 0xff)) { - airq = get_pci_apic_irq (bus, dev, pciint); - if (airq != 0xff) { /* APIC IRQ exists */ - rirq = irq; /* 're-directed' IRQ */ - irq = airq; /* use APIC IRQ */ - } - printf ("%d", irq); - } -#else - if (irq && (irq != 0xff)) - printf ("%d", irq); -#endif /* APIC_IO */ - else - printf ("??"); +pci_maptype(unsigned mapreg) +{ + static u_int8_t maptype[0x10] = { + PCI_MAPMEM, PCI_MAPPORT, + PCI_MAPMEM, 0, + PCI_MAPMEM, PCI_MAPPORT, + 0, 0, + PCI_MAPMEM|PCI_MAPMEMP, PCI_MAPPORT, + PCI_MAPMEM|PCI_MAPMEMP, 0, + PCI_MAPMEM|PCI_MAPMEMP, PCI_MAPPORT, + 0, 0, }; - printf (" on pci%d:%d:%d\n", bus, dev, func); - -#if defined(APIC_IO) - if (airq != 0xff) { /* APIC IRQ exists */ - data = PCI_INTERRUPT_LINE_INSERT(data, airq); - pci_conf_write (tag, PCI_INTERRUPT_REG, data); - undirect_pci_irq (rirq); /* free for ISA card */ - } -#endif /* APIC_IO */ - - /* - ** Read the current mapping, - ** and update the pcicb fields. - */ - - data = pci_conf_read(tag, PCI_CLASS_REG); - data &= (PCI_CLASS_MASK|PCI_SUBCLASS_MASK); - switch (data) { - case PCI_CLASS_BRIDGE|PCI_SUBCLASS_BRIDGE_PCI: - break; - case PCI_CLASS_BRIDGE|PCI_SUBCLASS_BRIDGE_CARDBUS: { - u_int map, addr, size; - map = pci_conf_read(tag, PCI_CARDBUS_SOCKET_REG); - pci_conf_write (tag, PCI_CARDBUS_SOCKET_REG, 0xffffffff); - size = pci_conf_read(tag, PCI_CARDBUS_SOCKET_REG); - size = (~size) + 1; - addr = pci_memalloc (pcicb, map, size); - pci_conf_write (tag, PCI_CARDBUS_SOCKET_REG, addr); - pcicb->pcicb_mamount += size; - break; - } - default: - for (reg=PCI_MAP_REG_START;reg<PCI_MAP_REG_END;reg+=4) { - u_int map, addr, size; - - - map = pci_conf_read (tag, reg); - if (!(map & PCI_MAP_MEMORY_ADDRESS_MASK)) - continue; - - pci_conf_write (tag, reg, 0xffffffff); - data = pci_conf_read (tag, reg); - pci_conf_write (tag, reg, map); - - switch (data & 7) { - - default: - continue; - case 1: - case 5: - addr = map & PCI_MAP_IO_ADDRESS_MASK; - size = -(data & PCI_MAP_IO_ADDRESS_MASK); - size &= ~(addr ^ -addr); - - pci_register_io (pcicb, addr, addr+size-1); - pcicb->pcicb_pamount += size; - break; - - case 0: - case 2: - case 4: - size = -(data & PCI_MAP_MEMORY_ADDRESS_MASK); - addr = map & PCI_MAP_MEMORY_ADDRESS_MASK; - if (addr >= 0x100000) { - pci_register_memory (pcicb, addr, addr+size-1); - pcicb->pcicb_mamount += size; - }; - break; - } - if (bootverbose) - printf ("\tmapreg[%02x] type=%d addr=%08x size=%04x.\n", - reg, map&7, addr, size); - } - } - - /* - ** attach device - ** may produce additional log messages, - ** i.e. when installing subdevices. - */ - - (*dvp->pd_attach) (tag, unit); - - /* - ** Special processing of certain classes - */ - - data = pci_conf_read(tag, PCI_CLASS_REG); - - switch (data & (PCI_CLASS_MASK|PCI_SUBCLASS_MASK)) { - struct pcicb *this, **link; - unsigned char primary, secondary, subordinate; - u_int command; - - case PCI_CLASS_BRIDGE|PCI_SUBCLASS_BRIDGE_PCI: - - /* - ** get current configuration of the bridge. - */ - data = pci_conf_read (tag, PCI_PCI_BRIDGE_BUS_REG); - primary = PCI_PRIMARY_BUS_EXTRACT (data); - secondary = PCI_SECONDARY_BUS_EXTRACT(data); - subordinate = PCI_SUBORDINATE_BUS_EXTRACT(data); -#ifndef PCI_QUIET - if (bootverbose) { - printf ("\tbridge from pci%d to pci%d through %d.\n", - primary, secondary, subordinate); - printf ("\tmapping regs: io:%08lx mem:%08lx pmem:%08lx\n", - pci_conf_read (tag, PCI_PCI_BRIDGE_IO_REG), - pci_conf_read (tag, PCI_PCI_BRIDGE_MEM_REG), - pci_conf_read (tag, PCI_PCI_BRIDGE_PMEM_REG)); - } -#endif - /* - ** check for uninitialized bridge. - */ - if (!(primary < secondary - && secondary <= subordinate - && bus == primary)) { - - printf ("\tINCORRECTLY or NEVER CONFIGURED.\n"); - /* - ** disable this bridge - */ - pci_conf_write (tag, PCI_COMMAND_STATUS_REG, 0xffff0000); - secondary = 0; - subordinate = 0; - }; - - /* - ** allocate bus descriptor for bus behind the bridge - */ - link = &pcicb->pcicb_down; - while (*link && (*link)->pcicb_bus < secondary) - link = &(*link)->pcicb_next; - - this = malloc (sizeof (*this), M_DEVBUF, M_WAITOK); - - /* - ** Initialize this descriptor so far. - ** (the initialization is completed just before - ** scanning the bus behind the bridge. - */ - bzero (this, sizeof(*this)); - this->pcicb_next = *link; - this->pcicb_up = pcicb; - this->pcicb_bridge = tag; - this->pcicb_bus = secondary; - this->pcicb_subordinate = subordinate; - - command = pci_conf_read(tag,PCI_COMMAND_STATUS_REG); - - if (command & PCI_COMMAND_IO_ENABLE){ - /* - ** Bridge was configured by the bios. - ** Read out the mapped io region. - */ - unsigned reg; - - reg = pci_conf_read (tag, PCI_PCI_BRIDGE_IO_REG); - this->pcicb_iobase = PCI_PPB_IOBASE_EXTRACT (reg); - this->pcicb_iolimit = PCI_PPB_IOLIMIT_EXTRACT(reg); - - /* - ** Note the used io space. - */ - pci_register_io (pcicb, this->pcicb_iobase, - this->pcicb_iolimit); - - }; - - if (command & PCI_COMMAND_MEM_ENABLE) { - /* - ** Bridge was configured by the bios. - ** Read out the mapped memory regions. - */ - unsigned reg; - - /* - ** non prefetchable memory - */ - reg = pci_conf_read (tag, PCI_PCI_BRIDGE_MEM_REG); - this->pcicb_membase = PCI_PPB_MEMBASE_EXTRACT (reg); - this->pcicb_memlimit = PCI_PPB_MEMLIMIT_EXTRACT(reg); - - /* - ** Register used memory space. - */ - pci_register_memory (pcicb, - this->pcicb_membase, - this->pcicb_memlimit); - - /* - ** prefetchable memory - */ - reg = pci_conf_read (tag, PCI_PCI_BRIDGE_PMEM_REG); - this->pcicb_p_membase = PCI_PPB_MEMBASE_EXTRACT (reg); - this->pcicb_p_memlimit = PCI_PPB_MEMLIMIT_EXTRACT(reg); - - /* - ** Register used memory space. - */ - pci_register_memory (pcicb, - this->pcicb_p_membase, - this->pcicb_p_memlimit); - } - - /* - ** Link it in chain. - */ - *link=this; - - /* - ** Update mapping info of parent bus. - */ - if (!pcicb->pcicb_bfrom||secondary< pcicb->pcicb_bfrom) - pcicb->pcicb_bfrom = secondary; - if (subordinate > pcicb->pcicb_bupto) - pcicb->pcicb_bupto = subordinate; - } + return maptype[mapreg & 0x0f]; } -/*======================================================== -** -** pci_bus_config() -** -** Autoconfiguration of one pci bus. -** -**======================================================== -*/ +/* return log2 of map size decoded for memory or port map */ static int -pci_mfdev (int bus, int device) +pci_mapsize(unsigned testval) { - pcici_t tag0,tag1; - unsigned pci_id0, pci_id1; - - /* - ** Detect a multi-function device that complies to the PCI 2.0 spec - */ - tag0 = pcibus->pb_tag (bus, device, 0); - if (pci_conf_read (tag0, PCI_HEADER_MISC) & PCI_HEADER_MULTIFUNCTION) - return 1; - - /* - ** Well, as always: Theory and implementation of PCI ... - ** - ** If there is a valid device ID returned for function 1 AND - ** the device ID of function 0 and 1 is different OR - ** the first mapping register of 0 and 1 differs, - ** then assume a multi-function device anyway ... - ** - ** Example of such a broken device: ISA and IDE chip i83371FB (Triton) - */ - tag1 = pcibus->pb_tag (bus, device, 1); - pci_id1 = pci_conf_read (tag1, PCI_ID_REG); - - if (pci_id1 != 0xffffffff) { - - pci_id0 = pci_conf_read (tag0, PCI_ID_REG); - - if (pci_id0 != pci_id1) - return 1; - - if (pci_conf_read (tag0, PCI_MAP_REG_START) - != pci_conf_read (tag1, PCI_MAP_REG_START)) - return 1; - } - return 0; -} + int ln2size; -static void -pci_bus_config (void) -{ - int bus_no; - u_char device; - u_char reg; - pcici_t tag, mtag; - pcidi_t type; - - struct pci_device *dvp; - - /* - ** first initialize the bridge (bus controller chip) - */ - bus_no = pci_bridge_config (); - - printf ("Probing for devices on PCI bus %d:\n", bus_no); -#ifndef PCI_QUIET - if (bootverbose && !pci_info_done) { - pci_info_done=1; - printf ("\tconfiguration mode %d allows %d devices.\n", - pci_mechanism, pci_maxdevice); - }; -#endif - for (device=0; device<pci_maxdevice; device ++) { - char *name = NULL; - struct pci_device **dvpp; - int func, maxfunc = 0; - - for (func=0; func <= maxfunc; func++) { - tag = pcibus->pb_tag (bus_no, device, func); - type = pci_conf_read (tag, PCI_ID_REG); - - if ((!type) || (type==0xfffffffful)) continue; - - /* - ** lookup device in ioconfiguration: - */ - - dvpp = (struct pci_device **)pcidevice_set.ls_items; - - while (dvp = *dvpp++) { - if (dvp->pd_probe) { - if (name=(*dvp->pd_probe)(tag, type)) - break; - } - }; - /* - ** check for mirrored devices. - */ - if (func != 0) { - goto real_device; - } - if (device & 0x10) { - mtag=pcibus->pb_tag (bus_no, - (u_char)(device & ~0x10), 0); - } else if (device & 0x08) { - mtag=pcibus->pb_tag (bus_no, - (u_char)(device & ~0x08), 0); - } else goto real_device; - - if (type!=pci_conf_read (mtag, PCI_ID_REG)) - goto real_device; - - for (reg=PCI_MAP_REG_START;reg<PCI_MAP_REG_END;reg+=4) - if (pci_conf_read(tag,reg)!=pci_conf_read(mtag,reg)) - goto real_device; - -#ifndef PCI_QUIET - if (dvp==NULL) continue; - if (bootverbose) - printf ("%s? <%s> mirrored on pci%d:%d\n", - dvp->pd_name, name, bus_no, device); -#endif - continue; - - real_device: - -#ifndef PCI_QUIET -#ifdef PCI_BRIDGE_DEBUG - if (bootverbose) { - printf ("\tconfig header: 0x%08x 0x%08x 0x%08x 0x%08x\n", - pci_conf_read (tag, 0), - pci_conf_read (tag, 4), - pci_conf_read (tag, 8), - pci_conf_read (tag, 12)); - } -#endif -#endif - - if (func == 0 && pci_mfdev (bus_no, device)) { - maxfunc = 7; - } - - pci_remember(bus_no, device, func, dvp); - - if (dvp==NULL) { -#ifndef PCI_QUIET - if (pci_conf_count) - continue; - - if (maxfunc == 0) - printf("%s%d:%d: ", - pcibus->pb_name, bus_no, device); - else - printf("%s%d:%d:%d: ", - pcibus->pb_name, bus_no, device, func); - not_supported (tag, type); -#endif - continue; - }; - - if (*name) { - pci_attach (bus_no, device, func, dvp, name); - } - } - } - -#ifndef PCI_QUIET - if (bootverbose) { - if (pcicb->pcicb_mamount) - printf ("%s%d: uses %ud bytes of memory from %x upto %x.\n", - pcibus->pb_name, bus_no, - pcicb->pcicb_mamount, - pcicb->pcicb_mfrom, pcicb->pcicb_mupto); - if (pcicb->pcicb_pamount) - printf ("%s%d: uses %ud bytes of I/O space from %x upto %x.\n", - pcibus->pb_name, bus_no, - pcicb->pcicb_pamount, - pcicb->pcicb_pfrom, pcicb->pcicb_pupto); - if (pcicb->pcicb_bfrom) - printf ("%s%d: subordinate busses from %x upto %x.\n", - pcibus->pb_name, bus_no, - pcicb->pcicb_bfrom, pcicb->pcicb_bupto); + testval = pci_mapbase(testval); + ln2size = 32; + while ((testval & 0x80000000) != 0) + { + ln2size--; + testval <<= 1; } -#endif + return (ln2size); } -/*======================================================== -** -** pci_configure () -** -** Autoconfiguration of pci devices. -** -** Has to take care of mirrored devices, which are -** entailed by incomplete decoding of pci address lines. -** -**======================================================== -*/ - -void pci_configure() -{ - struct pcibus **pbp = (struct pcibus**) pcibus_set.ls_items; - - /* - ** check pci bus present - */ +/* return log2 of address range supported by map register */ - while (!pci_maxdevice && (pcibus = *pbp++)) { - (*pcibus->pb_setup)(); - } - - if (!pci_maxdevice) return; - - /* - ** hello world .. - */ - - pciroots = 1; - while (pciroots--) { - - pcicb = malloc (sizeof (struct pcicb), M_DEVBUF, M_WAITOK); - if (pcicb == NULL) { - return; - } - bzero (pcicb, sizeof (struct pcicb)); - pcicb->pcicb_bus = pcibusmax; - pcicb->pcicb_iolimit = 0xffff; - pcicb->pcicb_membase = 0x02000000; - pcicb->pcicb_p_membase = 0x02000000; - pcicb->pcicb_memlimit = 0xffffffff; - pcicb->pcicb_p_memlimit = 0xffffffff; - - while (pcicb != NULL) { - pci_bus_config (); - - if (pcibusmax < pcicb->pcicb_bus) - (pcibusmax = pcicb->pcicb_bus); - - if (pcicb->pcicb_down) { - pcicb = pcicb->pcicb_down; - continue; - }; - - while (pcicb && !pcicb->pcicb_next) - pcicb = pcicb->pcicb_up; - - if (pcicb) - pcicb = pcicb->pcicb_next; - } - pcibusmax++; +static int +pci_maprange(unsigned mapreg) +{ + int ln2range = 0; + switch (mapreg & 0x07) { + case 0x00: + case 0x01: + case 0x05: + ln2range = 32; + break; + case 0x02: + ln2range = 20; + break; + case 0x04: + ln2range = 64; + break; } - pci_conf_count++; + return (ln2range); } -/*======================================================== -** -** pci_rescan () -** -** try to find lkm driver for device -** -** May be called more than once. -** Any device is attached only once. -** -**======================================================== -*/ - -static void pci_rescan() +/* extract map parameters into newly allocated array of pcimap structures */ + +static pcimap * +pci_readmaps(pcicfgregs *cfg, int maxmaps) { int i; - for (i = 0; i < pci_dev_list_count; i++) - { - struct pci_lkm *lkm; - pcici_t tag; - struct pci_device *dvp; - pcidi_t type = pci_dev_list[i].pc_devid; - char *name = NULL; - int bus, dev, func; - - if (pci_dev_list[i].pc_dvp) - continue; - - bus = pci_dev_list[i].pc_sel.pc_bus; - dev = pci_dev_list[i].pc_sel.pc_dev; - func = pci_dev_list[i].pc_sel.pc_func; - - tag = pcibus->pb_tag (bus, dev, func); - - for (lkm = pci_lkm_head; lkm; lkm = lkm->next) { - dvp = lkm->dvp; - if (name=(*dvp->pd_probe)(tag, type)) - break; - } - if (name && *name) { - pcicb = pci_dev_list[i].pc_cb; - pci_attach (bus, dev, func, dvp, name); - pci_dev_list[i].pc_dvp = dvp; + pcimap *map; + int map64 = 0; + + while (maxmaps > 0 + && pci_cfgread(cfg, PCIR_MAPS + (maxmaps -1) *4, 4) == 0) + maxmaps--; + + map = malloc(maxmaps * sizeof (pcimap), M_DEVBUF, M_WAITOK); + if (map != NULL) { + bzero(map, sizeof(pcimap) * maxmaps); + + for (i = 0; i < maxmaps; i++) { + int reg = PCIR_MAPS + i*4; + u_int32_t base; + u_int32_t testval; + + base = pci_cfgread(cfg, reg, 4); + + if (map64 == 0) { + pci_cfgwrite(cfg, reg, 0xffffffff, 4); + testval = pci_cfgread(cfg, reg, 4); + pci_cfgwrite(cfg, reg, base, 4); + + map[i].base = pci_mapbase(base); + map[i].type = pci_maptype(base); + map[i].ln2size = pci_mapsize(testval); + map[i].ln2range = pci_maprange(testval); + map64 = map[i].ln2range == 64; + } else { + /* only fill in base, other fields are 0 */ + map[i].base = base; + map64 = 0; + } + if (map[i].type == 0) { + /* + * This indicates, that some config space register + * was mistaken to contain a map, while it in fact + * contains unrelated information! + * Ignore this map and all that might have been + * expected to follow ... + */ + maxmaps = i; + } } + cfg->nummaps = maxmaps; } + return (map); } -/*======================================================== -** -** pci_register_lkm () -** -** Add LKM PCI driver's struct pci_device to pci_lkm chain -** -**======================================================== -*/ +/* adjust some values from PCI 1.0 devices to match 2.0 standards ... */ -int pci_register_lkm (struct pci_device *dvp, int if_revision) +static void +pci_fixancient(pcicfgregs *cfg) { - struct pci_lkm *lkm; - - if (if_revision != 0) { - return -1; - } - - if (!dvp || !dvp->pd_probe || !dvp->pd_attach) { - return -1; - } - - lkm = malloc (sizeof (*lkm), M_DEVBUF, M_WAITOK); - if (!lkm) { - return -1; - } + if (cfg->hdrtype != 0) + return; - lkm->dvp = dvp; - lkm->next = pci_lkm_head; - pci_lkm_head = lkm; - pci_rescan(); - return 0; + /* PCI to PCI bridges use header type 1 */ + if (cfg->class == PCIC_BRIDGE && cfg->subclass == PCIS_BRIDGE_PCI) + cfg->hdrtype = 1; } -/*----------------------------------------------------------------------- -** -** Map device into port space. -** -** Actually the device should have been mapped by the bios. -** This function only reads and verifies the value. -** -** PCI-Specification: 6.2.5.1: address maps -** -**----------------------------------------------------------------------- -*/ - -int pci_map_port (pcici_t tag, u_long reg, u_short* pa) +/* read config data specific to header type 1 device (PCI to PCI bridge) */ + +static void * +pci_readppb(pcicfgregs *cfg) { - unsigned data, ioaddr, iosize; - struct pcicb *link = pcicb; + pcih1cfgregs *p; - /* - ** sanity check - */ + p = malloc(sizeof (pcih1cfgregs), M_DEVBUF, M_WAITOK); + if (p == NULL) + return (NULL); - if (reg < PCI_MAP_REG_START || reg >= PCI_MAP_REG_END || (reg & 3)) { - printf ("pci_map_port failed: bad register=0x%x\n", - (unsigned)reg); - return (0); - }; + bzero(p, sizeof *p); - /* - ** get size and type of port - ** - ** type is in the lowest two bits. - ** If device requires 2^n bytes, the next - ** n-2 bits are hardwired as 0. - */ - - ioaddr = pci_conf_read (tag, reg) & PCI_MAP_IO_ADDRESS_MASK; - if (!ioaddr) { - printf ("pci_map_port failed: not configured by bios.\n"); - return (0); - }; + p->secstat = pci_cfgread(cfg, PCIR_SECSTAT_1, 2); + p->bridgectl = pci_cfgread(cfg, PCIR_BRIDGECTL_1, 2); - pci_conf_write (tag, reg, 0xfffffffful); - data = pci_conf_read (tag, reg); - pci_conf_write (tag, reg, ioaddr); + p->seclat = pci_cfgread(cfg, PCIR_SECLAT_1, 1); - if ((data & 0x03) != PCI_MAP_IO) { - printf ("pci_map_port failed: bad port type=0x%x\n", - (unsigned) data); - return (0); - }; - iosize = -(data & PCI_MAP_IO_ADDRESS_MASK); - iosize &= ~(ioaddr ^ -ioaddr); - if (ioaddr < pcicb->pcicb_iobase - || ioaddr + iosize -1 > pcicb->pcicb_iolimit) { - printf ("pci_map_port failed: device's iorange 0x%x-0x%x " - "is incompatible with its bridge's range 0x%x-0x%x\n", - (unsigned) ioaddr, (unsigned) ioaddr + iosize - 1, - (unsigned) pcicb->pcicb_iobase, - (unsigned) pcicb->pcicb_iolimit); - return (0); - } + p->iobase = PCI_PPBIOBASE (pci_cfgread(cfg, PCIR_IOBASEH_1, 2), + pci_cfgread(cfg, PCIR_IOBASEL_1, 1)); + p->iolimit = PCI_PPBIOLIMIT (pci_cfgread(cfg, PCIR_IOLIMITH_1, 2), + pci_cfgread(cfg, PCIR_IOLIMITL_1, 1)); -#ifndef PCI_QUIET - if (bootverbose) - printf ("\treg%d: ioaddr=0x%x size=0x%x\n", - (unsigned) reg, (unsigned) ioaddr, (unsigned) iosize); -#endif - /* - ** set the configuration register of and - ** return the address to the driver. - ** Make sure to enable each upstream bridge - ** so I/O and DMA can go all the way. - */ - - for (;;) { - data = pci_conf_read (tag, PCI_COMMAND_STATUS_REG) & 0xffff; - data |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE; - (void) pci_conf_write(tag, PCI_COMMAND_STATUS_REG, data); - if ((link = link->pcicb_up) == NULL) - break; - tag = link->pcicb_bridge; - } + p->membase = PCI_PPBMEMBASE (0, + pci_cfgread(cfg, PCIR_MEMBASE_1, 2)); + p->memlimit = PCI_PPBMEMLIMIT (0, + pci_cfgread(cfg, PCIR_MEMLIMIT_1, 2)); - *pa = ioaddr; + p->pmembase = PCI_PPBMEMBASE ( + (pci_addr_t)pci_cfgread(cfg, PCIR_PMBASEH_1, 4), + pci_cfgread(cfg, PCIR_PMBASEL_1, 2)); - return (1); + p->pmemlimit = PCI_PPBMEMLIMIT ( + (pci_addr_t)pci_cfgread(cfg, PCIR_PMLIMITH_1, 4), + pci_cfgread(cfg, PCIR_PMLIMITL_1, 2)); + return (p); } -/*----------------------------------------------------------------------- -** -** Map device into virtual and physical space -** -** Actually the device should have been mapped by the bios. -** This function only reads and verifies the value. -** -** PCI-Specification: 6.2.5.1: address maps -** -**----------------------------------------------------------------------- -*/ - -int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa) -{ - struct pcicb *link = pcicb; - unsigned data ,paddr; - vm_size_t psize, poffs; - vm_offset_t vaddr; - - /* - ** sanity check - */ - - if (reg < PCI_MAP_REG_START || reg >= PCI_MAP_REG_END || (reg & 3)) { - printf ("pci_map_mem failed: bad register=0x%x\n", - (unsigned)reg); - return (0); - }; - - /* - ** save old mapping, get size and type of memory - ** - ** type is in the lowest four bits. - ** If device requires 2^n bytes, the next - ** n-4 bits are read as 0. - */ - - paddr = pci_conf_read (tag, reg) & PCI_MAP_MEMORY_ADDRESS_MASK; - pci_conf_write (tag, reg, 0xfffffffful); - data = pci_conf_read (tag, reg); - pci_conf_write (tag, reg, paddr); - - /* - ** check the type - */ - - if (!((data & PCI_MAP_MEMORY_TYPE_MASK) == PCI_MAP_MEMORY_TYPE_32BIT_1M - && (paddr & ~0xfffff) == 0) - && (data & PCI_MAP_MEMORY_TYPE_MASK) != PCI_MAP_MEMORY_TYPE_32BIT){ - printf ("pci_map_mem failed: bad memory type=0x%x\n", - (unsigned) data); - return (0); - }; - - /* - ** get the size. - */ - - psize = -(data & PCI_MAP_MEMORY_ADDRESS_MASK); - - if (!paddr || paddr == PCI_MAP_MEMORY_ADDRESS_MASK) { - paddr = pci_memalloc (pcicb, 0, psize); - if (!paddr) { - printf ("pci_map_mem: not configured by bios.\n"); - return (0); - }; - pci_register_memory (pcicb, paddr, paddr+psize-1); - }; +/* read config data specific to header type 2 device (PCI to CardBus bridge) */ - if (paddr < pcicb->pcicb_membase || - paddr + psize - 1 > pcicb->pcicb_memlimit) { - printf ("pci_map_mem failed: device's memrange 0x%x-0x%x is " - "incompatible with its bridge's memrange 0x%x-0x%x\n", - (unsigned) paddr, - (unsigned) (paddr + psize - 1), - (unsigned) pcicb->pcicb_membase, - (unsigned) pcicb->pcicb_memlimit); -/* return (0);*/ -/* ACHTUNG: Ist der Code richtig, wenn eine PCI-PCI-Bridge fuer - * die PCI-Slots verwendet wird, aber die Onboard-Devices direkt - * an der CPU-PCI-Bridge haengen (Siehe Compaq Prolinea Problem) ??? - */ - } - pci_conf_write (tag, reg, paddr); - - /* - ** Truncate paddr to page boundary. - ** (Or does pmap_mapdev the job?) - */ +static void * +pci_readpcb(pcicfgregs *cfg) +{ + pcih2cfgregs *p; - poffs = paddr - trunc_page (paddr); - vaddr = (vm_offset_t) pmap_mapdev (paddr-poffs, psize+poffs); + p = malloc(sizeof (pcih2cfgregs), M_DEVBUF, M_WAITOK); + if (p == NULL) + return (NULL); - if (!vaddr) return (0); + bzero(p, sizeof *p); - vaddr += poffs; + p->secstat = pci_cfgread(cfg, PCIR_SECSTAT_2, 2); + p->bridgectl = pci_cfgread(cfg, PCIR_BRIDGECTL_2, 2); + + p->seclat = pci_cfgread(cfg, PCIR_SECLAT_2, 1); -#ifndef PCI_QUIET - /* - ** display values. - */ + p->membase0 = pci_cfgread(cfg, PCIR_MEMBASE0_2, 4); + p->memlimit0 = pci_cfgread(cfg, PCIR_MEMLIMIT0_2, 4); + p->membase1 = pci_cfgread(cfg, PCIR_MEMBASE1_2, 4); + p->memlimit1 = pci_cfgread(cfg, PCIR_MEMLIMIT1_2, 4); - if (bootverbose) - printf ("\treg%d: virtual=0x%lx physical=0x%lx size=0x%lx\n", - (unsigned) reg, (u_long)vaddr, (u_long)paddr, (u_long)psize); -#endif - /* - ** set the configuration register and - ** return the address to the driver - ** Make sure to enable each upstream bridge - ** so memory and DMA can go all the way. - */ - - for (;;) { - data = pci_conf_read (tag, PCI_COMMAND_STATUS_REG) & 0xffff; - data |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE; - (void) pci_conf_write(tag, PCI_COMMAND_STATUS_REG, data); - if ((link = link->pcicb_up) == NULL) - break; - tag = link->pcicb_bridge; - } + p->iobase0 = pci_cfgread(cfg, PCIR_IOBASE0_2, 4); + p->iolimit0 = pci_cfgread(cfg, PCIR_IOLIMIT0_2, 4); + p->iobase1 = pci_cfgread(cfg, PCIR_IOBASE1_2, 4); + p->iolimit1 = pci_cfgread(cfg, PCIR_IOLIMIT1_2, 4); - *va = vaddr; - *pa = paddr; - - return (1); + p->pccardif = pci_cfgread(cfg, PCIR_PCCARDIF_2, 4); + return p; } -/*----------------------------------------------------------------------- -** -** Pci meta interrupt handler -** -** This handler assumes level triggered interrupts. -** It's possible to build a kernel which handles shared -** edge triggered interrupts by the options "PCI_EDGE_INT". -** But there is a performance penalty. -** -** (Of course you can delete the #ifdef PCI_EDGE_INT bracketed -** code at all :-) :-) :-) -** -**----------------------------------------------------------------------- -*/ - -static struct pci_int_desc* - pci_int_desc [PCI_MAX_IRQ]; - -#ifndef NO_SHARED_IRQ - -static inline unsigned -splq (unsigned mask) -{ - unsigned temp=cpl; - cpl |= mask; - return temp; -} +/* extract header type specific config data */ static void -pci_int (int irq) +pci_hdrtypedata(pcicfgregs *cfg) { - struct pci_int_desc * p; - int s; - - if (irq<0 || irq >= PCI_MAX_IRQ) { - printf ("pci_int: irq %d out of range, ignored\n", irq); - return; - }; - for (p = pci_int_desc[irq]; p!=NULL; p=p->pcid_next) { - s = splq (*p->pcid_maskptr); - (*p->pcid_handler) (p->pcid_argument); - p-> pcid_tally++; - splx (s); -#if 0 - if (p->pcid_tally<20) - printf ("PCI_INT: irq=%d h=%p cpl o=%x n=%x val=%d\n", - irq, p->pcid_handler, s, cpl, c); -#endif - }; -} -#endif - -/*----------------------------------------------------------------------- -** -** Auxiliary function for interrupt (un)mapping. -** -**----------------------------------------------------------------------- -*/ - -static u_int -getirq (pcici_t tag) -{ - u_int irq; - - irq = PCI_INTERRUPT_LINE_EXTRACT( - pci_conf_read (tag, PCI_INTERRUPT_REG)); - - if (irq == 0 || irq == 0xff) { - printf ("\tint line register not set by bios\n"); - return (0xff); + switch (cfg->hdrtype) { + case 0: + cfg->subvendor = pci_cfgread(cfg, PCIR_SUBVEND_0, 2); + cfg->subdevice = pci_cfgread(cfg, PCIR_SUBDEV_0, 2); + cfg->map = pci_readmaps(cfg, PCI_MAXMAPS_0); + break; + case 1: + cfg->subvendor = pci_cfgread(cfg, PCIR_SUBVEND_1, 2); + cfg->subdevice = pci_cfgread(cfg, PCIR_SUBDEV_1, 2); + cfg->secondarybus = pci_cfgread(cfg, PCIR_SECBUS_1, 1); + cfg->subordinatebus = pci_cfgread(cfg, PCIR_SUBBUS_1, 1); + cfg->map = pci_readmaps(cfg, PCI_MAXMAPS_1); + cfg->hdrspec = pci_readppb(cfg); + break; + case 2: + cfg->subvendor = pci_cfgread(cfg, PCIR_SUBVEND_2, 2); + cfg->subdevice = pci_cfgread(cfg, PCIR_SUBDEV_2, 2); + cfg->secondarybus = pci_cfgread(cfg, PCIR_SECBUS_2, 1); + cfg->subordinatebus = pci_cfgread(cfg, PCIR_SUBBUS_2, 1); + cfg->map = pci_readmaps(cfg, PCI_MAXMAPS_2); + cfg->hdrspec = pci_readpcb(cfg); + break; } +} - if (irq >= PCI_MAX_IRQ) { - printf ("\tirq %d out of bounds (must be < %d).\n", - irq, PCI_MAX_IRQ); - return (0xff); +/* read configuration header into pcicfgrect structure */ + +static pcicfgregs * +pci_readcfg(pcicfgregs *probe) +{ + pcicfgregs *cfg = NULL; + + if (pci_cfgread(probe, PCIR_DEVVENDOR, 4) != -1) { + cfg = malloc(sizeof (pcicfgregs), M_DEVBUF, M_WAITOK); + if (cfg == NULL) + return (cfg); + + bzero(cfg, sizeof *cfg); + + cfg->bus = probe->bus; + cfg->slot = probe->slot; + cfg->func = probe->func; + cfg->parent = probe->parent; + + cfg->vendor = pci_cfgread(cfg, PCIR_VENDOR, 2); + cfg->device = pci_cfgread(cfg, PCIR_DEVICE, 2); + cfg->cmdreg = pci_cfgread(cfg, PCIR_COMMAND, 2); + cfg->statreg = pci_cfgread(cfg, PCIR_STATUS, 2); + cfg->class = pci_cfgread(cfg, PCIR_CLASS, 1); + cfg->subclass = pci_cfgread(cfg, PCIR_SUBCLASS, 1); + cfg->progif = pci_cfgread(cfg, PCIR_PROGIF, 1); + cfg->revid = pci_cfgread(cfg, PCIR_REVID, 1); + cfg->hdrtype = pci_cfgread(cfg, PCIR_HEADERTYPE, 1); + cfg->cachelnsz = pci_cfgread(cfg, PCIR_CACHELNSZ, 1); + cfg->lattimer = pci_cfgread(cfg, PCIR_LATTIMER, 1); + cfg->intpin = pci_cfgread(cfg, PCIR_INTPIN, 1); + cfg->intline = pci_cfgread(cfg, PCIR_INTLINE, 1); + cfg->mingnt = pci_cfgread(cfg, PCIR_MINGNT, 1); + cfg->maxlat = pci_cfgread(cfg, PCIR_MAXLAT, 1); + + cfg->mfdev = (cfg->hdrtype & PCIM_MFDEV) != 0; + cfg->hdrtype &= ~PCIM_MFDEV; + + pci_fixancient(cfg); + pci_hdrtypedata(cfg); } - - return (irq); + return (cfg); } -static struct pci_int_desc ** -getintdescbytag (u_int irq, pcici_t tag) -{ - struct pci_int_desc *p, **pp; - - pp=&pci_int_desc[irq]; - while (((p=*pp)) && !sametag(p->pcid_tag,tag)) - pp=&p->pcid_next; - - if (!p) return (NULL); +/* free pcicfgregs structure and all depending data structures */ - return (pp); -} - -static struct pci_int_desc * -getintdescbymptr (u_int irq, unsigned * mptr) +static int +pci_freecfg(pcicfgregs *cfg) { - struct pci_int_desc *p; - - for (p=pci_int_desc[irq];p;p=p->pcid_next) - if (p->pcid_maskptr == mptr) break; - return (p); + if (cfg->hdrspec != NULL) + free(cfg->hdrspec, M_DEVBUF); + if (cfg->map != NULL) + free(cfg->map, M_DEVBUF); + free(cfg, M_DEVBUF); + return (0); } -/*----------------------------------------------------------------------- -** -** Map pci interrupt. -** -**----------------------------------------------------------------------- -*/ - -static unsigned pci_mask0 = 0; - -int pci_map_int (pcici_t tag, pci_inthand_t *func, void *arg, unsigned *maskptr) +static void +pci_addcfg(pcicfgregs *cfg) { - u_int irq; - int result, oldspl; - unsigned mask; - struct pci_int_desc *tail, *mdp=NULL, *new=NULL; - - /* - ** Get irq line from configuration space, - ** and check for consistency. - */ - - irq = getirq (tag); - if (irq == 0xff) { - return (0); - }; - mask= 1ul << irq; - - /* - ** disable this interrupt. - */ - - oldspl = splq (mask); - - /* - ** If handler for this tag already installed, - ** remove it first. - */ - - if (getintdescbytag (irq, tag) != NULL) - pci_unmap_int (tag); - - /* - ** If this irq not yet included in the mask, include it. - */ - - mdp = getintdescbymptr (irq, maskptr); - if (!mdp) { - result = pcibus->pb_imaskinc (irq, maskptr); - if (result) - goto conflict; - }; - - /* - ** Allocate descriptor and initialize it. - */ - - tail = pci_int_desc[irq]; - - new = malloc (sizeof (*new), M_DEVBUF, M_WAITOK); - bzero (new, sizeof (*new)); - - new->pcid_next = tail; - new->pcid_tag = tag; - new->pcid_handler = func; - new->pcid_argument = arg; - new->pcid_maskptr = maskptr; - new->pcid_tally = 0; - new->pcid_mask = mask; - - /* - ** If first handler: install it. - ** If second handler: install shared-int-handler. - */ - - if (!tail) { - /* - ** first handler for this irq. - */ - - result = pcibus->pb_iattach - /* - * XXX if we get here, then `func' must be pci_int - * so the bogus casts are almost OK since they just - * undo the bogus casts that were needed to pass - * pci_int and its arg to pci_map_int(). - */ - (irq, (inthand2_t *) func, (int) arg, maskptr); - if (result) goto conflict; - -#ifdef NO_SHARED_IRQ - } else goto conflict; -#else - } else if (!tail->pcid_next) { - /* - ** Second handler for this irq. - */ - - if (bootverbose) - printf ("\tusing shared irq %d.\n", irq); - - /* - ** replace old handler by shared-int-handler. - */ - - result = pcibus->pb_idetach (irq, - (inthand2_t *) tail->pcid_handler); - if (result) - printf ("\tCANNOT DETACH INT HANDLER.\n"); - - result = pcibus->pb_iattach (irq, pci_int, irq, &pci_mask0); - if (result) { - printf ("\tCANNOT ATTACH SHARED INT HANDLER.\n"); - goto fail; - }; +#ifdef PCI_DEBUG + if (bootverbose) { + int i; + printf("new pci: vendor=0x%04x, dev=0x%04x, revid=0x%02x\n", + cfg->vendor, cfg->device, cfg->revid); + printf("\t cmdreg=0x%04x, statreg=0x%04x, cachelnsz=%d (dwords)\n", + cfg->cmdreg, cfg->statreg, cfg->cachelnsz); + printf("\t class=%02x-%02x-%02x, hdrtype=0x%02x, mfdev=%d\n", + cfg->class, cfg->subclass, cfg->progif, cfg->hdrtype, cfg->mfdev); + printf("\t lattimer=0x%02x (%d ns), mingnt=0x%02x (%d ns), maxlat=0x%02x (%d ns)\n", + cfg->lattimer, cfg->lattimer * 30, + cfg->mingnt, cfg->mingnt * 250, cfg->maxlat, cfg->maxlat * 250); + + if (cfg->intpin > 0) + printf("\t intpin=%c, irq=%d\n", cfg->intpin +'a' -1, cfg->intline); + + for (i = 0; i < cfg->nummaps; i++) { + pcimap *m = &cfg->map[i]; + printf("\t map[%d]: type %x, range %2d, base %08x, size %2d\n", + i, m->type, m->ln2range, m->base, m->ln2size); + } } -#endif - /* - ** Link new descriptor, reenable ints and done. - */ - - pci_int_desc[irq] = new; - splx (oldspl); - return (1); - - /* - ** Handle some problems. - */ - -conflict: - printf ("\tirq %d already in use.\n", irq); -fail: - /* - ** If descriptor allocated, free it. - ** If included in mask, remove it. - */ - - if (new) free(new, M_DEVBUF); - if (!mdp) (void) pcibus->pb_imaskexc (irq, maskptr); - splx (oldspl); - return (0); +#endif /* PCI_DEBUG */ + pci_drvattach(cfg); /* XXX currently defined in pci_compat.c */ } -/*----------------------------------------------------------------------- -** -** Unmap pci interrupt. -** -**----------------------------------------------------------------------- -*/ +/* return pointer to device that is a bridge to this bus */ -int pci_unmap_int (pcici_t tag) +static pcicfgregs * +pci_bridgeto(int bus) { - int result, oldspl; - struct pci_int_desc *this, **hook, *tail; - unsigned irq; - - /* - ** Get irq line from configuration space, - ** and check for consistency. - */ - - irq = getirq (tag); - if (irq == 0xff) { - return (0); - }; - - /* - ** Search and unlink interrupt descriptor. - */ - - hook = getintdescbytag (irq, tag); - if (hook == NULL) { - printf ("\tno irq %d handler for pci %x\n", - irq, tag.tag); - return (0); - }; - - this = *hook; - *hook= this->pcid_next; - - /* - ** Message - */ - - printf ("\tirq %d handler %p(%p) unmapped for pci %x after %d ints.\n", - irq, this->pcid_handler, this->pcid_argument, - this->pcid_tag.tag, this->pcid_tally); - - /* - ** If this irq no longer included in the mask, remove it. - */ - - if (!getintdescbymptr (irq, this->pcid_maskptr)) - (void) pcibus->pb_imaskexc (irq, this->pcid_maskptr); - - tail = pci_int_desc[irq]; - - if (tail == NULL) { - - /* - ** Remove the old handler. - */ - - result = pcibus->pb_idetach (irq, - (inthand2_t *) this->pcid_handler); - if (result) - printf ("\tirq %d: cannot remove handler.\n", irq); - - } else if (tail->pcid_next == NULL) { - - /* - ** Remove the shared int handler. - ** Install the last remaining handler. - */ - - oldspl = splq (1ul << irq); - - result = pcibus->pb_idetach (irq, pci_int); - if (result) - printf ("\tirq %d: cannot remove handler.\n", irq); - - result = pcibus->pb_iattach (irq, - (inthand2_t *) tail->pcid_handler, - (int) tail->pcid_argument, - tail->pcid_maskptr); - - if (result) - printf ("\tirq %d: cannot install handler.\n", irq); - - splx (oldspl); - }; - - free (this, M_DEVBUF); - return (1); + return (NULL); /* XXX not yet implemented */ } -/*----------------------------------------------------------- -** -** Display of unknown devices. -** -**----------------------------------------------------------- -*/ -struct vt { - u_short ident; - char* name; -}; - -static struct vt VendorTable[] = { - {0x0e11, "Compaq"}, - {0x1000, "NCR/Symbios"}, - {0x1002, "ATI Technologies Inc."}, - {0x1004, "VLSI"}, - {0x100B, "National Semiconductor"}, - {0x100E, "Weitek"}, - {0x1011, "Digital Equipment Corporation"}, - {0x1013, "Cirrus Logic"}, - {0x101A, "NCR"}, - {0x1022, "AMD"}, - {0x102B, "Matrox"}, - {0x102C, "Chips & Technologies"}, - {0x1039, "Silicon Integrated Systems"}, - {0x1042, "SMC"}, - {0x1044, "DPT"}, - {0x1045, "OPTI"}, - {0x104B, "Bus Logic"}, - {0x104C, "TI"}, - {0x1060, "UMC"}, - {0x1080, "Contaq"}, - {0x1095, "CMD"}, - {0x10b9, "ACER Labs"}, - {0x10c8, "NeoMagic"}, - {0x1106, "VIA Technologies"}, - {0x5333, "S3 Inc."}, - {0x8086, "Intel Corporation"}, - {0x9004, "Adaptec"}, - {0,0} -}; - -typedef struct { - const int subclass; - const char *name; -} subclass_name; - -/* 0x00 prehistoric subclasses */ -static const subclass_name old_subclasses[] = -{ - { 0x00, "misc" }, - { 0x01, "vga" }, - { 0x00, NULL } -}; - -/* 0x01 mass storage subclasses */ -static const subclass_name storage_subclasses[] = -{ - { 0x00, "scsi" }, - { 0x01, "ide" }, - { 0x02, "floppy"}, - { 0x03, "ipi" }, - { 0x80, "misc" }, - { 0x00, NULL } -}; - -/* 0x02 network subclasses */ -static const subclass_name network_subclasses[] = -{ - { 0x00, "ethernet" }, - { 0x01, "tokenring" }, - { 0x02, "fddi" }, - { 0x80, "misc" }, - { 0x00, NULL } -}; - -/* 0x03 display subclasses */ -static const subclass_name display_subclasses[] = -{ - { 0x00, "vga" }, - { 0x01, "xga" }, - { 0x80, "misc" }, - { 0x00, NULL } -}; - -/* 0x04 multimedia subclasses */ -static const subclass_name multimedia_subclasses[] = -{ - { 0x00, "video" }, - { 0x01, "audio" }, - { 0x80, "misc" }, - { 0x00, NULL } -}; - -/* 0x05 memory subclasses */ -static const subclass_name memory_subclasses[] = -{ - { 0x00, "ram" }, - { 0x01, "flash" }, - { 0x80, "misc" }, - { 0x00, NULL } -}; - -/* 0x06 bridge subclasses */ -static const subclass_name bridge_subclasses[] = -{ - { 0x00, "host" }, - { 0x01, "isa" }, - { 0x02, "eisa" }, - { 0x03, "mc" }, - { 0x04, "pci" }, - { 0x05, "pcmcia"}, - { 0x07, "cardbus"}, - { 0x80, "misc" }, - { 0x00, NULL } -}; - -static const subclass_name *const subclasses[] = { - old_subclasses, - storage_subclasses, - network_subclasses, - display_subclasses, - multimedia_subclasses, - memory_subclasses, - bridge_subclasses, -}; - -static const char *const majclasses[] = { - "old", - "storage", - "network", - "display", - "multimedia", - "memory", - "bridge", - "comms", - "system", - "input", - "docking", - "processor", - "serial" -}; - - -void not_supported (pcici_t tag, u_long type) -{ - u_long reg; - u_long data; - u_char class; - u_char subclass; - struct vt * vp; - int pciint; - int irq; - - /* - ** lookup the names. - */ - - for (vp=VendorTable; vp->ident; vp++) - if (vp->ident == (type & 0xffff)) - break; +/* scan one PCI bus for devices */ - /* - ** and display them. - */ - - if (vp->ident) printf (vp->name); - else printf ("vendor=0x%04lx", type & 0xffff); - - printf (", device=0x%04lx", type >> 16); - - data = pci_conf_read(tag, PCI_CLASS_REG); - class = (data >> 24) & 0xff; - subclass = (data >> 16) & 0xff; - - if (class < sizeof(majclasses) / sizeof(majclasses[0])) { - printf(", class=%s", majclasses[class]); - } else { - printf(", class=0x%02x", class); - } - - if (class < sizeof(subclasses) / sizeof(subclasses[0])) { - const subclass_name *p = subclasses[class]; - while (p->name && (p->subclass != subclass)) - p++; - if (p->name) { - printf(" (%s)", p->name); - } else { - printf(" (unknown subclass 0x%02lx)", subclass); +static int +pci_probebus(int bus) +{ + pcicfgregs probe; + int bushigh = bus; + + bzero(&probe, sizeof probe); + probe.parent = pci_bridgeto(bus); + probe.bus = bus; + for (probe.slot = 0; probe.slot <= PCI_SLOTMAX; probe.slot++) { + int pcifunchigh = 0; + for (probe.func = 0; probe.func <= pcifunchigh; probe.func++) { + pcicfgregs *cfg = pci_readcfg(&probe); + if (cfg != NULL) { + if (cfg->mfdev) + pcifunchigh = 7; + + if (bushigh < cfg->subordinatebus) + bushigh = cfg->subordinatebus; + + pci_addcfg(cfg); + cfg = NULL; /* we don't own this anymore ... */ + } } - } else { - printf(", subclass=0x%02x", subclass); } + return (bushigh); +} - data = pci_conf_read (tag, PCI_INTERRUPT_REG); - pciint = PCI_INTERRUPT_PIN_EXTRACT(data); - - if (pciint) { - - printf (" int %c irq ", 0x60+pciint); - - irq = PCI_INTERRUPT_LINE_EXTRACT(data); - - /* - ** If it's zero, the isa irq number is unknown, - ** and we cannot bind the pci interrupt. - */ +/* scan a PCI bus tree reached through one PCI attachment point */ - if (irq && (irq != 0xff)) - printf ("%d", irq); - else - printf ("??"); - }; +int +pci_probe(pciattach *parent) +{ + int bushigh; + int bus = 0; - if (class != (PCI_CLASS_BRIDGE >> 24)) - printf (" [no driver assigned]"); - printf ("\n"); + bushigh = pci_bushigh(); + while (bus <= bushigh) { + int newbushigh; - if (bootverbose) { - if (class == (PCI_CLASS_BRIDGE >> 24)) { - printf ("configuration space registers:"); - for (reg = 0; reg < 0x100; reg+=4) { - if ((reg & 0x0f) == 0) printf ("\n%02x:\t", reg); - printf ("%08x ", pci_conf_read (tag, reg)); - } - printf ("\n"); - } else { - for (reg=PCI_MAP_REG_START; reg<PCI_MAP_REG_END; reg+=4) { - data = pci_conf_read (tag, reg); - if ((data&~7)==0) continue; - switch (data&7) { + printf("Probing for devices on PCI bus %d:\n", bus); + newbushigh = pci_probebus(bus); - case 1: - case 5: - printf ("\tmap(%x): io(%04lx)\n", - reg, data & ~3); - break; - case 0: - printf ("\tmap(%x): mem32(%08lx)\n", - reg, data & ~7); - break; - case 2: - printf ("\tmap(%x): mem20(%05lx)\n", - reg, data & ~7); - break; - case 4: - printf ("\tmap(%x): mem64(%08x%08lx)\n", - reg, pci_conf_read (tag, reg +4), data & ~7); - reg += 4; - break; - } - } - } + if (bushigh < newbushigh) + bushigh = newbushigh; + bus++; } + return (bushigh); } /* - * This is the user interface to the PCI configuration space. + * This is the user interface to PCI configuration space. */ - - -static void -pci_remember(int bus, int dev, int func, struct pci_device *dvp) -{ - struct pci_conf *p; - pcici_t tag; - - if (++pci_dev_list_count > pci_dev_list_size) { - struct pci_conf *new; - - pci_dev_list_size += 8; - MALLOC(new, struct pci_conf *, pci_dev_list_size * sizeof *new, - M_DEVL, M_NOWAIT); - if (!new) { - pci_dev_list_size -= 8; - pci_dev_list_count--; - return; - } - - if (pci_dev_list) { - bcopy(pci_dev_list, new, ((pci_dev_list_size - 8) * - sizeof *new)); - FREE(pci_dev_list, M_DEVL); - } - pci_dev_list = new; - } - - p = &pci_dev_list[pci_dev_list_count - 1]; - p->pc_sel.pc_bus = bus; - p->pc_sel.pc_dev = dev; - p->pc_sel.pc_func = func; - p->pc_dvp = dvp; - p->pc_cb = pcicb; - - tag = pcibus->pb_tag (bus, dev, func); - p->pc_hdr = (pci_conf_read (tag, PCI_HEADER_MISC) >> 16) & 0xff; - p->pc_devid = pci_conf_read(tag, PCI_ID_REG); - p->pc_class = pci_conf_read(tag, PCI_CLASS_REG); - switch (p->pc_hdr & 0x7f) { - case 0: - p->pc_subid = pci_conf_read(tag, PCI_SUBID_REG0); - break; - case 1: - p->pc_subid = pci_conf_read(tag, PCI_SUBID_REG1); - break; - case 2: - p->pc_subid = pci_conf_read(tag, PCI_SUBID_REG2); - break; - default: - p->pc_subid = 0; - } -} - + static int pci_open(dev_t dev, int oflags, int devtype, struct proc *p) { if ((oflags & FWRITE) && securelevel > 0) { return EPERM; } - return 0; } @@ -1904,79 +470,62 @@ pci_ioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) struct pci_io *io; size_t iolen; int error; - pcici_t tag; if (cmd != PCIOCGETCONF && !(flag & FWRITE)) return EPERM; switch(cmd) { case PCIOCGETCONF: +#ifdef NOTYET +static struct pci_conf *pci_dev_list; +static unsigned pci_dev_list_count; +static unsigned pci_dev_list_size; + cio = (struct pci_conf_io *)data; iolen = min(cio->pci_len, pci_dev_list_count * sizeof(struct pci_conf)); cio->pci_len = pci_dev_list_count * sizeof(struct pci_conf); error = copyout(pci_dev_list, cio->pci_buf, iolen); +#else + error = ENODEV; +#endif break; case PCIOCREAD: io = (struct pci_io *)data; switch(io->pi_width) { + pcicfgregs probe; case 4: - tag = pcibus->pb_tag (io->pi_sel.pc_bus, - io->pi_sel.pc_dev, - io->pi_sel.pc_func); - io->pi_data = pci_conf_read(tag, io->pi_reg); - error = 0; - break; case 2: case 1: - default: - error = ENODEV; - break; - } - break; - - case PCIOCWRITE: - io = (struct pci_io *)data; - switch(io->pi_width) { - case 4: - tag = pcibus->pb_tag (io->pi_sel.pc_bus, - io->pi_sel.pc_dev, - io->pi_sel.pc_func); - pci_conf_write(tag, io->pi_reg, io->pi_data); + probe.bus = io->pi_sel.pc_bus; + probe.slot = io->pi_sel.pc_dev; + probe.func = io->pi_sel.pc_func; + io->pi_data = pci_cfgread(&probe, + io->pi_reg, io->pi_width); error = 0; break; - case 2: - case 1: default: error = ENODEV; break; } break; - case PCIOCATTACHED: + case PCIOCWRITE: io = (struct pci_io *)data; switch(io->pi_width) { + pcicfgregs probe; case 4: - { - int i = pci_dev_list_count; - struct pci_conf *p = pci_dev_list; - error = ENODEV; - while (i--) { - if (io->pi_sel.pc_bus == p->pc_sel.pc_bus && - io->pi_sel.pc_dev == p->pc_sel.pc_dev && - io->pi_sel.pc_func == p->pc_sel.pc_func) { - io->pi_data = (u_int32_t)p->pc_dvp; - error = 0; - break; - } - p++; - } - } - break; case 2: case 1: + probe.bus = io->pi_sel.pc_bus; + probe.slot = io->pi_sel.pc_dev; + probe.func = io->pi_sel.pc_func; + pci_cfgwrite(&probe, + io->pi_reg, io->pi_data, io->pi_width); + error = 0; + break; default: error = ENODEV; break; @@ -2017,4 +566,4 @@ pci_cdevinit(void *dummy) SYSINIT(pcidev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+PCI_CDEV, pci_cdevinit, NULL); -#endif /* NPCI */ +#endif /* NPCI > 0 */ diff --git a/sys/dev/pci/pcireg.h b/sys/dev/pci/pcireg.h index 05e3c07..cd5c6e8 100644 --- a/sys/dev/pci/pcireg.h +++ b/sys/dev/pci/pcireg.h @@ -1,208 +1,250 @@ -/************************************************************************** -** -** $Id: pcireg.h,v 1.13 1997/04/20 06:57:43 phk Exp $ -** -** Names for PCI configuration space registers. -** -** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved. -** -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR 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. -** -*************************************************************************** -*/ - -#ifndef __PCI_REG_H__ -#define __PCI_REG_H__ "pl2 95/03/21" - +#ifndef PCI_COMPAT +#define PCI_COMPAT +#endif /* -** Device identification register; contains a vendor ID and a device ID. -** We have little need to distinguish the two parts. -*/ -#define PCI_ID_REG 0x00 + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR 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. + * + * $Id$ + * + */ /* -** Command and status register. -*/ -#define PCI_COMMAND_STATUS_REG 0x04 - + * PCIM_xxx: mask to locate subfield in register + * PCIR_xxx: config register offset + * PCIC_xxx: device class + * PCIS_xxx: device subclass + * PCIP_xxx: device programming interface + * PCIV_xxx: PCI vendor ID (only required to fixup ancient devices) + * PCID_xxx: device ID + */ + +/* some PCI bus constants */ + +#define PCI_BUSMAX 255 +#define PCI_SLOTMAX 31 +#define PCI_FUNCMAX 7 +#define PCI_REGMAX 255 + +/* PCI config header registers for all devices */ + +#define PCIR_DEVVENDOR 0x00 +#define PCIR_VENDOR 0x00 +#define PCIR_DEVICE 0x02 +#define PCIR_COMMAND 0x04 +#define PCIR_STATUS 0x06 +#define PCIR_REVID 0x08 +#define PCIR_PROGIF 0x09 +#define PCIR_SUBCLASS 0x0a +#define PCIR_CLASS 0x0b +#define PCIR_CACHELNSZ 0x0c +#define PCIR_LATTIMER 0x0d +#define PCIR_HEADERTYPE 0x0e +#define PCIM_MFDEV 0x80 +#define PCIR_BIST 0x0f + +/* config registers for header type 0 devices */ + +#define PCIR_MAPS 0x10 +#define PCIR_CARDBUSCIS 0x28 +#define PCIR_SUBVEND_0 0x2c +#define PCIR_SUBDEV_0 0x2e +#define PCIR_INTLINE 0x3c +#define PCIR_INTPIN 0x3d +#define PCIR_MINGNT 0x3e +#define PCIR_MAXLAT 0x3f + +/* config registers for header type 1 devices */ + +#define PCIR_SECSTAT_1 0 /**/ + +#define PCIR_PRIBUS_1 0x18 +#define PCIR_SECBUS_1 0x19 +#define PCIR_SUBBUS_1 0x1a +#define PCIR_SECLAT_1 0x1b + +#define PCIR_IOBASEL_1 0x1c +#define PCIR_IOLIMITL_1 0x1d +#define PCIR_IOBASEH_1 0 /**/ +#define PCIR_IOLIMITH_1 0 /**/ + +#define PCIR_MEMBASE_1 0x20 +#define PCIR_MEMLIMIT_1 0x22 + +#define PCIR_PMBASEL_1 0x24 +#define PCIR_PMLIMITL_1 0x26 +#define PCIR_PMBASEH_1 0 /**/ +#define PCIR_PMLIMITH_1 0 /**/ + +#define PCIR_BRIDGECTL_1 0 /**/ + +#define PCIR_SUBVEND_1 0x34 +#define PCIR_SUBDEV_1 0x36 + +/* config registers for header type 2 devices */ + +#define PCIR_SECSTAT_2 0x16 + +#define PCIR_PRIBUS_2 0x18 +#define PCIR_SECBUS_2 0x19 +#define PCIR_SUBBUS_2 0x1a +#define PCIR_SECLAT_2 0x1b + +#define PCIR_MEMBASE0_2 0x1c +#define PCIR_MEMLIMIT0_2 0x20 +#define PCIR_MEMBASE1_2 0x24 +#define PCIR_MEMLIMIT1_2 0x28 +#define PCIR_IOBASE0_2 0x2c +#define PCIR_IOLIMIT0_2 0x30 +#define PCIR_IOBASE1_2 0x34 +#define PCIR_IOLIMIT1_2 0x38 + +#define PCIR_BRIDGECTL_2 0x3e + +#define PCIR_SUBVEND_2 0x40 +#define PCIR_SUBDEV_2 0x42 + +#define PCIR_PCCARDIF_2 0x44 + +/* PCI device class, subclass and programming interface definitions */ + +#define PCIC_OLD 0x00 +#define PCIS_OLD_NONVGA 0x00 +#define PCIS_OLD_VGA 0x01 + +#define PCIC_STORAGE 0x01 +#define PCIS_STORAGE_SCSI 0x00 +#define PCIS_STORAGE_IDE 0x01 +#define PCIP_STORAGE_IDE_MODEPRIM 0x01 +#define PCIP_STORAGE_IDE_PROGINDPRIM 0x02 +#define PCIP_STORAGE_IDE_MODESEC 0x04 +#define PCIP_STORAGE_IDE_PROGINDSEC 0x08 +#define PCIP_STORAGE_IDE_MASTERDEV 0x80 +#define PCIS_STORAGE_FLOPPY 0x02 +#define PCIS_STORAGE_IPI 0x03 +#define PCIS_STORAGE_RAID 0x04 +#define PCIS_STORAGE_OTHER 0x80 + +#define PCIC_NETWORK 0x02 +#define PCIS_NETWORK_ETHERNET 0x00 +#define PCIS_NETWORK_TOKENRING 0x01 +#define PCIS_NETWORK_FDDI 0x02 +#define PCIS_NETWORK_ATM 0x03 +#define PCIS_NETWORK_OTHER 0x80 + +#define PCIC_DISPLAY 0x03 +#define PCIS_DISPLAY_VGA 0x00 +#define PCIS_DISPLAY_XGA 0x01 +#define PCIS_DISPLAY_OTHER 0x80 + +#define PCIC_MULTIMEDIA 0x04 +#define PCIS_MULTIMEDIA_VIDEO 0x00 +#define PCIS_MULTIMEDIA_AUDIO 0x01 +#define PCIS_MULTIMEDIA_OTHER 0x80 + +#define PCIC_MEMORY 0x05 +#define PCIS_MEMORY_RAM 0x00 +#define PCIS_MEMORY_FLASH 0x01 +#define PCIS_MEMORY_OTHER 0x80 + +#define PCIC_BRIDGE 0x06 +#define PCIS_BRDIGE_HOST 0x00 +#define PCIS_BRIDGE_ISA 0x01 +#define PCIS_BRIDGE_EISA 0x02 +#define PCIS_BRIDGE_MCA 0x03 +#define PCIS_BRIDGE_PCI 0x04 +#define PCIS_BRIDGE_PCMCIA 0x05 +#define PCIS_BRIDGE_NUBUS 0x06 +#define PCIS_BRIDGE_CARDBUS 0x07 +#define PCIS_BRIDGE_OTHER 0x80 + +#define PCIC_SIMPLECOMM 0x07 +#define PCIS_SIMPLECOMM_UART 0x00 +#define PCIS_SIMPLECOMM_PAR 0x01 +#define PCIS_SIMPLECOMM_OTHER 0x80 + +#define PCIC_BASEPERIPH 0x08 +#define PCIS_BASEPERIPH_PIC 0x00 +#define PCIS_BASEPERIPH_DMA 0x01 +#define PCIS_BASEPERIPH_TIMER 0x02 +#define PCIS_BASEPERIPH_RTC 0x03 +#define PCIS_BASEPERIPH_OTHER 0x80 + +#define PCIC_INPUTDEV 0x09 +#define PCIS_INPUTDEV_KEYBOARD 0x00 +#define PCIS_INPUTDEV_DIGITIZER 0x01 +#define PCIS_INPUTDEV_MOUSE 0x02 +#define PCIS_INPUTDEV_OTHER 0x80 + +#define PCIC_DOCKING 0x0a +#define PCIS_DOCKING_GENERIC 0x00 +#define PCIS_DOCKING_OTHER 0x80 + +#define PCIC_PROCESSOR 0x0b +#define PCIS_PROCESSOR_386 0x00 +#define PCIS_PROCESSOR_486 0x01 +#define PCIS_PROCESSOR_PENTIUM 0x02 +#define PCIS_PROCESSOR_ALPHA 0x10 +#define PCIS_PROCESSOR_POWERPC 0x20 +#define PCIS_PROCESSOR_COPROC 0x40 + +#define PCIC_SERIALBUS 0x0c +#define PCIS_SERIALBUS_FW 0x00 +#define PCIS_SERIALBUS_ACCESS 0x01 +#define PCIS_SERIALBUS_SSA 0x02 +#define PCIS_SERIALBUS_USB 0x03 +#define PCIS_SERIALBUS_FC 0x04 +#define PCIS_SERIALBUS +#define PCIS_SERIALBUS + +#define PCIC_OTHER 0xff + +/* some PCI vendor definitions (only used to identify ancient devices !!! */ + +#define PCIV_INTEL 0x8086 + +#define PCID_INTEL_SATURN 0x0483 +#define PCID_INTEL_ORION 0x84c4 + +/* for compatibility to FreeBSD-2.2 version of PCI code */ + +#ifdef PCI_COMPAT + +#define PCI_ID_REG 0x00 +#define PCI_COMMAND_STATUS_REG 0x04 #define PCI_COMMAND_IO_ENABLE 0x00000001 -#define PCI_COMMAND_MEM_ENABLE 0x00000002 -#define PCI_COMMAND_MASTER_ENABLE 0x00000004 -#define PCI_COMMAND_SPECIAL_ENABLE 0x00000008 -#define PCI_COMMAND_INVALIDATE_ENABLE 0x00000010 -#define PCI_COMMAND_PALETTE_ENABLE 0x00000020 -#define PCI_COMMAND_PARITY_ENABLE 0x00000040 -#define PCI_COMMAND_STEPPING_ENABLE 0x00000080 -#define PCI_COMMAND_SERR_ENABLE 0x00000100 -#define PCI_COMMAND_BACKTOBACK_ENABLE 0x00000200 - -#define PCI_STATUS_BACKTOBACK_OKAY 0x00800000 -#define PCI_STATUS_PARITY_ERROR 0x01000000 -#define PCI_STATUS_DEVSEL_FAST 0x00000000 -#define PCI_STATUS_DEVSEL_MEDIUM 0x02000000 -#define PCI_STATUS_DEVSEL_SLOW 0x04000000 -#define PCI_STATUS_DEVSEL_MASK 0x06000000 -#define PCI_STATUS_TARGET_TARGET_ABORT 0x08000000 -#define PCI_STATUS_MASTER_TARGET_ABORT 0x10000000 -#define PCI_STATUS_MASTER_ABORT 0x20000000 -#define PCI_STATUS_SPECIAL_ERROR 0x40000000 -#define PCI_STATUS_PARITY_DETECT 0x80000000 - -/* -** Class register; defines basic type of device. -*/ -#define PCI_CLASS_REG 0x08 - -#define PCI_CLASS_MASK 0xff000000 -#define PCI_SUBCLASS_MASK 0x00ff0000 - -/* base classes */ -#define PCI_CLASS_PREHISTORIC 0x00000000 -#define PCI_CLASS_MASS_STORAGE 0x01000000 -#define PCI_CLASS_NETWORK 0x02000000 -#define PCI_CLASS_DISPLAY 0x03000000 -#define PCI_CLASS_MULTIMEDIA 0x04000000 -#define PCI_CLASS_MEMORY 0x05000000 -#define PCI_CLASS_BRIDGE 0x06000000 -#define PCI_CLASS_UNDEFINED 0xff000000 - -/* 0x00 prehistoric subclasses */ -#define PCI_SUBCLASS_PREHISTORIC_MISC 0x00000000 -#define PCI_SUBCLASS_PREHISTORIC_VGA 0x00010000 - -/* 0x01 mass storage subclasses */ -#define PCI_SUBCLASS_MASS_STORAGE_SCSI 0x00000000 -#define PCI_SUBCLASS_MASS_STORAGE_IDE 0x00010000 -#define PCI_SUBCLASS_MASS_STORAGE_FLOPPY 0x00020000 -#define PCI_SUBCLASS_MASS_STORAGE_IPI 0x00030000 -#define PCI_SUBCLASS_MASS_STORAGE_MISC 0x00800000 - -/* 0x02 network subclasses */ -#define PCI_SUBCLASS_NETWORK_ETHERNET 0x00000000 -#define PCI_SUBCLASS_NETWORK_TOKENRING 0x00010000 -#define PCI_SUBCLASS_NETWORK_FDDI 0x00020000 -#define PCI_SUBCLASS_NETWORK_MISC 0x00800000 - -/* 0x03 display subclasses */ -#define PCI_SUBCLASS_DISPLAY_VGA 0x00000000 -#define PCI_SUBCLASS_DISPLAY_XGA 0x00010000 -#define PCI_SUBCLASS_DISPLAY_MISC 0x00800000 - -/* 0x04 multimedia subclasses */ -#define PCI_SUBCLASS_MULTIMEDIA_VIDEO 0x00000000 -#define PCI_SUBCLASS_MULTIMEDIA_AUDIO 0x00010000 -#define PCI_SUBCLASS_MULTIMEDIA_MISC 0x00800000 - -/* 0x05 memory subclasses */ -#define PCI_SUBCLASS_MEMORY_RAM 0x00000000 -#define PCI_SUBCLASS_MEMORY_FLASH 0x00010000 -#define PCI_SUBCLASS_MEMORY_MISC 0x00800000 - -/* 0x06 bridge subclasses */ -#define PCI_SUBCLASS_BRIDGE_HOST 0x00000000 -#define PCI_SUBCLASS_BRIDGE_ISA 0x00010000 -#define PCI_SUBCLASS_BRIDGE_EISA 0x00020000 -#define PCI_SUBCLASS_BRIDGE_MC 0x00030000 -#define PCI_SUBCLASS_BRIDGE_PCI 0x00040000 -#define PCI_SUBCLASS_BRIDGE_PCMCIA 0x00050000 -#define PCI_SUBCLASS_BRIDGE_CARDBUS 0x00070000 -#define PCI_SUBCLASS_BRIDGE_MISC 0x00800000 - -/* -** Header registers -*/ -#define PCI_HEADER_MISC 0x0c - -#define PCI_HEADER_MULTIFUNCTION 0x00800000 - -/* -** Mapping registers -*/ -#define PCI_MAP_REG_START 0x10 -#define PCI_MAP_REG_END 0x28 - -#define PCI_MAP_MEMORY 0x00000000 +#define PCI_CLASS_REG 0x08 +#define PCI_CLASS_MASK 0xff000000 +#define PCI_SUBCLASS_MASK 0x00ff0000 +#define PCI_CLASS_PREHISTORIC 0x00000000 +#define PCI_SUBCLASS_PREHISTORIC_VGA 0x00010000 +#define PCI_CLASS_DISPLAY 0x03000000 +#define PCI_SUBCLASS_DISPLAY_VGA 0x00000000 +#define PCI_CLASS_BRIDGE 0x06000000 +#define PCI_MAP_REG_START 0x10 +#define PCI_MAP_REG_END 0x28 #define PCI_MAP_IO 0x00000001 +#define PCI_INTERRUPT_REG 0x3c -#define PCI_MAP_MEMORY_TYPE_32BIT 0x00000000 -#define PCI_MAP_MEMORY_TYPE_32BIT_1M 0x00000002 -#define PCI_MAP_MEMORY_TYPE_64BIT 0x00000004 -#define PCI_MAP_MEMORY_TYPE_MASK 0x00000006 -#define PCI_MAP_MEMORY_CACHABLE 0x00000008 -#define PCI_MAP_MEMORY_ADDRESS_MASK 0xfffffff0 - -#define PCI_MAP_IO_ADDRESS_MASK 0xfffffffc -/* -** PCI-PCI bridge mapping registers -*/ -#define PCI_PCI_BRIDGE_BUS_REG 0x18 -#define PCI_PCI_BRIDGE_IO_REG 0x1c -#define PCI_PCI_BRIDGE_MEM_REG 0x20 -#define PCI_PCI_BRIDGE_PMEM_REG 0x24 - -#define PCI_SUBID_REG0 0x2c -#define PCI_SUBID_REG1 0x34 -#define PCI_SUBID_REG2 0x40 - -#define PCI_SUBORDINATE_BUS_MASK 0x00ff0000 -#define PCI_SECONDARY_BUS_MASK 0x0000ff00 -#define PCI_PRIMARY_BUS_MASK 0x000000ff - -#define PCI_SUBORDINATE_BUS_EXTRACT(x) (((x) >> 16) & 0xff) -#define PCI_SECONDARY_BUS_EXTRACT(x) (((x) >> 8) & 0xff) -#define PCI_PRIMARY_BUS_EXTRACT(x) (((x) ) & 0xff) - -#define PCI_PRIMARY_BUS_INSERT(x, y) (((x) & ~PCI_PRIMARY_BUS_MASK) | ((y) << 0)) -#define PCI_SECONDARY_BUS_INSERT(x, y) (((x) & ~PCI_SECONDARY_BUS_MASK) | ((y) << 8)) -#define PCI_SUBORDINATE_BUS_INSERT(x, y) (((x) & ~PCI_SUBORDINATE_BUS_MASK) | ((y) << 16)) - -#define PCI_PPB_IOBASE_EXTRACT(x) (((x) << 8) & 0xF000) -#define PCI_PPB_IOLIMIT_EXTRACT(x) (((x) << 0) & 0xF000 | 0x0FFF) - -#define PCI_PPB_MEMBASE_EXTRACT(x) (((x) << 16) & 0xFFF00000) -#define PCI_PPB_MEMLIMIT_EXTRACT(x) (((x) << 0) & 0xFFF00000 | 0x000FFFFF) - -/* -** PCI-Cardbus bridge mapping registers -*/ -#define PCI_CARDBUS_SOCKET_REG 0x10 - -/* -** Interrupt configuration register -*/ -#define PCI_INTERRUPT_REG 0x3c - -#define PCI_INTERRUPT_PIN_MASK 0x0000ff00 -#define PCI_INTERRUPT_PIN_EXTRACT(x) ((((x) & PCI_INTERRUPT_PIN_MASK) >> 8) & 0xff) -#define PCI_INTERRUPT_PIN_NONE 0x00 -#define PCI_INTERRUPT_PIN_A 0x01 -#define PCI_INTERRUPT_PIN_B 0x02 -#define PCI_INTERRUPT_PIN_C 0x03 -#define PCI_INTERRUPT_PIN_D 0x04 - -#define PCI_INTERRUPT_LINE_MASK 0x000000ff -#define PCI_INTERRUPT_LINE_EXTRACT(x) ((((x) & PCI_INTERRUPT_LINE_MASK) >> 0) & 0xff) -#define PCI_INTERRUPT_LINE_INSERT(x,v) (((x) & ~PCI_INTERRUPT_LINE_MASK) | ((v) << 0)) - -#endif /* __PCI_REG_H__ */ +#endif /* PCI_COMPAT */ diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h index cb85100..4bb8496 100644 --- a/sys/dev/pci/pcivar.h +++ b/sys/dev/pci/pcivar.h @@ -1,129 +1,183 @@ -/************************************************************************** -** -** $Id$ -** -** Declarations for pci device drivers. -** -** FreeBSD -** -**------------------------------------------------------------------------- -** -** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR 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. -** -*************************************************************************** -*/ - -#ifndef __PCI_VAR_H__ -#define __PCI_VAR_H__ "pl2 95/03/21" - -/*----------------------------------------------------------------- -** -** main pci initialization function. -** called at boot time from autoconf.c -** -**----------------------------------------------------------------- -*/ - -void pci_configure (void); - -/*----------------------------------------------------------------- -** -** The pci configuration id describes a pci device on the bus. -** It is constructed from: bus, device & function numbers. -** -**----------------------------------------------------------------- -*/ - -typedef union { - u_long cfg1; - struct { - u_char enable; - u_char forward; - u_short port; - } cfg2; - unsigned tag; - } pcici_t; - -#define sametag(x,y) ((x).tag == (y).tag) - -/*----------------------------------------------------------------- -** -** Each pci device has an unique device id. -** It is used to find a matching driver. -** -**----------------------------------------------------------------- -*/ - -typedef u_long pcidi_t; - -/*----------------------------------------------------------------- -** -** The following functions are provided for the device driver -** to read/write the configuration space. -** -** pci_conf_read(): -** Read a long word from the pci configuration space. -** Requires a tag (from pcitag) and the register -** number (should be a long word alligned one). -** -** pci_conf_write(): -** Writes a long word to the pci configuration space. -** Requires a tag (from pcitag), the register number -** (should be a long word alligned one), and a value. -** -**----------------------------------------------------------------- -*/ - -u_long pci_conf_read (pcici_t tag, u_long reg ); - -void pci_conf_write (pcici_t tag, u_long reg, u_long data); - -/*----------------------------------------------------------------- -** -** The pci driver structure. -** -** name: The short device name. -** -** probe: Checks if the driver can support a device -** with this type. The tag may be used to get -** more info with pci_read_conf(). See below. -** It returns a string with the devices name, -** or a NULL pointer, if the driver cannot -** support this device. -** -** attach: Allocate a control structure and prepare -** it. This function may use the pci mapping -** functions. See below. -** (configuration id) or type. -** -** count: A pointer to a unit counter. -** It's used by the pci configurator to -** allocate unit numbers. -** -**----------------------------------------------------------------- -*/ +#ifndef PCI_COMPAT +#define PCI_COMPAT +#endif +/* + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR 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. + * + * $Id$ + * + */ + +/* some PCI bus constants */ + +#define PCI_BUSMAX 255 /* highest supported bus number */ +#define PCI_SLOTMAX 31 /* highest supported slot number */ +#define PCI_FUNCMAX 7 /* highest supported function number */ +#define PCI_REGMAX 255 /* highest supported config register addr. */ + +#define PCI_MAXMAPS_0 6 /* max. no. of memory/port maps */ +#define PCI_MAXMAPS_1 2 /* max. no. of maps for PCI to PCI bridge */ +#define PCI_MAXMAPS_2 1 /* max. no. of maps for CardBus bridge */ + +/* pci_addr_t covers this system's PCI bus address space: 32 or 64 bit */ + +#ifdef PCI_A64 +typedef u_int64_t pci_addr_t; /* u_int64_t for system with 64bit addresses */ +#else +typedef u_int32_t pci_addr_t; /* u_int64_t for system with 64bit addresses */ +#endif + +/* map register information */ + +typedef struct { + u_int32_t base; + u_int8_t type; +#define PCI_MAPMEM 0x01 /* memory map */ +#define PCI_MAPMEMP 0x02 /* prefetchable memory map */ +#define PCI_MAPPORT 0x04 /* port map */ + u_int8_t ln2size; + u_int8_t ln2range; +/* u_int8_t dummy;*/ +} pcimap; + +/* config header information common to all header types */ + +typedef struct pcicfg { + struct pcicfg *parent; + struct pcicfg *next; + pcimap *map; /* pointer to array of PCI maps */ + void *hdrspec; /* pointer to header type specific data */ + + u_int16_t subvendor; /* card vendor ID */ + u_int16_t subdevice; /* card device ID, assigned by card vendor */ + u_int16_t vendor; /* chip vendor ID */ + u_int16_t device; /* chip device ID, assigned by chip vendor */ + + u_int16_t cmdreg; /* disable/enable chip and PCI options */ + u_int16_t statreg; /* supported PCI features and error state */ + + u_int8_t class; /* chip PCI class */ + u_int8_t subclass; /* chip PCI subclass */ + u_int8_t progif; /* chip PCI programming interface */ + u_int8_t revid; /* chip revision ID */ + + u_int8_t hdrtype; /* chip config header type */ + u_int8_t cachelnsz; /* cache line size in 4byte units */ + u_int8_t intpin; /* PCI interrupt pin */ + u_int8_t intline; /* interrupt line (IRQ for PC arch) */ + + u_int8_t mingnt; /* min. useful bus grant time in 250ns units */ + u_int8_t maxlat; /* max. tolerated bus grant latency in 250ns */ + u_int8_t lattimer; /* latency timer in units of 30ns bus cycles */ + + u_int8_t mfdev; /* multi-function device (from hdrtype reg) */ + u_int8_t nummaps; /* actual number of PCI maps used */ + + u_int8_t bus; /* config space bus address */ + u_int8_t slot; /* config space slot address */ + u_int8_t func; /* config space function number */ + + u_int8_t secondarybus; /* bus on secondary side of bridge, if any */ + u_int8_t subordinatebus; /* topmost bus number behind bridge, if any */ +} pcicfgregs; + +/* additional type 1 device config header information (PCI to PCI bridge) */ + +#ifdef PCI_A64 +#define PCI_PPBMEMBASE(h,l) ((((pci_addr_t)(h) << 32) + ((l)<<16)) & ~0xfffff) +#define PCI_PPBMEMLIMIT(h,l) ((((pci_addr_t)(h) << 32) + ((l)<<16)) | 0xfffff) +#else +#define PCI_PPBMEMBASE(h,l) (((l)<<16) & ~0xfffff) +#define PCI_PPBMEMLIMIT(h,l) (((l)<<16) | 0xfffff) +#endif /* PCI_A64 */ + +#define PCI_PPBIOBASE(h,l) ((((h)<<16) + ((l)<<8)) & ~0xfff) +#define PCI_PPBIOLIMIT(h,l) ((((h)<<16) + ((l)<<8)) | 0xfff) + +typedef struct { + pci_addr_t pmembase; /* base address of prefetchable memory */ + pci_addr_t pmemlimit; /* topmost address of prefetchable memory */ + u_int32_t membase; /* base address of memory window */ + u_int32_t memlimit; /* topmost address of memory window */ + u_int32_t iobase; /* base address of port window */ + u_int32_t iolimit; /* topmost address of port window */ + u_int16_t secstat; /* secondary bus status register */ + u_int16_t bridgectl; /* bridge control register */ + u_int8_t seclat; /* CardBus latency timer */ +} pcih1cfgregs; + +/* additional type 2 device config header information (CardBus bridge) */ + +typedef struct { + u_int32_t membase0; /* base address of memory window */ + u_int32_t memlimit0; /* topmost address of memory window */ + u_int32_t membase1; /* base address of memory window */ + u_int32_t memlimit1; /* topmost address of memory window */ + u_int32_t iobase0; /* base address of port window */ + u_int32_t iolimit0; /* topmost address of port window */ + u_int32_t iobase1; /* base address of port window */ + u_int32_t iolimit1; /* topmost address of port window */ + u_int32_t pccardif; /* PC Card 16bit IF legacy more base addr. */ + u_int16_t secstat; /* secondary bus status register */ + u_int16_t bridgectl; /* bridge control register */ + u_int8_t seclat; /* CardBus latency timer */ +} pcih2cfgregs; + +/* PCI bus attach definitions (there could be multiple PCI bus *trees* ... */ + +typedef struct pciattach { + int unit; + int pcibushigh; + struct pciattach *next; +} pciattach; + +/* externally visible functions */ + +int pci_probe (pciattach *attach); +void pci_drvattach(pcicfgregs *cfg); + +/* low level PCI config register functions provided by pcibus.c */ + +int pci_cfgopen (void); +int pci_cfgread (pcicfgregs *cfg, int reg, int bytes); +void pci_cfgwrite (pcicfgregs *cfg, int reg, int data, int bytes); + +/* for compatibility to FreeBSD-2.2 version of PCI code */ + +#ifdef PCI_COMPAT + +typedef pcicfgregs *pcici_t; +typedef unsigned pcidi_t; +typedef void pci_inthand_t(void *arg); + +#define pci_max_burst_len (3) + +/* just copied from old PCI code for now ... */ + +extern struct linker_set pcidevice_set; +extern int pci_mechanism; struct pci_device { char* pd_name; @@ -133,97 +187,17 @@ struct pci_device { int (*pd_shutdown) (int, int); }; -/*----------------------------------------------------------------- -** -** This table includes pointers to all pci device drivers. -** It should be generated by the linker. -** -**----------------------------------------------------------------- -*/ - -extern struct linker_set pcidevice_set; - -extern unsigned pci_max_burst_len; /* log2 of safe burst transfer length */ -extern unsigned pci_mechanism; -extern unsigned pci_maxdevice; - -/*----------------------------------------------------------------- -** -** Map a pci device to physical and virtual memory. -** -** Entry selects the register in the pci configuration -** space, which supplies the size of the region, and -** receives the physical address. -** -** In case of success the function sets the addresses -** in *va and *pa, and returns 1. -** In case of errors a message is written, -** and the function returns 0. -** -**----------------------------------------------------------------- -*/ - -int pci_map_mem (pcici_t tag, u_long entry, vm_offset_t *va, vm_offset_t *pa); - -/*----------------------------------------------------------------- -** -** Map a pci device to an io port area. -** -** Entry selects the register in the pci configuration -** space, which supplies the size of the region, and -** receives the port number. -** -** In case of success the function sets the port number in pa, -** and returns 1. -** In case of errors a message is written, -** and the function returns 0. -** -**----------------------------------------------------------------- -*/ - -int pci_map_port (pcici_t tag, u_long entry, u_short * pa); - -/*----------------------------------------------------------------- -** -** Map a pci interrupt to an isa irq line, and enable the interrupt. -** -** ----------------- -** -** func is the interrupt handler, arg is the argument -** to the handler (usually a pointer to a softc). -** -** The maskptr argument should be &bio_imask, -** &net_imask etc. or NULL. -** -** If there is any error, a message is written, and -** the function returns with zero. -** Else it returns with a value different to zero. -** -** ----------------- -** -** The irq number is read from the configuration space. -** (Should have been set by the bios). -** -** Supports multiple handlers per irq (shared interrupts). -** -**----------------------------------------------------------------- -*/ - -typedef void pci_inthand_t(void *arg); - -struct pci_int_desc { - struct pci_int_desc * pcid_next; - pcici_t pcid_tag; - pci_inthand_t *pcid_handler; - void* pcid_argument; - unsigned * pcid_maskptr; - unsigned pcid_tally; - unsigned pcid_mask; +struct pci_lkm { + struct pci_device *dvp; + struct pci_lkm *next; }; -int pci_map_int (pcici_t tag, pci_inthand_t *func, void *arg, - unsigned *maskptr); - +u_long pci_conf_read (pcici_t tag, u_long reg); +void pci_conf_write (pcici_t tag, u_long reg, u_long data); +int pci_map_port (pcici_t tag, u_long reg, u_short* pa); +int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa); +int pci_map_int (pcici_t tag, pci_inthand_t *func, void *arg, unsigned *maskptr); int pci_unmap_int (pcici_t tag); +int pci_register_lkm (struct pci_device *dvp, int if_revision); -#endif +#endif /* PCI_COMPAT */ diff --git a/sys/i386/include/pci_cfgreg.h b/sys/i386/include/pci_cfgreg.h new file mode 100644 index 0000000..44556e7 --- /dev/null +++ b/sys/i386/include/pci_cfgreg.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR 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. + * + * $Id$ + * + */ + +#define CONF1_ADDR_PORT 0x0cf8 +#define CONF1_DATA_PORT 0x0cfc + +#define CONF1_ENABLE 0x80000000ul +#define CONF1_ENABLE_CHK 0x80000000ul +#define CONF1_ENABLE_MSK 0x7ff00000ul +#define CONF1_ENABLE_CHK1 0xff000001ul +#define CONF1_ENABLE_MSK1 0x80000001ul +#define CONF1_ENABLE_RES1 0x80000000ul + +#define CONF2_ENABLE_PORT 0x0cf8 +#ifdef PC98 +#define CONF2_FORWARD_PORT 0x0cf9 +#else +#define CONF2_FORWARD_PORT 0x0cfa +#endif + +#define CONF2_ENABLE_CHK 0x0e +#define CONF2_ENABLE_RES 0x0e diff --git a/sys/i386/isa/pcibus.c b/sys/i386/isa/pcibus.c index 31de543..df84794 100644 --- a/sys/i386/isa/pcibus.c +++ b/sys/i386/isa/pcibus.c @@ -1,538 +1,265 @@ -/************************************************************************** -** -** $Id: pcibus.c,v 1.34 1997/04/09 09:16:27 se Exp $ -** -** pci bus subroutines for i386 architecture. -** -** FreeBSD -** -**------------------------------------------------------------------------- -** -** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR 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. -** -*************************************************************************** -*/ - -#include "vector.h" - -#include <sys/param.h> +/* + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR 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. + * + * $Id$ + * + */ + +#include <sys/types.h> #include <sys/systm.h> -#include <sys/kernel.h> - -#include <i386/isa/icu.h> -#include <i386/isa/isa_device.h> -#include <pci/pcivar.h> #include <pci/pcireg.h> -#include <pci/pcibus.h> - -/*----------------------------------------------------------------- -** -** The following functions are provided by the pci bios. -** They are used only by the pci configuration. -** -** pcibus_setup(): -** Probes for a pci system. -** Sets pci_maxdevice and pci_mechanism. -** -** pcibus_tag(): -** Creates a handle for pci configuration space access. -** This handle is given to the read/write functions. -** -** pcibus_ftag(): -** Creates a modified handle. -** -** pcibus_read(): -** Read a long word from the pci configuration space. -** Requires a tag (from pcitag) and the register -** number (should be a long word aligned one). -** -** pcibus_write(): -** Writes a long word to the pci configuration space. -** Requires a tag (from pcitag), the register number -** (should be a long word aligned one), and a value. -** -** pcibus_regirq(): -** Register an interrupt handler for a pci device. -** Requires a tag (from pcitag), the register number -** (should be a long word aligned one), and a value. -** -**----------------------------------------------------------------- -*/ - -static int -pcibus_check (void); - -static void -pcibus_setup (void); - -static pcici_t -pcibus_tag (u_char bus, u_char device, u_char func); - -static pcici_t -pcibus_ftag (pcici_t tag, u_char func); - -static u_long -pcibus_read (pcici_t tag, u_long reg); +#include <pci/pcivar.h> +#include <i386/isa/pcibus.h> -static void -pcibus_write (pcici_t tag, u_long reg, u_long data); +#ifdef PCI_COMPAT +/* XXX this is a terrible hack, which keeps the Tekram AMD SCSI driver happy */ +#define cfgmech pci_mechanism +int cfgmech; +#else +static int cfgmech; +#endif /* PCI_COMPAT */ +static int devmax; -static int -pcibus_ihandler_attach (int irq, inthand2_t *func, int arg, unsigned* maskptr); +/* enable configuration space accesses and return data port address */ static int -pcibus_ihandler_detach (int irq, inthand2_t *func); +pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) +{ + int dataport = 0; + + if (bus <= PCI_BUSMAX + && slot < devmax + && func <= PCI_FUNCMAX + && reg <= PCI_REGMAX + && bytes != 3 + && (unsigned) bytes <= 4 + && (reg & (bytes -1)) == 0) { + switch (cfgmech) { + case 1: + outl(CONF1_ADDR_PORT, + (bus << 16) | (slot << 11) | (func << 8) | reg); + dataport = CONF1_DATA_PORT; + break; + case 2: + outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); + outb(CONF2_FORWARD_PORT, bus); + dataport = 0xc000 | (slot << 8) | reg; + break; + } + } + return (dataport); +} -static int -pcibus_imask_include (int irq, unsigned* maskptr); +/* disable configuration space accesses */ -static int -pcibus_imask_exclude (int irq, unsigned* maskptr); - -static struct pcibus i386pci = { - "pci", - pcibus_setup, - pcibus_tag, - pcibus_ftag, - pcibus_read, - pcibus_write, - pcibus_ihandler_attach, - pcibus_ihandler_detach, - pcibus_imask_include, - pcibus_imask_exclude, -}; +static void +pci_cfgdisable(void) +{ + switch (cfgmech) { + case 1: + outl(CONF1_ADDR_PORT, 0); + break; + case 2: + outb(CONF2_ENABLE_PORT, 0); + outb(CONF2_FORWARD_PORT, 0); + break; + } +} -/* -** Announce structure to generic driver -*/ +/* read configuration space register */ -DATA_SET (pcibus_set, i386pci); +int +pci_cfgread(pcicfgregs *cfg, int reg, int bytes) +{ + int data = -1; + int port; -/*-------------------------------------------------------------------- -** -** Determine configuration mode -** -**-------------------------------------------------------------------- -*/ + port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); + if (port != 0) { + switch (bytes) { + case 1: + data = inb(port); + break; + case 2: + data = inw(port); + break; + case 4: + data = inl(port); + break; + } + pci_cfgdisable(); + } + return (data); +} -#define CONF1_ADDR_PORT 0x0cf8 -#define CONF1_DATA_PORT 0x0cfc +/* write configuration space register */ -#define CONF1_ENABLE 0x80000000ul -#define CONF1_ENABLE_CHK 0x80000000ul -#define CONF1_ENABLE_MSK 0x7ff00000ul -#define CONF1_ENABLE_CHK1 0xff000001ul -#define CONF1_ENABLE_MSK1 0x80000001ul -#define CONF1_ENABLE_RES1 0x80000000ul +void +pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) +{ + int port; -#define CONF2_ENABLE_PORT 0x0cf8 -#ifdef PC98 -#define CONF2_FORWARD_PORT 0x0cf9 -#else -#define CONF2_FORWARD_PORT 0x0cfa -#endif + port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); + if (port != 0) { + switch (bytes) { + case 1: + outb(port, data); + break; + case 2: + outw(port, data); + break; + case 4: + outl(port, data); + break; + } + pci_cfgdisable(); + } +} -#define CONF2_ENABLE_CHK 0x0e -#define CONF2_ENABLE_RES 0x0e +/* check whether the configuration mechanism has been correct identified */ static int -pcibus_check (void) +pci_cfgcheck(int maxdev) { u_char device; - if (bootverbose) printf ("pcibus_check:\tdevice "); + if (bootverbose) + printf("pci_cfgcheck:\tdevice "); - for (device = 0; device < pci_maxdevice; device++) { - unsigned long id, class, header; + for (device = 0; device < maxdev; device++) { + unsigned id, class, header; if (bootverbose) - printf ("%d ", device); - id = pcibus_read (pcibus_tag (0,device,0), 0); - if ((id == 0) || (id == 0xfffffffful)) + printf("%d ", device); + + id = inl(pci_cfgenable(0, device, 0, 0, 4)); + if (id == 0 || id == -1) continue; - class = pcibus_read (pcibus_tag (0,device,0), 8); + class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8; if (bootverbose) - printf ("[class=%x] ", class >> 8); - if ((class & 0xffffff00) == 0 || (class & 0xf8f0ff00) != 0) + printf("[class=%06x] ", class); + if (class == 0 || (class & 0xf8f0ff) != 0) continue; - header = pcibus_read (pcibus_tag (0,device,0), 12); + header = inb(pci_cfgenable(0, device, 0, 14, 1)); if (bootverbose) - printf ("[hdr=%x] ", (header >> 16) & 0xff); - if ((header & 0x007e0000) != 0) + printf("[hdr=%02x] ", header); + if ((header & 0x7e) != 0) continue; - if (bootverbose) printf ("is there (id=%08lx)\n", id); - return 1; + if (bootverbose) + printf("is there (id=%08x)\n", id); + + pci_cfgdisable(); + return (1); } if (bootverbose) - printf ("-- nothing found\n"); - return 0; + printf("-- nothing found\n"); + + pci_cfgdisable(); + return (0); } -static void -pcibus_setup (void) +int +pci_cfgopen(void) { unsigned long mode1res,oldval1; unsigned char mode2res,oldval2; - oldval1 = inl (CONF1_ADDR_PORT); + oldval1 = inl(CONF1_ADDR_PORT); if (bootverbose) { - printf ("pcibus_setup(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", oldval1); + printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", + oldval1); } - /*--------------------------------------- - ** Assume configuration mechanism 1 for now ... - **--------------------------------------- - */ - if ((oldval1 & CONF1_ENABLE_MSK) == 0) { - pci_mechanism = 1; - pci_maxdevice = 32; + cfgmech = 1; + devmax = 32; - outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK); - outb (CONF1_ADDR_PORT +3, 0); - mode1res = inl (CONF1_ADDR_PORT); - outl (CONF1_ADDR_PORT, oldval1); + outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); + outb(CONF1_ADDR_PORT +3, 0); + mode1res = inl(CONF1_ADDR_PORT); + outl(CONF1_ADDR_PORT, oldval1); if (bootverbose) - printf ("pcibus_setup(1a):\tmode1res=0x%08lx (0x%08lx)\n", - mode1res, CONF1_ENABLE_CHK); + printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", + mode1res, CONF1_ENABLE_CHK); if (mode1res) { - if (pcibus_check()) - return; - }; + if (pci_cfgcheck(32)) + return (cfgmech); + } - outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); + outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); mode1res = inl(CONF1_ADDR_PORT); - outl (CONF1_ADDR_PORT, oldval1); + outl(CONF1_ADDR_PORT, oldval1); if (bootverbose) - printf ("pcibus_setup(1b):\tmode1res=0x%08lx (0x%08lx)\n", - mode1res, CONF1_ENABLE_CHK1); + printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", + mode1res, CONF1_ENABLE_CHK1); if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { - if (pcibus_check()) - return; - }; + if (pci_cfgcheck(32)) + return (cfgmech); + } } - /*--------------------------------------- - ** Try configuration mechanism 2 ... - **--------------------------------------- - */ - - oldval2 = inb (CONF2_ENABLE_PORT); + oldval2 = inb(CONF2_ENABLE_PORT); if (bootverbose) { - printf ("pcibus_setup(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", oldval2); + printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", + oldval2); } if ((oldval2 & 0xf0) == 0) { - pci_mechanism = 2; - pci_maxdevice = 16; - - outb (CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); + cfgmech = 2; + devmax = 16; + + outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); mode2res = inb(CONF2_ENABLE_PORT); - outb (CONF2_ENABLE_PORT, oldval2); + outb(CONF2_ENABLE_PORT, oldval2); if (bootverbose) - printf ("pcibus_setup(2a):\tmode2res=0x%02x (0x%02x)\n", - mode2res, CONF2_ENABLE_CHK); + printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", + mode2res, CONF2_ENABLE_CHK); if (mode2res == CONF2_ENABLE_RES) { - if (bootverbose) - printf ("pcibus_setup(2a):\tnow trying mechanism 2\n"); - - if (pcibus_check()) - return; - } - } - - /*--------------------------------------- - ** No PCI bus host bridge found - **--------------------------------------- - */ - - pci_mechanism = 0; - pci_maxdevice = 0; -} - -/*-------------------------------------------------------------------- -** -** Build a pcitag from bus, device and function number -** -**-------------------------------------------------------------------- -*/ - -static pcici_t -pcibus_tag (unsigned char bus, unsigned char device, unsigned char func) -{ - pcici_t tag; - - tag.cfg1 = 0; - if (func >= 8) return tag; - - switch (pci_mechanism) { - - case 1: - if (device < 32) { - tag.cfg1 = CONF1_ENABLE - | (((u_long) bus ) << 16ul) - | (((u_long) device) << 11ul) - | (((u_long) func ) << 8ul); - } - break; - case 2: - if (device < 16) { - tag.cfg2.port = 0xc000 | (device << 8ul); - tag.cfg2.enable = 0xf0 | (func << 1ul); - tag.cfg2.forward = bus; - } - break; - }; - return tag; -} - -static pcici_t -pcibus_ftag (pcici_t tag, u_char func) -{ - switch (pci_mechanism) { - - case 1: - tag.cfg1 &= ~0x700ul; - tag.cfg1 |= (((u_long) func) << 8ul); - break; - case 2: - tag.cfg2.enable = 0xf0 | (func << 1ul); - break; - }; - return tag; -} - -/*-------------------------------------------------------------------- -** -** Read register from configuration space. -** -**-------------------------------------------------------------------- -*/ - -static u_long -pcibus_read (pcici_t tag, u_long reg) -{ - u_long addr, data = 0; - - if (!tag.cfg1) return (0xfffffffful); - - switch (pci_mechanism) { - - case 1: - addr = tag.cfg1 | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_read(1): addr=%x ", addr); -#endif - outl (CONF1_ADDR_PORT, addr); - data = inl (CONF1_DATA_PORT); - outl (CONF1_ADDR_PORT, 0 ); - break; - - case 2: - addr = tag.cfg2.port | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_read(2): addr=%x ", addr); -#endif - outb (CONF2_ENABLE_PORT , tag.cfg2.enable ); - outb (CONF2_FORWARD_PORT, tag.cfg2.forward); - - data = inl ((u_short) addr); - - outb (CONF2_ENABLE_PORT, 0); - outb (CONF2_FORWARD_PORT, 0); - break; - }; - -#ifdef PCI_DEBUG - printf ("data=%x\n", data); -#endif - - return (data); -} - -/*-------------------------------------------------------------------- -** -** Write register into configuration space. -** -**-------------------------------------------------------------------- -*/ - -static void -pcibus_write (pcici_t tag, u_long reg, u_long data) -{ - u_long addr; - - if (!tag.cfg1) return; - - switch (pci_mechanism) { - - case 1: - addr = tag.cfg1 | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_write(1): addr=%x data=%x\n", - addr, data); -#endif - outl (CONF1_ADDR_PORT, addr); - outl (CONF1_DATA_PORT, data); - outl (CONF1_ADDR_PORT, 0 ); - break; - - case 2: - addr = tag.cfg2.port | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_write(2): addr=%x data=%x\n", - addr, data); -#endif - outb (CONF2_ENABLE_PORT, tag.cfg2.enable); - outb (CONF2_FORWARD_PORT, tag.cfg2.forward); - - outl ((u_short) addr, data); - - outb (CONF2_ENABLE_PORT, 0); - outb (CONF2_FORWARD_PORT, 0); - break; - }; -} - -/*----------------------------------------------------------------------- -** -** Register an interrupt handler for a pci device. -** -**----------------------------------------------------------------------- -*/ - -static int -pcibus_ihandler_attach (int irq, inthand2_t *func, int arg, unsigned * maskptr) -{ - char buf[16]; - char *cp; - int free_id, id, result; + if (bootverbose) + printf("pci_open(2a):\tnow trying mechanism 2\n"); - sprintf(buf, "pci irq%d", irq); - for (cp = intrnames, free_id = 0, id = 0; id < NR_DEVICES; id++) { - if (strcmp(cp, buf) == 0) - break; - if (free_id <= 0 && strcmp(cp, "pci irqnn") == 0) - free_id = id; - while (*cp++ != '\0') - ; - } - if (id == NR_DEVICES) { - id = free_id; - if (id == 0) { - /* - * All pci irq counters are in use, perhaps because - * config is old so there aren't any. Abuse the - * clk0 counter. - */ - printf ( - "pcibus_ihandler_attach: counting pci irq%d's as clk0 irqs\n", - irq); + if (pci_cfgcheck(16)) + return (cfgmech); } } - result = register_intr( - irq, /* isa irq */ - id, /* device id */ - 0, /* flags? */ - func, /* handler */ - maskptr, /* mask pointer */ - arg); /* handler arg */ - - if (result) { - printf ("@@@ pcibus_ihandler_attach: result=%d\n", result); - return (result); - }; - update_intr_masks(); - - INTREN ((1ul<<irq)); - return (0); -} - -static int -pcibus_ihandler_detach (int irq, inthand2_t *func) -{ - int result; - - INTRDIS ((1ul<<irq)); - - result = unregister_intr (irq, func); - - if (result) - printf ("@@@ pcibus_ihandler_detach: result=%d\n", result); - - update_intr_masks(); - - return (result); -} - -static int -pcibus_imask_include (int irq, unsigned* maskptr) -{ - unsigned mask; - - if (!maskptr) return (0); - mask = 1ul << irq; - - if (*maskptr & mask) - return (-1); - - INTRMASK (*maskptr, mask); - update_intr_masks(); - - return (0); -} - -static int -pcibus_imask_exclude (int irq, unsigned* maskptr) -{ - unsigned mask; - - if (!maskptr) return (0); - - mask = 1ul << irq; - - if (! (*maskptr & mask)) - return (-1); - - INTRUNMASK (*maskptr, mask); - update_intr_masks(); - - return (0); + cfgmech = 0; + devmax = 0; + return (cfgmech); } diff --git a/sys/i386/isa/pcibus.h b/sys/i386/isa/pcibus.h new file mode 100644 index 0000000..44556e7 --- /dev/null +++ b/sys/i386/isa/pcibus.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR 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. + * + * $Id$ + * + */ + +#define CONF1_ADDR_PORT 0x0cf8 +#define CONF1_DATA_PORT 0x0cfc + +#define CONF1_ENABLE 0x80000000ul +#define CONF1_ENABLE_CHK 0x80000000ul +#define CONF1_ENABLE_MSK 0x7ff00000ul +#define CONF1_ENABLE_CHK1 0xff000001ul +#define CONF1_ENABLE_MSK1 0x80000001ul +#define CONF1_ENABLE_RES1 0x80000000ul + +#define CONF2_ENABLE_PORT 0x0cf8 +#ifdef PC98 +#define CONF2_FORWARD_PORT 0x0cf9 +#else +#define CONF2_FORWARD_PORT 0x0cfa +#endif + +#define CONF2_ENABLE_CHK 0x0e +#define CONF2_ENABLE_RES 0x0e diff --git a/sys/i386/pci/pci_bus.c b/sys/i386/pci/pci_bus.c index 31de543..df84794 100644 --- a/sys/i386/pci/pci_bus.c +++ b/sys/i386/pci/pci_bus.c @@ -1,538 +1,265 @@ -/************************************************************************** -** -** $Id: pcibus.c,v 1.34 1997/04/09 09:16:27 se Exp $ -** -** pci bus subroutines for i386 architecture. -** -** FreeBSD -** -**------------------------------------------------------------------------- -** -** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR 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. -** -*************************************************************************** -*/ - -#include "vector.h" - -#include <sys/param.h> +/* + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR 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. + * + * $Id$ + * + */ + +#include <sys/types.h> #include <sys/systm.h> -#include <sys/kernel.h> - -#include <i386/isa/icu.h> -#include <i386/isa/isa_device.h> -#include <pci/pcivar.h> #include <pci/pcireg.h> -#include <pci/pcibus.h> - -/*----------------------------------------------------------------- -** -** The following functions are provided by the pci bios. -** They are used only by the pci configuration. -** -** pcibus_setup(): -** Probes for a pci system. -** Sets pci_maxdevice and pci_mechanism. -** -** pcibus_tag(): -** Creates a handle for pci configuration space access. -** This handle is given to the read/write functions. -** -** pcibus_ftag(): -** Creates a modified handle. -** -** pcibus_read(): -** Read a long word from the pci configuration space. -** Requires a tag (from pcitag) and the register -** number (should be a long word aligned one). -** -** pcibus_write(): -** Writes a long word to the pci configuration space. -** Requires a tag (from pcitag), the register number -** (should be a long word aligned one), and a value. -** -** pcibus_regirq(): -** Register an interrupt handler for a pci device. -** Requires a tag (from pcitag), the register number -** (should be a long word aligned one), and a value. -** -**----------------------------------------------------------------- -*/ - -static int -pcibus_check (void); - -static void -pcibus_setup (void); - -static pcici_t -pcibus_tag (u_char bus, u_char device, u_char func); - -static pcici_t -pcibus_ftag (pcici_t tag, u_char func); - -static u_long -pcibus_read (pcici_t tag, u_long reg); +#include <pci/pcivar.h> +#include <i386/isa/pcibus.h> -static void -pcibus_write (pcici_t tag, u_long reg, u_long data); +#ifdef PCI_COMPAT +/* XXX this is a terrible hack, which keeps the Tekram AMD SCSI driver happy */ +#define cfgmech pci_mechanism +int cfgmech; +#else +static int cfgmech; +#endif /* PCI_COMPAT */ +static int devmax; -static int -pcibus_ihandler_attach (int irq, inthand2_t *func, int arg, unsigned* maskptr); +/* enable configuration space accesses and return data port address */ static int -pcibus_ihandler_detach (int irq, inthand2_t *func); +pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) +{ + int dataport = 0; + + if (bus <= PCI_BUSMAX + && slot < devmax + && func <= PCI_FUNCMAX + && reg <= PCI_REGMAX + && bytes != 3 + && (unsigned) bytes <= 4 + && (reg & (bytes -1)) == 0) { + switch (cfgmech) { + case 1: + outl(CONF1_ADDR_PORT, + (bus << 16) | (slot << 11) | (func << 8) | reg); + dataport = CONF1_DATA_PORT; + break; + case 2: + outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); + outb(CONF2_FORWARD_PORT, bus); + dataport = 0xc000 | (slot << 8) | reg; + break; + } + } + return (dataport); +} -static int -pcibus_imask_include (int irq, unsigned* maskptr); +/* disable configuration space accesses */ -static int -pcibus_imask_exclude (int irq, unsigned* maskptr); - -static struct pcibus i386pci = { - "pci", - pcibus_setup, - pcibus_tag, - pcibus_ftag, - pcibus_read, - pcibus_write, - pcibus_ihandler_attach, - pcibus_ihandler_detach, - pcibus_imask_include, - pcibus_imask_exclude, -}; +static void +pci_cfgdisable(void) +{ + switch (cfgmech) { + case 1: + outl(CONF1_ADDR_PORT, 0); + break; + case 2: + outb(CONF2_ENABLE_PORT, 0); + outb(CONF2_FORWARD_PORT, 0); + break; + } +} -/* -** Announce structure to generic driver -*/ +/* read configuration space register */ -DATA_SET (pcibus_set, i386pci); +int +pci_cfgread(pcicfgregs *cfg, int reg, int bytes) +{ + int data = -1; + int port; -/*-------------------------------------------------------------------- -** -** Determine configuration mode -** -**-------------------------------------------------------------------- -*/ + port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); + if (port != 0) { + switch (bytes) { + case 1: + data = inb(port); + break; + case 2: + data = inw(port); + break; + case 4: + data = inl(port); + break; + } + pci_cfgdisable(); + } + return (data); +} -#define CONF1_ADDR_PORT 0x0cf8 -#define CONF1_DATA_PORT 0x0cfc +/* write configuration space register */ -#define CONF1_ENABLE 0x80000000ul -#define CONF1_ENABLE_CHK 0x80000000ul -#define CONF1_ENABLE_MSK 0x7ff00000ul -#define CONF1_ENABLE_CHK1 0xff000001ul -#define CONF1_ENABLE_MSK1 0x80000001ul -#define CONF1_ENABLE_RES1 0x80000000ul +void +pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) +{ + int port; -#define CONF2_ENABLE_PORT 0x0cf8 -#ifdef PC98 -#define CONF2_FORWARD_PORT 0x0cf9 -#else -#define CONF2_FORWARD_PORT 0x0cfa -#endif + port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); + if (port != 0) { + switch (bytes) { + case 1: + outb(port, data); + break; + case 2: + outw(port, data); + break; + case 4: + outl(port, data); + break; + } + pci_cfgdisable(); + } +} -#define CONF2_ENABLE_CHK 0x0e -#define CONF2_ENABLE_RES 0x0e +/* check whether the configuration mechanism has been correct identified */ static int -pcibus_check (void) +pci_cfgcheck(int maxdev) { u_char device; - if (bootverbose) printf ("pcibus_check:\tdevice "); + if (bootverbose) + printf("pci_cfgcheck:\tdevice "); - for (device = 0; device < pci_maxdevice; device++) { - unsigned long id, class, header; + for (device = 0; device < maxdev; device++) { + unsigned id, class, header; if (bootverbose) - printf ("%d ", device); - id = pcibus_read (pcibus_tag (0,device,0), 0); - if ((id == 0) || (id == 0xfffffffful)) + printf("%d ", device); + + id = inl(pci_cfgenable(0, device, 0, 0, 4)); + if (id == 0 || id == -1) continue; - class = pcibus_read (pcibus_tag (0,device,0), 8); + class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8; if (bootverbose) - printf ("[class=%x] ", class >> 8); - if ((class & 0xffffff00) == 0 || (class & 0xf8f0ff00) != 0) + printf("[class=%06x] ", class); + if (class == 0 || (class & 0xf8f0ff) != 0) continue; - header = pcibus_read (pcibus_tag (0,device,0), 12); + header = inb(pci_cfgenable(0, device, 0, 14, 1)); if (bootverbose) - printf ("[hdr=%x] ", (header >> 16) & 0xff); - if ((header & 0x007e0000) != 0) + printf("[hdr=%02x] ", header); + if ((header & 0x7e) != 0) continue; - if (bootverbose) printf ("is there (id=%08lx)\n", id); - return 1; + if (bootverbose) + printf("is there (id=%08x)\n", id); + + pci_cfgdisable(); + return (1); } if (bootverbose) - printf ("-- nothing found\n"); - return 0; + printf("-- nothing found\n"); + + pci_cfgdisable(); + return (0); } -static void -pcibus_setup (void) +int +pci_cfgopen(void) { unsigned long mode1res,oldval1; unsigned char mode2res,oldval2; - oldval1 = inl (CONF1_ADDR_PORT); + oldval1 = inl(CONF1_ADDR_PORT); if (bootverbose) { - printf ("pcibus_setup(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", oldval1); + printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", + oldval1); } - /*--------------------------------------- - ** Assume configuration mechanism 1 for now ... - **--------------------------------------- - */ - if ((oldval1 & CONF1_ENABLE_MSK) == 0) { - pci_mechanism = 1; - pci_maxdevice = 32; + cfgmech = 1; + devmax = 32; - outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK); - outb (CONF1_ADDR_PORT +3, 0); - mode1res = inl (CONF1_ADDR_PORT); - outl (CONF1_ADDR_PORT, oldval1); + outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); + outb(CONF1_ADDR_PORT +3, 0); + mode1res = inl(CONF1_ADDR_PORT); + outl(CONF1_ADDR_PORT, oldval1); if (bootverbose) - printf ("pcibus_setup(1a):\tmode1res=0x%08lx (0x%08lx)\n", - mode1res, CONF1_ENABLE_CHK); + printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", + mode1res, CONF1_ENABLE_CHK); if (mode1res) { - if (pcibus_check()) - return; - }; + if (pci_cfgcheck(32)) + return (cfgmech); + } - outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); + outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); mode1res = inl(CONF1_ADDR_PORT); - outl (CONF1_ADDR_PORT, oldval1); + outl(CONF1_ADDR_PORT, oldval1); if (bootverbose) - printf ("pcibus_setup(1b):\tmode1res=0x%08lx (0x%08lx)\n", - mode1res, CONF1_ENABLE_CHK1); + printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", + mode1res, CONF1_ENABLE_CHK1); if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { - if (pcibus_check()) - return; - }; + if (pci_cfgcheck(32)) + return (cfgmech); + } } - /*--------------------------------------- - ** Try configuration mechanism 2 ... - **--------------------------------------- - */ - - oldval2 = inb (CONF2_ENABLE_PORT); + oldval2 = inb(CONF2_ENABLE_PORT); if (bootverbose) { - printf ("pcibus_setup(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", oldval2); + printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", + oldval2); } if ((oldval2 & 0xf0) == 0) { - pci_mechanism = 2; - pci_maxdevice = 16; - - outb (CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); + cfgmech = 2; + devmax = 16; + + outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); mode2res = inb(CONF2_ENABLE_PORT); - outb (CONF2_ENABLE_PORT, oldval2); + outb(CONF2_ENABLE_PORT, oldval2); if (bootverbose) - printf ("pcibus_setup(2a):\tmode2res=0x%02x (0x%02x)\n", - mode2res, CONF2_ENABLE_CHK); + printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", + mode2res, CONF2_ENABLE_CHK); if (mode2res == CONF2_ENABLE_RES) { - if (bootverbose) - printf ("pcibus_setup(2a):\tnow trying mechanism 2\n"); - - if (pcibus_check()) - return; - } - } - - /*--------------------------------------- - ** No PCI bus host bridge found - **--------------------------------------- - */ - - pci_mechanism = 0; - pci_maxdevice = 0; -} - -/*-------------------------------------------------------------------- -** -** Build a pcitag from bus, device and function number -** -**-------------------------------------------------------------------- -*/ - -static pcici_t -pcibus_tag (unsigned char bus, unsigned char device, unsigned char func) -{ - pcici_t tag; - - tag.cfg1 = 0; - if (func >= 8) return tag; - - switch (pci_mechanism) { - - case 1: - if (device < 32) { - tag.cfg1 = CONF1_ENABLE - | (((u_long) bus ) << 16ul) - | (((u_long) device) << 11ul) - | (((u_long) func ) << 8ul); - } - break; - case 2: - if (device < 16) { - tag.cfg2.port = 0xc000 | (device << 8ul); - tag.cfg2.enable = 0xf0 | (func << 1ul); - tag.cfg2.forward = bus; - } - break; - }; - return tag; -} - -static pcici_t -pcibus_ftag (pcici_t tag, u_char func) -{ - switch (pci_mechanism) { - - case 1: - tag.cfg1 &= ~0x700ul; - tag.cfg1 |= (((u_long) func) << 8ul); - break; - case 2: - tag.cfg2.enable = 0xf0 | (func << 1ul); - break; - }; - return tag; -} - -/*-------------------------------------------------------------------- -** -** Read register from configuration space. -** -**-------------------------------------------------------------------- -*/ - -static u_long -pcibus_read (pcici_t tag, u_long reg) -{ - u_long addr, data = 0; - - if (!tag.cfg1) return (0xfffffffful); - - switch (pci_mechanism) { - - case 1: - addr = tag.cfg1 | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_read(1): addr=%x ", addr); -#endif - outl (CONF1_ADDR_PORT, addr); - data = inl (CONF1_DATA_PORT); - outl (CONF1_ADDR_PORT, 0 ); - break; - - case 2: - addr = tag.cfg2.port | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_read(2): addr=%x ", addr); -#endif - outb (CONF2_ENABLE_PORT , tag.cfg2.enable ); - outb (CONF2_FORWARD_PORT, tag.cfg2.forward); - - data = inl ((u_short) addr); - - outb (CONF2_ENABLE_PORT, 0); - outb (CONF2_FORWARD_PORT, 0); - break; - }; - -#ifdef PCI_DEBUG - printf ("data=%x\n", data); -#endif - - return (data); -} - -/*-------------------------------------------------------------------- -** -** Write register into configuration space. -** -**-------------------------------------------------------------------- -*/ - -static void -pcibus_write (pcici_t tag, u_long reg, u_long data) -{ - u_long addr; - - if (!tag.cfg1) return; - - switch (pci_mechanism) { - - case 1: - addr = tag.cfg1 | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_write(1): addr=%x data=%x\n", - addr, data); -#endif - outl (CONF1_ADDR_PORT, addr); - outl (CONF1_DATA_PORT, data); - outl (CONF1_ADDR_PORT, 0 ); - break; - - case 2: - addr = tag.cfg2.port | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_write(2): addr=%x data=%x\n", - addr, data); -#endif - outb (CONF2_ENABLE_PORT, tag.cfg2.enable); - outb (CONF2_FORWARD_PORT, tag.cfg2.forward); - - outl ((u_short) addr, data); - - outb (CONF2_ENABLE_PORT, 0); - outb (CONF2_FORWARD_PORT, 0); - break; - }; -} - -/*----------------------------------------------------------------------- -** -** Register an interrupt handler for a pci device. -** -**----------------------------------------------------------------------- -*/ - -static int -pcibus_ihandler_attach (int irq, inthand2_t *func, int arg, unsigned * maskptr) -{ - char buf[16]; - char *cp; - int free_id, id, result; + if (bootverbose) + printf("pci_open(2a):\tnow trying mechanism 2\n"); - sprintf(buf, "pci irq%d", irq); - for (cp = intrnames, free_id = 0, id = 0; id < NR_DEVICES; id++) { - if (strcmp(cp, buf) == 0) - break; - if (free_id <= 0 && strcmp(cp, "pci irqnn") == 0) - free_id = id; - while (*cp++ != '\0') - ; - } - if (id == NR_DEVICES) { - id = free_id; - if (id == 0) { - /* - * All pci irq counters are in use, perhaps because - * config is old so there aren't any. Abuse the - * clk0 counter. - */ - printf ( - "pcibus_ihandler_attach: counting pci irq%d's as clk0 irqs\n", - irq); + if (pci_cfgcheck(16)) + return (cfgmech); } } - result = register_intr( - irq, /* isa irq */ - id, /* device id */ - 0, /* flags? */ - func, /* handler */ - maskptr, /* mask pointer */ - arg); /* handler arg */ - - if (result) { - printf ("@@@ pcibus_ihandler_attach: result=%d\n", result); - return (result); - }; - update_intr_masks(); - - INTREN ((1ul<<irq)); - return (0); -} - -static int -pcibus_ihandler_detach (int irq, inthand2_t *func) -{ - int result; - - INTRDIS ((1ul<<irq)); - - result = unregister_intr (irq, func); - - if (result) - printf ("@@@ pcibus_ihandler_detach: result=%d\n", result); - - update_intr_masks(); - - return (result); -} - -static int -pcibus_imask_include (int irq, unsigned* maskptr) -{ - unsigned mask; - - if (!maskptr) return (0); - mask = 1ul << irq; - - if (*maskptr & mask) - return (-1); - - INTRMASK (*maskptr, mask); - update_intr_masks(); - - return (0); -} - -static int -pcibus_imask_exclude (int irq, unsigned* maskptr) -{ - unsigned mask; - - if (!maskptr) return (0); - - mask = 1ul << irq; - - if (! (*maskptr & mask)) - return (-1); - - INTRUNMASK (*maskptr, mask); - update_intr_masks(); - - return (0); + cfgmech = 0; + devmax = 0; + return (cfgmech); } diff --git a/sys/i386/pci/pci_cfgreg.c b/sys/i386/pci/pci_cfgreg.c index 31de543..df84794 100644 --- a/sys/i386/pci/pci_cfgreg.c +++ b/sys/i386/pci/pci_cfgreg.c @@ -1,538 +1,265 @@ -/************************************************************************** -** -** $Id: pcibus.c,v 1.34 1997/04/09 09:16:27 se Exp $ -** -** pci bus subroutines for i386 architecture. -** -** FreeBSD -** -**------------------------------------------------------------------------- -** -** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR 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. -** -*************************************************************************** -*/ - -#include "vector.h" - -#include <sys/param.h> +/* + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR 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. + * + * $Id$ + * + */ + +#include <sys/types.h> #include <sys/systm.h> -#include <sys/kernel.h> - -#include <i386/isa/icu.h> -#include <i386/isa/isa_device.h> -#include <pci/pcivar.h> #include <pci/pcireg.h> -#include <pci/pcibus.h> - -/*----------------------------------------------------------------- -** -** The following functions are provided by the pci bios. -** They are used only by the pci configuration. -** -** pcibus_setup(): -** Probes for a pci system. -** Sets pci_maxdevice and pci_mechanism. -** -** pcibus_tag(): -** Creates a handle for pci configuration space access. -** This handle is given to the read/write functions. -** -** pcibus_ftag(): -** Creates a modified handle. -** -** pcibus_read(): -** Read a long word from the pci configuration space. -** Requires a tag (from pcitag) and the register -** number (should be a long word aligned one). -** -** pcibus_write(): -** Writes a long word to the pci configuration space. -** Requires a tag (from pcitag), the register number -** (should be a long word aligned one), and a value. -** -** pcibus_regirq(): -** Register an interrupt handler for a pci device. -** Requires a tag (from pcitag), the register number -** (should be a long word aligned one), and a value. -** -**----------------------------------------------------------------- -*/ - -static int -pcibus_check (void); - -static void -pcibus_setup (void); - -static pcici_t -pcibus_tag (u_char bus, u_char device, u_char func); - -static pcici_t -pcibus_ftag (pcici_t tag, u_char func); - -static u_long -pcibus_read (pcici_t tag, u_long reg); +#include <pci/pcivar.h> +#include <i386/isa/pcibus.h> -static void -pcibus_write (pcici_t tag, u_long reg, u_long data); +#ifdef PCI_COMPAT +/* XXX this is a terrible hack, which keeps the Tekram AMD SCSI driver happy */ +#define cfgmech pci_mechanism +int cfgmech; +#else +static int cfgmech; +#endif /* PCI_COMPAT */ +static int devmax; -static int -pcibus_ihandler_attach (int irq, inthand2_t *func, int arg, unsigned* maskptr); +/* enable configuration space accesses and return data port address */ static int -pcibus_ihandler_detach (int irq, inthand2_t *func); +pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) +{ + int dataport = 0; + + if (bus <= PCI_BUSMAX + && slot < devmax + && func <= PCI_FUNCMAX + && reg <= PCI_REGMAX + && bytes != 3 + && (unsigned) bytes <= 4 + && (reg & (bytes -1)) == 0) { + switch (cfgmech) { + case 1: + outl(CONF1_ADDR_PORT, + (bus << 16) | (slot << 11) | (func << 8) | reg); + dataport = CONF1_DATA_PORT; + break; + case 2: + outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); + outb(CONF2_FORWARD_PORT, bus); + dataport = 0xc000 | (slot << 8) | reg; + break; + } + } + return (dataport); +} -static int -pcibus_imask_include (int irq, unsigned* maskptr); +/* disable configuration space accesses */ -static int -pcibus_imask_exclude (int irq, unsigned* maskptr); - -static struct pcibus i386pci = { - "pci", - pcibus_setup, - pcibus_tag, - pcibus_ftag, - pcibus_read, - pcibus_write, - pcibus_ihandler_attach, - pcibus_ihandler_detach, - pcibus_imask_include, - pcibus_imask_exclude, -}; +static void +pci_cfgdisable(void) +{ + switch (cfgmech) { + case 1: + outl(CONF1_ADDR_PORT, 0); + break; + case 2: + outb(CONF2_ENABLE_PORT, 0); + outb(CONF2_FORWARD_PORT, 0); + break; + } +} -/* -** Announce structure to generic driver -*/ +/* read configuration space register */ -DATA_SET (pcibus_set, i386pci); +int +pci_cfgread(pcicfgregs *cfg, int reg, int bytes) +{ + int data = -1; + int port; -/*-------------------------------------------------------------------- -** -** Determine configuration mode -** -**-------------------------------------------------------------------- -*/ + port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); + if (port != 0) { + switch (bytes) { + case 1: + data = inb(port); + break; + case 2: + data = inw(port); + break; + case 4: + data = inl(port); + break; + } + pci_cfgdisable(); + } + return (data); +} -#define CONF1_ADDR_PORT 0x0cf8 -#define CONF1_DATA_PORT 0x0cfc +/* write configuration space register */ -#define CONF1_ENABLE 0x80000000ul -#define CONF1_ENABLE_CHK 0x80000000ul -#define CONF1_ENABLE_MSK 0x7ff00000ul -#define CONF1_ENABLE_CHK1 0xff000001ul -#define CONF1_ENABLE_MSK1 0x80000001ul -#define CONF1_ENABLE_RES1 0x80000000ul +void +pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) +{ + int port; -#define CONF2_ENABLE_PORT 0x0cf8 -#ifdef PC98 -#define CONF2_FORWARD_PORT 0x0cf9 -#else -#define CONF2_FORWARD_PORT 0x0cfa -#endif + port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); + if (port != 0) { + switch (bytes) { + case 1: + outb(port, data); + break; + case 2: + outw(port, data); + break; + case 4: + outl(port, data); + break; + } + pci_cfgdisable(); + } +} -#define CONF2_ENABLE_CHK 0x0e -#define CONF2_ENABLE_RES 0x0e +/* check whether the configuration mechanism has been correct identified */ static int -pcibus_check (void) +pci_cfgcheck(int maxdev) { u_char device; - if (bootverbose) printf ("pcibus_check:\tdevice "); + if (bootverbose) + printf("pci_cfgcheck:\tdevice "); - for (device = 0; device < pci_maxdevice; device++) { - unsigned long id, class, header; + for (device = 0; device < maxdev; device++) { + unsigned id, class, header; if (bootverbose) - printf ("%d ", device); - id = pcibus_read (pcibus_tag (0,device,0), 0); - if ((id == 0) || (id == 0xfffffffful)) + printf("%d ", device); + + id = inl(pci_cfgenable(0, device, 0, 0, 4)); + if (id == 0 || id == -1) continue; - class = pcibus_read (pcibus_tag (0,device,0), 8); + class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8; if (bootverbose) - printf ("[class=%x] ", class >> 8); - if ((class & 0xffffff00) == 0 || (class & 0xf8f0ff00) != 0) + printf("[class=%06x] ", class); + if (class == 0 || (class & 0xf8f0ff) != 0) continue; - header = pcibus_read (pcibus_tag (0,device,0), 12); + header = inb(pci_cfgenable(0, device, 0, 14, 1)); if (bootverbose) - printf ("[hdr=%x] ", (header >> 16) & 0xff); - if ((header & 0x007e0000) != 0) + printf("[hdr=%02x] ", header); + if ((header & 0x7e) != 0) continue; - if (bootverbose) printf ("is there (id=%08lx)\n", id); - return 1; + if (bootverbose) + printf("is there (id=%08x)\n", id); + + pci_cfgdisable(); + return (1); } if (bootverbose) - printf ("-- nothing found\n"); - return 0; + printf("-- nothing found\n"); + + pci_cfgdisable(); + return (0); } -static void -pcibus_setup (void) +int +pci_cfgopen(void) { unsigned long mode1res,oldval1; unsigned char mode2res,oldval2; - oldval1 = inl (CONF1_ADDR_PORT); + oldval1 = inl(CONF1_ADDR_PORT); if (bootverbose) { - printf ("pcibus_setup(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", oldval1); + printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", + oldval1); } - /*--------------------------------------- - ** Assume configuration mechanism 1 for now ... - **--------------------------------------- - */ - if ((oldval1 & CONF1_ENABLE_MSK) == 0) { - pci_mechanism = 1; - pci_maxdevice = 32; + cfgmech = 1; + devmax = 32; - outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK); - outb (CONF1_ADDR_PORT +3, 0); - mode1res = inl (CONF1_ADDR_PORT); - outl (CONF1_ADDR_PORT, oldval1); + outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); + outb(CONF1_ADDR_PORT +3, 0); + mode1res = inl(CONF1_ADDR_PORT); + outl(CONF1_ADDR_PORT, oldval1); if (bootverbose) - printf ("pcibus_setup(1a):\tmode1res=0x%08lx (0x%08lx)\n", - mode1res, CONF1_ENABLE_CHK); + printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", + mode1res, CONF1_ENABLE_CHK); if (mode1res) { - if (pcibus_check()) - return; - }; + if (pci_cfgcheck(32)) + return (cfgmech); + } - outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); + outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); mode1res = inl(CONF1_ADDR_PORT); - outl (CONF1_ADDR_PORT, oldval1); + outl(CONF1_ADDR_PORT, oldval1); if (bootverbose) - printf ("pcibus_setup(1b):\tmode1res=0x%08lx (0x%08lx)\n", - mode1res, CONF1_ENABLE_CHK1); + printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", + mode1res, CONF1_ENABLE_CHK1); if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { - if (pcibus_check()) - return; - }; + if (pci_cfgcheck(32)) + return (cfgmech); + } } - /*--------------------------------------- - ** Try configuration mechanism 2 ... - **--------------------------------------- - */ - - oldval2 = inb (CONF2_ENABLE_PORT); + oldval2 = inb(CONF2_ENABLE_PORT); if (bootverbose) { - printf ("pcibus_setup(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", oldval2); + printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", + oldval2); } if ((oldval2 & 0xf0) == 0) { - pci_mechanism = 2; - pci_maxdevice = 16; - - outb (CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); + cfgmech = 2; + devmax = 16; + + outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); mode2res = inb(CONF2_ENABLE_PORT); - outb (CONF2_ENABLE_PORT, oldval2); + outb(CONF2_ENABLE_PORT, oldval2); if (bootverbose) - printf ("pcibus_setup(2a):\tmode2res=0x%02x (0x%02x)\n", - mode2res, CONF2_ENABLE_CHK); + printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", + mode2res, CONF2_ENABLE_CHK); if (mode2res == CONF2_ENABLE_RES) { - if (bootverbose) - printf ("pcibus_setup(2a):\tnow trying mechanism 2\n"); - - if (pcibus_check()) - return; - } - } - - /*--------------------------------------- - ** No PCI bus host bridge found - **--------------------------------------- - */ - - pci_mechanism = 0; - pci_maxdevice = 0; -} - -/*-------------------------------------------------------------------- -** -** Build a pcitag from bus, device and function number -** -**-------------------------------------------------------------------- -*/ - -static pcici_t -pcibus_tag (unsigned char bus, unsigned char device, unsigned char func) -{ - pcici_t tag; - - tag.cfg1 = 0; - if (func >= 8) return tag; - - switch (pci_mechanism) { - - case 1: - if (device < 32) { - tag.cfg1 = CONF1_ENABLE - | (((u_long) bus ) << 16ul) - | (((u_long) device) << 11ul) - | (((u_long) func ) << 8ul); - } - break; - case 2: - if (device < 16) { - tag.cfg2.port = 0xc000 | (device << 8ul); - tag.cfg2.enable = 0xf0 | (func << 1ul); - tag.cfg2.forward = bus; - } - break; - }; - return tag; -} - -static pcici_t -pcibus_ftag (pcici_t tag, u_char func) -{ - switch (pci_mechanism) { - - case 1: - tag.cfg1 &= ~0x700ul; - tag.cfg1 |= (((u_long) func) << 8ul); - break; - case 2: - tag.cfg2.enable = 0xf0 | (func << 1ul); - break; - }; - return tag; -} - -/*-------------------------------------------------------------------- -** -** Read register from configuration space. -** -**-------------------------------------------------------------------- -*/ - -static u_long -pcibus_read (pcici_t tag, u_long reg) -{ - u_long addr, data = 0; - - if (!tag.cfg1) return (0xfffffffful); - - switch (pci_mechanism) { - - case 1: - addr = tag.cfg1 | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_read(1): addr=%x ", addr); -#endif - outl (CONF1_ADDR_PORT, addr); - data = inl (CONF1_DATA_PORT); - outl (CONF1_ADDR_PORT, 0 ); - break; - - case 2: - addr = tag.cfg2.port | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_read(2): addr=%x ", addr); -#endif - outb (CONF2_ENABLE_PORT , tag.cfg2.enable ); - outb (CONF2_FORWARD_PORT, tag.cfg2.forward); - - data = inl ((u_short) addr); - - outb (CONF2_ENABLE_PORT, 0); - outb (CONF2_FORWARD_PORT, 0); - break; - }; - -#ifdef PCI_DEBUG - printf ("data=%x\n", data); -#endif - - return (data); -} - -/*-------------------------------------------------------------------- -** -** Write register into configuration space. -** -**-------------------------------------------------------------------- -*/ - -static void -pcibus_write (pcici_t tag, u_long reg, u_long data) -{ - u_long addr; - - if (!tag.cfg1) return; - - switch (pci_mechanism) { - - case 1: - addr = tag.cfg1 | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_write(1): addr=%x data=%x\n", - addr, data); -#endif - outl (CONF1_ADDR_PORT, addr); - outl (CONF1_DATA_PORT, data); - outl (CONF1_ADDR_PORT, 0 ); - break; - - case 2: - addr = tag.cfg2.port | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_write(2): addr=%x data=%x\n", - addr, data); -#endif - outb (CONF2_ENABLE_PORT, tag.cfg2.enable); - outb (CONF2_FORWARD_PORT, tag.cfg2.forward); - - outl ((u_short) addr, data); - - outb (CONF2_ENABLE_PORT, 0); - outb (CONF2_FORWARD_PORT, 0); - break; - }; -} - -/*----------------------------------------------------------------------- -** -** Register an interrupt handler for a pci device. -** -**----------------------------------------------------------------------- -*/ - -static int -pcibus_ihandler_attach (int irq, inthand2_t *func, int arg, unsigned * maskptr) -{ - char buf[16]; - char *cp; - int free_id, id, result; + if (bootverbose) + printf("pci_open(2a):\tnow trying mechanism 2\n"); - sprintf(buf, "pci irq%d", irq); - for (cp = intrnames, free_id = 0, id = 0; id < NR_DEVICES; id++) { - if (strcmp(cp, buf) == 0) - break; - if (free_id <= 0 && strcmp(cp, "pci irqnn") == 0) - free_id = id; - while (*cp++ != '\0') - ; - } - if (id == NR_DEVICES) { - id = free_id; - if (id == 0) { - /* - * All pci irq counters are in use, perhaps because - * config is old so there aren't any. Abuse the - * clk0 counter. - */ - printf ( - "pcibus_ihandler_attach: counting pci irq%d's as clk0 irqs\n", - irq); + if (pci_cfgcheck(16)) + return (cfgmech); } } - result = register_intr( - irq, /* isa irq */ - id, /* device id */ - 0, /* flags? */ - func, /* handler */ - maskptr, /* mask pointer */ - arg); /* handler arg */ - - if (result) { - printf ("@@@ pcibus_ihandler_attach: result=%d\n", result); - return (result); - }; - update_intr_masks(); - - INTREN ((1ul<<irq)); - return (0); -} - -static int -pcibus_ihandler_detach (int irq, inthand2_t *func) -{ - int result; - - INTRDIS ((1ul<<irq)); - - result = unregister_intr (irq, func); - - if (result) - printf ("@@@ pcibus_ihandler_detach: result=%d\n", result); - - update_intr_masks(); - - return (result); -} - -static int -pcibus_imask_include (int irq, unsigned* maskptr) -{ - unsigned mask; - - if (!maskptr) return (0); - mask = 1ul << irq; - - if (*maskptr & mask) - return (-1); - - INTRMASK (*maskptr, mask); - update_intr_masks(); - - return (0); -} - -static int -pcibus_imask_exclude (int irq, unsigned* maskptr) -{ - unsigned mask; - - if (!maskptr) return (0); - - mask = 1ul << irq; - - if (! (*maskptr & mask)) - return (-1); - - INTRUNMASK (*maskptr, mask); - update_intr_masks(); - - return (0); + cfgmech = 0; + devmax = 0; + return (cfgmech); } diff --git a/sys/i386/pci/pci_pir.c b/sys/i386/pci/pci_pir.c index 31de543..df84794 100644 --- a/sys/i386/pci/pci_pir.c +++ b/sys/i386/pci/pci_pir.c @@ -1,538 +1,265 @@ -/************************************************************************** -** -** $Id: pcibus.c,v 1.34 1997/04/09 09:16:27 se Exp $ -** -** pci bus subroutines for i386 architecture. -** -** FreeBSD -** -**------------------------------------------------------------------------- -** -** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR 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. -** -*************************************************************************** -*/ - -#include "vector.h" - -#include <sys/param.h> +/* + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR 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. + * + * $Id$ + * + */ + +#include <sys/types.h> #include <sys/systm.h> -#include <sys/kernel.h> - -#include <i386/isa/icu.h> -#include <i386/isa/isa_device.h> -#include <pci/pcivar.h> #include <pci/pcireg.h> -#include <pci/pcibus.h> - -/*----------------------------------------------------------------- -** -** The following functions are provided by the pci bios. -** They are used only by the pci configuration. -** -** pcibus_setup(): -** Probes for a pci system. -** Sets pci_maxdevice and pci_mechanism. -** -** pcibus_tag(): -** Creates a handle for pci configuration space access. -** This handle is given to the read/write functions. -** -** pcibus_ftag(): -** Creates a modified handle. -** -** pcibus_read(): -** Read a long word from the pci configuration space. -** Requires a tag (from pcitag) and the register -** number (should be a long word aligned one). -** -** pcibus_write(): -** Writes a long word to the pci configuration space. -** Requires a tag (from pcitag), the register number -** (should be a long word aligned one), and a value. -** -** pcibus_regirq(): -** Register an interrupt handler for a pci device. -** Requires a tag (from pcitag), the register number -** (should be a long word aligned one), and a value. -** -**----------------------------------------------------------------- -*/ - -static int -pcibus_check (void); - -static void -pcibus_setup (void); - -static pcici_t -pcibus_tag (u_char bus, u_char device, u_char func); - -static pcici_t -pcibus_ftag (pcici_t tag, u_char func); - -static u_long -pcibus_read (pcici_t tag, u_long reg); +#include <pci/pcivar.h> +#include <i386/isa/pcibus.h> -static void -pcibus_write (pcici_t tag, u_long reg, u_long data); +#ifdef PCI_COMPAT +/* XXX this is a terrible hack, which keeps the Tekram AMD SCSI driver happy */ +#define cfgmech pci_mechanism +int cfgmech; +#else +static int cfgmech; +#endif /* PCI_COMPAT */ +static int devmax; -static int -pcibus_ihandler_attach (int irq, inthand2_t *func, int arg, unsigned* maskptr); +/* enable configuration space accesses and return data port address */ static int -pcibus_ihandler_detach (int irq, inthand2_t *func); +pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) +{ + int dataport = 0; + + if (bus <= PCI_BUSMAX + && slot < devmax + && func <= PCI_FUNCMAX + && reg <= PCI_REGMAX + && bytes != 3 + && (unsigned) bytes <= 4 + && (reg & (bytes -1)) == 0) { + switch (cfgmech) { + case 1: + outl(CONF1_ADDR_PORT, + (bus << 16) | (slot << 11) | (func << 8) | reg); + dataport = CONF1_DATA_PORT; + break; + case 2: + outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); + outb(CONF2_FORWARD_PORT, bus); + dataport = 0xc000 | (slot << 8) | reg; + break; + } + } + return (dataport); +} -static int -pcibus_imask_include (int irq, unsigned* maskptr); +/* disable configuration space accesses */ -static int -pcibus_imask_exclude (int irq, unsigned* maskptr); - -static struct pcibus i386pci = { - "pci", - pcibus_setup, - pcibus_tag, - pcibus_ftag, - pcibus_read, - pcibus_write, - pcibus_ihandler_attach, - pcibus_ihandler_detach, - pcibus_imask_include, - pcibus_imask_exclude, -}; +static void +pci_cfgdisable(void) +{ + switch (cfgmech) { + case 1: + outl(CONF1_ADDR_PORT, 0); + break; + case 2: + outb(CONF2_ENABLE_PORT, 0); + outb(CONF2_FORWARD_PORT, 0); + break; + } +} -/* -** Announce structure to generic driver -*/ +/* read configuration space register */ -DATA_SET (pcibus_set, i386pci); +int +pci_cfgread(pcicfgregs *cfg, int reg, int bytes) +{ + int data = -1; + int port; -/*-------------------------------------------------------------------- -** -** Determine configuration mode -** -**-------------------------------------------------------------------- -*/ + port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); + if (port != 0) { + switch (bytes) { + case 1: + data = inb(port); + break; + case 2: + data = inw(port); + break; + case 4: + data = inl(port); + break; + } + pci_cfgdisable(); + } + return (data); +} -#define CONF1_ADDR_PORT 0x0cf8 -#define CONF1_DATA_PORT 0x0cfc +/* write configuration space register */ -#define CONF1_ENABLE 0x80000000ul -#define CONF1_ENABLE_CHK 0x80000000ul -#define CONF1_ENABLE_MSK 0x7ff00000ul -#define CONF1_ENABLE_CHK1 0xff000001ul -#define CONF1_ENABLE_MSK1 0x80000001ul -#define CONF1_ENABLE_RES1 0x80000000ul +void +pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) +{ + int port; -#define CONF2_ENABLE_PORT 0x0cf8 -#ifdef PC98 -#define CONF2_FORWARD_PORT 0x0cf9 -#else -#define CONF2_FORWARD_PORT 0x0cfa -#endif + port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); + if (port != 0) { + switch (bytes) { + case 1: + outb(port, data); + break; + case 2: + outw(port, data); + break; + case 4: + outl(port, data); + break; + } + pci_cfgdisable(); + } +} -#define CONF2_ENABLE_CHK 0x0e -#define CONF2_ENABLE_RES 0x0e +/* check whether the configuration mechanism has been correct identified */ static int -pcibus_check (void) +pci_cfgcheck(int maxdev) { u_char device; - if (bootverbose) printf ("pcibus_check:\tdevice "); + if (bootverbose) + printf("pci_cfgcheck:\tdevice "); - for (device = 0; device < pci_maxdevice; device++) { - unsigned long id, class, header; + for (device = 0; device < maxdev; device++) { + unsigned id, class, header; if (bootverbose) - printf ("%d ", device); - id = pcibus_read (pcibus_tag (0,device,0), 0); - if ((id == 0) || (id == 0xfffffffful)) + printf("%d ", device); + + id = inl(pci_cfgenable(0, device, 0, 0, 4)); + if (id == 0 || id == -1) continue; - class = pcibus_read (pcibus_tag (0,device,0), 8); + class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8; if (bootverbose) - printf ("[class=%x] ", class >> 8); - if ((class & 0xffffff00) == 0 || (class & 0xf8f0ff00) != 0) + printf("[class=%06x] ", class); + if (class == 0 || (class & 0xf8f0ff) != 0) continue; - header = pcibus_read (pcibus_tag (0,device,0), 12); + header = inb(pci_cfgenable(0, device, 0, 14, 1)); if (bootverbose) - printf ("[hdr=%x] ", (header >> 16) & 0xff); - if ((header & 0x007e0000) != 0) + printf("[hdr=%02x] ", header); + if ((header & 0x7e) != 0) continue; - if (bootverbose) printf ("is there (id=%08lx)\n", id); - return 1; + if (bootverbose) + printf("is there (id=%08x)\n", id); + + pci_cfgdisable(); + return (1); } if (bootverbose) - printf ("-- nothing found\n"); - return 0; + printf("-- nothing found\n"); + + pci_cfgdisable(); + return (0); } -static void -pcibus_setup (void) +int +pci_cfgopen(void) { unsigned long mode1res,oldval1; unsigned char mode2res,oldval2; - oldval1 = inl (CONF1_ADDR_PORT); + oldval1 = inl(CONF1_ADDR_PORT); if (bootverbose) { - printf ("pcibus_setup(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", oldval1); + printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", + oldval1); } - /*--------------------------------------- - ** Assume configuration mechanism 1 for now ... - **--------------------------------------- - */ - if ((oldval1 & CONF1_ENABLE_MSK) == 0) { - pci_mechanism = 1; - pci_maxdevice = 32; + cfgmech = 1; + devmax = 32; - outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK); - outb (CONF1_ADDR_PORT +3, 0); - mode1res = inl (CONF1_ADDR_PORT); - outl (CONF1_ADDR_PORT, oldval1); + outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); + outb(CONF1_ADDR_PORT +3, 0); + mode1res = inl(CONF1_ADDR_PORT); + outl(CONF1_ADDR_PORT, oldval1); if (bootverbose) - printf ("pcibus_setup(1a):\tmode1res=0x%08lx (0x%08lx)\n", - mode1res, CONF1_ENABLE_CHK); + printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", + mode1res, CONF1_ENABLE_CHK); if (mode1res) { - if (pcibus_check()) - return; - }; + if (pci_cfgcheck(32)) + return (cfgmech); + } - outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); + outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); mode1res = inl(CONF1_ADDR_PORT); - outl (CONF1_ADDR_PORT, oldval1); + outl(CONF1_ADDR_PORT, oldval1); if (bootverbose) - printf ("pcibus_setup(1b):\tmode1res=0x%08lx (0x%08lx)\n", - mode1res, CONF1_ENABLE_CHK1); + printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", + mode1res, CONF1_ENABLE_CHK1); if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { - if (pcibus_check()) - return; - }; + if (pci_cfgcheck(32)) + return (cfgmech); + } } - /*--------------------------------------- - ** Try configuration mechanism 2 ... - **--------------------------------------- - */ - - oldval2 = inb (CONF2_ENABLE_PORT); + oldval2 = inb(CONF2_ENABLE_PORT); if (bootverbose) { - printf ("pcibus_setup(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", oldval2); + printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", + oldval2); } if ((oldval2 & 0xf0) == 0) { - pci_mechanism = 2; - pci_maxdevice = 16; - - outb (CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); + cfgmech = 2; + devmax = 16; + + outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); mode2res = inb(CONF2_ENABLE_PORT); - outb (CONF2_ENABLE_PORT, oldval2); + outb(CONF2_ENABLE_PORT, oldval2); if (bootverbose) - printf ("pcibus_setup(2a):\tmode2res=0x%02x (0x%02x)\n", - mode2res, CONF2_ENABLE_CHK); + printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", + mode2res, CONF2_ENABLE_CHK); if (mode2res == CONF2_ENABLE_RES) { - if (bootverbose) - printf ("pcibus_setup(2a):\tnow trying mechanism 2\n"); - - if (pcibus_check()) - return; - } - } - - /*--------------------------------------- - ** No PCI bus host bridge found - **--------------------------------------- - */ - - pci_mechanism = 0; - pci_maxdevice = 0; -} - -/*-------------------------------------------------------------------- -** -** Build a pcitag from bus, device and function number -** -**-------------------------------------------------------------------- -*/ - -static pcici_t -pcibus_tag (unsigned char bus, unsigned char device, unsigned char func) -{ - pcici_t tag; - - tag.cfg1 = 0; - if (func >= 8) return tag; - - switch (pci_mechanism) { - - case 1: - if (device < 32) { - tag.cfg1 = CONF1_ENABLE - | (((u_long) bus ) << 16ul) - | (((u_long) device) << 11ul) - | (((u_long) func ) << 8ul); - } - break; - case 2: - if (device < 16) { - tag.cfg2.port = 0xc000 | (device << 8ul); - tag.cfg2.enable = 0xf0 | (func << 1ul); - tag.cfg2.forward = bus; - } - break; - }; - return tag; -} - -static pcici_t -pcibus_ftag (pcici_t tag, u_char func) -{ - switch (pci_mechanism) { - - case 1: - tag.cfg1 &= ~0x700ul; - tag.cfg1 |= (((u_long) func) << 8ul); - break; - case 2: - tag.cfg2.enable = 0xf0 | (func << 1ul); - break; - }; - return tag; -} - -/*-------------------------------------------------------------------- -** -** Read register from configuration space. -** -**-------------------------------------------------------------------- -*/ - -static u_long -pcibus_read (pcici_t tag, u_long reg) -{ - u_long addr, data = 0; - - if (!tag.cfg1) return (0xfffffffful); - - switch (pci_mechanism) { - - case 1: - addr = tag.cfg1 | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_read(1): addr=%x ", addr); -#endif - outl (CONF1_ADDR_PORT, addr); - data = inl (CONF1_DATA_PORT); - outl (CONF1_ADDR_PORT, 0 ); - break; - - case 2: - addr = tag.cfg2.port | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_read(2): addr=%x ", addr); -#endif - outb (CONF2_ENABLE_PORT , tag.cfg2.enable ); - outb (CONF2_FORWARD_PORT, tag.cfg2.forward); - - data = inl ((u_short) addr); - - outb (CONF2_ENABLE_PORT, 0); - outb (CONF2_FORWARD_PORT, 0); - break; - }; - -#ifdef PCI_DEBUG - printf ("data=%x\n", data); -#endif - - return (data); -} - -/*-------------------------------------------------------------------- -** -** Write register into configuration space. -** -**-------------------------------------------------------------------- -*/ - -static void -pcibus_write (pcici_t tag, u_long reg, u_long data) -{ - u_long addr; - - if (!tag.cfg1) return; - - switch (pci_mechanism) { - - case 1: - addr = tag.cfg1 | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_write(1): addr=%x data=%x\n", - addr, data); -#endif - outl (CONF1_ADDR_PORT, addr); - outl (CONF1_DATA_PORT, data); - outl (CONF1_ADDR_PORT, 0 ); - break; - - case 2: - addr = tag.cfg2.port | (reg & 0xfc); -#ifdef PCI_DEBUG - printf ("pci_conf_write(2): addr=%x data=%x\n", - addr, data); -#endif - outb (CONF2_ENABLE_PORT, tag.cfg2.enable); - outb (CONF2_FORWARD_PORT, tag.cfg2.forward); - - outl ((u_short) addr, data); - - outb (CONF2_ENABLE_PORT, 0); - outb (CONF2_FORWARD_PORT, 0); - break; - }; -} - -/*----------------------------------------------------------------------- -** -** Register an interrupt handler for a pci device. -** -**----------------------------------------------------------------------- -*/ - -static int -pcibus_ihandler_attach (int irq, inthand2_t *func, int arg, unsigned * maskptr) -{ - char buf[16]; - char *cp; - int free_id, id, result; + if (bootverbose) + printf("pci_open(2a):\tnow trying mechanism 2\n"); - sprintf(buf, "pci irq%d", irq); - for (cp = intrnames, free_id = 0, id = 0; id < NR_DEVICES; id++) { - if (strcmp(cp, buf) == 0) - break; - if (free_id <= 0 && strcmp(cp, "pci irqnn") == 0) - free_id = id; - while (*cp++ != '\0') - ; - } - if (id == NR_DEVICES) { - id = free_id; - if (id == 0) { - /* - * All pci irq counters are in use, perhaps because - * config is old so there aren't any. Abuse the - * clk0 counter. - */ - printf ( - "pcibus_ihandler_attach: counting pci irq%d's as clk0 irqs\n", - irq); + if (pci_cfgcheck(16)) + return (cfgmech); } } - result = register_intr( - irq, /* isa irq */ - id, /* device id */ - 0, /* flags? */ - func, /* handler */ - maskptr, /* mask pointer */ - arg); /* handler arg */ - - if (result) { - printf ("@@@ pcibus_ihandler_attach: result=%d\n", result); - return (result); - }; - update_intr_masks(); - - INTREN ((1ul<<irq)); - return (0); -} - -static int -pcibus_ihandler_detach (int irq, inthand2_t *func) -{ - int result; - - INTRDIS ((1ul<<irq)); - - result = unregister_intr (irq, func); - - if (result) - printf ("@@@ pcibus_ihandler_detach: result=%d\n", result); - - update_intr_masks(); - - return (result); -} - -static int -pcibus_imask_include (int irq, unsigned* maskptr) -{ - unsigned mask; - - if (!maskptr) return (0); - mask = 1ul << irq; - - if (*maskptr & mask) - return (-1); - - INTRMASK (*maskptr, mask); - update_intr_masks(); - - return (0); -} - -static int -pcibus_imask_exclude (int irq, unsigned* maskptr) -{ - unsigned mask; - - if (!maskptr) return (0); - - mask = 1ul << irq; - - if (! (*maskptr & mask)) - return (-1); - - INTRUNMASK (*maskptr, mask); - update_intr_masks(); - - return (0); + cfgmech = 0; + devmax = 0; + return (cfgmech); } diff --git a/sys/pci/pci.c b/sys/pci/pci.c index 4456fe6..b6f056e 100644 --- a/sys/pci/pci.c +++ b/sys/pci/pci.c @@ -1,1893 +1,459 @@ -/************************************************************************** -** -** $Id: pci.c,v 1.70 1997/04/26 11:46:18 peter Exp $ -** -** General subroutines for the PCI bus. -** pci_configure () -** -** FreeBSD -** -**------------------------------------------------------------------------- -** -** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR 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) 1997, Stefan Esser <se@freebsd.org> + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR 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. + * + * $Id$ + * + */ #include "pci.h" #if NPCI > 0 -/*======================================================== -** -** #includes and declarations -** -**======================================================== -*/ - -#include "opt_smp.h" +#include <stddef.h> +#include <sys/types.h> #include <sys/param.h> +#include <sys/time.h> #include <sys/systm.h> #include <sys/malloc.h> -#include <sys/errno.h> -#include <sys/kernel.h> -#include <sys/proc.h> /* declaration of wakeup(), used by vm.h */ +#include <sys/fcntl.h> #include <sys/conf.h> +#include <sys/kernel.h> #ifdef DEVFS #include <sys/devfsext.h> #endif /* DEVFS */ -#include <sys/fcntl.h> #include <vm/vm.h> -#include <vm/vm_param.h> #include <vm/pmap.h> - -#include <i386/isa/isa_device.h> /* XXX inthand2_t */ - -#include <pci/pcivar.h> #include <pci/pcireg.h> -#include <pci/pcibus.h> +#include <pci/pcivar.h> #include <pci/pci_ioctl.h> -/*======================================================== -** -** Structs and Functions -** -**======================================================== -*/ - -struct pcicb { - struct pcicb *pcicb_next; - struct pcicb *pcicb_up; - struct pcicb *pcicb_down; - pcici_t pcicb_bridge; - - u_char pcicb_bus; - u_char pcicb_subordinate; - u_int pcicb_mfrom; - u_int pcicb_mupto; - u_int pcicb_mamount; - u_short pcicb_pfrom; - u_short pcicb_pupto; - u_short pcicb_pamount; - u_char pcicb_bfrom; - u_char pcicb_bupto; - - u_long pcicb_iobase; - u_long pcicb_iolimit; - u_long pcicb_membase; - u_long pcicb_memlimit; - u_long pcicb_p_membase; - u_long pcicb_p_memlimit; -}; - -struct pci_lkm { - struct pci_device *dvp; - struct pci_lkm *next; -}; - -static void -not_supported (pcici_t tag, u_long type); - -static void -pci_bus_config (void); - -static void -pci_rescan (void); - -static void pci_attach (int bus, int dev, int func, - struct pci_device *dvp, const char *name); - -static int -pci_bridge_config (void); +/* return highest PCI bus number known to be used, or -1 if none */ static int -pci_mfdev (int bus, int device); - -static void pci_remember (int bus, int dev, int func, struct pci_device *dvp); - -/*======================================================== -** -** Variables -** -**======================================================== -*/ - -/* -** log2 of safe burst len (in words) -*/ - -unsigned pci_max_burst_len = 3; /* 2=16Byte, 3=32Byte, 4=64Byte, ... */ -unsigned pci_mechanism = 0; -unsigned pci_maxdevice = 0; -unsigned pciroots = 0; /* XXX pcisupport.c increments this - * for the Orion host to PCI bridge - * UGLY hack ... :( Will be changed :) - */ -/*-------------------------------------------------------- -** -** Local variables. -** -**-------------------------------------------------------- -*/ - -static struct pcibus *pcibus; - -static int pci_conf_count; -static int pci_info_done; -static int pcibusmax; -static struct pcicb *pcicb; - -static struct pci_conf *pci_dev_list; -static unsigned pci_dev_list_count; -static unsigned pci_dev_list_size; - -static struct pci_lkm *pci_lkm_head; - -/*----------------------------------------------------------------- -** -** The following functions are provided for the device driver -** to read/write the configuration space. -** -** pci_conf_read(): -** Read a long word from the pci configuration space. -** Requires a tag (from pcitag) and the register -** number (should be a long word alligned one). -** -** pci_conf_write(): -** Writes a long word to the pci configuration space. -** Requires a tag (from pcitag), the register number -** (should be a long word alligned one), and a value. -** -**----------------------------------------------------------------- -*/ - -u_long -pci_conf_read (pcici_t tag, u_long reg) -{ - return (pcibus->pb_read (tag, reg)); -} - -void -pci_conf_write (pcici_t tag, u_long reg, u_long data) -{ - pcibus->pb_write (tag, reg, data); -} - -/*======================================================== -** -** Subroutines for configuration. -** -**======================================================== -*/ - -static void -pci_register_io (struct pcicb * cb, u_int base, u_int limit) +pci_bushigh(void) { -#ifdef PCI_BRIDGE_DEBUG - if (bootverbose) - printf ("register_io: bus=%d base=%x limit=%x\n", - cb->pcicb_bus, base, limit); -#endif - - if (!cb->pcicb_pfrom || base < cb->pcicb_pfrom) - cb->pcicb_pfrom = base; - if (limit > cb->pcicb_pupto) - cb->pcicb_pupto = limit; - - /* - ** XXX should set bridge io mapping here - ** but it can be mapped in 4k blocks only, - ** leading to conflicts with isa/eisa .. - */ + if (pci_cfgopen() == 0) + return (-1); + return (0); } -static void -pci_register_memory (struct pcicb * cb, u_int base, u_int limit) -{ -#ifdef PCI_BRIDGE_DEBUG - if (bootverbose) - printf ("register_mem: bus=%d base=%x limit=%x\n", - cb->pcicb_bus, base, limit); -#endif +/* return base address of memory or port map */ - if (!cb->pcicb_mfrom || base < cb->pcicb_mfrom) - cb->pcicb_mfrom = base; - if (limit > cb->pcicb_mupto) - cb->pcicb_mupto = limit; - /* - ** set the bridges mapping - ** - ** XXX should handle the 1Mb granularity. - */ - if (cb->pcicb_bridge.tag) { - pci_conf_write(cb->pcicb_bridge, - PCI_PCI_BRIDGE_MEM_REG, - (cb->pcicb_memlimit & 0xffff0000) | - (cb->pcicb_membase >> 16)); - if (bootverbose) - printf ("\t[pci%d uses memory from %x to %x]\n", - cb->pcicb_bus, - (unsigned) cb->pcicb_membase, - (unsigned) cb->pcicb_memlimit); - } -} - -/* -** XXX This function is neither complete nor tested. -** It's only used if the bios hasn't done it's job -** of mapping the pci devices in the physical memory. -*/ - -static u_int -pci_memalloc (struct pcicb * cb, u_int addr, u_int size) +static int +pci_mapbase(unsigned mapreg) { - u_int result = 0, limit=0, newbase=0; -#ifdef PCI_BRIDGE_DEBUG - if (bootverbose) - printf ("memalloc: bus=%d addr=%x size=%x ..\n", - cb->pcicb_bus, addr, size); -#endif - - if (!cb) goto done; - - if (!cb->pcicb_membase) { - printf ("memalloc: bus%d: membase not set.\n", - cb->pcicb_bus); - goto done; - } - - /* - ** get upper allocation limit - */ - limit = cb->pcicb_memlimit; - if (cb->pcicb_mfrom && cb->pcicb_mfrom <= limit) - limit = cb->pcicb_mfrom-1; - - /* - ** address fixed, and impossible to allocate ? - */ - if (addr && addr+size-1 > limit) - goto done; - - /* - ** get possible address - */ - - result = addr; - if (!result) result = ((limit + 1) / size - 1) * size; - - /* - ** if not local available, request from parent. - */ - - if (result < cb->pcicb_membase) { - newbase = pci_memalloc (cb->pcicb_up, result, size); - if (newbase) cb->pcicb_membase = result; - else result=0; - } -done: - if (result) - pci_register_memory (cb, result, result+size-1); - -#ifdef PCI_BRIDGE_DEBUG - printf ("memalloc: bus=%d addr=%x size=%x --> %x (limit=%x).\n", - cb->pcicb_bus, addr, size, result, limit); -#endif - - return (result); + int mask = 0x03; + if ((mapreg & 0x01) == 0) + mask = 0x0f; + return (mapreg & ~mask); } -/*======================================================== -** -** pci_bridge_config() -** -** Configuration of a pci bridge. -** -**======================================================== -*/ +/* return map type of memory or port map */ static int -pci_bridge_config (void) -{ - pcici_t tag; - struct pcicb* parent; - - tag = pcicb->pcicb_bridge; - if (tag.tag) { - - if (!pcicb->pcicb_bus) { - u_int data; - /* - ** Get the lowest available bus number. - */ - pcicb->pcicb_bus = ++pcibusmax; - - /* - ** and configure the bridge - */ - data = pci_conf_read (tag, PCI_PCI_BRIDGE_BUS_REG); - data = PCI_PRIMARY_BUS_INSERT(data, pcicb->pcicb_up->pcicb_bus); - data = PCI_SECONDARY_BUS_INSERT(data, pcicb->pcicb_bus); - data = PCI_SUBORDINATE_BUS_INSERT(data, pcicb->pcicb_bus); - pci_conf_write (tag, PCI_PCI_BRIDGE_BUS_REG, data); - - /* - ** Propagate the new upper bus number limit. - */ - for (parent = pcicb->pcicb_up; parent != NULL; - parent = parent->pcicb_up) - { - if (parent->pcicb_subordinate >= pcicb->pcicb_bus) - continue; - parent->pcicb_subordinate = pcicb->pcicb_bus; - if (!parent->pcicb_bridge.tag) - continue; - data = pci_conf_read - (parent->pcicb_bridge, PCI_PCI_BRIDGE_BUS_REG); - data = PCI_SUBORDINATE_BUS_INSERT - (data, pcicb->pcicb_bus); - pci_conf_write (parent->pcicb_bridge, - PCI_PCI_BRIDGE_BUS_REG, data); - } - } - - if (!pcicb->pcicb_membase) { - u_int size = 0x100000; - pcicb->pcicb_membase = pci_memalloc (pcicb->pcicb_up, 0, size); - if (pcicb->pcicb_membase) - pcicb->pcicb_memlimit = pcicb->pcicb_membase+size-1; - } - } - return pcicb->pcicb_bus; -} - -/*======================================================== -** -** pci_attach() -** -** Attach one device -** -**======================================================== -*/ - -static void pci_attach (int bus, int dev, int func, - struct pci_device *dvp, const char *name) -{ - u_long data; - int unit; - u_char reg; - u_char pciint; - int irq; -#if defined(APIC_IO) - u_char airq = 0xff; - u_char rirq = 0xff; -#endif /* APIC_IO */ - pcici_t tag = pcibus->pb_tag (bus, dev, func); - - /* - ** Get and increment the unit. - */ - - unit = (*dvp->pd_count)++; - - /* - ** Announce this device - */ - - printf ("%s%d <%s> rev %d", dvp->pd_name, unit, name, - (unsigned) pci_conf_read (tag, PCI_CLASS_REG) & 0xff); - - /* - ** Get the int pin number (pci interrupt number a-d) - ** from the pci configuration space. - */ - - data = pci_conf_read (tag, PCI_INTERRUPT_REG); - pciint = PCI_INTERRUPT_PIN_EXTRACT(data); - - if (pciint) { - - printf (" int %c irq ", 0x60+pciint); - - irq = PCI_INTERRUPT_LINE_EXTRACT(data); - - /* - ** If it's zero, the isa irq number is unknown, - ** and we cannot bind the pci interrupt. - */ - -#if defined(APIC_IO) - if (irq && (irq != 0xff)) { - airq = get_pci_apic_irq (bus, dev, pciint); - if (airq != 0xff) { /* APIC IRQ exists */ - rirq = irq; /* 're-directed' IRQ */ - irq = airq; /* use APIC IRQ */ - } - printf ("%d", irq); - } -#else - if (irq && (irq != 0xff)) - printf ("%d", irq); -#endif /* APIC_IO */ - else - printf ("??"); +pci_maptype(unsigned mapreg) +{ + static u_int8_t maptype[0x10] = { + PCI_MAPMEM, PCI_MAPPORT, + PCI_MAPMEM, 0, + PCI_MAPMEM, PCI_MAPPORT, + 0, 0, + PCI_MAPMEM|PCI_MAPMEMP, PCI_MAPPORT, + PCI_MAPMEM|PCI_MAPMEMP, 0, + PCI_MAPMEM|PCI_MAPMEMP, PCI_MAPPORT, + 0, 0, }; - printf (" on pci%d:%d:%d\n", bus, dev, func); - -#if defined(APIC_IO) - if (airq != 0xff) { /* APIC IRQ exists */ - data = PCI_INTERRUPT_LINE_INSERT(data, airq); - pci_conf_write (tag, PCI_INTERRUPT_REG, data); - undirect_pci_irq (rirq); /* free for ISA card */ - } -#endif /* APIC_IO */ - - /* - ** Read the current mapping, - ** and update the pcicb fields. - */ - - data = pci_conf_read(tag, PCI_CLASS_REG); - data &= (PCI_CLASS_MASK|PCI_SUBCLASS_MASK); - switch (data) { - case PCI_CLASS_BRIDGE|PCI_SUBCLASS_BRIDGE_PCI: - break; - case PCI_CLASS_BRIDGE|PCI_SUBCLASS_BRIDGE_CARDBUS: { - u_int map, addr, size; - map = pci_conf_read(tag, PCI_CARDBUS_SOCKET_REG); - pci_conf_write (tag, PCI_CARDBUS_SOCKET_REG, 0xffffffff); - size = pci_conf_read(tag, PCI_CARDBUS_SOCKET_REG); - size = (~size) + 1; - addr = pci_memalloc (pcicb, map, size); - pci_conf_write (tag, PCI_CARDBUS_SOCKET_REG, addr); - pcicb->pcicb_mamount += size; - break; - } - default: - for (reg=PCI_MAP_REG_START;reg<PCI_MAP_REG_END;reg+=4) { - u_int map, addr, size; - - - map = pci_conf_read (tag, reg); - if (!(map & PCI_MAP_MEMORY_ADDRESS_MASK)) - continue; - - pci_conf_write (tag, reg, 0xffffffff); - data = pci_conf_read (tag, reg); - pci_conf_write (tag, reg, map); - - switch (data & 7) { - - default: - continue; - case 1: - case 5: - addr = map & PCI_MAP_IO_ADDRESS_MASK; - size = -(data & PCI_MAP_IO_ADDRESS_MASK); - size &= ~(addr ^ -addr); - - pci_register_io (pcicb, addr, addr+size-1); - pcicb->pcicb_pamount += size; - break; - - case 0: - case 2: - case 4: - size = -(data & PCI_MAP_MEMORY_ADDRESS_MASK); - addr = map & PCI_MAP_MEMORY_ADDRESS_MASK; - if (addr >= 0x100000) { - pci_register_memory (pcicb, addr, addr+size-1); - pcicb->pcicb_mamount += size; - }; - break; - } - if (bootverbose) - printf ("\tmapreg[%02x] type=%d addr=%08x size=%04x.\n", - reg, map&7, addr, size); - } - } - - /* - ** attach device - ** may produce additional log messages, - ** i.e. when installing subdevices. - */ - - (*dvp->pd_attach) (tag, unit); - - /* - ** Special processing of certain classes - */ - - data = pci_conf_read(tag, PCI_CLASS_REG); - - switch (data & (PCI_CLASS_MASK|PCI_SUBCLASS_MASK)) { - struct pcicb *this, **link; - unsigned char primary, secondary, subordinate; - u_int command; - - case PCI_CLASS_BRIDGE|PCI_SUBCLASS_BRIDGE_PCI: - - /* - ** get current configuration of the bridge. - */ - data = pci_conf_read (tag, PCI_PCI_BRIDGE_BUS_REG); - primary = PCI_PRIMARY_BUS_EXTRACT (data); - secondary = PCI_SECONDARY_BUS_EXTRACT(data); - subordinate = PCI_SUBORDINATE_BUS_EXTRACT(data); -#ifndef PCI_QUIET - if (bootverbose) { - printf ("\tbridge from pci%d to pci%d through %d.\n", - primary, secondary, subordinate); - printf ("\tmapping regs: io:%08lx mem:%08lx pmem:%08lx\n", - pci_conf_read (tag, PCI_PCI_BRIDGE_IO_REG), - pci_conf_read (tag, PCI_PCI_BRIDGE_MEM_REG), - pci_conf_read (tag, PCI_PCI_BRIDGE_PMEM_REG)); - } -#endif - /* - ** check for uninitialized bridge. - */ - if (!(primary < secondary - && secondary <= subordinate - && bus == primary)) { - - printf ("\tINCORRECTLY or NEVER CONFIGURED.\n"); - /* - ** disable this bridge - */ - pci_conf_write (tag, PCI_COMMAND_STATUS_REG, 0xffff0000); - secondary = 0; - subordinate = 0; - }; - - /* - ** allocate bus descriptor for bus behind the bridge - */ - link = &pcicb->pcicb_down; - while (*link && (*link)->pcicb_bus < secondary) - link = &(*link)->pcicb_next; - - this = malloc (sizeof (*this), M_DEVBUF, M_WAITOK); - - /* - ** Initialize this descriptor so far. - ** (the initialization is completed just before - ** scanning the bus behind the bridge. - */ - bzero (this, sizeof(*this)); - this->pcicb_next = *link; - this->pcicb_up = pcicb; - this->pcicb_bridge = tag; - this->pcicb_bus = secondary; - this->pcicb_subordinate = subordinate; - - command = pci_conf_read(tag,PCI_COMMAND_STATUS_REG); - - if (command & PCI_COMMAND_IO_ENABLE){ - /* - ** Bridge was configured by the bios. - ** Read out the mapped io region. - */ - unsigned reg; - - reg = pci_conf_read (tag, PCI_PCI_BRIDGE_IO_REG); - this->pcicb_iobase = PCI_PPB_IOBASE_EXTRACT (reg); - this->pcicb_iolimit = PCI_PPB_IOLIMIT_EXTRACT(reg); - - /* - ** Note the used io space. - */ - pci_register_io (pcicb, this->pcicb_iobase, - this->pcicb_iolimit); - - }; - - if (command & PCI_COMMAND_MEM_ENABLE) { - /* - ** Bridge was configured by the bios. - ** Read out the mapped memory regions. - */ - unsigned reg; - - /* - ** non prefetchable memory - */ - reg = pci_conf_read (tag, PCI_PCI_BRIDGE_MEM_REG); - this->pcicb_membase = PCI_PPB_MEMBASE_EXTRACT (reg); - this->pcicb_memlimit = PCI_PPB_MEMLIMIT_EXTRACT(reg); - - /* - ** Register used memory space. - */ - pci_register_memory (pcicb, - this->pcicb_membase, - this->pcicb_memlimit); - - /* - ** prefetchable memory - */ - reg = pci_conf_read (tag, PCI_PCI_BRIDGE_PMEM_REG); - this->pcicb_p_membase = PCI_PPB_MEMBASE_EXTRACT (reg); - this->pcicb_p_memlimit = PCI_PPB_MEMLIMIT_EXTRACT(reg); - - /* - ** Register used memory space. - */ - pci_register_memory (pcicb, - this->pcicb_p_membase, - this->pcicb_p_memlimit); - } - - /* - ** Link it in chain. - */ - *link=this; - - /* - ** Update mapping info of parent bus. - */ - if (!pcicb->pcicb_bfrom||secondary< pcicb->pcicb_bfrom) - pcicb->pcicb_bfrom = secondary; - if (subordinate > pcicb->pcicb_bupto) - pcicb->pcicb_bupto = subordinate; - } + return maptype[mapreg & 0x0f]; } -/*======================================================== -** -** pci_bus_config() -** -** Autoconfiguration of one pci bus. -** -**======================================================== -*/ +/* return log2 of map size decoded for memory or port map */ static int -pci_mfdev (int bus, int device) +pci_mapsize(unsigned testval) { - pcici_t tag0,tag1; - unsigned pci_id0, pci_id1; - - /* - ** Detect a multi-function device that complies to the PCI 2.0 spec - */ - tag0 = pcibus->pb_tag (bus, device, 0); - if (pci_conf_read (tag0, PCI_HEADER_MISC) & PCI_HEADER_MULTIFUNCTION) - return 1; - - /* - ** Well, as always: Theory and implementation of PCI ... - ** - ** If there is a valid device ID returned for function 1 AND - ** the device ID of function 0 and 1 is different OR - ** the first mapping register of 0 and 1 differs, - ** then assume a multi-function device anyway ... - ** - ** Example of such a broken device: ISA and IDE chip i83371FB (Triton) - */ - tag1 = pcibus->pb_tag (bus, device, 1); - pci_id1 = pci_conf_read (tag1, PCI_ID_REG); - - if (pci_id1 != 0xffffffff) { - - pci_id0 = pci_conf_read (tag0, PCI_ID_REG); - - if (pci_id0 != pci_id1) - return 1; - - if (pci_conf_read (tag0, PCI_MAP_REG_START) - != pci_conf_read (tag1, PCI_MAP_REG_START)) - return 1; - } - return 0; -} + int ln2size; -static void -pci_bus_config (void) -{ - int bus_no; - u_char device; - u_char reg; - pcici_t tag, mtag; - pcidi_t type; - - struct pci_device *dvp; - - /* - ** first initialize the bridge (bus controller chip) - */ - bus_no = pci_bridge_config (); - - printf ("Probing for devices on PCI bus %d:\n", bus_no); -#ifndef PCI_QUIET - if (bootverbose && !pci_info_done) { - pci_info_done=1; - printf ("\tconfiguration mode %d allows %d devices.\n", - pci_mechanism, pci_maxdevice); - }; -#endif - for (device=0; device<pci_maxdevice; device ++) { - char *name = NULL; - struct pci_device **dvpp; - int func, maxfunc = 0; - - for (func=0; func <= maxfunc; func++) { - tag = pcibus->pb_tag (bus_no, device, func); - type = pci_conf_read (tag, PCI_ID_REG); - - if ((!type) || (type==0xfffffffful)) continue; - - /* - ** lookup device in ioconfiguration: - */ - - dvpp = (struct pci_device **)pcidevice_set.ls_items; - - while (dvp = *dvpp++) { - if (dvp->pd_probe) { - if (name=(*dvp->pd_probe)(tag, type)) - break; - } - }; - /* - ** check for mirrored devices. - */ - if (func != 0) { - goto real_device; - } - if (device & 0x10) { - mtag=pcibus->pb_tag (bus_no, - (u_char)(device & ~0x10), 0); - } else if (device & 0x08) { - mtag=pcibus->pb_tag (bus_no, - (u_char)(device & ~0x08), 0); - } else goto real_device; - - if (type!=pci_conf_read (mtag, PCI_ID_REG)) - goto real_device; - - for (reg=PCI_MAP_REG_START;reg<PCI_MAP_REG_END;reg+=4) - if (pci_conf_read(tag,reg)!=pci_conf_read(mtag,reg)) - goto real_device; - -#ifndef PCI_QUIET - if (dvp==NULL) continue; - if (bootverbose) - printf ("%s? <%s> mirrored on pci%d:%d\n", - dvp->pd_name, name, bus_no, device); -#endif - continue; - - real_device: - -#ifndef PCI_QUIET -#ifdef PCI_BRIDGE_DEBUG - if (bootverbose) { - printf ("\tconfig header: 0x%08x 0x%08x 0x%08x 0x%08x\n", - pci_conf_read (tag, 0), - pci_conf_read (tag, 4), - pci_conf_read (tag, 8), - pci_conf_read (tag, 12)); - } -#endif -#endif - - if (func == 0 && pci_mfdev (bus_no, device)) { - maxfunc = 7; - } - - pci_remember(bus_no, device, func, dvp); - - if (dvp==NULL) { -#ifndef PCI_QUIET - if (pci_conf_count) - continue; - - if (maxfunc == 0) - printf("%s%d:%d: ", - pcibus->pb_name, bus_no, device); - else - printf("%s%d:%d:%d: ", - pcibus->pb_name, bus_no, device, func); - not_supported (tag, type); -#endif - continue; - }; - - if (*name) { - pci_attach (bus_no, device, func, dvp, name); - } - } - } - -#ifndef PCI_QUIET - if (bootverbose) { - if (pcicb->pcicb_mamount) - printf ("%s%d: uses %ud bytes of memory from %x upto %x.\n", - pcibus->pb_name, bus_no, - pcicb->pcicb_mamount, - pcicb->pcicb_mfrom, pcicb->pcicb_mupto); - if (pcicb->pcicb_pamount) - printf ("%s%d: uses %ud bytes of I/O space from %x upto %x.\n", - pcibus->pb_name, bus_no, - pcicb->pcicb_pamount, - pcicb->pcicb_pfrom, pcicb->pcicb_pupto); - if (pcicb->pcicb_bfrom) - printf ("%s%d: subordinate busses from %x upto %x.\n", - pcibus->pb_name, bus_no, - pcicb->pcicb_bfrom, pcicb->pcicb_bupto); + testval = pci_mapbase(testval); + ln2size = 32; + while ((testval & 0x80000000) != 0) + { + ln2size--; + testval <<= 1; } -#endif + return (ln2size); } -/*======================================================== -** -** pci_configure () -** -** Autoconfiguration of pci devices. -** -** Has to take care of mirrored devices, which are -** entailed by incomplete decoding of pci address lines. -** -**======================================================== -*/ - -void pci_configure() -{ - struct pcibus **pbp = (struct pcibus**) pcibus_set.ls_items; - - /* - ** check pci bus present - */ +/* return log2 of address range supported by map register */ - while (!pci_maxdevice && (pcibus = *pbp++)) { - (*pcibus->pb_setup)(); - } - - if (!pci_maxdevice) return; - - /* - ** hello world .. - */ - - pciroots = 1; - while (pciroots--) { - - pcicb = malloc (sizeof (struct pcicb), M_DEVBUF, M_WAITOK); - if (pcicb == NULL) { - return; - } - bzero (pcicb, sizeof (struct pcicb)); - pcicb->pcicb_bus = pcibusmax; - pcicb->pcicb_iolimit = 0xffff; - pcicb->pcicb_membase = 0x02000000; - pcicb->pcicb_p_membase = 0x02000000; - pcicb->pcicb_memlimit = 0xffffffff; - pcicb->pcicb_p_memlimit = 0xffffffff; - - while (pcicb != NULL) { - pci_bus_config (); - - if (pcibusmax < pcicb->pcicb_bus) - (pcibusmax = pcicb->pcicb_bus); - - if (pcicb->pcicb_down) { - pcicb = pcicb->pcicb_down; - continue; - }; - - while (pcicb && !pcicb->pcicb_next) - pcicb = pcicb->pcicb_up; - - if (pcicb) - pcicb = pcicb->pcicb_next; - } - pcibusmax++; +static int +pci_maprange(unsigned mapreg) +{ + int ln2range = 0; + switch (mapreg & 0x07) { + case 0x00: + case 0x01: + case 0x05: + ln2range = 32; + break; + case 0x02: + ln2range = 20; + break; + case 0x04: + ln2range = 64; + break; } - pci_conf_count++; + return (ln2range); } -/*======================================================== -** -** pci_rescan () -** -** try to find lkm driver for device -** -** May be called more than once. -** Any device is attached only once. -** -**======================================================== -*/ - -static void pci_rescan() +/* extract map parameters into newly allocated array of pcimap structures */ + +static pcimap * +pci_readmaps(pcicfgregs *cfg, int maxmaps) { int i; - for (i = 0; i < pci_dev_list_count; i++) - { - struct pci_lkm *lkm; - pcici_t tag; - struct pci_device *dvp; - pcidi_t type = pci_dev_list[i].pc_devid; - char *name = NULL; - int bus, dev, func; - - if (pci_dev_list[i].pc_dvp) - continue; - - bus = pci_dev_list[i].pc_sel.pc_bus; - dev = pci_dev_list[i].pc_sel.pc_dev; - func = pci_dev_list[i].pc_sel.pc_func; - - tag = pcibus->pb_tag (bus, dev, func); - - for (lkm = pci_lkm_head; lkm; lkm = lkm->next) { - dvp = lkm->dvp; - if (name=(*dvp->pd_probe)(tag, type)) - break; - } - if (name && *name) { - pcicb = pci_dev_list[i].pc_cb; - pci_attach (bus, dev, func, dvp, name); - pci_dev_list[i].pc_dvp = dvp; + pcimap *map; + int map64 = 0; + + while (maxmaps > 0 + && pci_cfgread(cfg, PCIR_MAPS + (maxmaps -1) *4, 4) == 0) + maxmaps--; + + map = malloc(maxmaps * sizeof (pcimap), M_DEVBUF, M_WAITOK); + if (map != NULL) { + bzero(map, sizeof(pcimap) * maxmaps); + + for (i = 0; i < maxmaps; i++) { + int reg = PCIR_MAPS + i*4; + u_int32_t base; + u_int32_t testval; + + base = pci_cfgread(cfg, reg, 4); + + if (map64 == 0) { + pci_cfgwrite(cfg, reg, 0xffffffff, 4); + testval = pci_cfgread(cfg, reg, 4); + pci_cfgwrite(cfg, reg, base, 4); + + map[i].base = pci_mapbase(base); + map[i].type = pci_maptype(base); + map[i].ln2size = pci_mapsize(testval); + map[i].ln2range = pci_maprange(testval); + map64 = map[i].ln2range == 64; + } else { + /* only fill in base, other fields are 0 */ + map[i].base = base; + map64 = 0; + } + if (map[i].type == 0) { + /* + * This indicates, that some config space register + * was mistaken to contain a map, while it in fact + * contains unrelated information! + * Ignore this map and all that might have been + * expected to follow ... + */ + maxmaps = i; + } } + cfg->nummaps = maxmaps; } + return (map); } -/*======================================================== -** -** pci_register_lkm () -** -** Add LKM PCI driver's struct pci_device to pci_lkm chain -** -**======================================================== -*/ +/* adjust some values from PCI 1.0 devices to match 2.0 standards ... */ -int pci_register_lkm (struct pci_device *dvp, int if_revision) +static void +pci_fixancient(pcicfgregs *cfg) { - struct pci_lkm *lkm; - - if (if_revision != 0) { - return -1; - } - - if (!dvp || !dvp->pd_probe || !dvp->pd_attach) { - return -1; - } - - lkm = malloc (sizeof (*lkm), M_DEVBUF, M_WAITOK); - if (!lkm) { - return -1; - } + if (cfg->hdrtype != 0) + return; - lkm->dvp = dvp; - lkm->next = pci_lkm_head; - pci_lkm_head = lkm; - pci_rescan(); - return 0; + /* PCI to PCI bridges use header type 1 */ + if (cfg->class == PCIC_BRIDGE && cfg->subclass == PCIS_BRIDGE_PCI) + cfg->hdrtype = 1; } -/*----------------------------------------------------------------------- -** -** Map device into port space. -** -** Actually the device should have been mapped by the bios. -** This function only reads and verifies the value. -** -** PCI-Specification: 6.2.5.1: address maps -** -**----------------------------------------------------------------------- -*/ - -int pci_map_port (pcici_t tag, u_long reg, u_short* pa) +/* read config data specific to header type 1 device (PCI to PCI bridge) */ + +static void * +pci_readppb(pcicfgregs *cfg) { - unsigned data, ioaddr, iosize; - struct pcicb *link = pcicb; + pcih1cfgregs *p; - /* - ** sanity check - */ + p = malloc(sizeof (pcih1cfgregs), M_DEVBUF, M_WAITOK); + if (p == NULL) + return (NULL); - if (reg < PCI_MAP_REG_START || reg >= PCI_MAP_REG_END || (reg & 3)) { - printf ("pci_map_port failed: bad register=0x%x\n", - (unsigned)reg); - return (0); - }; + bzero(p, sizeof *p); - /* - ** get size and type of port - ** - ** type is in the lowest two bits. - ** If device requires 2^n bytes, the next - ** n-2 bits are hardwired as 0. - */ - - ioaddr = pci_conf_read (tag, reg) & PCI_MAP_IO_ADDRESS_MASK; - if (!ioaddr) { - printf ("pci_map_port failed: not configured by bios.\n"); - return (0); - }; + p->secstat = pci_cfgread(cfg, PCIR_SECSTAT_1, 2); + p->bridgectl = pci_cfgread(cfg, PCIR_BRIDGECTL_1, 2); - pci_conf_write (tag, reg, 0xfffffffful); - data = pci_conf_read (tag, reg); - pci_conf_write (tag, reg, ioaddr); + p->seclat = pci_cfgread(cfg, PCIR_SECLAT_1, 1); - if ((data & 0x03) != PCI_MAP_IO) { - printf ("pci_map_port failed: bad port type=0x%x\n", - (unsigned) data); - return (0); - }; - iosize = -(data & PCI_MAP_IO_ADDRESS_MASK); - iosize &= ~(ioaddr ^ -ioaddr); - if (ioaddr < pcicb->pcicb_iobase - || ioaddr + iosize -1 > pcicb->pcicb_iolimit) { - printf ("pci_map_port failed: device's iorange 0x%x-0x%x " - "is incompatible with its bridge's range 0x%x-0x%x\n", - (unsigned) ioaddr, (unsigned) ioaddr + iosize - 1, - (unsigned) pcicb->pcicb_iobase, - (unsigned) pcicb->pcicb_iolimit); - return (0); - } + p->iobase = PCI_PPBIOBASE (pci_cfgread(cfg, PCIR_IOBASEH_1, 2), + pci_cfgread(cfg, PCIR_IOBASEL_1, 1)); + p->iolimit = PCI_PPBIOLIMIT (pci_cfgread(cfg, PCIR_IOLIMITH_1, 2), + pci_cfgread(cfg, PCIR_IOLIMITL_1, 1)); -#ifndef PCI_QUIET - if (bootverbose) - printf ("\treg%d: ioaddr=0x%x size=0x%x\n", - (unsigned) reg, (unsigned) ioaddr, (unsigned) iosize); -#endif - /* - ** set the configuration register of and - ** return the address to the driver. - ** Make sure to enable each upstream bridge - ** so I/O and DMA can go all the way. - */ - - for (;;) { - data = pci_conf_read (tag, PCI_COMMAND_STATUS_REG) & 0xffff; - data |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE; - (void) pci_conf_write(tag, PCI_COMMAND_STATUS_REG, data); - if ((link = link->pcicb_up) == NULL) - break; - tag = link->pcicb_bridge; - } + p->membase = PCI_PPBMEMBASE (0, + pci_cfgread(cfg, PCIR_MEMBASE_1, 2)); + p->memlimit = PCI_PPBMEMLIMIT (0, + pci_cfgread(cfg, PCIR_MEMLIMIT_1, 2)); - *pa = ioaddr; + p->pmembase = PCI_PPBMEMBASE ( + (pci_addr_t)pci_cfgread(cfg, PCIR_PMBASEH_1, 4), + pci_cfgread(cfg, PCIR_PMBASEL_1, 2)); - return (1); + p->pmemlimit = PCI_PPBMEMLIMIT ( + (pci_addr_t)pci_cfgread(cfg, PCIR_PMLIMITH_1, 4), + pci_cfgread(cfg, PCIR_PMLIMITL_1, 2)); + return (p); } -/*----------------------------------------------------------------------- -** -** Map device into virtual and physical space -** -** Actually the device should have been mapped by the bios. -** This function only reads and verifies the value. -** -** PCI-Specification: 6.2.5.1: address maps -** -**----------------------------------------------------------------------- -*/ - -int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa) -{ - struct pcicb *link = pcicb; - unsigned data ,paddr; - vm_size_t psize, poffs; - vm_offset_t vaddr; - - /* - ** sanity check - */ - - if (reg < PCI_MAP_REG_START || reg >= PCI_MAP_REG_END || (reg & 3)) { - printf ("pci_map_mem failed: bad register=0x%x\n", - (unsigned)reg); - return (0); - }; - - /* - ** save old mapping, get size and type of memory - ** - ** type is in the lowest four bits. - ** If device requires 2^n bytes, the next - ** n-4 bits are read as 0. - */ - - paddr = pci_conf_read (tag, reg) & PCI_MAP_MEMORY_ADDRESS_MASK; - pci_conf_write (tag, reg, 0xfffffffful); - data = pci_conf_read (tag, reg); - pci_conf_write (tag, reg, paddr); - - /* - ** check the type - */ - - if (!((data & PCI_MAP_MEMORY_TYPE_MASK) == PCI_MAP_MEMORY_TYPE_32BIT_1M - && (paddr & ~0xfffff) == 0) - && (data & PCI_MAP_MEMORY_TYPE_MASK) != PCI_MAP_MEMORY_TYPE_32BIT){ - printf ("pci_map_mem failed: bad memory type=0x%x\n", - (unsigned) data); - return (0); - }; - - /* - ** get the size. - */ - - psize = -(data & PCI_MAP_MEMORY_ADDRESS_MASK); - - if (!paddr || paddr == PCI_MAP_MEMORY_ADDRESS_MASK) { - paddr = pci_memalloc (pcicb, 0, psize); - if (!paddr) { - printf ("pci_map_mem: not configured by bios.\n"); - return (0); - }; - pci_register_memory (pcicb, paddr, paddr+psize-1); - }; +/* read config data specific to header type 2 device (PCI to CardBus bridge) */ - if (paddr < pcicb->pcicb_membase || - paddr + psize - 1 > pcicb->pcicb_memlimit) { - printf ("pci_map_mem failed: device's memrange 0x%x-0x%x is " - "incompatible with its bridge's memrange 0x%x-0x%x\n", - (unsigned) paddr, - (unsigned) (paddr + psize - 1), - (unsigned) pcicb->pcicb_membase, - (unsigned) pcicb->pcicb_memlimit); -/* return (0);*/ -/* ACHTUNG: Ist der Code richtig, wenn eine PCI-PCI-Bridge fuer - * die PCI-Slots verwendet wird, aber die Onboard-Devices direkt - * an der CPU-PCI-Bridge haengen (Siehe Compaq Prolinea Problem) ??? - */ - } - pci_conf_write (tag, reg, paddr); - - /* - ** Truncate paddr to page boundary. - ** (Or does pmap_mapdev the job?) - */ +static void * +pci_readpcb(pcicfgregs *cfg) +{ + pcih2cfgregs *p; - poffs = paddr - trunc_page (paddr); - vaddr = (vm_offset_t) pmap_mapdev (paddr-poffs, psize+poffs); + p = malloc(sizeof (pcih2cfgregs), M_DEVBUF, M_WAITOK); + if (p == NULL) + return (NULL); - if (!vaddr) return (0); + bzero(p, sizeof *p); - vaddr += poffs; + p->secstat = pci_cfgread(cfg, PCIR_SECSTAT_2, 2); + p->bridgectl = pci_cfgread(cfg, PCIR_BRIDGECTL_2, 2); + + p->seclat = pci_cfgread(cfg, PCIR_SECLAT_2, 1); -#ifndef PCI_QUIET - /* - ** display values. - */ + p->membase0 = pci_cfgread(cfg, PCIR_MEMBASE0_2, 4); + p->memlimit0 = pci_cfgread(cfg, PCIR_MEMLIMIT0_2, 4); + p->membase1 = pci_cfgread(cfg, PCIR_MEMBASE1_2, 4); + p->memlimit1 = pci_cfgread(cfg, PCIR_MEMLIMIT1_2, 4); - if (bootverbose) - printf ("\treg%d: virtual=0x%lx physical=0x%lx size=0x%lx\n", - (unsigned) reg, (u_long)vaddr, (u_long)paddr, (u_long)psize); -#endif - /* - ** set the configuration register and - ** return the address to the driver - ** Make sure to enable each upstream bridge - ** so memory and DMA can go all the way. - */ - - for (;;) { - data = pci_conf_read (tag, PCI_COMMAND_STATUS_REG) & 0xffff; - data |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE; - (void) pci_conf_write(tag, PCI_COMMAND_STATUS_REG, data); - if ((link = link->pcicb_up) == NULL) - break; - tag = link->pcicb_bridge; - } + p->iobase0 = pci_cfgread(cfg, PCIR_IOBASE0_2, 4); + p->iolimit0 = pci_cfgread(cfg, PCIR_IOLIMIT0_2, 4); + p->iobase1 = pci_cfgread(cfg, PCIR_IOBASE1_2, 4); + p->iolimit1 = pci_cfgread(cfg, PCIR_IOLIMIT1_2, 4); - *va = vaddr; - *pa = paddr; - - return (1); + p->pccardif = pci_cfgread(cfg, PCIR_PCCARDIF_2, 4); + return p; } -/*----------------------------------------------------------------------- -** -** Pci meta interrupt handler -** -** This handler assumes level triggered interrupts. -** It's possible to build a kernel which handles shared -** edge triggered interrupts by the options "PCI_EDGE_INT". -** But there is a performance penalty. -** -** (Of course you can delete the #ifdef PCI_EDGE_INT bracketed -** code at all :-) :-) :-) -** -**----------------------------------------------------------------------- -*/ - -static struct pci_int_desc* - pci_int_desc [PCI_MAX_IRQ]; - -#ifndef NO_SHARED_IRQ - -static inline unsigned -splq (unsigned mask) -{ - unsigned temp=cpl; - cpl |= mask; - return temp; -} +/* extract header type specific config data */ static void -pci_int (int irq) +pci_hdrtypedata(pcicfgregs *cfg) { - struct pci_int_desc * p; - int s; - - if (irq<0 || irq >= PCI_MAX_IRQ) { - printf ("pci_int: irq %d out of range, ignored\n", irq); - return; - }; - for (p = pci_int_desc[irq]; p!=NULL; p=p->pcid_next) { - s = splq (*p->pcid_maskptr); - (*p->pcid_handler) (p->pcid_argument); - p-> pcid_tally++; - splx (s); -#if 0 - if (p->pcid_tally<20) - printf ("PCI_INT: irq=%d h=%p cpl o=%x n=%x val=%d\n", - irq, p->pcid_handler, s, cpl, c); -#endif - }; -} -#endif - -/*----------------------------------------------------------------------- -** -** Auxiliary function for interrupt (un)mapping. -** -**----------------------------------------------------------------------- -*/ - -static u_int -getirq (pcici_t tag) -{ - u_int irq; - - irq = PCI_INTERRUPT_LINE_EXTRACT( - pci_conf_read (tag, PCI_INTERRUPT_REG)); - - if (irq == 0 || irq == 0xff) { - printf ("\tint line register not set by bios\n"); - return (0xff); + switch (cfg->hdrtype) { + case 0: + cfg->subvendor = pci_cfgread(cfg, PCIR_SUBVEND_0, 2); + cfg->subdevice = pci_cfgread(cfg, PCIR_SUBDEV_0, 2); + cfg->map = pci_readmaps(cfg, PCI_MAXMAPS_0); + break; + case 1: + cfg->subvendor = pci_cfgread(cfg, PCIR_SUBVEND_1, 2); + cfg->subdevice = pci_cfgread(cfg, PCIR_SUBDEV_1, 2); + cfg->secondarybus = pci_cfgread(cfg, PCIR_SECBUS_1, 1); + cfg->subordinatebus = pci_cfgread(cfg, PCIR_SUBBUS_1, 1); + cfg->map = pci_readmaps(cfg, PCI_MAXMAPS_1); + cfg->hdrspec = pci_readppb(cfg); + break; + case 2: + cfg->subvendor = pci_cfgread(cfg, PCIR_SUBVEND_2, 2); + cfg->subdevice = pci_cfgread(cfg, PCIR_SUBDEV_2, 2); + cfg->secondarybus = pci_cfgread(cfg, PCIR_SECBUS_2, 1); + cfg->subordinatebus = pci_cfgread(cfg, PCIR_SUBBUS_2, 1); + cfg->map = pci_readmaps(cfg, PCI_MAXMAPS_2); + cfg->hdrspec = pci_readpcb(cfg); + break; } +} - if (irq >= PCI_MAX_IRQ) { - printf ("\tirq %d out of bounds (must be < %d).\n", - irq, PCI_MAX_IRQ); - return (0xff); +/* read configuration header into pcicfgrect structure */ + +static pcicfgregs * +pci_readcfg(pcicfgregs *probe) +{ + pcicfgregs *cfg = NULL; + + if (pci_cfgread(probe, PCIR_DEVVENDOR, 4) != -1) { + cfg = malloc(sizeof (pcicfgregs), M_DEVBUF, M_WAITOK); + if (cfg == NULL) + return (cfg); + + bzero(cfg, sizeof *cfg); + + cfg->bus = probe->bus; + cfg->slot = probe->slot; + cfg->func = probe->func; + cfg->parent = probe->parent; + + cfg->vendor = pci_cfgread(cfg, PCIR_VENDOR, 2); + cfg->device = pci_cfgread(cfg, PCIR_DEVICE, 2); + cfg->cmdreg = pci_cfgread(cfg, PCIR_COMMAND, 2); + cfg->statreg = pci_cfgread(cfg, PCIR_STATUS, 2); + cfg->class = pci_cfgread(cfg, PCIR_CLASS, 1); + cfg->subclass = pci_cfgread(cfg, PCIR_SUBCLASS, 1); + cfg->progif = pci_cfgread(cfg, PCIR_PROGIF, 1); + cfg->revid = pci_cfgread(cfg, PCIR_REVID, 1); + cfg->hdrtype = pci_cfgread(cfg, PCIR_HEADERTYPE, 1); + cfg->cachelnsz = pci_cfgread(cfg, PCIR_CACHELNSZ, 1); + cfg->lattimer = pci_cfgread(cfg, PCIR_LATTIMER, 1); + cfg->intpin = pci_cfgread(cfg, PCIR_INTPIN, 1); + cfg->intline = pci_cfgread(cfg, PCIR_INTLINE, 1); + cfg->mingnt = pci_cfgread(cfg, PCIR_MINGNT, 1); + cfg->maxlat = pci_cfgread(cfg, PCIR_MAXLAT, 1); + + cfg->mfdev = (cfg->hdrtype & PCIM_MFDEV) != 0; + cfg->hdrtype &= ~PCIM_MFDEV; + + pci_fixancient(cfg); + pci_hdrtypedata(cfg); } - - return (irq); + return (cfg); } -static struct pci_int_desc ** -getintdescbytag (u_int irq, pcici_t tag) -{ - struct pci_int_desc *p, **pp; - - pp=&pci_int_desc[irq]; - while (((p=*pp)) && !sametag(p->pcid_tag,tag)) - pp=&p->pcid_next; - - if (!p) return (NULL); +/* free pcicfgregs structure and all depending data structures */ - return (pp); -} - -static struct pci_int_desc * -getintdescbymptr (u_int irq, unsigned * mptr) +static int +pci_freecfg(pcicfgregs *cfg) { - struct pci_int_desc *p; - - for (p=pci_int_desc[irq];p;p=p->pcid_next) - if (p->pcid_maskptr == mptr) break; - return (p); + if (cfg->hdrspec != NULL) + free(cfg->hdrspec, M_DEVBUF); + if (cfg->map != NULL) + free(cfg->map, M_DEVBUF); + free(cfg, M_DEVBUF); + return (0); } -/*----------------------------------------------------------------------- -** -** Map pci interrupt. -** -**----------------------------------------------------------------------- -*/ - -static unsigned pci_mask0 = 0; - -int pci_map_int (pcici_t tag, pci_inthand_t *func, void *arg, unsigned *maskptr) +static void +pci_addcfg(pcicfgregs *cfg) { - u_int irq; - int result, oldspl; - unsigned mask; - struct pci_int_desc *tail, *mdp=NULL, *new=NULL; - - /* - ** Get irq line from configuration space, - ** and check for consistency. - */ - - irq = getirq (tag); - if (irq == 0xff) { - return (0); - }; - mask= 1ul << irq; - - /* - ** disable this interrupt. - */ - - oldspl = splq (mask); - - /* - ** If handler for this tag already installed, - ** remove it first. - */ - - if (getintdescbytag (irq, tag) != NULL) - pci_unmap_int (tag); - - /* - ** If this irq not yet included in the mask, include it. - */ - - mdp = getintdescbymptr (irq, maskptr); - if (!mdp) { - result = pcibus->pb_imaskinc (irq, maskptr); - if (result) - goto conflict; - }; - - /* - ** Allocate descriptor and initialize it. - */ - - tail = pci_int_desc[irq]; - - new = malloc (sizeof (*new), M_DEVBUF, M_WAITOK); - bzero (new, sizeof (*new)); - - new->pcid_next = tail; - new->pcid_tag = tag; - new->pcid_handler = func; - new->pcid_argument = arg; - new->pcid_maskptr = maskptr; - new->pcid_tally = 0; - new->pcid_mask = mask; - - /* - ** If first handler: install it. - ** If second handler: install shared-int-handler. - */ - - if (!tail) { - /* - ** first handler for this irq. - */ - - result = pcibus->pb_iattach - /* - * XXX if we get here, then `func' must be pci_int - * so the bogus casts are almost OK since they just - * undo the bogus casts that were needed to pass - * pci_int and its arg to pci_map_int(). - */ - (irq, (inthand2_t *) func, (int) arg, maskptr); - if (result) goto conflict; - -#ifdef NO_SHARED_IRQ - } else goto conflict; -#else - } else if (!tail->pcid_next) { - /* - ** Second handler for this irq. - */ - - if (bootverbose) - printf ("\tusing shared irq %d.\n", irq); - - /* - ** replace old handler by shared-int-handler. - */ - - result = pcibus->pb_idetach (irq, - (inthand2_t *) tail->pcid_handler); - if (result) - printf ("\tCANNOT DETACH INT HANDLER.\n"); - - result = pcibus->pb_iattach (irq, pci_int, irq, &pci_mask0); - if (result) { - printf ("\tCANNOT ATTACH SHARED INT HANDLER.\n"); - goto fail; - }; +#ifdef PCI_DEBUG + if (bootverbose) { + int i; + printf("new pci: vendor=0x%04x, dev=0x%04x, revid=0x%02x\n", + cfg->vendor, cfg->device, cfg->revid); + printf("\t cmdreg=0x%04x, statreg=0x%04x, cachelnsz=%d (dwords)\n", + cfg->cmdreg, cfg->statreg, cfg->cachelnsz); + printf("\t class=%02x-%02x-%02x, hdrtype=0x%02x, mfdev=%d\n", + cfg->class, cfg->subclass, cfg->progif, cfg->hdrtype, cfg->mfdev); + printf("\t lattimer=0x%02x (%d ns), mingnt=0x%02x (%d ns), maxlat=0x%02x (%d ns)\n", + cfg->lattimer, cfg->lattimer * 30, + cfg->mingnt, cfg->mingnt * 250, cfg->maxlat, cfg->maxlat * 250); + + if (cfg->intpin > 0) + printf("\t intpin=%c, irq=%d\n", cfg->intpin +'a' -1, cfg->intline); + + for (i = 0; i < cfg->nummaps; i++) { + pcimap *m = &cfg->map[i]; + printf("\t map[%d]: type %x, range %2d, base %08x, size %2d\n", + i, m->type, m->ln2range, m->base, m->ln2size); + } } -#endif - /* - ** Link new descriptor, reenable ints and done. - */ - - pci_int_desc[irq] = new; - splx (oldspl); - return (1); - - /* - ** Handle some problems. - */ - -conflict: - printf ("\tirq %d already in use.\n", irq); -fail: - /* - ** If descriptor allocated, free it. - ** If included in mask, remove it. - */ - - if (new) free(new, M_DEVBUF); - if (!mdp) (void) pcibus->pb_imaskexc (irq, maskptr); - splx (oldspl); - return (0); +#endif /* PCI_DEBUG */ + pci_drvattach(cfg); /* XXX currently defined in pci_compat.c */ } -/*----------------------------------------------------------------------- -** -** Unmap pci interrupt. -** -**----------------------------------------------------------------------- -*/ +/* return pointer to device that is a bridge to this bus */ -int pci_unmap_int (pcici_t tag) +static pcicfgregs * +pci_bridgeto(int bus) { - int result, oldspl; - struct pci_int_desc *this, **hook, *tail; - unsigned irq; - - /* - ** Get irq line from configuration space, - ** and check for consistency. - */ - - irq = getirq (tag); - if (irq == 0xff) { - return (0); - }; - - /* - ** Search and unlink interrupt descriptor. - */ - - hook = getintdescbytag (irq, tag); - if (hook == NULL) { - printf ("\tno irq %d handler for pci %x\n", - irq, tag.tag); - return (0); - }; - - this = *hook; - *hook= this->pcid_next; - - /* - ** Message - */ - - printf ("\tirq %d handler %p(%p) unmapped for pci %x after %d ints.\n", - irq, this->pcid_handler, this->pcid_argument, - this->pcid_tag.tag, this->pcid_tally); - - /* - ** If this irq no longer included in the mask, remove it. - */ - - if (!getintdescbymptr (irq, this->pcid_maskptr)) - (void) pcibus->pb_imaskexc (irq, this->pcid_maskptr); - - tail = pci_int_desc[irq]; - - if (tail == NULL) { - - /* - ** Remove the old handler. - */ - - result = pcibus->pb_idetach (irq, - (inthand2_t *) this->pcid_handler); - if (result) - printf ("\tirq %d: cannot remove handler.\n", irq); - - } else if (tail->pcid_next == NULL) { - - /* - ** Remove the shared int handler. - ** Install the last remaining handler. - */ - - oldspl = splq (1ul << irq); - - result = pcibus->pb_idetach (irq, pci_int); - if (result) - printf ("\tirq %d: cannot remove handler.\n", irq); - - result = pcibus->pb_iattach (irq, - (inthand2_t *) tail->pcid_handler, - (int) tail->pcid_argument, - tail->pcid_maskptr); - - if (result) - printf ("\tirq %d: cannot install handler.\n", irq); - - splx (oldspl); - }; - - free (this, M_DEVBUF); - return (1); + return (NULL); /* XXX not yet implemented */ } -/*----------------------------------------------------------- -** -** Display of unknown devices. -** -**----------------------------------------------------------- -*/ -struct vt { - u_short ident; - char* name; -}; - -static struct vt VendorTable[] = { - {0x0e11, "Compaq"}, - {0x1000, "NCR/Symbios"}, - {0x1002, "ATI Technologies Inc."}, - {0x1004, "VLSI"}, - {0x100B, "National Semiconductor"}, - {0x100E, "Weitek"}, - {0x1011, "Digital Equipment Corporation"}, - {0x1013, "Cirrus Logic"}, - {0x101A, "NCR"}, - {0x1022, "AMD"}, - {0x102B, "Matrox"}, - {0x102C, "Chips & Technologies"}, - {0x1039, "Silicon Integrated Systems"}, - {0x1042, "SMC"}, - {0x1044, "DPT"}, - {0x1045, "OPTI"}, - {0x104B, "Bus Logic"}, - {0x104C, "TI"}, - {0x1060, "UMC"}, - {0x1080, "Contaq"}, - {0x1095, "CMD"}, - {0x10b9, "ACER Labs"}, - {0x10c8, "NeoMagic"}, - {0x1106, "VIA Technologies"}, - {0x5333, "S3 Inc."}, - {0x8086, "Intel Corporation"}, - {0x9004, "Adaptec"}, - {0,0} -}; - -typedef struct { - const int subclass; - const char *name; -} subclass_name; - -/* 0x00 prehistoric subclasses */ -static const subclass_name old_subclasses[] = -{ - { 0x00, "misc" }, - { 0x01, "vga" }, - { 0x00, NULL } -}; - -/* 0x01 mass storage subclasses */ -static const subclass_name storage_subclasses[] = -{ - { 0x00, "scsi" }, - { 0x01, "ide" }, - { 0x02, "floppy"}, - { 0x03, "ipi" }, - { 0x80, "misc" }, - { 0x00, NULL } -}; - -/* 0x02 network subclasses */ -static const subclass_name network_subclasses[] = -{ - { 0x00, "ethernet" }, - { 0x01, "tokenring" }, - { 0x02, "fddi" }, - { 0x80, "misc" }, - { 0x00, NULL } -}; - -/* 0x03 display subclasses */ -static const subclass_name display_subclasses[] = -{ - { 0x00, "vga" }, - { 0x01, "xga" }, - { 0x80, "misc" }, - { 0x00, NULL } -}; - -/* 0x04 multimedia subclasses */ -static const subclass_name multimedia_subclasses[] = -{ - { 0x00, "video" }, - { 0x01, "audio" }, - { 0x80, "misc" }, - { 0x00, NULL } -}; - -/* 0x05 memory subclasses */ -static const subclass_name memory_subclasses[] = -{ - { 0x00, "ram" }, - { 0x01, "flash" }, - { 0x80, "misc" }, - { 0x00, NULL } -}; - -/* 0x06 bridge subclasses */ -static const subclass_name bridge_subclasses[] = -{ - { 0x00, "host" }, - { 0x01, "isa" }, - { 0x02, "eisa" }, - { 0x03, "mc" }, - { 0x04, "pci" }, - { 0x05, "pcmcia"}, - { 0x07, "cardbus"}, - { 0x80, "misc" }, - { 0x00, NULL } -}; - -static const subclass_name *const subclasses[] = { - old_subclasses, - storage_subclasses, - network_subclasses, - display_subclasses, - multimedia_subclasses, - memory_subclasses, - bridge_subclasses, -}; - -static const char *const majclasses[] = { - "old", - "storage", - "network", - "display", - "multimedia", - "memory", - "bridge", - "comms", - "system", - "input", - "docking", - "processor", - "serial" -}; - - -void not_supported (pcici_t tag, u_long type) -{ - u_long reg; - u_long data; - u_char class; - u_char subclass; - struct vt * vp; - int pciint; - int irq; - - /* - ** lookup the names. - */ - - for (vp=VendorTable; vp->ident; vp++) - if (vp->ident == (type & 0xffff)) - break; +/* scan one PCI bus for devices */ - /* - ** and display them. - */ - - if (vp->ident) printf (vp->name); - else printf ("vendor=0x%04lx", type & 0xffff); - - printf (", device=0x%04lx", type >> 16); - - data = pci_conf_read(tag, PCI_CLASS_REG); - class = (data >> 24) & 0xff; - subclass = (data >> 16) & 0xff; - - if (class < sizeof(majclasses) / sizeof(majclasses[0])) { - printf(", class=%s", majclasses[class]); - } else { - printf(", class=0x%02x", class); - } - - if (class < sizeof(subclasses) / sizeof(subclasses[0])) { - const subclass_name *p = subclasses[class]; - while (p->name && (p->subclass != subclass)) - p++; - if (p->name) { - printf(" (%s)", p->name); - } else { - printf(" (unknown subclass 0x%02lx)", subclass); +static int +pci_probebus(int bus) +{ + pcicfgregs probe; + int bushigh = bus; + + bzero(&probe, sizeof probe); + probe.parent = pci_bridgeto(bus); + probe.bus = bus; + for (probe.slot = 0; probe.slot <= PCI_SLOTMAX; probe.slot++) { + int pcifunchigh = 0; + for (probe.func = 0; probe.func <= pcifunchigh; probe.func++) { + pcicfgregs *cfg = pci_readcfg(&probe); + if (cfg != NULL) { + if (cfg->mfdev) + pcifunchigh = 7; + + if (bushigh < cfg->subordinatebus) + bushigh = cfg->subordinatebus; + + pci_addcfg(cfg); + cfg = NULL; /* we don't own this anymore ... */ + } } - } else { - printf(", subclass=0x%02x", subclass); } + return (bushigh); +} - data = pci_conf_read (tag, PCI_INTERRUPT_REG); - pciint = PCI_INTERRUPT_PIN_EXTRACT(data); - - if (pciint) { - - printf (" int %c irq ", 0x60+pciint); - - irq = PCI_INTERRUPT_LINE_EXTRACT(data); - - /* - ** If it's zero, the isa irq number is unknown, - ** and we cannot bind the pci interrupt. - */ +/* scan a PCI bus tree reached through one PCI attachment point */ - if (irq && (irq != 0xff)) - printf ("%d", irq); - else - printf ("??"); - }; +int +pci_probe(pciattach *parent) +{ + int bushigh; + int bus = 0; - if (class != (PCI_CLASS_BRIDGE >> 24)) - printf (" [no driver assigned]"); - printf ("\n"); + bushigh = pci_bushigh(); + while (bus <= bushigh) { + int newbushigh; - if (bootverbose) { - if (class == (PCI_CLASS_BRIDGE >> 24)) { - printf ("configuration space registers:"); - for (reg = 0; reg < 0x100; reg+=4) { - if ((reg & 0x0f) == 0) printf ("\n%02x:\t", reg); - printf ("%08x ", pci_conf_read (tag, reg)); - } - printf ("\n"); - } else { - for (reg=PCI_MAP_REG_START; reg<PCI_MAP_REG_END; reg+=4) { - data = pci_conf_read (tag, reg); - if ((data&~7)==0) continue; - switch (data&7) { + printf("Probing for devices on PCI bus %d:\n", bus); + newbushigh = pci_probebus(bus); - case 1: - case 5: - printf ("\tmap(%x): io(%04lx)\n", - reg, data & ~3); - break; - case 0: - printf ("\tmap(%x): mem32(%08lx)\n", - reg, data & ~7); - break; - case 2: - printf ("\tmap(%x): mem20(%05lx)\n", - reg, data & ~7); - break; - case 4: - printf ("\tmap(%x): mem64(%08x%08lx)\n", - reg, pci_conf_read (tag, reg +4), data & ~7); - reg += 4; - break; - } - } - } + if (bushigh < newbushigh) + bushigh = newbushigh; + bus++; } + return (bushigh); } /* - * This is the user interface to the PCI configuration space. + * This is the user interface to PCI configuration space. */ - - -static void -pci_remember(int bus, int dev, int func, struct pci_device *dvp) -{ - struct pci_conf *p; - pcici_t tag; - - if (++pci_dev_list_count > pci_dev_list_size) { - struct pci_conf *new; - - pci_dev_list_size += 8; - MALLOC(new, struct pci_conf *, pci_dev_list_size * sizeof *new, - M_DEVL, M_NOWAIT); - if (!new) { - pci_dev_list_size -= 8; - pci_dev_list_count--; - return; - } - - if (pci_dev_list) { - bcopy(pci_dev_list, new, ((pci_dev_list_size - 8) * - sizeof *new)); - FREE(pci_dev_list, M_DEVL); - } - pci_dev_list = new; - } - - p = &pci_dev_list[pci_dev_list_count - 1]; - p->pc_sel.pc_bus = bus; - p->pc_sel.pc_dev = dev; - p->pc_sel.pc_func = func; - p->pc_dvp = dvp; - p->pc_cb = pcicb; - - tag = pcibus->pb_tag (bus, dev, func); - p->pc_hdr = (pci_conf_read (tag, PCI_HEADER_MISC) >> 16) & 0xff; - p->pc_devid = pci_conf_read(tag, PCI_ID_REG); - p->pc_class = pci_conf_read(tag, PCI_CLASS_REG); - switch (p->pc_hdr & 0x7f) { - case 0: - p->pc_subid = pci_conf_read(tag, PCI_SUBID_REG0); - break; - case 1: - p->pc_subid = pci_conf_read(tag, PCI_SUBID_REG1); - break; - case 2: - p->pc_subid = pci_conf_read(tag, PCI_SUBID_REG2); - break; - default: - p->pc_subid = 0; - } -} - + static int pci_open(dev_t dev, int oflags, int devtype, struct proc *p) { if ((oflags & FWRITE) && securelevel > 0) { return EPERM; } - return 0; } @@ -1904,79 +470,62 @@ pci_ioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) struct pci_io *io; size_t iolen; int error; - pcici_t tag; if (cmd != PCIOCGETCONF && !(flag & FWRITE)) return EPERM; switch(cmd) { case PCIOCGETCONF: +#ifdef NOTYET +static struct pci_conf *pci_dev_list; +static unsigned pci_dev_list_count; +static unsigned pci_dev_list_size; + cio = (struct pci_conf_io *)data; iolen = min(cio->pci_len, pci_dev_list_count * sizeof(struct pci_conf)); cio->pci_len = pci_dev_list_count * sizeof(struct pci_conf); error = copyout(pci_dev_list, cio->pci_buf, iolen); +#else + error = ENODEV; +#endif break; case PCIOCREAD: io = (struct pci_io *)data; switch(io->pi_width) { + pcicfgregs probe; case 4: - tag = pcibus->pb_tag (io->pi_sel.pc_bus, - io->pi_sel.pc_dev, - io->pi_sel.pc_func); - io->pi_data = pci_conf_read(tag, io->pi_reg); - error = 0; - break; case 2: case 1: - default: - error = ENODEV; - break; - } - break; - - case PCIOCWRITE: - io = (struct pci_io *)data; - switch(io->pi_width) { - case 4: - tag = pcibus->pb_tag (io->pi_sel.pc_bus, - io->pi_sel.pc_dev, - io->pi_sel.pc_func); - pci_conf_write(tag, io->pi_reg, io->pi_data); + probe.bus = io->pi_sel.pc_bus; + probe.slot = io->pi_sel.pc_dev; + probe.func = io->pi_sel.pc_func; + io->pi_data = pci_cfgread(&probe, + io->pi_reg, io->pi_width); error = 0; break; - case 2: - case 1: default: error = ENODEV; break; } break; - case PCIOCATTACHED: + case PCIOCWRITE: io = (struct pci_io *)data; switch(io->pi_width) { + pcicfgregs probe; case 4: - { - int i = pci_dev_list_count; - struct pci_conf *p = pci_dev_list; - error = ENODEV; - while (i--) { - if (io->pi_sel.pc_bus == p->pc_sel.pc_bus && - io->pi_sel.pc_dev == p->pc_sel.pc_dev && - io->pi_sel.pc_func == p->pc_sel.pc_func) { - io->pi_data = (u_int32_t)p->pc_dvp; - error = 0; - break; - } - p++; - } - } - break; case 2: case 1: + probe.bus = io->pi_sel.pc_bus; + probe.slot = io->pi_sel.pc_dev; + probe.func = io->pi_sel.pc_func; + pci_cfgwrite(&probe, + io->pi_reg, io->pi_data, io->pi_width); + error = 0; + break; default: error = ENODEV; break; @@ -2017,4 +566,4 @@ pci_cdevinit(void *dummy) SYSINIT(pcidev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+PCI_CDEV, pci_cdevinit, NULL); -#endif /* NPCI */ +#endif /* NPCI > 0 */ diff --git a/sys/pci/pci_compat.c b/sys/pci/pci_compat.c new file mode 100644 index 0000000..c14d864 --- /dev/null +++ b/sys/pci/pci_compat.c @@ -0,0 +1,351 @@ +/* + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR 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. + * + * $Id$ + * + */ + +#include "pci.h" +#if NPCI > 0 + +/* for compatibility to FreeBSD-2.2 version of PCI code */ + +#include <stddef.h> + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/fcntl.h> +#include <sys/kernel.h> /* for DATA_SET support */ + +#include <vm/vm.h> +#include <vm/pmap.h> +#include <i386/isa/isa_device.h> +#include <sys/interrupt.h> + +#include <pci/pcireg.h> +#include <pci/pcivar.h> + +#ifdef RESOURCE_CHECK +#include <sys/drvresource.h> +#endif + +#ifdef PCI_COMPAT + +/* ------------------------------------------------------------------------- */ + +static int +pci_mapno(pcicfgregs *cfg, int reg) +{ + int map = -1; + + if ((reg & 0x03) == 0) { + map = (reg -0x10) / 4; + if (map < 0 || map >= cfg->nummaps) + map = -1; + } + return (map); +} + +static int +pci_isportmap(pcicfgregs *cfg, int map) +{ + return ((unsigned)map < cfg->nummaps + && (cfg->map[map].type & PCI_MAPPORT) != 0); +} + +static int +pci_ismemmap(pcicfgregs *cfg, int map) +{ + return ((unsigned)map < cfg->nummaps + && (cfg->map[map].type & PCI_MAPMEM) != 0); +} + +/* ------------------------------------------------------------------------- */ + +u_long +pci_conf_read(pcici_t tag, u_long reg) +{ + return (pci_cfgread(tag, reg, 4)); +} + +void +pci_conf_write(pcici_t tag, u_long reg, u_long data) +{ + pci_cfgwrite(tag, reg, data, 4); +} + +int pci_map_port(pcici_t cfg, u_long reg, u_short* pa) +{ + int map; + + map = pci_mapno(cfg, reg); + if (pci_isportmap(cfg, map)) { + u_int32_t iobase; + u_int32_t iosize; + + iobase = cfg->map[map].base; + iosize = 1 << cfg->map[map].ln2size; +#ifdef RESOURCE_CHECK + if (resource_claim(cfg, REST_PORT, RESF_NONE, + iobase, iobase + iosize -1) == 0) +#endif /* RESOURCE_CHECK */ + { + *pa = iobase; + return (1); + } + } + return (0); +} + +int pci_map_mem(pcici_t cfg, u_long reg, vm_offset_t* va, vm_offset_t* pa) +{ + int map; + + map = pci_mapno(cfg, reg); + if (pci_ismemmap(cfg, map)) { + u_int32_t paddr; + u_int32_t psize; + + paddr = cfg->map[map].base; + psize = 1 << cfg->map[map].ln2size; +#ifdef RESOURCE_CHECK + if (resource_claim(cfg, REST_MEM, RESF_NONE, + paddr, paddr + psize -1) == 0) +#endif /* RESOURCE_CHECK */ + { + u_int32_t poffs; + vm_offset_t vaddr; + + poffs = paddr - trunc_page(paddr); + vaddr = (vm_offset_t)pmap_mapdev(paddr-poffs, psize+poffs); + if (vaddr != NULL) { + vaddr += poffs; + *va = vaddr; + *pa = paddr; + return (1); + } + } + } + return (0); +} + +int +pci_map_int(pcici_t cfg, pci_inthand_t *func, void *arg, unsigned *maskptr) +{ + if (cfg->intpin != 0) { + int irq = cfg->intline; + void *dev_instance = (void *)-1; /* XXX use cfg->devdata */ + intrec *idesc; + + idesc = intr_create(dev_instance, irq, func, arg, maskptr, 0); + return (intr_connect(idesc) == 0); + } + return (1); +} + +int +pci_unmap_int(pcici_t cfg) +{ + return (0); /* not supported, yet, since cfg doesn't know about idesc */ +} + +/* ------------------------------------------------------------------------- */ + +/* + * Preliminary support for "wired" PCI devices. + * This code supports currently only devices on PCI bus 0, since the + * mapping from PCI BIOS bus numbers to configuration file bus numbers + * is not yet maintained, whenever a PCI to PCI bridge is found. + * The "bus" field of "pciwirecfg" correlates an PCI bus with the bridge + * it is attached to. The "biosbus" field is to be updated for each bus, + * whose bridge is probed. An entry with bus != 0 and biosbus == 0 is + * invalid and will be skipped in the search for a wired unit, but not + * in the test for a free unit number. + */ + +typedef struct { + char *name; + int unit; + u_int8_t bus; + u_int8_t slot; + u_int8_t func; + u_int8_t biosbus; +} pciwirecfg; + +static pciwirecfg pci_wireddevs[] = { + /* driver, unit, bus, slot, func, BIOS bus */ + { "ncr", 2, 1, 4, 0, 0 }, + { "ed", 2, 1, 5, 0, 0 }, + /* do not delete the end marker that follows this comment !!! */ + { NULL } +}; + +/* return unit number of wired device, or -1 if no match */ + +static int +pci_wiredunit(pcicfgregs *cfg, char *name) +{ + pciwirecfg *p; + + p = pci_wireddevs; + while (p->name != NULL) { + if (p->bus == cfg->bus + && p->slot == cfg->slot + && p->func == cfg->func + && strcmp(p->name, name) == 0) + return (p->unit); + p++; + } + return (-1); +} + +/* return free unit number equal or greater to the one supplied as parameter */ + +static int +pci_freeunit(pcicfgregs *cfg, char *name, int unit) +{ + pciwirecfg *p; + + p = pci_wireddevs; + while (p->name != NULL) { + if (p->unit == unit && strcmp(p->name, name) == 0) { + p = pci_wireddevs; + unit++; + } else { + p++; + } + } + return (unit); +} + +static char *drvname; + +static char* +pci_probedrv(pcicfgregs *cfg, struct pci_device *dvp) +{ + if (dvp && dvp->pd_probe) { + pcidi_t type = (cfg->device << 16) + cfg->vendor; + return (dvp->pd_probe(cfg, type)); + } + return (NULL); +} + +static struct pci_lkm *pci_lkm_head; + +static struct pci_device* +pci_finddrv(pcicfgregs *cfg) +{ + struct pci_device **dvpp; + struct pci_device *dvp = NULL; + struct pci_lkm *lkm; + + drvname = NULL; + lkm = pci_lkm_head; + while (drvname == NULL && lkm != NULL) { + dvp = lkm->dvp; + drvname = pci_probedrv(cfg, dvp); + lkm = lkm->next; + } + + dvpp = (struct pci_device **)pcidevice_set.ls_items; + while (drvname == NULL && (dvp = *dvpp++) != NULL) + drvname = pci_probedrv(cfg, dvp); + return (dvp); +} + +static void +pci_drvmessage(pcicfgregs *cfg, char *name, int unit) +{ + if (drvname == NULL || *drvname == '\0') + return; + printf("%s%d: <%s> rev 0x%02x", name, unit, drvname, cfg->revid); + if (cfg->intpin != 0) + printf(" int %c irq %d", cfg->intpin + 'a' -1, cfg->intline); + printf(" on pci%d.%d.%d\n", cfg->bus, cfg->slot, cfg->func); +} + + +void +pci_drvattach(pcicfgregs *cfg) +{ + struct pci_device *dvp; + + dvp = pci_finddrv(cfg); + if (dvp != NULL) { + int unit; + + unit = pci_wiredunit(cfg, dvp->pd_name); + if (unit < 0) { + unit = pci_freeunit(cfg, dvp->pd_name, *dvp->pd_count); + *dvp->pd_count = unit +1; + } + pci_drvmessage(cfg, dvp->pd_name, unit); + if (dvp->pd_attach) + dvp->pd_attach(cfg, unit); + } +} + +/* ------------------------------------------------------------------------- */ + +static void +pci_rescan(void) +{ + /* XXX do nothing, currently, soon to come ... */ +} + +int pci_register_lkm (struct pci_device *dvp, int if_revision) +{ + struct pci_lkm *lkm; + + if (if_revision != 0) { + return (-1); + } + if (dvp == NULL || dvp->pd_probe == NULL || dvp->pd_attach == NULL) { + return (-1); + } + lkm = malloc (sizeof (*lkm), M_DEVBUF, M_WAITOK); + if (lkm != NULL) { + return (-1); + } + + lkm->dvp = dvp; + lkm->next = pci_lkm_head; + pci_lkm_head = lkm; + pci_rescan(); + return (0); +} + +void +pci_configure(void) +{ + pci_probe(NULL); +} + +/* ------------------------------------------------------------------------- */ + +#endif /* PCI_COMPAT */ +#endif /* NPCI > 0 */ diff --git a/sys/pci/pcireg.h b/sys/pci/pcireg.h index 05e3c07..cd5c6e8 100644 --- a/sys/pci/pcireg.h +++ b/sys/pci/pcireg.h @@ -1,208 +1,250 @@ -/************************************************************************** -** -** $Id: pcireg.h,v 1.13 1997/04/20 06:57:43 phk Exp $ -** -** Names for PCI configuration space registers. -** -** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved. -** -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR 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. -** -*************************************************************************** -*/ - -#ifndef __PCI_REG_H__ -#define __PCI_REG_H__ "pl2 95/03/21" - +#ifndef PCI_COMPAT +#define PCI_COMPAT +#endif /* -** Device identification register; contains a vendor ID and a device ID. -** We have little need to distinguish the two parts. -*/ -#define PCI_ID_REG 0x00 + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR 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. + * + * $Id$ + * + */ /* -** Command and status register. -*/ -#define PCI_COMMAND_STATUS_REG 0x04 - + * PCIM_xxx: mask to locate subfield in register + * PCIR_xxx: config register offset + * PCIC_xxx: device class + * PCIS_xxx: device subclass + * PCIP_xxx: device programming interface + * PCIV_xxx: PCI vendor ID (only required to fixup ancient devices) + * PCID_xxx: device ID + */ + +/* some PCI bus constants */ + +#define PCI_BUSMAX 255 +#define PCI_SLOTMAX 31 +#define PCI_FUNCMAX 7 +#define PCI_REGMAX 255 + +/* PCI config header registers for all devices */ + +#define PCIR_DEVVENDOR 0x00 +#define PCIR_VENDOR 0x00 +#define PCIR_DEVICE 0x02 +#define PCIR_COMMAND 0x04 +#define PCIR_STATUS 0x06 +#define PCIR_REVID 0x08 +#define PCIR_PROGIF 0x09 +#define PCIR_SUBCLASS 0x0a +#define PCIR_CLASS 0x0b +#define PCIR_CACHELNSZ 0x0c +#define PCIR_LATTIMER 0x0d +#define PCIR_HEADERTYPE 0x0e +#define PCIM_MFDEV 0x80 +#define PCIR_BIST 0x0f + +/* config registers for header type 0 devices */ + +#define PCIR_MAPS 0x10 +#define PCIR_CARDBUSCIS 0x28 +#define PCIR_SUBVEND_0 0x2c +#define PCIR_SUBDEV_0 0x2e +#define PCIR_INTLINE 0x3c +#define PCIR_INTPIN 0x3d +#define PCIR_MINGNT 0x3e +#define PCIR_MAXLAT 0x3f + +/* config registers for header type 1 devices */ + +#define PCIR_SECSTAT_1 0 /**/ + +#define PCIR_PRIBUS_1 0x18 +#define PCIR_SECBUS_1 0x19 +#define PCIR_SUBBUS_1 0x1a +#define PCIR_SECLAT_1 0x1b + +#define PCIR_IOBASEL_1 0x1c +#define PCIR_IOLIMITL_1 0x1d +#define PCIR_IOBASEH_1 0 /**/ +#define PCIR_IOLIMITH_1 0 /**/ + +#define PCIR_MEMBASE_1 0x20 +#define PCIR_MEMLIMIT_1 0x22 + +#define PCIR_PMBASEL_1 0x24 +#define PCIR_PMLIMITL_1 0x26 +#define PCIR_PMBASEH_1 0 /**/ +#define PCIR_PMLIMITH_1 0 /**/ + +#define PCIR_BRIDGECTL_1 0 /**/ + +#define PCIR_SUBVEND_1 0x34 +#define PCIR_SUBDEV_1 0x36 + +/* config registers for header type 2 devices */ + +#define PCIR_SECSTAT_2 0x16 + +#define PCIR_PRIBUS_2 0x18 +#define PCIR_SECBUS_2 0x19 +#define PCIR_SUBBUS_2 0x1a +#define PCIR_SECLAT_2 0x1b + +#define PCIR_MEMBASE0_2 0x1c +#define PCIR_MEMLIMIT0_2 0x20 +#define PCIR_MEMBASE1_2 0x24 +#define PCIR_MEMLIMIT1_2 0x28 +#define PCIR_IOBASE0_2 0x2c +#define PCIR_IOLIMIT0_2 0x30 +#define PCIR_IOBASE1_2 0x34 +#define PCIR_IOLIMIT1_2 0x38 + +#define PCIR_BRIDGECTL_2 0x3e + +#define PCIR_SUBVEND_2 0x40 +#define PCIR_SUBDEV_2 0x42 + +#define PCIR_PCCARDIF_2 0x44 + +/* PCI device class, subclass and programming interface definitions */ + +#define PCIC_OLD 0x00 +#define PCIS_OLD_NONVGA 0x00 +#define PCIS_OLD_VGA 0x01 + +#define PCIC_STORAGE 0x01 +#define PCIS_STORAGE_SCSI 0x00 +#define PCIS_STORAGE_IDE 0x01 +#define PCIP_STORAGE_IDE_MODEPRIM 0x01 +#define PCIP_STORAGE_IDE_PROGINDPRIM 0x02 +#define PCIP_STORAGE_IDE_MODESEC 0x04 +#define PCIP_STORAGE_IDE_PROGINDSEC 0x08 +#define PCIP_STORAGE_IDE_MASTERDEV 0x80 +#define PCIS_STORAGE_FLOPPY 0x02 +#define PCIS_STORAGE_IPI 0x03 +#define PCIS_STORAGE_RAID 0x04 +#define PCIS_STORAGE_OTHER 0x80 + +#define PCIC_NETWORK 0x02 +#define PCIS_NETWORK_ETHERNET 0x00 +#define PCIS_NETWORK_TOKENRING 0x01 +#define PCIS_NETWORK_FDDI 0x02 +#define PCIS_NETWORK_ATM 0x03 +#define PCIS_NETWORK_OTHER 0x80 + +#define PCIC_DISPLAY 0x03 +#define PCIS_DISPLAY_VGA 0x00 +#define PCIS_DISPLAY_XGA 0x01 +#define PCIS_DISPLAY_OTHER 0x80 + +#define PCIC_MULTIMEDIA 0x04 +#define PCIS_MULTIMEDIA_VIDEO 0x00 +#define PCIS_MULTIMEDIA_AUDIO 0x01 +#define PCIS_MULTIMEDIA_OTHER 0x80 + +#define PCIC_MEMORY 0x05 +#define PCIS_MEMORY_RAM 0x00 +#define PCIS_MEMORY_FLASH 0x01 +#define PCIS_MEMORY_OTHER 0x80 + +#define PCIC_BRIDGE 0x06 +#define PCIS_BRDIGE_HOST 0x00 +#define PCIS_BRIDGE_ISA 0x01 +#define PCIS_BRIDGE_EISA 0x02 +#define PCIS_BRIDGE_MCA 0x03 +#define PCIS_BRIDGE_PCI 0x04 +#define PCIS_BRIDGE_PCMCIA 0x05 +#define PCIS_BRIDGE_NUBUS 0x06 +#define PCIS_BRIDGE_CARDBUS 0x07 +#define PCIS_BRIDGE_OTHER 0x80 + +#define PCIC_SIMPLECOMM 0x07 +#define PCIS_SIMPLECOMM_UART 0x00 +#define PCIS_SIMPLECOMM_PAR 0x01 +#define PCIS_SIMPLECOMM_OTHER 0x80 + +#define PCIC_BASEPERIPH 0x08 +#define PCIS_BASEPERIPH_PIC 0x00 +#define PCIS_BASEPERIPH_DMA 0x01 +#define PCIS_BASEPERIPH_TIMER 0x02 +#define PCIS_BASEPERIPH_RTC 0x03 +#define PCIS_BASEPERIPH_OTHER 0x80 + +#define PCIC_INPUTDEV 0x09 +#define PCIS_INPUTDEV_KEYBOARD 0x00 +#define PCIS_INPUTDEV_DIGITIZER 0x01 +#define PCIS_INPUTDEV_MOUSE 0x02 +#define PCIS_INPUTDEV_OTHER 0x80 + +#define PCIC_DOCKING 0x0a +#define PCIS_DOCKING_GENERIC 0x00 +#define PCIS_DOCKING_OTHER 0x80 + +#define PCIC_PROCESSOR 0x0b +#define PCIS_PROCESSOR_386 0x00 +#define PCIS_PROCESSOR_486 0x01 +#define PCIS_PROCESSOR_PENTIUM 0x02 +#define PCIS_PROCESSOR_ALPHA 0x10 +#define PCIS_PROCESSOR_POWERPC 0x20 +#define PCIS_PROCESSOR_COPROC 0x40 + +#define PCIC_SERIALBUS 0x0c +#define PCIS_SERIALBUS_FW 0x00 +#define PCIS_SERIALBUS_ACCESS 0x01 +#define PCIS_SERIALBUS_SSA 0x02 +#define PCIS_SERIALBUS_USB 0x03 +#define PCIS_SERIALBUS_FC 0x04 +#define PCIS_SERIALBUS +#define PCIS_SERIALBUS + +#define PCIC_OTHER 0xff + +/* some PCI vendor definitions (only used to identify ancient devices !!! */ + +#define PCIV_INTEL 0x8086 + +#define PCID_INTEL_SATURN 0x0483 +#define PCID_INTEL_ORION 0x84c4 + +/* for compatibility to FreeBSD-2.2 version of PCI code */ + +#ifdef PCI_COMPAT + +#define PCI_ID_REG 0x00 +#define PCI_COMMAND_STATUS_REG 0x04 #define PCI_COMMAND_IO_ENABLE 0x00000001 -#define PCI_COMMAND_MEM_ENABLE 0x00000002 -#define PCI_COMMAND_MASTER_ENABLE 0x00000004 -#define PCI_COMMAND_SPECIAL_ENABLE 0x00000008 -#define PCI_COMMAND_INVALIDATE_ENABLE 0x00000010 -#define PCI_COMMAND_PALETTE_ENABLE 0x00000020 -#define PCI_COMMAND_PARITY_ENABLE 0x00000040 -#define PCI_COMMAND_STEPPING_ENABLE 0x00000080 -#define PCI_COMMAND_SERR_ENABLE 0x00000100 -#define PCI_COMMAND_BACKTOBACK_ENABLE 0x00000200 - -#define PCI_STATUS_BACKTOBACK_OKAY 0x00800000 -#define PCI_STATUS_PARITY_ERROR 0x01000000 -#define PCI_STATUS_DEVSEL_FAST 0x00000000 -#define PCI_STATUS_DEVSEL_MEDIUM 0x02000000 -#define PCI_STATUS_DEVSEL_SLOW 0x04000000 -#define PCI_STATUS_DEVSEL_MASK 0x06000000 -#define PCI_STATUS_TARGET_TARGET_ABORT 0x08000000 -#define PCI_STATUS_MASTER_TARGET_ABORT 0x10000000 -#define PCI_STATUS_MASTER_ABORT 0x20000000 -#define PCI_STATUS_SPECIAL_ERROR 0x40000000 -#define PCI_STATUS_PARITY_DETECT 0x80000000 - -/* -** Class register; defines basic type of device. -*/ -#define PCI_CLASS_REG 0x08 - -#define PCI_CLASS_MASK 0xff000000 -#define PCI_SUBCLASS_MASK 0x00ff0000 - -/* base classes */ -#define PCI_CLASS_PREHISTORIC 0x00000000 -#define PCI_CLASS_MASS_STORAGE 0x01000000 -#define PCI_CLASS_NETWORK 0x02000000 -#define PCI_CLASS_DISPLAY 0x03000000 -#define PCI_CLASS_MULTIMEDIA 0x04000000 -#define PCI_CLASS_MEMORY 0x05000000 -#define PCI_CLASS_BRIDGE 0x06000000 -#define PCI_CLASS_UNDEFINED 0xff000000 - -/* 0x00 prehistoric subclasses */ -#define PCI_SUBCLASS_PREHISTORIC_MISC 0x00000000 -#define PCI_SUBCLASS_PREHISTORIC_VGA 0x00010000 - -/* 0x01 mass storage subclasses */ -#define PCI_SUBCLASS_MASS_STORAGE_SCSI 0x00000000 -#define PCI_SUBCLASS_MASS_STORAGE_IDE 0x00010000 -#define PCI_SUBCLASS_MASS_STORAGE_FLOPPY 0x00020000 -#define PCI_SUBCLASS_MASS_STORAGE_IPI 0x00030000 -#define PCI_SUBCLASS_MASS_STORAGE_MISC 0x00800000 - -/* 0x02 network subclasses */ -#define PCI_SUBCLASS_NETWORK_ETHERNET 0x00000000 -#define PCI_SUBCLASS_NETWORK_TOKENRING 0x00010000 -#define PCI_SUBCLASS_NETWORK_FDDI 0x00020000 -#define PCI_SUBCLASS_NETWORK_MISC 0x00800000 - -/* 0x03 display subclasses */ -#define PCI_SUBCLASS_DISPLAY_VGA 0x00000000 -#define PCI_SUBCLASS_DISPLAY_XGA 0x00010000 -#define PCI_SUBCLASS_DISPLAY_MISC 0x00800000 - -/* 0x04 multimedia subclasses */ -#define PCI_SUBCLASS_MULTIMEDIA_VIDEO 0x00000000 -#define PCI_SUBCLASS_MULTIMEDIA_AUDIO 0x00010000 -#define PCI_SUBCLASS_MULTIMEDIA_MISC 0x00800000 - -/* 0x05 memory subclasses */ -#define PCI_SUBCLASS_MEMORY_RAM 0x00000000 -#define PCI_SUBCLASS_MEMORY_FLASH 0x00010000 -#define PCI_SUBCLASS_MEMORY_MISC 0x00800000 - -/* 0x06 bridge subclasses */ -#define PCI_SUBCLASS_BRIDGE_HOST 0x00000000 -#define PCI_SUBCLASS_BRIDGE_ISA 0x00010000 -#define PCI_SUBCLASS_BRIDGE_EISA 0x00020000 -#define PCI_SUBCLASS_BRIDGE_MC 0x00030000 -#define PCI_SUBCLASS_BRIDGE_PCI 0x00040000 -#define PCI_SUBCLASS_BRIDGE_PCMCIA 0x00050000 -#define PCI_SUBCLASS_BRIDGE_CARDBUS 0x00070000 -#define PCI_SUBCLASS_BRIDGE_MISC 0x00800000 - -/* -** Header registers -*/ -#define PCI_HEADER_MISC 0x0c - -#define PCI_HEADER_MULTIFUNCTION 0x00800000 - -/* -** Mapping registers -*/ -#define PCI_MAP_REG_START 0x10 -#define PCI_MAP_REG_END 0x28 - -#define PCI_MAP_MEMORY 0x00000000 +#define PCI_CLASS_REG 0x08 +#define PCI_CLASS_MASK 0xff000000 +#define PCI_SUBCLASS_MASK 0x00ff0000 +#define PCI_CLASS_PREHISTORIC 0x00000000 +#define PCI_SUBCLASS_PREHISTORIC_VGA 0x00010000 +#define PCI_CLASS_DISPLAY 0x03000000 +#define PCI_SUBCLASS_DISPLAY_VGA 0x00000000 +#define PCI_CLASS_BRIDGE 0x06000000 +#define PCI_MAP_REG_START 0x10 +#define PCI_MAP_REG_END 0x28 #define PCI_MAP_IO 0x00000001 +#define PCI_INTERRUPT_REG 0x3c -#define PCI_MAP_MEMORY_TYPE_32BIT 0x00000000 -#define PCI_MAP_MEMORY_TYPE_32BIT_1M 0x00000002 -#define PCI_MAP_MEMORY_TYPE_64BIT 0x00000004 -#define PCI_MAP_MEMORY_TYPE_MASK 0x00000006 -#define PCI_MAP_MEMORY_CACHABLE 0x00000008 -#define PCI_MAP_MEMORY_ADDRESS_MASK 0xfffffff0 - -#define PCI_MAP_IO_ADDRESS_MASK 0xfffffffc -/* -** PCI-PCI bridge mapping registers -*/ -#define PCI_PCI_BRIDGE_BUS_REG 0x18 -#define PCI_PCI_BRIDGE_IO_REG 0x1c -#define PCI_PCI_BRIDGE_MEM_REG 0x20 -#define PCI_PCI_BRIDGE_PMEM_REG 0x24 - -#define PCI_SUBID_REG0 0x2c -#define PCI_SUBID_REG1 0x34 -#define PCI_SUBID_REG2 0x40 - -#define PCI_SUBORDINATE_BUS_MASK 0x00ff0000 -#define PCI_SECONDARY_BUS_MASK 0x0000ff00 -#define PCI_PRIMARY_BUS_MASK 0x000000ff - -#define PCI_SUBORDINATE_BUS_EXTRACT(x) (((x) >> 16) & 0xff) -#define PCI_SECONDARY_BUS_EXTRACT(x) (((x) >> 8) & 0xff) -#define PCI_PRIMARY_BUS_EXTRACT(x) (((x) ) & 0xff) - -#define PCI_PRIMARY_BUS_INSERT(x, y) (((x) & ~PCI_PRIMARY_BUS_MASK) | ((y) << 0)) -#define PCI_SECONDARY_BUS_INSERT(x, y) (((x) & ~PCI_SECONDARY_BUS_MASK) | ((y) << 8)) -#define PCI_SUBORDINATE_BUS_INSERT(x, y) (((x) & ~PCI_SUBORDINATE_BUS_MASK) | ((y) << 16)) - -#define PCI_PPB_IOBASE_EXTRACT(x) (((x) << 8) & 0xF000) -#define PCI_PPB_IOLIMIT_EXTRACT(x) (((x) << 0) & 0xF000 | 0x0FFF) - -#define PCI_PPB_MEMBASE_EXTRACT(x) (((x) << 16) & 0xFFF00000) -#define PCI_PPB_MEMLIMIT_EXTRACT(x) (((x) << 0) & 0xFFF00000 | 0x000FFFFF) - -/* -** PCI-Cardbus bridge mapping registers -*/ -#define PCI_CARDBUS_SOCKET_REG 0x10 - -/* -** Interrupt configuration register -*/ -#define PCI_INTERRUPT_REG 0x3c - -#define PCI_INTERRUPT_PIN_MASK 0x0000ff00 -#define PCI_INTERRUPT_PIN_EXTRACT(x) ((((x) & PCI_INTERRUPT_PIN_MASK) >> 8) & 0xff) -#define PCI_INTERRUPT_PIN_NONE 0x00 -#define PCI_INTERRUPT_PIN_A 0x01 -#define PCI_INTERRUPT_PIN_B 0x02 -#define PCI_INTERRUPT_PIN_C 0x03 -#define PCI_INTERRUPT_PIN_D 0x04 - -#define PCI_INTERRUPT_LINE_MASK 0x000000ff -#define PCI_INTERRUPT_LINE_EXTRACT(x) ((((x) & PCI_INTERRUPT_LINE_MASK) >> 0) & 0xff) -#define PCI_INTERRUPT_LINE_INSERT(x,v) (((x) & ~PCI_INTERRUPT_LINE_MASK) | ((v) << 0)) - -#endif /* __PCI_REG_H__ */ +#endif /* PCI_COMPAT */ diff --git a/sys/pci/pcisupport.c b/sys/pci/pcisupport.c index 313db95..97dfb1e 100644 --- a/sys/pci/pcisupport.c +++ b/sys/pci/pcisupport.c @@ -1,6 +1,6 @@ /************************************************************************** ** -** $Id: pcisupport.c,v 1.44 1997/03/25 19:03:04 se Exp $ +** $Id: pcisupport.c,v 1.45 1997/03/28 18:40:24 phk Exp $ ** ** Device driver for DEC/INTEL PCI chipsets. ** @@ -50,8 +50,6 @@ #include <pci/pcivar.h> #include <pci/pcireg.h> -static void config_orion (pcici_t tag); - /*--------------------------------------------------------- ** ** Intel chipsets for 486 / Pentium processor @@ -81,9 +79,6 @@ struct condmsg { const char *text; }; -/* make sure formats expand to at least as many chars !!! */ -#define PPB_DESCR "generic PCI bridge (vendor=%04x device=%04x subclass=%1.2d)" - static char* generic_pci_bridge (pcici_t tag) { @@ -114,7 +109,6 @@ generic_pci_bridge (pcici_t tag) return 0; } - static char* chipset_probe (pcici_t tag, pcidi_t type) { @@ -163,6 +157,8 @@ chipset_probe (pcici_t tag, pcidi_t type) case 0x12378086: return ("Intel 82440FX (Natoma) PCI and memory controller"); case 0x84c48086: + tag->secondarybus = + tag->subordinatebus = pci_cfgread(tag, 0x4a, 1); return ("Intel 82450KX (Orion) PCI memory controller"); case 0x84c58086: return ("Intel 82454GX (Orion) host to PCI bridge"); @@ -672,27 +668,9 @@ dumpconfigspace (pcici_t tag) #endif /* PCI_QUIET */ -extern unsigned pciroots; - -static void -config_orion (pcici_t tag) -{ - unsigned busno = (pci_conf_read (tag, 0x48) >> 16) & 0xff; - - if (busno > 0) { - pciroots++; - } -} - static void chipset_attach (pcici_t config_id, int unit) { - switch (pci_conf_read (config_id, PCI_ID_REG)) { - - case 0x84c48086: /* Intel Orion */ - config_orion (config_id); - break; - } #ifndef PCI_QUIET if (!bootverbose) return; diff --git a/sys/pci/pcivar.h b/sys/pci/pcivar.h index cb85100..4bb8496 100644 --- a/sys/pci/pcivar.h +++ b/sys/pci/pcivar.h @@ -1,129 +1,183 @@ -/************************************************************************** -** -** $Id$ -** -** Declarations for pci device drivers. -** -** FreeBSD -** -**------------------------------------------------------------------------- -** -** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR 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. -** -*************************************************************************** -*/ - -#ifndef __PCI_VAR_H__ -#define __PCI_VAR_H__ "pl2 95/03/21" - -/*----------------------------------------------------------------- -** -** main pci initialization function. -** called at boot time from autoconf.c -** -**----------------------------------------------------------------- -*/ - -void pci_configure (void); - -/*----------------------------------------------------------------- -** -** The pci configuration id describes a pci device on the bus. -** It is constructed from: bus, device & function numbers. -** -**----------------------------------------------------------------- -*/ - -typedef union { - u_long cfg1; - struct { - u_char enable; - u_char forward; - u_short port; - } cfg2; - unsigned tag; - } pcici_t; - -#define sametag(x,y) ((x).tag == (y).tag) - -/*----------------------------------------------------------------- -** -** Each pci device has an unique device id. -** It is used to find a matching driver. -** -**----------------------------------------------------------------- -*/ - -typedef u_long pcidi_t; - -/*----------------------------------------------------------------- -** -** The following functions are provided for the device driver -** to read/write the configuration space. -** -** pci_conf_read(): -** Read a long word from the pci configuration space. -** Requires a tag (from pcitag) and the register -** number (should be a long word alligned one). -** -** pci_conf_write(): -** Writes a long word to the pci configuration space. -** Requires a tag (from pcitag), the register number -** (should be a long word alligned one), and a value. -** -**----------------------------------------------------------------- -*/ - -u_long pci_conf_read (pcici_t tag, u_long reg ); - -void pci_conf_write (pcici_t tag, u_long reg, u_long data); - -/*----------------------------------------------------------------- -** -** The pci driver structure. -** -** name: The short device name. -** -** probe: Checks if the driver can support a device -** with this type. The tag may be used to get -** more info with pci_read_conf(). See below. -** It returns a string with the devices name, -** or a NULL pointer, if the driver cannot -** support this device. -** -** attach: Allocate a control structure and prepare -** it. This function may use the pci mapping -** functions. See below. -** (configuration id) or type. -** -** count: A pointer to a unit counter. -** It's used by the pci configurator to -** allocate unit numbers. -** -**----------------------------------------------------------------- -*/ +#ifndef PCI_COMPAT +#define PCI_COMPAT +#endif +/* + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * 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 unmodified, 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR 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. + * + * $Id$ + * + */ + +/* some PCI bus constants */ + +#define PCI_BUSMAX 255 /* highest supported bus number */ +#define PCI_SLOTMAX 31 /* highest supported slot number */ +#define PCI_FUNCMAX 7 /* highest supported function number */ +#define PCI_REGMAX 255 /* highest supported config register addr. */ + +#define PCI_MAXMAPS_0 6 /* max. no. of memory/port maps */ +#define PCI_MAXMAPS_1 2 /* max. no. of maps for PCI to PCI bridge */ +#define PCI_MAXMAPS_2 1 /* max. no. of maps for CardBus bridge */ + +/* pci_addr_t covers this system's PCI bus address space: 32 or 64 bit */ + +#ifdef PCI_A64 +typedef u_int64_t pci_addr_t; /* u_int64_t for system with 64bit addresses */ +#else +typedef u_int32_t pci_addr_t; /* u_int64_t for system with 64bit addresses */ +#endif + +/* map register information */ + +typedef struct { + u_int32_t base; + u_int8_t type; +#define PCI_MAPMEM 0x01 /* memory map */ +#define PCI_MAPMEMP 0x02 /* prefetchable memory map */ +#define PCI_MAPPORT 0x04 /* port map */ + u_int8_t ln2size; + u_int8_t ln2range; +/* u_int8_t dummy;*/ +} pcimap; + +/* config header information common to all header types */ + +typedef struct pcicfg { + struct pcicfg *parent; + struct pcicfg *next; + pcimap *map; /* pointer to array of PCI maps */ + void *hdrspec; /* pointer to header type specific data */ + + u_int16_t subvendor; /* card vendor ID */ + u_int16_t subdevice; /* card device ID, assigned by card vendor */ + u_int16_t vendor; /* chip vendor ID */ + u_int16_t device; /* chip device ID, assigned by chip vendor */ + + u_int16_t cmdreg; /* disable/enable chip and PCI options */ + u_int16_t statreg; /* supported PCI features and error state */ + + u_int8_t class; /* chip PCI class */ + u_int8_t subclass; /* chip PCI subclass */ + u_int8_t progif; /* chip PCI programming interface */ + u_int8_t revid; /* chip revision ID */ + + u_int8_t hdrtype; /* chip config header type */ + u_int8_t cachelnsz; /* cache line size in 4byte units */ + u_int8_t intpin; /* PCI interrupt pin */ + u_int8_t intline; /* interrupt line (IRQ for PC arch) */ + + u_int8_t mingnt; /* min. useful bus grant time in 250ns units */ + u_int8_t maxlat; /* max. tolerated bus grant latency in 250ns */ + u_int8_t lattimer; /* latency timer in units of 30ns bus cycles */ + + u_int8_t mfdev; /* multi-function device (from hdrtype reg) */ + u_int8_t nummaps; /* actual number of PCI maps used */ + + u_int8_t bus; /* config space bus address */ + u_int8_t slot; /* config space slot address */ + u_int8_t func; /* config space function number */ + + u_int8_t secondarybus; /* bus on secondary side of bridge, if any */ + u_int8_t subordinatebus; /* topmost bus number behind bridge, if any */ +} pcicfgregs; + +/* additional type 1 device config header information (PCI to PCI bridge) */ + +#ifdef PCI_A64 +#define PCI_PPBMEMBASE(h,l) ((((pci_addr_t)(h) << 32) + ((l)<<16)) & ~0xfffff) +#define PCI_PPBMEMLIMIT(h,l) ((((pci_addr_t)(h) << 32) + ((l)<<16)) | 0xfffff) +#else +#define PCI_PPBMEMBASE(h,l) (((l)<<16) & ~0xfffff) +#define PCI_PPBMEMLIMIT(h,l) (((l)<<16) | 0xfffff) +#endif /* PCI_A64 */ + +#define PCI_PPBIOBASE(h,l) ((((h)<<16) + ((l)<<8)) & ~0xfff) +#define PCI_PPBIOLIMIT(h,l) ((((h)<<16) + ((l)<<8)) | 0xfff) + +typedef struct { + pci_addr_t pmembase; /* base address of prefetchable memory */ + pci_addr_t pmemlimit; /* topmost address of prefetchable memory */ + u_int32_t membase; /* base address of memory window */ + u_int32_t memlimit; /* topmost address of memory window */ + u_int32_t iobase; /* base address of port window */ + u_int32_t iolimit; /* topmost address of port window */ + u_int16_t secstat; /* secondary bus status register */ + u_int16_t bridgectl; /* bridge control register */ + u_int8_t seclat; /* CardBus latency timer */ +} pcih1cfgregs; + +/* additional type 2 device config header information (CardBus bridge) */ + +typedef struct { + u_int32_t membase0; /* base address of memory window */ + u_int32_t memlimit0; /* topmost address of memory window */ + u_int32_t membase1; /* base address of memory window */ + u_int32_t memlimit1; /* topmost address of memory window */ + u_int32_t iobase0; /* base address of port window */ + u_int32_t iolimit0; /* topmost address of port window */ + u_int32_t iobase1; /* base address of port window */ + u_int32_t iolimit1; /* topmost address of port window */ + u_int32_t pccardif; /* PC Card 16bit IF legacy more base addr. */ + u_int16_t secstat; /* secondary bus status register */ + u_int16_t bridgectl; /* bridge control register */ + u_int8_t seclat; /* CardBus latency timer */ +} pcih2cfgregs; + +/* PCI bus attach definitions (there could be multiple PCI bus *trees* ... */ + +typedef struct pciattach { + int unit; + int pcibushigh; + struct pciattach *next; +} pciattach; + +/* externally visible functions */ + +int pci_probe (pciattach *attach); +void pci_drvattach(pcicfgregs *cfg); + +/* low level PCI config register functions provided by pcibus.c */ + +int pci_cfgopen (void); +int pci_cfgread (pcicfgregs *cfg, int reg, int bytes); +void pci_cfgwrite (pcicfgregs *cfg, int reg, int data, int bytes); + +/* for compatibility to FreeBSD-2.2 version of PCI code */ + +#ifdef PCI_COMPAT + +typedef pcicfgregs *pcici_t; +typedef unsigned pcidi_t; +typedef void pci_inthand_t(void *arg); + +#define pci_max_burst_len (3) + +/* just copied from old PCI code for now ... */ + +extern struct linker_set pcidevice_set; +extern int pci_mechanism; struct pci_device { char* pd_name; @@ -133,97 +187,17 @@ struct pci_device { int (*pd_shutdown) (int, int); }; -/*----------------------------------------------------------------- -** -** This table includes pointers to all pci device drivers. -** It should be generated by the linker. -** -**----------------------------------------------------------------- -*/ - -extern struct linker_set pcidevice_set; - -extern unsigned pci_max_burst_len; /* log2 of safe burst transfer length */ -extern unsigned pci_mechanism; -extern unsigned pci_maxdevice; - -/*----------------------------------------------------------------- -** -** Map a pci device to physical and virtual memory. -** -** Entry selects the register in the pci configuration -** space, which supplies the size of the region, and -** receives the physical address. -** -** In case of success the function sets the addresses -** in *va and *pa, and returns 1. -** In case of errors a message is written, -** and the function returns 0. -** -**----------------------------------------------------------------- -*/ - -int pci_map_mem (pcici_t tag, u_long entry, vm_offset_t *va, vm_offset_t *pa); - -/*----------------------------------------------------------------- -** -** Map a pci device to an io port area. -** -** Entry selects the register in the pci configuration -** space, which supplies the size of the region, and -** receives the port number. -** -** In case of success the function sets the port number in pa, -** and returns 1. -** In case of errors a message is written, -** and the function returns 0. -** -**----------------------------------------------------------------- -*/ - -int pci_map_port (pcici_t tag, u_long entry, u_short * pa); - -/*----------------------------------------------------------------- -** -** Map a pci interrupt to an isa irq line, and enable the interrupt. -** -** ----------------- -** -** func is the interrupt handler, arg is the argument -** to the handler (usually a pointer to a softc). -** -** The maskptr argument should be &bio_imask, -** &net_imask etc. or NULL. -** -** If there is any error, a message is written, and -** the function returns with zero. -** Else it returns with a value different to zero. -** -** ----------------- -** -** The irq number is read from the configuration space. -** (Should have been set by the bios). -** -** Supports multiple handlers per irq (shared interrupts). -** -**----------------------------------------------------------------- -*/ - -typedef void pci_inthand_t(void *arg); - -struct pci_int_desc { - struct pci_int_desc * pcid_next; - pcici_t pcid_tag; - pci_inthand_t *pcid_handler; - void* pcid_argument; - unsigned * pcid_maskptr; - unsigned pcid_tally; - unsigned pcid_mask; +struct pci_lkm { + struct pci_device *dvp; + struct pci_lkm *next; }; -int pci_map_int (pcici_t tag, pci_inthand_t *func, void *arg, - unsigned *maskptr); - +u_long pci_conf_read (pcici_t tag, u_long reg); +void pci_conf_write (pcici_t tag, u_long reg, u_long data); +int pci_map_port (pcici_t tag, u_long reg, u_short* pa); +int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa); +int pci_map_int (pcici_t tag, pci_inthand_t *func, void *arg, unsigned *maskptr); int pci_unmap_int (pcici_t tag); +int pci_register_lkm (struct pci_device *dvp, int if_revision); -#endif +#endif /* PCI_COMPAT */ diff --git a/sys/pci/tek390.c b/sys/pci/tek390.c index 3d73555..3983ea2 100644 --- a/sys/pci/tek390.c +++ b/sys/pci/tek390.c @@ -1231,6 +1231,16 @@ int DC390_initAdapter( PACB pACB, ULONG io_port, UCHAR Irq, USHORT index, } +#ifdef PCI_COMPAT +static pcicfgregs *cfg; +#define DC390_EnableCfg(a,b) +#define DC390_DisableCfg(a) +#define DC390_inByte(a,reg) pci_cfgread(cfg,reg,1) +#define DC390_inWord(a,reg) pci_cfgread(cfg,reg,2) +#define DC390_inDword(a,reg) pci_cfgread(cfg,reg,4) +#define DC390_OutB(a,reg,val) pci_cfgwrite(cfg,reg,val,1) +#else + void DC390_EnableCfg( USHORT mechnum, UCHAR regval ) { @@ -1366,6 +1376,7 @@ DC390_OutB(USHORT mechnum, UCHAR regval, UCHAR bval ) splx(flags); } +#endif /PCI_COMPAT */ void DC390_EnDisableCE( UCHAR mode, USHORT mechnum, PUCHAR regval ) @@ -1527,6 +1538,9 @@ USHORT DC390_ToMech( USHORT Mechnum, pcici_t config_id ) { +#ifdef PCI_COMPAT + cfg = config_id; +#else if(Mechnum == 2) { mech2bus = config_id.cfg2.forward; /* Bus num */ @@ -1537,6 +1551,7 @@ DC390_ToMech( USHORT Mechnum, pcici_t config_id ) { mech1addr = config_id.cfg1; } +#endif /* PCI_COMPAT */ return(0); } |