pci: Add MPTable Host-PCI/PCI-PCI bridges drivers.
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Thu, 9 Jul 2009 14:06:54 +0000 (22:06 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Sat, 11 Jul 2009 02:27:17 +0000 (10:27 +0800)
- This driver overrides PCI bridge interrupt routing method.
- Nuke APIC_IO workaround in PCI configuration reading functions.

Obtained-from: FreeBSD

sys/bus/pci/i386/mptable_pci.c [new file with mode: 0644]
sys/bus/pci/i386/pci_cfgreg.c
sys/bus/pci/pci.c
sys/platform/pc32/conf/files

diff --git a/sys/bus/pci/i386/mptable_pci.c b/sys/bus/pci/i386/mptable_pci.c
new file mode 100644 (file)
index 0000000..8297b03
--- /dev/null
@@ -0,0 +1,236 @@
+/*-
+ * Copyright (c) 2003 John Baldwin <jhb@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, 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. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD @169221
+ */
+
+/*
+ * Host to PCI and PCI to PCI bridge drivers that use the MP Table to route
+ * interrupts from PCI devices to I/O APICs.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <bus/pci/pcireg.h>
+#include <bus/pci/pcivar.h>
+#include <bus/pci/pcib_private.h>
+
+#include <machine/smp.h>
+
+#include "legacyvar.h"
+#include "pci_cfgreg.h"
+
+#include "pcib_if.h"
+
+static int
+mptable_pci_route_interrupt(device_t pcib, device_t dev, int pin)
+{
+       int line, bus, slot;
+
+       bus = pci_get_bus(dev);
+       slot = pci_get_slot(dev);
+
+       line = pci_apic_irq(bus, slot, pin);
+       if (line >= 0) {
+               return line;
+       } else {
+               /* 
+                * PCI interrupts might be redirected to the
+                * ISA bus according to some MP tables.  Use the
+                * same methods as used by the ISA devices
+                * devices to find the proper IOAPIC int pin.
+                */
+               kprintf("MPTable: Try routing through ISA bus for "
+                       "bus %d slot %d INT%c\n",
+                       bus, slot, 'A' + pin - 1);
+               line = isa_apic_irq(pci_get_irq(dev));
+               if (line >= 0)
+                       return line;
+       }
+
+       kprintf("MPTable: Unable to route for bus %d slot %d INT%c\n",
+               bus, slot, 'A' + pin - 1);
+       return PCI_INVALID_IRQ;
+}
+
+/* Host to PCI bridge driver. */
+
+static int
+mptable_hostb_probe(device_t dev)
+{
+
+       if (pci_cfgregopen() == 0)
+               return (ENXIO);
+#ifdef notyet
+       if (mptable_pci_probe_table(pcib_get_bus(dev)) != 0)
+               return (ENXIO);
+#endif
+       device_set_desc(dev, "MPTable Host-PCI bridge");
+       return (0);
+}
+
+static int
+mptable_hostb_attach(device_t dev)
+{
+
+       device_add_child(dev, "pci", pcib_get_bus(dev));
+       return (bus_generic_attach(dev));
+}
+
+/* Pass MSI requests up to the nexus. */
+static int
+mptable_hostb_alloc_msi(device_t pcib, device_t dev, int count, int maxcount,
+    int *irqs)
+{
+       device_t bus;
+
+       bus = device_get_parent(pcib);
+       return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount,
+           irqs));
+}
+
+static int
+mptable_hostb_alloc_msix(device_t pcib, device_t dev, int *irq)
+{
+       device_t bus;
+
+       bus = device_get_parent(pcib);
+       return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq));
+}
+
+static int
+mptable_hostb_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr,
+    uint32_t *data)
+{
+       device_t bus;
+
+       bus = device_get_parent(pcib);
+       return (PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data));
+}
+
+static device_method_t mptable_hostb_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_probe,         mptable_hostb_probe),
+       DEVMETHOD(device_attach,        mptable_hostb_attach),
+       DEVMETHOD(device_shutdown,      bus_generic_shutdown),
+       DEVMETHOD(device_suspend,       bus_generic_suspend),
+       DEVMETHOD(device_resume,        bus_generic_resume),
+
+       /* Bus interface */
+       DEVMETHOD(bus_print_child,      bus_generic_print_child),
+       DEVMETHOD(bus_read_ivar,        legacy_pcib_read_ivar),
+       DEVMETHOD(bus_write_ivar,       legacy_pcib_write_ivar),
+       DEVMETHOD(bus_alloc_resource,   legacy_pcib_alloc_resource),
+       DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+       DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+       DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+       DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
+       DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
+
+       /* pcib interface */
+       DEVMETHOD(pcib_maxslots,        legacy_pcib_maxslots),
+       DEVMETHOD(pcib_read_config,     legacy_pcib_read_config),
+       DEVMETHOD(pcib_write_config,    legacy_pcib_write_config),
+       DEVMETHOD(pcib_route_interrupt, mptable_pci_route_interrupt),
+       DEVMETHOD(pcib_alloc_msi,       mptable_hostb_alloc_msi),
+       DEVMETHOD(pcib_release_msi,     pcib_release_msi),
+       DEVMETHOD(pcib_alloc_msix,      mptable_hostb_alloc_msix),
+       DEVMETHOD(pcib_release_msix,    pcib_release_msix),
+       DEVMETHOD(pcib_map_msi,         mptable_hostb_map_msi),
+
+       { 0, 0 }
+};
+
+static devclass_t hostb_devclass;
+
+DEFINE_CLASS_0(pcib, mptable_hostb_driver, mptable_hostb_methods, 1);
+DRIVER_MODULE(mptable_pcib, legacy, mptable_hostb_driver, hostb_devclass, 0, 0);
+
+/* PCI to PCI bridge driver. */
+
+static int
+mptable_pcib_probe(device_t dev)
+{
+       int bus;
+
+       if ((pci_get_class(dev) != PCIC_BRIDGE) ||
+           (pci_get_subclass(dev) != PCIS_BRIDGE_PCI))
+               return (ENXIO);
+       bus = pci_read_config(dev, PCIR_SECBUS_1, 1);
+       if (bus == 0)
+               return (ENXIO);
+#ifdef notyet
+       if (mptable_pci_probe_table(bus) != 0)
+               return (ENXIO);
+#endif
+       device_set_desc(dev, "MPTable PCI-PCI bridge");
+       return (-500);
+}
+
+static device_method_t mptable_pcib_pci_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_probe,         mptable_pcib_probe),
+       DEVMETHOD(device_attach,        pcib_attach),
+       DEVMETHOD(device_shutdown,      bus_generic_shutdown),
+       DEVMETHOD(device_suspend,       bus_generic_suspend),
+       DEVMETHOD(device_resume,        bus_generic_resume),
+
+       /* Bus interface */
+       DEVMETHOD(bus_print_child,      bus_generic_print_child),
+       DEVMETHOD(bus_read_ivar,        pcib_read_ivar),
+       DEVMETHOD(bus_write_ivar,       pcib_write_ivar),
+       DEVMETHOD(bus_alloc_resource,   pcib_alloc_resource),
+       DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+       DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+       DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+       DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
+       DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
+
+       /* pcib interface */
+       DEVMETHOD(pcib_maxslots,        pcib_maxslots),
+       DEVMETHOD(pcib_read_config,     pcib_read_config),
+       DEVMETHOD(pcib_write_config,    pcib_write_config),
+       DEVMETHOD(pcib_route_interrupt, mptable_pci_route_interrupt),
+       DEVMETHOD(pcib_alloc_msi,       pcib_alloc_msi),
+       DEVMETHOD(pcib_release_msi,     pcib_release_msi),
+       DEVMETHOD(pcib_alloc_msix,      pcib_alloc_msix),
+       DEVMETHOD(pcib_release_msix,    pcib_release_msix),
+       DEVMETHOD(pcib_map_msi,         pcib_map_msi),
+
+       {0, 0}
+};
+
+static devclass_t pcib_devclass;
+
+DEFINE_CLASS_0(pcib, mptable_pcib_driver, mptable_pcib_pci_methods,
+    sizeof(struct pcib_softc));
+DRIVER_MODULE(mptable_pcib, pci, mptable_pcib_driver, pcib_devclass, 0, 0);
index 4c2f1c4..2099553 100644 (file)
@@ -42,9 +42,6 @@
 #include <bus/pci/pcireg.h>
 #include "pci_cfgreg.h"
 #include <machine/pc/bios.h>
