summaryrefslogtreecommitdiff
path: root/sys/i386/pci/pci_pir.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/i386/pci/pci_pir.c')
-rw-r--r--sys/i386/pci/pci_pir.c653
1 files changed, 190 insertions, 463 deletions
diff --git a/sys/i386/pci/pci_pir.c b/sys/i386/pci/pci_pir.c
index 31de543cea12..df8479459099 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);
}