Sync PCI code with FreeBSD 7.2
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Sat, 4 Jul 2009 03:32:50 +0000 (11:32 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Wed, 8 Jul 2009 10:50:34 +0000 (18:50 +0800)
Submitted-by: Alexander Polakov <polachok@gmail.com>
40 files changed:
sys/bus/isa/isa_common.c
sys/bus/pci/amd64/pci_cfgreg.c [deleted file]
sys/bus/pci/amd64/pci_cfgreg.h [deleted file]
sys/bus/pci/amd64/pcibus.c [deleted file]
sys/bus/pci/amd64/pcibus.h [deleted file]
sys/bus/pci/dc21040reg.h
sys/bus/pci/eisa_pci.c [new file with mode: 0644]
sys/bus/pci/fixup_pci.c [new file with mode: 0644]
sys/bus/pci/hostb_pci.c [new file with mode: 0644]
sys/bus/pci/i386/legacy.c [new file with mode: 0644]
sys/bus/pci/i386/pci_bus.c [moved from sys/bus/pci/i386/pcibus.c with 51% similarity]
sys/bus/pci/i386/pci_cfgreg.c
sys/bus/pci/i386/pci_cfgreg.h
sys/bus/pci/i386/pci_pir.c [new file with mode: 0644]
sys/bus/pci/ignore_pci.c [new file with mode: 0644]
sys/bus/pci/isa_pci.c [new file with mode: 0644]
sys/bus/pci/pci.c
sys/bus/pci/pci_compat.c [deleted file]
sys/bus/pci/pci_if.m
sys/bus/pci/pci_isab.c [deleted file]
sys/bus/pci/pci_pci.c [new file with mode: 0644]
sys/bus/pci/pci_pcib.c [deleted file]
sys/bus/pci/pci_private.h
sys/bus/pci/pci_user.c [new file with mode: 0644]
sys/bus/pci/pcib_if.m
sys/bus/pci/pcib_private.h
sys/bus/pci/pcibus.h
sys/bus/pci/pcidevs [deleted file]
sys/bus/pci/pcireg.h
sys/bus/pci/pcisupport.c [deleted file]
sys/bus/pci/pcivar.h
sys/bus/pci/vga_pci.c [new file with mode: 0644]
sys/conf/files
sys/dev/pccard/cardbus/cardbus.c
sys/kern/kern_slaballoc.c
sys/platform/pc32/conf/files
sys/platform/pc32/include/legacyvar.h [new file with mode: 0644]
sys/sys/bus.h
sys/sys/malloc.h
sys/sys/pciio.h

index cc07df8..b18affd 100644 (file)
@@ -1045,3 +1045,15 @@ DRIVER_MODULE(isa, isab, isa_driver, isa_devclass, 0, 0);
 DRIVER_MODULE(isa, nexus, isa_driver, isa_devclass, 0, 0);
 #endif
 
+/*
+ * Code common to ISA bridges.
+ */
+int
+isab_attach(device_t dev)
+{
+        device_t child;
+        child = device_add_child(dev, "isa", 0);
+        if (child != NULL)
+                return (bus_generic_attach(dev));
+        return (ENXIO);
+}
diff --git a/sys/bus/pci/amd64/pci_cfgreg.c b/sys/bus/pci/amd64/pci_cfgreg.c
deleted file mode 100644 (file)
index 0502b7a..0000000
+++ /dev/null
@@ -1,852 +0,0 @@
-/*
- * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
- * Copyright (c) 2000, Michael Smith <msmith@freebsd.org>
- * Copyright (c) 2000, BSDi
- * 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.
- *
- * $FreeBSD: src/sys/i386/isa/pci_cfgreg.c,v 1.1.2.7 2001/11/28 05:47:03 imp Exp $
- * $DragonFly: src/sys/bus/pci/amd64/pci_cfgreg.c,v 1.1 2008/08/02 05:22:19 dillon Exp $
- *
- */
-
-#include <sys/param.h>         /* XXX trim includes */
-#include <sys/systm.h>
-#include <sys/bus.h>
-#include <sys/kernel.h>
-#include <sys/module.h>
-#include <sys/malloc.h>
-#include <sys/sysctl.h>
-#include <vm/vm.h>
-#include <vm/pmap.h>
-#include <machine/md_var.h>
-#include <machine/clock.h>
-#include <bus/pci/pcivar.h>
-#include <bus/pci/pcireg.h>
-#include <bus/isa/isavar.h>
-#include "pci_cfgreg.h"
-#include <machine/segments.h>
-#include <machine/pc/bios.h>
-#include <machine/smp.h>
-
-#define PRVERB(a) do {                                                 \
-       if (bootverbose)                                                \
-               kprintf a ;                                             \
-} while(0)
-
-static int pci_disable_bios_route = 0;
-SYSCTL_INT(_hw, OID_AUTO, pci_disable_bios_route, CTLFLAG_RD,
-       &pci_disable_bios_route, 0, "disable interrupt routing via PCI-BIOS");
-TUNABLE_INT("hw.pci_disable_bios_route", &pci_disable_bios_route);
-
-static int cfgmech;
-static int devmax;
-
-#if 0
-static int     pci_cfgintr_valid(struct PIR_entry *pe, int pin, int irq);
-static int     pci_cfgintr_unique(struct PIR_entry *pe, int pin);
-static int     pci_cfgintr_linked(struct PIR_entry *pe, int pin);
-static int     pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin);
-static int     pci_cfgintr_virgin(struct PIR_entry *pe, int pin);
-#endif
-
-static void    pci_print_irqmask(u_int16_t irqs);
-#if 0
-static void    pci_print_route_table(struct PIR_table *prt, int size);
-#endif
-static int     pcireg_cfgread(int bus, int slot, int func, int reg, int bytes);
-static void    pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
-static int     pcireg_cfgopen(void);
-
-static struct PIR_table        *pci_route_table;
-static int             pci_route_count;
-
-/*
- * Some BIOS writers seem to want to ignore the spec and put
- * 0 in the intline rather than 255 to indicate none. Some use
- * numbers in the range 128-254 to indicate something strange and
- * apparently undocumented anywhere. Assume these are completely bogus
- * and map them to 255, which means "none".
- */
-static int
-pci_map_intline(int line)
-{
-       if (line == 0 || line >= 128)
-               return (PCI_INVALID_IRQ);
-       return (line);
-}
-
-#if 0
-
-static u_int16_t
-pcibios_get_version(void)
-{
-       struct bios_regs args;
-
-       if (PCIbios.ventry == 0) {
-               PRVERB(("pcibios: No call entry point\n"));
-               return (0);
-       }
-       args.eax = PCIBIOS_BIOS_PRESENT;
-       if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) {
-               PRVERB(("pcibios: BIOS_PRESENT call failed\n"));
-               return (0);
-       }
-       if (args.edx != 0x20494350) {
-               PRVERB(("pcibios: BIOS_PRESENT didn't return 'PCI ' in edx\n"));
-               return (0);
-       }
-       return (args.ebx & 0xffff);
-}
-
-#endif
-
-/* 
- * Initialise access to PCI configuration space 
- */
-int
-pci_cfgregopen(void)
-{
-       static int              opened = 0;
-       u_long                  sigaddr;
-       static struct PIR_table *pt;
-       u_int16_t               v;
-       u_int8_t                ck, *cv;
-       int                     i;
-
-       if (opened)
-               return (1);
-
-       if (pcireg_cfgopen() == 0)
-               return (0);
-
-#if 0
-       v = pcibios_get_version();
-       if (v > 0)
-               kprintf("pcibios: BIOS version %x.%02x\n", (v & 0xff00) >> 8,
-                      v & 0xff);
-       /*
-        * Look for the interrupt routing table.
-        *
-        * We use PCI BIOS's PIR table if it's available $PIR is the
-        * standard way to do this.  Sadly some machines are not
-        * standards conforming and have _PIR instead. We shrug and cope
-        * by looking for both.
-        */
-       if (pcibios_get_version() >= 0x0210 && pt == NULL) {
-               sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0);
-               if (sigaddr == 0)
-                       sigaddr = bios_sigsearch(0, "_PIR", 4, 16, 0);
-               if (sigaddr != 0) {
-                       pt = (struct PIR_table *)(uintptr_t)
-                            BIOS_PADDRTOVADDR(sigaddr);
-                       for (cv = (u_int8_t *)pt, ck = 0, i = 0;
-                            i < (pt->pt_header.ph_length); i++)
-                               ck += cv[i];
-                       if (ck == 0 && pt->pt_header.ph_length >
-                           sizeof(struct PIR_header)) {
-                               pci_route_table = pt;
-                               pci_route_count = (pt->pt_header.ph_length -
-                                   sizeof(struct PIR_header)) /
-                                   sizeof(struct PIR_entry);
-                               kprintf("Using $PIR table, %d entries at %p\n",
-                                      pci_route_count, pci_route_table);
-                               if (bootverbose)
-                                       pci_print_route_table(pci_route_table,
-                                           pci_route_count);
-                       }
-               }
-       }
-#endif
-       opened = 1;
-       return (1);     
-}
-
-/* 
- * Read configuration space register
- */
-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
-        * the code uses 255 as an invalid IRQ.
-        */
-       if (reg == PCIR_INTLINE && bytes == 1) {
-               line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1);
-               return pci_map_intline(line);
-       }
-#endif /* APIC_IO */
-       return (pcireg_cfgread(bus, slot, func, reg, bytes));
-}
-
-/* 
- * Write configuration space register 
- */
-void
-pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes)
-{
-       pcireg_cfgwrite(bus, slot, func, reg, data, bytes);
-}
-
-int
-pci_cfgread(pcicfgregs *cfg, int reg, int bytes)
-{
-       return (pci_cfgregread(cfg->bus, cfg->slot, cfg->func, reg, bytes));
-}
-
-void
-pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes)
-{
-       pci_cfgregwrite(cfg->bus, cfg->slot, cfg->func, reg, data, bytes);
-}
-
-/*
- * XXX
- */
-int
-pci_cfgintr(int bus, int device, int pin, int oldirq)
-{
-       return (PCI_INVALID_IRQ);
-}
-
-#if 0
-
-/*
- * Route a PCI interrupt
- */
-int
-pci_cfgintr(int bus, int device, int pin, int oldirq)
-{
-       struct PIR_entry        *pe;
-       int                     i, irq;
-       struct bios_regs        args;
-       u_int16_t               v;
-
-       int already = 0;
-       int errok = 0;
-    
-       v = pcibios_get_version();
-       if (v < 0x0210) {
-               PRVERB((
-                 "pci_cfgintr: BIOS %x.%02x doesn't support interrupt routing\n",
-                 (v & 0xff00) >> 8, v & 0xff));
-               return (PCI_INVALID_IRQ);
-       }
-       if ((bus < 0) || (bus > 255) || (device < 0) || (device > 255) ||
-           (pin < 1) || (pin > 4))
-               return (PCI_INVALID_IRQ);
-
-       /*
-        * Scan the entry table for a contender
-        */
-       for (i = 0, pe = &pci_route_table->pt_entry[0]; i < pci_route_count;
-            i++, pe++) {
-               if ((bus != pe->pe_bus) || (device != pe->pe_device))
-                       continue;
-
-               /*
-                * A link of 0 means that this intpin is not connected to
-                * any other device's interrupt pins and is not connected to
-                * any of the Interrupt Router's interrupt pins, so we can't
-                * route it.
-                */
-               if (pe->pe_intpin[pin - 1].link == 0)
-                       continue;
-
-               if (pci_cfgintr_valid(pe, pin, oldirq)) {
-                       kprintf("pci_cfgintr: %d:%d INT%c BIOS irq %d\n", bus,
-                              device, 'A' + pin - 1, oldirq);
-                       return (oldirq);
-               }
-
-               /*
-                * We try to find a linked interrupt, then we look to see
-                * if the interrupt is uniquely routed, then we look for
-                * a virgin interrupt. The virgin interrupt should return
-                * an interrupt we can route, but if that fails, maybe we
-                * should try harder to route a different interrupt.
-                * However, experience has shown that that's rarely the
-                * failure mode we see.
-                */
-               irq = pci_cfgintr_linked(pe, pin);
-               if (irq != PCI_INVALID_IRQ)
-                       already = 1;
-               if (irq == PCI_INVALID_IRQ) {
-                       irq = pci_cfgintr_unique(pe, pin);
-                       if (irq != PCI_INVALID_IRQ)
-                               errok = 1;
-               }
-               if (irq == PCI_INVALID_IRQ)
-                       irq = pci_cfgintr_virgin(pe, pin);
-
-               if (irq == PCI_INVALID_IRQ)
-                       break;
-
-               if (pci_disable_bios_route != 0)
-                       break;
-               /*
-                * Ask the BIOS to route the interrupt. If we picked an
-                * interrupt that failed, we should really try other
-                * choices that the BIOS offers us.
-                *
-                * For uniquely routed interrupts, we need to try
-                * to route them on some machines. Yet other machines
-                * fail to route, so we have to pretend that in that
-                * case it worked.  Isn't PC hardware fun?
-                *
-                * NOTE: if we want to whack hardware to do this, then
-                * I think the right way to do that would be to have
-                * bridge drivers that do this. I'm not sure that the
-                * $PIR table would be valid for those interrupt
-                * routers.
-                */
-               args.eax = PCIBIOS_ROUTE_INTERRUPT;
-               args.ebx = (bus << 8) | (device << 3);
-               /* pin value is 0xa - 0xd */
-               args.ecx = (irq << 8) | (0xa + pin -1);
-               if (!already &&
-                   bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)) &&
-                   !errok) {
-                       PRVERB(("pci_cfgintr: ROUTE_INTERRUPT failed.\n"));
-                       return (PCI_INVALID_IRQ);
-               }
-               kprintf("pci_cfgintr: %d:%d INT%c routed to irq %d\n", bus,
-                      device, 'A' + pin - 1, irq);
-               return(irq);
-       }
-
-       PRVERB(("pci_cfgintr: can't route an interrupt to %d:%d INT%c oldirq=%d\n", bus,
-              device, 'A' + pin - 1, oldirq));
-       return (PCI_INVALID_IRQ);
-}
-
-/*
- * Check to see if an existing IRQ setting is valid.
- */
-static int
-pci_cfgintr_valid(struct PIR_entry *pe, int pin, int irq)
-{
-       uint32_t irqmask;
-
-       if (!PCI_INTERRUPT_VALID(irq))
-               return (0);
-       irqmask = pe->pe_intpin[pin - 1].irqs;
-       if (irqmask & (1 << irq)) {
-               PRVERB(("pci_cfgintr_valid: BIOS irq %d is valid\n", irq));
-               return (1);
-       }
-       return (0);
-}
-
-/*
- * Look to see if the routing table claims this pin is uniquely routed.
- */
-static int
-pci_cfgintr_unique(struct PIR_entry *pe, int pin)
-{
-       int             irq;
-       uint32_t        irqmask;
-
-       irqmask = pe->pe_intpin[pin - 1].irqs;
-       if(irqmask != 0 && powerof2(irqmask)) {
-               irq = ffs(irqmask) - 1;
-               PRVERB(("pci_cfgintr_unique: hard-routed to irq %d\n", irq));
-               return (irq);
-       }
-       return (PCI_INVALID_IRQ);
-}
-
-/*
- * Look for another device which shares the same link byte and
- * already has a unique IRQ, or which has had one routed already.
- */
-static int
-pci_cfgintr_linked(struct PIR_entry *pe, int pin)
-{
-       struct PIR_entry        *oe;
-       struct PIR_intpin       *pi;
-       int                     i, j, irq;
-
-       /*
-        * Scan table slots.
-        */
-       for (i = 0, oe = &pci_route_table->pt_entry[0]; i < pci_route_count;
-            i++, oe++) {
-               /* scan interrupt pins */
-               for (j = 0, pi = &oe->pe_intpin[0]; j < 4; j++, pi++) {
-
-                       /* don't look at the entry we're trying to match */
-                       if ((pe == oe) && (i == (pin - 1)))
-                               continue;
-                       /* compare link bytes */
-                       if (pi->link != pe->pe_intpin[pin - 1].link)
-                               continue;
-                       /* link destination mapped to a unique interrupt? */
-                       if (pi->irqs != 0 && powerof2(pi->irqs)) {
-                               irq = ffs(pi->irqs) - 1;
-                               PRVERB(("pci_cfgintr_linked: linked (%x) to hard-routed irq %d\n",
-                                      pi->link, irq));
-                               return(irq);
-                       } 
-
-                       /*
-                        * look for the real PCI device that matches this
-                        * table entry
-                        */
-                       irq = pci_cfgintr_search(pe, oe->pe_bus, oe->pe_device,
-                                                j + 1, pin);
-                       if (irq != PCI_INVALID_IRQ)
-                               return (irq);
-               }
-       }
-       return (PCI_INVALID_IRQ);
-}
-
-/*
- * Scan for the real PCI device at (bus)/(device) using intpin (matchpin) and
- * see if it has already been assigned an interrupt.
- */
-static int
-pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin)
-{
-       devclass_t              pci_devclass;
-       device_t                *pci_devices;
-       int                     pci_count;
-       device_t                *pci_children;
-       int                     pci_childcount;
-       device_t                *busp, *childp;
-       int                     i, j, irq;
-
-       /*
-        * Find all the PCI busses.
-        */
-       pci_count = 0;
-       if ((pci_devclass = devclass_find("pci")) != NULL)
-               devclass_get_devices(pci_devclass, &pci_devices, &pci_count);
-
-       /*
-        * Scan all the PCI busses/devices looking for this one.
-        */
-       irq = PCI_INVALID_IRQ;
-       for (i = 0, busp = pci_devices; (i < pci_count) && (irq == PCI_INVALID_IRQ);
-            i++, busp++) {
-               pci_childcount = 0;
-               device_get_children(*busp, &pci_children, &pci_childcount);
-               
-               for (j = 0, childp = pci_children; j < pci_childcount; j++,
-                    childp++) {
-                       if ((pci_get_bus(*childp) == bus) &&
-                           (pci_get_slot(*childp) == device) &&
-                           (pci_get_intpin(*childp) == matchpin)) {
-                               irq = pci_map_intline(pci_get_irq(*childp));
-                               if (irq != PCI_INVALID_IRQ)
-                                       PRVERB(("pci_cfgintr_search: linked (%x) to configured irq %d at %d:%d:%d\n",
-                                           pe->pe_intpin[pin - 1].link, irq,
-                                           pci_get_bus(*childp),
-                                           pci_get_slot(*childp),
-                                           pci_get_function(*childp)));
-                               break;
-                       }
-               }
-               if (pci_children != NULL)
-                       kfree(pci_children, M_TEMP);
-       }
-       if (pci_devices != NULL)
-               kfree(pci_devices, M_TEMP);
-       return (irq);
-}
-
-/*
- * Pick a suitable IRQ from those listed as routable to this device.
- */
-static int
-pci_cfgintr_virgin(struct PIR_entry *pe, int pin)
-{
-       int irq, ibit;
-    
-       /*
-        * first scan the set of PCI-only interrupts and see if any of these
-        * are routable
-        */
-       for (irq = 0; irq < 16; irq++) {
-               ibit = (1 << irq);
-
-               /* can we use this interrupt? */
-               if ((pci_route_table->pt_header.ph_pci_irqs & ibit) &&
-                   (pe->pe_intpin[pin - 1].irqs & ibit)) {
-                       PRVERB(("pci_cfgintr_virgin: using routable PCI-only interrupt %d\n", irq));
-                       return (irq);
-               }
-       }
-    
-       /* life is tough, so just pick an interrupt */
-       for (irq = 0; irq < 16; irq++) {
-               ibit = (1 << irq);
-    
-               if (pe->pe_intpin[pin - 1].irqs & ibit) {
-                       PRVERB(("pci_cfgintr_virgin: using routable interrupt %d\n", irq));
-                       return (irq);
-               }
-       }
-       return (PCI_INVALID_IRQ);
-}
-
-static void
-pci_print_irqmask(u_int16_t irqs)
-{
-       int i, first;
-
-       if (irqs == 0) {
-               kprintf("none");
-               return;
-       }
-       first = 1;
-       for (i = 0; i < 16; i++, irqs >>= 1)
-               if (irqs & 1) {
-                       if (!first)
-                               kprintf(" ");
-                       else
-                               first = 0;
-                       kprintf("%d", i);
-               }
-}
-
-/*
- * Dump the contents of a PCI BIOS Interrupt Routing Table to the console.
- */
-static void
-pci_print_route_table(struct PIR_table *ptr, int size)
-{
-       struct PIR_entry *entry;
-       struct PIR_intpin *intpin;
-       int i, pin;
-
-       kprintf("PCI-Only Interrupts: ");
-       pci_print_irqmask(ptr->pt_header.ph_pci_irqs);
-       kprintf("\nLocation  Bus Device Pin  Link  IRQs\n");
-       entry = &ptr->pt_entry[0];
-       for (i = 0; i < size; i++, entry++) {
-               intpin = &entry->pe_intpin[0];
-               for (pin = 0; pin < 4; pin++, intpin++)
-                       if (intpin->link != 0) {
-                               if (entry->pe_slot == 0)
-                                       kprintf("embedded ");
-                               else
-                                       kprintf("slot %-3d ", entry->pe_slot);
-                               kprintf(" %3d  %3d    %c   0x%02x  ",
-                                      entry->pe_bus, entry->pe_device,
-                                      'A' + pin, intpin->link);
-                               pci_print_irqmask(intpin->irqs);
-                               kprintf("\n");
-                       }
-       }
-}
-
-/*
- * See if any interrupts for a given PCI bus are routed in the PIR.  Don't
- * even bother looking if the BIOS doesn't support routing anyways.
- */
-int
-pci_probe_route_table(int bus)
-{
-       int i;
-       u_int16_t v;
-
-       v = pcibios_get_version();
-       if (v < 0x0210)
-               return (0);
-       for (i = 0; i < pci_route_count; i++)
-               if (pci_route_table->pt_entry[i].pe_bus == bus)
-                       return (1);
-       return (0);
-}
-
-#endif
-
-/* 
- * Configuration space access using direct register operations
- */
-
-/* enable configuration space accesses and return data port address */
-static int
-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, (1 << 31)
-                            | (bus << 16) | (slot << 11) 
-                            | (func << 8) | (reg & ~0x03));
-                       dataport = CONF1_DATA_PORT + (reg & 0x03);
-                       break;
-               case 2:
-                       outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
-                       outb(CONF2_FORWARD_PORT, bus);
-                       dataport = 0xc000 | (slot << 8) | reg;
-                       break;
-               }
-       }
-       return (dataport);
-}
-
-/* disable configuration space accesses */
-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;
-       }
-}
-
-static int
-pcireg_cfgread(int bus, int slot, int func, int reg, int bytes)
-{
-       int data = -1;
-       int port;
-
-       port = pci_cfgenable(bus, slot, 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);
-}
-
-static void
-pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
-{
-       int port;
-
-       port = pci_cfgenable(bus, slot, 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();
-       }
-}
-
-/* check whether the configuration mechanism has been correctly identified */
-static int
-pci_cfgcheck(int maxdev)
-{
-       uint32_t id, class;
-       uint8_t header;
-       uint8_t device;
-       int port;
-
-       if (bootverbose) 
-               kprintf("pci_cfgcheck:\tdevice ");
-
-       for (device = 0; device < maxdev; device++) {
-               if (bootverbose) 
-                       kprintf("%d ", device);
-
-               port = pci_cfgenable(0, device, 0, 0, 4);
-               id = inl(port);
-               if (id == 0 || id == 0xffffffff)
-                       continue;
-
-               port = pci_cfgenable(0, device, 0, 8, 4);
-               class = inl(port) >> 8;
-               if (bootverbose)
-                       kprintf("[class=%06x] ", class);
-               if (class == 0 || (class & 0xf870ff) != 0)
-                       continue;
-
-               port = pci_cfgenable(0, device, 0, 14, 1);
-               header = inb(port);
-               if (bootverbose)
-                       kprintf("[hdr=%02x] ", header);
-               if ((header & 0x7e) != 0)
-                       continue;
-
-               if (bootverbose)
-                       kprintf("is there (id=%08x)\n", id);
-
-               pci_cfgdisable();
-               return (1);
-       }
-       if (bootverbose) 
-               kprintf("-- nothing found\n");
-
-       pci_cfgdisable();
-       return (0);
-}
-
-static int
-pcireg_cfgopen(void)
-{
-       uint32_t mode1res,oldval1;
-       uint8_t mode2res,oldval2;
-
-       oldval1 = inl(CONF1_ADDR_PORT);
-
-       if (bootverbose) {
-               kprintf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08x\n",
-                      oldval1);
-       }
-
-       if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
-
-               cfgmech = 1;
-               devmax = 32;
-
-               outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
-               DELAY(1);
-               mode1res = inl(CONF1_ADDR_PORT);
-               outl(CONF1_ADDR_PORT, oldval1);
-
-               if (bootverbose)
-                       kprintf("pci_open(1a):\tmode1res=0x%08x (0x%08lx)\n", 
-                              mode1res, CONF1_ENABLE_CHK);
-
-               if (mode1res) {
-                       if (pci_cfgcheck(32)) 
-                               return (cfgmech);
-               }
-
-               outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
-               mode1res = inl(CONF1_ADDR_PORT);
-               outl(CONF1_ADDR_PORT, oldval1);
-
-               if (bootverbose)
-                       kprintf("pci_open(1b):\tmode1res=0x%08x (0x%08lx)\n", 
-                              mode1res, CONF1_ENABLE_CHK1);
-
-               if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
-                       if (pci_cfgcheck(32)) 
-                               return (cfgmech);
-               }
-       }
-
-       oldval2 = inb(CONF2_ENABLE_PORT);
-
-       if (bootverbose) {
-               kprintf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
-                      oldval2);
-       }
-
-       if ((oldval2 & 0xf0) == 0) {
-
-               cfgmech = 2;
-               devmax = 16;
-
-               outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
-               mode2res = inb(CONF2_ENABLE_PORT);
-               outb(CONF2_ENABLE_PORT, oldval2);
-
-               if (bootverbose)
-                       kprintf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 
-                              mode2res, CONF2_ENABLE_CHK);
-
-               if (mode2res == CONF2_ENABLE_RES) {
-                       if (bootverbose)
-                               kprintf("pci_open(2a):\tnow trying mechanism 2\n");
-
-                       if (pci_cfgcheck(16)) 
-                               return (cfgmech);
-               }
-       }
-
-       cfgmech = 0;
-       devmax = 0;
-       return (cfgmech);
-}
diff --git a/sys/bus/pci/amd64/pci_cfgreg.h b/sys/bus/pci/amd64/pci_cfgreg.h
deleted file mode 100644 (file)
index 3fe6b44..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.
- *
- * $FreeBSD: src/sys/i386/include/pci_cfgreg.h,v 1.4.2.1 2001/07/28 05:55:07 imp Exp $
- * $DragonFly: src/sys/bus/pci/amd64/pci_cfgreg.h,v 1.1 2008/08/02 05:22:19 dillon Exp $
- *
- */
-
-#ifndef _MACHINE_PCI_CFGREG_H_
-#define _MACHINE_PCI_CFGREG_H_
-
-#define CONF1_ADDR_PORT    0x0cf8
-#define CONF1_DATA_PORT    0x0cfc
-
-#define CONF1_ENABLE       0x80000000ul
-#define CONF1_ENABLE_CHK   0x80000000ul
-#define CONF1_ENABLE_MSK   0x7f000000ul
-#define CONF1_ENABLE_CHK1  0xff000001ul
-#define CONF1_ENABLE_MSK1  0x80000001ul
-#define CONF1_ENABLE_RES1  0x80000000ul
-
-#define CONF2_ENABLE_PORT  0x0cf8
-#define CONF2_FORWARD_PORT 0x0cfa
-
-#define CONF2_ENABLE_CHK   0x0e
-#define CONF2_ENABLE_RES   0x0e
-
-int            pci_cfgregopen(void);
-u_int32_t      pci_cfgregread(int bus, int slot, int func, int reg, int bytes);
-void           pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes);
-int            pci_cfgintr(int bus, int device, int pin, int oldirq);
-int            pci_probe_route_table(int bus);
-
-#define PCI_INVALID_IRQ                255
-#define PCI_INTERRUPT_VALID(x) ((x) != PCI_INVALID_IRQ)
-
-#endif
diff --git a/sys/bus/pci/amd64/pcibus.c b/sys/bus/pci/amd64/pcibus.c
deleted file mode 100644 (file)
index 9ffc9d9..0000000
+++ /dev/null
@@ -1,721 +0,0 @@
-/*
- * 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.
- *
- * $FreeBSD: src/sys/i386/isa/pcibus.c,v 1.57.2.12 2003/08/07 06:19:26 imp Exp $
- * $DragonFly: src/sys/bus/pci/amd64/pcibus.c,v 1.2 2008/09/05 10:39:36 hasso Exp $
- *
- */
-
-#include "opt_pci.h"
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/bus.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/sysctl.h>
-
-#include <bus/pci/pcivar.h>
-#include <bus/pci/pcireg.h>
-#include "pcibus.h"
-#include <bus/isa/isavar.h>
-#include "pci_cfgreg.h"
-#include <machine/md_var.h>
-#include <machine/nexusvar.h>
-
-#include "pcib_if.h"
-
-static u_int32_t nexus_pcib_read_config(device_t, int, int, int, int, int);
-
-/*
- * Figure out if a PCI entity is a host bridge, return its name or NULL.
- */
-static const char *
-nexus_legacypci_is_host_bridge(int bus, int slot, int func,
-                         u_int32_t id, u_int8_t class, u_int8_t subclass,
-                         u_int8_t *busnum)
-{
-       const char *s = NULL;
-       static u_int8_t pxb[4]; /* hack for 450nx */
-
-       *busnum = 0;
-
-       switch (id) {
-       case 0x12258086:
-               s = "Intel 824?? host to PCI bridge";
-               /* XXX This is a guess */
-               /* *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x41, 1); */
-               *busnum = bus;
-               break;
-       case 0x71208086:
-               s = "Intel 82810 (i810 GMCH) Host To Hub bridge";
-               break;
-       case 0x71228086:
-               s = "Intel 82810-DC100 (i810-DC100 GMCH) Host To Hub bridge";
-               break;
-       case 0x71248086:
-               s = "Intel 82810E (i810E GMCH) Host To Hub bridge";
-               break;
-       case 0x71808086:
-               s = "Intel 82443LX (440 LX) host to PCI bridge";
-               break;
-       case 0x71908086:
-               s = "Intel 82443BX (440 BX) host to PCI bridge";
-               break;
-       case 0x71928086:
-               s = "Intel 82443BX host to PCI bridge (AGP disabled)";
-               break;
-       case 0x71948086:
-               s = "Intel 82443MX host to PCI bridge";
-               break;
-       case 0x71a08086:
-               s = "Intel 82443GX host to PCI bridge";
-               break;
-       case 0x71a18086:
-               s = "Intel 82443GX host to AGP bridge";
-               break;
-       case 0x71a28086:
-               s = "Intel 82443GX host to PCI bridge (AGP disabled)";
-               break;
-       case 0x84c48086:
-               s = "Intel 82454KX/GX (Orion) host to PCI bridge";
-               *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x4a, 1);
-               break;
-       case 0x84ca8086:
-               /*
-                * For the 450nx chipset, there is a whole bundle of
-                * things pretending to be host bridges. The MIOC will 
-                * be seen first and isn't really a pci bridge (the
-                * actual busses are attached to the PXB's). We need to 
-                * read the registers of the MIOC to figure out the
-                * bus numbers for the PXB channels.
-                *
-                * Since the MIOC doesn't have a pci bus attached, we
-                * pretend it wasn't there.
-                */
-               pxb[0] = nexus_pcib_read_config(0, bus, slot, func,
-                                               0xd0, 1); /* BUSNO[0] */
-               pxb[1] = nexus_pcib_read_config(0, bus, slot, func,
-                                               0xd1, 1) + 1;   /* SUBA[0]+1 */
-               pxb[2] = nexus_pcib_read_config(0, bus, slot, func,
-                                               0xd3, 1); /* BUSNO[1] */
-               pxb[3] = nexus_pcib_read_config(0, bus, slot, func,
-                                               0xd4, 1) + 1;   /* SUBA[1]+1 */
-               return NULL;
-       case 0x84cb8086:
-               switch (slot) {
-               case 0x12:
-                       s = "Intel 82454NX PXB#0, Bus#A";
-                       *busnum = pxb[0];
-                       break;
-               case 0x13:
-                       s = "Intel 82454NX PXB#0, Bus#B";
-                       *busnum = pxb[1];
-                       break;
-               case 0x14:
-                       s = "Intel 82454NX PXB#1, Bus#A";
-                       *busnum = pxb[2];
-                       break;
-               case 0x15:
-                       s = "Intel 82454NX PXB#1, Bus#B";
-                       *busnum = pxb[3];
-                       break;
-               }
-               break;
-       case 0x1A308086:
-               s = "Intel 82845 Host to PCI bridge";
-               break;
-
-               /* AMD -- vendor 0x1022 */
-       case 0x30001022:
-               s = "AMD Elan SC520 host to PCI bridge";
-#ifdef CPU_ELAN
-               init_AMD_Elan_sc520();
-#else
-               kprintf("*** WARNING: kernel option CPU_ELAN missing");
-               kprintf("-- timekeeping may be wrong\n");
-#endif
-               break;
-       case 0x70061022:
-               s = "AMD-751 host to PCI bridge";
-               break;
-       case 0x700e1022:
-               s = "AMD-761 host to PCI bridge";
-               break;
-
-               /* SiS -- vendor 0x1039 */
-       case 0x04961039:
-               s = "SiS 85c496";
-               break;
-       case 0x04061039:
-               s = "SiS 85c501";
-               break;
-       case 0x06011039:
-               s = "SiS 85c601";
-               break;
-       case 0x55911039:
-               s = "SiS 5591 host to PCI bridge";
-               break;
-       case 0x00011039:
-               s = "SiS 5591 host to AGP bridge";
-               break;
-
-               /* VLSI -- vendor 0x1004 */
-       case 0x00051004:
-               s = "VLSI 82C592 Host to PCI bridge";
-               break;
-
-               /* XXX Here is MVP3, I got the datasheet but NO M/B to test it  */
-               /* totally. Please let me know if anything wrong.            -F */
-               /* XXX need info on the MVP3 -- any takers? */
-       case 0x05981106:
-               s = "VIA 82C598MVP (Apollo MVP3) host bridge";
-               break;
-
-               /* AcerLabs -- vendor 0x10b9 */
-               /* Funny : The datasheet told me vendor id is "10b8",sub-vendor */
-               /* id is '10b9" but the register always shows "10b9". -Foxfair  */
-       case 0x154110b9:
-               s = "AcerLabs M1541 (Aladdin-V) PCI host bridge";
-               break;
-
-               /* OPTi -- vendor 0x1045 */
-       case 0xc7011045:
-               s = "OPTi 82C700 host to PCI bridge";
-               break;
-       case 0xc8221045:
-               s = "OPTi 82C822 host to PCI Bridge";
-               break;
-
-               /* ServerWorks -- vendor 0x1166 */
-       case 0x00051166:
-               s = "ServerWorks NB6536 2.0HE host to PCI bridge";
-               *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1);
-               break;
-       
-       case 0x00061166:
-               /* FALLTHROUGH */
-       case 0x00081166:
-               /* FALLTHROUGH */
-       case 0x02011166:
-               /* FALLTHROUGH */
-       case 0x010f1014: /* IBM re-badged ServerWorks chipset */
-               /* FALLTHROUGH */
-               s = "ServerWorks host to PCI bridge";
-               *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1);
-               break;
-
-       case 0x00091166:
-               s = "ServerWorks NB6635 3.0LE host to PCI bridge";
-               *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1);
-               break;
-
-       case 0x00101166:
-               s = "ServerWorks CIOB30 host to PCI bridge";
-               *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1);
-               break;
-
-       case 0x00111166:
-               /* FALLTHROUGH */
-       case 0x03021014: /* IBM re-badged ServerWorks chipset */
-               s = "ServerWorks CMIC-HE host to PCI-X bridge";
-               *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1);
-               break;
-
-               /* XXX unknown chipset, but working */
-       case 0x00171166:
-               /* FALLTHROUGH */
-       case 0x01011166:
-               s = "ServerWorks host to PCI bridge(unknown chipset)";
-               *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1);
-               break;
-
-               /* Integrated Micro Solutions -- vendor 0x10e0 */
-       case 0x884910e0:
-               s = "Integrated Micro Solutions VL Bridge";
-               break;
-
-       default:
-               if (class == PCIC_BRIDGE && subclass == PCIS_BRIDGE_HOST)
-                       s = "Host to PCI bridge";
-               break;
-       }
-
-       return s;
-}
-
-/*
- * Identify the existance of the first pci bus and install a child to
- * nexus if we find it.  Use an order of 1 so it gets probed after
- * any ACPI device installed under nexus.  To avoid boot-time confusion,
- * we do not install any 'pcib' devices at this time.
- *
- * The identify method coupled with the driver spec of the same name
- * automatically installs it under the nexus.
- */
-static int
-nexus_legacypci_identify(driver_t *driver, device_t parent)
-{
-       /*
-        * Basically a static device, there's no point reinstalling it
-        * on rescan.
-        */
-       if (device_get_state(parent) == DS_ATTACHED)
-               return (0);
-       if (device_get_state(parent) == DS_INPROGRESS)
-               return (0);
-
-       if (pci_cfgregopen() == 0)
-               return (ENXIO);
-
-       BUS_ADD_CHILD(parent, parent, 100, "legacypci", 0);
-       return (0);
-}
-
-/*
- * Scan the first pci bus for host-pci bridges and add pcib instances
- * to the nexus for each bridge.
- */
-static int
-nexus_legacypci_probe(device_t dev)
-{
-       int bus, slot, func;
-       u_int8_t  hdrtype;
-       int found = 0;
-       int pcifunchigh;
-       int found824xx = 0;
-       device_t child;
-
-       /*
-        * Do not install any pci busses ('pcib' devices) if the PCI
-        * subsystem has already been claimed by someone else.
-        */
-       if (pcib_owner != NULL) {
-               device_printf(dev, "PCI subsystem owned by %s, skipping scan\n",
-                             pcib_owner);
-               return (ENXIO);
-       }
-       pcib_owner = "legacypci";
-
-       if (pci_cfgregopen() == 0)
-               return (ENXIO);
-
-       /*
-        * Scan away!
-        */
-       bus = 0;
- retry:
-       for (slot = 0; slot <= PCI_SLOTMAX; slot++) {
-               func = 0;
-               hdrtype = nexus_pcib_read_config(0, bus, slot, func,
-                                                PCIR_HDRTYPE, 1);
-               if ((hdrtype & ~PCIM_MFDEV) > 2)
-                       continue;
-               if (hdrtype & PCIM_MFDEV)
-                       pcifunchigh = 7;
-               else
-                       pcifunchigh = 0;
-               for (func = 0; func <= pcifunchigh; func++) {
-                       /*
-                        * Read the IDs and class from the device.
-                        */
-                       u_int32_t id;
-                       u_int8_t class, subclass, busnum;
-                       const char *s;
-                       device_t *devs;
-                       int ndevs, i;
-
-                       id = nexus_pcib_read_config(0, bus, slot, func,
-                                                   PCIR_DEVVENDOR, 4);
-                       if (id == -1)
-                               continue;
-                       class = nexus_pcib_read_config(0, bus, slot, func,
-                                                      PCIR_CLASS, 1);
-                       subclass = nexus_pcib_read_config(0, bus, slot, func,
-                                                         PCIR_SUBCLASS, 1);
-
-                       s = nexus_legacypci_is_host_bridge(bus, slot, func,
-                                                     id, class, subclass,
-                                                     &busnum);
-                       if (s == NULL)
-                               continue;
-
-                       /*
-                        * Check to see if the physical bus has already
-                        * been seen. Eg: hybrid 32 and 64 bit host
-                        * bridges to the same logical bus.
-                        */
-                       if (device_get_children(dev, &devs, &ndevs) == 0) {
-                               for (i = 0; s != NULL && i < ndevs; i++) {
-                                       if (strcmp(device_get_name(devs[i]),
-                                           "pcib") != 0)
-                                               continue;
-                                       if (nexus_get_pcibus(devs[i]) == busnum)
-                                               s = NULL;
-                               }
-                               kfree(devs, M_TEMP);
-                       }
-
-                       if (s == NULL)
-                               continue;
-                       /*
-                        * Add at priority 100+busnum to keep the scanning
-                        * order sane in the boot dmesg output.
-                        */
-                       child = BUS_ADD_CHILD(dev, dev, 100 + busnum, 
-                                             "pcib", busnum);
-                       device_set_desc(child, s);
-                       nexus_set_pcibus(child, busnum);
-
-                       found = 1;
-                       if (id == 0x12258086)
-                               found824xx = 1;
-               }
-       }
-       if (found824xx && bus == 0) {
-               bus++;
-               goto retry;
-       }
-
-#if 0
-       /*
-        * Now that we have installed the main PCI bridges, go
-        * probe and attach each one.
-        */
-       bus_generic_attach(dev);
-#endif
-
-       /*
-        * Make sure we add at least one bridge since some old
-        * hardware doesn't actually have a host-pci bridge device.
-        * Note that pci_cfgregopen() thinks we have PCI devices..
-        */
-       if (!found) {
-               if (bootverbose) {
-                       kprintf("nexus_pcib_identify: no bridge found, "
-                              "adding pcib0 anyway\n");
-               }
-               child = BUS_ADD_CHILD(dev, dev, 100, "pcib", 0);
-               nexus_set_pcibus(child, 0);
-       }
-       return (0);
-}
-
-static int
-nexus_legacypci_attach(device_t dev)
-{
-       bus_generic_attach(dev);
-       return (0);
-}
-
-#ifdef PCI_MAP_FIXUP
-
-SYSCTL_DECL(_hw_pci);
-
-static unsigned long legacy_host_mem_start = 0xffffffff80000000;
-/* XXX need TUNABLE_ULONG? */
-TUNABLE_INT("hw.pci.host_mem_start", (int *)&legacy_host_mem_start);
-SYSCTL_ULONG(_hw_pci, OID_AUTO, host_mem_start, CTLFLAG_RD,
-            &legacy_host_mem_start, 0x80000000,
-            "Limit the host bridge memory to being above this address.  "
-            "Must be\n"
-            "set at boot via hw.pci.host_mem_start tunable.");
-
-static struct resource *
-nexus_legacypci_alloc_resource(device_t dev, device_t child, int type, int *rid,
-                              u_long start, u_long end, u_long count,
-                              u_int flags)
-{
-       /*
-        * If no memory preference is given, use upper 32MB slot most
-        * bioses use for their memory window.  Typically other bridges
-        * before us get in the way to assert their preferences on memory.
-        * Hardcoding like this sucks, so a more MD/MI way needs to be
-        * found to do it.  This is typically only used on older laptops
-        * that don't have pci busses behind pci bridge, so assuming > 32MB
-        * is likely OK.
-        *
-        * However, this can cause problems for other chipsets, so we make
-        * this tunable by hw.pci.host_mem_start.
-        */
-       if (type == SYS_RES_MEMORY && start == 0UL && end == ~0UL)
-               start = legacy_host_mem_start;
-       if (type == SYS_RES_IOPORT && start == 0UL && end == ~0UL)
-               start = 0x1000;
-       return bus_generic_alloc_resource(dev, child, type, rid,
-                                         start, end, count, flags);
-}
-
-#endif /* PCI_MAP_FIXUP */
-
-static device_method_t legacypci_methods[] = {
-       /* Device interface */
-       DEVMETHOD(device_identify,      nexus_legacypci_identify),
-       DEVMETHOD(device_probe,         nexus_legacypci_probe),
-       DEVMETHOD(device_attach,        nexus_legacypci_attach),
-       DEVMETHOD(device_shutdown,      bus_generic_shutdown),
-       DEVMETHOD(device_suspend,       bus_generic_suspend),
-       DEVMETHOD(device_resume,        bus_generic_resume),
-
-       /*
-        * Bus interface - propogate through to the nexus.  Note that
-        * this means devices under us will have nexus ivars.
-        */
-       DEVMETHOD(bus_add_child,        bus_generic_add_child),
-       DEVMETHOD(bus_print_child,      bus_generic_print_child),
-       DEVMETHOD(bus_read_ivar,        bus_generic_read_ivar),
-       DEVMETHOD(bus_write_ivar,       bus_generic_write_ivar),
-#ifdef PCI_MAP_FIXUP
-       DEVMETHOD(bus_alloc_resource,   nexus_legacypci_alloc_resource),
-#else
-       DEVMETHOD(bus_alloc_resource,   bus_generic_alloc_resource),
-#endif
-       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),
-        DEVMETHOD(bus_set_resource,     bus_generic_set_resource),
-        DEVMETHOD(bus_get_resource,     bus_generic_get_resource),
-        DEVMETHOD(bus_delete_resource,  bus_generic_delete_resource),
-       { 0, 0 }
-};
-
-static driver_t legacypci_driver = {
-       "legacypci",
-       legacypci_methods,
-       1,
-};
-
-static devclass_t legacypci_devclass;
-
-DRIVER_MODULE(legacypci, nexus, legacypci_driver, legacypci_devclass, 0, 0);
-
-/*
- * Legacypci Host-Bridge PCI BUS support.  The underlying pcib devices
- * will only exist if we actually control the PCI bus.  The actual PCI
- * bus driver is attached in our attach routine.
- *
- * There is no identify function because the legacypci placeholder will
- * have already scanned and added PCIB devices for the host-bridges found.
- */
-static int
-nexus_pcib_maxslots(device_t dev)
-{
-       return 31;
-}
-
-/*
- * Read configuration space register.
- */
-static u_int32_t
-nexus_pcib_read_config(device_t dev, int bus, int slot, int func,
-                      int reg, int bytes)
-{
-       return (pci_cfgregread(bus, slot, func, reg, bytes));
-}
-
-/*
- * Write configuration space register.
- */
-static void
-nexus_pcib_write_config(device_t dev, int bus, int slot, int func,
-                       int reg, u_int32_t data, int bytes)
-{
-       pci_cfgregwrite(bus, slot, func, reg, data, bytes);
-}
-
-/*
- * Stack a pci device on top of the pci bridge bus device.
- */
-static int
-nexus_pcib_probe(device_t dev)
-{
-       BUS_ADD_CHILD(dev, dev, 0, "pci", device_get_unit(dev));
-       return (0);
-}
-
-static int
-nexus_pcib_attach(device_t dev)
-{
-       int error;
-
-       error = bus_generic_attach(dev);
-       return (error);
-}
-
-/* route interrupt */
-
-static int
-nexus_pcib_route_interrupt(device_t pcib, device_t dev, int pin)
-{
-       return(pci_cfgintr(pci_get_bus(dev), pci_get_slot(dev), pin, 
-                          pci_get_irq(dev)));
-}
-
-static device_method_t nexus_pcib_methods[] = {
-       /* Device interface */
-       DEVMETHOD(device_probe,         nexus_pcib_probe),
-       DEVMETHOD(device_attach,        nexus_pcib_attach),
-       DEVMETHOD(device_shutdown,      bus_generic_shutdown),
-       DEVMETHOD(device_suspend,       bus_generic_suspend),
-       DEVMETHOD(device_resume,        bus_generic_resume),
-
-       /*
-        * Bus interface - propogate through to the nexus.  Note
-        * that this means we will get nexus-managed ivars.
-        */
-       DEVMETHOD(bus_add_child,        bus_generic_add_child),
-       DEVMETHOD(bus_print_child,      bus_generic_print_child),
-       DEVMETHOD(bus_read_ivar,        bus_generic_read_ivar),
-       DEVMETHOD(bus_write_ivar,       bus_generic_write_ivar),
-       DEVMETHOD(bus_alloc_resource,   bus_generic_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,        nexus_pcib_maxslots),
-       DEVMETHOD(pcib_read_config,     nexus_pcib_read_config),
-       DEVMETHOD(pcib_write_config,    nexus_pcib_write_config),
-       DEVMETHOD(pcib_route_interrupt, nexus_pcib_route_interrupt),
-
-       { 0, 0 }
-};
-
-static driver_t nexus_pcib_driver = {
-       "pcib",
-       nexus_pcib_methods,
-       1,
-};
-
-static devclass_t      pcib_devclass;
-
-DRIVER_MODULE(pcib, legacypci, nexus_pcib_driver, pcib_devclass, 0, 0);
-
-
-/*
- * Provide a device to "eat" the host->pci bridges that we dug up above
- * and stop them showing up twice on the probes.  This also stops them
- * showing up as 'none' in pciconf -l.
- *
- * Return an ultra-low priority so other devices can attach the bus before
- * our dummy attach.
- *
- * XXX may have to disable the registration entirely to support module-loaded
- * bridges such as agp.ko.
- */
-static int
-pci_hostb_probe(device_t dev)
-{
-       if (pci_get_class(dev) == PCIC_BRIDGE &&
-           pci_get_subclass(dev) == PCIS_BRIDGE_HOST) {
-               device_set_desc(dev, "Host to PCI bridge");
-               device_quiet(dev);
-               return -10000;
-       }
-       return (ENXIO);
-}
-
-static int
-pci_hostb_attach(device_t dev)
-{
-       return (0);
-}
-
-static device_method_t pci_hostb_methods[] = {
-       /* Device interface */
-       DEVMETHOD(device_probe,         pci_hostb_probe),
-       DEVMETHOD(device_attach,        pci_hostb_attach),
-       DEVMETHOD(device_shutdown,      bus_generic_shutdown),
-       DEVMETHOD(device_suspend,       bus_generic_suspend),
-       DEVMETHOD(device_resume,        bus_generic_resume),
-
-       { 0, 0 }
-};
-static driver_t pci_hostb_driver = {
-       "hostb",
-       pci_hostb_methods,
-       1,
-};
-static devclass_t pci_hostb_devclass;
-
-DRIVER_MODULE(hostb, pci, pci_hostb_driver, pci_hostb_devclass, 0, 0);
-
-
-/*
- * Install placeholder to claim the resources owned by the
- * PCI bus interface.  This could be used to extract the 
- * config space registers in the extreme case where the PnP
- * ID is available and the PCI BIOS isn't, but for now we just
- * eat the PnP ID and do nothing else.
- *
- * XXX we should silence this probe, as it will generally confuse 
- * people.
- */
-static struct isa_pnp_id pcibus_pnp_ids[] = {
-       { 0x030ad041 /* PNP030A */, "PCI Bus" },
-       { 0 }
-};
-
-static int
-pcibus_pnp_probe(device_t dev)
-{
-       int result;
-       
-       if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, pcibus_pnp_ids)) <= 0)
-               device_quiet(dev);
-       return (result);
-}
-
-static int
-pcibus_pnp_attach(device_t dev)
-{
-       return(0);
-}
-
-static device_method_t pcibus_pnp_methods[] = {
-       /* Device interface */
-       DEVMETHOD(device_probe,         pcibus_pnp_probe),
-       DEVMETHOD(device_attach,        pcibus_pnp_attach),
-       DEVMETHOD(device_detach,        bus_generic_detach),
-       DEVMETHOD(device_shutdown,      bus_generic_shutdown),
-       DEVMETHOD(device_suspend,       bus_generic_suspend),
-       DEVMETHOD(device_resume,        bus_generic_resume),
-       { 0, 0 }
-};
-
-static driver_t pcibus_pnp_driver = {
-       "pcibus_pnp",
-       pcibus_pnp_methods,
-       1,              /* no softc */
-};
-
-static devclass_t pcibus_pnp_devclass;
-
-DRIVER_MODULE(pcibus_pnp, isa, pcibus_pnp_driver, pcibus_pnp_devclass, 0, 0);
-
diff --git a/sys/bus/pci/amd64/pcibus.h b/sys/bus/pci/amd64/pcibus.h
deleted file mode 100644 (file)
index 6b5a362..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.
- *
- * $FreeBSD: src/sys/i386/isa/pcibus.h,v 1.2 1999/08/28 00:44:59 peter Exp $
- * $DragonFly: src/sys/bus/pci/amd64/pcibus.h,v 1.1 2008/08/02 05:22:19 dillon Exp $
- *
- */
-
-#define CONF1_ADDR_PORT    0x0cf8
-#define CONF1_DATA_PORT    0x0cfc
-
-#define CONF1_ENABLE       0x80000000ul
-#define CONF1_ENABLE_CHK   0x80000000ul
-#define CONF1_ENABLE_MSK   0x7f000000ul
-#define CONF1_ENABLE_CHK1  0xff000001ul
-#define CONF1_ENABLE_MSK1  0x80000001ul
-#define CONF1_ENABLE_RES1  0x80000000ul
-
-#define CONF2_ENABLE_PORT  0x0cf8
-#define CONF2_FORWARD_PORT 0x0cfa
-
-#define CONF2_ENABLE_CHK   0x0e
-#define CONF2_ENABLE_RES   0x0e
index a773c7e..6e5f54b 100644 (file)
@@ -419,7 +419,7 @@ typedef struct {
 #define        TULIP_GP_ZX346_FULLDUPLEX       0x00000004      /* Full Duplex Sensed */
 #define        TULIP_GP_ZX34X_LB102            0x00000002      /* 100tx twister LB */
 #define        TULIP_GP_ZX34X_NLB101           0x00000001      /* PDT/PDR LB */
-#define        TULIP_GP_ZX34X_INIT             0x00000009      
+#define        TULIP_GP_ZX34X_INIT             0x00000009
 
 /*
  * Compex's OUI.  We need to twiddle a bit on their 21041 card.
diff --git a/sys/bus/pci/eisa_pci.c b/sys/bus/pci/eisa_pci.c
new file mode 100644 (file)
index 0000000..c348e41
--- /dev/null
@@ -0,0 +1,128 @@
+/*-
+ * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier
+ * Copyright (c) 2000 Michael Smith <msmith@freebsd.org>
+ * Copyright (c) 2000 BSDi
+ * 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 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.
+ * __FBSDID("$FreeBSD: src/sys/dev/pci/eisa_pci.c,v 1.6.28.1 2009/04/15 03:14:26 kensmith Exp $");
+ */
+
+#include <sys/cdefs.h>
+
+/*
+ * PCI:EISA bridge support
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <bus/pci/pcivar.h>
+#include <bus/pci/pcireg.h>
+
+static int     eisab_probe(device_t dev);
+static int     eisab_attach(device_t dev);
+
+static device_method_t eisab_methods[] = {
+    /* Device interface */
+    DEVMETHOD(device_probe,            eisab_probe),
+    DEVMETHOD(device_attach,           eisab_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_alloc_resource,      bus_generic_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),
+
+    { 0, 0 }
+};
+
+static driver_t eisab_driver = {
+    "eisab",
+    eisab_methods,
+    0,
+};
+
+static devclass_t eisab_devclass;
+
+DRIVER_MODULE(eisab, pci, eisab_driver, eisab_devclass, 0, 0);
+
+static int
+eisab_probe(device_t dev)
+{
+    int                matched = 0;
+
+    /*
+     * Generic match by class/subclass.
+     */
+    if ((pci_get_class(dev) == PCIC_BRIDGE) &&
+       (pci_get_subclass(dev) == PCIS_BRIDGE_EISA))
+       matched = 1;
+
+    /*
+     * Some bridges don't correctly report their class.
+     */
+    switch (pci_get_devid(dev)) {
+    case 0x04828086:           /* may show up as PCI-HOST or 0:0 */
+       matched = 1;
+       break;
+    default:
+       break;
+    }
+    
+    if (matched) {
+       device_set_desc(dev, "PCI-EISA bridge");
+       return(-10000);
+    }
+    return(ENXIO);
+}
+
+static int
+eisab_attach(device_t dev)
+{
+    /*
+     * Attach an EISA bus.  Note that we can only have one EISA bus.
+     */
+    if (!devclass_get_device(devclass_find("eisa"), 0))
+       device_add_child(dev, "eisa", -1);
+
+    /*
+     * Attach an ISA bus as well, since the EISA bus may have ISA
+     * cards installed, and we may have no EISA support in the system.
+     */
+    if (!devclass_get_device(devclass_find("isa"), 0))
+       device_add_child(dev, "isa", -1);
+
+    bus_generic_attach(dev);
+
+    return(0);
+}
diff --git a/sys/bus/pci/fixup_pci.c b/sys/bus/pci/fixup_pci.c
new file mode 100644 (file)
index 0000000..ecade92
--- /dev/null
@@ -0,0 +1,141 @@
+/*-
+ * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier
+ * Copyright (c) 2000 Michael Smith <msmith@freebsd.org>
+ * Copyright (c) 2000 BSDi
+ * 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 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.
+ * __FBSDID("$FreeBSD: src/sys/dev/pci/fixup_pci.c,v 1.7.8.1 2009/04/15 03:14:26 kensmith Exp $");
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/types.h>
+
+#include <bus/pci/pcivar.h>
+#include <bus/pci/pcireg.h>
+
+/*
+ * Chipset fixups.
+ *
+ * These routines are invoked during the probe phase for devices which
+ * typically don't have specific device drivers, but which require
+ * some cleaning up.
+ */
+
+static int     fixup_pci_probe(device_t dev);
+static void    fixwsc_natoma(device_t dev);
+static void    fixc1_nforce2(device_t dev);
+
+static device_method_t fixup_pci_methods[] = {
+    /* Device interface */
+    DEVMETHOD(device_probe,            fixup_pci_probe),
+    DEVMETHOD(device_attach,           bus_generic_attach),
+    { 0, 0 }
+};
+
+static driver_t fixup_pci_driver = {
+    "fixup_pci",
+    fixup_pci_methods,
+    0,
+};
+
+static devclass_t fixup_pci_devclass;
+
+DRIVER_MODULE(fixup_pci, pci, fixup_pci_driver, fixup_pci_devclass, 0, 0);
+
+static int
+fixup_pci_probe(device_t dev)
+{
+    switch (pci_get_devid(dev)) {
+    case 0x12378086:           /* Intel 82440FX (Natoma) */
+       fixwsc_natoma(dev);
+       break;
+    case 0x01e010de:           /* nVidia nForce2 */
+       fixc1_nforce2(dev);
+       break;
+    }
+    return(ENXIO);
+}
+
+static void
+fixwsc_natoma(device_t dev)
+{
+    int                pmccfg;
+
+    pmccfg = pci_read_config(dev, 0x50, 2);
+#if defined(SMP)
+    if (pmccfg & 0x8000) {
+       kprintf("Correcting Natoma config for SMP\n");
+       pmccfg &= ~0x8000;
+       pci_write_config(dev, 0x50, pmccfg, 2);
+    }
+#else
+    if ((pmccfg & 0x8000) == 0) {
+       kprintf("Correcting Natoma config for non-SMP\n");
+       pmccfg |= 0x8000;
+       pci_write_config(dev, 0x50, pmccfg, 2);
+    }
+#endif
+}
+
+/*
+ * Set the SYSTEM_IDLE_TIMEOUT to 80 ns on nForce2 systems to work
+ * around a hang that is triggered when the CPU generates a very fast
+ * CONNECT/HALT cycle sequence.  Specifically, the hang can result in
+ * the lapic timer being stopped.
+ *
+ * This requires changing the value for config register at offset 0x6c
+ * for the Host-PCI bridge at bus/dev/function 0/0/0:
+ *
+ * Chip        Current Value   New Value
+ * ----        ----------      ----------
+ * C17 0x1F0FFF01      0x1F01FF01
+ * C18D        0x9F0FFF01      0x9F01FF01
+ *
+ * We do this by always clearing the bits in 0x000e0000.
+ *
+ * See also: http://lkml.org/lkml/2004/5/3/157
+ */
+static void
+fixc1_nforce2(device_t dev)
+{
+       uint32_t val;
+
+       if (pci_get_bus(dev) == 0 && pci_get_slot(dev) == 0 &&
+           pci_get_function(dev) == 0) {
+               val = pci_read_config(dev, 0x6c, 4);
+               if (val & 0x000e0000) {
+                       kprintf("Correcting nForce2 C1 CPU disconnect hangs\n");
+                       val &= ~0x000e0000;
+                       pci_write_config(dev, 0x6c, val, 4);
+               }
+       }
+}
diff --git a/sys/bus/pci/hostb_pci.c b/sys/bus/pci/hostb_pci.c
new file mode 100644 (file)
index 0000000..c960461
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * 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.
+ * __FBSDID("$FreeBSD: src/sys/dev/pci/hostb_pci.c,v 1.1.8.1 2009/04/15 03:14:26 kensmith Exp $");
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <sys/types.h>
+#include <sys/systm.h>
+
+#include <bus/pci/pcivar.h>
+#include <bus/pci/pcireg.h>
+
+/*
+ * Provide a device to "eat" the host->pci bridge devices that show up
+ * on PCI busses and stop them showing up twice on the probes.  This also
+ * stops them showing up as 'none' in pciconf -l.  If the host bridge
+ * provides an AGP capability then we create a child agp device for the
+ * agp GART driver to attach to.
+ */
+static int
+pci_hostb_probe(device_t dev)
+{
+       u_int32_t id;
+       id = pci_get_devid(dev);
+
+       switch (id) {
+
+       /* VIA VT82C596 Power Managment Function */
+       case 0x30501106:
+               return (ENXIO);
+
+       default:
+               break;
+       }
+
+       if (pci_get_class(dev) == PCIC_BRIDGE &&
+           pci_get_subclass(dev) == PCIS_BRIDGE_HOST) {
+               device_set_desc(dev, "Host to PCI bridge");
+               device_quiet(dev);
+               return (-10000);
+       }
+       return (ENXIO);
+}
+
+static int
+pci_hostb_attach(device_t dev)
+{
+
+       bus_generic_probe(dev);
+
+       /*
+        * If AGP capabilities are present on this device, then create
+        * an AGP child.
+        */
+       if (pci_find_extcap(dev, PCIY_AGP, NULL) == 0)
+               device_add_child(dev, "agp", -1);
+       bus_generic_attach(dev);
+       return (0);
+}
+
+/* Bus interface. */
+
+static int
+pci_hostb_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+
+       return (BUS_READ_IVAR(device_get_parent(dev), dev, which, result));
+}
+
+static int
+pci_hostb_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
+{
+
+       return (EINVAL);
+}
+
+static struct resource *
+pci_hostb_alloc_resource(device_t dev, device_t child, int type, int *rid,
+    u_long start, u_long end, u_long count, u_int flags)
+{
+
+       return (bus_alloc_resource(dev, type, rid, start, end, count, flags));
+}
+
+static int
+pci_hostb_release_resource(device_t dev, device_t child, int type, int rid,
+    struct resource *r)
+{
+
+       return (bus_release_resource(dev, type, rid, r));
+}
+
+/* PCI interface. */
+
+static uint32_t
+pci_hostb_read_config(device_t dev, device_t child, int reg, int width)
+{
+
+       return (pci_read_config(dev, reg, width));
+}
+
+static void
+pci_hostb_write_config(device_t dev, device_t child, int reg, 
+    uint32_t val, int width)
+{
+
+       pci_write_config(dev, reg, val, width);
+}
+
+static int
+pci_hostb_enable_busmaster(device_t dev, device_t child)
+{
+
+       device_printf(dev, "child %s requested pci_enable_busmaster\n",
+           device_get_nameunit(child));
+       return (pci_enable_busmaster(dev));
+}
+
+static int
+pci_hostb_disable_busmaster(device_t dev, device_t child)
+{
+
+       device_printf(dev, "child %s requested pci_disable_busmaster\n",
+           device_get_nameunit(child));
+       return (pci_disable_busmaster(dev));
+}
+
+static int
+pci_hostb_enable_io(device_t dev, device_t child, int space)
+{
+
+       device_printf(dev, "child %s requested pci_enable_io\n",
+           device_get_nameunit(child));
+       return (pci_enable_io(dev, space));
+}
+
+static int
+pci_hostb_disable_io(device_t dev, device_t child, int space)
+{
+
+       device_printf(dev, "child %s requested pci_disable_io\n",
+           device_get_nameunit(child));
+       return (pci_disable_io(dev, space));
+}
+
+static int
+pci_hostb_set_powerstate(device_t dev, device_t child, int state)
+{
+
+       device_printf(dev, "child %s requested pci_set_powerstate\n",
+           device_get_nameunit(child));
+       return (pci_set_powerstate(dev, state));
+}
+
+static int
+pci_hostb_get_powerstate(device_t dev, device_t child)
+{
+
+       device_printf(dev, "child %s requested pci_get_powerstate\n",
+           device_get_nameunit(child));
+       return (pci_get_powerstate(dev));
+}
+
+static int
+pci_hostb_assign_interrupt(device_t dev, device_t child)
+{
+
+       device_printf(dev, "child %s requested pci_assign_interrupt\n",
+           device_get_nameunit(child));
+       return (PCI_ASSIGN_INTERRUPT(device_get_parent(dev), dev));
+}
+
+static int
+pci_hostb_find_extcap(device_t dev, device_t child, int capability,
+    int *capreg)
+{
+
+       return (pci_find_extcap(dev, capability, capreg));
+}
+
+static device_method_t pci_hostb_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_probe,         pci_hostb_probe),
+       DEVMETHOD(device_attach,        pci_hostb_attach),
+       DEVMETHOD(device_shutdown,      bus_generic_shutdown),
+       DEVMETHOD(device_suspend,       bus_generic_suspend),
+       DEVMETHOD(device_resume,        bus_generic_resume),
+
+       /* Bus interface */
+       DEVMETHOD(bus_read_ivar,        pci_hostb_read_ivar),
+       DEVMETHOD(bus_write_ivar,       pci_hostb_write_ivar),
+       DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
+       DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
+
+       DEVMETHOD(bus_alloc_resource,   pci_hostb_alloc_resource),
+       DEVMETHOD(bus_release_resource, pci_hostb_release_resource),
+       DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+       DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+
+       /* PCI interface */
+       DEVMETHOD(pci_read_config,      pci_hostb_read_config),
+       DEVMETHOD(pci_write_config,     pci_hostb_write_config),
+       DEVMETHOD(pci_enable_busmaster, pci_hostb_enable_busmaster),
+       DEVMETHOD(pci_disable_busmaster, pci_hostb_disable_busmaster),
+       DEVMETHOD(pci_enable_io,        pci_hostb_enable_io),
+       DEVMETHOD(pci_disable_io,       pci_hostb_disable_io),
+       DEVMETHOD(pci_get_powerstate,   pci_hostb_get_powerstate),
+       DEVMETHOD(pci_set_powerstate,   pci_hostb_set_powerstate),
+       DEVMETHOD(pci_assign_interrupt, pci_hostb_assign_interrupt),
+       DEVMETHOD(pci_find_extcap,      pci_hostb_find_extcap),
+
+       { 0, 0 }
+};
+
+static driver_t pci_hostb_driver = {
+       "hostb",
+       pci_hostb_methods,
+       1,
+};
+
+static devclass_t pci_hostb_devclass;
+
+DRIVER_MODULE(hostb, pci, pci_hostb_driver, pci_hostb_devclass, 0, 0);
diff --git a/sys/bus/pci/i386/legacy.c b/sys/bus/pci/i386/legacy.c
new file mode 100644 (file)
index 0000000..60645cb
--- /dev/null
@@ -0,0 +1,360 @@
+/*-
+ * Copyright 1998 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. 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.
+ * __FBSDID("$FreeBSD: src/sys/i386/i386/legacy.c,v 1.63.2.1.4.1 2009/04/15 03:14:26 kensmith Exp $");
+ */
+
+#include <sys/cdefs.h>
+
+/*
+ * This code implements a system driver for legacy systems that do not
+ * support ACPI or when ACPI support is not present in the kernel.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+
+#undef DEV_MCA
+#ifdef DEV_MCA
+#include <i386/bios/mca_machdep.h>
+#endif
+
+#include <machine/legacyvar.h>
+
+static MALLOC_DEFINE(M_LEGACYDEV, "legacydrv", "legacy system device");
+struct legacy_device {
+       int                     lg_pcibus;
+};
+
+#define DEVTOAT(dev)   ((struct legacy_device *)device_get_ivars(dev))
+
+static void legacy_identify(driver_t *driver, device_t parent);
+static int legacy_probe(device_t);
+static int legacy_attach(device_t);
+static int legacy_print_child(device_t, device_t);
+static device_t legacy_add_child(device_t bus, device_t parent, int order, const char *name,
+                               int unit);
+static int legacy_read_ivar(device_t, device_t, int, uintptr_t *);
+static int legacy_write_ivar(device_t, device_t, int, uintptr_t);
+
+static device_method_t legacy_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_identify,      legacy_identify),
+       DEVMETHOD(device_probe,         legacy_probe),
+       DEVMETHOD(device_attach,        legacy_attach),
+       DEVMETHOD(device_detach,        bus_generic_detach),
+       DEVMETHOD(device_shutdown,      bus_generic_shutdown),
+       DEVMETHOD(device_suspend,       bus_generic_suspend),
+       DEVMETHOD(device_resume,        bus_generic_resume),
+
+       /* Bus interface */
+       DEVMETHOD(bus_print_child,      legacy_print_child),
+       DEVMETHOD(bus_add_child,        legacy_add_child),
+       DEVMETHOD(bus_read_ivar,        legacy_read_ivar),
+       DEVMETHOD(bus_write_ivar,       legacy_write_ivar),
+       DEVMETHOD(bus_alloc_resource,   bus_generic_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),
+
+       { 0, 0 }
+};
+
+static driver_t legacy_driver = {
+       "legacy",
+       legacy_methods,
+       1,                      /* no softc */
+};
+static devclass_t legacy_devclass;
+
+DRIVER_MODULE(legacy, nexus, legacy_driver, legacy_devclass, 0, 0);
+
+static void
+legacy_identify(driver_t *driver, device_t parent)
+{
+
+       /*
+        * Add child device with order of 11 so it gets probed
+        * after ACPI (which is at order 10).
+        */
+       if (BUS_ADD_CHILD(parent, parent, 11, "legacy", 0) == NULL)
+               panic("legacy: could not attach");
+}
+
+static int
+legacy_probe(device_t dev)
+{
+       device_t acpi;
+
+       /*
+        * Fail to probe if ACPI is ok.
+        */
+       acpi = devclass_get_device(devclass_find("acpi"), 0);
+       if (acpi != NULL && device_is_alive(acpi))
+               return (ENXIO);
+       device_set_desc(dev, "legacy system");
+       device_quiet(dev);
+       return (0);
+}
+
+static int
+legacy_attach(device_t dev)
+{
+       device_t child;
+
+       /*
+        * Let our child drivers identify any child devices that they
+        * can find.  Once that is done attach any devices that we
+        * found.
+        */
+       bus_generic_probe(dev);
+       bus_generic_attach(dev);
+
+#ifndef PC98
+       /*
+        * If we didn't see EISA or ISA on a pci bridge, create some
+        * connection points now so they show up "on motherboard".
+        */
+       if (!devclass_get_device(devclass_find("eisa"), 0)) {
+               child = BUS_ADD_CHILD(dev, dev, 0, "eisa", 0);
+               if (child == NULL)
+                       panic("legacy_attach eisa");
+               device_probe_and_attach(child);
+       }
+#endif
+#ifdef DEV_MCA
+       if (MCA_system && !devclass_get_device(devclass_find("mca"), 0)) {
+               child = BUS_ADD_CHILD(dev, dev, 0, "mca", 0);
+               if (child == 0)
+                       panic("legacy_probe mca");
+               device_probe_and_attach(child);
+       }
+#endif
+       if (!devclass_get_device(devclass_find("isa"), 0)) {
+               child = BUS_ADD_CHILD(dev, dev, 0, "isa", 0);
+               if (child == NULL)
+                       panic("legacy_attach isa");
+               device_probe_and_attach(child);
+       }
+
+       return 0;
+}
+
+static int
+legacy_print_child(device_t bus, device_t child)
+{
+       struct legacy_device *atdev = DEVTOAT(child);
+       int retval = 0;
+
+       retval += bus_print_child_header(bus, child);
+       if (atdev->lg_pcibus != -1)
+               retval += kprintf(" pcibus %d", atdev->lg_pcibus);
+       retval += kprintf(" on motherboard\n"); /* XXX "motherboard", ick */
+
+       return (retval);
+}
+
+static device_t
+legacy_add_child(device_t bus, device_t parent, int order, const char *name, int unit)
+{
+       device_t child;
+       struct legacy_device *atdev;
+       atdev = kmalloc(sizeof(struct legacy_device), M_LEGACYDEV,
+           M_NOWAIT | M_ZERO);
+       if (atdev == NULL)
+               return(NULL);
+       atdev->lg_pcibus = -1;
+
+       child = device_add_child_ordered(bus, order, name, unit);
+       if (child == NULL) {
+               kfree(atdev, M_LEGACYDEV);
+       }
+       else {
+               /* should we kfree this in legacy_child_detached? */
+               device_set_ivars(child, atdev);
+       }
+       return (child);
+}
+
+static int
+legacy_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+       struct legacy_device *atdev = DEVTOAT(child);
+
+       switch (which) {
+       case LEGACY_IVAR_PCIDOMAIN:
+               *result = 0;
+               break;
+       case LEGACY_IVAR_PCIBUS:
+               *result = atdev->lg_pcibus;
+               break;
+       default:
+               return ENOENT;
+       }
+       return 0;
+}
+
+static int
+legacy_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
+{
+       struct legacy_device *atdev = DEVTOAT(child);
+
+       switch (which) {
+       case LEGACY_IVAR_PCIDOMAIN:
+               return EINVAL;
+       case LEGACY_IVAR_PCIBUS:
+               atdev->lg_pcibus = value;
+               break;
+       default:
+               return ENOENT;
+       }
+       return 0;
+}
+
+#ifdef notyet
+/*
+ * Legacy CPU attachment when ACPI is not available.  Drivers like
+ * cpufreq(4) hang off this.
+ */
+static void    cpu_identify(driver_t *driver, device_t parent);
+static int     cpu_read_ivar(device_t dev, device_t child, int index,
+                   uintptr_t *result);
+static device_t cpu_add_child(device_t bus, int order, const char *name,
+                   int unit);
+static struct resource_list *cpu_get_rlist(device_t dev, device_t child);
+
+struct cpu_device {
+       struct resource_list cd_rl;
+       struct pcpu *cd_pcpu;
+};
+
+static device_method_t cpu_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_identify,      cpu_identify),
+       DEVMETHOD(device_probe,         bus_generic_probe),
+       DEVMETHOD(device_attach,        bus_generic_attach),
+       DEVMETHOD(device_detach,        bus_generic_detach),
+       DEVMETHOD(device_shutdown,      bus_generic_shutdown),
+       DEVMETHOD(device_suspend,       bus_generic_suspend),
+       DEVMETHOD(device_resume,        bus_generic_resume),
+
+       /* Bus interface */
+       DEVMETHOD(bus_add_child,        cpu_add_child),
+       DEVMETHOD(bus_read_ivar,        cpu_read_ivar),
+       DEVMETHOD(bus_print_child,      bus_generic_print_child),
+       DEVMETHOD(bus_get_resource_list, cpu_get_rlist),
+       DEVMETHOD(bus_get_resource,     bus_generic_rl_get_resource),
+       DEVMETHOD(bus_set_resource,     bus_generic_rl_set_resource),
+       DEVMETHOD(bus_alloc_resource,   bus_generic_rl_alloc_resource),
+       DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource),
+       DEVMETHOD(bus_driver_added,     bus_generic_driver_added),
+       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),
+
+       { 0, 0 }
+};
+
+static driver_t cpu_driver = {
+       "cpu",
+       cpu_methods,
+       1,              /* no softc */
+};
+static devclass_t cpu_devclass;
+DRIVER_MODULE(cpu, legacy, cpu_driver, cpu_devclass, 0, 0);
+
+static void
+cpu_identify(driver_t *driver, device_t parent)
+{
+       device_t child;
+       int i;
+
+       /*
+        * Attach a cpuX device for each CPU.  We use an order of 150
+        * so that these devices are attached after the Host-PCI
+        * bridges (which are added at order 100).
+        */
+       for (i = 0; i <= mp_maxid; i++)
+               if (!CPU_ABSENT(i)) {
+                       child = BUS_ADD_CHILD(parent, 150, "cpu", i);
+                       if (child == NULL)
+                               panic("legacy_attach cpu");
+               }
+}
+
+static device_t
+cpu_add_child(device_t bus, int order, const char *name, int unit)
+{
+       struct cpu_device *cd;
+       device_t child;
+       struct pcpu *pc;
+
+       if ((cd = kmalloc(sizeof(*cd), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL)
+               return (NULL);
+
+       resource_list_init(&cd->cd_rl);
+       pc = pcpu_find(device_get_unit(bus));
+       cd->cd_pcpu = pc;
+
+       child = device_add_child_ordered(bus, order, name, unit);
+       if (child != NULL) {
+               pc->pc_device = child;
+               device_set_ivars(child, cd);
+       } else
+               kfree(cd, M_DEVBUF);
+       return (child);
+}
+
+static struct resource_list *
+cpu_get_rlist(device_t dev, device_t child)
+{
+       struct cpu_device *cpdev;
+
+       cpdev = device_get_ivars(child);
+       return (&cpdev->cd_rl);
+}
+
+static int
+cpu_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
+{
+       struct cpu_device *cpdev;
+
+       if (index != CPU_IVAR_PCPU)
+               return (ENOENT);
+       cpdev = device_get_ivars(child);
+       *result = (uintptr_t)cpdev->cd_pcpu;
+       return (0);
+}
+#endif
similarity index 51%
rename from sys/bus/pci/i386/pcibus.c
rename to sys/bus/pci/i386/pci_bus.c
index 0858091..ca8e7cc 100644 (file)
@@ -1,5 +1,5 @@
-/*
- * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
+/*-
+ * Copyright (c) 1997, Stefan Esser <se@kfreebsd.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * 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: src/sys/i386/isa/pcibus.c,v 1.57.2.12 2003/08/07 06:19:26 imp Exp $
- * $DragonFly: src/sys/bus/pci/i386/pcibus.c,v 1.21 2008/09/05 10:39:36 hasso Exp $
- *
+ * __FBSDID("$FreeBSD: src/sys/i386/pci/pci_bus.c,v 1.128.8.1 2009/04/15 03:14:26 kensmith Exp $");
  */
 
+#include <sys/cdefs.h>
+
 #include "opt_pci.h"
 
 #include <sys/param.h>
 #include <sys/bus.h>
 #include <sys/kernel.h>
 #include <sys/malloc.h>
+#include <sys/module.h>
 #include <sys/sysctl.h>
 
 #include <bus/pci/pcivar.h>
 #include <bus/pci/pcireg.h>
-#include "pcibus.h"
+#include <bus/pci/pcib_private.h>
 #include <bus/isa/isavar.h>
-#include "pci_cfgreg.h"
 #include <machine/md_var.h>
-#include <machine/nexusvar.h>
+#include <machine/legacyvar.h>
+#include "pci_cfgreg.h"
 
 #include "pcib_if.h"
 
-static u_int32_t nexus_pcib_read_config(device_t, int, int, int, int, int);
+static int     pcibios_pcib_route_interrupt(device_t pcib, device_t dev,
+    int pin);
+
+int
+legacy_pcib_maxslots(device_t dev)
+{
+       return 31;
+}
+
+/* read configuration space register */
+
+u_int32_t
+legacy_pcib_read_config(device_t dev, int bus, int slot, int func,
+                       int reg, int bytes)
+{
+       return(pci_cfgregread(bus, slot, func, reg, bytes));
+}
+
+/* write configuration space register */
+
+void
+legacy_pcib_write_config(device_t dev, int bus, int slot, int func,
+                        int reg, u_int32_t data, int bytes)
+{
+       pci_cfgregwrite(bus, slot, func, reg, data, bytes);
+}
+
+/* Pass MSI requests up to the nexus. */
+
+static int
+legacy_pcib_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
+legacy_pcib_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
+legacy_pcib_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));
+}
 
