[Midnightbsd-cvs] src: dev/pci: merge and sync with freebsd 7

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Tue Nov 25 12:07:18 EST 2008


Log Message:
-----------
merge and sync with freebsd 7

Modified Files:
--------------
    src/sys/dev/pci:
        fixup_pci.c (r1.2 -> r1.3)
        isa_pci.c (r1.1.1.1 -> r1.2)
        pci.c (r1.2 -> r1.3)
        pci_if.m (r1.1.1.1 -> r1.2)
        pci_pci.c (r1.2 -> r1.3)
        pci_private.h (r1.1.1.2 -> r1.2)
        pci_user.c (r1.1.1.1 -> r1.2)
        pcib_if.m (r1.1.1.1 -> r1.2)
        pcib_private.h (r1.1.1.1 -> r1.2)
        pcireg.h (r1.1.1.2 -> r1.2)
        pcivar.h (r1.2 -> r1.3)

Added Files:
-----------
    src/sys/dev/pci:
        hostb_pci.c (r1.1)
        vga_pci.c (r1.1)

-------------- next part --------------
--- /dev/null
+++ sys/dev/pci/vga_pci.c
@@ -0,0 +1,255 @@
+/*-
+ * Copyright (c) 2005 John Baldwin <jhb at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/pci/vga_pci.c,v 1.5 2006/02/01 15:45:29 jhb Exp $");
+
+/*
+ * Simple driver for PCI VGA display devices.  Drivers such as agp(4) and
+ * drm(4) should attach as children of this device.
+ *
+ * XXX: The vgapci name is a hack until we somehow merge the isa vga driver
+ * in or rename it.
+ */
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+static int
+vga_pci_probe(device_t dev)
+{
+
+	switch (pci_get_class(dev)) {
+	case PCIC_DISPLAY:
+		break;
+	case PCIC_OLD:
+		if (pci_get_subclass(dev) != PCIS_OLD_VGA)
+			return (ENXIO);
+		break;
+	default:
+		return (ENXIO);
+	}
+	device_set_desc(dev, "VGA-compatible display");
+	return (BUS_PROBE_GENERIC);
+}
+
+static int
+vga_pci_attach(device_t dev)
+{
+
+	bus_generic_probe(dev);
+
+	/* Always create a drm child for now to make it easier on drm. */
+	device_add_child(dev, "drm", -1);
+	bus_generic_attach(dev);
+	return (0);
+}
+
+static int
+vga_pci_suspend(device_t dev)
+{
+
+	return (bus_generic_suspend(dev));
+}
+
+static int
+vga_pci_resume(device_t dev)
+{
+
+	return (bus_generic_resume(dev));
+}
+
+/* Bus interface. */
+
+static int
+vga_pci_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
+vga_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
+{
+
+	return (EINVAL);
+}
+
+static struct resource *
+vga_pci_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
+vga_pci_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
+vga_pci_read_config(device_t dev, device_t child, int reg, int width)
+{
+
+	return (pci_read_config(dev, reg, width));
+}
+
+static void
+vga_pci_write_config(device_t dev, device_t child, int reg, 
+    uint32_t val, int width)
+{
+
+	pci_write_config(dev, reg, val, width);
+}
+
+static int
+vga_pci_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
+vga_pci_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
+vga_pci_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
+vga_pci_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
+vga_pci_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
+vga_pci_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
+vga_pci_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
+vga_pci_find_extcap(device_t dev, device_t child, int capability,
+    int *capreg)
+{
+
+	return (pci_find_extcap(dev, capability, capreg));
+}
+
+static device_method_t vga_pci_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		vga_pci_probe),
+	DEVMETHOD(device_attach,	vga_pci_attach),
+	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
+	DEVMETHOD(device_suspend,	vga_pci_suspend),
+	DEVMETHOD(device_resume,	vga_pci_resume),
+
+	/* Bus interface */
+	DEVMETHOD(bus_read_ivar,	vga_pci_read_ivar),
+	DEVMETHOD(bus_write_ivar,	vga_pci_write_ivar),
+	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
+	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
+
+	DEVMETHOD(bus_alloc_resource,	vga_pci_alloc_resource),
+	DEVMETHOD(bus_release_resource,	vga_pci_release_resource),
+	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+
+	/* PCI interface */
+	DEVMETHOD(pci_read_config,	vga_pci_read_config),
+	DEVMETHOD(pci_write_config,	vga_pci_write_config),
+	DEVMETHOD(pci_enable_busmaster,	vga_pci_enable_busmaster),
+	DEVMETHOD(pci_disable_busmaster, vga_pci_disable_busmaster),
+	DEVMETHOD(pci_enable_io,	vga_pci_enable_io),
+	DEVMETHOD(pci_disable_io,	vga_pci_disable_io),
+	DEVMETHOD(pci_get_powerstate,	vga_pci_get_powerstate),
+	DEVMETHOD(pci_set_powerstate,	vga_pci_set_powerstate),
+	DEVMETHOD(pci_assign_interrupt,	vga_pci_assign_interrupt),
+	DEVMETHOD(pci_find_extcap,	vga_pci_find_extcap),
+
+	{ 0, 0 }
+};
+
+static driver_t vga_pci_driver = {
+	"vgapci",
+	vga_pci_methods,
+	1,
+};
+
+static devclass_t vga_devclass;
+
+DRIVER_MODULE(vgapci, pci, vga_pci_driver, vga_devclass, 0, 0);
Index: pcivar.h
===================================================================
RCS file: /home/cvs/src/sys/dev/pci/pcivar.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/dev/pci/pcivar.h -L sys/dev/pci/pcivar.h -u -r1.2 -r1.3
--- sys/dev/pci/pcivar.h
+++ sys/dev/pci/pcivar.h
@@ -23,33 +23,28 @@
  * (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/dev/pci/pcivar.h,v 1.66.2.1 2006/01/30 18:34:41 imp Exp $
+ * $FreeBSD: src/sys/dev/pci/pcivar.h,v 1.80 2007/09/30 11:05:15 marius Exp $
  *
  */
 
 #ifndef _PCIVAR_H_
-#define _PCIVAR_H_
+#define	_PCIVAR_H_
 
 #include <sys/queue.h>
 
 /* some PCI bus constants */
 
-#define PCI_BUSMAX	255	/* highest supported bus number */
-#define PCI_SLOTMAX	31	/* highest supported slot number */
-#define PCI_FUNCMAX	7	/* highest supported function number */
-#define PCI_REGMAX	255	/* highest supported config register addr. */
-
-#define PCI_MAXMAPS_0	6	/* max. no. of memory/port maps */
-#define PCI_MAXMAPS_1	2	/* max. no. of maps for PCI to PCI bridge */
-#define PCI_MAXMAPS_2	1	/* max. no. of maps for CardBus bridge */
-
-/* pci_addr_t covers this system's PCI bus address space: 32 or 64 bit */
-
-#ifdef PCI_A64
-typedef uint64_t pci_addr_t;	/* uint64_t for system with 64bit addresses */
-#else
-typedef uint32_t pci_addr_t;	/* uint64_t for system with 64bit addresses */
-#endif
+#define	PCI_DOMAINMAX	65535	/* highest supported domain number */
+#define	PCI_BUSMAX	255	/* highest supported bus number */
+#define	PCI_SLOTMAX	31	/* highest supported slot number */
+#define	PCI_FUNCMAX	7	/* highest supported function number */
+#define	PCI_REGMAX	255	/* highest supported config register addr. */
+
+#define	PCI_MAXMAPS_0	6	/* max. no. of memory/port maps */
+#define	PCI_MAXMAPS_1	2	/* max. no. of maps for PCI to PCI bridge */
+#define	PCI_MAXMAPS_2	1	/* max. no. of maps for CardBus bridge */
+
+typedef uint64_t pci_addr_t;
 
 /* Interesting values for PCI power management */
 struct pcicfg_pp {
@@ -59,11 +54,65 @@
     uint8_t	pp_data;	/* config space address of PCI power data reg */
 };
  
+struct vpd_readonly {
+    char	keyword[2];
+    char	*value;
+};
+
+struct vpd_write {
+    char	keyword[2];
+    char	*value;
+    int 	start;
+    int 	len;
+};
+
+struct pcicfg_vpd {
+    uint8_t	vpd_reg;	/* base register, + 2 for addr, + 4 data */
+    char	vpd_cached;
+    char	*vpd_ident;	/* string identifier */
+    int 	vpd_rocnt;
+    struct vpd_readonly *vpd_ros;
+    int 	vpd_wcnt;
+    struct vpd_write *vpd_w;
+};
+
 /* Interesting values for PCI MSI */
 struct pcicfg_msi {
     uint16_t	msi_ctrl;	/* Message Control */
+    uint8_t	msi_location;	/* Offset of MSI capability registers. */
     uint8_t	msi_msgnum;	/* Number of messages */
-    uint16_t	msi_data;	/* Location of MSI data word */
+    int		msi_alloc;	/* Number of allocated messages. */
+    uint64_t	msi_addr;	/* Contents of address register. */
+    uint16_t	msi_data;	/* Contents of data register. */
+    u_int	msi_handlers;
+};
+
+/* Interesting values for PCI MSI-X */
+struct msix_vector {
+    uint64_t	mv_address;	/* Contents of address register. */
+    uint32_t	mv_data;	/* Contents of data register. */
+    int		mv_irq;
+};
+
+struct msix_table_entry {
+    u_int	mte_vector;	/* 1-based index into msix_vectors array. */
+    u_int	mte_handlers;
+};
+
+struct pcicfg_msix {
+    uint16_t	msix_ctrl;	/* Message Control */
+    uint16_t	msix_msgnum;	/* Number of messages */
+    uint8_t	msix_location;	/* Offset of MSI-X capability registers. */
+    uint8_t	msix_table_bar;	/* BAR containing vector table. */
+    uint8_t	msix_pba_bar;	/* BAR containing PBA. */
+    uint32_t	msix_table_offset;
+    uint32_t	msix_pba_offset;
+    int		msix_alloc;	/* Number of allocated vectors. */
+    int		msix_table_len;	/* Length of virtual table. */
+    struct msix_table_entry *msix_table; /* Virtual table. */
+    struct msix_vector *msix_vectors;	/* Array of allocated vectors. */
+    struct resource *msix_table_res;	/* Resource containing vector table. */
+    struct resource *msix_pba_res;	/* Resource containing PBA. */
 };
 
 /* config header information common to all header types */
@@ -98,26 +147,23 @@
     uint8_t	mfdev;		/* multi-function device (from hdrtype reg) */
     uint8_t	nummaps;	/* actual number of PCI maps used */
 
+    uint32_t	domain;		/* PCI domain */
     uint8_t	bus;		/* config space bus address */
     uint8_t	slot;		/* config space slot address */
     uint8_t	func;		/* config space function number */
 
     struct pcicfg_pp pp;	/* pci power management */
+    struct pcicfg_vpd vpd;	/* pci vital product data */
     struct pcicfg_msi msi;	/* pci msi */
+    struct pcicfg_msix msix;	/* pci msi-x */
 } pcicfgregs;
 
 /* additional type 1 device config header information (PCI to PCI bridge) */
 
-#ifdef PCI_A64
-#define PCI_PPBMEMBASE(h,l)  ((((pci_addr_t)(h) << 32) + ((l)<<16)) & ~0xfffff)
-#define PCI_PPBMEMLIMIT(h,l) ((((pci_addr_t)(h) << 32) + ((l)<<16)) | 0xfffff)
-#else
-#define PCI_PPBMEMBASE(h,l)  (((l)<<16) & ~0xfffff)
-#define PCI_PPBMEMLIMIT(h,l) (((l)<<16) | 0xfffff)
-#endif /* PCI_A64 */
-
-#define PCI_PPBIOBASE(h,l)   ((((h)<<16) + ((l)<<8)) & ~0xfff)
-#define PCI_PPBIOLIMIT(h,l)  ((((h)<<16) + ((l)<<8)) | 0xfff)
+#define	PCI_PPBMEMBASE(h,l)  ((((pci_addr_t)(h) << 32) + ((l)<<16)) & ~0xfffff)
+#define	PCI_PPBMEMLIMIT(h,l) ((((pci_addr_t)(h) << 32) + ((l)<<16)) | 0xfffff)
+#define	PCI_PPBIOBASE(h,l)   ((((h)<<16) + ((l)<<8)) & ~0xfff)
+#define	PCI_PPBIOLIMIT(h,l)  ((((h)<<16) + ((l)<<8)) | 0xfff)
 
 typedef struct {
     pci_addr_t	pmembase;	/* base address of prefetchable memory */
@@ -168,8 +214,8 @@
  * Define pci-specific resource flags for accessing memory via dense
  * or bwx memory spaces. These flags are ignored on i386.
  */
-#define PCI_RF_DENSE	0x10000
-#define PCI_RF_BWX	0x20000
+#define	PCI_RF_DENSE	0x10000
+#define	PCI_RF_BWX	0x20000
 
 enum pci_device_ivars {
     PCI_IVAR_SUBVENDOR,
@@ -183,6 +229,7 @@
     PCI_IVAR_REVID,
     PCI_IVAR_INTPIN,
     PCI_IVAR_IRQ,
+    PCI_IVAR_DOMAIN,
     PCI_IVAR_BUS,
     PCI_IVAR_SLOT,
     PCI_IVAR_FUNCTION,
@@ -197,7 +244,7 @@
 /*
  * Simplified accessors for pci devices
  */
-#define PCI_ACCESSOR(var, ivar, type)					\
+#define	PCI_ACCESSOR(var, ivar, type)					\
 	__BUS_ACCESSOR(pci, var, PCI, ivar, type)
 
 PCI_ACCESSOR(subvendor,		SUBVENDOR,	uint16_t)
@@ -211,6 +258,7 @@
 PCI_ACCESSOR(revid,		REVID,		uint8_t)
 PCI_ACCESSOR(intpin,		INTPIN,		uint8_t)
 PCI_ACCESSOR(irq,		IRQ,		uint8_t)
+PCI_ACCESSOR(domain,		DOMAIN,		uint32_t)
 PCI_ACCESSOR(bus,		BUS,		uint8_t)
 PCI_ACCESSOR(slot,		SLOT,		uint8_t)
 PCI_ACCESSOR(function,		FUNCTION,	uint8_t)
@@ -244,12 +292,14 @@
 
 /*typedef enum pci_device_ivars pcib_device_ivars;*/
 enum pcib_device_ivars {
+	PCIB_IVAR_DOMAIN,
 	PCIB_IVAR_BUS
 };
 
-#define PCIB_ACCESSOR(var, ivar, type)					 \
+#define	PCIB_ACCESSOR(var, ivar, type)					 \
     __BUS_ACCESSOR(pcib, var, PCIB, ivar, type)
 
+PCIB_ACCESSOR(domain,		DOMAIN,		uint32_t)
 PCIB_ACCESSOR(bus,		BUS,		uint32_t)
 
 #undef PCIB_ACCESSOR
@@ -259,8 +309,8 @@
  * on i386 or other platforms should be mapped out in the MD pcireadconf
  * code and not here, since the only MI invalid IRQ is 255.
  */
-#define PCI_INVALID_IRQ		255
-#define PCI_INTERRUPT_VALID(x)	((x) != PCI_INVALID_IRQ)
+#define	PCI_INVALID_IRQ		255
+#define	PCI_INTERRUPT_VALID(x)	((x) != PCI_INVALID_IRQ)
 
 /*
  * Convenience functions.
@@ -292,6 +342,18 @@
     return(PCI_DISABLE_IO(device_get_parent(dev), dev, space));
 }
 
+static __inline int
+pci_get_vpd_ident(device_t dev, const char **identptr)
+{
+    return(PCI_GET_VPD_IDENT(device_get_parent(dev), dev, identptr));
+}
+
+static __inline int
+pci_get_vpd_readonly(device_t dev, const char *kw, const char **identptr)
+{
+    return(PCI_GET_VPD_READONLY(device_get_parent(dev), dev, kw, identptr));
+}
+
 /*
  * Check if the address range falls within the VGA defined address range(s)
  */
@@ -317,19 +379,19 @@
  *	power from the system and delivering full functionality to the user.
  * D1	Class-specific low-power state in which device context may or may not
  *	be lost.  Buses in D1 cannot do anything to the bus that would force
- *	devices on that bus to loose context.
+ *	devices on that bus to lose context.
  * D2	Class-specific low-power state in which device context may or may
  *	not be lost.  Attains greater power savings than D1.  Buses in D2
- *	can cause devices on that bus to loose some context.  Devices in D2
+ *	can cause devices on that bus to lose some context.  Devices in D2
  *	must be prepared for the bus to be in D2 or higher.
  * D3	State in which the device is off and not running.  Device context is
  *	lost.  Power can be removed from the device.
  */
-#define PCI_POWERSTATE_D0	0
-#define PCI_POWERSTATE_D1	1
-#define PCI_POWERSTATE_D2	2
-#define PCI_POWERSTATE_D3	3
-#define PCI_POWERSTATE_UNKNOWN	-1
+#define	PCI_POWERSTATE_D0	0
+#define	PCI_POWERSTATE_D1	1
+#define	PCI_POWERSTATE_D2	2
+#define	PCI_POWERSTATE_D3	3
+#define	PCI_POWERSTATE_UNKNOWN	-1
 
 static __inline int
 pci_set_powerstate(device_t dev, int state)
@@ -343,17 +405,63 @@
     return PCI_GET_POWERSTATE(device_get_parent(dev), dev);
 }
 
-#if 0
-/* depends on ACPI import */
 static __inline int
 pci_find_extcap(device_t dev, int capability, int *capreg)
 {
     return PCI_FIND_EXTCAP(device_get_parent(dev), dev, capability, capreg);
 }
-#endif
+
+static __inline int
+pci_alloc_msi(device_t dev, int *count)
+{
+    return (PCI_ALLOC_MSI(device_get_parent(dev), dev, count));
+}
+
+static __inline int
+pci_alloc_msix(device_t dev, int *count)
+{
+    return (PCI_ALLOC_MSIX(device_get_parent(dev), dev, count));
+}
+
+static __inline int
+pci_remap_msix(device_t dev, int count, const u_int *vectors)
+{
+    return (PCI_REMAP_MSIX(device_get_parent(dev), dev, count, vectors));
+}
+
+static __inline int
+pci_release_msi(device_t dev)
+{
+    return (PCI_RELEASE_MSI(device_get_parent(dev), dev));
+}
+
+static __inline int
+pci_msi_count(device_t dev)
+{
+    return (PCI_MSI_COUNT(device_get_parent(dev), dev));
+}
+
+static __inline int
+pci_msix_count(device_t dev)
+{
+    return (PCI_MSIX_COUNT(device_get_parent(dev), dev));
+}
 
 device_t pci_find_bsf(uint8_t, uint8_t, uint8_t);
+device_t pci_find_dbsf(uint32_t, uint8_t, uint8_t, uint8_t);
 device_t pci_find_device(uint16_t, uint16_t);
+
+/*
+ * Can be used by MD code to request the PCI bus to re-map an MSI or
+ * MSI-X message.
+ */
+int	pci_remap_msi_irq(device_t dev, u_int irq);
+
+/* Can be used by drivers to manage the MSI-X table. */
+int	pci_pending_msix(device_t dev, u_int index);
+
+int	pci_msi_device_blacklisted(device_t dev);
+
 #endif	/* _SYS_BUS_H_ */
 
 /*
Index: pci.c
===================================================================
RCS file: /home/cvs/src/sys/dev/pci/pci.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/dev/pci/pci.c -L sys/dev/pci/pci.c -u -r1.2 -r1.3
--- sys/dev/pci/pci.c
+++ sys/dev/pci/pci.c
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/pci/pci.c,v 1.292.2.9 2006/09/25 15:49:51 marcel Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/pci/pci.c,v 1.355.2.1 2007/11/26 17:37:24 jkim Exp $");
 
 #include "opt_bus.h"
 
@@ -41,7 +41,7 @@
 #include <sys/kernel.h>
 #include <sys/queue.h>
 #include <sys/sysctl.h>
-#include <sys/types.h>
+#include <sys/endian.h>
 
 #include <vm/vm.h>
 #include <vm/pmap.h>
@@ -52,6 +52,10 @@
 #include <sys/rman.h>
 #include <machine/resource.h>
 
+#if defined(__i386__) || defined(__amd64__)
+#include <machine/intr_machdep.h>
+#endif
+
 #include <sys/pciio.h>
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
@@ -60,16 +64,15 @@
 #include "pcib_if.h"
 #include "pci_if.h"
 
-#if (defined(__i386__) && !defined(PC98)) || defined(__amd64__) || \
-    defined (__ia64__)
+#ifdef __HAVE_ACPI
 #include <contrib/dev/acpica/acpi.h>
 #include "acpi_if.h"
 #else
-#define ACPI_PWR_FOR_SLEEP(x, y, z)
+#define	ACPI_PWR_FOR_SLEEP(x, y, z)
 #endif
 
 static uint32_t		pci_mapbase(unsigned mapreg);
-static int		pci_maptype(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);
@@ -84,13 +87,30 @@
 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, 
+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, 
+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 */
@@ -107,8 +127,8 @@
 	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,	bus_generic_setup_intr),