-#ifdef APIC_IO
-#include <machine/smp.h>
-#endif
 
 #include <vm/vm.h>
 #include <vm/vm_param.h>
@@ -191,48 +188,7 @@ u_int32_t
 pci_cfgregread(int bus, int slot, int func, int reg, int bytes)
 {
        uint32_t line;
-#ifdef APIC_IO
-       uint32_t pin;
-
-       /*
-        * If we are using the APIC, the contents of the intline
-        * register will probably be wrong (since they are set up for
-        * use with the PIC.  Rather than rewrite these registers
-        * (maybe that would be smarter) we trap attempts to read them
-        * and translate to our private vector numbers.
-        */
-       if ((reg == PCIR_INTLINE) && (bytes == 1)) {
 
-               pin = pcireg_cfgread(bus, slot, func, PCIR_INTPIN, 1);
-               line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1);
-
-               if (pin != 0) {
-                       int airq;
-
-                       airq = pci_apic_irq(bus, slot, pin);
-                       if (airq >= 0) {
-                               /* PCI specific entry found in MP table */
-                               if (airq != line)
-                                       undirect_pci_irq(line);
-                               return (airq);
-                       } else {
-                               /* 
-                                * PCI interrupts might be redirected to the
-                                * ISA bus according to some MP tables. Use the
-                                * same methods as used by the ISA devices
-                                * devices to find the proper IOAPIC int pin.
-                                */
-                               airq = isa_apic_irq(line);
-                               if ((airq >= 0) && (airq != line)) {
-                                       /* XXX: undirect_pci_irq() ? */
-                                       undirect_isa_irq(line);
-                                       return (airq);
-                               }
-                       }
-               }
-               return (line);
-       }
-#else
        /*
         * Some BIOS writers seem to want to ignore the spec and put
         * 0 in the intline rather than 255 to indicate none.  The rest of
@@ -242,7 +198,6 @@ pci_cfgregread(int bus, int slot, int func, int reg, int bytes)
                line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1);
                return (pci_i386_map_intline(line));
        }
-#endif /* APIC_IO */
        return (pcireg_cfgread(bus, slot, func, reg, bytes));
 }
 