-/*
- * Figure out if a PCI entity is a host bridge, return its name or NULL.
- */
 static const char *
-nexus_legacypci_is_host_bridge(int bus, int slot, int func,
-                         u_int32_t id, u_int8_t class, u_int8_t subclass,
-                         u_int8_t *busnum)
+legacy_pcib_is_host_bridge(int bus, int slot, int func,
+                         uint32_t id, uint8_t class, uint8_t subclass,
+                         uint8_t *busnum)
 {
        const char *s = NULL;
-       static u_int8_t pxb[4]; /* hack for 450nx */
+       static uint8_t pxb[4];  /* hack for 450nx */
 
        *busnum = 0;
 
@@ -66,7 +120,7 @@ nexus_legacypci_is_host_bridge(int bus, int slot, int func,
        case 0x12258086:
                s = "Intel 824?? host to PCI bridge";
                /* XXX This is a guess */
-               /* *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x41, 1); */
+               /* *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x41, 1); */
                *busnum = bus;
                break;
        case 0x71208086:
@@ -78,6 +132,9 @@ nexus_legacypci_is_host_bridge(int bus, int slot, int func,
        case 0x71248086:
                s = "Intel 82810E (i810E GMCH) Host To Hub bridge";
                break;
+       case 0x11308086:
+               s = "Intel 82815 (i815 GMCH) Host To Hub bridge";
+               break;
        case 0x71808086:
                s = "Intel 82443LX (440 LX) host to PCI bridge";
                break;
@@ -101,27 +158,27 @@ nexus_legacypci_is_host_bridge(int bus, int slot, int func,
                break;
        case 0x84c48086:
                s = "Intel 82454KX/GX (Orion) host to PCI bridge";
-               *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x4a, 1);
+               *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x4a, 1);
                break;
        case 0x84ca8086:
                /*
                 * For the 450nx chipset, there is a whole bundle of
-                * things pretending to be host bridges. The MIOC will 
+                * things pretending to be host bridges. The MIOC will
                 * be seen first and isn't really a pci bridge (the
-                * actual busses are attached to the PXB's). We need to 
+                * actual busses are attached to the PXB's). We need to
                 * read the registers of the MIOC to figure out the
                 * bus numbers for the PXB channels.
                 *
                 * Since the MIOC doesn't have a pci bus attached, we
                 * pretend it wasn't there.
                 */
-               pxb[0] = nexus_pcib_read_config(0, bus, slot, func,
+               pxb[0] = legacy_pcib_read_config(0, bus, slot, func,
                                                0xd0, 1); /* BUSNO[0] */
-               pxb[1] = nexus_pcib_read_config(0, bus, slot, func,
+               pxb[1] = legacy_pcib_read_config(0, bus, slot, func,
                                                0xd1, 1) + 1;   /* SUBA[0]+1 */
-               pxb[2] = nexus_pcib_read_config(0, bus, slot, func,
+               pxb[2] = legacy_pcib_read_config(0, bus, slot, func,
                                                0xd3, 1); /* BUSNO[1] */
-               pxb[3] = nexus_pcib_read_config(0, bus, slot, func,
+               pxb[3] = legacy_pcib_read_config(0, bus, slot, func,
                                                0xd4, 1) + 1;   /* SUBA[1]+1 */
                return NULL;
        case 0x84cb8086:
@@ -144,9 +201,6 @@ nexus_legacypci_is_host_bridge(int bus, int slot, int func,
                        break;
                }
                break;
-       case 0x1A308086:
-               s = "Intel 82845 Host to PCI bridge";
-               break;
 
                /* AMD -- vendor 0x1022 */
        case 0x30001022:
@@ -154,8 +208,8 @@ nexus_legacypci_is_host_bridge(int bus, int slot, int func,
 #ifdef CPU_ELAN
                init_AMD_Elan_sc520();
 #else
-               kprintf("*** WARNING: kernel option CPU_ELAN missing");
-               kprintf("-- timekeeping may be wrong\n");
+               kprintf(
+"*** WARNING: missing CPU_ELAN -- timekeeping may be wrong\n");
 #endif
                break;
        case 0x70061022:
@@ -212,9 +266,9 @@ nexus_legacypci_is_host_bridge(int bus, int slot, int func,
                /* ServerWorks -- vendor 0x1166 */
        case 0x00051166:
                s = "ServerWorks NB6536 2.0HE host to PCI bridge";
-               *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1);
+               *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1);
                break;
-       
+
        case 0x00061166:
                /* FALLTHROUGH */
        case 0x00081166:
@@ -222,26 +276,25 @@ nexus_legacypci_is_host_bridge(int bus, int slot, int func,
        case 0x02011166:
                /* FALLTHROUGH */
        case 0x010f1014: /* IBM re-badged ServerWorks chipset */
-               /* FALLTHROUGH */
                s = "ServerWorks host to PCI bridge";
-               *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1);
+               *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1);
                break;
 
        case 0x00091166:
                s = "ServerWorks NB6635 3.0LE host to PCI bridge";
-               *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1);
+               *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1);
                break;
 
        case 0x00101166:
                s = "ServerWorks CIOB30 host to PCI bridge";
-               *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1);
+               *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1);
                break;
 
        case 0x00111166:
                /* FALLTHROUGH */
        case 0x03021014: /* IBM re-badged ServerWorks chipset */
                s = "ServerWorks CMIC-HE host to PCI-X bridge";
-               *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1);
+               *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1);
                break;
 
                /* XXX unknown chipset, but working */