-	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
+	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),
@@ -128,16 +148,25 @@
 	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;
+static devclass_t pci_devclass;
 DRIVER_MODULE(pci, pcib, pci_driver, pci_devclass, pci_modevent, 0);
 MODULE_VERSION(pci, 1);
 
@@ -148,7 +177,8 @@
 struct pci_quirk {
 	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;
 };
@@ -160,17 +190,43 @@
 	/* 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");
@@ -198,15 +254,40 @@
     &pci_do_power_resume, 1,
   "Transition from D3 -> D0 on resume.");
 
-/* Find a device_t by bus/slot/function */
+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_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);
@@ -236,37 +317,32 @@
 /* return base address of memory or port map */
 
 static uint32_t
-pci_mapbase(unsigned mapreg)
+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 uint8_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;
 
@@ -282,197 +358,1563 @@
 	return (ln2size);
 }
 
-/* return log2 of address range supported by map register */
+/* return log2 of address range supported by map register */
+
+static int
+pci_maprange(unsigned mapreg)
+{
+	int ln2range = 0;
+
+	if (PCI_BAR_IO(mapreg))
+		ln2range = 32;
+	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);
+}
+
+/* adjust some values from PCI 1.0 devices to match 2.0 standards ... */
+
+static void
+pci_fixancient(pcicfgregs *cfg)
+{
+	if (cfg->hdrtype != 0)
+		return;
+
+	/* PCI to PCI bridges use header type 1 */
+	if (cfg->baseclass == PCIC_BRIDGE && cfg->subclass == PCIS_BRIDGE_PCI)
+		cfg->hdrtype = 1;
+}
+
+/* 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)
+	switch (cfg->hdrtype) {
+	case 0:
+		cfg->subvendor      = REG(PCIR_SUBVEND_0, 2);
+		cfg->subdevice      = REG(PCIR_SUBDEV_0, 2);
+		cfg->nummaps	    = PCI_MAXMAPS_0;
+		break;
+	case 1:
+		cfg->nummaps	    = PCI_MAXMAPS_1;
+		break;
+	case 2:
+		cfg->subvendor      = REG(PCIR_SUBVEND_2, 2);
+		cfg->subdevice      = REG(PCIR_SUBDEV_2, 2);
+		cfg->nummaps	    = PCI_MAXMAPS_2;
+		break;
+	}
+#undef REG
+}
+
+/* read configuration header into pcicfgregs structure */
+struct pci_devinfo *
+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)
+	pcicfgregs *cfg = NULL;
+	struct pci_devinfo *devlist_entry;
+	struct devlist *devlist_head;
+
+	devlist_head = &pci_devq;
+
+	devlist_entry = NULL;
+
+	if (REG(PCIR_DEVVENDOR, 4) != -1) {
+		devlist_entry = malloc(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;
+		cfg->vendor		= REG(PCIR_VENDOR, 2);
+		cfg->device		= REG(PCIR_DEVICE, 2);
+		cfg->cmdreg		= REG(PCIR_COMMAND, 2);
+		cfg->statreg		= REG(PCIR_STATUS, 2);
+		cfg->baseclass		= REG(PCIR_CLASS, 1);
+		cfg->subclass		= REG(PCIR_SUBCLASS, 1);
+		cfg->progif		= REG(PCIR_PROGIF, 1);
+		cfg->revid		= REG(PCIR_REVID, 1);
+		cfg->hdrtype		= REG(PCIR_HDRTYPE, 1);
+		cfg->cachelnsz		= REG(PCIR_CACHELNSZ, 1);
+		cfg->lattimer		= REG(PCIR_LATTIMER, 1);
+		cfg->intpin		= REG(PCIR_INTPIN, 1);
+		cfg->intline		= REG(PCIR_INTLINE, 1);
+
+		cfg->mingnt		= REG(PCIR_MINGNT, 1);
+		cfg->maxlat		= REG(PCIR_MAXLAT, 1);
+
+		cfg->mfdev		= (cfg->hdrtype & PCIM_MFDEV) != 0;
+		cfg->hdrtype		&= ~PCIM_MFDEV;
+
+		pci_fixancient(cfg);
+		pci_hdrtypedata(pcib, b, s, f, 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;
+		devlist_entry->conf.pc_hdr = cfg->hdrtype;
+
+		devlist_entry->conf.pc_subvendor = cfg->subvendor;
+		devlist_entry->conf.pc_subdevice = cfg->subdevice;
+		devlist_entry->conf.pc_vendor = cfg->vendor;
+		devlist_entry->conf.pc_device = cfg->device;
+
+		devlist_entry->conf.pc_class = cfg->baseclass;
+		devlist_entry->conf.pc_subclass = cfg->subclass;
+		devlist_entry->conf.pc_progif = cfg->progif;
+		devlist_entry->conf.pc_revid = cfg->revid;
+
+		pci_numdevs++;
+		pci_generation++;
+	}
+	return (devlist_entry);
+#undef REG
+}
+
+static void
+pci_read_extcap(device_t pcib, pcicfgregs *cfg)
+{
+#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 & PCIM_HDRTYPE) {
+	case 0:
+	case 1:
+		ptrptr = PCIR_CAP_PTR;
+		break;
+	case 2:
+		ptrptr = PCIR_CAP_PTR_2;	/* cardbus capabilities ptr */
+		break;
+	default:
+		return;		/* no extended capabilities support */
+	}
+	nextptr = REG(ptrptr, 1);	/* sanity check? */
+
+	/*
+	 * Read capability entries.
+	 */
+	while (nextptr != 0) {
+		/* Sanity check */
+		if (nextptr > 255) {
+			printf("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 */
+			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;
+#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);
+				}
+
+				/* Enable MSI -> HT mapping. */
+				val |= PCIM_HTCMD_MSI_ENABLE;
+				WREG(ptr + PCIR_HT_COMMAND, val, 2);
+				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_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;
+		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_EXPRESS:	/* PCI-express */
+			/*
+			 * Assume we have a PCI-express chipset if we have
+			 * at least one PCI-express root port.
+			 */
+			val = REG(ptr + PCIR_EXPRESS_FLAGS, 2);
+			if ((val & PCIM_EXP_FLAGS_TYPE) ==
+			    PCIM_EXP_TYPE_ROOT_PORT)
+				pcie_chipset = 1;
+			break;
+		default:
+			break;
+		}
+	}
+/* REG and WREG use carry through to next functions */
+}
+
+/*
+ * PCI Vital Product Data
+ */
+
+#define	PCI_VPD_TIMEOUT		1000000
+
+static int
+pci_read_vpd_reg(device_t pcib, pcicfgregs *cfg, int reg, uint32_t *data)
+{
+	int count = PCI_VPD_TIMEOUT;
+
+	KASSERT((reg & 3) == 0, ("VPD register must by 4 byte aligned"));
+
+	WREG(cfg->vpd.vpd_reg + PCIR_VPD_ADDR, reg, 2);
+
+	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));
+
+	return (0);
+}
+
+#if 0
+static int
+pci_write_vpd_reg(device_t pcib, pcicfgregs *cfg, int reg, uint32_t data)
+{
+	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);
+}
+
+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
+		printf("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;
+					printf(
+			    "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 = malloc(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 = malloc(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 = malloc(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 = reallocf(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.
+				 */
+				printf(
+				    "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 = malloc(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 = malloc(
+				    (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)
+						printf(
+				"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 = reallocf(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 = reallocf(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 = malloc((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 = reallocf(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:
+			printf("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++)
+				free(cfg->vpd.vpd_ros[off].value, M_DEVBUF);
+			free(cfg->vpd.vpd_ros, M_DEVBUF);
+			cfg->vpd.vpd_ros = NULL;
+		}
+	}
+	if (state < -1) {
+		/* I/O error, clean up */
+		printf("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) {
+			free(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++)
+				free(cfg->vpd.vpd_w[off].value, M_DEVBUF);
+			free(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);
+}
+
+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) {
+					printf("-%d", irq);
+					run = 0;
+				}
+
+				/* Start new range. */
+				printf(",%lu", rle->start);
+				irq = rle->start;
+			}
+
+			/* Unfinished range? */
+			if (run)
+				printf("-%d", irq);
+			printf(" 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 = malloc(sizeof(struct msix_vector) * actual,
+	    M_DEVBUF, M_WAITOK | M_ZERO);
+	cfg->msix.msix_table = malloc(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 freed 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 freed 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 = malloc(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) {
+			free(used, M_DEVBUF);
+			return (EINVAL);
+		}
+	if (used[0] != 1) {
+		free(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.
+	 */
+	free(msix->msix_table, M_DEVBUF);
+	msix->msix_table = malloc(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 = malloc(sizeof(struct msix_vector) * (j + 1), M_DEVBUF,
+		    M_WAITOK);
+		bcopy(msix->msix_vectors, vec, sizeof(struct msix_vector) *
+		    (j + 1));
+		free(msix->msix_vectors, M_DEVBUF);
+		msix->msix_vectors = vec;
+		msix->msix_alloc = j + 1;
+	}
+	free(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)
+				printf(", ");
+			if (vectors[i] == 0)
+				printf("---");
+			else
+				printf("%d",
+				    msix->msix_vectors[vectors[i]].mv_irq);
+		}
+		printf("\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);
+	}
+	free(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);
+	free(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);
+}
+
+/*
+ * 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);
+}
+
+void
+pci_disable_msi(device_t dev)
+{
+	struct pci_devinfo *dinfo = device_get_ivars(dev);
+	struct pcicfg_msi *msi = &dinfo->cfg.msi;
+
+	/* 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);
+}
 
-static int
-pci_maprange(unsigned mapreg)
+/*
+ * Returns true if the specified device is blacklisted because MSI
+ * doesn't work.
+ */
+int
+pci_msi_device_blacklisted(device_t dev)
 {
-	int ln2range = 0;
-	switch (mapreg & 0x07) {
-	case 0x00:
-	case 0x01:
-	case 0x05:
-		ln2range = 32;
-		break;
-	case 0x02:
-		ln2range = 20;
-		break;
-	case 0x04:
-		ln2range = 64;
-		break;
+	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 (ln2range);
+	return (0);
 }
 
-/* adjust some values from PCI 1.0 devices to match 2.0 standards ... */
-
-static void
-pci_fixancient(pcicfgregs *cfg)
+/*
+ * 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)
 {
-	if (cfg->hdrtype != 0)
-		return;
+	device_t dev;
 
-	/* PCI to PCI bridges use header type 1 */
-	if (cfg->baseclass == PCIC_BRIDGE && cfg->subclass == PCIS_BRIDGE_PCI)
-		cfg->hdrtype = 1;
-}
+	if (!pci_honor_msi_blacklist)
+		return (0);
 
-/* extract header type specific config data */
+	/* 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);
+}
 
-static void
-pci_hdrtypedata(device_t pcib, int b, int s, int f, pcicfgregs *cfg)
+/*
+ * 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)
 {
-#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);
-		cfg->subdevice      = REG(PCIR_SUBDEV_0, 2);
-		cfg->nummaps	    = PCI_MAXMAPS_0;
-		break;
-	case 1:
-		cfg->subvendor      = REG(PCIR_SUBVEND_1, 2);
-		cfg->subdevice      = REG(PCIR_SUBDEV_1, 2);
-		cfg->nummaps	    = PCI_MAXMAPS_1;
-		break;
-	case 2:
-		cfg->subvendor      = REG(PCIR_SUBVEND_2, 2);
-		cfg->subdevice      = REG(PCIR_SUBDEV_2, 2);
-		cfg->nummaps	    = PCI_MAXMAPS_2;
-		break;
-	}
-#undef REG
-}
+	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;
 
-/* read configuration header into pcicfgregs structure */
+	/* Don't let count == 0 get us into trouble. */
+	if (*count == 0)
+		return (EINVAL);
 
-struct pci_devinfo *
-pci_read_device(device_t pcib, int b, int s, int f, size_t size)
-{
-#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;
+	/* 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);
 
-	devlist_head = &pci_devq;
+	/* Already have allocated messages? */
+	if (cfg->msi.msi_alloc != 0 || cfg->msix.msix_alloc != 0)
+		return (ENXIO);
 
-	devlist_entry = NULL;
+	/* If MSI is blacklisted for this system, fail. */
+	if (pci_msi_blacklisted())
+		return (ENXIO);
 
-	if (REG(PCIR_DEVVENDOR, 4) != -1) {
-		devlist_entry = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
-		if (devlist_entry == NULL)
-			return (NULL);
+	/* MSI capability present? */
+	if (cfg->msi.msi_location == 0 || !pci_do_msi)
+		return (ENODEV);
 
-		cfg = &devlist_entry->cfg;
-		
-		cfg->bus		= b;
-		cfg->slot		= s;
-		cfg->func		= f;
-		cfg->vendor		= REG(PCIR_VENDOR, 2);
-		cfg->device		= REG(PCIR_DEVICE, 2);
-		cfg->cmdreg		= REG(PCIR_COMMAND, 2);
-		cfg->statreg		= REG(PCIR_STATUS, 2);
-		cfg->baseclass		= REG(PCIR_CLASS, 1);
-		cfg->subclass		= REG(PCIR_SUBCLASS, 1);
-		cfg->progif		= REG(PCIR_PROGIF, 1);
-		cfg->revid		= REG(PCIR_REVID, 1);
-		cfg->hdrtype		= REG(PCIR_HDRTYPE, 1);
-		cfg->cachelnsz		= REG(PCIR_CACHELNSZ, 1);
-		cfg->lattimer		= REG(PCIR_LATTIMER, 1);
-		cfg->intpin		= REG(PCIR_INTPIN, 1);
-		cfg->intline		= REG(PCIR_INTLINE, 1);
+	if (bootverbose)
+		device_printf(child,
+		    "attempting to allocate %d MSI vectors (%d supported)\n",
+		    *count, cfg->msi.msi_msgnum);
 
-		cfg->mingnt		= REG(PCIR_MINGNT, 1);
-		cfg->maxlat		= REG(PCIR_MAXLAT, 1);
+	/* Don't ask for more than the device supports. */
+	actual = min(*count, cfg->msi.msi_msgnum);
 
-		cfg->mfdev		= (cfg->hdrtype & PCIM_MFDEV) != 0;
-		cfg->hdrtype		&= ~PCIM_MFDEV;
+	/* Don't ask for more than 32 messages. */
+	actual = min(actual, 32);
 
-		pci_fixancient(cfg);
-		pci_hdrtypedata(pcib, b, s, f, cfg);
+	/* MSI requires power of 2 number of messages. */
+	if (!powerof2(actual))
+		return (EINVAL);
 
-		if (REG(PCIR_STATUS, 2) & PCIM_STATUS_CAPPRESENT)
-			pci_read_extcap(pcib, cfg);
+	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);
 
-		STAILQ_INSERT_TAIL(devlist_head, devlist_entry, pci_links);
+		/* Try N / 2. */
+		actual >>= 1;
+	}
 
-		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;
-		devlist_entry->conf.pc_hdr = cfg->hdrtype;
+	/*
+	 * 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);
 
-		devlist_entry->conf.pc_subvendor = cfg->subvendor;
-		devlist_entry->conf.pc_subdevice = cfg->subdevice;
-		devlist_entry->conf.pc_vendor = cfg->vendor;
-		devlist_entry->conf.pc_device = cfg->device;
+	if (bootverbose) {
+		if (actual == 1)
+			device_printf(child, "using IRQ %d for MSI\n", irqs[0]);
+		else {
+			int run;
 
-		devlist_entry->conf.pc_class = cfg->baseclass;
-		devlist_entry->conf.pc_subclass = cfg->subclass;
-		devlist_entry->conf.pc_progif = cfg->progif;
-		devlist_entry->conf.pc_revid = cfg->revid;
+			/*
+			 * 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;
+				}
 
-		pci_numdevs++;
-		pci_generation++;
+				/* Finish previous range. */
+				if (run) {
+					printf("-%d", irqs[i - 1]);
+					run = 0;
+				}
+
+				/* Start new range. */
+				printf(",%d", irqs[i]);
+			}
+
+			/* Unfinished range? */
+			if (run)
+				printf("-%d", irqs[actual - 1]);
+			printf(" for MSI\n");
+		}
 	}
-	return (devlist_entry);
-#undef REG
+
+	/* 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);
 }
 
-static void
-pci_read_extcap(device_t pcib, pcicfgregs *cfg)
+/* Release the MSI messages associated with this device. */
+int
+pci_release_msi_method(device_t dev, device_t child)
 {
-#define REG(n, w)	PCIB_READ_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, w)
-	int	ptr, nextptr, ptrptr;
+	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];
 
-	switch (cfg->hdrtype & PCIM_HDRTYPE) {
-	case 0:
-		ptrptr = PCIR_CAP_PTR;
-		break;
-	case 2:
-		ptrptr = 0x14;
-		break;
-	default:
-		return;		/* no extended capabilities support */
-	}
-	nextptr = REG(ptrptr, 1);	/* sanity check? */
+	/* Try MSI-X first. */
+	error = pci_release_msix(dev, child);
+	if (error != ENODEV)
+		return (error);
 
-	/*
-	 * Read capability entries.
-	 */
-	while (nextptr != 0) {
-		/* Sanity check */
-		if (nextptr > 255) {
-			printf("illegal PCI extended capability offset %d\n",
-			    nextptr);
-			return;
-		}
-		/* Find the next entry */
-		ptr = nextptr;
-		nextptr = REG(ptr + 1, 1);
+	/* 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);
+}
 
-		/* Process this entry */
-		switch (REG(ptr, 1)) {
-		case PCIY_PMG:		/* PCI power management */
-			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_MSI:		/* PCI MSI */
-			cfg->msi.msi_ctrl = REG(ptr + PCIR_MSI_CTRL, 2);
-			if (cfg->msi.msi_ctrl & PCIM_MSICTRL_64BIT)
-				cfg->msi.msi_data = PCIR_MSI_DATA_64BIT;
-			else
-				cfg->msi.msi_data = PCIR_MSI_DATA;
-			cfg->msi.msi_msgnum = 1 << ((cfg->msi.msi_ctrl &
-						     PCIM_MSICTRL_MMC_MASK)>>1);
-		default:
-			break;
-		}
-	}
-#undef REG
+/*
+ * 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);
 }
 
 /* free pcicfgregs structure and all depending data structures */
@@ -481,9 +1923,19 @@
 pci_freecfg(struct pci_devinfo *dinfo)
 {
 	struct devlist *devlist_head;
+	int i;
 
 	devlist_head = &pci_devq;
 
+	if (dinfo->cfg.vpd.vpd_reg) {
+		free(dinfo->cfg.vpd.vpd_ident, M_DEVBUF);
+		for (i = 0; i < dinfo->cfg.vpd.vpd_rocnt; i++)
+			free(dinfo->cfg.vpd.vpd_ros[i].value, M_DEVBUF);
+		free(dinfo->cfg.vpd.vpd_ros, M_DEVBUF);
+		for (i = 0; i < dinfo->cfg.vpd.vpd_wcnt; i++)
+			free(dinfo->cfg.vpd.vpd_w[i].value, M_DEVBUF);
+		free(dinfo->cfg.vpd.vpd_w, M_DEVBUF);
+	}
 	STAILQ_REMOVE(devlist_head, dinfo, pci_devinfo, pci_links);
 	free(dinfo, M_DEVBUF);
 
@@ -563,9 +2015,9 @@
 
 	if (bootverbose)
 		printf(
-		    "pci%d:%d:%d: Transition from D%d to D%d\n",
-		    dinfo->cfg.bus, dinfo->cfg.slot, dinfo->cfg.func,
-		    oldstate, state);
+		    "pci%d:%d:%d:%d: Transition from D%d to D%d\n",
+		    dinfo->cfg.domain, dinfo->cfg.bus, dinfo->cfg.slot,
+		    dinfo->cfg.func, oldstate, state);
 
 	PCI_WRITE_CONFIG(dev, child, cfg->pp.pp_status, status, 2);
 	if (delay)