index e6db4c7..7a4257f 100644 (file)
 #include <sys/sysctl.h>
 #include <sys/endian.h>
 
-#ifdef APIC_IO
-#include <machine/smp.h>
-#endif
-
 #include <vm/vm.h>
 #include <vm/pmap.h>
 #include <vm/vm_extern.h>
@@ -493,38 +489,6 @@ pci_read_device(device_t pcib, int d, int b, int s, int f, size_t size)
                cfg->intpin             = REG(PCIR_INTPIN, 1);
                cfg->intline            = REG(PCIR_INTLINE, 1);
 
-#ifdef APIC_IO
-               /*
-                * If using the APIC the intpin is probably wrong, since it
-                * is often setup by the BIOS with the PIC in mind.
-                */
-               if (cfg->intpin != 0) {
-                       int airq;
-
-                       airq = pci_apic_irq(cfg->bus, cfg->slot, cfg->intpin);
-                       if (airq >= 0) {
-                               /* PCI specific entry found in MP table */
-                               if (airq != cfg->intline) {
-                                       undirect_pci_irq(cfg->intline);
-                                       cfg->intline = airq;
-                               }
-                       } else {
-                               /* 
-                                * PCI interrupts might be redirected to the
-                                * ISA bus according to some MP tables. Use the
-                                * same methods as used by the ISA devices
-                                * devices to find the proper IOAPIC int pin.
-                                */
-                               airq = isa_apic_irq(cfg->intline);
-                               if ((airq >= 0) && (airq != cfg->intline)) {
-                                       /* XXX: undirect_pci_irq() ? */
-                                       undirect_isa_irq(cfg->intline);
-                                       cfg->intline = airq;
-                               }
-                       }
-               }
-#endif /* APIC_IO */
-
                cfg->mingnt             = REG(PCIR_MINGNT, 1);
                cfg->maxlat             = REG(PCIR_MAXLAT, 1);
 
@@ -2911,7 +2875,7 @@ pci_add_resources(device_t pcib, device_t bus, device_t dev, int force, uint32_t
        }
 
        if (cfg->intpin > 0 && PCI_INTERRUPT_VALID(cfg->intline)) {
-#ifdef __PCI_REROUTE_INTERRUPT
+#if defined(__PCI_REROUTE_INTERRUPT) || defined(APIC_IO)
                /*
                 * Try to re-route interrupts. Sometimes the BIOS or
                 * firmware may leave bogus values in these registers.
index 6cd9b1f..9576536 100644 (file)
@@ -223,6 +223,7 @@ bus/pci/i386/legacy.c                       optional        pci
 bus/pci/i386/pci_bus.c                 optional        pci
 bus/pci/i386/pci_cfgreg.c              optional        pci
 bus/pci/i386/pci_pir.c                 optional        pci
+bus/pci/i386/mptable_pci.c             optional        pci smp apic_io
 platform/pc32/isa/pmtimer.c            optional        pmtimer acpi
 # XXX drhodus
 platform/pc32/isa/prof_machdep.c       optional        profiling-routine