@@ -249,7 +302,13 @@ nexus_legacypci_is_host_bridge(int bus, int slot, int func,
                /* FALLTHROUGH */
        case 0x01011166:
                s = "ServerWorks host to PCI bridge(unknown chipset)";
-               *busnum = nexus_pcib_read_config(0, bus, slot, func, 0x44, 1);
+               *busnum = legacy_pcib_read_config(0, bus, slot, func, 0x44, 1);
+               break;
+
+               /* Compaq/HP -- vendor 0x0e11 */
+       case 0x60100e11:
+               s = "Compaq/HP Model 6010 HotPlug PCI Bridge";
+               *busnum = legacy_pcib_read_config(0, bus, slot, func, 0xc8, 1);
                break;
 
                /* Integrated Micro Solutions -- vendor 0x10e0 */
@@ -267,74 +326,50 @@ nexus_legacypci_is_host_bridge(int bus, int slot, int func,
 }
 
 /*
- * Identify the existance of the first pci bus and install a child to
- * nexus if we find it.  Use an order of 1 so it gets probed after
- * any ACPI device installed under nexus.  To avoid boot-time confusion,
- * we do not install any 'pcib' devices at this time.
- *
- * The identify method coupled with the driver spec of the same name
- * automatically installs it under the nexus.
- */
-static int
-nexus_legacypci_identify(driver_t *driver, device_t parent)
-{
-       /*
-        * Basically a static device, there's no point reinstalling it
-        * on rescan.
-        */
-       if (device_get_state(parent) == DS_ATTACHED)
-               return (0);
-       if (device_get_state(parent) == DS_INPROGRESS)
-               return (0);
-
-       if (pci_cfgregopen() == 0)
-               return (ENXIO);
-
-       BUS_ADD_CHILD(parent, parent, 100, "legacypci", 0);
-       return (0);
-}
-
-/*
  * Scan the first pci bus for host-pci bridges and add pcib instances
  * to the nexus for each bridge.
  */
-static int
-nexus_legacypci_probe(device_t dev)
+static void
+legacy_pcib_identify(driver_t *driver, device_t parent)
 {
        int bus, slot, func;
        u_int8_t  hdrtype;
        int found = 0;
        int pcifunchigh;
        int found824xx = 0;
+       int found_orion = 0;
        device_t child;
+       devclass_t pci_devclass;
 
+       if (pci_cfgregopen() == 0)
+               return;
        /*
-        * Do not install any pci busses ('pcib' devices) if the PCI
-        * subsystem has already been claimed by someone else.
+        * Check to see if we haven't already had a PCI bus added
+        * via some other means.  If we have, bail since otherwise
+        * we're going to end up duplicating it.
         */
-       if (pcib_owner != NULL) {
-               device_printf(dev, "PCI subsystem owned by %s, skipping scan\n",
-                             pcib_owner);
-               return (ENXIO);
-       }
-       pcib_owner = "legacypci";
+       if ((pci_devclass = devclass_find("pci")) &&
+               devclass_get_device(pci_devclass, 0))
+               return;
 
-       if (pci_cfgregopen() == 0)
-               return (ENXIO);
 
-       /*
-        * Scan away!
-        */
        bus = 0;
  retry:
        for (slot = 0; slot <= PCI_SLOTMAX; slot++) {
                func = 0;
-               hdrtype = nexus_pcib_read_config(0, bus, slot, func,
+               hdrtype = legacy_pcib_read_config(0, bus, slot, func,
                                                 PCIR_HDRTYPE, 1);
-               if ((hdrtype & ~PCIM_MFDEV) > 2)
+               /*
+                * When enumerating bus devices, the standard says that
+                * one should check the header type and ignore the slots whose
+                * header types that the software doesn't know about.  We use
+                * this to filter out devices.
+                */
+               if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
                        continue;
-               if (hdrtype & PCIM_MFDEV)
-                       pcifunchigh = 7;
+               if ((hdrtype & PCIM_MFDEV) &&
+                   (!found_orion || hdrtype != 0xff))
+                       pcifunchigh = PCI_FUNCMAX;
                else
                        pcifunchigh = 0;
                for (func = 0; func <= pcifunchigh; func++) {
@@ -347,16 +382,16 @@ nexus_legacypci_probe(device_t dev)
                        device_t *devs;
                        int ndevs, i;
 
-                       id = nexus_pcib_read_config(0, bus, slot, func,
+                       id = legacy_pcib_read_config(0, bus, slot, func,
                                                    PCIR_DEVVENDOR, 4);
                        if (id == -1)
                                continue;
-                       class = nexus_pcib_read_config(0, bus, slot, func,
+                       class = legacy_pcib_read_config(0, bus, slot, func,
                                                       PCIR_CLASS, 1);
-                       subclass = nexus_pcib_read_config(0, bus, slot, func,
+                       subclass = legacy_pcib_read_config(0, bus, slot, func,
                                                          PCIR_SUBCLASS, 1);
 
-                       s = nexus_legacypci_is_host_bridge(bus, slot, func,
+                       s = legacy_pcib_is_host_bridge(bus, slot, func,
                                                      id, class, subclass,
                                                      &busnum);
                        if (s == NULL)
@@ -364,15 +399,15 @@ nexus_legacypci_probe(device_t dev)
 
                        /*
                         * Check to see if the physical bus has already
-                        * been seen. Eg: hybrid 32 and 64 bit host
+                        * been seen.  Eg: hybrid 32 and 64 bit host
                         * bridges to the same logical bus.
                         */
-                       if (device_get_children(dev, &devs, &ndevs) == 0) {
+                       if (device_get_children(parent, &devs, &ndevs) == 0) {
                                for (i = 0; s != NULL && i < ndevs; i++) {
                                        if (strcmp(device_get_name(devs[i]),
                                            "pcib") != 0)
                                                continue;
-                                       if (nexus_get_pcibus(devs[i]) == busnum)
+                                       if (legacy_get_pcibus(devs[i]) == busnum)
                                                s = NULL;
                                }
                                kfree(devs, M_TEMP);
@@ -380,18 +415,21 @@ nexus_legacypci_probe(device_t dev)
 
                        if (s == NULL)
                                continue;
+
                        /*
-                        * Add at priority 100+busnum to keep the scanning
-                        * order sane in the boot dmesg output.
+                        * Add at priority 100 to make sure we
+                        * go after any motherboard resources
                         */
-                       child = BUS_ADD_CHILD(dev, dev, 100 + busnum, 
+                       child = BUS_ADD_CHILD(parent, parent, 100 + busnum,
                                              "pcib", busnum);
                        device_set_desc(child, s);
-                       nexus_set_pcibus(child, busnum);
+                       legacy_set_pcibus(child, busnum);
 
                        found = 1;
                        if (id == 0x12258086)
                                found824xx = 1;
+                       if (id == 0x84c48086)
+                               found_orion = 1;
                }
        }
        if (found824xx && bus == 0) {
@@ -399,199 +437,126 @@ nexus_legacypci_probe(device_t dev)
                goto retry;
        }
 
-#if 0
-       /*
-        * Now that we have installed the main PCI bridges, go
-        * probe and attach each one.
-        */
-       bus_generic_attach(dev);
-#endif
-
        /*
         * Make sure we add at least one bridge since some old
         * hardware doesn't actually have a host-pci bridge device.
         * Note that pci_cfgregopen() thinks we have PCI devices..
         */
        if (!found) {
-               if (bootverbose) {
-                       kprintf("nexus_pcib_identify: no bridge found, "
-                              "adding pcib0 anyway\n");
-               }
-               child = BUS_ADD_CHILD(dev, dev, 100, "pcib", 0);
-               nexus_set_pcibus(child, 0);
+               if (bootverbose)
+                       kprintf(
+       "legacy_pcib_identify: no bridge found, adding pcib0 anyway\n");
+               child = BUS_ADD_CHILD(parent, parent, 100, "pcib", 0);
+               legacy_set_pcibus(child, 0);
        }
-       return (0);
 }
 
 static int
-nexus_legacypci_attach(device_t dev)
+legacy_pcib_probe(device_t dev)
 {
-       bus_generic_attach(dev);
-       return (0);
+       if (pci_cfgregopen() == 0)
+               return ENXIO;
+       return -100;
 }
 
-#ifdef PCI_MAP_FIXUP
-
-SYSCTL_DECL(_hw_pci);
-
-static unsigned long legacy_host_mem_start = 0x80000000;
-/* XXX need TUNABLE_ULONG? */
-TUNABLE_INT("hw.pci.host_mem_start", (int *)&legacy_host_mem_start);
-SYSCTL_ULONG(_hw_pci, OID_AUTO, host_mem_start, CTLFLAG_RD,
-            &legacy_host_mem_start, 0x80000000,
-            "Limit the host bridge memory to being above this address.  "
-            "Must be\n"
-            "set at boot via hw.pci.host_mem_start tunable.");
-
-static struct resource *
-nexus_legacypci_alloc_resource(device_t dev, device_t child, int type, int *rid,
-                              u_long start, u_long end, u_long count,
-                              u_int flags)
+static int
+legacy_pcib_attach(device_t dev)
 {
-       /*
-        * If no memory preference is given, use upper 32MB slot most
-        * bioses use for their memory window.  Typically other bridges
-        * before us get in the way to assert their preferences on memory.
-        * Hardcoding like this sucks, so a more MD/MI way needs to be
-        * found to do it.  This is typically only used on older laptops
-        * that don't have pci busses behind pci bridge, so assuming > 32MB
-        * is likely OK.
-        *
-        * However, this can cause problems for other chipsets, so we make
-        * this tunable by hw.pci.host_mem_start.
-        */
-       if (type == SYS_RES_MEMORY && start == 0UL && end == ~0UL)
-               start = legacy_host_mem_start;
-       if (type == SYS_RES_IOPORT && start == 0UL && end == ~0UL)
-               start = 0x1000;
-       return bus_generic_alloc_resource(dev, child, type, rid,
-                                         start, end, count, flags);
-}
-
-#endif /* PCI_MAP_FIXUP */
-
-static device_method_t legacypci_methods[] = {
-       /* Device interface */
-       DEVMETHOD(device_identify,      nexus_legacypci_identify),
-       DEVMETHOD(device_probe,         nexus_legacypci_probe),
-       DEVMETHOD(device_attach,        nexus_legacypci_attach),
-       DEVMETHOD(device_shutdown,      bus_generic_shutdown),
-       DEVMETHOD(device_suspend,       bus_generic_suspend),
-       DEVMETHOD(device_resume,        bus_generic_resume),
+       device_t pir;
+       int bus;
 
        /*
-        * Bus interface - propogate through to the nexus.  Note that
-        * this means devices under us will have nexus ivars.
+        * Look for a PCI BIOS interrupt routing table as that will be
+        * our method of routing interrupts if we have one.
         */
-       DEVMETHOD(bus_add_child,        bus_generic_add_child),
-       DEVMETHOD(bus_print_child,      bus_generic_print_child),
-       DEVMETHOD(bus_read_ivar,        bus_generic_read_ivar),
-       DEVMETHOD(bus_write_ivar,       bus_generic_write_ivar),
-#ifdef PCI_MAP_FIXUP
-       DEVMETHOD(bus_alloc_resource,   nexus_legacypci_alloc_resource),
-#else
-       DEVMETHOD(bus_alloc_resource,   bus_generic_alloc_resource),
-#endif
-       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),
-        DEVMETHOD(bus_set_resource,     bus_generic_set_resource),
-        DEVMETHOD(bus_get_resource,     bus_generic_get_resource),
-        DEVMETHOD(bus_delete_resource,  bus_generic_delete_resource),
-       { 0, 0 }
-};
-
-static driver_t legacypci_driver = {
-       "legacypci",
-       legacypci_methods,
-       1,
-};
-
-static devclass_t legacypci_devclass;
-
-DRIVER_MODULE(legacypci, nexus, legacypci_driver, legacypci_devclass, 0, 0);
-
-/*
- * Legacypci Host-Bridge PCI BUS support.  The underlying pcib devices
- * will only exist if we actually control the PCI bus.  The actual PCI
- * bus driver is attached in our attach routine.
- *
- * There is no identify function because the legacypci placeholder will
- * have already scanned and added PCIB devices for the host-bridges found.
- */
-static int
-nexus_pcib_maxslots(device_t dev)
-{
-       return 31;
-}
-
-/*
- * Read configuration space register.
- */
-static u_int32_t
-nexus_pcib_read_config(device_t dev, int bus, int slot, int func,
-                      int reg, int bytes)
-{
-       return (pci_cfgregread(bus, slot, func, reg, bytes));
+       bus = pcib_get_bus(dev);
+       if (pci_pir_probe(bus, 0)) {
+               pir = BUS_ADD_CHILD(device_get_parent(dev), device_get_parent(dev), 0, "pir", 0);
+               if (pir != NULL)
+                       device_probe_and_attach(pir);
+       }
+       device_add_child(dev, "pci", bus);
+       return bus_generic_attach(dev);
 }
 
-/*
- * Write configuration space register.
- */
-static void
-nexus_pcib_write_config(device_t dev, int bus, int slot, int func,
-                       int reg, u_int32_t data, int bytes)
+int
+legacy_pcib_read_ivar(device_t dev, device_t child, int which,
+    uintptr_t *result)
 {
-       pci_cfgregwrite(bus, slot, func, reg, data, bytes);
-}
 
-/*
- * Stack a pci device on top of the pci bridge bus device.
- */
-static int
-nexus_pcib_probe(device_t dev)
-{
-       BUS_ADD_CHILD(dev, dev, 0, "pci", device_get_unit(dev));
-       return (0);
+       switch (which) {
+       case  PCIB_IVAR_DOMAIN:
+               *result = 0;
+               return 0;
+       case  PCIB_IVAR_BUS:
+               *result = legacy_get_pcibus(dev);
+               return 0;
+       }
+       return ENOENT;
 }
 
-static int
-nexus_pcib_attach(device_t dev)
+int
+legacy_pcib_write_ivar(device_t dev, device_t child, int which,
+    uintptr_t value)
 {
-       int error;
 
-       error = bus_generic_attach(dev);
-       return (error);
+       switch (which) {
+       case  PCIB_IVAR_DOMAIN:
+               return EINVAL;
+       case  PCIB_IVAR_BUS:
+               legacy_set_pcibus(dev, value);
+               return 0;
+       }
+       return ENOENT;
 }
 
-/* route interrupt */
+SYSCTL_DECL(_hw_pci);
 
-static int
-nexus_pcib_route_interrupt(device_t pcib, device_t dev, int pin)
+static unsigned long legacy_host_mem_start = 0x80000000;
+TUNABLE_INT("hw.pci.host_mem_start", &legacy_host_mem_start);
+SYSCTL_ULONG(_hw_pci, OID_AUTO, host_mem_start, CTLFLAG_RD,
+    &legacy_host_mem_start, 0x80000000,
+    "Limit the host bridge memory to being above this address.  Must be\n\
+set at boot via a tunable.");
+
+struct resource *
+legacy_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
+    u_long start, u_long end, u_long count, u_int flags)
 {
-       return(pci_cfgintr(pci_get_bus(dev), pci_get_slot(dev), pin, 
-                          pci_get_irq(dev)));
+    /*
+     * If no memory preference is given, use upper 32MB slot most
+     * bioses use for their memory window.  Typically other bridges
+     * before us get in the way to assert their preferences on memory.
+     * Hardcoding like this sucks, so a more MD/MI way needs to be
+     * found to do it.  This is typically only used on older laptops
+     * that don't have pci busses behind pci bridge, so assuming > 32MB
+     * is liekly OK.
+     *
+     * However, this can cause problems for other chipsets, so we make
+     * this tunable by hw.pci.host_mem_start.
+     */
+    if (type == SYS_RES_MEMORY && start == 0UL && end == ~0UL)
+       start = legacy_host_mem_start;
+    if (type == SYS_RES_IOPORT && start == 0UL && end == ~0UL)
+       start = 0x1000;
+    return (bus_generic_alloc_resource(dev, child, type, rid, start, end,
+       count, flags));
 }
 
-static device_method_t nexus_pcib_methods[] = {
+static device_method_t legacy_pcib_methods[] = {
        /* Device interface */
-       DEVMETHOD(device_probe,         nexus_pcib_probe),
-       DEVMETHOD(device_attach,        nexus_pcib_attach),
+       DEVMETHOD(device_identify,      legacy_pcib_identify),
+       DEVMETHOD(device_probe,         legacy_pcib_probe),
+       DEVMETHOD(device_attach,        legacy_pcib_attach),
        DEVMETHOD(device_shutdown,      bus_generic_shutdown),
        DEVMETHOD(device_suspend,       bus_generic_suspend),
        DEVMETHOD(device_resume,        bus_generic_resume),
 
-       /*
-        * Bus interface - propogate through to the nexus.  Note
-        * that this means we will get nexus-managed ivars.
-        */
-       DEVMETHOD(bus_add_child,        bus_generic_add_child),
+       /* Bus interface */
        DEVMETHOD(bus_print_child,      bus_generic_print_child),
-       DEVMETHOD(bus_read_ivar,        bus_generic_read_ivar),
-       DEVMETHOD(bus_write_ivar,       bus_generic_write_ivar),
-       DEVMETHOD(bus_alloc_resource,   bus_generic_alloc_resource),
+       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),
@@ -599,86 +564,38 @@ static device_method_t nexus_pcib_methods[] = {
        DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
 
        /* pcib interface */
-       DEVMETHOD(pcib_maxslots,        nexus_pcib_maxslots),
-       DEVMETHOD(pcib_read_config,     nexus_pcib_read_config),
-       DEVMETHOD(pcib_write_config,    nexus_pcib_write_config),
-       DEVMETHOD(pcib_route_interrupt, nexus_pcib_route_interrupt),
-
+       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, pcibios_pcib_route_interrupt),
+#ifdef notyet
+       DEVMETHOD(pcib_alloc_msi,       legacy_pcib_alloc_msi),
+       DEVMETHOD(pcib_release_msi,     pcib_release_msi),
+       DEVMETHOD(pcib_alloc_msix,      legacy_pcib_alloc_msix),
+       DEVMETHOD(pcib_release_msix,    pcib_release_msix),
+       DEVMETHOD(pcib_map_msi,         legacy_pcib_map_msi),
+#endif
        { 0, 0 }
 };
 
-static driver_t nexus_pcib_driver = {
-       "pcib",
-       nexus_pcib_methods,
-       1,
-};
+static devclass_t hostb_devclass;
 
-static devclass_t      pcib_devclass;
-
-DRIVER_MODULE(pcib, legacypci, nexus_pcib_driver, pcib_devclass, 0, 0);
-
-
-/*
- * Provide a device to "eat" the host->pci bridges that we dug up above
- * and stop them showing up twice on the probes.  This also stops them
- * showing up as 'none' in pciconf -l.
- *
- * Return an ultra-low priority so other devices can attach the bus before
- * our dummy attach.
- *
- * XXX may have to disable the registration entirely to support module-loaded
- * bridges such as agp.ko.
- */
-static int
-pci_hostb_probe(device_t dev)
-{
-       if (pci_get_class(dev) == PCIC_BRIDGE &&
-           pci_get_subclass(dev) == PCIS_BRIDGE_HOST) {
-               device_set_desc(dev, "Host to PCI bridge");
-               device_quiet(dev);
-               return -10000;
-       }
-       return (ENXIO);
-}
-
-static int
-pci_hostb_attach(device_t dev)
-{
-       return (0);
-}
-
-static device_method_t pci_hostb_methods[] = {
-       /* Device interface */
-       DEVMETHOD(device_probe,         pci_hostb_probe),
-       DEVMETHOD(device_attach,        pci_hostb_attach),
-       DEVMETHOD(device_shutdown,      bus_generic_shutdown),
-       DEVMETHOD(device_suspend,       bus_generic_suspend),
-       DEVMETHOD(device_resume,        bus_generic_resume),
-
-       { 0, 0 }
-};
-static driver_t pci_hostb_driver = {
-       "hostb",
-       pci_hostb_methods,
-       1,
-};
-static devclass_t pci_hostb_devclass;
-
-DRIVER_MODULE(hostb, pci, pci_hostb_driver, pci_hostb_devclass, 0, 0);
+DEFINE_CLASS_0(pcib, legacy_pcib_driver, legacy_pcib_methods, 1);
+DRIVER_MODULE(pcib, legacy, legacy_pcib_driver, hostb_devclass, 0, 0);
 
 
 /*
  * Install placeholder to claim the resources owned by the
- * PCI bus interface.  This could be used to extract the 
+ * PCI bus interface.  This could be used to extract the
  * config space registers in the extreme case where the PnP
  * ID is available and the PCI BIOS isn't, but for now we just
  * eat the PnP ID and do nothing else.
  *
- * XXX we should silence this probe, as it will generally confuse 
+ * XXX we should silence this probe, as it will generally confuse
  * people.
  */
 static struct isa_pnp_id pcibus_pnp_ids[] = {
-       { 0x030ad041 /* PNP030A */, "PCI Bus" },
+       { 0x030ad041 /* PNP0A03 */, "PCI Bus" },
        { 0 }
 };
 
@@ -686,10 +603,10 @@ static int
 pcibus_pnp_probe(device_t dev)
 {
        int result;
-       
+
        if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, pcibus_pnp_ids)) <= 0)
                device_quiet(dev);
-       return (result);
+       return(result);
 }
 
 static int
@@ -709,13 +626,78 @@ static device_method_t pcibus_pnp_methods[] = {
        { 0, 0 }
 };
 
-static driver_t pcibus_pnp_driver = {
-       "pcibus_pnp",
-       pcibus_pnp_methods,
-       1,              /* no softc */
-};
-
 static devclass_t pcibus_pnp_devclass;
 
+DEFINE_CLASS_0(pcibus_pnp, pcibus_pnp_driver, pcibus_pnp_methods, 1);
 DRIVER_MODULE(pcibus_pnp, isa, pcibus_pnp_driver, pcibus_pnp_devclass, 0, 0);
 
+
+/*
+ * Provide a PCI-PCI bridge driver for PCI busses behind PCI-PCI bridges
+ * that appear in the PCIBIOS Interrupt Routing Table to use the routing
+ * table for interrupt routing when possible.
+ */
+static int     pcibios_pcib_probe(device_t bus);
+
+static device_method_t pcibios_pcib_pci_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_probe,         pcibios_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, pcibios_pcib_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, pcibios_pcib_driver, pcibios_pcib_pci_methods,
+    sizeof(struct pcib_softc));
+DRIVER_MODULE(pcibios_pcib, pci, pcibios_pcib_driver, pcib_devclass, 0, 0);
+
+static int
+pcibios_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);
+       if (!pci_pir_probe(bus, 1))
+               return (ENXIO);
+       device_set_desc(dev, "PCIBIOS PCI-PCI bridge");
+       return (-2000);
+}
+
+static int
+pcibios_pcib_route_interrupt(device_t pcib, device_t dev, int pin)
+{
+       return (pci_pir_route_interrupt(pci_get_bus(dev), pci_get_slot(dev),
+               pci_get_function(dev), pin));
+}
index 137d0fd..ec81352 100644 (file)
@@ -1,7 +1,8 @@
-/*
- * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
- * Copyright (c) 2000, Michael Smith <msmith@freebsd.org>
+/*-
+ * Copyright (c) 1997, Stefan Esser <se@kfreebsd.org>
+ * Copyright (c) 2000, Michael Smith <msmith@kfreebsd.org>
  * Copyright (c) 2000, BSDi
+ * Copyright (c) 2004, Scott Long <scottl@kfreebsd.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * 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: src/sys/i386/isa/pci_cfgreg.c,v 1.1.2.7 2001/11/28 05:47:03 imp Exp $
- * $DragonFly: src/sys/bus/pci/i386/pci_cfgreg.c,v 1.15 2008/08/02 05:22:20 dillon Exp $
- *
+ * __FBSDID("$FreeBSD: src/sys/i386/pci/pci_cfgreg.c,v 1.124.2.2.6.1 2009/04/15 03:14:26 kensmith Exp $");
  */
 
-#include <sys/param.h>         /* XXX trim includes */
+#if defined(__DragonFly__)
+#define mtx_init(a, b, c, d) spin_init(a)
+#define mtx_lock_spin(a) spin_lock_wr(a)
+#define mtx_unlock_spin(a) spin_unlock_wr(a)
+#endif
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/bus.h>
-#include <sys/kernel.h>
-#include <sys/module.h>
+#include <sys/lock.h>
 #include <sys/malloc.h>
-#include <sys/sysctl.h>
-#include <vm/vm.h>
-#include <vm/pmap.h>
-#include <machine/md_var.h>
-#include <machine/clock.h>
+#include <sys/thread2.h>
+#include <sys/spinlock.h>
+#include <sys/spinlock2.h>
+#include <sys/queue.h>
 #include <bus/pci/pcivar.h>
 #include <bus/pci/pcireg.h>
-#include <bus/isa/isavar.h>
 #include "pci_cfgreg.h"
-#include <machine/segments.h>
 #include <machine/pc/bios.h>
-#include <machine/smp.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_extern.h>
+#include <vm/pmap.h>
+#include <machine/pmap.h>
 
 #define PRVERB(a) do {                                                 \
        if (bootverbose)                                                \
                kprintf a ;                                             \
 } while(0)
 