@@ -715,17 +2167,18 @@
 void
 pci_print_verbose(struct pci_devinfo *dinfo)
 {
+
 	if (bootverbose) {
 		pcicfgregs *cfg = &dinfo->cfg;
 
-		printf("found->\tvendor=0x%04x, dev=0x%04x, revid=0x%02x\n", 
+		printf("found->\tvendor=0x%04x, dev=0x%04x, revid=0x%02x\n",
 		    cfg->vendor, cfg->device, cfg->revid);
-		printf("\tbus=%d, slot=%d, func=%d\n",
-		    cfg->bus, cfg->slot, cfg->func);
+		printf("\tdomain=%d, bus=%d, slot=%d, func=%d\n",
+		    cfg->domain, cfg->bus, cfg->slot, cfg->func);
 		printf("\tclass=%02x-%02x-%02x, hdrtype=0x%02x, mfdev=%d\n",
 		    cfg->baseclass, cfg->subclass, cfg->progif, cfg->hdrtype,
 		    cfg->mfdev);
-		printf("\tcmdreg=0x%04x, statreg=0x%04x, cachelnsz=%d (dwords)\n", 
+		printf("\tcmdreg=0x%04x, statreg=0x%04x, cachelnsz=%d (dwords)\n",
 		    cfg->cmdreg, cfg->statreg, cfg->cachelnsz);
 		printf("\tlattimer=0x%02x (%d ns), mingnt=0x%02x (%d ns), maxlat=0x%02x (%d ns)\n",
 		    cfg->lattimer, cfg->lattimer * 30, cfg->mingnt,
@@ -743,16 +2196,28 @@
 			    cfg->pp.pp_cap & PCIM_PCAP_D2SUPP ? " D2" : "",
 			    status & PCIM_PSTAT_DMASK);
 		}
-		if (cfg->msi.msi_data) {
+		if (cfg->msi.msi_location) {
 			int ctrl;
 
-			ctrl =  cfg->msi.msi_ctrl;
+			ctrl = cfg->msi.msi_ctrl;
 			printf("\tMSI supports %d message%s%s%s\n",
 			    cfg->msi.msi_msgnum,
 			    (cfg->msi.msi_msgnum == 1) ? "" : "s",
 			    (ctrl & PCIM_MSICTRL_64BIT) ? ", 64 bit" : "",
 			    (ctrl & PCIM_MSICTRL_VECTOR) ? ", vector masks":"");
 		}
+		if (cfg->msix.msix_location) {
+			printf("\tMSI-X supports %d message%s ",
+			    cfg->msix.msix_msgnum,
+			    (cfg->msix.msix_msgnum == 1) ? "" : "s");
+			if (cfg->msix.msix_table_bar == cfg->msix.msix_pba_bar)
+				printf("in map 0x%x\n",
+				    cfg->msix.msix_table_bar);
+			else
+				printf("in maps 0x%x and 0x%x\n",
+				    cfg->msix.msix_table_bar,
+				    cfg->msix.msix_pba_bar);
+		}
 	}
 }
 
@@ -780,8 +2245,8 @@
     int prefetch)
 {
 	uint32_t map;
-	uint64_t base;
-	uint64_t start, end, count;
+	pci_addr_t base;
+	pci_addr_t start, end, count;
 	uint8_t ln2size;
 	uint8_t ln2range;
 	uint32_t testval;
@@ -795,7 +2260,7 @@
 	testval = PCIB_READ_CONFIG(pcib, b, s, f, reg, 4);
 	PCIB_WRITE_CONFIG(pcib, b, s, f, reg, map, 4);
 
-	if (pci_maptype(map) & PCI_MAPMEM)
+	if (PCI_BAR_MEM(map))
 		type = SYS_RES_MEMORY;
 	else
 		type = SYS_RES_IOPORT;
@@ -811,8 +2276,7 @@
 	 * areas to the type of memory involved.  Memory must be at least
 	 * 16 bytes in size, while I/O ranges must be at least 4.
 	 */
-	if ((testval & 0x1) == 0x1 &&
-	    (testval & 0x2) != 0)
+	if (PCI_BAR_IO(testval) && (testval & PCIM_BAR_IO_RESERVED) != 0)
 		return (barlen);
 	if ((type == SYS_RES_MEMORY && ln2size < 4) ||
 	    (type == SYS_RES_IOPORT && ln2size < 2))
@@ -821,11 +2285,9 @@
 	if (ln2range == 64)
 		/* Read the other half of a 64bit map register */
 		base |= (uint64_t) PCIB_READ_CONFIG(pcib, b, s, f, reg + 4, 4) << 32;
-
 	if (bootverbose) {
-		printf("\tmap[%02x]: type %x, range %2d, base %08x, size %2d",
-		    reg, pci_maptype(map), ln2range, 
-		    (unsigned int) base, ln2size);
+		printf("\tmap[%02x]: type %s, range %2d, base %#jx, size %2d",
+		    reg, pci_maptype(map), ln2range, (uintmax_t)base, ln2size);
 		if (type == SYS_RES_IOPORT && !pci_porten(pcib, b, s, f))
 			printf(", port disabled\n");
 		else if (type == SYS_RES_MEMORY && !pci_memen(pcib, b, s, f))
@@ -847,6 +2309,12 @@
 	 */
 	if (!force && (base == 0 || map == testval))
 		return (barlen);
+	if ((u_long)base != base) {
+		device_printf(bus,
+		    "pci%d:%d:%d:%d bar %#x too many address bits",
+		    pci_get_domain(dev), b, s, f, reg);
+		return (barlen);
+	}
 
 	/*
 	 * This code theoretically does the right thing, but has
@@ -890,8 +2358,20 @@
 	 */
 	res = resource_list_alloc(rl, bus, dev, type, &reg, start, end, count,
 	    prefetch ? RF_PREFETCHABLE : 0);
-	if (res != NULL)
-		pci_write_config(dev, reg, rman_get_start(res), 4);
+	if (res == NULL)
+		return (barlen);
+	start = rman_get_start(res);
+	if ((u_long)start != start) {
+		/* Wait a minute!  this platform can't do this address. */
+		device_printf(bus,
+		    "pci%d:%d.%d.%x bar %#x start %#jx, too many bits.",
+		    pci_get_domain(dev), b, s, f, reg, (uintmax_t)start);
+		resource_list_release(rl, bus, dev, type, reg, res);
+		return (barlen);
+	}
+	pci_write_config(dev, reg, start, 4);
+	if (ln2range == 64)
+		pci_write_config(dev, reg + 4, start >> 32, 4);
 	return (barlen);
 }
 
@@ -899,7 +2379,7 @@
  * For ATA devices we need to decide early what addressing mode to use.
  * Legacy demands that the primary and secondary ATA ports sits on the
  * same addresses that old ISA hardware did. This dictates that we use
- * those addresses and ignore the BAR's if we cannot set PCI native 
+ * those addresses and ignore the BAR's if we cannot set PCI native
  * addressing mode.
  */
 static void
@@ -970,8 +2450,9 @@
 
 	/* Let the user override the IRQ with a tunable. */
 	irq = PCI_INVALID_IRQ;
-	snprintf(tunable_name, sizeof(tunable_name), "hw.pci%d.%d.INT%c.irq",
-	    cfg->bus, cfg->slot, cfg->intpin + 'A' - 1);
+	snprintf(tunable_name, sizeof(tunable_name),
+	    "hw.pci%d.%d.%d.INT%c.irq",
+	    cfg->domain, cfg->bus, cfg->slot, cfg->intpin + 'A' - 1);
 	if (TUNABLE_INT_FETCH(tunable_name, &irq) && (irq >= 255 || irq <= 0))
 		irq = PCI_INVALID_IRQ;
 
@@ -1022,7 +2503,9 @@
 	/* ATA devices needs special map treatment */
 	if ((pci_get_class(dev) == PCIC_STORAGE) &&
 	    (pci_get_subclass(dev) == PCIS_STORAGE_IDE) &&
-	    (pci_get_progif(dev) & PCIP_STORAGE_IDE_MASTERDEV))
+	    ((pci_get_progif(dev) & PCIP_STORAGE_IDE_MASTERDEV) ||
+	     (!pci_read_config(dev, PCIR_BAR(0), 4) &&
+	      !pci_read_config(dev, PCIR_BAR(2), 4))) )
 		pci_ata_maps(pcib, bus, dev, b, s, f, rl, force, prefetchmask);
 	else
 		for (i = 0; i < cfg->nummaps;)
@@ -1040,8 +2523,7 @@
 	}
 
 	if (cfg->intpin > 0 && PCI_INTERRUPT_VALID(cfg->intline)) {
-#if defined(__ia64__) || defined(__i386__) || defined(__amd64__) || \
-		defined(__arm__) || defined(__alpha__)
+#ifdef __PCI_REROUTE_INTERRUPT
 		/*
 		 * Try to re-route interrupts. Sometimes the BIOS or
 		 * firmware may leave bogus values in these registers.
@@ -1056,9 +2538,9 @@
 }
 
 void
-pci_add_children(device_t dev, int busno, size_t dinfo_size)
+pci_add_children(device_t dev, int domain, int busno, size_t dinfo_size)
 {
-#define REG(n, w)	PCIB_READ_CONFIG(pcib, busno, s, f, n, w)
+#define	REG(n, w)	PCIB_READ_CONFIG(pcib, busno, s, f, n, w)
 	device_t pcib = device_get_parent(dev);
 	struct pci_devinfo *dinfo;
 	int maxslots;
@@ -1067,7 +2549,7 @@
 
 	KASSERT(dinfo_size >= sizeof(struct pci_devinfo),
 	    ("dinfo_size too small"));
-	maxslots = PCIB_MAXSLOTS(pcib);	
+	maxslots = PCIB_MAXSLOTS(pcib);
 	for (s = 0; s <= maxslots; s++) {
 		pcifunchigh = 0;
 		f = 0;
@@ -1078,7 +2560,8 @@
 		if (hdrtype & PCIM_MFDEV)
 			pcifunchigh = PCI_FUNCMAX;
 		for (f = 0; f <= pcifunchigh; f++) {
-			dinfo = pci_read_device(pcib, busno, s, f, dinfo_size);
+			dinfo = pci_read_device(pcib, domain, busno, s, f,
+			    dinfo_size);
 			if (dinfo != NULL) {
 				pci_add_child(dev, dinfo);
 			}
@@ -1112,19 +2595,21 @@
 static int
 pci_attach(device_t dev)
 {
-	int busno;
+	int busno, domain;
 
 	/*
 	 * Since there can be multiple independantly numbered PCI
-	 * busses on some large alpha systems, we can't use the unit
-	 * number to decide what bus we are probing. We ask the parent 
-	 * pcib what our bus number is.
+	 * busses on systems with multiple PCI domains, we can't use
+	 * the unit number to decide which bus we are probing. We ask
+	 * the parent pcib what our domain and bus numbers are.
 	 */
+	domain = pcib_get_domain(dev);
 	busno = pcib_get_bus(dev);
 	if (bootverbose)
-		device_printf(dev, "physical bus=%d\n", busno);
+		device_printf(dev, "domain=%d, physical bus=%d\n",
+		    domain, busno);
 
-	pci_add_children(dev, busno, sizeof(struct pci_devinfo));
+	pci_add_children(dev, domain, busno, sizeof(struct pci_devinfo));
 
 	return (bus_generic_attach(dev));
 }
@@ -1247,8 +2732,9 @@
 		dinfo = device_get_ivars(child);
 		pci_print_verbose(dinfo);
 		if (bootverbose)
-			printf("pci%d:%d:%d: reprobing on driver added\n",
-			    dinfo->cfg.bus, dinfo->cfg.slot, dinfo->cfg.func);
+			printf("pci%d:%d:%d:%d: reprobing on driver added\n",
+			    dinfo->cfg.domain, dinfo->cfg.bus, dinfo->cfg.slot,
+			    dinfo->cfg.func);
 		pci_cfg_restore(child, dinfo);
 		if (device_probe_and_attach(child) != 0)
 			pci_cfg_save(child, dinfo, 1);
@@ -1257,6 +2743,134 @@
 }
 
 int
+pci_setup_intr(device_t dev, device_t child, struct resource *irq, int flags,
+    driver_filter_t *filter, driver_intr_t *intr, void *arg, void **cookiep)
+{
+	struct pci_devinfo *dinfo;
+	struct msix_table_entry *mte;
+	struct msix_vector *mv;
+	uint64_t addr;
+	uint32_t data;
+	void *cookie;
+	int error, rid;
+
+	error = bus_generic_setup_intr(dev, child, irq, flags, filter, intr,
+	    arg, &cookie);
+	if (error)
+		return (error);
+
+	/*
+	 * If this is a direct child, check to see if the interrupt is
+	 * MSI or MSI-X.  If so, ask our parent to map the MSI and give
+	 * us the address and data register values.  If we fail for some
+	 * reason, teardown the interrupt handler.
+	 */
+	rid = rman_get_rid(irq);
+	if (device_get_parent(child) == dev && rid > 0) {
+		dinfo = device_get_ivars(child);
+		if (dinfo->cfg.msi.msi_alloc > 0) {
+			if (dinfo->cfg.msi.msi_addr == 0) {
+				KASSERT(dinfo->cfg.msi.msi_handlers == 0,
+			    ("MSI has handlers, but vectors not mapped"));
+				error = PCIB_MAP_MSI(device_get_parent(dev),
+				    child, rman_get_start(irq), &addr, &data);
+				if (error)
+					goto bad;
+				dinfo->cfg.msi.msi_addr = addr;
+				dinfo->cfg.msi.msi_data = data;
+				pci_enable_msi(child, addr, data);
+			}
+			dinfo->cfg.msi.msi_handlers++;
+		} else {
+			KASSERT(dinfo->cfg.msix.msix_alloc > 0,
+			    ("No MSI or MSI-X interrupts allocated"));
+			KASSERT(rid <= dinfo->cfg.msix.msix_table_len,
+			    ("MSI-X index too high"));
+			mte = &dinfo->cfg.msix.msix_table[rid - 1];
+			KASSERT(mte->mte_vector != 0, ("no message vector"));
+			mv = &dinfo->cfg.msix.msix_vectors[mte->mte_vector - 1];
+			KASSERT(mv->mv_irq == rman_get_start(irq),
+			    ("IRQ mismatch"));
+			if (mv->mv_address == 0) {
+				KASSERT(mte->mte_handlers == 0,
+		    ("MSI-X table entry has handlers, but vector not mapped"));
+				error = PCIB_MAP_MSI(device_get_parent(dev),
+				    child, rman_get_start(irq), &addr, &data);
+				if (error)
+					goto bad;
+				mv->mv_address = addr;
+				mv->mv_data = data;
+			}
+			if (mte->mte_handlers == 0) {
+				pci_enable_msix(child, rid - 1, mv->mv_address,
+				    mv->mv_data);
+				pci_unmask_msix(child, rid - 1);
+			}
+			mte->mte_handlers++;
+		}
+	bad:
+		if (error) {
+			(void)bus_generic_teardown_intr(dev, child, irq,
+			    cookie);
+			return (error);
+		}
+	}
+	*cookiep = cookie;
+	return (0);
+}
+
+int
+pci_teardown_intr(device_t dev, device_t child, struct resource *irq,
+    void *cookie)
+{
+	struct msix_table_entry *mte;
+	struct resource_list_entry *rle;
+	struct pci_devinfo *dinfo;
+	int error, rid;
+
+	/*
+	 * If this is a direct child, check to see if the interrupt is
+	 * MSI or MSI-X.  If so, decrement the appropriate handlers
+	 * count and mask the MSI-X message, or disable MSI messages
+	 * if the count drops to 0.
+	 */
+	if (irq == NULL || !(rman_get_flags(irq) & RF_ACTIVE))
+		return (EINVAL);
+	rid = rman_get_rid(irq);
+	if (device_get_parent(child) == dev && rid > 0) {
+		dinfo = device_get_ivars(child);
+		rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, rid);
+		if (rle->res != irq)
+			return (EINVAL);
+		if (dinfo->cfg.msi.msi_alloc > 0) {
+			KASSERT(rid <= dinfo->cfg.msi.msi_alloc,
+			    ("MSI-X index too high"));
+			if (dinfo->cfg.msi.msi_handlers == 0)
+				return (EINVAL);
+			dinfo->cfg.msi.msi_handlers--;
+			if (dinfo->cfg.msi.msi_handlers == 0)
+				pci_disable_msi(child);
+		} else {
+			KASSERT(dinfo->cfg.msix.msix_alloc > 0,
+			    ("No MSI or MSI-X interrupts allocated"));
+			KASSERT(rid <= dinfo->cfg.msix.msix_table_len,
+			    ("MSI-X index too high"));
+			mte = &dinfo->cfg.msix.msix_table[rid - 1];
+			if (mte->mte_handlers == 0)
+				return (EINVAL);
+			mte->mte_handlers--;
+			if (mte->mte_handlers == 0)
+				pci_mask_msix(child, rid - 1);
+		}
+	}
+	error = bus_generic_teardown_intr(dev, child, irq, cookie);
+	if (device_get_parent(child) == dev && rid > 0)
+		KASSERT(error == 0,
+		    ("%s: generic teardown failed for MSI/MSI-X", __func__));
+	return (error);
+}
+
+int
 pci_print_child(device_t dev, device_t child)
 {
 	struct pci_devinfo *dinfo;
@@ -1345,7 +2959,7 @@
 	{PCIC_PROCESSOR,	-1,			"processor"},
 	{PCIC_SERIALBUS,	-1,			"serial bus"},
 	{PCIC_SERIALBUS,	PCIS_SERIALBUS_FW,	"FireWire"},
-	{PCIC_SERIALBUS,	PCIS_SERIALBUS_ACCESS,	"AccessBus"},	 
+	{PCIC_SERIALBUS,	PCIS_SERIALBUS_ACCESS,	"AccessBus"},
 	{PCIC_SERIALBUS,	PCIS_SERIALBUS_SSA,	"SSA"},
 	{PCIC_SERIALBUS,	PCIS_SERIALBUS_USB,	"USB"},
 	{PCIC_SERIALBUS,	PCIS_SERIALBUS_FC,	"Fibre Channel"},
@@ -1374,7 +2988,7 @@
 {
 	int	i;
 	char	*cp, *scp, *device;
-	
+
 	/*
 	 * Look for a listing for this device in a loaded device database.
 	 */
@@ -1398,35 +3012,33 @@
 				}
 			}
 		}
-		device_printf(dev, "<%s%s%s>", 
+		device_printf(dev, "<%s%s%s>",
 		    cp ? cp : "",
 		    ((cp != NULL) && (scp != NULL)) ? ", " : "",
 		    scp ? scp : "");
 	}
 	printf(" at device %d.%d (no driver attached)\n",
 	    pci_get_slot(child), pci_get_function(child));
-	if (pci_do_power_nodriver)
-		pci_cfg_save(child,
-		    (struct pci_devinfo *) device_get_ivars(child), 1);
+	pci_cfg_save(child, (struct pci_devinfo *)device_get_ivars(child), 1);
 	return;
 }
 
 /*
- * Parse the PCI device database, if loaded, and return a pointer to a 
+ * Parse the PCI device database, if loaded, and return a pointer to a
  * description of the device.
  *
  * The database is flat text formatted as follows:
  *
  * Any line not in a valid format is ignored.
  * Lines are terminated with newline '\n' characters.
- * 
+ *
  * A VENDOR line consists of the 4 digit (hex) vendor code, a TAB, then
  * the vendor name.
- * 
+ *
  * A DEVICE line is entered immediately below the corresponding VENDOR ID.
  * - devices cannot be listed without a corresponding VENDOR line.
  * A DEVICE line consists of a TAB, the 4 digit (hex) device code,
- * another TAB, then the device name.                                            
+ * another TAB, then the device name.
  */
 
 /*
@@ -1440,7 +3052,7 @@
  * database with a newline when we initialise.
  */
 static int
