summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorse <se@FreeBSD.org>1997-05-26 15:08:43 +0000
committerse <se@FreeBSD.org>1997-05-26 15:08:43 +0000
commitcfea77580682c68592b48cba9da572bc10e93b61 (patch)
tree23db6fa5f0b52728e0fa65fe609484e3e52cbab3
parenteba9732c9776c3bb526db98340a2a84ab9172e13 (diff)
downloadFreeBSD-src-cfea77580682c68592b48cba9da572bc10e93b61.zip
FreeBSD-src-cfea77580682c68592b48cba9da572bc10e93b61.tar.gz
Completely replace the PCI bus driver code to make it better reflect
reality. There will be a new call interface, but for now the file pci_compat.c (which is to be deleted, after all drivers are converted) provides an emulation of the old PCI bus driver functions. The only change that might be visible to drivers is, that the type pcici_t (which had been meant to be just a handle, whose exact definition should not be relied on), has been converted into a pcicfgregs* . The Tekram AMD SCSI driver bogusly relied on the definition of pcici_t and has been converted to just call the PCI drivers functions to access configuration space register, instead of inventing its own ... This code is by no means complete, but assumed to be fully operational, and brings the official code base more in line with my development code. A new generic device descriptor data type has to be agreed on. The PCI code will then use that data type to provide new functionality: 1) userconfig support 2) "wired" PCI devices 3) conflicts checking against ISA/EISA 4) maps will depend on the command register enable bits 5) PCI to Anything bridges can be defined as devices, and are probed like any "standard" PCI device. The following features are currently missing, but will be added back, soon: 1) unknown device probe message 2) suppression of "mirrored" devices caused by ancient, broken chip-sets This code relies on generic shared interrupt support just commited to kern_intr.c (plus the modifications of isa.c and isa_device.h).
-rw-r--r--sys/amd64/include/pci_cfgreg.h48
-rw-r--r--sys/amd64/pci/pci_bus.c653
-rw-r--r--sys/amd64/pci/pci_cfgreg.c653
-rw-r--r--sys/conf/files1
-rw-r--r--sys/dev/pci/pci.c2181
-rw-r--r--sys/dev/pci/pcireg.h446
-rw-r--r--sys/dev/pci/pcivar.h406
-rw-r--r--sys/i386/include/pci_cfgreg.h48
-rw-r--r--sys/i386/isa/pcibus.c653
-rw-r--r--sys/i386/isa/pcibus.h48
-rw-r--r--sys/i386/pci/pci_bus.c653
-rw-r--r--sys/i386/pci/pci_cfgreg.c653
-rw-r--r--sys/i386/pci/pci_pir.c653
-rw-r--r--sys/pci/pci.c2181
-rw-r--r--sys/pci/pci_compat.c351
-rw-r--r--sys/pci/pcireg.h446
-rw-r--r--sys/pci/pcisupport.c28
-rw-r--r--sys/pci/pcivar.h406
-rw-r--r--sys/pci/tek390.c15
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);
}
OpenPOWER on IntegriCloud