-static int pci_disable_bios_route = 0;
-SYSCTL_INT(_hw, OID_AUTO, pci_disable_bios_route, CTLFLAG_RD,
-       &pci_disable_bios_route, 0, "disable interrupt routing via PCI-BIOS");
-TUNABLE_INT("hw.pci_disable_bios_route", &pci_disable_bios_route);
-
+#define PCIE_CACHE 8
+struct pcie_cfg_elem {
+       TAILQ_ENTRY(pcie_cfg_elem)      elem;
+       vm_offset_t     vapage;
+       vm_paddr_t      papage;
+};
+
+enum {
+       CFGMECH_NONE = 0,
+       CFGMECH_1,
+       CFGMECH_2,
+       CFGMECH_PCIE,
+};
+
+static TAILQ_HEAD(pcie_cfg_list, pcie_cfg_elem) pcie_list[MAXCPU];
+static uint32_t pciebar;
 static int cfgmech;
 static int devmax;
+#if defined(__DragonFly__)
+static struct spinlock pcicfg_mtx;
+#else
+static struct mtx pcicfg_mtx;
+#endif
 
-static int     pci_cfgintr_valid(struct PIR_entry *pe, int pin, int irq);
-static int     pci_cfgintr_unique(struct PIR_entry *pe, int pin);
-static int     pci_cfgintr_linked(struct PIR_entry *pe, int pin);
-static int     pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin);
-static int     pci_cfgintr_virgin(struct PIR_entry *pe, int pin);
-
-static void    pci_print_irqmask(u_int16_t irqs);
-static void    pci_print_route_table(struct PIR_table *prt, int size);
 static int     pcireg_cfgread(int bus, int slot, int func, int reg, int bytes);
 static void    pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
 static int     pcireg_cfgopen(void);
 
-static struct PIR_table        *pci_route_table;
-static int             pci_route_count;
+static int     pciereg_cfgopen(void);
+static int     pciereg_cfgread(int bus, int slot, int func, int reg,
+                               int bytes);
+static void    pciereg_cfgwrite(int bus, int slot, int func, int reg,
+                                int data, int bytes);
 
 /*
  * Some BIOS writers seem to want to ignore the spec and put
- * 0 in the intline rather than 255 to indicate none. Some use
+ * 0 in the intline rather than 255 to indicate none.  Some use
  * numbers in the range 128-254 to indicate something strange and
- * apparently undocumented anywhere. Assume these are completely bogus
+ * apparently undocumented anywhere.  Assume these are completely bogus
  * and map them to 255, which means "none".
  */
-static int
-pci_map_intline(int line)
+static __inline int 
+pci_i386_map_intline(int line)
 {
        if (line == 0 || line >= 128)
                return (PCI_INVALID_IRQ);
@@ -120,57 +139,47 @@ int
 pci_cfgregopen(void)
 {
        static int              opened = 0;
-       u_long                  sigaddr;
-       static struct PIR_table *pt;
+       u_int16_t               vid, did;
        u_int16_t               v;
-       u_int8_t                ck, *cv;
-       int                     i;
-
        if (opened)
-               return (1);
+               return(1);
 
        if (pcireg_cfgopen() == 0)
-               return (0);
+               return(0);
 
        v = pcibios_get_version();
        if (v > 0)
-               kprintf("pcibios: BIOS version %x.%02x\n", (v & 0xff00) >> 8,
-                      v & 0xff);
+               PRVERB(("pcibios: BIOS version %x.%02x\n", (v & 0xff00) >> 8,
+                   v & 0xff));
+       mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN);
+       opened = 1;
+
+       /* $PIR requires PCI BIOS 2.10 or greater. */
+       if (v >= 0x0210)
+               pci_pir_open();
 
        /*
-        * Look for the interrupt routing table.
-        *
-        * We use PCI BIOS's PIR table if it's available $PIR is the
-        * standard way to do this.  Sadly some machines are not
-        * standards conforming and have _PIR instead. We shrug and cope
-        * by looking for both.
+        * Grope around in the PCI config space to see if this is a
+        * chipset that is capable of doing memory-mapped config cycles.
+        * This also implies that it can do PCIe extended config cycles.
         */
-       if (pcibios_get_version() >= 0x0210 && pt == NULL) {
-               sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0);
-               if (sigaddr == 0)
-                       sigaddr = bios_sigsearch(0, "_PIR", 4, 16, 0);
-               if (sigaddr != 0) {
-                       pt = (struct PIR_table *)(uintptr_t)
-                            BIOS_PADDRTOVADDR(sigaddr);
-                       for (cv = (u_int8_t *)pt, ck = 0, i = 0;
-                            i < (pt->pt_header.ph_length); i++)
-                               ck += cv[i];
-                       if (ck == 0 && pt->pt_header.ph_length >
-                           sizeof(struct PIR_header)) {
-                               pci_route_table = pt;
-                               pci_route_count = (pt->pt_header.ph_length -
-                                   sizeof(struct PIR_header)) /
-                                   sizeof(struct PIR_entry);
-                               kprintf("Using $PIR table, %d entries at %p\n",
-                                      pci_route_count, pci_route_table);
-                               if (bootverbose)
-                                       pci_print_route_table(pci_route_table,
-                                           pci_route_count);
-                       }
+
+       /* Check for supported chipsets */
+       vid = pci_cfgregread(0, 0, 0, PCIR_VENDOR, 2);
+       did = pci_cfgregread(0, 0, 0, PCIR_DEVICE, 2);
+       if (vid == 0x8086) {
+               if (did == 0x3590 || did == 0x3592) {
+                       /* Intel 7520 or 7320 */
+                       pciebar = pci_cfgregread(0, 0, 0, 0xce, 2) << 16;
+                       pciereg_cfgopen();
+               } else if (did == 0x2580 || did == 0x2584) {
+                       /* Intel 915 or 925 */
+                       pciebar = pci_cfgregread(0, 0, 0, 0x48, 4);
+                       pciereg_cfgopen();
                }
        }
-       opened = 1;
-       return (1);     
+
+       return(1);
 }
 
 /* 
@@ -180,58 +189,16 @@ 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
         * the code uses 255 as an invalid IRQ.
         */
        if (reg == PCIR_INTLINE && bytes == 1) {
                line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1);
-               return pci_map_intline(line);
+               return (pci_i386_map_intline(line));
        }
-#endif /* APIC_IO */
        return (pcireg_cfgread(bus, slot, func, reg, bytes));
 }
 
@@ -241,381 +208,52 @@ pci_cfgregread(int bus, int slot, int func, int reg, int bytes)
 void
 pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes)
 {
-       pcireg_cfgwrite(bus, slot, func, reg, data, bytes);
-}
-
-int
-pci_cfgread(pcicfgregs *cfg, int reg, int bytes)
-{
-       return (pci_cfgregread(cfg->bus, cfg->slot, cfg->func, reg, bytes));
-}
 
-void
-pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes)
-{
-       pci_cfgregwrite(cfg->bus, cfg->slot, cfg->func, reg, data, bytes);
+       pcireg_cfgwrite(bus, slot, func, reg, data, bytes);
 }
 
-
-/*
- * Route a PCI interrupt
+/* 
+ * Configuration space access using direct register operations
  */
-int
-pci_cfgintr(int bus, int device, int pin, int oldirq)
-{
-       struct PIR_entry        *pe;
-       int                     i, irq;
-       struct bios_regs        args;
-       u_int16_t               v;
 
-       int already = 0;
-       int errok = 0;
-    
-       v = pcibios_get_version();
-       if (v < 0x0210) {
-               PRVERB((
-                 "pci_cfgintr: BIOS %x.%02x doesn't support interrupt routing\n",
-                 (v & 0xff00) >> 8, v & 0xff));
-               return (PCI_INVALID_IRQ);
-       }
-       if ((bus < 0) || (bus > 255) || (device < 0) || (device > 255) ||
-           (pin < 1) || (pin > 4))
-               return (PCI_INVALID_IRQ);
-
-       /*
-        * Scan the entry table for a contender
-        */
-       for (i = 0, pe = &pci_route_table->pt_entry[0]; i < pci_route_count;
-            i++, pe++) {
-               if ((bus != pe->pe_bus) || (device != pe->pe_device))
-                       continue;
+/* enable configuration space accesses and return data port address */
+static int
+pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
+{
+       int dataport = 0;
 
+#ifdef XBOX
+       if (arch_i386_is_xbox) {
                /*
-                * A link of 0 means that this intpin is not connected to
-                * any other device's interrupt pins and is not connected to
-                * any of the Interrupt Router's interrupt pins, so we can't
-                * route it.
+                * The Xbox MCPX chipset is a derivative of the nForce 1
+                * chipset. It almost has the same bus layout; some devices
+                * cannot be used, because they have been removed.
                 */
-               if (pe->pe_intpin[pin - 1].link == 0)
-                       continue;
-
-               if (pci_cfgintr_valid(pe, pin, oldirq)) {
-                       kprintf("pci_cfgintr: %d:%d INT%c BIOS irq %d\n", bus,
-                              device, 'A' + pin - 1, oldirq);
-                       return (oldirq);
-               }
 
                /*
-                * We try to find a linked interrupt, then we look to see
-                * if the interrupt is uniquely routed, then we look for
-                * a virgin interrupt. The virgin interrupt should return
-                * an interrupt we can route, but if that fails, maybe we
-                * should try harder to route a different interrupt.
-                * However, experience has shown that that's rarely the
-                * failure mode we see.
+                * Devices 00:00.1 and 00:00.2 used to be memory controllers on
+                * the nForce chipset, but on the Xbox, using them will lockup
+                * the chipset.
                 */
-               irq = pci_cfgintr_linked(pe, pin);
-               if (irq != PCI_INVALID_IRQ)
-                       already = 1;
-               if (irq == PCI_INVALID_IRQ) {
-                       irq = pci_cfgintr_unique(pe, pin);
-                       if (irq != PCI_INVALID_IRQ)
-                               errok = 1;
-               }
-               if (irq == PCI_INVALID_IRQ)
-                       irq = pci_cfgintr_virgin(pe, pin);
-
-               if (irq == PCI_INVALID_IRQ)
-                       break;
-
-               if (pci_disable_bios_route != 0)
-                       break;
+               if (bus == 0 && slot == 0 && (func == 1 || func == 2))
+                       return dataport;
+               
                /*
-                * Ask the BIOS to route the interrupt. If we picked an
-                * interrupt that failed, we should really try other
-                * choices that the BIOS offers us.
-                *
-                * For uniquely routed interrupts, we need to try
-                * to route them on some machines. Yet other machines
-                * fail to route, so we have to pretend that in that
-                * case it worked.  Isn't PC hardware fun?
-                *
-                * NOTE: if we want to whack hardware to do this, then
-                * I think the right way to do that would be to have
-                * bridge drivers that do this. I'm not sure that the
-                * $PIR table would be valid for those interrupt
-                * routers.
+                * Bus 1 only contains a VGA controller at 01:00.0. When you try
+                * to probe beyond that device, you only get garbage, which
+                * could cause lockups.
                 */
-               args.eax = PCIBIOS_ROUTE_INTERRUPT;
-               args.ebx = (bus << 8) | (device << 3);
-               /* pin value is 0xa - 0xd */
-               args.ecx = (irq << 8) | (0xa + pin -1);
-               if (!already &&
-                   bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)) &&
-                   !errok) {
-                       PRVERB(("pci_cfgintr: ROUTE_INTERRUPT failed.\n"));
-                       return (PCI_INVALID_IRQ);
-               }
-               kprintf("pci_cfgintr: %d:%d INT%c routed to irq %d\n", bus,
-                      device, 'A' + pin - 1, irq);
-               return(irq);
-       }
-
-       PRVERB(("pci_cfgintr: can't route an interrupt to %d:%d INT%c oldirq=%d\n", bus,
-              device, 'A' + pin - 1, oldirq));
-       return (PCI_INVALID_IRQ);
-}
-
-/*
- * Check to see if an existing IRQ setting is valid.
- */
-static int
-pci_cfgintr_valid(struct PIR_entry *pe, int pin, int irq)
-{
-       uint32_t irqmask;
-
-       if (!PCI_INTERRUPT_VALID(irq))
-               return (0);
-       irqmask = pe->pe_intpin[pin - 1].irqs;
-       if (irqmask & (1 << irq)) {
-               PRVERB(("pci_cfgintr_valid: BIOS irq %d is valid\n", irq));
-               return (1);
-       }
-       return (0);
-}
-
-/*
- * Look to see if the routing table claims this pin is uniquely routed.
- */
-static int
-pci_cfgintr_unique(struct PIR_entry *pe, int pin)
-{
-       int             irq;
-       uint32_t        irqmask;
-
-       irqmask = pe->pe_intpin[pin - 1].irqs;
-       if(irqmask != 0 && powerof2(irqmask)) {
-               irq = ffs(irqmask) - 1;
-               PRVERB(("pci_cfgintr_unique: hard-routed to irq %d\n", irq));
-               return (irq);
-       }
-       return (PCI_INVALID_IRQ);
-}
-
-/*
- * Look for another device which shares the same link byte and
- * already has a unique IRQ, or which has had one routed already.
- */
-static int
-pci_cfgintr_linked(struct PIR_entry *pe, int pin)
-{
-       struct PIR_entry        *oe;
-       struct PIR_intpin       *pi;
-       int                     i, j, irq;
-
-       /*
-        * Scan table slots.
-        */
-       for (i = 0, oe = &pci_route_table->pt_entry[0]; i < pci_route_count;
-            i++, oe++) {
-               /* scan interrupt pins */
-               for (j = 0, pi = &oe->pe_intpin[0]; j < 4; j++, pi++) {
-
-                       /* don't look at the entry we're trying to match */
-                       if ((pe == oe) && (j == (pin - 1)))
-                               continue;
-                       /* compare link bytes */
-                       if (pi->link != pe->pe_intpin[pin - 1].link)
-                               continue;
-                       /* link destination mapped to a unique interrupt? */
-                       if (pi->irqs != 0 && powerof2(pi->irqs)) {
-                               irq = ffs(pi->irqs) - 1;
-                               PRVERB(("pci_cfgintr_linked: linked (%x) to hard-routed irq %d\n",
-                                      pi->link, irq));
-                               return(irq);
-                       } 
-
-                       /*
-                        * look for the real PCI device that matches this
-                        * table entry
-                        */
-                       irq = pci_cfgintr_search(pe, oe->pe_bus, oe->pe_device,
-                                                j + 1, pin);
-                       if (irq != PCI_INVALID_IRQ)
-                               return (irq);
-               }
-       }
-       return (PCI_INVALID_IRQ);
-}
-
-/*
- * Scan for the real PCI device at (bus)/(device) using intpin (matchpin) and
- * see if it has already been assigned an interrupt.
- */
-static int
-pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin)
-{
-       devclass_t              pci_devclass;
-       device_t                *pci_devices;
-       int                     pci_count;
-       device_t                *pci_children;
-       int                     pci_childcount;
-       device_t                *busp, *childp;
-       int                     i, j, irq;
-
-       /*
-        * Find all the PCI busses.
-        */
-       pci_count = 0;
-       if ((pci_devclass = devclass_find("pci")) != NULL)
-               devclass_get_devices(pci_devclass, &pci_devices, &pci_count);
-
-       /*
-        * Scan all the PCI busses/devices looking for this one.
-        */
-       irq = PCI_INVALID_IRQ;
-       for (i = 0, busp = pci_devices; (i < pci_count) && (irq == PCI_INVALID_IRQ);
-            i++, busp++) {
-               pci_childcount = 0;
-               device_get_children(*busp, &pci_children, &pci_childcount);
+               if (bus == 1 && (slot != 0 || func != 0))
+                       return dataport;
                
-               for (j = 0, childp = pci_children; j < pci_childcount; j++,
-                    childp++) {
-                       if ((pci_get_bus(*childp) == bus) &&
-                           (pci_get_slot(*childp) == device) &&
-                           (pci_get_intpin(*childp) == matchpin)) {
-                               irq = pci_map_intline(pci_get_irq(*childp));
-                               if (irq != PCI_INVALID_IRQ)
-                                       PRVERB(("pci_cfgintr_search: linked (%x) to configured irq %d at %d:%d:%d\n",
-                                           pe->pe_intpin[pin - 1].link, irq,
-                                           pci_get_bus(*childp),
-                                           pci_get_slot(*childp),
-                                           pci_get_function(*childp)));
-                               break;
-                       }
-               }
-               if (pci_children != NULL)
-                       kfree(pci_children, M_TEMP);
-       }
-       if (pci_devices != NULL)
-               kfree(pci_devices, M_TEMP);
-       return (irq);
-}
-
-/*
- * Pick a suitable IRQ from those listed as routable to this device.
- */
-static int
-pci_cfgintr_virgin(struct PIR_entry *pe, int pin)
-{
-       int irq, ibit;
-    
-       /*
-        * first scan the set of PCI-only interrupts and see if any of these
-        * are routable
-        */
-       for (irq = 0; irq < 16; irq++) {
-               ibit = (1 << irq);
-
-               /* can we use this interrupt? */
-               if ((pci_route_table->pt_header.ph_pci_irqs & ibit) &&
-                   (pe->pe_intpin[pin - 1].irqs & ibit)) {
-                       PRVERB(("pci_cfgintr_virgin: using routable PCI-only interrupt %d\n", irq));
-                       return (irq);
-               }
-       }
-    
-       /* life is tough, so just pick an interrupt */
-       for (irq = 0; irq < 16; irq++) {
-               ibit = (1 << irq);
-    
-               if (pe->pe_intpin[pin - 1].irqs & ibit) {
-                       PRVERB(("pci_cfgintr_virgin: using routable interrupt %d\n", irq));
-                       return (irq);
-               }
-       }
-       return (PCI_INVALID_IRQ);
-}
-
-static void
-pci_print_irqmask(u_int16_t irqs)
-{
-       int i, first;
-
-       if (irqs == 0) {
-               kprintf("none");
-               return;
-       }
-       first = 1;
-       for (i = 0; i < 16; i++, irqs >>= 1)
-               if (irqs & 1) {
-                       if (!first)
-                               kprintf(" ");
-                       else
-                               first = 0;
-                       kprintf("%d", i);
-               }
-}
-
-/*
- * Dump the contents of a PCI BIOS Interrupt Routing Table to the console.
- */
-static void
-pci_print_route_table(struct PIR_table *ptr, int size)
-{
-       struct PIR_entry *entry;
-       struct PIR_intpin *intpin;
-       int i, pin;
-
-       kprintf("PCI-Only Interrupts: ");
-       pci_print_irqmask(ptr->pt_header.ph_pci_irqs);
-       kprintf("\nLocation  Bus Device Pin  Link  IRQs\n");
-       entry = &ptr->pt_entry[0];
-       for (i = 0; i < size; i++, entry++) {
-               intpin = &entry->pe_intpin[0];
-               for (pin = 0; pin < 4; pin++, intpin++)
-                       if (intpin->link != 0) {
-                               if (entry->pe_slot == 0)
-                                       kprintf("embedded ");
-                               else
-                                       kprintf("slot %-3d ", entry->pe_slot);
-                               kprintf(" %3d  %3d    %c   0x%02x  ",
-                                      entry->pe_bus, entry->pe_device,
-                                      'A' + pin, intpin->link);
-                               pci_print_irqmask(intpin->irqs);
-                               kprintf("\n");
-                       }
+               /*
+                * Bus 2 used to contain the AGP controller, but the Xbox MCPX
+                * doesn't have one. Probing it can cause lockups.
+                */
+               if (bus >= 2)
+                       return dataport;
        }
-}
-
-/*
- * See if any interrupts for a given PCI bus are routed in the PIR.  Don't
- * even bother looking if the BIOS doesn't support routing anyways.
- */
-int
-pci_probe_route_table(int bus)
-{
-       int i;
-       u_int16_t v;
-
-       v = pcibios_get_version();
-       if (v < 0x0210)
-               return (0);
-       for (i = 0; i < pci_route_count; i++)
-               if (pci_route_table->pt_entry[i].pe_bus == bus)
-                       return (1);
-       return (0);
-}
-
-/* 
- * Configuration space access using direct register operations
- */
-
-/* enable configuration space accesses and return data port address */
-static int
-pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
-{
-       int dataport = 0;
+#endif
 
        if (bus <= PCI_BUSMAX
            && slot < devmax
@@ -625,13 +263,13 @@ pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
            && (unsigned) bytes <= 4
            && (reg & (bytes - 1)) == 0) {
                switch (cfgmech) {
-               case 1:
+               case CFGMECH_1:
                        outl(CONF1_ADDR_PORT, (1 << 31)
-                            | (bus << 16) | (slot << 11) 
-                            | (func << 8) | (reg & ~0x03));
+                           | (bus << 16) | (slot << 11) 
+                           | (func << 8) | (reg & ~0x03));
                        dataport = CONF1_DATA_PORT + (reg & 0x03);
                        break;
-               case 2:
+               case CFGMECH_2:
                        outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
                        outb(CONF2_FORWARD_PORT, bus);
                        dataport = 0xc000 | (slot << 8) | reg;
@@ -646,12 +284,16 @@ static void
 pci_cfgdisable(void)
 {
        switch (cfgmech) {
-       case 1:
-               outl(CONF1_ADDR_PORT, 0);
+       case CFGMECH_1:
+               /*
+                * Do nothing for the config mechanism 1 case.
+                * Writing a 0 to the address port can apparently
+                * confuse some bridges and cause spurious
+                * access failures.
+                */
                break;
-       case 2:
+       case CFGMECH_2:
                outb(CONF2_ENABLE_PORT, 0);
-               outb(CONF2_FORWARD_PORT, 0);
                break;
        }
 }
@@ -662,6 +304,12 @@ pcireg_cfgread(int bus, int slot, int func, int reg, int bytes)
        int data = -1;
        int port;
 
+       if (cfgmech == CFGMECH_PCIE) {
+               data = pciereg_cfgread(bus, slot, func, reg, bytes);
+               return (data);
+       }
+
+       mtx_lock_spin(&pcicfg_mtx);
        port = pci_cfgenable(bus, slot, func, reg, bytes);
        if (port != 0) {
                switch (bytes) {
@@ -677,6 +325,7 @@ pcireg_cfgread(int bus, int slot, int func, int reg, int bytes)
                }
                pci_cfgdisable();
        }
+       mtx_unlock_spin(&pcicfg_mtx);
        return (data);
 }
 
@@ -685,6 +334,12 @@ pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
 {
        int port;
 
+       if (cfgmech == CFGMECH_PCIE) {
+               pciereg_cfgwrite(bus, slot, func, reg, data, bytes);
+               return;
+       }
+
+       mtx_lock_spin(&pcicfg_mtx);
        port = pci_cfgenable(bus, slot, func, reg, bytes);
        if (port != 0) {
                switch (bytes) {
@@ -700,6 +355,7 @@ pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
                }
                pci_cfgdisable();
        }
+       mtx_unlock_spin(&pcicfg_mtx);
 }
 
 /* check whether the configuration mechanism has been correctly identified */
@@ -753,59 +409,58 @@ pci_cfgcheck(int maxdev)
 static int
 pcireg_cfgopen(void)
 {
-       uint32_t mode1res,oldval1;
-       uint8_t mode2res,oldval2;
+       uint32_t mode1res, oldval1;
+       uint8_t mode2res, oldval2;
 
+       /* Check for type #1 first. */
        oldval1 = inl(CONF1_ADDR_PORT);
 
        if (bootverbose) {
                kprintf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08x\n",
-                      oldval1);
+                   oldval1);
        }
 