-pci_describe_parse_line(char **ptr, int *vendor, int *device, char **desc) 
+pci_describe_parse_line(char **ptr, int *vendor, int *device, char **desc)
 {
 	char	*cp = *ptr;
 	int	left;
@@ -1463,7 +3075,7 @@
 		if (*cp == '\t' &&
 		    sscanf(cp, "%x\t%80[^\n]", device, *desc) == 2)
 			break;
-		
+
 		/* skip to next line */
 		while (*cp != '\n' && left > 0) {
 			cp++;
@@ -1492,7 +3104,7 @@
 	char	*desc, *vp, *dp, *line;
 
 	desc = vp = dp = NULL;
-	
+
 	/*
 	 * If we have no vendor data, we can't do anything.
 	 */
@@ -1588,6 +3200,9 @@
 	case PCI_IVAR_IRQ:
 		*result = cfg->intline;
 		break;
+	case PCI_IVAR_DOMAIN:
+		*result = cfg->domain;
+		break;
 	case PCI_IVAR_BUS:
 		*result = cfg->bus;
 		break;
@@ -1640,6 +3255,7 @@
 	case PCI_IVAR_PROGIF:
 	case PCI_IVAR_REVID:
 	case PCI_IVAR_IRQ:
+	case PCI_IVAR_DOMAIN:
 	case PCI_IVAR_BUS:
 	case PCI_IVAR_SLOT:
 	case PCI_IVAR_FUNCTION:
@@ -1666,7 +3282,7 @@
 	struct devlist *devlist_head;
 	struct pci_conf *p;
 	const char *name;
-	int i, error, none_count, quit;
+	int i, error, none_count;
 
 	none_count = 0;
 	/* get the head of the device queue */
@@ -1675,10 +3291,9 @@
 	/*
 	 * Go through the list of devices and print out devices
 	 */
-	db_setup_paging(db_simple_pager, &quit, db_lines_per_page);
-	for (error = 0, i = 0, quit = 0,
+	for (error = 0, i = 0,
 	     dinfo = STAILQ_FIRST(devlist_head);
-	     (dinfo != NULL) && (error == 0) && (i < pci_numdevs) && !quit;
+	     (dinfo != NULL) && (error == 0) && (i < pci_numdevs) && !db_pager_quit;
 	     dinfo = STAILQ_NEXT(dinfo, pci_links), i++) {
 
 		/* Populate pd_name and pd_unit */
@@ -1687,12 +3302,12 @@
 			name = device_get_name(dinfo->cfg.dev);
 
 		p = &dinfo->conf;
-		db_printf("%s%d at pci%d:%d:%d:\tclass=0x%06x card=0x%08x "
+		db_printf("%s%d at pci%d:%d:%d:%d:\tclass=0x%06x card=0x%08x "
 			"chip=0x%08x rev=0x%02x hdr=0x%02x\n",
 			(name && *name) ? name : "none",
 			(name && *name) ? (int)device_get_unit(dinfo->cfg.dev) :
 			none_count++,
-			p->pc_sel.pc_bus, p->pc_sel.pc_dev,
+			p->pc_sel.pc_domain, p->pc_sel.pc_bus, p->pc_sel.pc_dev,
 			p->pc_sel.pc_func, (p->pc_class << 16) |
 			(p->pc_subclass << 8) | p->pc_progif,
 			(p->pc_subdevice << 16) | p->pc_subvendor,
@@ -1710,7 +3325,7 @@
 	struct resource_list *rl = &dinfo->resources;
 	struct resource_list_entry *rle;
 	struct resource *res;
-	uint32_t map, testval;
+	pci_addr_t map, testval;
 	int mapsize;
 
 	/*
@@ -1724,9 +3339,19 @@
 	map = pci_read_config(child, *rid, 4);
 	pci_write_config(child, *rid, 0xffffffff, 4);
 	testval = pci_read_config(child, *rid, 4);
+	if (pci_maprange(testval) == 64)
+		map |= (pci_addr_t)pci_read_config(child, *rid + 4, 4) << 32;
 	if (pci_mapbase(testval) == 0)
 		goto out;
-	if (pci_maptype(testval) & PCI_MAPMEM) {
+
+	/*
+	 * Restore the original value of the BAR.  We may have reprogrammed
+	 * the BAR of the low-level console device and when booting verbose,
+	 * we need the console device addressable.
+	 */
+	pci_write_config(child, *rid, map, 4);
+
+	if (PCI_BAR_MEM(testval)) {
 		if (type != SYS_RES_MEMORY) {
 			if (bootverbose)
 				device_printf(dev,
@@ -1753,10 +3378,10 @@
 	 * another driver, which won't work.
 	 */
 	mapsize = pci_mapsize(testval);
-	count = 1 << mapsize;
+	count = 1UL << mapsize;
 	if (RF_ALIGNMENT(flags) < mapsize)
 		flags = (flags & ~RF_ALIGNMENT_MASK) | RF_ALIGNMENT_LOG2(mapsize);
-	
+
 	/*
 	 * Allocate enough resource, and then write back the
 	 * appropriate bar for that resource.
@@ -1784,6 +3409,8 @@
 	map = rman_get_start(res);
 out:;
 	pci_write_config(child, *rid, map, 4);
+	if (pci_maprange(testval) == 64)
+		pci_write_config(child, *rid + 4, map >> 32, 4);
 	return (res);
 }
 
@@ -1804,11 +3431,18 @@
 		switch (type) {
 		case SYS_RES_IRQ:
 			/*
+			 * Can't alloc legacy interrupt once MSI messages
+			 * have been allocated.
+			 */
+			if (*rid == 0 && (cfg->msi.msi_alloc > 0 ||
+			    cfg->msix.msix_alloc > 0))
+				return (NULL);
+			/*
 			 * If the child device doesn't have an
 			 * interrupt routed and is deserving of an
 			 * interrupt, try to assign it one.
 			 */
-			if (!PCI_INTERRUPT_VALID(cfg->intline) &&
+			if (*rid == 0 && !PCI_INTERRUPT_VALID(cfg->intline) &&
 			    (cfg->intpin != 0))
 				pci_assign_interrupt(dev, child, 0);
 			break;
@@ -1847,10 +3481,10 @@
 			    "Reserved %#lx bytes for rid %#x type %d at %#lx\n",
 				    rman_get_size(rle->res), *rid, type,
 				    rman_get_start(rle->res));
-			if ((flags & RF_ACTIVE) && 
+			if ((flags & RF_ACTIVE) &&
 			    bus_generic_activate_resource(dev, child, type,
 			    *rid, rle->res) != 0)
-				return NULL;
+				return (NULL);
 			return (rle->res);
 		}
 	}
@@ -1886,7 +3520,7 @@
 		}
 		resource_list_delete(rl, type, rid);
 	}
-	/* 
+	/*
 	 * Why do we turn off the PCI configuration BAR when we delete a
 	 * resource? -- imp
 	 */
@@ -1913,7 +3547,7 @@
 }
 
 void
-pci_write_config_method(device_t dev, device_t child, int reg, 
+pci_write_config_method(device_t dev, device_t child, int reg,
     uint32_t val, int width)
 {
 	struct pci_devinfo *dinfo = device_get_ivars(child);
@@ -2019,6 +3653,12 @@
 	pci_write_config(dev, PCIR_LATTIMER, dinfo->cfg.lattimer, 1);
 	pci_write_config(dev, PCIR_PROGIF, dinfo->cfg.progif, 1);
 	pci_write_config(dev, PCIR_REVID, dinfo->cfg.revid, 1);
+
+	/* Restore MSI and MSI-X configurations if they are present. */
+	if (dinfo->cfg.msi.msi_location != 0)
+		pci_resume_msi(dev);
+	if (dinfo->cfg.msix.msix_location != 0)
+		pci_resume_msix(dev);
 }
 
 void
Index: fixup_pci.c
===================================================================
RCS file: /home/cvs/src/sys/dev/pci/fixup_pci.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/dev/pci/fixup_pci.c -L sys/dev/pci/fixup_pci.c -u -r1.2 -r1.3
--- sys/dev/pci/fixup_pci.c
+++ sys/dev/pci/fixup_pci.c
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/pci/fixup_pci.c,v 1.6.8.1 2006/05/31 21:37:11 jhb Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/pci/fixup_pci.c,v 1.7 2006/05/24 14:08:31 jhb Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
Index: pci_user.c
===================================================================
RCS file: /home/cvs/src/sys/dev/pci/pci_user.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/pci/pci_user.c -L sys/dev/pci/pci_user.c -u -r1.1.1.1 -r1.2
--- sys/dev/pci/pci_user.c
+++ sys/dev/pci/pci_user.c
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/pci/pci_user.c,v 1.19.2.1 2005/09/16 17:58:06 ps Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/pci/pci_user.c,v 1.22.2.1.2.2 2008/01/24 18:53:29 jhb Exp $");
 
 #include "opt_bus.h"	/* XXX trim includes */
 #include "opt_compat.h"
@@ -125,6 +125,11 @@
 		 * comparison.  If the comparison fails, we don't have a
 		 * match, go on to the next item if there is one.
 		 */
+		if (((matches[i].flags & PCI_GETCONF_MATCH_DOMAIN) != 0)
+		 && (match_buf->pc_sel.pc_domain !=
+		 matches[i].pc_sel.pc_domain))
+			continue;
+
 		if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0)
 		 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
 			continue;
@@ -164,33 +169,178 @@
 	return(1);
 }
 
+#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
+    defined(COMPAT_FREEBSD6)
+#define PRE7_COMPAT
+
+typedef enum {
+	PCI_GETCONF_NO_MATCH_OLD	= 0x00,
+	PCI_GETCONF_MATCH_BUS_OLD	= 0x01,
+	PCI_GETCONF_MATCH_DEV_OLD	= 0x02,
+	PCI_GETCONF_MATCH_FUNC_OLD	= 0x04,
+	PCI_GETCONF_MATCH_NAME_OLD	= 0x08,
+	PCI_GETCONF_MATCH_UNIT_OLD	= 0x10,
+	PCI_GETCONF_MATCH_VENDOR_OLD	= 0x20,
+	PCI_GETCONF_MATCH_DEVICE_OLD	= 0x40,
+	PCI_GETCONF_MATCH_CLASS_OLD	= 0x80
+} pci_getconf_flags_old;
+
+struct pcisel_old {
+	u_int8_t	pc_bus;		/* bus number */
+	u_int8_t	pc_dev;		/* device on this bus */
+	u_int8_t	pc_func;	/* function on this device */
+};
+
+struct pci_conf_old {
+	struct pcisel_old pc_sel;	/* bus+slot+function */
+	u_int8_t	pc_hdr;		/* PCI header type */
+	u_int16_t	pc_subvendor;	/* card vendor ID */
+	u_int16_t	pc_subdevice;	/* card device ID, assigned by
+					   card vendor */
+	u_int16_t	pc_vendor;	/* chip vendor ID */
+	u_int16_t	pc_device;	/* chip device ID, assigned by
+					   chip vendor */
+	u_int8_t	pc_class;	/* chip PCI class */
+	u_int8_t	pc_subclass;	/* chip PCI subclass */
+	u_int8_t	pc_progif;	/* chip PCI programming interface */
+	u_int8_t	pc_revid;	/* chip revision ID */
+	char		pd_name[PCI_MAXNAMELEN + 1];  /* device name */
+	u_long		pd_unit;	/* device unit number */
+};
+
+struct pci_match_conf_old {
+	struct pcisel_old	pc_sel;		/* bus+slot+function */
+	char			pd_name[PCI_MAXNAMELEN + 1];  /* device name */
+	u_long			pd_unit;	/* Unit number */
+	u_int16_t		pc_vendor;	/* PCI Vendor ID */
+	u_int16_t		pc_device;	/* PCI Device ID */
+	u_int8_t		pc_class;	/* PCI class */
+	pci_getconf_flags_old	flags;		/* Matching expression */
+};
+
+struct pci_io_old {
+	struct pcisel_old pi_sel;	/* device to operate on */
+	int		pi_reg;		/* configuration register to examine */
+	int		pi_width;	/* width (in bytes) of read or write */
+	u_int32_t	pi_data;	/* data to write or result of read */
+};
+
+#define	PCIOCGETCONF_OLD	_IOWR('p', 1, struct pci_conf_io)
+#define	PCIOCREAD_OLD		_IOWR('p', 2, struct pci_io_old)
+#define	PCIOCWRITE_OLD		_IOWR('p', 3, struct pci_io_old)
+
+static int	pci_conf_match_old(struct pci_match_conf_old *matches,
+		    int num_matches, struct pci_conf *match_buf);
+
+static int
+pci_conf_match_old(struct pci_match_conf_old *matches, int num_matches,
+    struct pci_conf *match_buf)
+{
+	int i;
+
+	if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
+		return(1);
+
+	for (i = 0; i < num_matches; i++) {
+		if (match_buf->pc_sel.pc_domain != 0)
+			continue;
+
+		/*
+		 * I'm not sure why someone would do this...but...
+		 */
+		if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD)
+			continue;
+
+		/*
+		 * Look at each of the match flags.  If it's set, do the
+		 * comparison.  If the comparison fails, we don't have a
+		 * match, go on to the next item if there is one.
+		 */
+		if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0)
+		 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
+			continue;
+
+		if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0)
+		 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
+			continue;
+
+		if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0)
+		 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
+			continue;
+
+		if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0)
+		 && (match_buf->pc_vendor != matches[i].pc_vendor))
+			continue;
+
+		if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0)
+		 && (match_buf->pc_device != matches[i].pc_device))
+			continue;
+
+		if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0)
+		 && (match_buf->pc_class != matches[i].pc_class))
+			continue;
+
+		if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0)
+		 && (match_buf->pd_unit != matches[i].pd_unit))
+			continue;
+
+		if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_OLD) != 0)
+		 && (strncmp(matches[i].pd_name, match_buf->pd_name,
+			     sizeof(match_buf->pd_name)) != 0))
+			continue;
+
+		return(0);
+	}
+
+	return(1);
+}
+
+#endif
+
 static int
 pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
 {
-	device_t pcidev;
-	struct pci_io *io;
+	device_t pcidev, brdev;
+	void *confdata;
 	const char *name;
-	int error;
+	struct devlist *devlist_head;
+	struct pci_conf_io *cio;
+	struct pci_devinfo *dinfo;
+	struct pci_io *io;
+	struct pci_match_conf *pattern_buf;
+	size_t confsz, iolen, pbufsz;
+	int error, ionum, i, num_patterns;
+#ifdef PRE7_COMPAT
+	struct pci_conf_old conf_old;
+	struct pci_io iodata;
+	struct pci_io_old *io_old;
+	struct pci_match_conf_old *pattern_buf_old;
 
+	io_old = NULL;
+	pattern_buf_old = NULL;
+
+	if (!(flag & FWRITE) &&
+	    (cmd != PCIOCGETCONF && cmd != PCIOCGETCONF_OLD))
+		return EPERM;
+#else
 	if (!(flag & FWRITE) && cmd != PCIOCGETCONF)
 		return EPERM;
+#endif
 
 	switch(cmd) {
+#ifdef PRE7_COMPAT
+	case PCIOCGETCONF_OLD:
+		/* FALLTHROUGH */
+#endif
 	case PCIOCGETCONF:
-		{
-		struct pci_devinfo *dinfo;
-		struct pci_conf_io *cio;
-		struct devlist *devlist_head;
-		struct pci_match_conf *pattern_buf;
-		int num_patterns;
-		size_t iolen;
-		int ionum, i;
-
 		cio = (struct pci_conf_io *)data;
 
+		pattern_buf = NULL;
 		num_patterns = 0;
 		dinfo = NULL;
 
+		cio->num_matches = 0;
+
 		/*
 		 * If the user specified an offset into the device list,
 		 * but the list has changed since they last called this
@@ -199,7 +349,6 @@
 		 */
 		if ((cio->offset != 0)
 		 && (cio->generation != pci_generation)){
-			cio->num_matches = 0;	
 			cio->status = PCI_GETCONF_LIST_CHANGED;
 			error = 0;
 			break;
@@ -210,7 +359,6 @@
 		 * past the end of our list.
 		 */
 		if (cio->offset >= pci_numdevs) {
-			cio->num_matches = 0;
 			cio->status = PCI_GETCONF_LAST_DEVICE;
 			error = 0;
 			break;
@@ -225,15 +373,20 @@
 		 * multiple of sizeof(struct pci_conf) in case the user
 		 * didn't specify a multiple of that size.
 		 */
-		iolen = min(cio->match_buf_len - 
-			    (cio->match_buf_len % sizeof(struct pci_conf)),
-			    pci_numdevs * sizeof(struct pci_conf));
+#ifdef PRE7_COMPAT
+		if (cmd == PCIOCGETCONF_OLD)
+			confsz = sizeof(struct pci_conf_old);
+		else
+#endif
+			confsz = sizeof(struct pci_conf);
+		iolen = min(cio->match_buf_len - (cio->match_buf_len % confsz),
+		    pci_numdevs * confsz);
 
 		/*
 		 * Since we know that iolen is a multiple of the size of
 		 * the pciconf union, it's okay to do this.
 		 */
-		ionum = iolen / sizeof(struct pci_conf);
+		ionum = iolen / confsz;
 
 		/*
 		 * If this test is true, the user wants the pci_conf
@@ -254,11 +407,15 @@
 			 * it's far more likely to just catch folks that
 			 * updated their kernel but not their userland.
 			 */
-			if ((cio->num_patterns *
-			    sizeof(struct pci_match_conf)) != cio->pat_buf_len){
-				/* The user made a mistake, return an error*/
+#ifdef PRE7_COMPAT
+			if (cmd == PCIOCGETCONF_OLD)
+				pbufsz = sizeof(struct pci_match_conf_old);
+			else
+#endif
+				pbufsz = sizeof(struct pci_match_conf);
+			if (cio->num_patterns * pbufsz != cio->pat_buf_len) {
+				/* The user made a mistake, return an error. */
 				cio->status = PCI_GETCONF_ERROR;
-				cio->num_matches = 0;
 				error = EINVAL;
 				break;
 			}
@@ -266,27 +423,34 @@
 			/*
 			 * Allocate a buffer to hold the patterns.
 			 */
-			pattern_buf = malloc(cio->pat_buf_len, M_TEMP,
-					     M_WAITOK);
-			error = copyin(cio->patterns, pattern_buf,
-				       cio->pat_buf_len);
+#ifdef PRE7_COMPAT
+			if (cmd == PCIOCGETCONF_OLD) {
+				pattern_buf_old = malloc(cio->pat_buf_len,
+				    M_TEMP, M_WAITOK);
+				error = copyin(cio->patterns,
+				    pattern_buf_old, cio->pat_buf_len);
+			} else
+#endif
+			{
+				pattern_buf = malloc(cio->pat_buf_len, M_TEMP,
+				    M_WAITOK);
+				error = copyin(cio->patterns, pattern_buf,
+				    cio->pat_buf_len);
+			}
 			if (error != 0) {
 				error = EINVAL;
 				goto getconfexit;
 			}
 			num_patterns = cio->num_patterns;
-
 		} else if ((cio->num_patterns > 0)
 			|| (cio->pat_buf_len > 0)) {
 			/*
 			 * The user made a mistake, spit out an error.
 			 */
 			cio->status = PCI_GETCONF_ERROR;
-			cio->num_matches = 0;
 			error = EINVAL;
 			break;
-		} else
-			pattern_buf = NULL;
+		}
 
 		/*
 		 * Go through the list of devices and copy out the devices
@@ -303,7 +467,7 @@
 
 			/* Populate pd_name and pd_unit */
 			name = NULL;
-			if (dinfo->cfg.dev && dinfo->conf.pd_name[0] == '\0')
+			if (dinfo->cfg.dev)
 				name = device_get_name(dinfo->cfg.dev);
 			if (name) {
 				strncpy(dinfo->conf.pd_name, name,
@@ -311,12 +475,25 @@
 				dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0;
 				dinfo->conf.pd_unit =
 					device_get_unit(dinfo->cfg.dev);
+			} else {
+				dinfo->conf.pd_name[0] = '\0';
+				dinfo->conf.pd_unit = 0;
 			}
 
-			if ((pattern_buf == NULL) ||
-			    (pci_conf_match(pattern_buf, num_patterns,
-					    &dinfo->conf) == 0)) {
-
+#ifdef PRE7_COMPAT
+			if ((cmd == PCIOCGETCONF_OLD &&
+			    (pattern_buf_old == NULL ||
+			    pci_conf_match_old(pattern_buf_old, num_patterns,
+			    &dinfo->conf) == 0)) ||
+			    (cmd == PCIOCGETCONF &&
+			    (pattern_buf == NULL ||
+			    pci_conf_match(pattern_buf, num_patterns,
+			    &dinfo->conf) == 0))) {
+#else
+			if (pattern_buf == NULL ||
+			    pci_conf_match(pattern_buf, num_patterns,
+			    &dinfo->conf) == 0) {
+#endif
 				/*
 				 * If we've filled up the user's buffer,
 				 * break out at this point.  Since we've
@@ -328,12 +505,46 @@
 				if (cio->num_matches >= ionum)
 					break;
 
-				/* only if can copy it out do we count it */
-				if (!(error = copyout(&dinfo->conf,
-				    &cio->matches[cio->num_matches],
-				    sizeof(struct pci_conf)))) {
+#ifdef PRE7_COMPAT
+				if (cmd == PCIOCGETCONF_OLD) {
+					conf_old.pc_sel.pc_bus =
+					    dinfo->conf.pc_sel.pc_bus;
+					conf_old.pc_sel.pc_dev =
+					    dinfo->conf.pc_sel.pc_dev;
+					conf_old.pc_sel.pc_func =
+					    dinfo->conf.pc_sel.pc_func;
+					conf_old.pc_hdr = dinfo->conf.pc_hdr;
+					conf_old.pc_subvendor =
+					    dinfo->conf.pc_subvendor;
+					conf_old.pc_subdevice =
+					    dinfo->conf.pc_subdevice;
+					conf_old.pc_vendor =
+					    dinfo->conf.pc_vendor;
+					conf_old.pc_device =
+					    dinfo->conf.pc_device;
+					conf_old.pc_class =
+					    dinfo->conf.pc_class;
+					conf_old.pc_subclass =
+					    dinfo->conf.pc_subclass;
+					conf_old.pc_progif =
+					    dinfo->conf.pc_progif;
+					conf_old.pc_revid =
+					    dinfo->conf.pc_revid;
+					strncpy(conf_old.pd_name,
+					    dinfo->conf.pd_name,
+					    sizeof(conf_old.pd_name));
+					conf_old.pd_name[PCI_MAXNAMELEN] = 0;
+					conf_old.pd_unit =
+					    dinfo->conf.pd_unit;
+					confdata = &conf_old;
+				} else
+#endif
+					confdata = &dinfo->conf;
+				/* Only if we can copy it out do we count it. */
+				if (!(error = copyout(confdata,
+				    (caddr_t)cio->matches +
+				    confsz * cio->num_matches, confsz)))
 					cio->num_matches++;
-				}
 			}
 		}
 
@@ -348,7 +559,7 @@
 		 * another ioctl call with offset != 0.
 		 */
 		cio->generation = pci_generation;
-		
+
 		/*
 		 * If this is the last device, inform the user so he won't
 		 * bother asking for more devices.  If dinfo isn't NULL, we
@@ -363,10 +574,27 @@
 getconfexit:
 		if (pattern_buf != NULL)
 			free(pattern_buf, M_TEMP);
+#ifdef PRE7_COMPAT
+		if (pattern_buf_old != NULL)
+			free(pattern_buf_old, M_TEMP);
+#endif
 
 		break;
-		}
 
+#ifdef PRE7_COMPAT
+	case PCIOCREAD_OLD:
+	case PCIOCWRITE_OLD:
+		io_old = (struct pci_io_old *)data;
+		iodata.pi_sel.pc_domain = 0;
+		iodata.pi_sel.pc_bus = io_old->pi_sel.pc_bus;
+		iodata.pi_sel.pc_dev = io_old->pi_sel.pc_dev;
+		iodata.pi_sel.pc_func = io_old->pi_sel.pc_func;
+		iodata.pi_reg = io_old->pi_reg;
+		iodata.pi_width = io_old->pi_width;
+		iodata.pi_data = io_old->pi_data;
+		data = (caddr_t)&iodata;
+		/* FALLTHROUGH */
+#endif
 	case PCIOCREAD:
 	case PCIOCWRITE:
 		io = (struct pci_io *)data;
@@ -374,27 +602,31 @@
 		case 4:
 		case 2:
 		case 1:
-			/* make sure register is in bounds and aligned */
-			if (cmd == PCIOCREAD || cmd == PCIOCWRITE)
-				if (io->pi_reg < 0 ||
-				    io->pi_reg + io->pi_width > PCI_REGMAX ||
-				    io->pi_reg & (io->pi_width - 1))
-					error = EINVAL;
+			/* Make sure register is in bounds and aligned. */
+			if (io->pi_reg < 0 ||
+			    io->pi_reg + io->pi_width > PCI_REGMAX + 1 ||
+			    io->pi_reg & (io->pi_width - 1)) {
+				error = EINVAL;
+				break;
+			}
 			/*
 			 * Assume that the user-level bus number is
 			 * in fact the physical PCI bus number.
 			 * Look up the grandparent, i.e. the bridge device,
 			 * so that we can issue configuration space cycles.
 			 */
-			pcidev = pci_find_bsf(io->pi_sel.pc_bus,
-			    io->pi_sel.pc_dev, io->pi_sel.pc_func);
+			pcidev = pci_find_dbsf(io->pi_sel.pc_domain,
+			    io->pi_sel.pc_bus, io->pi_sel.pc_dev,
+			    io->pi_sel.pc_func);
 			if (pcidev) {
-				device_t busdev, brdev;
-
-				busdev = device_get_parent(pcidev);
-				brdev = device_get_parent(busdev);
+				brdev = device_get_parent(
+				    device_get_parent(pcidev));
 
+#ifdef PRE7_COMPAT
+				if (cmd == PCIOCWRITE || cmd == PCIOCWRITE_OLD)
+#else
 				if (cmd == PCIOCWRITE)
+#endif
 					PCIB_WRITE_CONFIG(brdev,
 							  io->pi_sel.pc_bus,
 							  io->pi_sel.pc_dev,
@@ -402,6 +634,16 @@
 							  io->pi_reg,
 							  io->pi_data,
 							  io->pi_width);
+#ifdef PRE7_COMPAT
+				else if (cmd == PCIOCREAD_OLD)
+					io_old->pi_data =
+						PCIB_READ_CONFIG(brdev,
+							  io->pi_sel.pc_bus,
+							  io->pi_sel.pc_dev,
+							  io->pi_sel.pc_func,
+							  io->pi_reg,
+							  io->pi_width);
+#endif
 				else
 					io->pi_data =
 						PCIB_READ_CONFIG(brdev,
@@ -413,8 +655,8 @@
 				error = 0;
 			} else {
 #ifdef COMPAT_FREEBSD4
-				if (cmd == PCIOCREAD) {
-					io->pi_data = -1;
+				if (cmd == PCIOCREAD_OLD) {
+					io_old->pi_data = -1;
 					error = 0;
 				} else
 #endif
Index: isa_pci.c
===================================================================
RCS file: /home/cvs/src/sys/dev/pci/isa_pci.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/pci/isa_pci.c -L sys/dev/pci/isa_pci.c -u -r1.1.1.1 -r1.2
--- sys/dev/pci/isa_pci.c
+++ sys/dev/pci/isa_pci.c
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/pci/isa_pci.c,v 1.12.8.1 2005/10/06 20:21:03 jhb Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/pci/isa_pci.c,v 1.13 2005/09/29 15:00:09 jhb Exp $");
 
 /*
  * PCI:ISA bridge support
Index: pci_if.m
===================================================================
RCS file: /home/cvs/src/sys/dev/pci/pci_if.m,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/pci/pci_if.m -L sys/dev/pci/pci_if.m -u -r1.1.1.1 -r1.2
--- sys/dev/pci/pci_if.m
+++ sys/dev/pci/pci_if.m
@@ -23,13 +23,22 @@
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-# $FreeBSD: src/sys/dev/pci/pci_if.m,v 1.7 2005/01/06 01:43:05 imp Exp $
+# $FreeBSD: src/sys/dev/pci/pci_if.m,v 1.12 2007/05/02 17:50:35 jhb Exp $
 #
 
 #include <sys/bus.h>
 
 INTERFACE pci;
 
+CODE {
+	static int
+	null_msi_count(device_t dev, device_t child)
+	{
+		return (0);
+	}
+};
+
+
 METHOD u_int32_t read_config {
 	device_t	dev;
 	device_t	child;
@@ -56,6 +65,19 @@
 	int		state;
 };
 
+METHOD int get_vpd_ident {
+	device_t	dev;
+	device_t	child;
+	const char	**identptr;
+};
+
+METHOD int get_vpd_readonly {
+	device_t	dev;
+	device_t	child;
+	const char	*kw;
+	const char	**vptr;
+};
+
 METHOD int enable_busmaster {
 	device_t	dev;
 	device_t	child;
@@ -82,3 +104,44 @@
 	device_t	dev;
 	device_t	child;
 };
+
+METHOD int find_extcap {
+	device_t	dev;
+	device_t	child;
+	int		capability;
+	int		*capreg;
+};
+
+METHOD int alloc_msi {
+	device_t	dev;
+	device_t	child;
+	int		*count;
+};
+
+METHOD int alloc_msix {
+	device_t	dev;
+	device_t	child;
+	int		*count;
+};
+
+METHOD int remap_msix {
+	device_t	dev;
+	device_t	child;
+	int		count;
+	const u_int	*vectors;
+};
+
+METHOD int release_msi {
+	device_t	dev;
+	device_t	child;
+};
+
+METHOD int msi_count {
+	device_t	dev;
+	device_t	child;
+} DEFAULT null_msi_count;
+
+METHOD int msix_count {
+	device_t	dev;
+	device_t	child;
+} DEFAULT null_msi_count;
--- /dev/null
+++ sys/dev/pci/hostb_pci.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 1997, Stefan Esser <se at 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/pci/hostb_pci.c,v 1.1 2005/12/20 21:09:44 jhb Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/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);
Index: pci_private.h
===================================================================
RCS file: /home/cvs/src/sys/dev/pci/pci_private.h,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -L sys/dev/pci/pci_private.h -L sys/dev/pci/pci_private.h -u -r1.1.1.2 -r1.2
--- sys/dev/pci/pci_private.h
+++ sys/dev/pci/pci_private.h
@@ -25,21 +25,21 @@
  * (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/dev/pci/pci_private.h,v 1.14.2.1 2006/01/30 18:38:08 imp Exp $
+ * $FreeBSD: src/sys/dev/pci/pci_private.h,v 1.25 2007/09/30 11:05:15 marius Exp $
  *
  */
 
 #ifndef _PCI_PRIVATE_H_
-#define _PCI_PRIVATE_H_
+#define	_PCI_PRIVATE_H_
 
 /*
  * Export definitions of the pci bus so that we can more easily share
- * it with "subclass" busses.  A more generic subclassing mechanism would
- * be nice, but is not present in the tree at this time.
+ * it with "subclass" busses.
  */
-extern devclass_t pci_devclass;
+DECLARE_CLASS(pci_driver);
 
-void		pci_add_children(device_t dev, int busno, size_t dinfo_size);
+void		pci_add_children(device_t dev, int domain, int busno,
+		    size_t dinfo_size);
 void		pci_add_child(device_t bus, struct pci_devinfo *dinfo);
 void		pci_add_resources(device_t bus, device_t dev, int force,
 		    uint32_t prefetchmask);
@@ -50,6 +50,15 @@
 		    uintptr_t *result);
 int		pci_write_ivar(device_t dev, device_t child, int which,
 		    uintptr_t value);
+int		pci_setup_intr(device_t dev, device_t child,
+		    struct resource *irq, int flags, driver_filter_t *filter,
+		    driver_intr_t *intr, void *arg, void **cookiep);
+int		pci_teardown_intr(device_t dev, device_t child,
+		    struct resource *irq, void *cookie);
+int		pci_get_vpd_ident_method(device_t dev, device_t child,
+		    const char **identptr);
+int		pci_get_vpd_readonly_method(device_t dev, device_t child,
+		    const char *kw, const char **vptr);
 int		pci_set_powerstate_method(device_t dev, device_t child,
 		    int state);
 int		pci_get_powerstate_method(device_t dev, device_t child);
@@ -61,13 +70,22 @@
 int		pci_disable_busmaster_method(device_t dev, device_t child);
 int		pci_enable_io_method(device_t dev, device_t child, int space);
 int		pci_disable_io_method(device_t dev, device_t child, int space);
+int		pci_find_extcap_method(device_t dev, device_t child,
+		    int capability, int *capreg);
+int		pci_alloc_msi_method(device_t dev, device_t child, int *count);
+int		pci_alloc_msix_method(device_t dev, device_t child, int *count);
+int		pci_remap_msix_method(device_t dev, device_t child,
+		    int count, const u_int *vectors);
+int		pci_release_msi_method(device_t dev, device_t child);
+int		pci_msi_count_method(device_t dev, device_t child);
+int		pci_msix_count_method(device_t dev, device_t child);
 struct resource	*pci_alloc_resource(device_t dev, device_t child, 
 		    int type, int *rid, u_long start, u_long end, u_long count,
 		    u_int flags);
 void		pci_delete_resource(device_t dev, device_t child, 
 		    int type, int rid);
 struct resource_list *pci_get_resource_list (device_t dev, device_t child);
-struct pci_devinfo *pci_read_device(device_t pcib, int b, int s, int f,
+struct pci_devinfo *pci_read_device(device_t pcib, int d, int b, int s, int f,
 		    size_t size);
 void		pci_print_verbose(struct pci_devinfo *dinfo);
 int		pci_freecfg(struct pci_devinfo *dinfo);
@@ -78,6 +96,17 @@
 int		pci_assign_interrupt_method(device_t dev, device_t child);
 int		pci_resume(device_t dev);
 int		pci_suspend(device_t dev);
+
+/** Restore the config register state.  The state must be previously
+ * saved with pci_cfg_save.  However, the pci bus driver takes care of
+ * that.  This function will also return the device to PCI_POWERSTATE_D0
+ * if it is currently in a lower power mode.
+ */
 void		pci_cfg_restore(device_t, struct pci_devinfo *);
+
+/** Save the config register state.  Optionally set the power state to D3
+ * if the third argument is non-zero.
+ */
 void		pci_cfg_save(device_t, struct pci_devinfo *, int);
+
 #endif /* _PCI_PRIVATE_H_ */
Index: pcib_if.m
===================================================================
RCS file: /home/cvs/src/sys/dev/pci/pcib_if.m,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/pci/pcib_if.m -L sys/dev/pci/pcib_if.m -u -r1.1.1.1 -r1.2
--- sys/dev/pci/pcib_if.m
+++ sys/dev/pci/pcib_if.m
@@ -23,7 +23,7 @@
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-# $FreeBSD: src/sys/dev/pci/pcib_if.m,v 1.7 2005/04/13 19:10:27 imp Exp $
+# $FreeBSD: src/sys/dev/pci/pcib_if.m,v 1.11 2007/05/02 17:50:35 jhb Exp $
 #
 
 #include <sys/bus.h>
@@ -84,7 +84,63 @@
 # a device's interrupt register.
 #
 METHOD int route_interrupt {
-	device_t pcib;
-	device_t dev;
-	int pin;
+	device_t	pcib;
+	device_t	dev;
+	int		pin;
 } DEFAULT null_route_interrupt;
+
+#
+# Allocate 'count' MSI messsages mapped onto 'count' IRQs.  'irq' points
+# to an array of at least 'count' ints.  The max number of messages this
+# device supports is included so that the MD code can take that into
+# account when assigning resources so that the proper number of low bits
+# are clear in the resulting message data value.
+#
+METHOD int alloc_msi {
+	device_t	pcib;
+	device_t	dev;
+	int		count;
+	int		maxcount;
+	int		*irqs;
+};
+
+#
+# Release 'count' MSI messages mapped onto 'count' IRQs stored in the
+# array pointed to by 'irqs'.
+#
+METHOD int release_msi {
+	device_t	pcib;
+	device_t	dev;
+	int		count;
+	int		*irqs;
+};
+
+#
+# Allocate a single MSI-X message mapped onto '*irq'.
+#
+METHOD int alloc_msix {
+	device_t	pcib;
+	device_t	dev;
+	int		*irq;
+};
+
+#
+# Release a single MSI-X message mapped onto 'irq'.
+#
+METHOD int release_msix {
+	device_t	pcib;
+	device_t	dev;
+	int		irq;
+};
+
+#
+# Determine the MSI/MSI-X message address and data for 'irq'.  The address
+# is returned in '*addr', and the data in '*data'.
+#
+METHOD int map_msi {
+	device_t	pcib;
+	device_t	dev;
+	int		irq;
+	uint64_t	*addr;
+	uint32_t	*data;
+};
Index: pcib_private.h
===================================================================
RCS file: /home/cvs/src/sys/dev/pci/pcib_private.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/pci/pcib_private.h -L sys/dev/pci/pcib_private.h -u -r1.1.1.1 -r1.2
--- sys/dev/pci/pcib_private.h
+++ sys/dev/pci/pcib_private.h
@@ -27,7 +27,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/dev/pci/pcib_private.h,v 1.6 2004/01/11 06:52:31 imp Exp $
+ * $FreeBSD: src/sys/dev/pci/pcib_private.h,v 1.13 2007/09/30 11:05:15 marius Exp $
  */
 
 #ifndef __PCIB_PRIVATE_H__
@@ -45,8 +45,10 @@
 {
     device_t	dev;
     uint32_t	flags;		/* flags */
-#define PCIB_SUBTRACTIVE	0x1
+#define	PCIB_SUBTRACTIVE	0x1
+#define	PCIB_DISABLE_MSI	0x2
     uint16_t	command;	/* command register */
+    uint32_t	domain;		/* domain number */
     uint8_t	secbus;		/* secondary bus number */
     uint8_t	subbus;		/* subordinate bus number */
     pci_addr_t	pmembase;	/* base address of prefetchable memory */
@@ -74,7 +76,10 @@
 uint32_t	pcib_read_config(device_t dev, int b, int s, int f, int reg, int width);
 void		pcib_write_config(device_t dev, int b, int s, int f, int reg, uint32_t val, int width);
 int		pcib_route_interrupt(device_t pcib, device_t dev, int pin);
-
-extern devclass_t pcib_devclass;
+int		pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs);
+int		pcib_release_msi(device_t pcib, device_t dev, int count, int *irqs);
+int		pcib_alloc_msix(device_t pcib, device_t dev, int *irq);
+int		pcib_release_msix(device_t pcib, device_t dev, int irq);
+int		pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, uint32_t *data);
 
 #endif
Index: pci_pci.c
===================================================================
RCS file: /home/cvs/src/sys/dev/pci/pci_pci.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/dev/pci/pci_pci.c -L sys/dev/pci/pci_pci.c -u -r1.2 -r1.3
--- sys/dev/pci/pci_pci.c
+++ sys/dev/pci/pci_pci.c
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/pci/pci_pci.c,v 1.37.2.1 2006/05/22 23:38:08 jkim Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/pci/pci_pci.c,v 1.50 2007/09/30 11:05:15 marius Exp $");
 
 /*
  * PCI:PCI bridge support.
@@ -79,21 +79,48 @@
     DEVMETHOD(pcib_read_config,		pcib_read_config),
     DEVMETHOD(pcib_write_config,	pcib_write_config),
     DEVMETHOD(pcib_route_interrupt,	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 driver_t pcib_driver = {
-    "pcib",
-    pcib_methods,
-    sizeof(struct pcib_softc),
-};
-
-devclass_t pcib_devclass;
+static devclass_t pcib_devclass;
 
+DEFINE_CLASS_0(pcib, pcib_driver, pcib_methods, sizeof(struct pcib_softc));
 DRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, 0, 0);
 
 /*
+ * Is the prefetch window open (eg, can we allocate memory in it?)
+ */
+static int
+pcib_is_prefetch_open(struct pcib_softc *sc)
+{
+	return (sc->pmembase > 0 && sc->pmembase < sc->pmemlimit);
+}
+
+/*
+ * Is the nonprefetch window open (eg, can we allocate memory in it?)
+ */
+static int
+pcib_is_nonprefetch_open(struct pcib_softc *sc)
+{
+	return (sc->membase > 0 && sc->membase < sc->memlimit);
+}
+
+/*
+ * Is the io window open (eg, can we allocate ports in it?)
+ */
+static int
+pcib_is_io_open(struct pcib_softc *sc)
+{
+	return (sc->iobase > 0 && sc->iobase < sc->iolimit);
+}
+
+/*
  * Generic device interface
  */
 static int
@@ -120,6 +147,7 @@
      * Get current bridge configuration.
      */
     sc->command   = pci_read_config(dev, PCIR_COMMAND, 1);
+    sc->domain    = pci_get_domain(dev);
     sc->secbus    = pci_read_config(dev, PCIR_SECBUS_1, 1);
     sc->subbus    = pci_read_config(dev, PCIR_SUBBUS_1, 1);
     sc->secstat   = pci_read_config(dev, PCIR_SECSTAT_1, 2);
@@ -153,10 +181,10 @@
     if (sc->command & PCIM_CMD_MEMEN) {
 	sc->membase   = PCI_PPBMEMBASE(0, pci_read_config(dev, PCIR_MEMBASE_1, 2));
 	sc->memlimit  = PCI_PPBMEMLIMIT(0, pci_read_config(dev, PCIR_MEMLIMIT_1, 2));
-	sc->pmembase  = PCI_PPBMEMBASE((pci_addr_t)pci_read_config(dev, PCIR_PMBASEH_1, 4),
-				       pci_read_config(dev, PCIR_PMBASEL_1, 2));
-	sc->pmemlimit = PCI_PPBMEMLIMIT((pci_addr_t)pci_read_config(dev, PCIR_PMLIMITH_1, 4),
-					pci_read_config(dev, PCIR_PMLIMITL_1, 2));
+	sc->pmembase  = PCI_PPBMEMBASE(pci_read_config(dev, PCIR_PMBASEH_1, 4),
+	    pci_read_config(dev, PCIR_PMBASEL_1, 2));
+	sc->pmemlimit = PCI_PPBMEMLIMIT(pci_read_config(dev, PCIR_PMLIMITH_1, 4),
+	    pci_read_config(dev, PCIR_PMLIMITL_1, 2));
     }
 
     /*
@@ -214,6 +242,9 @@
 	}
     }
 
+    if (pci_msi_device_blacklisted(dev))
+	sc->flags |= PCIB_DISABLE_MSI;
+
     /*
      * Intel 815, 845 and other chipsets say they are PCI-PCI bridges,
      * but have a ProgIF of 0x80.  The 82801 family (AA, AB, BAM/CAM,
@@ -223,15 +254,22 @@
      * parts as subtractive.
      */
     if ((pci_get_devid(dev) & 0xff00ffff) == 0x24008086 ||
-      pci_read_config(dev, PCIR_PROGIF, 1) == 1)
+      pci_read_config(dev, PCIR_PROGIF, 1) == PCIP_BRIDGE_PCI_SUBTRACTIVE)
 	sc->flags |= PCIB_SUBTRACTIVE;
 	
     if (bootverbose) {
+	device_printf(dev, "  domain            %d\n", sc->domain);
 	device_printf(dev, "  secondary bus     %d\n", sc->secbus);
 	device_printf(dev, "  subordinate bus   %d\n", sc->subbus);
 	device_printf(dev, "  I/O decode        0x%x-0x%x\n", sc->iobase, sc->iolimit);
-	device_printf(dev, "  memory decode     0x%x-0x%x\n", sc->membase, sc->memlimit);
-	device_printf(dev, "  prefetched decode 0x%x-0x%x\n", sc->pmembase, sc->pmemlimit);
+	if (pcib_is_nonprefetch_open(sc))
+	    device_printf(dev, "  memory decode     0x%jx-0x%jx\n",
+	      (uintmax_t)sc->membase, (uintmax_t)sc->memlimit);
+	if (pcib_is_prefetch_open(sc))
+	    device_printf(dev, "  prefetched decode 0x%jx-0x%jx\n",
+	      (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit);
+	else
+	    device_printf(dev, "  no prefetched decode\n");
 	if (sc->flags & PCIB_SUBTRACTIVE)
 	    device_printf(dev, "  Subtractively decoded bridge.\n");
     }
@@ -273,6 +311,9 @@
     struct pcib_softc	*sc = device_get_softc(dev);
     
     switch (which) {
+    case PCIB_IVAR_DOMAIN:
+	*result = sc->domain;
+	return(0);
     case PCIB_IVAR_BUS:
 	*result = sc->secbus;
 	return(0);
@@ -286,41 +327,16 @@
     struct pcib_softc	*sc = device_get_softc(dev);
 
     switch (which) {
+    case PCIB_IVAR_DOMAIN:
+	return(EINVAL);
     case PCIB_IVAR_BUS:
 	sc->secbus = value;
-	break;
+	return(0);
     }
     return(ENOENT);
 }
 
 /*
- * Is the prefetch window open (eg, can we allocate memory in it?)
- */
-static int
-pcib_is_prefetch_open(struct pcib_softc *sc)
-{
-	return (sc->pmembase > 0 && sc->pmembase < sc->pmemlimit);
-}
-
-/*
- * Is the nonprefetch window open (eg, can we allocate memory in it?)
- */
-static int
-pcib_is_nonprefetch_open(struct pcib_softc *sc)
-{
-	return (sc->membase > 0 && sc->membase < sc->memlimit);
-}
-
-/*
- * Is the io window open (eg, can we allocate ports in it?)
- */
-static int
-pcib_is_io_open(struct pcib_softc *sc)
-{
-	return (sc->iobase > 0 && sc->iobase < sc->iolimit);
-}
-
-/*
  * We have to trap resource allocation requests and ensure that the bridge
  * is set up to, or capable of handling them.
  */
@@ -329,11 +345,18 @@
     u_long start, u_long end, u_long count, u_int flags)
 {
 	struct pcib_softc	*sc = device_get_softc(dev);
+	const char *name, *suffix;
 	int ok;
 
 	/*
 	 * Fail the allocation for this range if it's not supported.
 	 */
+	name = device_get_nameunit(child);
+	if (name == NULL) {
+		name = "";
+		suffix = "";
+	} else
+		suffix = " ";
 	switch (type) {
 	case SYS_RES_IOPORT:
 		ok = 0;
@@ -374,16 +397,15 @@
 			ok = 0;
 		}
 		if (!ok) {
-			device_printf(dev, "%s requested unsupported I/O "
+			device_printf(dev, "%s%srequested unsupported I/O "
 			    "range 0x%lx-0x%lx (decoding 0x%x-0x%x)\n",
-			    device_get_nameunit(child), start, end,
-			    sc->iobase, sc->iolimit);
+			    name, suffix, start, end, sc->iobase, sc->iolimit);
 			return (NULL);
 		}
 		if (bootverbose)
 			device_printf(dev,
-			    "%s requested I/O range 0x%lx-0x%lx: in range\n",
-			    device_get_nameunit(child), start, end);
+			    "%s%srequested I/O range 0x%lx-0x%lx: in range\n",
+			    name, suffix, start, end);
 		break;
 
 	case SYS_RES_MEMORY:
@@ -449,17 +471,17 @@
 		}
 		if (!ok && bootverbose)
 			device_printf(dev,
-			    "%s requested unsupported memory range "
-			    "0x%lx-0x%lx (decoding 0x%x-0x%x, 0x%x-0x%x)\n",
-			    device_get_nameunit(child), start, end,
-			    sc->membase, sc->memlimit, sc->pmembase,
-			    sc->pmemlimit);
+			    "%s%srequested unsupported memory range %#lx-%#lx "
+			    "(decoding %#jx-%#jx, %#jx-%#jx)\n",
+			    name, suffix, start, end,
+			    (uintmax_t)sc->membase, (uintmax_t)sc->memlimit,
+			    (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit);
 		if (!ok)
 			return (NULL);
 		if (bootverbose)
-			device_printf(dev,"%s requested memory range "
+			device_printf(dev,"%s%srequested memory range "
 			    "0x%lx-0x%lx: good\n",
-			    device_get_nameunit(child), start, end);
+			    name, suffix, start, end);
 		break;
 
 	default:
@@ -532,6 +554,64 @@
     return(intnum);
 }
 
+/* Pass request to alloc MSI/MSI-X messages up to the parent bridge. */
+int
+pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs)
+{
+	struct pcib_softc *sc = device_get_softc(pcib);
+	device_t bus;
+
+	if (sc->flags & PCIB_DISABLE_MSI)
+		return (ENXIO);
+	bus = device_get_parent(pcib);
+	return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount,
+	    irqs));
+}
+
+/* Pass request to release MSI/MSI-X messages up to the parent bridge. */
+int
+pcib_release_msi(device_t pcib, device_t dev, int count, int *irqs)
+{
+	device_t bus;
+
+	bus = device_get_parent(pcib);
+	return (PCIB_RELEASE_MSI(device_get_parent(bus), dev, count, irqs));
+}
+
+/* Pass request to alloc an MSI-X message up to the parent bridge. */
+int
+pcib_alloc_msix(device_t pcib, device_t dev, int *irq)
+{
+	struct pcib_softc *sc = device_get_softc(pcib);
+	device_t bus;
+
+	if (sc->flags & PCIB_DISABLE_MSI)
+		return (ENXIO);
+	bus = device_get_parent(pcib);
+	return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq));
+}
+
+/* Pass request to release an MSI-X message up to the parent bridge. */
+int
+pcib_release_msix(device_t pcib, device_t dev, int irq)
+{
+	device_t bus;
+
+	bus = device_get_parent(pcib);
+	return (PCIB_RELEASE_MSIX(device_get_parent(bus), dev, irq));
+}
+
+/* Pass request to map MSI/MSI-X message up to parent bridge. */
+int
+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));
+}
+
 /*
  * Try to read the bus number of a host-PCI bridge using appropriate config
  * registers.
Index: pcireg.h
===================================================================
RCS file: /home/cvs/src/sys/dev/pci/pcireg.h,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -L sys/dev/pci/pcireg.h -L sys/dev/pci/pcireg.h -u -r1.1.1.2 -r1.2
--- sys/dev/pci/pcireg.h
+++ sys/dev/pci/pcireg.h
@@ -23,7 +23,7 @@
  * (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/dev/pci/pcireg.h,v 1.45.2.1 2006/01/29 21:03:46 imp Exp $
+ * $FreeBSD: src/sys/dev/pci/pcireg.h,v 1.64 2007/09/19 13:05:58 sepotvin Exp $
  *
  */
 
@@ -40,53 +40,53 @@
 
 /* some PCI bus constants */
 
-#define PCI_BUSMAX	255
-#define PCI_SLOTMAX	31
-#define PCI_FUNCMAX	7
-#define PCI_REGMAX	255
-#define PCI_MAXHDRTYPE	2
+#define	PCI_BUSMAX	255
+#define	PCI_SLOTMAX	31
+#define	PCI_FUNCMAX	7
+#define	PCI_REGMAX	255
+#define	PCI_MAXHDRTYPE	2
 
 /* PCI config header registers for all devices */
 
-#define PCIR_DEVVENDOR	0x00
-#define PCIR_VENDOR	0x00
-#define PCIR_DEVICE	0x02
-#define PCIR_COMMAND	0x04
-#define PCIM_CMD_PORTEN		0x0001
-#define PCIM_CMD_MEMEN		0x0002
-#define PCIM_CMD_BUSMASTEREN	0x0004
-#define PCIM_CMD_SPECIALEN	0x0008
-#define PCIM_CMD_MWRICEN	0x0010
-#define PCIM_CMD_PERRESPEN	0x0040
-#define PCIM_CMD_SERRESPEN	0x0100
-#define PCIM_CMD_BACKTOBACK	0x0200
-#define PCIR_STATUS	0x06
-#define PCIM_STATUS_CAPPRESENT	0x0010
-#define PCIM_STATUS_66CAPABLE	0x0020
-#define PCIM_STATUS_BACKTOBACK	0x0080
-#define PCIM_STATUS_PERRREPORT	0x0100
-#define PCIM_STATUS_SEL_FAST	0x0000
-#define PCIM_STATUS_SEL_MEDIMUM	0x0200
-#define PCIM_STATUS_SEL_SLOW	0x0400
-#define PCIM_STATUS_SEL_MASK	0x0600
-#define PCIM_STATUS_STABORT	0x0800
-#define PCIM_STATUS_RTABORT	0x1000
-#define PCIM_STATUS_RMABORT	0x2000
-#define PCIM_STATUS_SERR	0x4000
-#define PCIM_STATUS_PERR	0x8000
-#define PCIR_REVID	0x08
-#define PCIR_PROGIF	0x09
-#define PCIR_SUBCLASS	0x0a
-#define PCIR_CLASS	0x0b
-#define PCIR_CACHELNSZ	0x0c
-#define PCIR_LATTIMER	0x0d
-#define PCIR_HDRTYPE	0x0e
-#define PCIM_HDRTYPE		0x7f
-#define PCIM_HDRTYPE_NORMAL	0x00
-#define PCIM_HDRTYPE_BRIDGE	0x01
-#define PCIM_HDRTYPE_CARDBUS	0x02
-#define PCIM_MFDEV		0x80
-#define PCIR_BIST	0x0f
+#define	PCIR_DEVVENDOR	0x00
+#define	PCIR_VENDOR	0x00
+#define	PCIR_DEVICE	0x02
+#define	PCIR_COMMAND	0x04
+#define	PCIM_CMD_PORTEN		0x0001
+#define	PCIM_CMD_MEMEN		0x0002
+#define	PCIM_CMD_BUSMASTEREN	0x0004
+#define	PCIM_CMD_SPECIALEN	0x0008
+#define	PCIM_CMD_MWRICEN	0x0010
+#define	PCIM_CMD_PERRESPEN	0x0040
+#define	PCIM_CMD_SERRESPEN	0x0100
+#define	PCIM_CMD_BACKTOBACK	0x0200
+#define	PCIR_STATUS	0x06
+#define	PCIM_STATUS_CAPPRESENT	0x0010
+#define	PCIM_STATUS_66CAPABLE	0x0020
+#define	PCIM_STATUS_BACKTOBACK	0x0080
+#define	PCIM_STATUS_PERRREPORT	0x0100
+#define	PCIM_STATUS_SEL_FAST	0x0000
+#define	PCIM_STATUS_SEL_MEDIMUM	0x0200
+#define	PCIM_STATUS_SEL_SLOW	0x0400
+#define	PCIM_STATUS_SEL_MASK	0x0600
+#define	PCIM_STATUS_STABORT	0x0800
+#define	PCIM_STATUS_RTABORT	0x1000
+#define	PCIM_STATUS_RMABORT	0x2000
+#define	PCIM_STATUS_SERR	0x4000
+#define	PCIM_STATUS_PERR	0x8000
+#define	PCIR_REVID	0x08
+#define	PCIR_PROGIF	0x09
+#define	PCIR_SUBCLASS	0x0a
+#define	PCIR_CLASS	0x0b
+#define	PCIR_CACHELNSZ	0x0c
+#define	PCIR_LATTIMER	0x0d
+#define	PCIR_HDRTYPE	0x0e
+#define	PCIM_HDRTYPE		0x7f
+#define	PCIM_HDRTYPE_NORMAL	0x00
+#define	PCIM_HDRTYPE_BRIDGE	0x01
+#define	PCIM_HDRTYPE_CARDBUS	0x02
+#define	PCIM_MFDEV		0x80
+#define	PCIR_BIST	0x0f
 
 /* Capability Register Offsets */
 