-       if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
-
-               cfgmech = 1;
-               devmax = 32;
+       cfgmech = CFGMECH_1;
+       devmax = 32;
 
-               outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
-               DELAY(1);
-               mode1res = inl(CONF1_ADDR_PORT);
-               outl(CONF1_ADDR_PORT, oldval1);
+       outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
+       DELAY(1);
+       mode1res = inl(CONF1_ADDR_PORT);
+       outl(CONF1_ADDR_PORT, oldval1);
 
-               if (bootverbose)
-                       kprintf("pci_open(1a):\tmode1res=0x%08x (0x%08lx)\n", 
-                              mode1res, CONF1_ENABLE_CHK);
+       if (bootverbose)
+               kprintf("pci_open(1a):\tmode1res=0x%08x (0x%08lx)\n",  mode1res,
+                   CONF1_ENABLE_CHK);
 
-               if (mode1res) {
-                       if (pci_cfgcheck(32)) 
-                               return (cfgmech);
-               }
+       if (mode1res) {
+               if (pci_cfgcheck(32)) 
+                       return (cfgmech);
+       }
 
-               outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
-               mode1res = inl(CONF1_ADDR_PORT);
-               outl(CONF1_ADDR_PORT, oldval1);
+       outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
+       mode1res = inl(CONF1_ADDR_PORT);
+       outl(CONF1_ADDR_PORT, oldval1);
 
-               if (bootverbose)
-                       kprintf("pci_open(1b):\tmode1res=0x%08x (0x%08lx)\n", 
-                              mode1res, CONF1_ENABLE_CHK1);
+       if (bootverbose)
+               kprintf("pci_open(1b):\tmode1res=0x%08x (0x%08lx)\n",  mode1res,
+                   CONF1_ENABLE_CHK1);
 
-               if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
-                       if (pci_cfgcheck(32)) 
-                               return (cfgmech);
-               }
+       if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
+               if (pci_cfgcheck(32)) 
+                       return (cfgmech);
        }
 
+       /* Type #1 didn't work, so try type #2. */
        oldval2 = inb(CONF2_ENABLE_PORT);
 
        if (bootverbose) {
                kprintf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
-                      oldval2);
+                   oldval2);
        }
 
        if ((oldval2 & 0xf0) == 0) {
 
-               cfgmech = 2;
+               cfgmech = CFGMECH_2;
                devmax = 16;
 
                outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
@@ -813,8 +468,8 @@ pcireg_cfgopen(void)
                outb(CONF2_ENABLE_PORT, oldval2);
 
                if (bootverbose)
-                       kprintf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 
-                              mode2res, CONF2_ENABLE_CHK);
+                       kprintf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n",
+                           mode2res, CONF2_ENABLE_CHK);
 
                if (mode2res == CONF2_ENABLE_RES) {
                        if (bootverbose)
@@ -825,7 +480,165 @@ pcireg_cfgopen(void)
                }
        }
 
-       cfgmech = 0;
+       /* Nothing worked, so punt. */
+       cfgmech = CFGMECH_NONE;
        devmax = 0;
        return (cfgmech);
 }
+
+static int
+pciereg_cfgopen(void)
+{
+#ifdef PCIE_CFG_MECH
+       struct pcie_cfg_list *pcielist;
+       struct pcie_cfg_elem *pcie_array, *elem;
+#ifdef SMP
+       struct pcpu *pc;
+#endif
+       vm_offset_t va;
+       int i;
+
+       if (bootverbose)
+               kprintf("Setting up PCIe mappings for BAR 0x%x\n", pciebar);
+
+#ifdef SMP
+       SLIST_FOREACH(pc, &cpuhead, pc_allcpu)
+#endif
+       {
+
+               pcie_array = kmalloc(sizeof(struct pcie_cfg_elem) * PCIE_CACHE,
+                   M_DEVBUF, M_NOWAIT);
+               if (pcie_array == NULL)
+                       return (0);
+
+               va = kmem_alloc_nofault(&kernel_map, PCIE_CACHE * PAGE_SIZE);
+               if (va == 0) {
+                       kfree(pcie_array, M_DEVBUF);
+                       return (0);
+               }
+
+#ifdef SMP
+               pcielist = &pcie_list[pc->pc_cpuid];
+#else
+               pcielist = &pcie_list[0];
+#endif
+               TAILQ_INIT(pcielist);
+               for (i = 0; i < PCIE_CACHE; i++) {
+                       elem = &pcie_array[i];
+                       elem->vapage = va + (i * PAGE_SIZE);
+                       elem->papage = 0;
+                       TAILQ_INSERT_HEAD(pcielist, elem, elem);
+               }
+       }
+
+       
+       cfgmech = CFGMECH_PCIE;
+       devmax = 32;
+       return (1);
+#else  /* !PCIE_CFG_MECH */
+       return (0);
+#endif /* PCIE_CFG_MECH */
+}
+
+#define PCIE_PADDR(bar, reg, bus, slot, func)  \
+       ((bar)                          |       \
+       (((bus) & 0xff) << 20)          |       \
+       (((slot) & 0x1f) << 15)         |       \
+       (((func) & 0x7) << 12)          |       \
+       ((reg) & 0xfff))
+
+/*
+ * Find an element in the cache that matches the physical page desired, or
+ * create a new mapping from the least recently used element.
+ * A very simple LRU algorithm is used here, does it need to be more
+ * efficient?
+ */
+static __inline struct pcie_cfg_elem *
+pciereg_findelem(vm_paddr_t papage)
+{
+       struct pcie_cfg_list *pcielist;
+       struct pcie_cfg_elem *elem;
+       pcielist = &pcie_list[mycpuid];
+       TAILQ_FOREACH(elem, pcielist, elem) {
+               if (elem->papage == papage)
+                       break;
+       }
+
+       if (elem == NULL) {
+               elem = TAILQ_LAST(pcielist, pcie_cfg_list);
+               if (elem->papage != 0) {
+                       pmap_kremove(elem->vapage);
+                       cpu_invlpg(&elem->vapage);
+               }
+               pmap_kenter(elem->vapage, papage);
+               elem->papage = papage;
+       }
+
+       if (elem != TAILQ_FIRST(pcielist)) {
+               TAILQ_REMOVE(pcielist, elem, elem);
+               TAILQ_INSERT_HEAD(pcielist, elem, elem);
+       }
+       return (elem);
+}
+
+static int
+pciereg_cfgread(int bus, int slot, int func, int reg, int bytes)
+{
+       struct pcie_cfg_elem *elem;
+       volatile vm_offset_t va;
+       vm_paddr_t pa, papage;
+       int data;
+
+       crit_enter();
+       pa = PCIE_PADDR(pciebar, reg, bus, slot, func);
+       papage = pa & ~PAGE_MASK;
+       elem = pciereg_findelem(papage);
+       va = elem->vapage | (pa & PAGE_MASK);
+
+       switch (bytes) {
+       case 4:
+               data = *(volatile uint32_t *)(va);
+               break;
+       case 2:
+               data = *(volatile uint16_t *)(va);
+               break;
+       case 1:
+               data = *(volatile uint8_t *)(va);
+               break;
+       default:
+               panic("pciereg_cfgread: invalid width");
+       }
+
+       crit_exit();
+       return (data);
+}
+
+static void
+pciereg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
+{
+       struct pcie_cfg_elem *elem;
+       volatile vm_offset_t va;
+       vm_paddr_t pa, papage;
+
+       crit_enter();
+       pa = PCIE_PADDR(pciebar, reg, bus, slot, func);
+       papage = pa & ~PAGE_MASK;
+       elem = pciereg_findelem(papage);
+       va = elem->vapage | (pa & PAGE_MASK);
+
+       switch (bytes) {
+       case 4:
+               *(volatile uint32_t *)(va) = data;
+               break;
+       case 2:
+               *(volatile uint16_t *)(va) = data;
+               break;
+       case 1:
+               *(volatile uint8_t *)(va) = data;
+               break;
+       default:
+               panic("pciereg_cfgwrite: invalid width");
+       }
+
+       crit_exit();
+}
index f30214a..87bf5cf 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*-
  * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
  * All rights reserved.
  *
  * (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: src/sys/i386/include/pci_cfgreg.h,v 1.4.2.1 2001/07/28 05:55:07 imp Exp $
- * $DragonFly: src/sys/bus/pci/i386/pci_cfgreg.h,v 1.3 2007/08/14 20:09:13 dillon Exp $
+ * $FreeBSD: src/sys/i386/include/pci_cfgreg.h,v 1.14.20.1 2009/04/15 03:14:26 kensmith Exp $
  *
  */
 
-#ifndef _MACHINE_PCI_CFGREG_H_
-#define _MACHINE_PCI_CFGREG_H_
-
 #define CONF1_ADDR_PORT    0x0cf8
 #define CONF1_DATA_PORT    0x0cfc
 
 int            pci_cfgregopen(void);
 u_int32_t      pci_cfgregread(int bus, int slot, int func, int reg, int bytes);
 void           pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes);
-int            pci_cfgintr(int bus, int device, int pin, int oldirq);
-int            pci_probe_route_table(int bus);
-
-#define PCI_INVALID_IRQ                255
-#define PCI_INTERRUPT_VALID(x) ((x) != PCI_INVALID_IRQ)
-
-#endif
+void           pci_pir_open(void);
+int            pci_pir_probe(int bus, int require_parse);
+int            pci_pir_route_interrupt(int bus, int device, int func, int pin);
diff --git a/sys/bus/pci/i386/pci_pir.c b/sys/bus/pci/i386/pci_pir.c
new file mode 100644 (file)
index 0000000..c459e0d
--- /dev/null
@@ -0,0 +1,747 @@
+/*-
+ * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
+ * Copyright (c) 2000, Michael Smith <msmith@freebsd.org>
+ * Copyright (c) 2000, BSDi
+ * Copyright (c) 2004, 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 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.
+ * __FBSDID("$FreeBSD: src/sys/i386/pci/pci_pir.c,v 1.120.2.1.4.1 2009/04/15 03:14:26 kensmith Exp $");
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_param.h>
+#include <machine/md_var.h>
+#include <bus/pci/pcivar.h>
+#include <bus/pci/pcireg.h>
+#include "pci_cfgreg.h"
+#include <machine/segments.h>
+#include <machine/pc/bios.h>
+
+#define        NUM_ISA_INTERRUPTS      16
+
+/*
+ * A link device.  Loosely based on the ACPI PCI link device.  This doesn't
+ * try to support priorities for different ISA interrupts.
+ */
+struct pci_link {
+       TAILQ_ENTRY(pci_link) pl_links;
+       uint8_t         pl_id;
+       uint8_t         pl_irq;
+       uint16_t        pl_irqmask;
+       int             pl_references;
+       int             pl_routed;
+};
+
+struct pci_link_lookup {
+       struct pci_link **pci_link_ptr;
+       int             bus;
+       int             device;
+       int             pin;
+};
+
+struct pci_dev_lookup {
+       uint8_t         link;
+       int             bus;
+       int             device;
+       int             pin;
+};
+
+typedef void pir_entry_handler(struct PIR_entry *entry,
+    struct PIR_intpin* intpin, void *arg);
+
+static void    pci_print_irqmask(u_int16_t irqs);
+static int     pci_pir_biosroute(int bus, int device, int func, int pin,
+                   int irq);
+static int     pci_pir_choose_irq(struct pci_link *pci_link, int irqmask);
+static void    pci_pir_create_links(struct PIR_entry *entry,
+                   struct PIR_intpin *intpin, void *arg);
+static void    pci_pir_dump_links(void);
+static struct pci_link *pci_pir_find_link(uint8_t link_id);
+static void    pci_pir_find_link_handler(struct PIR_entry *entry,
+                   struct PIR_intpin *intpin, void *arg);
+static void    pci_pir_initial_irqs(struct PIR_entry *entry,
+                   struct PIR_intpin *intpin, void *arg);
+static void    pci_pir_parse(void);
+static uint8_t pci_pir_search_irq(int bus, int device, int pin);
+static int     pci_pir_valid_irq(struct pci_link *pci_link, int irq);
+static void    pci_pir_walk_table(pir_entry_handler *handler, void *arg);
+
+static MALLOC_DEFINE(M_PIR, "$PIR", "$PIR structures");
+
+static struct PIR_table *pci_route_table;
+static device_t pir_device;
+static int pci_route_count, pir_bios_irqs, pir_parsed;
+static TAILQ_HEAD(, pci_link) pci_links;
+static int pir_interrupt_weight[NUM_ISA_INTERRUPTS];
+
+/* sysctl vars */
+SYSCTL_DECL(_hw_pci);
+
+/* XXX this likely should live in a header file */
+#ifdef PC98
+/* IRQs 3, 5, 7, 9, 10, 11, 12, 13 */
+#define PCI_IRQ_OVERRIDE_MASK 0x3e68
+#else
+/* IRQs 3, 4, 5, 6, 7, 9, 10, 11, 12, 14, 15 */
+#define PCI_IRQ_OVERRIDE_MASK 0xdef8
+#endif
+
+static uint32_t pci_irq_override_mask = PCI_IRQ_OVERRIDE_MASK;
+TUNABLE_INT("hw.pci.irq_override_mask", &pci_irq_override_mask);
+SYSCTL_INT(_hw_pci, OID_AUTO, irq_override_mask, CTLFLAG_RD,
+    &pci_irq_override_mask, PCI_IRQ_OVERRIDE_MASK,
+    "Mask of allowed irqs to try to route when it has no good clue about\n"
+    "which irqs it should use.");
+
+/*
+ * Look for the interrupt routing table.
+ *
+ * We use PCI BIOS's PIR table if it's available. $PIR is the standard way
+ * to do this.  Sadly, some machines are not standards conforming and have
+ * _PIR instead.  We shrug and cope by looking for both.
+ */
+void
+pci_pir_open(void)
+{
+       struct PIR_table *pt;
+       uint32_t sigaddr;
+       int i;
+       uint8_t ck, *cv;
+
+       /* Don't try if we've already found a table. */
+       if (pci_route_table != NULL)
+               return;
+
+       /* Look for $PIR and then _PIR. */
+       sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0);
+       if (sigaddr == 0)
+               sigaddr = bios_sigsearch(0, "_PIR", 4, 16, 0);
+       if (sigaddr == 0)
+               return;
+
+       /* If we found something, check the checksum and length. */
+       /* XXX - Use pmap_mapdev()? */
+       pt = (struct PIR_table *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr);
+       if (pt->pt_header.ph_length <= sizeof(struct PIR_header))
+               return;
+       for (cv = (u_int8_t *)pt, ck = 0, i = 0;
+            i < (pt->pt_header.ph_length); i++)
+               ck += cv[i];
+       if (ck != 0)
+               return;
+
+       /* Ok, we've got a valid table. */
+       pci_route_table = pt;
+       pci_route_count = (pt->pt_header.ph_length -
+           sizeof(struct PIR_header)) / 
+           sizeof(struct PIR_entry);
+}
+
+/*
+ * Find the pci_link structure for a given link ID.
+ */
+static struct pci_link *
+pci_pir_find_link(uint8_t link_id)
+{
+       struct pci_link *pci_link;
+
+       TAILQ_FOREACH(pci_link, &pci_links, pl_links) {
+               if (pci_link->pl_id == link_id)
+                       return (pci_link);
+       }
+       return (NULL);
+}
+
+/*
+ * Find the link device associated with a PCI device in the table.
+ */
+static void
+pci_pir_find_link_handler(struct PIR_entry *entry, struct PIR_intpin *intpin,
+    void *arg)
+{
+       struct pci_link_lookup *lookup;
+
+       lookup = (struct pci_link_lookup *)arg;
+       if (entry->pe_bus == lookup->bus &&
+           entry->pe_device == lookup->device &&
+           intpin - entry->pe_intpin == lookup->pin)
+               *lookup->pci_link_ptr = pci_pir_find_link(intpin->link);
+}
+
+/*
+ * Check to see if a possible IRQ setting is valid.
+ */
+static int
+pci_pir_valid_irq(struct pci_link *pci_link, int irq)
+{
+
+       if (!PCI_INTERRUPT_VALID(irq))
+               return (0);
+       return (pci_link->pl_irqmask & (1 << irq));
+}
+
+/*
+ * Walk the $PIR executing the worker function for each valid intpin entry
+ * in the table.  The handler is passed a pointer to both the entry and
+ * the intpin in the entry.
+ */
+static void
+pci_pir_walk_table(pir_entry_handler *handler, void *arg)
+{
+       struct PIR_entry *entry;
+       struct PIR_intpin *intpin;
+       int i, pin;
+
+       entry = &pci_route_table->pt_entry[0];
+       for (i = 0; i < pci_route_count; i++, entry++) {
+               intpin = &entry->pe_intpin[0];
+               for (pin = 0; pin < 4; pin++, intpin++)
+                       if (intpin->link != 0)
+                               handler(entry, intpin, arg);
+       }
+}
+
+static void
+pci_pir_create_links(struct PIR_entry *entry, struct PIR_intpin *intpin,
+    void *arg)
+{
+       struct pci_link *pci_link;
+
+       pci_link = pci_pir_find_link(intpin->link);
+       if (pci_link != NULL) {
+               pci_link->pl_references++;
+               if (intpin->irqs != pci_link->pl_irqmask) {
+                       if (bootverbose)
+                               kprintf(
+       "$PIR: Entry %d.%d.INT%c has different mask for link %#x, merging\n",
+                                   entry->pe_bus, entry->pe_device,
+                                   (intpin - entry->pe_intpin) + 'A',
+                                   pci_link->pl_id);
+                       pci_link->pl_irqmask &= intpin->irqs;
+               }
+       } else {
+               pci_link = kmalloc(sizeof(struct pci_link), M_PIR, M_WAITOK);
+               pci_link->pl_id = intpin->link;
+               pci_link->pl_irqmask = intpin->irqs;
+               pci_link->pl_irq = PCI_INVALID_IRQ;
+               pci_link->pl_references = 1;
+               pci_link->pl_routed = 0;
+               TAILQ_INSERT_TAIL(&pci_links, pci_link, pl_links);
+       }
+}
+
+/*
+ * Look to see if any of the function on the PCI device at bus/device have
+ * an interrupt routed to intpin 'pin' by the BIOS.
+ */
+static uint8_t
+pci_pir_search_irq(int bus, int device, int pin)
+{
+       uint32_t value;
+       uint8_t func, maxfunc;
+
+       /* See if we have a valid device at function 0. */
+       value = pci_cfgregread(bus, device, 0, PCIR_HDRTYPE, 1);
+       if ((value & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
+               return (PCI_INVALID_IRQ);
+       if (value & PCIM_MFDEV)
+               maxfunc = PCI_FUNCMAX;
+       else
+               maxfunc = 0;
+
+       /* Scan all possible functions at this device. */
+       for (func = 0; func <= maxfunc; func++) {
+               value = pci_cfgregread(bus, device, func, PCIR_DEVVENDOR, 4);
+               if (value == 0xffffffff)
+                       continue;
+               value = pci_cfgregread(bus, device, func, PCIR_INTPIN, 1);
+
+               /*
+                * See if it uses the pin in question.  Note that the passed
+                * in pin uses 0 for A, .. 3 for D whereas the intpin
+                * register uses 0 for no interrupt, 1 for A, .. 4 for D.
+                */
+               if (value != pin + 1)
+                       continue;
+               value = pci_cfgregread(bus, device, func, PCIR_INTLINE, 1);
+               if (bootverbose)
+                       kprintf(
+               "$PIR: Found matching pin for %d.%d.INT%c at func %d: %d\n",
+                           bus, device, pin + 'A', func, value);
+               if (value != PCI_INVALID_IRQ)
+                       return (value);
+       }
+       return (PCI_INVALID_IRQ);
+}
+
+/*
+ * Try to initialize IRQ based on this device's IRQ.
+ */
+static void
+pci_pir_initial_irqs(struct PIR_entry *entry, struct PIR_intpin *intpin,
+    void *arg)
+{
+       struct pci_link *pci_link;
+       uint8_t irq, pin;
+
+       pin = intpin - entry->pe_intpin;
+       pci_link = pci_pir_find_link(intpin->link);
+       irq = pci_pir_search_irq(entry->pe_bus, entry->pe_device, pin);
+       if (irq == PCI_INVALID_IRQ || irq == pci_link->pl_irq)
+               return;
+
+       /* Don't trust any BIOS IRQs greater than 15. */
+       if (irq >= NUM_ISA_INTERRUPTS) {
+               kprintf(
+       "$PIR: Ignoring invalid BIOS IRQ %d from %d.%d.INT%c for link %#x\n",
+                   irq, entry->pe_bus, entry->pe_device, pin + 'A',
+                   pci_link->pl_id);
+               return;
+       }
+
+       /*
+        * If we don't have an IRQ for this link yet, then we trust the
+        * BIOS, even if it seems invalid from the $PIR entries.
+        */
+       if (pci_link->pl_irq == PCI_INVALID_IRQ) {
+               if (!pci_pir_valid_irq(pci_link, irq))
+                       kprintf(
+       "$PIR: Using invalid BIOS IRQ %d from %d.%d.INT%c for link %#x\n",
+                           irq, entry->pe_bus, entry->pe_device, pin + 'A',
+                           pci_link->pl_id);
+               pci_link->pl_irq = irq;
+               pci_link->pl_routed = 1;
+               return;
+       }
+
+       /*
+        * We have an IRQ and it doesn't match the current IRQ for this
+        * link.  If the new IRQ is invalid, then warn about it and ignore
+        * it.  If the old IRQ is invalid and the new IRQ is valid, then
+        * prefer the new IRQ instead.  If both IRQs are valid, then just
+        * use the first one.  Note that if we ever get into this situation
+        * we are having to guess which setting the BIOS actually routed.
+        * Perhaps we should just give up instead.
+        */
+       if (!pci_pir_valid_irq(pci_link, irq)) {
+               kprintf(
+               "$PIR: BIOS IRQ %d for %d.%d.INT%c is not valid for link %#x\n",
+                   irq, entry->pe_bus, entry->pe_device, pin + 'A',
+                   pci_link->pl_id);
+       } else if (!pci_pir_valid_irq(pci_link, pci_link->pl_irq)) {
+               kprintf(
+"$PIR: Preferring valid BIOS IRQ %d from %d.%d.INT%c for link %#x to IRQ %d\n", 
+                   irq, entry->pe_bus, entry->pe_device, pin + 'A',
+                   pci_link->pl_id, pci_link->pl_irq);
+               pci_link->pl_irq = irq;
+               pci_link->pl_routed = 1;
+       } else
+               kprintf(
+       "$PIR: BIOS IRQ %d for %d.%d.INT%c does not match link %#x irq %d\n",
+                   irq, entry->pe_bus, entry->pe_device, pin + 'A',
+                   pci_link->pl_id, pci_link->pl_irq);
+}
+
+/*
+ * Parse $PIR to enumerate link devices and attempt to determine their
+ * initial state.  This could perhaps be cleaner if we had drivers for the
+ * various interrupt routers as they could read the initial IRQ for each
+ * link.
+ */
+static void
+pci_pir_parse(void)
+{
+       char tunable_buffer[64];
+       struct pci_link *pci_link;
+       int i, irq;
+
+       /* Only parse once. */
+       if (pir_parsed)
+               return;
+       pir_parsed = 1;
+
+       /* Enumerate link devices. */
+       TAILQ_INIT(&pci_links);
+       pci_pir_walk_table(pci_pir_create_links, NULL);
+       if (bootverbose) {
+               kprintf("$PIR: Links after initial probe:\n");
+               pci_pir_dump_links();
+       }
+
+       /*
+        * Check to see if the BIOS has already routed any of the links by
+        * checking each device connected to each link to see if it has a
+        * valid IRQ.
+        */
+       pci_pir_walk_table(pci_pir_initial_irqs, NULL);
+       if (bootverbose) {
+               kprintf("$PIR: Links after initial IRQ discovery:\n");
+               pci_pir_dump_links();
+       }
+
+       /*
+        * Allow the user to override the IRQ for a given link device.  We
+        * allow invalid IRQs to be specified but warn about them.  An IRQ
+        * of 255 or 0 clears any preset IRQ.
+        */
+       i = 0;
+       TAILQ_FOREACH(pci_link, &pci_links, pl_links) {
+               ksnprintf(tunable_buffer, sizeof(tunable_buffer),
+                   "hw.pci.link.%#x.irq", pci_link->pl_id);
+               if (kgetenv_int(tunable_buffer, &irq) == 0)
+                       continue;
+               if (irq == 0)
+                       irq = PCI_INVALID_IRQ;
+               if (irq != PCI_INVALID_IRQ &&
+                   !pci_pir_valid_irq(pci_link, irq) && bootverbose)
+                       kprintf(
+               "$PIR: Warning, IRQ %d for link %#x is not listed as valid\n",
+                           irq, pci_link->pl_id);
+               pci_link->pl_routed = 0;
+               pci_link->pl_irq = irq;
+               i = 1;
+       }
+       if (bootverbose && i) {
+               kprintf("$PIR: Links after tunable overrides:\n");
+               pci_pir_dump_links();
+       }
+
+       /*
+        * Build initial interrupt weights as well as bitmap of "known-good"
+        * IRQs that the BIOS has already used for PCI link devices.
+        */
+       TAILQ_FOREACH(pci_link, &pci_links, pl_links) {
+               if (!PCI_INTERRUPT_VALID(pci_link->pl_irq))
+                       continue;
+               pir_bios_irqs |= 1 << pci_link->pl_irq;
+               pir_interrupt_weight[pci_link->pl_irq] +=
+                   pci_link->pl_references;
+       }
+       if (bootverbose) {
+               kprintf("$PIR: IRQs used by BIOS: ");
+               pci_print_irqmask(pir_bios_irqs);
+               kprintf("\n");
+               kprintf("$PIR: Interrupt Weights:\n[ ");
+               for (i = 0; i < NUM_ISA_INTERRUPTS; i++)
+                       kprintf(" %3d", i);
+               kprintf(" ]\n[ ");
+               for (i = 0; i < NUM_ISA_INTERRUPTS; i++)
+                       kprintf(" %3d", pir_interrupt_weight[i]);
+               kprintf(" ]\n");
+       }
+}
+
+/*
+ * Use the PCI BIOS to route an interrupt for a given device.
+ *
+ * Input:
+ * AX = PCIBIOS_ROUTE_INTERRUPT
+ * BH = bus
+ * BL = device [7:3] / function [2:0]
+ * CH = IRQ
+ * CL = Interrupt Pin (0x0A = A, ... 0x0D = D)
+ */
+static int
+pci_pir_biosroute(int bus, int device, int func, int pin, int irq)
+{
+       struct bios_regs args;
+
+       args.eax = PCIBIOS_ROUTE_INTERRUPT;
+       args.ebx = (bus << 8) | (device << 3) | func;
+       args.ecx = (irq << 8) | (0xa + pin);
+       return (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)));
+}
+
+
+/*
+ * Route a PCI interrupt using a link device from the $PIR.
+ */
+int
+pci_pir_route_interrupt(int bus, int device, int func, int pin)
+{
+       struct pci_link_lookup lookup;
+       struct pci_link *pci_link;
+       int error, irq;
+
+       if (pci_route_table == NULL)
+               return (PCI_INVALID_IRQ);
+
+       /* Lookup link device for this PCI device/pin. */
+       pci_link = NULL;
+       lookup.bus = bus;
+       lookup.device = device;
+       lookup.pin = pin - 1;
+       lookup.pci_link_ptr = &pci_link;
+       pci_pir_walk_table(pci_pir_find_link_handler, &lookup);
+       if (pci_link == NULL) {
+               kprintf("$PIR: No matching entry for %d.%d.INT%c\n", bus,
+                   device, pin - 1 + 'A');
+               return (PCI_INVALID_IRQ);
+       }
+
+       /*
+        * Pick a new interrupt if we don't have one already.  We look
+        * for an interrupt from several different sets.  First, if
+        * this link only has one valid IRQ, use that.  Second, we
+        * check the set of PCI only interrupts from the $PIR.  Third,
+        * we check the set of known-good interrupts that the BIOS has
+        * already used.  Lastly, we check the "all possible valid
+        * IRQs" set.
+        */
+       if (!PCI_INTERRUPT_VALID(pci_link->pl_irq)) {
+               if (pci_link->pl_irqmask != 0 && powerof2(pci_link->pl_irqmask))
+                       irq = ffs(pci_link->pl_irqmask) - 1;
+               else
+                       irq = pci_pir_choose_irq(pci_link,
+                           pci_route_table->pt_header.ph_pci_irqs);
+               if (!PCI_INTERRUPT_VALID(irq))
+                       irq = pci_pir_choose_irq(pci_link, pir_bios_irqs);
+               if (!PCI_INTERRUPT_VALID(irq))
+                       irq = pci_pir_choose_irq(pci_link,
+                           pci_irq_override_mask);
+               if (!PCI_INTERRUPT_VALID(irq)) {
+                       if (bootverbose)
+                               kprintf(
+                       "$PIR: Failed to route interrupt for %d:%d INT%c\n",
+                                   bus, device, pin - 1 + 'A');
+                       return (PCI_INVALID_IRQ);
+               }
+               pci_link->pl_irq = irq;
+       }
+
+       /* Ask the BIOS to route this IRQ if we haven't done so already. */
+       if (!pci_link->pl_routed) {
+               error = pci_pir_biosroute(bus, device, func, pin - 1,
+                   pci_link->pl_irq);
+
+               /* Ignore errors when routing a unique interrupt. */
+               if (error && !powerof2(pci_link->pl_irqmask)) {
+                       kprintf("$PIR: ROUTE_INTERRUPT failed.\n");
+                       return (PCI_INVALID_IRQ);
+               }
+               pci_link->pl_routed = 1;
+
+               /* Ensure the interrupt is set to level/low trigger. */
+               KASSERT(pir_device != NULL, ("missing pir device"));
+               BUS_CONFIG_INTR(pir_device, pci_link->pl_irq,
+                   INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
+       }
+       if (bootverbose)
+               kprintf("$PIR: %d:%d INT%c routed to irq %d\n", bus, device,
+                   pin - 1 + 'A', pci_link->pl_irq);
+       return (pci_link->pl_irq);
+}
+
+/*
+ * Try to pick an interrupt for the specified link from the interrupts
+ * set in the mask.
+ */
+static int
+pci_pir_choose_irq(struct pci_link *pci_link, int irqmask)
+{
+       int i, irq, realmask;
+
+       /* XXX: Need to have a #define of known bad IRQs to also mask out? */
+       realmask = pci_link->pl_irqmask & irqmask;
+       if (realmask == 0)
+               return (PCI_INVALID_IRQ);
+
+       /* Find IRQ with lowest weight. */
+       irq = PCI_INVALID_IRQ;
+       for (i = 0; i < NUM_ISA_INTERRUPTS; i++) {
+               if (!(realmask & 1 << i))
+                       continue;
+               if (irq == PCI_INVALID_IRQ ||
+                   pir_interrupt_weight[i] < pir_interrupt_weight[irq])
+                       irq = i;
+       }
+       if (bootverbose && PCI_INTERRUPT_VALID(irq)) {
+               kprintf("$PIR: Found IRQ %d for link %#x from ", irq,
+                   pci_link->pl_id);
+               pci_print_irqmask(realmask);
+               kprintf("\n");
+       }
+       return (irq);
+}
+
+static void
+pci_print_irqmask(u_int16_t irqs)
+{
+       int i, first;
+
+       if (irqs == 0) {
+               kprintf("none");
+               return;
+       }
+       first = 1;
+       for (i = 0; i < 16; i++, irqs >>= 1)
+               if (irqs & 1) {
+                       if (!first)
+                               kprintf(" ");
+                       else
+                               first = 0;
+                       kprintf("%d", i);
+               }
+}
+
+/*
+ * Display link devices.
+ */
+static void
+pci_pir_dump_links(void)
+{
+       struct pci_link *pci_link;
+
+       kprintf("Link  IRQ  Rtd  Ref  IRQs\n");
+       TAILQ_FOREACH(pci_link, &pci_links, pl_links) {
+               kprintf("%#4x  %3d   %c   %3d  ", pci_link->pl_id,
+                   pci_link->pl_irq, pci_link->pl_routed ? 'Y' : 'N',
+                   pci_link->pl_references);
+               pci_print_irqmask(pci_link->pl_irqmask);
+               kprintf("\n");
+       }
+}
+
+/*
+ * See if any interrupts for a given PCI bus are routed in the PIR.  Don't
+ * even bother looking if the BIOS doesn't support routing anyways.  If we
+ * are probing a PCI-PCI bridge, then require_parse will be true and we should
+ * only succeed if a host-PCI bridge has already attached and parsed the PIR.
+ */
+int
+pci_pir_probe(int bus, int require_parse)
+{
+       int i;
+       if (pci_route_table == NULL || (require_parse && !pir_parsed))
+               return (0);
+       for (i = 0; i < pci_route_count; i++)
+               if (pci_route_table->pt_entry[i].pe_bus == bus)
+                       return (1);
+       return (0);
+}
+
+/*
+ * The driver for the new-bus psuedo device pir0 for the $PIR table.
+ */
+
+static int
+pir_probe(device_t dev)
+{
+       char buf[64];
+kprintf("pir probe\n");
+       ksnprintf(buf, sizeof(buf), "PCI Interrupt Routing Table: %d Entries",
+           pci_route_count);
+       device_set_desc_copy(dev, buf);
+       return (0);
+}
+
+static int
+pir_attach(device_t dev)
+{
+
+       pci_pir_parse();
+       KASSERT(pir_device == NULL, ("Multiple pir devices"));
+       pir_device = dev;
+       return (0);
+}
+
+static void
+pir_resume_find_device(struct PIR_entry *entry, struct PIR_intpin *intpin,
+    void *arg)
+{
+       struct pci_dev_lookup *pd;
+
+       pd = (struct pci_dev_lookup *)arg;
+       if (intpin->link != pd->link || pd->bus != -1)
+               return;
+       pd->bus = entry->pe_bus;
+       pd->device = entry->pe_device;
+       pd->pin = intpin - entry->pe_intpin;
+}
+
+static int
+pir_resume(device_t dev)
+{
+       struct pci_dev_lookup pd;
+       struct pci_link *pci_link;
+       int error;
+
+       /* Ask the BIOS to re-route each link that was already routed. */
+       TAILQ_FOREACH(pci_link, &pci_links, pl_links) {
+               if (!PCI_INTERRUPT_VALID(pci_link->pl_irq)) {
+                       KASSERT(!pci_link->pl_routed,
+                           ("link %#x is routed but has invalid PCI IRQ",
+                           pci_link->pl_id));
+                       continue;
+               }
+               if (pci_link->pl_routed) {
+                       pd.bus = -1;
+                       pd.link = pci_link->pl_id;
+                       pci_pir_walk_table(pir_resume_find_device, &pd);
+                       KASSERT(pd.bus != -1,
+               ("did not find matching entry for link %#x in the $PIR table",
+                           pci_link->pl_id));
+                       if (bootverbose)
+                               device_printf(dev,
+                           "Using %d.%d.INT%c to route link %#x to IRQ %d\n",
+                                   pd.bus, pd.device, pd.pin + 'A',
+                                   pci_link->pl_id, pci_link->pl_irq);
+                       error = pci_pir_biosroute(pd.bus, pd.device, 0, pd.pin,
+                           pci_link->pl_irq);
+                       if (error)
+                               device_printf(dev,
+                           "ROUTE_INTERRUPT on resume for link %#x failed.\n",
+                                   pci_link->pl_id);
+               }
+       }
+       return (0);
+}
+
+static device_method_t pir_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_probe,         pir_probe),
+       DEVMETHOD(device_attach,        pir_attach),
+       DEVMETHOD(device_resume,        pir_resume),
+
+       { 0, 0 }
+};
+
+static driver_t pir_driver = {
+       "pir",
+       pir_methods,
+       1,
+};
+
+static devclass_t pir_devclass;
+
+DRIVER_MODULE(pir, legacy, pir_driver, pir_devclass, 0, 0);
diff --git a/sys/bus/pci/ignore_pci.c b/sys/bus/pci/ignore_pci.c
new file mode 100644 (file)
index 0000000..237b463
--- /dev/null
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2000 Michael Smith <msmith@freebsd.org>
+ * Copyright (c) 2000 BSDi
+ * 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.
+ *
+ * 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.
+ * __FBSDID("$FreeBSD: src/sys/dev/pci/ignore_pci.c,v 1.4.28.1 2009/04/15 03:14:26 kensmith Exp $");
+ */
+
+#include <sys/cdefs.h>
+
+/*
+ * 'Ignore' driver - eats devices that show up errnoeously on PCI
+ * but shouldn't ever be listed or handled by a driver.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <bus/pci/pcivar.h>
+
+static int     ignore_pci_probe(device_t dev);
+
+static device_method_t ignore_pci_methods[] = {
+    /* Device interface */
+    DEVMETHOD(device_probe,            ignore_pci_probe),
+    DEVMETHOD(device_attach,           bus_generic_attach),
+    { 0, 0 }
+};
+
+static driver_t ignore_pci_driver = {
+    "ignore_pci",
+    ignore_pci_methods,
+    0,
+};
+
+static devclass_t ignore_pci_devclass;
+
+DRIVER_MODULE(ignore_pci, pci, ignore_pci_driver, ignore_pci_devclass, 0, 0);
+
+static int
+ignore_pci_probe(device_t dev)
+{
+    switch (pci_get_devid(dev)) {
+    case 0x10001042ul: /* SMC 37C665 */
+       device_set_desc(dev, "ignored");
+       device_quiet(dev);
+       return(-10000);
+    }
+    return(ENXIO);
+}
diff --git a/sys/bus/pci/isa_pci.c b/sys/bus/pci/isa_pci.c
new file mode 100644 (file)
index 0000000..2818ab6
--- /dev/null
@@ -0,0 +1,151 @@
+/*-
+ * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier
+ * Copyright (c) 2000 Michael Smith <msmith@freebsd.org>
+ * Copyright (c) 2000 BSDi
+ * 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 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.
+ * __FBSDID("$FreeBSD: src/sys/dev/pci/isa_pci.c,v 1.13.8.1 2009/04/15 03:14:26 kensmith Exp $");
+ */
+
+#include <sys/cdefs.h>
+
+/*
+ * PCI:ISA bridge support
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <bus/isa/isavar.h>
+#include <bus/pci/pcivar.h>
+#include <bus/pci/pcireg.h>
+
+static int     isab_probe(device_t dev);
+
+#if 0
+int
+isab_attach(device_t dev)
+{
+       return ENXIO;
+}
+#endif
+
+static device_method_t isab_methods[] = {
+    /* Device interface */
+    DEVMETHOD(device_probe,            isab_probe),
+    DEVMETHOD(device_attach,           isab_attach),
+    DEVMETHOD(device_detach,           bus_generic_detach),
+    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_alloc_resource,      bus_generic_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),
+
+    { 0, 0 }
+};
+
+static driver_t isab_driver = {
+    "isab",
+    isab_methods,
+    0,
+};
+
+devclass_t isab_devclass;
+
+DRIVER_MODULE(isab, pci, isab_driver, isab_devclass, 0, 0);
+
+/*
+ * XXX we need to add a quirk list here for bridges that don't correctly
+ *     report themselves.
+ */
+static int
+isab_probe(device_t dev)
+{
+    int                matched = 0;
+
+    /*
+     * Try for a generic match based on class/subclass.
+     */
+    if ((pci_get_class(dev) == PCIC_BRIDGE) &&
+       (pci_get_subclass(dev) == PCIS_BRIDGE_ISA)) {
+       matched = 1;
+    } else {
+       /*
+        * These are devices that we *know* are PCI:ISA bridges. 
+        * Sometimes, however, they don't report themselves as
+        * such.  Check in case one of them is pretending to be
+        * something else.
+        */
+       switch (pci_get_devid(dev)) {
+       case 0x04848086:        /* Intel 82378ZB/82378IB */
+       case 0x122e8086:        /* Intel 82371FB */
+       case 0x70008086:        /* Intel 82371SB */
+       case 0x71108086:        /* Intel 82371AB */
+       case 0x71988086:        /* Intel 82443MX */
+       case 0x24108086:        /* Intel 82801AA (ICH) */
+       case 0x24208086:        /* Intel 82801AB (ICH0) */
+       case 0x24408086:        /* Intel 82801AB (ICH2) */
+       case 0x00061004:        /* VLSI 82C593 */
+       case 0x05861106:        /* VIA 82C586 */
+       case 0x05961106:        /* VIA 82C596 */
+       case 0x06861106:        /* VIA 82C686 */
+       case 0x153310b9:        /* AcerLabs M1533 */
+       case 0x154310b9:        /* AcerLabs M1543 */
+       case 0x00081039:        /* SiS 85c503 */
+       case 0x00001078:        /* Cyrix Cx5510 */
+       case 0x01001078:        /* Cyrix Cx5530 */
+       case 0xc7001045:        /* OPTi 82C700 (FireStar) */
+       case 0x00011033:        /* NEC 0001 (C-bus) */
+       case 0x002c1033:        /* NEC 002C (C-bus) */
+       case 0x003b1033:        /* NEC 003B (C-bus) */
+       case 0x886a1060:        /* UMC UM8886 ISA */
+       case 0x02001166:        /* ServerWorks IB6566 PCI */
+           if (bootverbose)
+               kprintf("PCI-ISA bridge with incorrect subclass 0x%x\n",
+                      pci_get_subclass(dev));
+           matched = 1;
+           break;
+       
+       default:
+           break;
+       }
+    }
+
+    if (matched) {
+       device_set_desc(dev, "PCI-ISA bridge");
+       return(-10000);
+    }
+    return(ENXIO);
+}
index 721b258..c43b090 100644 (file)
@@ -1,5 +1,7 @@
-/*
- * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
+/*-
+ * Copyright (c) 1997, Stefan Esser <se@kfreebsd.org>
+ * Copyright (c) 2000, Michael Smith <msmith@kfreebsd.org>
+ * Copyright (c) 2000, BSDi
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * 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: src/sys/pci/pci.c,v 1.141.2.15 2002/04/30 17:48:18 tmm Exp $
- * $DragonFly: src/sys/bus/pci/pci.c,v 1.58 2008/11/16 18:44:00 swildner Exp $
- *
+ * __FBSDID("$FreeBSD: src/sys/dev/pci/pci.c,v 1.355.2.9.2.1 2009/04/15 03:14:26 kensmith Exp $");
  */
 
-#include "opt_bus.h"
-#include "opt_pci.h"
+#include <sys/cdefs.h>
 
-#include "opt_compat_oldpci.h"
+#include "opt_bus.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
+#include <sys/linker.h>
 #include <sys/fcntl.h>
 #include <sys/conf.h>
 #include <sys/kernel.h>
 #include <sys/queue.h>
-#include <sys/types.h>
 #include <sys/sysctl.h>
-#include <sys/buf.h>
+#include <sys/endian.h>
 
 #include <vm/vm.h>
 #include <vm/pmap.h>
 
 #include <sys/bus.h>
 #include <sys/rman.h>
-#include <machine/smp.h>
-#include "pci_cfgreg.h"
+#include <sys/device.h>
 
 #include <sys/pciio.h>
-#include "pcireg.h"
-#include "pcivar.h"
-#include "pci_private.h"
+#include <bus/pci/pcireg.h>
+#include <bus/pci/pcivar.h>
+#include <bus/pci/pci_private.h>
 
 #include "pcib_if.h"
+#include "pci_if.h"
+
+#ifdef __HAVE_ACPI
+#include <contrib/dev/acpica/acpi.h>
+#include "acpi_if.h"
+#else
+#define        ACPI_PWR_FOR_SLEEP(x, y, z)
+#endif
+
+static uint32_t                pci_mapbase(unsigned mapreg);
+static const char      *pci_maptype(unsigned mapreg);
+static int             pci_mapsize(unsigned testval);
+static int             pci_maprange(unsigned mapreg);
+static void            pci_fixancient(pcicfgregs *cfg);
+
+static int             pci_porten(device_t pcib, int b, int s, int f);
+static int             pci_memen(device_t pcib, int b, int s, int f);
+static void            pci_assign_interrupt(device_t bus, device_t dev,
+                           int force_route);
+static int             pci_add_map(device_t pcib, device_t bus, device_t dev,
+                           int b, int s, int f, int reg,
+                           struct resource_list *rl, int force, int prefetch);
+static int             pci_probe(device_t dev);
+static int             pci_attach(device_t dev);
+static void            pci_load_vendor_data(void);
+static int             pci_describe_parse_line(char **ptr, int *vendor,
+                           int *device, char **desc);
+static char            *pci_describe_device(device_t dev);
+static int             pci_modevent(module_t mod, int what, void *arg);
+static void            pci_hdrtypedata(device_t pcib, int b, int s, int f,
+                           pcicfgregs *cfg);
+static void            pci_read_extcap(device_t pcib, pcicfgregs *cfg);
+static int             pci_read_vpd_reg(device_t pcib, pcicfgregs *cfg,
+                           int reg, uint32_t *data);
+#if 0
+static int             pci_write_vpd_reg(device_t pcib, pcicfgregs *cfg,
+                           int reg, uint32_t data);
+#endif
+static void            pci_read_vpd(device_t pcib, pcicfgregs *cfg);
+static void            pci_disable_msi(device_t dev);
+static void            pci_enable_msi(device_t dev, uint64_t address,
+                           uint16_t data);
+static void            pci_enable_msix(device_t dev, u_int index,
+                           uint64_t address, uint32_t data);
+static void            pci_mask_msix(device_t dev, u_int index);
+static void            pci_unmask_msix(device_t dev, u_int index);
+static int             pci_msi_blacklisted(void);
+static void            pci_resume_msi(device_t dev);
+static void            pci_resume_msix(device_t dev);
+
+static device_method_t pci_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_probe,         pci_probe),
+       DEVMETHOD(device_attach,        pci_attach),
+       DEVMETHOD(device_detach,        bus_generic_detach),
+       DEVMETHOD(device_shutdown,      bus_generic_shutdown),
+       DEVMETHOD(device_suspend,       pci_suspend),
+       DEVMETHOD(device_resume,        pci_resume),
+
+       /* Bus interface */
+       DEVMETHOD(bus_print_child,      pci_print_child),
+       DEVMETHOD(bus_probe_nomatch,    pci_probe_nomatch),
+       DEVMETHOD(bus_read_ivar,        pci_read_ivar),
+       DEVMETHOD(bus_write_ivar,       pci_write_ivar),
+       DEVMETHOD(bus_driver_added,     pci_driver_added),
+       DEVMETHOD(bus_setup_intr,       pci_setup_intr),
+       DEVMETHOD(bus_teardown_intr,    pci_teardown_intr),
+
+       DEVMETHOD(bus_get_resource_list,pci_get_resource_list),
+       DEVMETHOD(bus_set_resource,     bus_generic_rl_set_resource),
+       DEVMETHOD(bus_get_resource,     bus_generic_rl_get_resource),
+       DEVMETHOD(bus_delete_resource,  pci_delete_resource),
+       DEVMETHOD(bus_alloc_resource,   pci_alloc_resource),
+       DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource),
+       DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+       DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+       DEVMETHOD(bus_child_pnpinfo_str, pci_child_pnpinfo_str_method),
+       DEVMETHOD(bus_child_location_str, pci_child_location_str_method),
+
+       /* PCI interface */
+       DEVMETHOD(pci_read_config,      pci_read_config_method),
+       DEVMETHOD(pci_write_config,     pci_write_config_method),
+       DEVMETHOD(pci_enable_busmaster, pci_enable_busmaster_method),
+       DEVMETHOD(pci_disable_busmaster, pci_disable_busmaster_method),
+       DEVMETHOD(pci_enable_io,        pci_enable_io_method),
+       DEVMETHOD(pci_disable_io,       pci_disable_io_method),
+       DEVMETHOD(pci_get_vpd_ident,    pci_get_vpd_ident_method),
+       DEVMETHOD(pci_get_vpd_readonly, pci_get_vpd_readonly_method),
+       DEVMETHOD(pci_get_powerstate,   pci_get_powerstate_method),
+       DEVMETHOD(pci_set_powerstate,   pci_set_powerstate_method),
+       DEVMETHOD(pci_assign_interrupt, pci_assign_interrupt_method),
+       DEVMETHOD(pci_find_extcap,      pci_find_extcap_method),
+       DEVMETHOD(pci_alloc_msi,        pci_alloc_msi_method),
+       DEVMETHOD(pci_alloc_msix,       pci_alloc_msix_method),
+       DEVMETHOD(pci_remap_msix,       pci_remap_msix_method),
+       DEVMETHOD(pci_release_msi,      pci_release_msi_method),
+       DEVMETHOD(pci_msi_count,        pci_msi_count_method),
+       DEVMETHOD(pci_msix_count,       pci_msix_count_method),
+
+       { 0, 0 }
+};
+
+DEFINE_CLASS_0(pci, pci_driver, pci_methods, 0);
 
-devclass_t     pci_devclass;
-const char     *pcib_owner;
+static devclass_t pci_devclass;
+DRIVER_MODULE(pci, pcib, pci_driver, pci_devclass, pci_modevent, 0);
+MODULE_VERSION(pci, 1);
+
+static char    *pci_vendordata;
+static size_t  pci_vendordata_size;
 
-static void            pci_read_capabilities(device_t dev, pcicfgregs *cfg);
-static int             pcie_slotimpl(const pcicfgregs *);
 
 struct pci_quirk {
-       u_int32_t devid;        /* Vendor/device of the card */
+       uint32_t devid; /* Vendor/device of the card */
        int     type;
-#define PCI_QUIRK_MAP_REG      1 /* PCI map register in weird place */
+#define        PCI_QUIRK_MAP_REG       1 /* PCI map register in weird place */
+#define        PCI_QUIRK_DISABLE_MSI   2 /* MSI/MSI-X doesn't work */
        int     arg1;
        int     arg2;
 };
 
 struct pci_quirk pci_quirks[] = {
-       /*
-        * The Intel 82371AB and 82443MX has a map register at offset 0x90.
-        */
+       /* The Intel 82371AB and 82443MX has a map register at offset 0x90. */
        { 0x71138086, PCI_QUIRK_MAP_REG,        0x90,    0 },
        { 0x719b8086, PCI_QUIRK_MAP_REG,        0x90,    0 },
        /* As does the Serverworks OSB4 (the SMBus mapping register) */
        { 0x02001166, PCI_QUIRK_MAP_REG,        0x90,    0 },
 
+       /*
+        * MSI doesn't work with the ServerWorks CNB20-HE Host Bridge
+        * or the CMIC-SL (AKA ServerWorks GC_LE).
+        */
+       { 0x00141166, PCI_QUIRK_DISABLE_MSI,    0,      0 },
+       { 0x00171166, PCI_QUIRK_DISABLE_MSI,    0,      0 },
+
+       /*
+        * MSI doesn't work on earlier Intel chipsets including
+        * E7500, E7501, E7505, 845, 865, 875/E7210, and 855.
+        */
+       { 0x25408086, PCI_QUIRK_DISABLE_MSI,    0,      0 },
+       { 0x254c8086, PCI_QUIRK_DISABLE_MSI,    0,      0 },
+       { 0x25508086, PCI_QUIRK_DISABLE_MSI,    0,      0 },
+       { 0x25608086, PCI_QUIRK_DISABLE_MSI,    0,      0 },
+       { 0x25708086, PCI_QUIRK_DISABLE_MSI,    0,      0 },
+       { 0x25788086, PCI_QUIRK_DISABLE_MSI,    0,      0 },
+       { 0x35808086, PCI_QUIRK_DISABLE_MSI,    0,      0 },
+
+       /*
+        * MSI doesn't work with devices behind the AMD 8131 HT-PCIX
+        * bridge.
+        */
+       { 0x74501022, PCI_QUIRK_DISABLE_MSI,    0,      0 },
+
        { 0 }
 };
 
 /* map register information */
-#define PCI_MAPMEM     0x01    /* memory map */
-#define PCI_MAPMEMP    0x02    /* prefetchable memory map */
-#define PCI_MAPPORT    0x04    /* port map */
+#define        PCI_MAPMEM      0x01    /* memory map */
+#define        PCI_MAPMEMP     0x02    /* prefetchable memory map */
+#define        PCI_MAPPORT     0x04    /* port map */
+
+struct devlist pci_devq;
+uint32_t pci_generation;
+uint32_t pci_numdevs = 0;
+static int pcie_chipset, pcix_chipset;
+
+/* sysctl vars */
+SYSCTL_NODE(_hw, OID_AUTO, pci, CTLFLAG_RD, 0, "PCI bus tuning parameters");
+
+static int pci_enable_io_modes = 1;
+TUNABLE_INT("hw.pci.enable_io_modes", &pci_enable_io_modes);
+SYSCTL_INT(_hw_pci, OID_AUTO, enable_io_modes, CTLFLAG_RW,
+    &pci_enable_io_modes, 1,
+    "Enable I/O and memory bits in the config register.  Some BIOSes do not\n\
+enable these bits correctly.  We'd like to do this all the time, but there\n\
+are some peripherals that this causes problems with.");
 
-static STAILQ_HEAD(devlist, pci_devinfo) pci_devq;
-u_int32_t pci_numdevs = 0;
-static u_int32_t pci_generation = 0;
-
-SYSCTL_NODE(_hw, OID_AUTO, pci, CTLFLAG_RD, 0, "pci parameters");
 static int pci_do_power_nodriver = 0;
 TUNABLE_INT("hw.pci.do_power_nodriver", &pci_do_power_nodriver);
 SYSCTL_INT(_hw_pci, OID_AUTO, do_power_nodriver, CTLFLAG_RW,
     &pci_do_power_nodriver, 0,
   "Place a function into D3 state when no driver attaches to it.  0 means\n\
 disable.  1 means conservatively place devices into D3 state.  2 means\n\
-aggressively place devices into D3 state.  3 means put absolutely everything\n\
+agressively place devices into D3 state.  3 means put absolutely everything\n\
 in D3 state.");
 
+static int pci_do_power_resume = 1;
+TUNABLE_INT("hw.pci.do_power_resume", &pci_do_power_resume);
+SYSCTL_INT(_hw_pci, OID_AUTO, do_power_resume, CTLFLAG_RW,
+    &pci_do_power_resume, 1,
+  "Transition from D3 -> D0 on resume.");
+
+static int pci_do_msi = 1;
+TUNABLE_INT("hw.pci.enable_msi", &pci_do_msi);
+SYSCTL_INT(_hw_pci, OID_AUTO, enable_msi, CTLFLAG_RW, &pci_do_msi, 1,
+    "Enable support for MSI interrupts");
+
+static int pci_do_msix = 1;
+TUNABLE_INT("hw.pci.enable_msix", &pci_do_msix);
+SYSCTL_INT(_hw_pci, OID_AUTO, enable_msix, CTLFLAG_RW, &pci_do_msix, 1,
+    "Enable support for MSI-X interrupts");
+
+static int pci_honor_msi_blacklist = 1;
+TUNABLE_INT("hw.pci.honor_msi_blacklist", &pci_honor_msi_blacklist);
+SYSCTL_INT(_hw_pci, OID_AUTO, honor_msi_blacklist, CTLFLAG_RD,
+    &pci_honor_msi_blacklist, 1, "Honor chipset blacklist for MSI");
+
+/* Find a device_t by bus/slot/function in domain 0 */
+
+device_t
+pci_find_bsf(uint8_t bus, uint8_t slot, uint8_t func)
+{
+
+       return (pci_find_dbsf(0, bus, slot, func));
+}
+
+/* Find a device_t by domain/bus/slot/function */
+
 device_t
-pci_find_bsf(u_int8_t bus, u_int8_t slot, u_int8_t func)
+pci_find_dbsf(uint32_t domain, uint8_t bus, uint8_t slot, uint8_t func)
 {
        struct pci_devinfo *dinfo;
 
        STAILQ_FOREACH(dinfo, &pci_devq, pci_links) {
-               if ((dinfo->cfg.bus == bus) &&
+               if ((dinfo->cfg.domain == domain) &&
+                   (dinfo->cfg.bus == bus) &&
                    (dinfo->cfg.slot == slot) &&
                    (dinfo->cfg.func == func)) {
                        return (dinfo->cfg.dev);
@@ -122,8 +292,10 @@ pci_find_bsf(u_int8_t bus, u_int8_t slot, u_int8_t func)
        return (NULL);
 }
 
+/* Find a device_t by vendor/device ID */
+
 device_t
-pci_find_device(u_int16_t vendor, u_int16_t device)
+pci_find_device(uint16_t vendor, uint16_t device)
 {
        struct pci_devinfo *dinfo;
 
@@ -137,78 +309,35 @@ pci_find_device(u_int16_t vendor, u_int16_t device)
        return (NULL);
 }
 
-int
-pcie_slot_implemented(device_t dev)
-{
-       struct pci_devinfo *dinfo = device_get_ivars(dev);
-
-       return pcie_slotimpl(&dinfo->cfg);
-}
-
-void
-pcie_set_max_readrq(device_t dev, uint16_t rqsize)
-{
-       uint8_t expr_ptr;
-       uint16_t val;
-
-       rqsize &= PCIEM_DEVCTL_MAX_READRQ_MASK;
-       if (rqsize > PCIEM_DEVCTL_MAX_READRQ_4096) {
-               panic("%s: invalid max read request size 0x%02x\n",
-                     device_get_nameunit(dev), rqsize);
-       }
-
-       expr_ptr = pci_get_pciecap_ptr(dev);
-       if (!expr_ptr)
-               panic("%s: not PCIe device\n", device_get_nameunit(dev));
-
-       val = pci_read_config(dev, expr_ptr + PCIER_DEVCTRL, 2);
-       if ((val & PCIEM_DEVCTL_MAX_READRQ_MASK) != rqsize) {
-               if (bootverbose)
-                       device_printf(dev, "adjust device control 0x%04x", val);
-
-               val &= ~PCIEM_DEVCTL_MAX_READRQ_MASK;
-               val |= rqsize;
-               pci_write_config(dev, expr_ptr + PCIER_DEVCTRL, val, 2);
-
-               if (bootverbose)
-                       kprintf(" -> 0x%04x\n", val);
-       }
-}
-
 /* return base address of memory or port map */
 
-static u_int32_t
-pci_mapbase(unsigned mapreg)
+static uint32_t
+pci_mapbase(uint32_t mapreg)
 {
-       int mask = 0x03;
-       if ((mapreg & 0x01) == 0)
-               mask = 0x0f;
-       return (mapreg & ~mask);
+
+       if (PCI_BAR_MEM(mapreg))
+               return (mapreg & PCIM_BAR_MEM_BASE);
+       else
+               return (mapreg & PCIM_BAR_IO_BASE);
 }
 
 /* return map type of memory or port map */
 
-static int
+static const char *
 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,
-       };
 
-       return maptype[mapreg & 0x0f];
+       if (PCI_BAR_IO(mapreg))
+               return ("I/O Port");
+       if (mapreg & PCIM_BAR_MEM_PREFETCH)
+               return ("Prefetchable Memory");
+       return ("Memory");
 }
 
 /* return log2 of map size decoded for memory or port map */
 
 static int
-pci_mapsize(unsigned testval)
+pci_mapsize(uint32_t testval)
 {
        int ln2size;
 
@@ -230,19 +359,21 @@ static int
 pci_maprange(unsigned mapreg)
 {
        int ln2range = 0;
-       switch (mapreg & 0x07) {
-       case 0x00:
-       case 0x01:
-       case 0x05:
+
+       if (PCI_BAR_IO(mapreg))
                ln2range = 32;
-               break;
-       case 0x02:
-               ln2range = 20;
-               break;
-       case 0x04:
-               ln2range = 64;
-               break;
-       }
+       else
+               switch (mapreg & PCIM_BAR_MEM_TYPE) {
+               case PCIM_BAR_MEM_32:
+                       ln2range = 32;
+                       break;
+               case PCIM_BAR_MEM_1MB:
+                       ln2range = 20;
+                       break;
+               case PCIM_BAR_MEM_64:
+                       ln2range = 64;
+                       break;
+               }
        return (ln2range);
 }
 
@@ -259,82 +390,12 @@ pci_fixancient(pcicfgregs *cfg)
                cfg->hdrtype = 1;
 }
 
-/* read config data specific to header type 1 device (PCI to PCI bridge) */
-
-static void *
-pci_readppb(device_t pcib, int b, int s, int f)
-{
-       pcih1cfgregs *p;
-
-       p = kmalloc(sizeof (pcih1cfgregs), M_DEVBUF, M_WAITOK | M_ZERO);
-
-       p->secstat = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_SECSTAT_1, 2);
-       p->bridgectl = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_BRIDGECTL_1, 2);
-
-       p->seclat = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_SECLAT_1, 1);
-
-       p->iobase = PCI_PPBIOBASE (PCIB_READ_CONFIG(pcib, b, s, f,
-                                                   PCIR_IOBASEH_1, 2),
-                                  PCIB_READ_CONFIG(pcib, b, s, f,
-                                                   PCIR_IOBASEL_1, 1));
-       p->iolimit = PCI_PPBIOLIMIT (PCIB_READ_CONFIG(pcib, b, s, f,
-                                                     PCIR_IOLIMITH_1, 2),
-                                    PCIB_READ_CONFIG(pcib, b, s, f,
-                                                     PCIR_IOLIMITL_1, 1));
-
-       p->membase = PCI_PPBMEMBASE (0,
-                                    PCIB_READ_CONFIG(pcib, b, s, f,
-                                                     PCIR_MEMBASE_1, 2));
-       p->memlimit = PCI_PPBMEMLIMIT (0,
-                                      PCIB_READ_CONFIG(pcib, b, s, f,
-                                                       PCIR_MEMLIMIT_1, 2));
-
-       p->pmembase = PCI_PPBMEMBASE (
-               (pci_addr_t)PCIB_READ_CONFIG(pcib, b, s, f, PCIR_PMBASEH_1, 4),
-               PCIB_READ_CONFIG(pcib, b, s, f, PCIR_PMBASEL_1, 2));
-
-       p->pmemlimit = PCI_PPBMEMLIMIT (
-               (pci_addr_t)PCIB_READ_CONFIG(pcib, b, s, f,
-                                            PCIR_PMLIMITH_1, 4),
-               PCIB_READ_CONFIG(pcib, b, s, f, PCIR_PMLIMITL_1, 2));
-
-       return (p);
-}
-
-/* read config data specific to header type 2 device (PCI to CardBus bridge) */
-
-static void *
-pci_readpcb(device_t pcib, int b, int s, int f)
-{
-       pcih2cfgregs *p;
-
-       p = kmalloc(sizeof (pcih2cfgregs), M_DEVBUF, M_WAITOK | M_ZERO);
-
-       p->secstat = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_SECSTAT_2, 2);
-       p->bridgectl = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_BRIDGECTL_2, 2);
-       
-       p->seclat = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_SECLAT_2, 1);
-
-       p->membase0 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_MEMBASE0_2, 4);
-       p->memlimit0 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_MEMLIMIT0_2, 4);
-       p->membase1 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_MEMBASE1_2, 4);
-       p->memlimit1 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_MEMLIMIT1_2, 4);
-
-       p->iobase0 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_IOBASE0_2, 4);
-       p->iolimit0 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_IOLIMIT0_2, 4);
-       p->iobase1 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_IOBASE1_2, 4);
-       p->iolimit1 = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_IOLIMIT1_2, 4);
-
-       p->pccardif = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_PCCARDIF_2, 4);
-       return p;
-}
-
 /* extract header type specific config data */
 
 static void
 pci_hdrtypedata(device_t pcib, int b, int s, int f, pcicfgregs *cfg)
 {
-#define REG(n,w)       PCIB_READ_CONFIG(pcib, b, s, f, n, w)
+#define        REG(n, w)       PCIB_READ_CONFIG(pcib, b, s, f, n, w)
        switch (cfg->hdrtype) {
        case 0:
                cfg->subvendor      = REG(PCIR_SUBVEND_0, 2);
@@ -342,32 +403,22 @@ pci_hdrtypedata(device_t pcib, int b, int s, int f, pcicfgregs *cfg)
                cfg->nummaps        = PCI_MAXMAPS_0;
                break;
        case 1:
-               cfg->subvendor      = REG(PCIR_SUBVEND_1, 2);
-               cfg->subdevice      = REG(PCIR_SUBDEV_1, 2);
-               cfg->secondarybus   = REG(PCIR_SECBUS_1, 1);
-               cfg->subordinatebus = REG(PCIR_SUBBUS_1, 1);
                cfg->nummaps        = PCI_MAXMAPS_1;
-               cfg->hdrspec        = pci_readppb(pcib, b, s, f);
                break;
        case 2:
                cfg->subvendor      = REG(PCIR_SUBVEND_2, 2);
                cfg->subdevice      = REG(PCIR_SUBDEV_2, 2);
-               cfg->secondarybus   = REG(PCIR_SECBUS_2, 1);
-               cfg->subordinatebus = REG(PCIR_SUBBUS_2, 1);
                cfg->nummaps        = PCI_MAXMAPS_2;
-               cfg->hdrspec        = pci_readpcb(pcib, b, s, f);
                break;
        }
 #undef REG
 }
 