@@ -95,236 +95,287 @@
 
 /* Capability Identification Numbers */
 
-#define PCIY_PMG	0x01	/* PCI Power Management */
-#define PCIY_AGP	0x02	/* AGP */
-#define PCIY_VPD	0x03	/* Vital Product Data */
-#define PCIY_SLOTID	0x04	/* Slot Identification */
-#define PCIY_MSI	0x05	/* Message Signaled Interrupts */
-#define PCIY_CHSWP	0x06	/* CompactPCI Hot Swap */
-#define PCIY_PCIX	0x07	/* PCI-X */
-#define PCIY_HT		0x08	/* HyperTransport */
-#define PCIY_VENDOR	0x09	/* Vendor Unique */
-#define PCIY_DEBUG	0x0a	/* Debug port */
-#define PCIY_CRES	0x0b	/* CompactPCI central resource control */
-#define PCIY_HOTPLUG	0x0c	/* PCI Hot-Plug */
-#define PCIY_AGP8X	0x0e	/* AGP 8x */
-#define PCIY_SECDEV	0x0f	/* Secure Device */
-#define PCIY_EXPRESS	0x10	/* PCI Express */
-#define PCIY_MSIX	0x11	/* MSI-X */
+#define	PCIY_PMG	0x01	/* PCI Power Management */
+#define	PCIY_AGP	0x02	/* AGP */
+#define	PCIY_VPD	0x03	/* Vital Product Data */
+#define	PCIY_SLOTID	0x04	/* Slot Identification */
+#define	PCIY_MSI	0x05	/* Message Signaled Interrupts */
+#define	PCIY_CHSWP	0x06	/* CompactPCI Hot Swap */
+#define	PCIY_PCIX	0x07	/* PCI-X */
+#define	PCIY_HT		0x08	/* HyperTransport */
+#define	PCIY_VENDOR	0x09	/* Vendor Unique */
+#define	PCIY_DEBUG	0x0a	/* Debug port */
+#define	PCIY_CRES	0x0b	/* CompactPCI central resource control */
+#define	PCIY_HOTPLUG	0x0c	/* PCI Hot-Plug */
+#define	PCIY_SUBVENDOR	0x0d	/* PCI-PCI bridge subvendor ID */
+#define	PCIY_AGP8X	0x0e	/* AGP 8x */
+#define	PCIY_SECDEV	0x0f	/* Secure Device */
+#define	PCIY_EXPRESS	0x10	/* PCI Express */
+#define	PCIY_MSIX	0x11	/* MSI-X */
 
 /* config registers for header type 0 devices */
 
-#define PCIR_BARS	0x10
-#define	PCIR_BAR(x)	(PCIR_BARS + (x) * 4)
-#define PCI_RID2BAR(rid) (((rid)-PCIR_BARS)/4)
-#define PCIR_CIS	0x28
-#define PCIM_CIS_ASI_MASK	0x7
-#define PCIM_CIS_ASI_TUPLE	0
-#define PCIM_CIS_ASI_BAR0	1
-#define PCIM_CIS_ASI_BAR1	2
-#define PCIM_CIS_ASI_BAR2	3
-#define PCIM_CIS_ASI_BAR3	4
-#define PCIM_CIS_ASI_BAR4	5
-#define PCIM_CIS_ASI_BAR5	6
-#define PCIM_CIS_ASI_ROM	7
-#define PCIM_CIS_ADDR_MASK	0x0ffffff8
-#define PCIM_CIS_ROM_MASK	0xf0000000
-#define PCIR_SUBVEND_0	0x2c
-#define PCIR_SUBDEV_0	0x2e
-#define PCIR_BIOS	0x30
-#define PCIM_BIOS_ENABLE	0x01
-#define PCIM_BIOS_ADDR_MASK	0xfffff800
+#define	PCIR_BARS	0x10
+#define	PCIR_BAR(x)		(PCIR_BARS + (x) * 4)
+#define	PCI_MAX_BAR_0		5	/* Number of standard bars */
+#define	PCI_RID2BAR(rid)	(((rid) - PCIR_BARS) / 4)
+#define	PCI_BAR_IO(x)		(((x) & PCIM_BAR_SPACE) == PCIM_BAR_IO_SPACE)
+#define	PCI_BAR_MEM(x)		(((x) & PCIM_BAR_SPACE) == PCIM_BAR_MEM_SPACE)
+#define	PCIM_BAR_SPACE		0x00000001
+#define	PCIM_BAR_MEM_SPACE	0
+#define	PCIM_BAR_IO_SPACE	1
+#define	PCIM_BAR_MEM_TYPE	0x00000006
+#define	PCIM_BAR_MEM_32		0
+#define	PCIM_BAR_MEM_1MB	2	/* Locate below 1MB in PCI <= 2.1 */
+#define	PCIM_BAR_MEM_64		4
+#define	PCIM_BAR_MEM_PREFETCH	0x00000008
+#define	PCIM_BAR_MEM_BASE	0xfffffff0
+#define	PCIM_BAR_IO_RESERVED	0x00000002
+#define	PCIM_BAR_IO_BASE	0xfffffffc
+#define	PCIR_CIS	0x28
+#define	PCIM_CIS_ASI_MASK	0x7
+#define	PCIM_CIS_ASI_CONFIG	0
+#define	PCIM_CIS_ASI_BAR0	1
+#define	PCIM_CIS_ASI_BAR1	2
+#define	PCIM_CIS_ASI_BAR2	3
+#define	PCIM_CIS_ASI_BAR3	4
+#define	PCIM_CIS_ASI_BAR4	5
+#define	PCIM_CIS_ASI_BAR5	6
+#define	PCIM_CIS_ASI_ROM	7
+#define	PCIM_CIS_ADDR_MASK	0x0ffffff8
+#define	PCIM_CIS_ROM_MASK	0xf0000000
+#define PCIM_CIS_CONFIG_MASK	0xff
+#define	PCIR_SUBVEND_0	0x2c
+#define	PCIR_SUBDEV_0	0x2e
+#define	PCIR_BIOS	0x30
+#define	PCIM_BIOS_ENABLE	0x01
+#define	PCIM_BIOS_ADDR_MASK	0xfffff800
 #define	PCIR_CAP_PTR	0x34
-#define PCIR_INTLINE	0x3c
-#define PCIR_INTPIN	0x3d
-#define PCIR_MINGNT	0x3e
-#define PCIR_MAXLAT	0x3f
+#define	PCIR_INTLINE	0x3c
+#define	PCIR_INTPIN	0x3d
+#define	PCIR_MINGNT	0x3e
+#define	PCIR_MAXLAT	0x3f
 
 /* config registers for header type 1 (PCI-to-PCI bridge) devices */
 
-#define PCIR_SECSTAT_1	0x1e
+#define	PCIR_SECSTAT_1	0x1e
 
-#define PCIR_PRIBUS_1	0x18
-#define PCIR_SECBUS_1	0x19
-#define PCIR_SUBBUS_1	0x1a
-#define PCIR_SECLAT_1	0x1b
-
-#define PCIR_IOBASEL_1	0x1c
-#define PCIR_IOLIMITL_1	0x1d
-#define PCIR_IOBASEH_1	0x30
-#define PCIR_IOLIMITH_1	0x32
-#define PCIM_BRIO_16		0x0
-#define PCIM_BRIO_32		0x1
-#define PCIM_BRIO_MASK		0xf
-
-#define PCIR_MEMBASE_1	0x20
-#define PCIR_MEMLIMIT_1	0x22
-
-#define PCIR_PMBASEL_1	0x24
-#define PCIR_PMLIMITL_1	0x26
-#define PCIR_PMBASEH_1	0x28
-#define PCIR_PMLIMITH_1	0x2c
+#define	PCIR_PRIBUS_1	0x18
+#define	PCIR_SECBUS_1	0x19
+#define	PCIR_SUBBUS_1	0x1a
+#define	PCIR_SECLAT_1	0x1b
+
+#define	PCIR_IOBASEL_1	0x1c
+#define	PCIR_IOLIMITL_1	0x1d
+#define	PCIR_IOBASEH_1	0x30
+#define	PCIR_IOLIMITH_1	0x32
+#define	PCIM_BRIO_16		0x0
+#define	PCIM_BRIO_32		0x1
+#define	PCIM_BRIO_MASK		0xf
+
+#define	PCIR_MEMBASE_1	0x20
+#define	PCIR_MEMLIMIT_1	0x22
+
+#define	PCIR_PMBASEL_1	0x24
+#define	PCIR_PMLIMITL_1	0x26
+#define	PCIR_PMBASEH_1	0x28
+#define	PCIR_PMLIMITH_1	0x2c
 
-#define PCIR_BRIDGECTL_1 0x3e
-
-#define PCIR_SUBVEND_1	0x34
-#define PCIR_SUBDEV_1	0x36
+#define	PCIR_BRIDGECTL_1 0x3e
 
 /* config registers for header type 2 (CardBus) devices */
 
 #define	PCIR_CAP_PTR_2	0x14
-#define PCIR_SECSTAT_2	0x16
+#define	PCIR_SECSTAT_2	0x16
 
-#define PCIR_PRIBUS_2	0x18
-#define PCIR_SECBUS_2	0x19
-#define PCIR_SUBBUS_2	0x1a
-#define PCIR_SECLAT_2	0x1b
-
-#define PCIR_MEMBASE0_2	0x1c
-#define PCIR_MEMLIMIT0_2 0x20
-#define PCIR_MEMBASE1_2	0x24
-#define PCIR_MEMLIMIT1_2 0x28
-#define PCIR_IOBASE0_2	0x2c
-#define PCIR_IOLIMIT0_2	0x30
-#define PCIR_IOBASE1_2	0x34
-#define PCIR_IOLIMIT1_2	0x38
+#define	PCIR_PRIBUS_2	0x18
+#define	PCIR_SECBUS_2	0x19
+#define	PCIR_SUBBUS_2	0x1a
+#define	PCIR_SECLAT_2	0x1b
+
+#define	PCIR_MEMBASE0_2	0x1c
+#define	PCIR_MEMLIMIT0_2 0x20
+#define	PCIR_MEMBASE1_2	0x24
+#define	PCIR_MEMLIMIT1_2 0x28
+#define	PCIR_IOBASE0_2	0x2c
+#define	PCIR_IOLIMIT0_2	0x30
+#define	PCIR_IOBASE1_2	0x34
+#define	PCIR_IOLIMIT1_2	0x38
 
-#define PCIR_BRIDGECTL_2 0x3e
+#define	PCIR_BRIDGECTL_2 0x3e
 
-#define PCIR_SUBVEND_2	0x40
-#define PCIR_SUBDEV_2	0x42
+#define	PCIR_SUBVEND_2	0x40
+#define	PCIR_SUBDEV_2	0x42
 
-#define PCIR_PCCARDIF_2	0x44
+#define	PCIR_PCCARDIF_2	0x44
 
 /* PCI device class, subclass and programming interface definitions */
 
-#define PCIC_OLD	0x00
-#define PCIS_OLD_NONVGA		0x00
-#define PCIS_OLD_VGA		0x01
-
-#define PCIC_STORAGE	0x01
-#define PCIS_STORAGE_SCSI	0x00
-#define PCIS_STORAGE_IDE	0x01
-#define PCIP_STORAGE_IDE_MODEPRIM	0x01
-#define PCIP_STORAGE_IDE_PROGINDPRIM	0x02
-#define PCIP_STORAGE_IDE_MODESEC	0x04
-#define PCIP_STORAGE_IDE_PROGINDSEC	0x08
-#define PCIP_STORAGE_IDE_MASTERDEV	0x80
-#define PCIS_STORAGE_FLOPPY	0x02
-#define PCIS_STORAGE_IPI	0x03
-#define PCIS_STORAGE_RAID	0x04
-#define PCIS_STORAGE_OTHER	0x80
-
-#define PCIC_NETWORK	0x02
-#define PCIS_NETWORK_ETHERNET	0x00
-#define PCIS_NETWORK_TOKENRING	0x01
-#define PCIS_NETWORK_FDDI	0x02
-#define PCIS_NETWORK_ATM	0x03
-#define PCIS_NETWORK_ISDN	0x04
-#define PCIS_NETWORK_OTHER	0x80
-
-#define PCIC_DISPLAY	0x03
-#define PCIS_DISPLAY_VGA	0x00
-#define PCIS_DISPLAY_XGA	0x01
-#define PCIS_DISPLAY_3D		0x02
-#define PCIS_DISPLAY_OTHER	0x80
-
-#define PCIC_MULTIMEDIA	0x04
-#define PCIS_MULTIMEDIA_VIDEO	0x00
-#define PCIS_MULTIMEDIA_AUDIO	0x01
-#define PCIS_MULTIMEDIA_TELE	0x02
-#define PCIS_MULTIMEDIA_OTHER	0x80
-
-#define PCIC_MEMORY	0x05
-#define PCIS_MEMORY_RAM		0x00
-#define PCIS_MEMORY_FLASH	0x01
-#define PCIS_MEMORY_OTHER	0x80
-
-#define PCIC_BRIDGE	0x06
-#define PCIS_BRIDGE_HOST	0x00
-#define PCIS_BRIDGE_ISA		0x01
-#define PCIS_BRIDGE_EISA	0x02
-#define PCIS_BRIDGE_MCA		0x03
-#define PCIS_BRIDGE_PCI		0x04
-#define PCIS_BRIDGE_PCMCIA	0x05
-#define PCIS_BRIDGE_NUBUS	0x06
-#define PCIS_BRIDGE_CARDBUS	0x07
-#define PCIS_BRIDGE_RACEWAY	0x08
-#define PCIS_BRIDGE_OTHER	0x80
-
-#define PCIC_SIMPLECOMM	0x07
-#define PCIS_SIMPLECOMM_UART	0x00
-#define PCIP_SIMPLECOMM_UART_16550A	0x02
-#define PCIS_SIMPLECOMM_PAR	0x01
-#define PCIS_SIMPLECOMM_MULSER	0x02
-#define PCIS_SIMPLECOMM_MODEM	0x03
-#define PCIS_SIMPLECOMM_OTHER	0x80
-
-#define PCIC_BASEPERIPH	0x08
-#define PCIS_BASEPERIPH_PIC	0x00
-#define PCIS_BASEPERIPH_DMA	0x01
-#define PCIS_BASEPERIPH_TIMER	0x02
-#define PCIS_BASEPERIPH_RTC	0x03
-#define PCIS_BASEPERIPH_PCIHOT	0x04
-#define PCIS_BASEPERIPH_OTHER	0x80
-
-#define PCIC_INPUTDEV	0x09
-#define PCIS_INPUTDEV_KEYBOARD	0x00
-#define PCIS_INPUTDEV_DIGITIZER	0x01
-#define PCIS_INPUTDEV_MOUSE	0x02
-#define PCIS_INPUTDEV_SCANNER	0x03
-#define PCIS_INPUTDEV_GAMEPORT	0x04
-#define PCIS_INPUTDEV_OTHER	0x80
-
-#define PCIC_DOCKING	0x0a
-#define PCIS_DOCKING_GENERIC	0x00
-#define PCIS_DOCKING_OTHER	0x80
-
-#define PCIC_PROCESSOR	0x0b
-#define PCIS_PROCESSOR_386	0x00
-#define PCIS_PROCESSOR_486	0x01
-#define PCIS_PROCESSOR_PENTIUM	0x02
-#define PCIS_PROCESSOR_ALPHA	0x10
-#define PCIS_PROCESSOR_POWERPC	0x20
-#define PCIS_PROCESSOR_MIPS	0x30
-#define PCIS_PROCESSOR_COPROC	0x40
-
-#define PCIC_SERIALBUS	0x0c
-#define PCIS_SERIALBUS_FW	0x00
-#define PCIS_SERIALBUS_ACCESS	0x01
-#define PCIS_SERIALBUS_SSA	0x02
-#define PCIS_SERIALBUS_USB	0x03
-#define PCIP_SERIALBUS_USB_UHCI	0x00
-#define PCIP_SERIALBUS_USB_OHCI	0x10
-#define PCIP_SERIALBUS_USB_EHCI	0x20
-#define PCIS_SERIALBUS_FC	0x04
-#define PCIS_SERIALBUS_SMBUS	0x05
-
-#define PCIC_WIRELESS	0x0d
-#define PCIS_WIRELESS_IRDA	0x00
-#define PCIS_WIRELESS_IR	0x01
-#define PCIS_WIRELESS_RF	0x10
-#define PCIS_WIRELESS_OTHER	0x80
-
-#define PCIC_INTELLIIO	0x0e
-#define PCIS_INTELLIIO_I2O	0x00
-
-#define PCIC_SATCOM	0x0f
-#define PCIS_SATCOM_TV		0x01
-#define PCIS_SATCOM_AUDIO	0x02
-#define PCIS_SATCOM_VOICE	0x03
-#define PCIS_SATCOM_DATA	0x04
-
-#define PCIC_CRYPTO	0x10
-#define PCIS_CRYPTO_NETCOMP	0x00
-#define PCIS_CRYPTO_ENTERTAIN	0x10
-#define PCIS_CRYPTO_OTHER	0x80
-
-#define PCIC_DASP	0x11
-#define PCIS_DASP_DPIO	0x00
-#define PCIS_DASP_OTHER	0x80
+#define	PCIC_OLD	0x00
+#define	PCIS_OLD_NONVGA		0x00
+#define	PCIS_OLD_VGA		0x01
+
+#define	PCIC_STORAGE	0x01
+#define	PCIS_STORAGE_SCSI	0x00
+#define	PCIS_STORAGE_IDE	0x01
+#define	PCIP_STORAGE_IDE_MODEPRIM	0x01
+#define	PCIP_STORAGE_IDE_PROGINDPRIM	0x02
+#define	PCIP_STORAGE_IDE_MODESEC	0x04
+#define	PCIP_STORAGE_IDE_PROGINDSEC	0x08
+#define	PCIP_STORAGE_IDE_MASTERDEV	0x80
+#define	PCIS_STORAGE_FLOPPY	0x02
+#define	PCIS_STORAGE_IPI	0x03
+#define	PCIS_STORAGE_RAID	0x04
+#define	PCIS_STORAGE_ATA_ADMA	0x05
+#define	PCIS_STORAGE_SATA	0x06
+#define	PCIP_STORAGE_SATA_AHCI_1_0	0x01
+#define	PCIS_STORAGE_SAS	0x07
+#define	PCIS_STORAGE_OTHER	0x80
+
+#define	PCIC_NETWORK	0x02
+#define	PCIS_NETWORK_ETHERNET	0x00
+#define	PCIS_NETWORK_TOKENRING	0x01
+#define	PCIS_NETWORK_FDDI	0x02
+#define	PCIS_NETWORK_ATM	0x03
+#define	PCIS_NETWORK_ISDN	0x04
+#define	PCIS_NETWORK_WORLDFIP	0x05
+#define	PCIS_NETWORK_PICMG	0x06
+#define	PCIS_NETWORK_OTHER	0x80
+
+#define	PCIC_DISPLAY	0x03
+#define	PCIS_DISPLAY_VGA	0x00
+#define	PCIS_DISPLAY_XGA	0x01
+#define	PCIS_DISPLAY_3D		0x02
+#define	PCIS_DISPLAY_OTHER	0x80
+
+#define	PCIC_MULTIMEDIA	0x04
+#define	PCIS_MULTIMEDIA_VIDEO	0x00
+#define	PCIS_MULTIMEDIA_AUDIO	0x01
+#define	PCIS_MULTIMEDIA_TELE	0x02
+#define	PCIS_MULTIMEDIA_OTHER	0x80
+
+#define	PCIC_MEMORY	0x05
+#define	PCIS_MEMORY_RAM		0x00
+#define	PCIS_MEMORY_FLASH	0x01
+#define	PCIS_MEMORY_OTHER	0x80
+
+#define	PCIC_BRIDGE	0x06
+#define	PCIS_BRIDGE_HOST	0x00
+#define	PCIS_BRIDGE_ISA		0x01
+#define	PCIS_BRIDGE_EISA	0x02
+#define	PCIS_BRIDGE_MCA		0x03
+#define	PCIS_BRIDGE_PCI		0x04
+#define	PCIP_BRIDGE_PCI_SUBTRACTIVE	0x01
+#define	PCIS_BRIDGE_PCMCIA	0x05
+#define	PCIS_BRIDGE_NUBUS	0x06
+#define	PCIS_BRIDGE_CARDBUS	0x07
+#define	PCIS_BRIDGE_RACEWAY	0x08
+#define	PCIS_BRIDGE_PCI_TRANSPARENT 0x09
+#define	PCIS_BRIDGE_INFINIBAND	0x0a
+#define	PCIS_BRIDGE_OTHER	0x80
+
+#define	PCIC_SIMPLECOMM	0x07
+#define	PCIS_SIMPLECOMM_UART	0x00
+#define	PCIP_SIMPLECOMM_UART_8250	0x00
+#define	PCIP_SIMPLECOMM_UART_16450A	0x01
+#define	PCIP_SIMPLECOMM_UART_16550A	0x02
+#define	PCIP_SIMPLECOMM_UART_16650A	0x03
+#define	PCIP_SIMPLECOMM_UART_16750A	0x04
+#define	PCIP_SIMPLECOMM_UART_16850A	0x05
+#define	PCIP_SIMPLECOMM_UART_16950A	0x06
+#define	PCIS_SIMPLECOMM_PAR	0x01
+#define	PCIS_SIMPLECOMM_MULSER	0x02
+#define	PCIS_SIMPLECOMM_MODEM	0x03
+#define	PCIS_SIMPLECOMM_GPIB	0x04
+#define	PCIS_SIMPLECOMM_SMART_CARD 0x05
+#define	PCIS_SIMPLECOMM_OTHER	0x80
+
+#define	PCIC_BASEPERIPH	0x08
+#define	PCIS_BASEPERIPH_PIC	0x00
+#define	PCIP_BASEPERIPH_PIC_8259A	0x00
+#define	PCIP_BASEPERIPH_PIC_ISA		0x01
+#define	PCIP_BASEPERIPH_PIC_EISA	0x02
+#define	PCIP_BASEPERIPH_PIC_IO_APIC	0x10
+#define	PCIP_BASEPERIPH_PIC_IOX_APIC	0x20
+#define	PCIS_BASEPERIPH_DMA	0x01
+#define	PCIS_BASEPERIPH_TIMER	0x02
+#define	PCIS_BASEPERIPH_RTC	0x03
+#define	PCIS_BASEPERIPH_PCIHOT	0x04
+#define	PCIS_BASEPERIPH_SDHC	0x05
+#define	PCIS_BASEPERIPH_OTHER	0x80
+
+#define	PCIC_INPUTDEV	0x09
+#define	PCIS_INPUTDEV_KEYBOARD	0x00
+#define	PCIS_INPUTDEV_DIGITIZER	0x01
+#define	PCIS_INPUTDEV_MOUSE	0x02
+#define	PCIS_INPUTDEV_SCANNER	0x03
+#define	PCIS_INPUTDEV_GAMEPORT	0x04
+#define	PCIS_INPUTDEV_OTHER	0x80
+
+#define	PCIC_DOCKING	0x0a
+#define	PCIS_DOCKING_GENERIC	0x00
+#define	PCIS_DOCKING_OTHER	0x80
+
+#define	PCIC_PROCESSOR	0x0b
+#define	PCIS_PROCESSOR_386	0x00
+#define	PCIS_PROCESSOR_486	0x01
+#define	PCIS_PROCESSOR_PENTIUM	0x02
+#define	PCIS_PROCESSOR_ALPHA	0x10
+#define	PCIS_PROCESSOR_POWERPC	0x20
+#define	PCIS_PROCESSOR_MIPS	0x30
+#define	PCIS_PROCESSOR_COPROC	0x40
+
+#define	PCIC_SERIALBUS	0x0c
+#define	PCIS_SERIALBUS_FW	0x00
+#define	PCIS_SERIALBUS_ACCESS	0x01
+#define	PCIS_SERIALBUS_SSA	0x02
+#define	PCIS_SERIALBUS_USB	0x03
+#define	PCIP_SERIALBUS_USB_UHCI		0x00
+#define	PCIP_SERIALBUS_USB_OHCI		0x10
+#define	PCIP_SERIALBUS_USB_EHCI		0x20
+#define	PCIP_SERIALBUS_USB_DEVICE	0xfe
+#define	PCIS_SERIALBUS_FC	0x04
+#define	PCIS_SERIALBUS_SMBUS	0x05
+#define	PCIS_SERIALBUS_INFINIBAND 0x06
+#define	PCIS_SERIALBUS_IPMI	0x07
+#define	PCIP_SERIALBUS_IPMI_SMIC	0x00
+#define	PCIP_SERIALBUS_IPMI_KCS		0x01
+#define	PCIP_SERIALBUS_IPMI_BT		0x02
+#define	PCIS_SERIALBUS_SERCOS	0x08
+#define	PCIS_SERIALBUS_CANBUS	0x09
+
+#define	PCIC_WIRELESS	0x0d
+#define	PCIS_WIRELESS_IRDA	0x00
+#define	PCIS_WIRELESS_IR	0x01
+#define	PCIS_WIRELESS_RF	0x10
+#define	PCIS_WIRELESS_BLUETOOTH	0x11
+#define	PCIS_WIRELESS_BROADBAND	0x12
+#define	PCIS_WIRELESS_80211A	0x20
+#define	PCIS_WIRELESS_80211B	0x21
+#define	PCIS_WIRELESS_OTHER	0x80
+
+#define	PCIC_INTELLIIO	0x0e
+#define	PCIS_INTELLIIO_I2O	0x00
+
+#define	PCIC_SATCOM	0x0f
+#define	PCIS_SATCOM_TV		0x01
+#define	PCIS_SATCOM_AUDIO	0x02
+#define	PCIS_SATCOM_VOICE	0x03
+#define	PCIS_SATCOM_DATA	0x04
+
+#define	PCIC_CRYPTO	0x10
+#define	PCIS_CRYPTO_NETCOMP	0x00
+#define	PCIS_CRYPTO_ENTERTAIN	0x10
+#define	PCIS_CRYPTO_OTHER	0x80
+
+#define	PCIC_DASP	0x11
+#define	PCIS_DASP_DPIO		0x00
+#define	PCIS_DASP_PERFCNTRS	0x01
+#define	PCIS_DASP_COMM_SYNC	0x10
+#define	PCIS_DASP_MGMT_CARD	0x20
+#define	PCIS_DASP_OTHER		0x80
 