-/* read configuration header into pcicfgrect structure */
-
+/* read configuration header into pcicfgregs structure */
 struct pci_devinfo *
-pci_read_device(device_t pcib, int b, int s, int f, size_t size)
+pci_read_device(device_t pcib, int d, int b, int s, int f, size_t size)
 {
-#define REG(n, w)      PCIB_READ_CONFIG(pcib, b, s, f, n, w)
-
+#define        REG(n, w)       PCIB_READ_CONFIG(pcib, b, s, f, n, w)
        pcicfgregs *cfg = NULL;
        struct pci_devinfo *devlist_entry;
        struct devlist *devlist_head;
@@ -376,12 +427,14 @@ pci_read_device(device_t pcib, int b, int s, int f, size_t size)
 
        devlist_entry = NULL;
 
-       if (PCIB_READ_CONFIG(pcib, b, s, f, PCIR_DEVVENDOR, 4) != -1) {
-
+       if (REG(PCIR_DEVVENDOR, 4) != -1) {
                devlist_entry = kmalloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
+               if (devlist_entry == NULL)
+                       return (NULL);
 
                cfg = &devlist_entry->cfg;
-               
+
+               cfg->domain             = d;
                cfg->bus                = b;
                cfg->slot               = s;
                cfg->func               = f;
@@ -399,38 +452,6 @@ pci_read_device(device_t pcib, 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);
 
@@ -439,10 +460,13 @@ pci_read_device(device_t pcib, int b, int s, int f, size_t size)
 
                pci_fixancient(cfg);
                pci_hdrtypedata(pcib, b, s, f, cfg);
-               pci_read_capabilities(pcib, cfg);
+
+               if (REG(PCIR_STATUS, 2) & PCIM_STATUS_CAPPRESENT)
+                       pci_read_extcap(pcib, cfg);
 
                STAILQ_INSERT_TAIL(devlist_head, devlist_entry, pci_links);
 
+               devlist_entry->conf.pc_sel.pc_domain = cfg->domain;
                devlist_entry->conf.pc_sel.pc_bus = cfg->bus;
                devlist_entry->conf.pc_sel.pc_dev = cfg->slot;
                devlist_entry->conf.pc_sel.pc_func = cfg->func;
@@ -465,220 +489,1535 @@ pci_read_device(device_t pcib, int b, int s, int f, size_t size)
 #undef REG
 }
 
-static int
-pci_fixup_nextptr(int *nextptr0)
-{
-       int nextptr = *nextptr0;
-
-       /* "Next pointer" is only one byte */
-       KASSERT(nextptr <= 0xff, ("Illegal next pointer %d\n", nextptr));
-
-       if (nextptr & 0x3) {
-               /*
-                * PCI local bus spec 3.0:
-                *
-                * "... The bottom two bits of all pointers are reserved
-                *  and must be implemented as 00b although software must
-                *  mask them to allow for future uses of these bits ..."
-                */
-               if (bootverbose) {
-                       kprintf("Illegal PCI extended capability "
-                               "offset, fixup 0x%02x -> 0x%02x\n",
-                               nextptr, nextptr & ~0x3);
-               }
-               nextptr &= ~0x3;
-       }
-       *nextptr0 = nextptr;
-
-       if (nextptr < 0x40) {
-               if (nextptr != 0) {
-                       kprintf("Illegal PCI extended capability "
-                               "offset 0x%02x", nextptr);
-               }
-               return 0;
-       }
-       return 1;
-}
-
-static void
-pci_read_cap_pmgt(device_t pcib, int ptr, pcicfgregs *cfg)
-{
-#define REG(n, w)      \
-       PCIB_READ_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, w)
-
-       struct pcicfg_pmgt *pmgt = &cfg->pmgt;
-
-       if (pmgt->pp_cap)
-               return;
-
-       pmgt->pp_cap = REG(ptr + PCIR_POWER_CAP, 2);
-       pmgt->pp_status = ptr + PCIR_POWER_STATUS;
-       pmgt->pp_pmcsr = ptr + PCIR_POWER_PMCSR;
-       /*
-        * XXX
-        * Following way may be used to to test whether
-        * 'data' register exists:
-        * if 'data_select' register of
-        * PCIR_POWER_STATUS(bits[12,9]) is read-only
-        * then 'data' register is _not_ implemented.
-        */
-       pmgt->pp_data = 0;
-
-#undef REG
-}
-
-static int
-pcie_slotimpl(const pcicfgregs *cfg)
-{
-       const struct pcicfg_expr *expr = &cfg->expr;
-       uint16_t port_type;
-
-       /*
-        * Only version 1 can be parsed currently 
-        */
-       if ((expr->expr_cap & PCIEM_CAP_VER_MASK) != PCIEM_CAP_VER_1)
-               return 0;
-
-       /*
-        * - Slot implemented bit is meaningful iff current port is
-        *   root port or down stream port.
-        * - Testing for root port or down stream port is meanningful
-        *   iff PCI configure has type 1 header.
-        */
-
-       if (cfg->hdrtype != 1)
-               return 0;
-
-       port_type = expr->expr_cap & PCIEM_CAP_PORT_TYPE;
-       if (port_type != PCIE_ROOT_PORT && port_type != PCIE_DOWN_STREAM_PORT)
-               return 0;
-
-       if (!(expr->expr_cap & PCIEM_CAP_SLOT_IMPL))
-               return 0;
-
-       return 1;
-}
-
-static void
-pci_read_cap_expr(device_t pcib, int ptr, pcicfgregs *cfg)
-{
-#define REG(n, w)      \
-       PCIB_READ_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, w)
-
-       struct pcicfg_expr *expr = &cfg->expr;
-
-       expr->expr_ptr = ptr;
-       expr->expr_cap = REG(ptr + PCIER_CAPABILITY, 2);
-
-       /*
-        * Only version 1 can be parsed currently 
-        */
-       if ((expr->expr_cap & PCIEM_CAP_VER_MASK) != PCIEM_CAP_VER_1)
-               return;
-
-       /*
-        * Read slot capabilities.  Slot capabilities exists iff
-        * current port's slot is implemented
-        */
-       if (pcie_slotimpl(cfg))
-               expr->expr_slotcap = REG(ptr + PCIER_SLOTCAP, 4);
-
-#undef REG
-}
-
 static void
-pci_read_capabilities(device_t pcib, pcicfgregs *cfg)
+pci_read_extcap(device_t pcib, pcicfgregs *cfg)
 {
-#define REG(n, w)      \
-       PCIB_READ_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, w)
-
-       int nextptr, ptrptr;
-
-       if ((REG(PCIR_STATUS, 2) & PCIM_STATUS_CAPPRESENT) == 0) {
-               /* No capabilities */
-               return;
-       }
+#define        REG(n, w)       PCIB_READ_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, w)
+#define        WREG(n, v, w)   PCIB_WRITE_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, v, w)
+#if defined(__i386__) || defined(__amd64__)
+       uint64_t addr;
+#endif
+       uint32_t val;
+       int     ptr, nextptr, ptrptr;
 