-#define PCIC_OTHER	0xff
+#define	PCIC_OTHER	0xff
 
 /* Bridge Control Values. */
 #define	PCIB_BCR_PERR_ENABLE		0x0001
@@ -340,92 +391,217 @@
 #define	PCIB_BCR_DISCARD_TIMER_SERREN	0x0800
 
 /* PCI power manangement */
-
-#define PCIR_POWER_CAP		0x2
-#define PCIM_PCAP_SPEC			0x0007
-#define PCIM_PCAP_PMEREQCLK		0x0008
-#define PCIM_PCAP_PMEREQPWR		0x0010
-#define PCIM_PCAP_DEVSPECINIT		0x0020
-#define PCIM_PCAP_DYNCLOCK		0x0040
-#define PCIM_PCAP_SECCLOCK		0x00c0
-#define PCIM_PCAP_CLOCKMASK		0x00c0
-#define PCIM_PCAP_REQFULLCLOCK		0x0100
-#define PCIM_PCAP_D1SUPP		0x0200
-#define PCIM_PCAP_D2SUPP		0x0400
-#define PCIM_PCAP_D0PME			0x1000
-#define PCIM_PCAP_D1PME			0x2000
-#define PCIM_PCAP_D2PME			0x4000
-
-#define PCIR_POWER_STATUS	0x4
-#define PCIM_PSTAT_D0			0x0000
-#define PCIM_PSTAT_D1			0x0001
-#define PCIM_PSTAT_D2			0x0002
-#define PCIM_PSTAT_D3			0x0003
-#define PCIM_PSTAT_DMASK		0x0003
-#define PCIM_PSTAT_REPENABLE		0x0010
-#define PCIM_PSTAT_PMEENABLE		0x0100
-#define PCIM_PSTAT_D0POWER		0x0000
-#define PCIM_PSTAT_D1POWER		0x0200
-#define PCIM_PSTAT_D2POWER		0x0400
-#define PCIM_PSTAT_D3POWER		0x0600
-#define PCIM_PSTAT_D0HEAT		0x0800
-#define PCIM_PSTAT_D1HEAT		0x1000
-#define PCIM_PSTAT_D2HEAT		0x1200
-#define PCIM_PSTAT_D3HEAT		0x1400
-#define PCIM_PSTAT_DATAUNKN		0x0000
-#define PCIM_PSTAT_DATADIV10		0x2000
-#define PCIM_PSTAT_DATADIV100		0x4000
-#define PCIM_PSTAT_DATADIV1000		0x6000
-#define PCIM_PSTAT_DATADIVMASK		0x6000
-#define PCIM_PSTAT_PME			0x8000
-
-#define PCIR_POWER_PMCSR	0x6
-#define PCIM_PMCSR_DCLOCK		0x10
-#define PCIM_PMCSR_B2SUPP		0x20
-#define PCIM_BMCSR_B3SUPP		0x40
-#define PCIM_BMCSR_BPCE			0x80
-
-#define PCIR_POWER_DATA		0x7
+#define	PCIR_POWER_CAP		0x2
+#define	PCIM_PCAP_SPEC			0x0007
+#define	PCIM_PCAP_PMEREQCLK		0x0008
+#define	PCIM_PCAP_PMEREQPWR		0x0010
+#define	PCIM_PCAP_DEVSPECINIT		0x0020
+#define	PCIM_PCAP_DYNCLOCK		0x0040
+#define	PCIM_PCAP_SECCLOCK		0x00c0
+#define	PCIM_PCAP_CLOCKMASK		0x00c0
+#define	PCIM_PCAP_REQFULLCLOCK		0x0100
+#define	PCIM_PCAP_D1SUPP		0x0200
+#define	PCIM_PCAP_D2SUPP		0x0400
+#define	PCIM_PCAP_D0PME			0x0800
+#define	PCIM_PCAP_D1PME			0x1000
+#define	PCIM_PCAP_D2PME			0x2000
+#define	PCIM_PCAP_D3PME_HOT		0x4000
+#define	PCIM_PCAP_D3PME_COLD		0x8000
+
+#define	PCIR_POWER_STATUS	0x4
+#define	PCIM_PSTAT_D0			0x0000
+#define	PCIM_PSTAT_D1			0x0001
+#define	PCIM_PSTAT_D2			0x0002
+#define	PCIM_PSTAT_D3			0x0003
+#define	PCIM_PSTAT_DMASK		0x0003
+#define	PCIM_PSTAT_REPENABLE		0x0010
+#define	PCIM_PSTAT_PMEENABLE		0x0100
+#define	PCIM_PSTAT_D0POWER		0x0000
+#define	PCIM_PSTAT_D1POWER		0x0200
+#define	PCIM_PSTAT_D2POWER		0x0400
+#define	PCIM_PSTAT_D3POWER		0x0600
+#define	PCIM_PSTAT_D0HEAT		0x0800
+#define	PCIM_PSTAT_D1HEAT		0x1000
+#define	PCIM_PSTAT_D2HEAT		0x1200
+#define	PCIM_PSTAT_D3HEAT		0x1400
+#define	PCIM_PSTAT_DATAUNKN		0x0000
+#define	PCIM_PSTAT_DATADIV10		0x2000
+#define	PCIM_PSTAT_DATADIV100		0x4000
+#define	PCIM_PSTAT_DATADIV1000		0x6000
+#define	PCIM_PSTAT_DATADIVMASK		0x6000
+#define	PCIM_PSTAT_PME			0x8000
+
+#define	PCIR_POWER_PMCSR	0x6
+#define	PCIM_PMCSR_DCLOCK		0x10
+#define	PCIM_PMCSR_B2SUPP		0x20
+#define	PCIM_BMCSR_B3SUPP		0x40
+#define	PCIM_BMCSR_BPCE			0x80
+
+#define	PCIR_POWER_DATA		0x7
+
+/* VPD capability registers */
+#define	PCIR_VPD_ADDR		0x2
+#define	PCIR_VPD_DATA		0x4
 
 /* PCI Message Signalled Interrupts (MSI) */
-#define PCIR_MSI_CTRL		0x2
-#define PCIM_MSICTRL_VECTOR		0x0100
-#define PCIM_MSICTRL_64BIT		0x0080
-#define PCIM_MSICTRL_MME_MASK		0x0070
-#define PCIM_MSICTRL_MME_1		0x0000
-#define PCIM_MSICTRL_MME_2		0x0010
-#define PCIM_MSICTRL_MME_4		0x0020
-#define PCIM_MSICTRL_MME_8		0x0030
-#define PCIM_MSICTRL_MME_16		0x0040
-#define PCIM_MSICTRL_MME_32		0x0050
-#define PCIM_MSICTRL_MMC_MASK		0x000E
-#define PCIM_MSICTRL_MMC_1		0x0000
-#define PCIM_MSICTRL_MMC_2		0x0002
-#define PCIM_MSICTRL_MMC_4		0x0004
-#define PCIM_MSICTRL_MMC_8		0x0006
-#define PCIM_MSICTRL_MMC_16		0x0008
-#define PCIM_MSICTRL_MMC_32		0x000A
-#define PCIM_MSICTRL_MSI_ENABLE		0x0001
-#define PCIR_MSI_ADDR		0x4
-#define PCIR_MSI_ADDR_HIGH	0x8
-#define PCIR_MSI_DATA		0x8
-#define PCIR_MSI_DATA_64BIT	0xc
-#define PCIR_MSI_MASK		0x10
-#define PCIR_MSI_PENDING	0x14
+#define	PCIR_MSI_CTRL		0x2
+#define	PCIM_MSICTRL_VECTOR		0x0100
+#define	PCIM_MSICTRL_64BIT		0x0080
+#define	PCIM_MSICTRL_MME_MASK		0x0070
+#define	PCIM_MSICTRL_MME_1		0x0000
+#define	PCIM_MSICTRL_MME_2		0x0010
+#define	PCIM_MSICTRL_MME_4		0x0020
+#define	PCIM_MSICTRL_MME_8		0x0030
+#define	PCIM_MSICTRL_MME_16		0x0040
+#define	PCIM_MSICTRL_MME_32		0x0050
+#define	PCIM_MSICTRL_MMC_MASK		0x000E
+#define	PCIM_MSICTRL_MMC_1		0x0000
+#define	PCIM_MSICTRL_MMC_2		0x0002
+#define	PCIM_MSICTRL_MMC_4		0x0004
+#define	PCIM_MSICTRL_MMC_8		0x0006
+#define	PCIM_MSICTRL_MMC_16		0x0008
+#define	PCIM_MSICTRL_MMC_32		0x000A
+#define	PCIM_MSICTRL_MSI_ENABLE		0x0001
+#define	PCIR_MSI_ADDR		0x4
+#define	PCIR_MSI_ADDR_HIGH	0x8
+#define	PCIR_MSI_DATA		0x8
+#define	PCIR_MSI_DATA_64BIT	0xc
+#define	PCIR_MSI_MASK		0x10
+#define	PCIR_MSI_PENDING	0x14
 
 /* PCI-X definitions */
-#define PCIXR_COMMAND	0x96
-#define PCIXR_DEVADDR	0x98
-#define PCIXM_DEVADDR_FNUM	0x0003	/* Function Number */
-#define PCIXM_DEVADDR_DNUM	0x00F8	/* Device Number */
-#define PCIXM_DEVADDR_BNUM	0xFF00	/* Bus Number */
-#define PCIXR_STATUS	0x9A
-#define PCIXM_STATUS_64BIT	0x0001	/* Active 64bit connection to device. */
-#define PCIXM_STATUS_133CAP	0x0002	/* Device is 133MHz capable */
-#define PCIXM_STATUS_SCDISC	0x0004	/* Split Completion Discarded */
-#define PCIXM_STATUS_UNEXPSC	0x0008	/* Unexpected Split Completion */
-#define PCIXM_STATUS_CMPLEXDEV	0x0010	/* Device Complexity (set == bridge) */
-#define PCIXM_STATUS_MAXMRDBC	0x0060	/* Maximum Burst Read Count */
-#define PCIXM_STATUS_MAXSPLITS	0x0380	/* Maximum Split Transactions */
-#define PCIXM_STATUS_MAXCRDS	0x1C00	/* Maximum Cumulative Read Size */
-#define PCIXM_STATUS_RCVDSCEM	0x2000	/* Received a Split Comp w/Error msg */
+
+/* For header type 0 devices */
+#define	PCIXR_COMMAND		0x2
+#define	PCIXM_COMMAND_DPERR_E		0x0001	/* Data Parity Error Recovery */
+#define	PCIXM_COMMAND_ERO		0x0002	/* Enable Relaxed Ordering */
+#define	PCIXM_COMMAND_MAX_READ		0x000c	/* Maximum Burst Read Count */
+#define	PCIXM_COMMAND_MAX_READ_512	0x0000
+#define	PCIXM_COMMAND_MAX_READ_1024	0x0004
+#define	PCIXM_COMMAND_MAX_READ_2048	0x0008
+#define	PCIXM_COMMAND_MAX_READ_4096	0x000c
+#define	PCIXM_COMMAND_MAX_SPLITS 	0x0070	/* Maximum Split Transactions */
+#define	PCIXM_COMMAND_MAX_SPLITS_1	0x0000
+#define	PCIXM_COMMAND_MAX_SPLITS_2	0x0010
+#define	PCIXM_COMMAND_MAX_SPLITS_3	0x0020
+#define	PCIXM_COMMAND_MAX_SPLITS_4	0x0030
+#define	PCIXM_COMMAND_MAX_SPLITS_8	0x0040
+#define	PCIXM_COMMAND_MAX_SPLITS_12	0x0050
+#define	PCIXM_COMMAND_MAX_SPLITS_16	0x0060
+#define	PCIXM_COMMAND_MAX_SPLITS_32	0x0070
+#define	PCIXM_COMMAND_VERSION		0x3000
+#define	PCIXR_STATUS		0x4
+#define	PCIXM_STATUS_DEVFN		0x000000FF
+#define	PCIXM_STATUS_BUS		0x0000FF00
+#define	PCIXM_STATUS_64BIT		0x00010000
+#define	PCIXM_STATUS_133CAP		0x00020000
+#define	PCIXM_STATUS_SC_DISCARDED	0x00040000
+#define	PCIXM_STATUS_UNEXP_SC		0x00080000
+#define	PCIXM_STATUS_COMPLEX_DEV	0x00100000
+#define	PCIXM_STATUS_MAX_READ		0x00600000
+#define	PCIXM_STATUS_MAX_READ_512	0x00000000
+#define	PCIXM_STATUS_MAX_READ_1024	0x00200000
+#define	PCIXM_STATUS_MAX_READ_2048	0x00400000
+#define	PCIXM_STATUS_MAX_READ_4096	0x00600000
+#define	PCIXM_STATUS_MAX_SPLITS		0x03800000
+#define	PCIXM_STATUS_MAX_SPLITS_1	0x00000000
+#define	PCIXM_STATUS_MAX_SPLITS_2	0x00800000
+#define	PCIXM_STATUS_MAX_SPLITS_3	0x01000000
+#define	PCIXM_STATUS_MAX_SPLITS_4	0x01800000
+#define	PCIXM_STATUS_MAX_SPLITS_8	0x02000000
+#define	PCIXM_STATUS_MAX_SPLITS_12	0x02800000
+#define	PCIXM_STATUS_MAX_SPLITS_16	0x03000000
+#define	PCIXM_STATUS_MAX_SPLITS_32	0x03800000
+#define	PCIXM_STATUS_MAX_CUM_READ	0x1C000000
+#define	PCIXM_STATUS_RCVD_SC_ERR	0x20000000
+#define	PCIXM_STATUS_266CAP		0x40000000
+#define	PCIXM_STATUS_533CAP		0x80000000
+
+/* For header type 1 devices (PCI-X bridges) */
+#define	PCIXR_SEC_STATUS	0x2
+#define	PCIXM_SEC_STATUS_64BIT		0x0001
+#define	PCIXM_SEC_STATUS_133CAP		0x0002
+#define	PCIXM_SEC_STATUS_SC_DISC	0x0004
+#define	PCIXM_SEC_STATUS_UNEXP_SC	0x0008
+#define	PCIXM_SEC_STATUS_SC_OVERRUN	0x0010
+#define	PCIXM_SEC_STATUS_SR_DELAYED	0x0020
+#define	PCIXM_SEC_STATUS_BUS_MODE	0x03c0
+#define	PCIXM_SEC_STATUS_VERSION	0x3000
+#define	PCIXM_SEC_STATUS_266CAP		0x4000
+#define	PCIXM_SEC_STATUS_533CAP		0x8000
+#define	PCIXR_BRIDGE_STATUS	0x4
+#define	PCIXM_BRIDGE_STATUS_DEVFN	0x000000FF
+#define	PCIXM_BRIDGE_STATUS_BUS		0x0000FF00
+#define	PCIXM_BRIDGE_STATUS_64BIT	0x00010000
+#define	PCIXM_BRIDGE_STATUS_133CAP	0x00020000
+#define	PCIXM_BRIDGE_STATUS_SC_DISCARDED 0x00040000
+#define	PCIXM_BRIDGE_STATUS_UNEXP_SC	0x00080000
+#define	PCIXM_BRIDGE_STATUS_SC_OVERRUN	0x00100000
+#define	PCIXM_BRIDGE_STATUS_SR_DELAYED	0x00200000
+#define	PCIXM_BRIDGE_STATUS_DEVID_MSGCAP 0x20000000
+#define	PCIXM_BRIDGE_STATUS_266CAP	0x40000000
+#define	PCIXM_BRIDGE_STATUS_533CAP	0x80000000
+
+/* HT (HyperTransport) Capability definitions */
+#define	PCIR_HT_COMMAND		0x2
+#define	PCIM_HTCMD_CAP_MASK		0xf800	/* Capability type. */
+#define	PCIM_HTCAP_SLAVE		0x0000	/* 000xx */
+#define	PCIM_HTCAP_HOST			0x2000	/* 001xx */
+#define	PCIM_HTCAP_SWITCH		0x4000	/* 01000 */
+#define	PCIM_HTCAP_INTERRUPT		0x8000	/* 10000 */
+#define	PCIM_HTCAP_REVISION_ID		0x8800	/* 10001 */
+#define	PCIM_HTCAP_UNITID_CLUMPING	0x9000	/* 10010 */
+#define	PCIM_HTCAP_EXT_CONFIG_SPACE	0x9800	/* 10011 */
+#define	PCIM_HTCAP_ADDRESS_MAPPING	0xa000	/* 10100 */
+#define	PCIM_HTCAP_MSI_MAPPING		0xa800	/* 10101 */
+#define	PCIM_HTCAP_DIRECT_ROUTE		0xb000	/* 10110 */
+#define	PCIM_HTCAP_VCSET		0xb800	/* 10111 */
+#define	PCIM_HTCAP_RETRY_MODE		0xc000	/* 11000 */
+#define	PCIM_HTCAP_X86_ENCODING		0xc800	/* 11001 */
+
+/* HT MSI Mapping Capability definitions. */
+#define	PCIM_HTCMD_MSI_ENABLE		0x0001
+#define	PCIM_HTCMD_MSI_FIXED		0x0002
+#define	PCIR_HTMSI_ADDRESS_LO	0x4
+#define	PCIR_HTMSI_ADDRESS_HI	0x8
+
+/* PCI Vendor capability definitions */
+#define	PCIR_VENDOR_LENGTH	0x2
+#define	PCIR_VENDOR_DATA	0x3
+
+/* PCI EHCI Debug Port definitions */
+#define	PCIR_DEBUG_PORT		0x2
+#define	PCIM_DEBUG_PORT_OFFSET		0x1FFF
+#define	PCIM_DEBUG_PORT_BAR		0xe000
+
+/* PCI-PCI Bridge Subvendor definitions */
+#define	PCIR_SUBVENDCAP_ID	0x4
+
+/* PCI Express definitions */
+#define	PCIR_EXPRESS_FLAGS	0x2
+#define	PCIM_EXP_FLAGS_VERSION		0x000F
+#define	PCIM_EXP_FLAGS_TYPE		0x00F0
+#define	PCIM_EXP_TYPE_ENDPOINT		0x0000
+#define	PCIM_EXP_TYPE_LEGACY_ENDPOINT	0x0010
+#define	PCIM_EXP_TYPE_ROOT_PORT		0x0040
+#define	PCIM_EXP_TYPE_UPSTREAM_PORT	0x0050
+#define	PCIM_EXP_TYPE_DOWNSTREAM_PORT	0x0060
+#define	PCIM_EXP_TYPE_PCI_BRIDGE	0x0070
+#define	PCIM_EXP_FLAGS_SLOT		0x0100
+#define	PCIM_EXP_FLAGS_IRQ		0x3e00
+
+/* MSI-X definitions */
+#define	PCIR_MSIX_CTRL		0x2
+#define	PCIM_MSIXCTRL_MSIX_ENABLE	0x8000
+#define	PCIM_MSIXCTRL_FUNCTION_MASK	0x4000
+#define	PCIM_MSIXCTRL_TABLE_SIZE	0x07FF
+#define	PCIR_MSIX_TABLE		0x4
+#define	PCIR_MSIX_PBA		0x8
+#define	PCIM_MSIX_BIR_MASK		0x7
+#define	PCIM_MSIX_BIR_BAR_10		0
+#define	PCIM_MSIX_BIR_BAR_14		1
+#define	PCIM_MSIX_BIR_BAR_18		2
+#define	PCIM_MSIX_BIR_BAR_1C		3
+#define	PCIM_MSIX_BIR_BAR_20		4
+#define	PCIM_MSIX_BIR_BAR_24		5
+#define	PCIM_MSIX_VCTRL_MASK		0x1


More information about the Midnightbsd-cvs mailing list