-       switch (cfg->hdrtype) {
+       switch (cfg->hdrtype & PCIM_HDRTYPE) {
        case 0:
        case 1:
                ptrptr = PCIR_CAP_PTR;
                break;
        case 2:
-               ptrptr = PCIR_CAP_PTR_2;
+               ptrptr = PCIR_CAP_PTR_2;        /* cardbus capabilities ptr */
                break;
        default:
-               return;         /* No capabilities support */
+               return;         /* no extended capabilities support */
        }
-       nextptr = REG(ptrptr, 1);
+       nextptr = REG(ptrptr, 1);       /* sanity check? */
 
        /*
         * Read capability entries.
         */
-       while (pci_fixup_nextptr(&nextptr)) {
-               int ptr = nextptr;
+       while (nextptr != 0) {
+               /* Sanity check */
+               if (nextptr > 255) {
+                       kprintf("illegal PCI extended capability offset %d\n",
+                           nextptr);
+                       return;
+               }
+               /* Find the next entry */
+               ptr = nextptr;
+               nextptr = REG(ptr + PCICAP_NEXTPTR, 1);
 
                /* Process this entry */
                switch (REG(ptr + PCICAP_ID, 1)) {
                case PCIY_PMG:          /* PCI power management */
-                       pci_read_cap_pmgt(pcib, ptr, cfg);
+                       if (cfg->pp.pp_cap == 0) {
+                               cfg->pp.pp_cap = REG(ptr + PCIR_POWER_CAP, 2);
+                               cfg->pp.pp_status = ptr + PCIR_POWER_STATUS;
+                               cfg->pp.pp_pmcsr = ptr + PCIR_POWER_PMCSR;
+                               if ((nextptr - ptr) > PCIR_POWER_DATA)
+                                       cfg->pp.pp_data = ptr + PCIR_POWER_DATA;
+                       }
                        break;
-               case PCIY_PCIX:         /* PCI-X */
-                       cfg->pcixcap_ptr = ptr;
+#if notyet
+#if defined(__i386__) || defined(__amd64__)
+               case PCIY_HT:           /* HyperTransport */
+                       /* Determine HT-specific capability type. */
+                       val = REG(ptr + PCIR_HT_COMMAND, 2);
+                       switch (val & PCIM_HTCMD_CAP_MASK) {
+                       case PCIM_HTCAP_MSI_MAPPING:
+                               if (!(val & PCIM_HTCMD_MSI_FIXED)) {
+                                       /* Sanity check the mapping window. */
+                                       addr = REG(ptr + PCIR_HTMSI_ADDRESS_HI,
+                                           4);
+                                       addr <<= 32;
+                                       addr |= REG(ptr + PCIR_HTMSI_ADDRESS_LO,
+                                           4);
+                                       if (addr != MSI_INTEL_ADDR_BASE)
+                                               device_printf(pcib,
+           "HT Bridge at pci%d:%d:%d:%d has non-default MSI window 0x%llx\n",
+                                                   cfg->domain, cfg->bus,
+                                                   cfg->slot, cfg->func,
+                                                   (long long)addr);
+                               } else
+                                       addr = MSI_INTEL_ADDR_BASE;
+
+                               cfg->ht.ht_msimap = ptr;
+                               cfg->ht.ht_msictrl = val;
+                               cfg->ht.ht_msiaddr = addr;
+                               break;
+                       }
+                       break;
+#endif
+               case PCIY_MSI:          /* PCI MSI */
+                       cfg->msi.msi_location = ptr;
+                       cfg->msi.msi_ctrl = REG(ptr + PCIR_MSI_CTRL, 2);
+                       cfg->msi.msi_msgnum = 1 << ((cfg->msi.msi_ctrl &
+                                                    PCIM_MSICTRL_MMC_MASK)>>1);
                        break;
-               case PCIY_EXPRESS:      /* PCI Express */
-                       pci_read_cap_expr(pcib, ptr, cfg);
+               case PCIY_MSIX:         /* PCI MSI-X */
+                       cfg->msix.msix_location = ptr;
+                       cfg->msix.msix_ctrl = REG(ptr + PCIR_MSIX_CTRL, 2);
+                       cfg->msix.msix_msgnum = (cfg->msix.msix_ctrl &
+                           PCIM_MSIXCTRL_TABLE_SIZE) + 1;
+                       val = REG(ptr + PCIR_MSIX_TABLE, 4);
+                       cfg->msix.msix_table_bar = PCIR_BAR(val &
+                           PCIM_MSIX_BIR_MASK);
+                       cfg->msix.msix_table_offset = val & ~PCIM_MSIX_BIR_MASK;
+                       val = REG(ptr + PCIR_MSIX_PBA, 4);
+                       cfg->msix.msix_pba_bar = PCIR_BAR(val &
+                           PCIM_MSIX_BIR_MASK);
+                       cfg->msix.msix_pba_offset = val & ~PCIM_MSIX_BIR_MASK;
+                       break;
+#endif
+               case PCIY_VPD:          /* PCI Vital Product Data */
+                       cfg->vpd.vpd_reg = ptr;
+                       break;
+               case PCIY_SUBVENDOR:
+                       /* Should always be true. */
+                       if ((cfg->hdrtype & PCIM_HDRTYPE) == 1) {
+                               val = REG(ptr + PCIR_SUBVENDCAP_ID, 4);
+                               cfg->subvendor = val & 0xffff;
+                               cfg->subdevice = val >> 16;
+                       }
+                       break;
+               case PCIY_PCIX:         /* PCI-X */
+                       /*
+                        * Assume we have a PCI-X chipset if we have
+                        * at least one PCI-PCI bridge with a PCI-X
+                        * capability.  Note that some systems with
+                        * PCI-express or HT chipsets might match on
+                        * this check as well.
+                        */
+                       if ((cfg->hdrtype & PCIM_HDRTYPE) == 1)
+                               pcix_chipset = 1;
                        break;
-               case PCIY_VPD:          /* Vital Product Data */
-                       cfg->vpdcap_ptr = ptr;
+               case PCIY_EXPRESS:      /* PCI-express */
+                       /*
+                        * Assume we have a PCI-express chipset if we have
+                        * at least one PCI-express device.
+                        */
+                       pcie_chipset = 1;
                        break;
                default:
                        break;
                }
-
-               /* Find the next entry */
-               nextptr = REG(ptr + PCICAP_NEXTPTR, 1);
        }
-
-#undef REG
+/* REG and WREG use carry through to next functions */
 }
 
-/* free pcicfgregs structure and all depending data structures */
+/*
+ * PCI Vital Product Data
+ */
+
+#define        PCI_VPD_TIMEOUT         1000000
 
-int
-pci_freecfg(struct pci_devinfo *dinfo)
+static int
+pci_read_vpd_reg(device_t pcib, pcicfgregs *cfg, int reg, uint32_t *data)
 {
-       struct devlist *devlist_head;
+       int count = PCI_VPD_TIMEOUT;
 
-       devlist_head = &pci_devq;
+       KASSERT((reg & 3) == 0, ("VPD register must by 4 byte aligned"));
 
-       if (dinfo->cfg.hdrspec != NULL)
-               kfree(dinfo->cfg.hdrspec, M_DEVBUF);
-       /* XXX this hasn't been tested */
-       STAILQ_REMOVE(devlist_head, dinfo, pci_devinfo, pci_links);
-       kfree(dinfo, M_DEVBUF);
+       WREG(cfg->vpd.vpd_reg + PCIR_VPD_ADDR, reg, 2);
 
-       /* increment the generation count */
-       pci_generation++;
+       while ((REG(cfg->vpd.vpd_reg + PCIR_VPD_ADDR, 2) & 0x8000) != 0x8000) {
+               if (--count < 0)
+                       return (ENXIO);
+               DELAY(1);       /* limit looping */
+       }
+       *data = (REG(cfg->vpd.vpd_reg + PCIR_VPD_DATA, 4));
 
-       /* we're losing one device */
-       pci_numdevs--;
        return (0);
 }
 
-
-/*
- * PCI power manangement
- */
-int
-pci_set_powerstate_method(device_t dev, device_t child, int state)
+#if 0
+static int
+pci_write_vpd_reg(device_t pcib, pcicfgregs *cfg, int reg, uint32_t data)
 {
-       struct pci_devinfo *dinfo = device_get_ivars(child);
-       pcicfgregs *cfg = &dinfo->cfg;
+       int count = PCI_VPD_TIMEOUT;
+
+       KASSERT((reg & 3) == 0, ("VPD register must by 4 byte aligned"));
+
+       WREG(cfg->vpd.vpd_reg + PCIR_VPD_DATA, data, 4);
+       WREG(cfg->vpd.vpd_reg + PCIR_VPD_ADDR, reg | 0x8000, 2);
+       while ((REG(cfg->vpd.vpd_reg + PCIR_VPD_ADDR, 2) & 0x8000) == 0x8000) {
+               if (--count < 0)
+                       return (ENXIO);
+               DELAY(1);       /* limit looping */
+       }
+
+       return (0);
+}
+#endif
+
+#undef PCI_VPD_TIMEOUT
+
+struct vpd_readstate {
+       device_t        pcib;
+       pcicfgregs      *cfg;
+       uint32_t        val;
+       int             bytesinval;
+       int             off;
+       uint8_t         cksum;
+};
+
+static int
+vpd_nextbyte(struct vpd_readstate *vrs, uint8_t *data)
+{
+       uint32_t reg;
+       uint8_t byte;
+
+       if (vrs->bytesinval == 0) {
+               if (pci_read_vpd_reg(vrs->pcib, vrs->cfg, vrs->off, &reg))
+                       return (ENXIO);
+               vrs->val = le32toh(reg);
+               vrs->off += 4;
+               byte = vrs->val & 0xff;
+               vrs->bytesinval = 3;
+       } else {
+               vrs->val = vrs->val >> 8;
+               byte = vrs->val & 0xff;
+               vrs->bytesinval--;
+       }
+
+       vrs->cksum += byte;
+       *data = byte;
+       return (0);
+}
+
+void
+pcie_set_max_readrq(device_t dev, uint16_t rqsize)
+{
+        int expr_ptr;
+        uint16_t val;
+        rqsize &= PCIEM_DEVCTL_MAX_READRQ_MASK;
+        if (rqsize > PCIEM_DEVCTL_MAX_READRQ_4096) {
+                panic("%s: invalid max read request size 0x%02x\n",
+                      device_get_nameunit(dev), rqsize);
+        }
+#warning "this code is incorrect, I think"
+       pci_find_extcap_method(device_get_parent(dev), dev, PCIY_EXPRESS, &expr_ptr);
+       if(!expr_ptr)
+               panic("%s: not PCI Express\n", device_get_nameunit(dev));
+        val = pci_read_config(dev, expr_ptr + PCIER_DEVCTRL, 2);
+        if ((val & PCIEM_DEVCTL_MAX_READRQ_MASK) != rqsize) {
+                if (bootverbose)
+                        device_printf(dev, "adjust device control 0x%04x", val);
+                val &= ~PCIEM_DEVCTL_MAX_READRQ_MASK;
+                val |= rqsize;
+                pci_write_config(dev, expr_ptr + PCIER_DEVCTRL, val, 2);
+
+                if (bootverbose)
+                        kprintf(" -> 0x%04x\n", val);
+        }
+}
+
+static void
+pci_read_vpd(device_t pcib, pcicfgregs *cfg)
+{
+       struct vpd_readstate vrs;
+       int state;
+       int name;
+       int remain;
+       int i;
+       int alloc, off;         /* alloc/off for RO/W arrays */
+       int cksumvalid;
+       int dflen;
+       uint8_t byte;
+       uint8_t byte2;
+
+       /* init vpd reader */
+       vrs.bytesinval = 0;
+       vrs.off = 0;
+       vrs.pcib = pcib;
+       vrs.cfg = cfg;
+       vrs.cksum = 0;
+
+       state = 0;
+       name = remain = i = 0;  /* shut up stupid gcc */
+       alloc = off = 0;        /* shut up stupid gcc */
+       dflen = 0;              /* shut up stupid gcc */
+       cksumvalid = -1;
+       while (state >= 0) {
+               if (vpd_nextbyte(&vrs, &byte)) {
+                       state = -2;
+                       break;
+               }
+#if 0
+               kprintf("vpd: val: %#x, off: %d, bytesinval: %d, byte: %#hhx, " \
+                   "state: %d, remain: %d, name: %#x, i: %d\n", vrs.val,
+                   vrs.off, vrs.bytesinval, byte, state, remain, name, i);
+#endif
+               switch (state) {
+               case 0:         /* item name */
+                       if (byte & 0x80) {
+                               if (vpd_nextbyte(&vrs, &byte2)) {
+                                       state = -2;
+                                       break;
+                               }
+                               remain = byte2;
+                               if (vpd_nextbyte(&vrs, &byte2)) {
+                                       state = -2;
+                                       break;
+                               }
+                               remain |= byte2 << 8;
+                               if (remain > (0x7f*4 - vrs.off)) {
+                                       state = -1;
+                                       kprintf(
+                           "pci%d:%d:%d:%d: invalid VPD data, remain %#x\n",
+                                           cfg->domain, cfg->bus, cfg->slot,
+                                           cfg->func, remain);
+                               }
+                               name = byte & 0x7f;
+                       } else {
+                               remain = byte & 0x7;
+                               name = (byte >> 3) & 0xf;
+                       }
+                       switch (name) {
+                       case 0x2:       /* String */
+                               cfg->vpd.vpd_ident = kmalloc(remain + 1,
+                                   M_DEVBUF, M_WAITOK);
+                               i = 0;
+                               state = 1;
+                               break;
+                       case 0xf:       /* End */
+                               state = -1;
+                               break;
+                       case 0x10:      /* VPD-R */
+                               alloc = 8;
+                               off = 0;
+                               cfg->vpd.vpd_ros = kmalloc(alloc *
+                                   sizeof(*cfg->vpd.vpd_ros), M_DEVBUF,
+                                   M_WAITOK | M_ZERO);
+                               state = 2;
+                               break;
+                       case 0x11:      /* VPD-W */
+                               alloc = 8;
+                               off = 0;
+                               cfg->vpd.vpd_w = kmalloc(alloc *
+                                   sizeof(*cfg->vpd.vpd_w), M_DEVBUF,
+                                   M_WAITOK | M_ZERO);
+                               state = 5;
+                               break;
+                       default:        /* Invalid data, abort */
+                               state = -1;
+                               break;
+                       }
+                       break;
+
+               case 1: /* Identifier String */
+                       cfg->vpd.vpd_ident[i++] = byte;
+                       remain--;
+                       if (remain == 0)  {
+                               cfg->vpd.vpd_ident[i] = '\0';
+                               state = 0;
+                       }
+                       break;
+
+               case 2: /* VPD-R Keyword Header */
+                       if (off == alloc) {
+                               cfg->vpd.vpd_ros = kreallocf(cfg->vpd.vpd_ros,
+                                   (alloc *= 2) * sizeof(*cfg->vpd.vpd_ros),
+                                   M_DEVBUF, M_WAITOK | M_ZERO);
+                       }
+                       cfg->vpd.vpd_ros[off].keyword[0] = byte;
+                       if (vpd_nextbyte(&vrs, &byte2)) {
+                               state = -2;
+                               break;
+                       }
+                       cfg->vpd.vpd_ros[off].keyword[1] = byte2;
+                       if (vpd_nextbyte(&vrs, &byte2)) {
+                               state = -2;
+                               break;
+                       }
+                       dflen = byte2;
+                       if (dflen == 0 &&
+                           strncmp(cfg->vpd.vpd_ros[off].keyword, "RV",
+                           2) == 0) {
+                               /*
+                                * if this happens, we can't trust the rest
+                                * of the VPD.
+                                */
+                               kprintf(
+                                   "pci%d:%d:%d:%d: bad keyword length: %d\n",
+                                   cfg->domain, cfg->bus, cfg->slot,
+                                   cfg->func, dflen);
+                               cksumvalid = 0;
+                               state = -1;
+                               break;
+                       } else if (dflen == 0) {
+                               cfg->vpd.vpd_ros[off].value = kmalloc(1 *
+                                   sizeof(*cfg->vpd.vpd_ros[off].value),
+                                   M_DEVBUF, M_WAITOK);
+                               cfg->vpd.vpd_ros[off].value[0] = '\x00';
+                       } else
+                               cfg->vpd.vpd_ros[off].value = kmalloc(
+                                   (dflen + 1) *
+                                   sizeof(*cfg->vpd.vpd_ros[off].value),
+                                   M_DEVBUF, M_WAITOK);
+                       remain -= 3;
+                       i = 0;
+                       /* keep in sync w/ state 3's transistions */
+                       if (dflen == 0 && remain == 0)
+                               state = 0;
+                       else if (dflen == 0)
+                               state = 2;
+                       else
+                               state = 3;
+                       break;
+
+               case 3: /* VPD-R Keyword Value */
+                       cfg->vpd.vpd_ros[off].value[i++] = byte;
+                       if (strncmp(cfg->vpd.vpd_ros[off].keyword,
+                           "RV", 2) == 0 && cksumvalid == -1) {
+                               if (vrs.cksum == 0)
+                                       cksumvalid = 1;
+                               else {
+                                       if (bootverbose)
+                                               kprintf(
+                               "pci%d:%d:%d:%d: bad VPD cksum, remain %hhu\n",
+                                                   cfg->domain, cfg->bus,
+                                                   cfg->slot, cfg->func,
+                                                   vrs.cksum);
+                                       cksumvalid = 0;
+                                       state = -1;
+                                       break;
+                               }
+                       }
+                       dflen--;
+                       remain--;
+                       /* keep in sync w/ state 2's transistions */
+                       if (dflen == 0)
+                               cfg->vpd.vpd_ros[off++].value[i++] = '\0';
+                       if (dflen == 0 && remain == 0) {
+                               cfg->vpd.vpd_rocnt = off;
+                               cfg->vpd.vpd_ros = kreallocf(cfg->vpd.vpd_ros,
+                                   off * sizeof(*cfg->vpd.vpd_ros),
+                                   M_DEVBUF, M_WAITOK | M_ZERO);
+                               state = 0;
+                       } else if (dflen == 0)
+                               state = 2;
+                       break;
+
+               case 4:
+                       remain--;
+                       if (remain == 0)
+                               state = 0;
+                       break;
+
+               case 5: /* VPD-W Keyword Header */
+                       if (off == alloc) {
+                               cfg->vpd.vpd_w = kreallocf(cfg->vpd.vpd_w,
+                                   (alloc *= 2) * sizeof(*cfg->vpd.vpd_w),
+                                   M_DEVBUF, M_WAITOK | M_ZERO);
+                       }
+                       cfg->vpd.vpd_w[off].keyword[0] = byte;
+                       if (vpd_nextbyte(&vrs, &byte2)) {
+                               state = -2;
+                               break;
+                       }
+                       cfg->vpd.vpd_w[off].keyword[1] = byte2;
+                       if (vpd_nextbyte(&vrs, &byte2)) {
+                               state = -2;
+                               break;
+                       }
+                       cfg->vpd.vpd_w[off].len = dflen = byte2;
+                       cfg->vpd.vpd_w[off].start = vrs.off - vrs.bytesinval;
+                       cfg->vpd.vpd_w[off].value = kmalloc((dflen + 1) *
+                           sizeof(*cfg->vpd.vpd_w[off].value),
+                           M_DEVBUF, M_WAITOK);
+                       remain -= 3;
+                       i = 0;
+                       /* keep in sync w/ state 6's transistions */
+                       if (dflen == 0 && remain == 0)
+                               state = 0;
+                       else if (dflen == 0)
+                               state = 5;
+                       else
+                               state = 6;
+                       break;
+
+               case 6: /* VPD-W Keyword Value */
+                       cfg->vpd.vpd_w[off].value[i++] = byte;
+                       dflen--;
+                       remain--;
+                       /* keep in sync w/ state 5's transistions */
+                       if (dflen == 0)
+                               cfg->vpd.vpd_w[off++].value[i++] = '\0';
+                       if (dflen == 0 && remain == 0) {
+                               cfg->vpd.vpd_wcnt = off;
+                               cfg->vpd.vpd_w = kreallocf(cfg->vpd.vpd_w,
+                                   off * sizeof(*cfg->vpd.vpd_w),
+                                   M_DEVBUF, M_WAITOK | M_ZERO);
+                               state = 0;
+                       } else if (dflen == 0)
+                               state = 5;
+                       break;
+
+               default:
+                       kprintf("pci%d:%d:%d:%d: invalid state: %d\n",
+                           cfg->domain, cfg->bus, cfg->slot, cfg->func,
+                           state);
+                       state = -1;
+                       break;
+               }
+       }
+
+       if (cksumvalid == 0 || state < -1) {
+               /* read-only data bad, clean up */
+               if (cfg->vpd.vpd_ros != NULL) {
+                       for (off = 0; cfg->vpd.vpd_ros[off].value; off++)
+                               kfree(cfg->vpd.vpd_ros[off].value, M_DEVBUF);
+                       kfree(cfg->vpd.vpd_ros, M_DEVBUF);
+                       cfg->vpd.vpd_ros = NULL;
+               }
+       }
+       if (state < -1) {
+               /* I/O error, clean up */
+               kprintf("pci%d:%d:%d:%d: failed to read VPD data.\n",
+                   cfg->domain, cfg->bus, cfg->slot, cfg->func);
+               if (cfg->vpd.vpd_ident != NULL) {
+                       kfree(cfg->vpd.vpd_ident, M_DEVBUF);
+                       cfg->vpd.vpd_ident = NULL;
+               }
+               if (cfg->vpd.vpd_w != NULL) {
+                       for (off = 0; cfg->vpd.vpd_w[off].value; off++)
+                               kfree(cfg->vpd.vpd_w[off].value, M_DEVBUF);
+                       kfree(cfg->vpd.vpd_w, M_DEVBUF);
+                       cfg->vpd.vpd_w = NULL;
+               }
+       }
+       cfg->vpd.vpd_cached = 1;
+#undef REG
+#undef WREG
+}
+
+int
+pci_get_vpd_ident_method(device_t dev, device_t child, const char **identptr)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(child);
+       pcicfgregs *cfg = &dinfo->cfg;
+
+       if (!cfg->vpd.vpd_cached && cfg->vpd.vpd_reg != 0)
+               pci_read_vpd(device_get_parent(dev), cfg);
+
+       *identptr = cfg->vpd.vpd_ident;
+
+       if (*identptr == NULL)
+               return (ENXIO);
+
+       return (0);
+}
+
+int
+pci_get_vpd_readonly_method(device_t dev, device_t child, const char *kw,
+       const char **vptr)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(child);
+       pcicfgregs *cfg = &dinfo->cfg;
+       int i;
+
+       if (!cfg->vpd.vpd_cached && cfg->vpd.vpd_reg != 0)
+               pci_read_vpd(device_get_parent(dev), cfg);
+
+       for (i = 0; i < cfg->vpd.vpd_rocnt; i++)
+               if (memcmp(kw, cfg->vpd.vpd_ros[i].keyword,
+                   sizeof(cfg->vpd.vpd_ros[i].keyword)) == 0) {
+                       *vptr = cfg->vpd.vpd_ros[i].value;
+               }
+
+       if (i != cfg->vpd.vpd_rocnt)
+               return (0);
+
+       *vptr = NULL;
+       return (ENXIO);
+}
+
+/*
+ * Return the offset in configuration space of the requested extended
+ * capability entry or 0 if the specified capability was not found.
+ */
+int
+pci_find_extcap_method(device_t dev, device_t child, int capability,
+    int *capreg)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(child);
+       pcicfgregs *cfg = &dinfo->cfg;
+       u_int32_t status;
+       u_int8_t ptr;
+
+       /*
+        * Check the CAP_LIST bit of the PCI status register first.
+        */
+       status = pci_read_config(child, PCIR_STATUS, 2);
+       if (!(status & PCIM_STATUS_CAPPRESENT))
+               return (ENXIO);
+
+       /*
+        * Determine the start pointer of the capabilities list.
+        */
+       switch (cfg->hdrtype & PCIM_HDRTYPE) {
+       case 0:
+       case 1:
+               ptr = PCIR_CAP_PTR;
+               break;
+       case 2:
+               ptr = PCIR_CAP_PTR_2;
+               break;
+       default:
+               /* XXX: panic? */
+               return (ENXIO);         /* no extended capabilities support */
+       }
+       ptr = pci_read_config(child, ptr, 1);
+
+       /*
+        * Traverse the capabilities list.
+        */
+       while (ptr != 0) {
+               if (pci_read_config(child, ptr + PCICAP_ID, 1) == capability) {
+                       if (capreg != NULL)
+                               *capreg = ptr;
+                       return (0);
+               }
+               ptr = pci_read_config(child, ptr + PCICAP_NEXTPTR, 1);
+       }
+
+       return (ENOENT);
+}
+
+/*
+ * Support for MSI-X message interrupts.
+ */
+void
+pci_enable_msix(device_t dev, u_int index, uint64_t address, uint32_t data)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(dev);
+       struct pcicfg_msix *msix = &dinfo->cfg.msix;
+       uint32_t offset;
+
+       KASSERT(msix->msix_table_len > index, ("bogus index"));
+       offset = msix->msix_table_offset + index * 16;
+       bus_write_4(msix->msix_table_res, offset, address & 0xffffffff);
+       bus_write_4(msix->msix_table_res, offset + 4, address >> 32);
+       bus_write_4(msix->msix_table_res, offset + 8, data);
+
+       /* Enable MSI -> HT mapping. */
+       pci_ht_map_msi(dev, address);
+}
+
+void
+pci_mask_msix(device_t dev, u_int index)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(dev);
+       struct pcicfg_msix *msix = &dinfo->cfg.msix;
+       uint32_t offset, val;
+
+       KASSERT(msix->msix_msgnum > index, ("bogus index"));
+       offset = msix->msix_table_offset + index * 16 + 12;
+       val = bus_read_4(msix->msix_table_res, offset);
+       if (!(val & PCIM_MSIX_VCTRL_MASK)) {
+               val |= PCIM_MSIX_VCTRL_MASK;
+               bus_write_4(msix->msix_table_res, offset, val);
+       }
+}
+
+void
+pci_unmask_msix(device_t dev, u_int index)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(dev);
+       struct pcicfg_msix *msix = &dinfo->cfg.msix;
+       uint32_t offset, val;
+
+       KASSERT(msix->msix_table_len > index, ("bogus index"));
+       offset = msix->msix_table_offset + index * 16 + 12;
+       val = bus_read_4(msix->msix_table_res, offset);
+       if (val & PCIM_MSIX_VCTRL_MASK) {
+               val &= ~PCIM_MSIX_VCTRL_MASK;
+               bus_write_4(msix->msix_table_res, offset, val);
+       }
+}
+
+int
+pci_pending_msix(device_t dev, u_int index)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(dev);
+       struct pcicfg_msix *msix = &dinfo->cfg.msix;
+       uint32_t offset, bit;
+
+       KASSERT(msix->msix_table_len > index, ("bogus index"));
+       offset = msix->msix_pba_offset + (index / 32) * 4;
+       bit = 1 << index % 32;
+       return (bus_read_4(msix->msix_pba_res, offset) & bit);
+}
+
+/*
+ * Restore MSI-X registers and table during resume.  If MSI-X is
+ * enabled then walk the virtual table to restore the actual MSI-X
+ * table.
+ */
+static void
+pci_resume_msix(device_t dev)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(dev);
+       struct pcicfg_msix *msix = &dinfo->cfg.msix;
+       struct msix_table_entry *mte;
+       struct msix_vector *mv;
+       int i;
+
+       if (msix->msix_alloc > 0) {
+               /* First, mask all vectors. */
+               for (i = 0; i < msix->msix_msgnum; i++)
+                       pci_mask_msix(dev, i);
+
+               /* Second, program any messages with at least one handler. */
+               for (i = 0; i < msix->msix_table_len; i++) {
+                       mte = &msix->msix_table[i];
+                       if (mte->mte_vector == 0 || mte->mte_handlers == 0)
+                               continue;
+                       mv = &msix->msix_vectors[mte->mte_vector - 1];
+                       pci_enable_msix(dev, i, mv->mv_address, mv->mv_data);
+                       pci_unmask_msix(dev, i);
+               }
+       }
+       pci_write_config(dev, msix->msix_location + PCIR_MSIX_CTRL,
+           msix->msix_ctrl, 2);
+}
+
+/*
+ * Attempt to allocate *count MSI-X messages.  The actual number allocated is
+ * returned in *count.  After this function returns, each message will be
+ * available to the driver as SYS_RES_IRQ resources starting at rid 1.
+ */
+int
+pci_alloc_msix_method(device_t dev, device_t child, int *count)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(child);
+       pcicfgregs *cfg = &dinfo->cfg;
+       struct resource_list_entry *rle;
+       int actual, error, i, irq, max;
+
+       /* Don't let count == 0 get us into trouble. */
+       if (*count == 0)
+               return (EINVAL);
+
+       /* If rid 0 is allocated, then fail. */
+       rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 0);
+       if (rle != NULL && rle->res != NULL)
+               return (ENXIO);
+
+       /* Already have allocated messages? */
+       if (cfg->msi.msi_alloc != 0 || cfg->msix.msix_alloc != 0)
+               return (ENXIO);
+
+       /* If MSI is blacklisted for this system, fail. */
+       if (pci_msi_blacklisted())
+               return (ENXIO);
+
+       /* MSI-X capability present? */
+       if (cfg->msix.msix_location == 0 || !pci_do_msix)
+               return (ENODEV);
+
+       /* Make sure the appropriate BARs are mapped. */
+       rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY,
+           cfg->msix.msix_table_bar);
+       if (rle == NULL || rle->res == NULL ||
+           !(rman_get_flags(rle->res) & RF_ACTIVE))
+               return (ENXIO);
+       cfg->msix.msix_table_res = rle->res;
+       if (cfg->msix.msix_pba_bar != cfg->msix.msix_table_bar) {
+               rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY,
+                   cfg->msix.msix_pba_bar);
+               if (rle == NULL || rle->res == NULL ||
+                   !(rman_get_flags(rle->res) & RF_ACTIVE))
+                       return (ENXIO);
+       }
+       cfg->msix.msix_pba_res = rle->res;
+
+       if (bootverbose)
+               device_printf(child,
+                   "attempting to allocate %d MSI-X vectors (%d supported)\n",
+                   *count, cfg->msix.msix_msgnum);
+       max = min(*count, cfg->msix.msix_msgnum);
+       for (i = 0; i < max; i++) {
+               /* Allocate a message. */
+               error = PCIB_ALLOC_MSIX(device_get_parent(dev), child, &irq);
+               if (error)
+                       break;
+               resource_list_add(&dinfo->resources, SYS_RES_IRQ, i + 1, irq,
+                   irq, 1);
+       }
+       actual = i;
+
+       if (bootverbose) {
+               rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 1);
+               if (actual == 1)
+                       device_printf(child, "using IRQ %lu for MSI-X\n",
+                           rle->start);
+               else {
+                       int run;
+
+                       /*
+                        * Be fancy and try to print contiguous runs of
+                        * IRQ values as ranges.  'irq' is the previous IRQ.
+                        * 'run' is true if we are in a range.
+                        */
+                       device_printf(child, "using IRQs %lu", rle->start);
+                       irq = rle->start;
+                       run = 0;
+                       for (i = 1; i < actual; i++) {
+                               rle = resource_list_find(&dinfo->resources,
+                                   SYS_RES_IRQ, i + 1);
+
+                               /* Still in a run? */
+                               if (rle->start == irq + 1) {
+                                       run = 1;
+                                       irq++;
+                                       continue;
+                               }
+
+                               /* Finish previous range. */
+                               if (run) {
+                                       kprintf("-%d", irq);
+                                       run = 0;
+                               }
+
+                               /* Start new range. */
+                               kprintf(",%lu", rle->start);
+                               irq = rle->start;
+                       }
+
+                       /* Unfinished range? */
+                       if (run)
+                               kprintf("-%d", irq);
+                       kprintf(" for MSI-X\n");
+               }
+       }
+
+       /* Mask all vectors. */
+       for (i = 0; i < cfg->msix.msix_msgnum; i++)
+               pci_mask_msix(child, i);
+
+       /* Allocate and initialize vector data and virtual table. */
+       cfg->msix.msix_vectors = kmalloc(sizeof(struct msix_vector) * actual,
+           M_DEVBUF, M_WAITOK | M_ZERO);
+       cfg->msix.msix_table = kmalloc(sizeof(struct msix_table_entry) * actual,
+           M_DEVBUF, M_WAITOK | M_ZERO);
+       for (i = 0; i < actual; i++) {
+               rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i + 1);
+               cfg->msix.msix_vectors[i].mv_irq = rle->start;
+               cfg->msix.msix_table[i].mte_vector = i + 1;
+       }
+
+       /* Update control register to enable MSI-X. */
+       cfg->msix.msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE;
+       pci_write_config(child, cfg->msix.msix_location + PCIR_MSIX_CTRL,
+           cfg->msix.msix_ctrl, 2);
+
+       /* Update counts of alloc'd messages. */
+       cfg->msix.msix_alloc = actual;
+       cfg->msix.msix_table_len = actual;
+       *count = actual;
+       return (0);
+}
+
+/*
+ * By default, pci_alloc_msix() will assign the allocated IRQ
+ * resources consecutively to the first N messages in the MSI-X table.
+ * However, device drivers may want to use different layouts if they
+ * either receive fewer messages than they asked for, or they wish to
+ * populate the MSI-X table sparsely.  This method allows the driver
+ * to specify what layout it wants.  It must be called after a
+ * successful pci_alloc_msix() but before any of the associated
+ * SYS_RES_IRQ resources are allocated via bus_alloc_resource().
+ *
+ * The 'vectors' array contains 'count' message vectors.  The array
+ * maps directly to the MSI-X table in that index 0 in the array
+ * specifies the vector for the first message in the MSI-X table, etc.
+ * The vector value in each array index can either be 0 to indicate
+ * that no vector should be assigned to a message slot, or it can be a
+ * number from 1 to N (where N is the count returned from a
+ * succcessful call to pci_alloc_msix()) to indicate which message
+ * vector (IRQ) to be used for the corresponding message.
+ *
+ * On successful return, each message with a non-zero vector will have
+ * an associated SYS_RES_IRQ whose rid is equal to the array index +
+ * 1.  Additionally, if any of the IRQs allocated via the previous
+ * call to pci_alloc_msix() are not used in the mapping, those IRQs
+ * will be kfreed back to the system automatically.
+ *
+ * For example, suppose a driver has a MSI-X table with 6 messages and
+ * asks for 6 messages, but pci_alloc_msix() only returns a count of
+ * 3.  Call the three vectors allocated by pci_alloc_msix() A, B, and
+ * C.  After the call to pci_alloc_msix(), the device will be setup to
+ * have an MSI-X table of ABC--- (where - means no vector assigned).
+ * If the driver ten passes a vector array of { 1, 0, 1, 2, 0, 2 },
+ * then the MSI-X table will look like A-AB-B, and the 'C' vector will
+ * be kfreed back to the system.  This device will also have valid
+ * SYS_RES_IRQ rids of 1, 3, 4, and 6.
+ *
+ * In any case, the SYS_RES_IRQ rid X will always map to the message
+ * at MSI-X table index X - 1 and will only be valid if a vector is
+ * assigned to that table entry.
+ */
+int
+pci_remap_msix_method(device_t dev, device_t child, int count,
+    const u_int *vectors)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(child);
+       struct pcicfg_msix *msix = &dinfo->cfg.msix;
+       struct resource_list_entry *rle;
+       int i, irq, j, *used;
+
+       /*
+        * Have to have at least one message in the table but the
+        * table can't be bigger than the actual MSI-X table in the
+        * device.
+        */
+       if (count == 0 || count > msix->msix_msgnum)
+               return (EINVAL);
+
+       /* Sanity check the vectors. */
+       for (i = 0; i < count; i++)
+               if (vectors[i] > msix->msix_alloc)
+                       return (EINVAL);
+
+       /*
+        * Make sure there aren't any holes in the vectors to be used.
+        * It's a big pain to support it, and it doesn't really make
+        * sense anyway.  Also, at least one vector must be used.
+        */
+       used = kmalloc(sizeof(int) * msix->msix_alloc, M_DEVBUF, M_WAITOK |
+           M_ZERO);
+       for (i = 0; i < count; i++)
+               if (vectors[i] != 0)
+                       used[vectors[i] - 1] = 1;
+       for (i = 0; i < msix->msix_alloc - 1; i++)
+               if (used[i] == 0 && used[i + 1] == 1) {
+                       kfree(used, M_DEVBUF);
+                       return (EINVAL);
+               }
+       if (used[0] != 1) {
+               kfree(used, M_DEVBUF);
+               return (EINVAL);
+       }
+       
+       /* Make sure none of the resources are allocated. */
+       for (i = 0; i < msix->msix_table_len; i++) {
+               if (msix->msix_table[i].mte_vector == 0)
+                       continue;
+               if (msix->msix_table[i].mte_handlers > 0)
+                       return (EBUSY);
+               rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i + 1);
+               KASSERT(rle != NULL, ("missing resource"));
+               if (rle->res != NULL)
+                       return (EBUSY);
+       }
+
+       /* Free the existing resource list entries. */
+       for (i = 0; i < msix->msix_table_len; i++) {
+               if (msix->msix_table[i].mte_vector == 0)
+                       continue;
+               resource_list_delete(&dinfo->resources, SYS_RES_IRQ, i + 1);
+       }
+
+       /*
+        * Build the new virtual table keeping track of which vectors are
+        * used.
+        */
+       kfree(msix->msix_table, M_DEVBUF);
+       msix->msix_table = kmalloc(sizeof(struct msix_table_entry) * count,
+           M_DEVBUF, M_WAITOK | M_ZERO);
+       for (i = 0; i < count; i++)
+               msix->msix_table[i].mte_vector = vectors[i];
+       msix->msix_table_len = count;
+
+       /* Free any unused IRQs and resize the vectors array if necessary. */
+       j = msix->msix_alloc - 1;
+       if (used[j] == 0) {
+               struct msix_vector *vec;
+
+               while (used[j] == 0) {
+                       PCIB_RELEASE_MSIX(device_get_parent(dev), child,
+                           msix->msix_vectors[j].mv_irq);
+                       j--;
+               }
+               vec = kmalloc(sizeof(struct msix_vector) * (j + 1), M_DEVBUF,
+                   M_WAITOK);
+               bcopy(msix->msix_vectors, vec, sizeof(struct msix_vector) *
+                   (j + 1));
+               kfree(msix->msix_vectors, M_DEVBUF);
+               msix->msix_vectors = vec;
+               msix->msix_alloc = j + 1;
+       }
+       kfree(used, M_DEVBUF);
+
+       /* Map the IRQs onto the rids. */
+       for (i = 0; i < count; i++) {
+               if (vectors[i] == 0)
+                       continue;
+               irq = msix->msix_vectors[vectors[i]].mv_irq;
+               resource_list_add(&dinfo->resources, SYS_RES_IRQ, i + 1, irq,
+                   irq, 1);
+       }
+
+       if (bootverbose) {
+               device_printf(child, "Remapped MSI-X IRQs as: ");
+               for (i = 0; i < count; i++) {
+                       if (i != 0)
+                               kprintf(", ");
+                       if (vectors[i] == 0)
+                               kprintf("---");
+                       else
+                               kprintf("%d",
+                                   msix->msix_vectors[vectors[i]].mv_irq);
+               }
+               kprintf("\n");
+       }
+
+       return (0);
+}
+
+static int
+pci_release_msix(device_t dev, device_t child)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(child);
+       struct pcicfg_msix *msix = &dinfo->cfg.msix;
+       struct resource_list_entry *rle;
+       int i;
+
+       /* Do we have any messages to release? */
+       if (msix->msix_alloc == 0)
+               return (ENODEV);
+
+       /* Make sure none of the resources are allocated. */
+       for (i = 0; i < msix->msix_table_len; i++) {
+               if (msix->msix_table[i].mte_vector == 0)
+                       continue;
+               if (msix->msix_table[i].mte_handlers > 0)
+                       return (EBUSY);
+               rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i + 1);
+               KASSERT(rle != NULL, ("missing resource"));
+               if (rle->res != NULL)
+                       return (EBUSY);
+       }
+
+       /* Update control register to disable MSI-X. */
+       msix->msix_ctrl &= ~PCIM_MSIXCTRL_MSIX_ENABLE;
+       pci_write_config(child, msix->msix_location + PCIR_MSIX_CTRL,
+           msix->msix_ctrl, 2);
+
+       /* Free the resource list entries. */
+       for (i = 0; i < msix->msix_table_len; i++) {
+               if (msix->msix_table[i].mte_vector == 0)
+                       continue;
+               resource_list_delete(&dinfo->resources, SYS_RES_IRQ, i + 1);
+       }
+       kfree(msix->msix_table, M_DEVBUF);
+       msix->msix_table_len = 0;
+
+       /* Release the IRQs. */
+       for (i = 0; i < msix->msix_alloc; i++)
+               PCIB_RELEASE_MSIX(device_get_parent(dev), child,
+                   msix->msix_vectors[i].mv_irq);
+       kfree(msix->msix_vectors, M_DEVBUF);
+       msix->msix_alloc = 0;
+       return (0);
+}
+
+/*
+ * Return the max supported MSI-X messages this device supports.
+ * Basically, assuming the MD code can alloc messages, this function
+ * should return the maximum value that pci_alloc_msix() can return.
+ * Thus, it is subject to the tunables, etc.
+ */
+int
+pci_msix_count_method(device_t dev, device_t child)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(child);
+       struct pcicfg_msix *msix = &dinfo->cfg.msix;
+
+       if (pci_do_msix && msix->msix_location != 0)
+               return (msix->msix_msgnum);
+       return (0);
+}
+
+/*
+ * HyperTransport MSI mapping control
+ */
+void
+pci_ht_map_msi(device_t dev, uint64_t addr)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(dev);
+       struct pcicfg_ht *ht = &dinfo->cfg.ht;
+
+       if (!ht->ht_msimap)
+               return;
+
+       if (addr && !(ht->ht_msictrl & PCIM_HTCMD_MSI_ENABLE) &&
+           ht->ht_msiaddr >> 20 == addr >> 20) {
+               /* Enable MSI -> HT mapping. */
+               ht->ht_msictrl |= PCIM_HTCMD_MSI_ENABLE;
+               pci_write_config(dev, ht->ht_msimap + PCIR_HT_COMMAND,
+                   ht->ht_msictrl, 2);
+       }
+
+       if (!addr && ht->ht_msictrl & PCIM_HTCMD_MSI_ENABLE) {
+               /* Disable MSI -> HT mapping. */
+               ht->ht_msictrl &= ~PCIM_HTCMD_MSI_ENABLE;
+               pci_write_config(dev, ht->ht_msimap + PCIR_HT_COMMAND,
+                   ht->ht_msictrl, 2);
+       }
+}
+
+/*
+ * Support for MSI message signalled interrupts.
+ */
+void
+pci_enable_msi(device_t dev, uint64_t address, uint16_t data)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(dev);
+       struct pcicfg_msi *msi = &dinfo->cfg.msi;
+
+       /* Write data and address values. */
+       pci_write_config(dev, msi->msi_location + PCIR_MSI_ADDR,
+           address & 0xffffffff, 4);
+       if (msi->msi_ctrl & PCIM_MSICTRL_64BIT) {
+               pci_write_config(dev, msi->msi_location + PCIR_MSI_ADDR_HIGH,
+                   address >> 32, 4);
+               pci_write_config(dev, msi->msi_location + PCIR_MSI_DATA_64BIT,
+                   data, 2);
+       } else
+               pci_write_config(dev, msi->msi_location + PCIR_MSI_DATA, data,
+                   2);
+
+       /* Enable MSI in the control register. */
+       msi->msi_ctrl |= PCIM_MSICTRL_MSI_ENABLE;
+       pci_write_config(dev, msi->msi_location + PCIR_MSI_CTRL, msi->msi_ctrl,
+           2);
+
+       /* Enable MSI -> HT mapping. */
+       pci_ht_map_msi(dev, address);
+}
+
+void
+pci_disable_msi(device_t dev)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(dev);
+       struct pcicfg_msi *msi = &dinfo->cfg.msi;
+
+       /* Disable MSI -> HT mapping. */
+       pci_ht_map_msi(dev, 0);
+
+       /* Disable MSI in the control register. */
+       msi->msi_ctrl &= ~PCIM_MSICTRL_MSI_ENABLE;
+       pci_write_config(dev, msi->msi_location + PCIR_MSI_CTRL, msi->msi_ctrl,
+           2);
+}
+
+/*
+ * Restore MSI registers during resume.  If MSI is enabled then
+ * restore the data and address registers in addition to the control
+ * register.
+ */
+static void
+pci_resume_msi(device_t dev)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(dev);
+       struct pcicfg_msi *msi = &dinfo->cfg.msi;
+       uint64_t address;
+       uint16_t data;
+
+       if (msi->msi_ctrl & PCIM_MSICTRL_MSI_ENABLE) {
+               address = msi->msi_addr;
+               data = msi->msi_data;
+               pci_write_config(dev, msi->msi_location + PCIR_MSI_ADDR,
+                   address & 0xffffffff, 4);
+               if (msi->msi_ctrl & PCIM_MSICTRL_64BIT) {
+                       pci_write_config(dev, msi->msi_location +
+                           PCIR_MSI_ADDR_HIGH, address >> 32, 4);
+                       pci_write_config(dev, msi->msi_location +
+                           PCIR_MSI_DATA_64BIT, data, 2);
+               } else
+                       pci_write_config(dev, msi->msi_location + PCIR_MSI_DATA,
+                           data, 2);
+       }
+       pci_write_config(dev, msi->msi_location + PCIR_MSI_CTRL, msi->msi_ctrl,
+           2);
+}
+
+int
+pci_remap_msi_irq(device_t dev, u_int irq)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(dev);
+       pcicfgregs *cfg = &dinfo->cfg;
+       struct resource_list_entry *rle;
+       struct msix_table_entry *mte;
+       struct msix_vector *mv;
+       device_t bus;
+       uint64_t addr;
+       uint32_t data;  
+       int error, i, j;
+
+       bus = device_get_parent(dev);
+
+       /*
+        * Handle MSI first.  We try to find this IRQ among our list
+        * of MSI IRQs.  If we find it, we request updated address and
+        * data registers and apply the results.
+        */
+       if (cfg->msi.msi_alloc > 0) {
+
+               /* If we don't have any active handlers, nothing to do. */
+               if (cfg->msi.msi_handlers == 0)
+                       return (0);
+               for (i = 0; i < cfg->msi.msi_alloc; i++) {
+                       rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ,
+                           i + 1);
+                       if (rle->start == irq) {
+                               error = PCIB_MAP_MSI(device_get_parent(bus),
+                                   dev, irq, &addr, &data);
+                               if (error)
+                                       return (error);
+                               pci_disable_msi(dev);
+                               dinfo->cfg.msi.msi_addr = addr;
+                               dinfo->cfg.msi.msi_data = data;
+                               pci_enable_msi(dev, addr, data);
+                               return (0);
+                       }
+               }
+               return (ENOENT);
+       }
+
+       /*
+        * For MSI-X, we check to see if we have this IRQ.  If we do,
+        * we request the updated mapping info.  If that works, we go
+        * through all the slots that use this IRQ and update them.
+        */
+       if (cfg->msix.msix_alloc > 0) {
+               for (i = 0; i < cfg->msix.msix_alloc; i++) {
+                       mv = &cfg->msix.msix_vectors[i];
+                       if (mv->mv_irq == irq) {
+                               error = PCIB_MAP_MSI(device_get_parent(bus),
+                                   dev, irq, &addr, &data);
+                               if (error)
+                                       return (error);
+                               mv->mv_address = addr;
+                               mv->mv_data = data;
+                               for (j = 0; j < cfg->msix.msix_table_len; j++) {
+                                       mte = &cfg->msix.msix_table[j];
+                                       if (mte->mte_vector != i + 1)
+                                               continue;
+                                       if (mte->mte_handlers == 0)
+                                               continue;
+                                       pci_mask_msix(dev, j);
+                                       pci_enable_msix(dev, j, addr, data);
+                                       pci_unmask_msix(dev, j);
+                               }
+                       }
+               }
+               return (ENOENT);
+       }
+
+       return (ENOENT);
+}
+
+/*
+ * Returns true if the specified device is blacklisted because MSI
+ * doesn't work.
+ */
+int
+pci_msi_device_blacklisted(device_t dev)
+{
+       struct pci_quirk *q;
+
+       if (!pci_honor_msi_blacklist)
+               return (0);
+
+       for (q = &pci_quirks[0]; q->devid; q++) {
+               if (q->devid == pci_get_devid(dev) &&
+                   q->type == PCI_QUIRK_DISABLE_MSI)
+                       return (1);
+       }
+       return (0);
+}
+
+/*
+ * Determine if MSI is blacklisted globally on this sytem.  Currently,
+ * we just check for blacklisted chipsets as represented by the
+ * host-PCI bridge at device 0:0:0.  In the future, it may become
+ * necessary to check other system attributes, such as the kenv values
+ * that give the motherboard manufacturer and model number.
+ */
+static int
+pci_msi_blacklisted(void)
+{
+       device_t dev;
+
+       if (!pci_honor_msi_blacklist)
+               return (0);
+
+       /* Blacklist all non-PCI-express and non-PCI-X chipsets. */
+       if (!(pcie_chipset || pcix_chipset))
+               return (1);
+
+       dev = pci_find_bsf(0, 0, 0);
+       if (dev != NULL)
+               return (pci_msi_device_blacklisted(dev));
+       return (0);
+}
+
+/*
+ * Attempt to allocate *count MSI messages.  The actual number allocated is
+ * returned in *count.  After this function returns, each message will be
+ * available to the driver as SYS_RES_IRQ resources starting at a rid 1.
+ */
+int
+pci_alloc_msi_method(device_t dev, device_t child, int *count)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(child);
+       pcicfgregs *cfg = &dinfo->cfg;
+       struct resource_list_entry *rle;
+       int actual, error, i, irqs[32];
+       uint16_t ctrl;
+
+       /* Don't let count == 0 get us into trouble. */
+       if (*count == 0)
+               return (EINVAL);
+
+       /* If rid 0 is allocated, then fail. */
+       rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 0);
+       if (rle != NULL && rle->res != NULL)
+               return (ENXIO);
+
+       /* Already have allocated messages? */
+       if (cfg->msi.msi_alloc != 0 || cfg->msix.msix_alloc != 0)
+               return (ENXIO);
+
+       /* If MSI is blacklisted for this system, fail. */
+       if (pci_msi_blacklisted())
+               return (ENXIO);
+
+       /* MSI capability present? */
+       if (cfg->msi.msi_location == 0 || !pci_do_msi)
+               return (ENODEV);
+
+       if (bootverbose)
+               device_printf(child,
+                   "attempting to allocate %d MSI vectors (%d supported)\n",
+                   *count, cfg->msi.msi_msgnum);
+
+       /* Don't ask for more than the device supports. */
+       actual = min(*count, cfg->msi.msi_msgnum);
+
+       /* Don't ask for more than 32 messages. */
+       actual = min(actual, 32);
+
+       /* MSI requires power of 2 number of messages. */
+       if (!powerof2(actual))
+               return (EINVAL);
+
+       for (;;) {
+               /* Try to allocate N messages. */
+               error = PCIB_ALLOC_MSI(device_get_parent(dev), child, actual,
+                   cfg->msi.msi_msgnum, irqs);
+               if (error == 0)
+                       break;
+               if (actual == 1)
+                       return (error);
+
+               /* Try N / 2. */
+               actual >>= 1;
+       }
+
+       /*
+        * We now have N actual messages mapped onto SYS_RES_IRQ
+        * resources in the irqs[] array, so add new resources
+        * starting at rid 1.
+        */
+       for (i = 0; i < actual; i++)
+               resource_list_add(&dinfo->resources, SYS_RES_IRQ, i + 1,
+                   irqs[i], irqs[i], 1);
+
+       if (bootverbose) {
+               if (actual == 1)
+                       device_printf(child, "using IRQ %d for MSI\n", irqs[0]);
+               else {
+                       int run;
+
+                       /*
+                        * Be fancy and try to print contiguous runs
+                        * of IRQ values as ranges.  'run' is true if
+                        * we are in a range.
+                        */
+                       device_printf(child, "using IRQs %d", irqs[0]);
+                       run = 0;
+                       for (i = 1; i < actual; i++) {
+
+                               /* Still in a run? */
+                               if (irqs[i] == irqs[i - 1] + 1) {
+                                       run = 1;
+                                       continue;
+                               }
+
+                               /* Finish previous range. */
+                               if (run) {
+                                       kprintf("-%d", irqs[i - 1]);
+                                       run = 0;
+                               }
+
+                               /* Start new range. */
+                               kprintf(",%d", irqs[i]);
+                       }
+
+                       /* Unfinished range? */
+                       if (run)
+                               kprintf("-%d", irqs[actual - 1]);
+                       kprintf(" for MSI\n");
+               }
+       }
+
+       /* Update control register with actual count. */
+       ctrl = cfg->msi.msi_ctrl;
+       ctrl &= ~PCIM_MSICTRL_MME_MASK;
+       ctrl |= (ffs(actual) - 1) << 4;
+       cfg->msi.msi_ctrl = ctrl;
+       pci_write_config(child, cfg->msi.msi_location + PCIR_MSI_CTRL, ctrl, 2);
+
+       /* Update counts of alloc'd messages. */
+       cfg->msi.msi_alloc = actual;
+       cfg->msi.msi_handlers = 0;
+       *count = actual;
+       return (0);
+}
+
+/* Release the MSI messages associated with this device. */
+int
+pci_release_msi_method(device_t dev, device_t child)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(child);
+       struct pcicfg_msi *msi = &dinfo->cfg.msi;
+       struct resource_list_entry *rle;
+       int error, i, irqs[32];
+
+       /* Try MSI-X first. */
+       error = pci_release_msix(dev, child);
+       if (error != ENODEV)
+               return (error);
+
+       /* Do we have any messages to release? */
+       if (msi->msi_alloc == 0)
+               return (ENODEV);
+       KASSERT(msi->msi_alloc <= 32, ("more than 32 alloc'd messages"));
+
+       /* Make sure none of the resources are allocated. */
+       if (msi->msi_handlers > 0)
+               return (EBUSY);
+       for (i = 0; i < msi->msi_alloc; i++) {
+               rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i + 1);
+               KASSERT(rle != NULL, ("missing MSI resource"));
+               if (rle->res != NULL)
+                       return (EBUSY);
+               irqs[i] = rle->start;
+       }
+
+       /* Update control register with 0 count. */
+       KASSERT(!(msi->msi_ctrl & PCIM_MSICTRL_MSI_ENABLE),
+           ("%s: MSI still enabled", __func__));
+       msi->msi_ctrl &= ~PCIM_MSICTRL_MME_MASK;
+       pci_write_config(child, msi->msi_location + PCIR_MSI_CTRL,
+           msi->msi_ctrl, 2);
+
+       /* Release the messages. */
+       PCIB_RELEASE_MSI(device_get_parent(dev), child, msi->msi_alloc, irqs);
+       for (i = 0; i < msi->msi_alloc; i++)
+               resource_list_delete(&dinfo->resources, SYS_RES_IRQ, i + 1);
+
+       /* Update alloc count. */
+       msi->msi_alloc = 0;
+       msi->msi_addr = 0;
+       msi->msi_data = 0;
+       return (0);
+}
+
+/*
+ * Return the max supported MSI messages this device supports.
+ * Basically, assuming the MD code can alloc messages, this function
+ * should return the maximum value that pci_alloc_msi() can return.
+ * Thus, it is subject to the tunables, etc.
+ */
+int
+pci_msi_count_method(device_t dev, device_t child)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(child);
+       struct pcicfg_msi *msi = &dinfo->cfg.msi;
+
+       if (pci_do_msi && msi->msi_location != 0)
+               return (msi->msi_msgnum);
+       return (0);
+}
+
+/* kfree pcicfgregs structure and all depending data structures */
+
+int
+pci_freecfg(struct pci_devinfo *dinfo)
+{
+       struct devlist *devlist_head;
+       int i;
+
+       devlist_head = &pci_devq;
+
+       if (dinfo->cfg.vpd.vpd_reg) {
+               kfree(dinfo->cfg.vpd.vpd_ident, M_DEVBUF);
+               for (i = 0; i < dinfo->cfg.vpd.vpd_rocnt; i++)
+                       kfree(dinfo->cfg.vpd.vpd_ros[i].value, M_DEVBUF);
+               kfree(dinfo->cfg.vpd.vpd_ros, M_DEVBUF);
+               for (i = 0; i < dinfo->cfg.vpd.vpd_wcnt; i++)
+                       kfree(dinfo->cfg.vpd.vpd_w[i].value, M_DEVBUF);
+               kfree(dinfo->cfg.vpd.vpd_w, M_DEVBUF);
+       }
+       STAILQ_REMOVE(devlist_head, dinfo, pci_devinfo, pci_links);
+       kfree(dinfo, M_DEVBUF);
+
+       /* increment the generation count */
+       pci_generation++;
+
+       /* we're losing one device */
+       pci_numdevs--;
+       return (0);
+}
+
+/*
+ * PCI power manangement
+ */
+int
+pci_set_powerstate_method(device_t dev, device_t child, int state)
+{
+       struct pci_devinfo *dinfo = device_get_ivars(child);
+       pcicfgregs *cfg = &dinfo->cfg;
        uint16_t status;
        int result, oldstate, highest, delay;
 
-       if (cfg->pmgt.pp_cap == 0)
+       if (cfg->pp.pp_cap == 0)
                return (EOPNOTSUPP);
 
        /*
@@ -709,7 +2048,7 @@ pci_set_powerstate_method(device_t dev, device_t child, int state)
            delay = 200;
        else
            delay = 0;
-       status = PCI_READ_CONFIG(dev, child, cfg->pmgt.pp_status, 2)
+       status = PCI_READ_CONFIG(dev, child, cfg->pp.pp_status, 2)
            & ~PCIM_PSTAT_DMASK;
        result = 0;
        switch (state) {
@@ -717,12 +2056,12 @@ pci_set_powerstate_method(device_t dev, device_t child, int state)
                status |= PCIM_PSTAT_D0;
                break;
        case PCI_POWERSTATE_D1:
-               if ((cfg->pmgt.pp_cap & PCIM_PCAP_D1SUPP) == 0)
+               if ((cfg->pp.pp_cap & PCIM_PCAP_D1SUPP) == 0)
                      &nbs