[Midnightbsd-cvs] src [10087] trunk/sys/dev/pci: sync pci

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sun May 27 19:28:52 EDT 2018


Revision: 10087
          http://svnweb.midnightbsd.org/src/?rev=10087
Author:   laffer1
Date:     2018-05-27 19:28:52 -0400 (Sun, 27 May 2018)
Log Message:
-----------
sync pci

Modified Paths:
--------------
    trunk/sys/dev/pci/eisa_pci.c
    trunk/sys/dev/pci/fixup_pci.c
    trunk/sys/dev/pci/hostb_pci.c
    trunk/sys/dev/pci/ignore_pci.c
    trunk/sys/dev/pci/isa_pci.c
    trunk/sys/dev/pci/pci.c
    trunk/sys/dev/pci/pci_if.m
    trunk/sys/dev/pci/pci_pci.c
    trunk/sys/dev/pci/pci_private.h
    trunk/sys/dev/pci/pci_subr.c
    trunk/sys/dev/pci/pci_user.c
    trunk/sys/dev/pci/pcib_if.m
    trunk/sys/dev/pci/pcib_private.h
    trunk/sys/dev/pci/pcireg.h
    trunk/sys/dev/pci/pcivar.h
    trunk/sys/dev/pci/vga_pci.c

Added Paths:
-----------
    trunk/sys/dev/pci/pcib_support.c

Property Changed:
----------------
    trunk/sys/dev/pci/pci_if.m
    trunk/sys/dev/pci/pcib_if.m

Modified: trunk/sys/dev/pci/eisa_pci.c
===================================================================
--- trunk/sys/dev/pci/eisa_pci.c	2018-05-27 23:27:48 UTC (rev 10086)
+++ trunk/sys/dev/pci/eisa_pci.c	2018-05-27 23:28:52 UTC (rev 10087)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier
  * Copyright (c) 2000 Michael Smith <msmith at freebsd.org>
@@ -29,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/pci/eisa_pci.c 227843 2011-11-22 21:28:20Z marius $");
 
 /*
  * PCI:EISA bridge support

Modified: trunk/sys/dev/pci/fixup_pci.c
===================================================================
--- trunk/sys/dev/pci/fixup_pci.c	2018-05-27 23:27:48 UTC (rev 10086)
+++ trunk/sys/dev/pci/fixup_pci.c	2018-05-27 23:28:52 UTC (rev 10087)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier
  * Copyright (c) 2000 Michael Smith <msmith at freebsd.org>
@@ -29,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/pci/fixup_pci.c 254207 2013-08-11 06:57:57Z rpaulo $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -92,13 +93,13 @@
     pmccfg = pci_read_config(dev, 0x50, 2);
 #if defined(SMP)
     if (pmccfg & 0x8000) {
-	printf("Correcting Natoma config for SMP\n");
+	device_printf(dev, "correcting Natoma config for SMP\n");
 	pmccfg &= ~0x8000;
 	pci_write_config(dev, 0x50, pmccfg, 2);
     }
 #else
     if ((pmccfg & 0x8000) == 0) {
-	printf("Correcting Natoma config for non-SMP\n");
+	device_printf(dev, "correcting Natoma config for non-SMP\n");
 	pmccfg |= 0x8000;
 	pci_write_config(dev, 0x50, pmccfg, 2);
     }
@@ -132,7 +133,8 @@
 	    pci_get_function(dev) == 0) {
 		val = pci_read_config(dev, 0x6c, 4);
 		if (val & 0x000e0000) {
-			printf("Correcting nForce2 C1 CPU disconnect hangs\n");
+			device_printf(dev, 
+			    "correcting nForce2 C1 CPU disconnect hangs\n");
 			val &= ~0x000e0000;
 			pci_write_config(dev, 0x6c, val, 4);
 		}

Modified: trunk/sys/dev/pci/hostb_pci.c
===================================================================
--- trunk/sys/dev/pci/hostb_pci.c	2018-05-27 23:27:48 UTC (rev 10086)
+++ trunk/sys/dev/pci/hostb_pci.c	2018-05-27 23:28:52 UTC (rev 10087)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * Copyright (c) 1997, Stefan Esser <se at freebsd.org>
  * All rights reserved.
@@ -25,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/pci/hostb_pci.c 232472 2012-03-03 18:08:57Z jhb $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -197,6 +198,14 @@
 }
 
 static int
+pci_hostb_find_cap(device_t dev, device_t child, int capability,
+    int *capreg)
+{
+
+	return (pci_find_cap(dev, capability, capreg));
+}
+
+static int
 pci_hostb_find_extcap(device_t dev, device_t child, int capability,
     int *capreg)
 {
@@ -204,6 +213,14 @@
 	return (pci_find_extcap(dev, capability, capreg));
 }
 
+static int
+pci_hostb_find_htcap(device_t dev, device_t child, int capability,
+    int *capreg)
+{
+
+	return (pci_find_htcap(dev, capability, capreg));
+}
+
 static device_method_t pci_hostb_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		pci_hostb_probe),
@@ -233,7 +250,9 @@
 	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_cap,		pci_hostb_find_cap),
 	DEVMETHOD(pci_find_extcap,	pci_hostb_find_extcap),
+	DEVMETHOD(pci_find_htcap,	pci_hostb_find_htcap),
 
 	{ 0, 0 }
 };

Modified: trunk/sys/dev/pci/ignore_pci.c
===================================================================
--- trunk/sys/dev/pci/ignore_pci.c	2018-05-27 23:27:48 UTC (rev 10086)
+++ trunk/sys/dev/pci/ignore_pci.c	2018-05-27 23:28:52 UTC (rev 10087)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2000 Michael Smith <msmith at freebsd.org>
  * Copyright (c) 2000 BSDi
@@ -26,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/pci/ignore_pci.c 129876 2004-05-30 17:57:46Z phk $");
 
 /*
  * 'Ignore' driver - eats devices that show up errnoeously on PCI

Modified: trunk/sys/dev/pci/isa_pci.c
===================================================================
--- trunk/sys/dev/pci/isa_pci.c	2018-05-27 23:27:48 UTC (rev 10086)
+++ trunk/sys/dev/pci/isa_pci.c	2018-05-27 23:28:52 UTC (rev 10087)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier
  * Copyright (c) 2000 Michael Smith <msmith at freebsd.org>
@@ -29,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/pci/isa_pci.c 228496 2011-12-14 12:34:02Z jhb $");
 
 /*
  * PCI:ISA bridge support

Modified: trunk/sys/dev/pci/pci.c
===================================================================
--- trunk/sys/dev/pci/pci.c	2018-05-27 23:27:48 UTC (rev 10086)
+++ trunk/sys/dev/pci/pci.c	2018-05-27 23:28:52 UTC (rev 10087)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1997, Stefan Esser <se at freebsd.org>
  * Copyright (c) 2000, Michael Smith <msmith at freebsd.org>
@@ -27,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/pci/pci.c 330938 2018-03-14 19:04:40Z jhb $");
 
 #include "opt_bus.h"
 
@@ -35,6 +36,7 @@
 #include <sys/systm.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
+#include <sys/limits.h>
 #include <sys/linker.h>
 #include <sys/fcntl.h>
 #include <sys/conf.h>
@@ -70,25 +72,11 @@
 #include "pcib_if.h"
 #include "pci_if.h"
 
-/*
- * XXX: Due to a limitation of the bus_dma_tag_create() API, we cannot
- * specify a 4GB boundary on 32-bit targets.  Usually this does not
- * matter as it is ok to use a boundary of 0 on these systems.
- * However, in the case of PAE, DMA addresses can cross a 4GB
- * boundary, so as a workaround use a 2GB boundary.
- */
-#if (BUS_SPACE_MAXADDR > 0xFFFFFFFF)
-#ifdef PAE
-#define	PCI_DMA_BOUNDARY	0x80000000
-#else
-#define	PCI_DMA_BOUNDARY	0x100000000
-#endif
-#endif
-
 #define	PCIR_IS_BIOS(cfg, reg)						\
 	(((cfg)->hdrtype == PCIM_HDRTYPE_NORMAL && reg == PCIR_BIOS) ||	\
 	 ((cfg)->hdrtype == PCIM_HDRTYPE_BRIDGE && reg == PCIR_BIOS_1))
 
+static int		pci_has_quirk(uint32_t devid, int quirk);
 static pci_addr_t	pci_mapbase(uint64_t mapreg);
 static const char	*pci_maptype(uint64_t mapreg);
 static int		pci_mapsize(uint64_t testval);
@@ -106,11 +94,13 @@
 			    struct resource_list *rl, int force, int prefetch);
 static int		pci_probe(device_t dev);
 static int		pci_attach(device_t dev);
+#ifdef PCI_RES_BUS
+static int		pci_detach(device_t dev);
+#endif
 static void		pci_load_vendor_data(void);
 static int		pci_describe_parse_line(char **ptr, int *vendor,
 			    int *device, char **desc);
 static char		*pci_describe_device(device_t dev);
-static bus_dma_tag_t	pci_get_dma_tag(device_t bus, device_t dev);
 static int		pci_modevent(module_t mod, int what, void *arg);
 static void		pci_hdrtypedata(device_t pcib, int b, int s, int f,
 			    pcicfgregs *cfg);
@@ -122,24 +112,26 @@
 			    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 int		pci_msix_blacklisted(void);
 static void		pci_resume_msi(device_t dev);
 static void		pci_resume_msix(device_t dev);
 static int		pci_remap_intr_method(device_t bus, device_t dev,
 			    u_int irq);
 
+static uint16_t		pci_get_rid_method(device_t dev, device_t child);
+
 static device_method_t pci_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		pci_probe),
 	DEVMETHOD(device_attach,	pci_attach),
+#ifdef PCI_RES_BUS
+	DEVMETHOD(device_detach,	pci_detach),
+#else
 	DEVMETHOD(device_detach,	bus_generic_detach),
+#endif
 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
 	DEVMETHOD(device_suspend,	pci_suspend),
 	DEVMETHOD(device_resume,	pci_resume),
@@ -160,9 +152,11 @@
 	DEVMETHOD(bus_delete_resource,	pci_delete_resource),
 	DEVMETHOD(bus_alloc_resource,	pci_alloc_resource),
 	DEVMETHOD(bus_adjust_resource,	bus_generic_adjust_resource),
-	DEVMETHOD(bus_release_resource,	bus_generic_rl_release_resource),
+	DEVMETHOD(bus_release_resource,	pci_release_resource),
 	DEVMETHOD(bus_activate_resource, pci_activate_resource),
 	DEVMETHOD(bus_deactivate_resource, pci_deactivate_resource),
+	DEVMETHOD(bus_child_deleted,	pci_child_deleted),
+	DEVMETHOD(bus_child_detached,	pci_child_detached),
 	DEVMETHOD(bus_child_pnpinfo_str, pci_child_pnpinfo_str_method),
 	DEVMETHOD(bus_child_location_str, pci_child_location_str_method),
 	DEVMETHOD(bus_remap_intr,	pci_remap_intr_method),
@@ -179,13 +173,22 @@
 	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_cap,		pci_find_cap_method),
 	DEVMETHOD(pci_find_extcap,	pci_find_extcap_method),
+	DEVMETHOD(pci_find_htcap,	pci_find_htcap_method),
 	DEVMETHOD(pci_alloc_msi,	pci_alloc_msi_method),
 	DEVMETHOD(pci_alloc_msix,	pci_alloc_msix_method),
+	DEVMETHOD(pci_enable_msi,	pci_enable_msi_method),
+	DEVMETHOD(pci_enable_msix,	pci_enable_msix_method),
+	DEVMETHOD(pci_disable_msi,	pci_disable_msi_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),
+	DEVMETHOD(pci_msix_pba_bar,	pci_msix_pba_bar_method),
+	DEVMETHOD(pci_msix_table_bar,	pci_msix_table_bar_method),
+	DEVMETHOD(pci_get_rid,		pci_get_rid_method),
+	DEVMETHOD(pci_child_added,	pci_child_added_method),
 
 	DEVMETHOD_END
 };
@@ -193,7 +196,7 @@
 DEFINE_CLASS_0(pci, pci_driver, pci_methods, sizeof(struct pci_softc));
 
 static devclass_t pci_devclass;
-DRIVER_MODULE(pci, pcib, pci_driver, pci_devclass, pci_modevent, 0);
+DRIVER_MODULE(pci, pcib, pci_driver, pci_devclass, pci_modevent, NULL);
 MODULE_VERSION(pci, 1);
 
 static char	*pci_vendordata;
@@ -203,15 +206,17 @@
 	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_DISABLE_MSI	2 /* MSI/MSI-X doesn't work */
+#define	PCI_QUIRK_DISABLE_MSI	2 /* Neither MSI nor MSI-X work */
 #define	PCI_QUIRK_ENABLE_MSI_VM	3 /* Older chipset in VM where MSI works */
 #define	PCI_QUIRK_UNMAP_REG	4 /* Ignore PCI map register */
+#define	PCI_QUIRK_DISABLE_MSIX	5 /* MSI-X doesn't work */
+#define	PCI_QUIRK_MSI_INTX_BUG	6 /* PCIM_CMD_INTxDIS disables MSI */
 	int	arg1;
 	int	arg2;
 };
 
 static const struct pci_quirk pci_quirks[] = {
-	/* The Intel 82371AB and 82443MX has a map register at offset 0x90. */
+	/* The Intel 82371AB and 82443MX have a map register at offset 0x90. */
 	{ 0x71138086, PCI_QUIRK_MAP_REG,	0x90,	 0 },
 	{ 0x719b8086, PCI_QUIRK_MAP_REG,	0x90,	 0 },
 	/* As does the Serverworks OSB4 (the SMBus mapping register) */
@@ -246,8 +251,8 @@
 	 * MSI-X allocation doesn't work properly for devices passed through
 	 * by VMware up to at least ESXi 5.1.
 	 */
-	{ 0x079015ad, PCI_QUIRK_DISABLE_MSI,	0,	0 }, /* PCI/PCI-X */
-	{ 0x07a015ad, PCI_QUIRK_DISABLE_MSI,	0,	0 }, /* PCIe */
+	{ 0x079015ad, PCI_QUIRK_DISABLE_MSIX,	0,	0 }, /* PCI/PCI-X */
+	{ 0x07a015ad, PCI_QUIRK_DISABLE_MSIX,	0,	0 }, /* PCIe */
 
 	/*
 	 * Some virtualization environments emulate an older chipset
@@ -265,6 +270,28 @@
 	 */
 	{ 0x43851002, PCI_QUIRK_UNMAP_REG,	0x14,	0 },
 
+	/*
+	 * Atheros AR8161/AR8162/E2200/E2400/E2500 Ethernet controllers have
+	 * a bug that MSI interrupt does not assert if PCIM_CMD_INTxDIS bit
+	 * of the command register is set.
+	 */
+	{ 0x10911969, PCI_QUIRK_MSI_INTX_BUG,	0,	0 },
+	{ 0xE0911969, PCI_QUIRK_MSI_INTX_BUG,	0,	0 },
+	{ 0xE0A11969, PCI_QUIRK_MSI_INTX_BUG,	0,	0 },
+	{ 0xE0B11969, PCI_QUIRK_MSI_INTX_BUG,	0,	0 },
+	{ 0x10901969, PCI_QUIRK_MSI_INTX_BUG,	0,	0 },
+
+	/*
+	 * Broadcom BCM5714(S)/BCM5715(S)/BCM5780(S) Ethernet MACs don't
+	 * issue MSI interrupts with PCIM_CMD_INTxDIS set either.
+	 */
+	{ 0x166814e4, PCI_QUIRK_MSI_INTX_BUG,	0,	0 }, /* BCM5714 */
+	{ 0x166914e4, PCI_QUIRK_MSI_INTX_BUG,	0,	0 }, /* BCM5714S */
+	{ 0x166a14e4, PCI_QUIRK_MSI_INTX_BUG,	0,	0 }, /* BCM5780 */
+	{ 0x166b14e4, PCI_QUIRK_MSI_INTX_BUG,	0,	0 }, /* BCM5780S */
+	{ 0x167814e4, PCI_QUIRK_MSI_INTX_BUG,	0,	0 }, /* BCM5715 */
+	{ 0x167914e4, PCI_QUIRK_MSI_INTX_BUG,	0,	0 }, /* BCM5715S */
+
 	{ 0 }
 };
 
@@ -289,6 +316,12 @@
 enable these bits correctly.  We'd like to do this all the time, but there\n\
 are some peripherals that this causes problems with.");
 
+static int pci_do_realloc_bars = 0;
+TUNABLE_INT("hw.pci.realloc_bars", &pci_do_realloc_bars);
+SYSCTL_INT(_hw_pci, OID_AUTO, realloc_bars, CTLFLAG_RW,
+    &pci_do_realloc_bars, 0,
+    "Attempt to allocate a new range for any BARs whose original firmware-assigned ranges fail to allocate during the initial device scan.");
+
 static int pci_do_power_nodriver = 0;
 TUNABLE_INT("hw.pci.do_power_nodriver", &pci_do_power_nodriver);
 SYSCTL_INT(_hw_pci, OID_AUTO, do_power_nodriver, CTLFLAG_RW,
@@ -320,10 +353,15 @@
 SYSCTL_INT(_hw_pci, OID_AUTO, enable_msix, CTLFLAG_RW, &pci_do_msix, 1,
     "Enable support for MSI-X interrupts");
 
+static int pci_msix_rewrite_table = 0;
+SYSCTL_INT(_hw_pci, OID_AUTO, msix_rewrite_table, CTLFLAG_RWTUN,
+    &pci_msix_rewrite_table, 0,
+    "Rewrite entire MSI-X table when updating MSI-X entries");
+
 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");
+    &pci_honor_msi_blacklist, 1, "Honor chipset blacklist for MSI/MSI-X");
 
 #if defined(__i386__) || defined(__amd64__)
 static int pci_usb_takeover = 1;
@@ -336,6 +374,35 @@
 Disable this if you depend on BIOS emulation of USB devices, that is\n\
 you use USB devices (like keyboard or mouse) but do not load USB drivers");
 
+static int pci_clear_bars;
+TUNABLE_INT("hw.pci.clear_bars", &pci_clear_bars);
+SYSCTL_INT(_hw_pci, OID_AUTO, clear_bars, CTLFLAG_RDTUN, &pci_clear_bars, 0,
+    "Ignore firmware-assigned resources for BARs.");
+
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+static int pci_clear_buses;
+TUNABLE_INT("hw.pci.clear_buses", &pci_clear_buses);
+SYSCTL_INT(_hw_pci, OID_AUTO, clear_buses, CTLFLAG_RDTUN, &pci_clear_buses, 0,
+    "Ignore firmware-assigned bus numbers.");
+#endif
+
+static int pci_enable_ari = 1;
+TUNABLE_INT("hw.pci.enable_ari", &pci_enable_ari);
+SYSCTL_INT(_hw_pci, OID_AUTO, enable_ari, CTLFLAG_RDTUN, &pci_enable_ari,
+    0, "Enable support for PCIe Alternative RID Interpretation");
+
+static int
+pci_has_quirk(uint32_t devid, int quirk)
+{
+	const struct pci_quirk *q;
+
+	for (q = &pci_quirks[0]; q->devid; q++) {
+		if (q->devid == devid && q->type == quirk)
+			return (1);
+	}
+	return (0);
+}
+
 /* Find a device_t by bus/slot/function in domain 0 */
 
 device_t
@@ -529,6 +596,8 @@
 	case PCIM_HDRTYPE_NORMAL:
 		cfg->subvendor      = REG(PCIR_SUBVEND_0, 2);
 		cfg->subdevice      = REG(PCIR_SUBDEV_0, 2);
+		cfg->mingnt         = REG(PCIR_MINGNT, 1);
+		cfg->maxlat         = REG(PCIR_MAXLAT, 1);
 		cfg->nummaps	    = PCI_MAXMAPS_0;
 		break;
 	case PCIM_HDRTYPE_BRIDGE:
@@ -558,8 +627,6 @@
 
 	if (REG(PCIR_DEVVENDOR, 4) != 0xfffffffful) {
 		devlist_entry = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
-		if (devlist_entry == NULL)
-			return (NULL);
 
 		cfg = &devlist_entry->cfg;
 
@@ -581,9 +648,6 @@
 		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;
 		STAILQ_INIT(&cfg->maps);
@@ -744,6 +808,7 @@
 			if ((cfg->hdrtype & PCIM_HDRTYPE) ==
 			    PCIM_HDRTYPE_BRIDGE)
 				pcix_chipset = 1;
+			cfg->pcix.pcix_location = ptr;
 			break;
 		case PCIY_EXPRESS:	/* PCI-express */
 			/*
@@ -751,6 +816,9 @@
 			 * at least one PCI-express device.
 			 */
 			pcie_chipset = 1;
+			cfg->pcie.pcie_location = ptr;
+			val = REG(ptr + PCIER_FLAGS, 2);
+			cfg->pcie.pcie_type = val & PCIEM_FLAGS_TYPE;
 			break;
 		default:
 			break;
@@ -907,10 +975,9 @@
 				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);
+					pci_printf(cfg,
+					    "invalid VPD data, remain %#x\n",
+					    remain);
 				}
 				name = byte & 0x7f;
 			} else {
@@ -974,7 +1041,7 @@
 				state = -2;
 				break;
 			}
-			dflen = byte2;
+			cfg->vpd.vpd_ros[off].len = dflen = byte2;
 			if (dflen == 0 &&
 			    strncmp(cfg->vpd.vpd_ros[off].keyword, "RV",
 			    2) == 0) {
@@ -982,10 +1049,8 @@
 				 * 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);
+				pci_printf(cfg, "bad keyword length: %d\n",
+				    dflen);
 				cksumvalid = 0;
 				state = -1;
 				break;
@@ -1018,10 +1083,8 @@
 					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,
+						pci_printf(cfg,
+					    "bad VPD cksum, remain %hhu\n",
 						    vrs.cksum);
 					cksumvalid = 0;
 					state = -1;
@@ -1099,9 +1162,7 @@
 			break;
 
 		default:
-			printf("pci%d:%d:%d:%d: invalid state: %d\n",
-			    cfg->domain, cfg->bus, cfg->slot, cfg->func,
-			    state);
+			pci_printf(cfg, "invalid state: %d\n", state);
 			state = -1;
 			break;
 		}
@@ -1118,8 +1179,7 @@
 	}
 	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);
+		pci_printf(cfg, "failed to read VPD data.\n");
 		if (cfg->vpd.vpd_ident != NULL) {
 			free(cfg->vpd.vpd_ident, M_DEVBUF);
 			cfg->vpd.vpd_ident = NULL;
@@ -1175,13 +1235,67 @@
 	return (ENXIO);
 }
 
+struct pcicfg_vpd *
+pci_fetch_vpd_list(device_t dev)
+{
+	struct pci_devinfo *dinfo = device_get_ivars(dev);
+	pcicfgregs *cfg = &dinfo->cfg;
+
+	if (!cfg->vpd.vpd_cached && cfg->vpd.vpd_reg != 0)
+		pci_read_vpd(device_get_parent(device_get_parent(dev)), cfg);
+	return (&cfg->vpd);
+}
+
 /*
- * Find the requested extended capability and return the offset in
- * configuration space via the pointer provided. The function returns
- * 0 on success and error code otherwise.
+ * Find the requested HyperTransport capability and return the offset
+ * in configuration space via the pointer provided.  The function
+ * returns 0 on success and an error code otherwise.
  */
 int
-pci_find_extcap_method(device_t dev, device_t child, int capability,
+pci_find_htcap_method(device_t dev, device_t child, int capability, int *capreg)
+{
+	int ptr, error;
+	uint16_t val;
+
+	error = pci_find_cap(child, PCIY_HT, &ptr);
+	if (error)
+		return (error);
+
+	/*
+	 * Traverse the capabilities list checking each HT capability
+	 * to see if it matches the requested HT capability.
+	 */
+	while (ptr != 0) {
+		val = pci_read_config(child, ptr + PCIR_HT_COMMAND, 2);
+		if (capability == PCIM_HTCAP_SLAVE ||
+		    capability == PCIM_HTCAP_HOST)
+			val &= 0xe000;
+		else
+			val &= PCIM_HTCMD_CAP_MASK;
+		if (val == capability) {
+			if (capreg != NULL)
+				*capreg = ptr;
+			return (0);
+		}
+
+		/* Skip to the next HT capability. */
+		while (ptr != 0) {
+			ptr = pci_read_config(child, ptr + PCICAP_NEXTPTR, 1);
+			if (pci_read_config(child, ptr + PCICAP_ID, 1) ==
+			    PCIY_HT)
+				break;
+		}
+	}
+	return (ENOENT);
+}
+
+/*
+ * Find the requested capability and return the offset in
+ * configuration space via the pointer provided.  The function returns
+ * 0 on success and an error code otherwise.
+ */
+int
+pci_find_cap_method(device_t dev, device_t child, int capability,
     int *capreg)
 {
 	struct pci_devinfo *dinfo = device_get_ivars(child);
@@ -1229,10 +1343,47 @@
 }
 
 /*
+ * Find the requested extended capability and return the offset in
+ * configuration space via the pointer provided.  The function returns
+ * 0 on success and an error code otherwise.
+ */
+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;
+	uint32_t ecap;
+	uint16_t ptr;
+
+	/* Only supported for PCI-express devices. */
+	if (cfg->pcie.pcie_location == 0)
+		return (ENXIO);
+
+	ptr = PCIR_EXTCAP;
+	ecap = pci_read_config(child, ptr, 4);
+	if (ecap == 0xffffffff || ecap == 0)
+		return (ENOENT);
+	for (;;) {
+		if (PCI_EXTCAP_ID(ecap) == capability) {
+			if (capreg != NULL)
+				*capreg = ptr;
+			return (0);
+		}
+		ptr = PCI_EXTCAP_NEXTPTR(ecap);
+		if (ptr == 0)
+			break;
+		ecap = pci_read_config(child, ptr, 4);
+	}
+
+	return (ENOENT);
+}
+
+/*
  * Support for MSI-X message interrupts.
  */
-void
-pci_enable_msix(device_t dev, u_int index, uint64_t address, uint32_t data)
+static void
+pci_write_msix_entry(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;
@@ -1243,9 +1394,34 @@
 	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_enable_msix_method(device_t dev, device_t child, u_int index,
+    uint64_t address, uint32_t data)
+{
+
+	if (pci_msix_rewrite_table) {
+		struct pci_devinfo *dinfo = device_get_ivars(child);
+		struct pcicfg_msix *msix = &dinfo->cfg.msix;
+
+		/*
+		 * Some VM hosts require MSIX to be disabled in the
+		 * control register before updating the MSIX table
+		 * entries are allowed. It is not enough to only
+		 * disable MSIX while updating a single entry. MSIX
+		 * must be disabled while updating all entries in the
+		 * table.
+		 */
+		pci_write_config(child,
+		    msix->msix_location + PCIR_MSIX_CTRL,
+		    msix->msix_ctrl & ~PCIM_MSIXCTRL_MSIX_ENABLE, 2);
+		pci_resume_msix(child);
+	} else
+		pci_write_msix_entry(child, index, address, data);
+
 	/* Enable MSI -> HT mapping. */
-	pci_ht_map_msi(dev, address);
+	pci_ht_map_msi(child, address);
 }
 
 void
@@ -1318,7 +1494,8 @@
 			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_write_msix_entry(dev, i, mv->mv_address,
+			    mv->mv_data);
 			pci_unmask_msix(dev, i);
 		}
 	}
@@ -1352,8 +1529,8 @@
 	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())
+	/* If MSI-X is blacklisted for this system, fail. */
+	if (pci_msix_blacklisted())
 		return (ENXIO);
 
 	/* MSI-X capability present? */
@@ -1496,7 +1673,7 @@
  * 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 },
+ * If the driver then 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.
@@ -1601,7 +1778,7 @@
 	for (i = 0; i < count; i++) {
 		if (vectors[i] == 0)
 			continue;
-		irq = msix->msix_vectors[vectors[i]].mv_irq;
+		irq = msix->msix_vectors[vectors[i] - 1].mv_irq;
 		resource_list_add(&dinfo->resources, SYS_RES_IRQ, i + 1, irq,
 		    irq, 1);
 	}
@@ -1615,7 +1792,7 @@
 				printf("---");
 			else
 				printf("%d",
-				    msix->msix_vectors[vectors[i]].mv_irq);
+				    msix->msix_vectors[vectors[i] - 1].mv_irq);
 		}
 		printf("\n");
 	}
@@ -1687,6 +1864,28 @@
 	return (0);
 }
 
+int
+pci_msix_pba_bar_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_pba_bar);
+	return (-1);
+}
+
+int
+pci_msix_table_bar_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_table_bar);
+	return (-1);
+}
+
 /*
  * HyperTransport MSI mapping control
  */
@@ -1716,12 +1915,30 @@
 }
 
 int
+pci_get_max_payload(device_t dev)
+{
+	struct pci_devinfo *dinfo = device_get_ivars(dev);
+	int cap;
+	uint16_t val;
+
+	cap = dinfo->cfg.pcie.pcie_location;
+	if (cap == 0)
+		return (0);
+	val = pci_read_config(dev, cap + PCIER_DEVICE_CTL, 2);
+	val &= PCIEM_CTL_MAX_PAYLOAD;
+	val >>= 5;
+	return (1 << (val + 7));
+}
+
+int
 pci_get_max_read_req(device_t dev)
 {
+	struct pci_devinfo *dinfo = device_get_ivars(dev);
 	int cap;
 	uint16_t val;
 
-	if (pci_find_cap(dev, PCIY_EXPRESS, &cap) != 0)
+	cap = dinfo->cfg.pcie.pcie_location;
+	if (cap == 0)
 		return (0);
 	val = pci_read_config(dev, cap + PCIER_DEVICE_CTL, 2);
 	val &= PCIEM_CTL_MAX_READ_REQUEST;
@@ -1732,10 +1949,12 @@
 int
 pci_set_max_read_req(device_t dev, int size)
 {
+	struct pci_devinfo *dinfo = device_get_ivars(dev);
 	int cap;
 	uint16_t val;
 
-	if (pci_find_cap(dev, PCIY_EXPRESS, &cap) != 0)
+	cap = dinfo->cfg.pcie.pcie_location;
+	if (cap == 0)
 		return (0);
 	if (size < 128)
 		size = 128;
@@ -1749,49 +1968,107 @@
 	return (size);
 }
 
+uint32_t
+pcie_read_config(device_t dev, int reg, int width)
+{
+	struct pci_devinfo *dinfo = device_get_ivars(dev);
+	int cap;
+
+	cap = dinfo->cfg.pcie.pcie_location;
+	if (cap == 0) {
+		if (width == 2)
+			return (0xffff);
+		return (0xffffffff);
+	}
+
+	return (pci_read_config(dev, cap + reg, width));
+}
+
+void
+pcie_write_config(device_t dev, int reg, uint32_t value, int width)
+{
+	struct pci_devinfo *dinfo = device_get_ivars(dev);
+	int cap;
+
+	cap = dinfo->cfg.pcie.pcie_location;
+	if (cap == 0)
+		return;
+	pci_write_config(dev, cap + reg, value, width);
+}
+
 /*
+ * Adjusts a PCI-e capability register by clearing the bits in mask
+ * and setting the bits in (value & mask).  Bits not set in mask are
+ * not adjusted.
+ *
+ * Returns the old value on success or all ones on failure.
+ */
+uint32_t
+pcie_adjust_config(device_t dev, int reg, uint32_t mask, uint32_t value,
+    int width)
+{
+	struct pci_devinfo *dinfo = device_get_ivars(dev);
+	uint32_t old, new;
+	int cap;
+
+	cap = dinfo->cfg.pcie.pcie_location;
+	if (cap == 0) {
+		if (width == 2)
+			return (0xffff);
+		return (0xffffffff);
+	}
+
+	old = pci_read_config(dev, cap + reg, width);
+	new = old & ~mask;
+	new |= (value & mask);
+	pci_write_config(dev, cap + reg, new, width);
+	return (old);
+}
+
+/*
  * Support for MSI message signalled interrupts.
  */
 void
-pci_enable_msi(device_t dev, uint64_t address, uint16_t data)
+pci_enable_msi_method(device_t dev, device_t child, uint64_t address,
+    uint16_t data)
 {
-	struct pci_devinfo *dinfo = device_get_ivars(dev);
+	struct pci_devinfo *dinfo = device_get_ivars(child);
 	struct pcicfg_msi *msi = &dinfo->cfg.msi;
 
 	/* Write data and address values. */
-	pci_write_config(dev, msi->msi_location + PCIR_MSI_ADDR,
+	pci_write_config(child, 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,
+		pci_write_config(child, msi->msi_location + PCIR_MSI_ADDR_HIGH,
 		    address >> 32, 4);
-		pci_write_config(dev, msi->msi_location + PCIR_MSI_DATA_64BIT,
+		pci_write_config(child, msi->msi_location + PCIR_MSI_DATA_64BIT,
 		    data, 2);
 	} else
-		pci_write_config(dev, msi->msi_location + PCIR_MSI_DATA, data,
+		pci_write_config(child, 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);
+	pci_write_config(child, msi->msi_location + PCIR_MSI_CTRL,
+	    msi->msi_ctrl, 2);
 
 	/* Enable MSI -> HT mapping. */
-	pci_ht_map_msi(dev, address);
+	pci_ht_map_msi(child, address);
 }
 
 void
-pci_disable_msi(device_t dev)
+pci_disable_msi_method(device_t dev, device_t child)
 {
-	struct pci_devinfo *dinfo = device_get_ivars(dev);
+	struct pci_devinfo *dinfo = device_get_ivars(child);
 	struct pcicfg_msi *msi = &dinfo->cfg.msi;
 
 	/* Disable MSI -> HT mapping. */
-	pci_ht_map_msi(dev, 0);
+	pci_ht_map_msi(child, 0);
 
 	/* Disable MSI in the control register. */
 	msi->msi_ctrl &= ~PCIM_MSICTRL_MSI_ENABLE;
-	pci_write_config(dev, msi->msi_location + PCIR_MSI_CTRL, msi->msi_ctrl,
-	    2);
+	pci_write_config(child, msi->msi_location + PCIR_MSI_CTRL,
+	    msi->msi_ctrl, 2);
 }
 
 /*
@@ -1905,38 +2182,15 @@
 int
 pci_msi_device_blacklisted(device_t dev)
 {
-	const struct pci_quirk *q;
 
 	if (!pci_honor_msi_blacklist)
 		return (0);
 
-	for (q = &pci_quirks[0]; q->devid; q++) {
-		if (q->devid == pci_get_devid(dev) &&
-		    q->type == PCI_QUIRK_DISABLE_MSI)
-			return (1);
-	}
-	return (0);
+	return (pci_has_quirk(pci_get_devid(dev), PCI_QUIRK_DISABLE_MSI));
 }
 
 /*
- * Returns true if a specified chipset supports MSI when it is
- * emulated hardware in a virtual machine.
- */
-static int
-pci_msi_vm_chipset(device_t dev)
-{
-	const struct pci_quirk *q;
-
-	for (q = &pci_quirks[0]; q->devid; q++) {
-		if (q->devid == pci_get_devid(dev) &&
-		    q->type == PCI_QUIRK_ENABLE_MSI_VM)
-			return (1);
-	}
-	return (0);
-}
-
-/*
- * Determine if MSI is blacklisted globally on this sytem.  Currently,
+ * Determine if MSI is blacklisted globally on this system.  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
@@ -1953,9 +2207,14 @@
 	/* Blacklist all non-PCI-express and non-PCI-X chipsets. */
 	if (!(pcie_chipset || pcix_chipset)) {
 		if (vm_guest != VM_GUEST_NO) {
+			/*
+			 * Whitelist older chipsets in virtual
+			 * machines known to support MSI.
+			 */
 			dev = pci_find_bsf(0, 0, 0);
 			if (dev != NULL)
-				return (pci_msi_vm_chipset(dev) == 0);
+				return (!pci_has_quirk(pci_get_devid(dev),
+					PCI_QUIRK_ENABLE_MSI_VM));
 		}
 		return (1);
 	}
@@ -1967,6 +2226,45 @@
 }
 
 /*
+ * Returns true if the specified device is blacklisted because MSI-X
+ * doesn't work.  Note that this assumes that if MSI doesn't work,
+ * MSI-X doesn't either.
+ */
+int
+pci_msix_device_blacklisted(device_t dev)
+{
+
+	if (!pci_honor_msi_blacklist)
+		return (0);
+
+	if (pci_has_quirk(pci_get_devid(dev), PCI_QUIRK_DISABLE_MSIX))
+		return (1);
+
+	return (pci_msi_device_blacklisted(dev));
+}
+
+/*
+ * Determine if MSI-X is blacklisted globally on this system.  If MSI
+ * is blacklisted, assume that MSI-X is as well.  Check for additional
+ * chipsets where MSI works but MSI-X does not.
+ */
+static int
+pci_msix_blacklisted(void)
+{
+	device_t dev;
+
+	if (!pci_honor_msi_blacklist)
+		return (0);
+
+	dev = pci_find_bsf(0, 0, 0);
+	if (dev != NULL && pci_has_quirk(pci_get_devid(dev),
+	    PCI_QUIRK_DISABLE_MSIX))
+		return (1);
+
+	return (pci_msi_blacklisted());
+}
+
+/*
  * 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.
@@ -2199,7 +2497,7 @@
 	struct pci_devinfo *dinfo = device_get_ivars(child);
 	pcicfgregs *cfg = &dinfo->cfg;
 	uint16_t status;
-	int result, oldstate, highest, delay;
+	int oldstate, highest, delay;
 
 	if (cfg->pp.pp_cap == 0)
 		return (EOPNOTSUPP);
@@ -2234,7 +2532,6 @@
 	    delay = 0;
 	status = PCI_READ_CONFIG(dev, child, cfg->pp.pp_status, 2)
 	    & ~PCIM_PSTAT_DMASK;
-	result = 0;
 	switch (state) {
 	case PCI_POWERSTATE_D0:
 		status |= PCIM_PSTAT_D0;
@@ -2622,7 +2919,7 @@
 	struct pci_map *pm;
 	pci_addr_t base, map, testval;
 	pci_addr_t start, end, count;
-	int barlen, basezero, maprange, mapsize, type;
+	int barlen, basezero, flags, maprange, mapsize, type;
 	uint16_t cmd;
 	struct resource *res;
 
@@ -2728,7 +3025,10 @@
 	}
 
 	count = (pci_addr_t)1 << mapsize;
-	if (basezero || base == pci_mapbase(testval)) {
+	flags = RF_ALIGNMENT_LOG2(mapsize);
+	if (prefetch)
+		flags |= RF_PREFETCHABLE;
+	if (basezero || base == pci_mapbase(testval) || pci_clear_bars) {
 		start = 0;	/* Let the parent decide. */
 		end = ~0ul;
 	} else {
@@ -2744,14 +3044,35 @@
 	 * pci_alloc_resource().
 	 */
 	res = resource_list_reserve(rl, bus, dev, type, &reg, start, end, count,
-	    prefetch ? RF_PREFETCHABLE : 0);
+	    flags);
+	if (pci_do_realloc_bars && res == NULL && (start != 0 || end != ~0ul)) {
+		/*
+		 * If the allocation fails, try to allocate a resource for
+		 * this BAR using any available range.  The firmware felt
+		 * it was important enough to assign a resource, so don't
+		 * disable decoding if we can help it.
+		 */
+		resource_list_delete(rl, type, reg);
+		resource_list_add(rl, type, reg, 0, ~0ul, count);
+		res = resource_list_reserve(rl, bus, dev, type, &reg, 0, ~0ul,
+		    count, flags);
+	}
 	if (res == NULL) {
 		/*
 		 * If the allocation fails, delete the resource list entry
-		 * to force pci_alloc_resource() to allocate resources
-		 * from the parent.
+		 * and disable decoding for this device.
+		 *
+		 * If the driver requests this resource in the future,
+		 * pci_reserve_map() will try to allocate a fresh
+		 * resource range.
 		 */
 		resource_list_delete(rl, type, reg);
+		pci_disable_io(dev, type);
+		if (bootverbose)
+			device_printf(bus,
+			    "pci%d:%d:%d:%d bar %#x failed to allocate\n",
+			    pci_get_domain(dev), pci_get_bus(dev),
+			    pci_get_slot(dev), pci_get_function(dev), reg);
 	} else {
 		start = rman_get_start(res);
 		pci_write_bar(dev, pm, start);
@@ -2770,7 +3091,6 @@
 pci_ata_maps(device_t bus, device_t dev, struct resource_list *rl, int force,
     uint32_t prefetchmask)
 {
-	struct resource *r;
 	int rid, type, progif;
 #if 0
 	/* if this device supports PCI native addressing use it */
@@ -2793,11 +3113,11 @@
 	} else {
 		rid = PCIR_BAR(0);
 		resource_list_add(rl, type, rid, 0x1f0, 0x1f7, 8);
-		r = resource_list_reserve(rl, bus, dev, type, &rid, 0x1f0,
+		(void)resource_list_reserve(rl, bus, dev, type, &rid, 0x1f0,
 		    0x1f7, 8, 0);
 		rid = PCIR_BAR(1);
 		resource_list_add(rl, type, rid, 0x3f6, 0x3f6, 1);
-		r = resource_list_reserve(rl, bus, dev, type, &rid, 0x3f6,
+		(void)resource_list_reserve(rl, bus, dev, type, &rid, 0x3f6,
 		    0x3f6, 1, 0);
 	}
 	if (progif & PCIP_STORAGE_IDE_MODESEC) {
@@ -2808,11 +3128,11 @@
 	} else {
 		rid = PCIR_BAR(2);
 		resource_list_add(rl, type, rid, 0x170, 0x177, 8);
-		r = resource_list_reserve(rl, bus, dev, type, &rid, 0x170,
+		(void)resource_list_reserve(rl, bus, dev, type, &rid, 0x170,
 		    0x177, 8, 0);
 		rid = PCIR_BAR(3);
 		resource_list_add(rl, type, rid, 0x376, 0x376, 1);
-		r = resource_list_reserve(rl, bus, dev, type, &rid, 0x376,
+		(void)resource_list_reserve(rl, bus, dev, type, &rid, 0x376,
 		    0x376, 1, 0);
 	}
 	pci_add_map(bus, dev, PCIR_BAR(4), rl, force,
@@ -3048,6 +3368,164 @@
 	bus_release_resource(self, SYS_RES_MEMORY, rid, res);
 }
 
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+static void
+pci_reserve_secbus(device_t bus, device_t dev, pcicfgregs *cfg,
+    struct resource_list *rl)
+{
+	struct resource *res;
+	char *cp;
+	u_long start, end, count;
+	int rid, sec_bus, sec_reg, sub_bus, sub_reg, sup_bus;
+
+	switch (cfg->hdrtype & PCIM_HDRTYPE) {
+	case PCIM_HDRTYPE_BRIDGE:
+		sec_reg = PCIR_SECBUS_1;
+		sub_reg = PCIR_SUBBUS_1;
+		break;
+	case PCIM_HDRTYPE_CARDBUS:
+		sec_reg = PCIR_SECBUS_2;
+		sub_reg = PCIR_SUBBUS_2;
+		break;
+	default:
+		return;
+	}
+
+	/*
+	 * If the existing bus range is valid, attempt to reserve it
+	 * from our parent.  If this fails for any reason, clear the
+	 * secbus and subbus registers.
+	 *
+	 * XXX: Should we reset sub_bus to sec_bus if it is < sec_bus?
+	 * This would at least preserve the existing sec_bus if it is
+	 * valid.
+	 */
+	sec_bus = PCI_READ_CONFIG(bus, dev, sec_reg, 1);
+	sub_bus = PCI_READ_CONFIG(bus, dev, sub_reg, 1);
+
+	/* Quirk handling. */
+	switch (pci_get_devid(dev)) {
+	case 0x12258086:		/* Intel 82454KX/GX (Orion) */
+		sup_bus = pci_read_config(dev, 0x41, 1);
+		if (sup_bus != 0xff) {
+			sec_bus = sup_bus + 1;
+			sub_bus = sup_bus + 1;
+			PCI_WRITE_CONFIG(bus, dev, sec_reg, sec_bus, 1);
+			PCI_WRITE_CONFIG(bus, dev, sub_reg, sub_bus, 1);
+		}
+		break;
+
+	case 0x00dd10de:
+		/* Compaq R3000 BIOS sets wrong subordinate bus number. */
+		if ((cp = getenv("smbios.planar.maker")) == NULL)
+			break;
+		if (strncmp(cp, "Compal", 6) != 0) {
+			freeenv(cp);
+			break;
+		}
+		freeenv(cp);
+		if ((cp = getenv("smbios.planar.product")) == NULL)
+			break;
+		if (strncmp(cp, "08A0", 4) != 0) {
+			freeenv(cp);
+			break;
+		}
+		freeenv(cp);
+		if (sub_bus < 0xa) {
+			sub_bus = 0xa;
+			PCI_WRITE_CONFIG(bus, dev, sub_reg, sub_bus, 1);
+		}
+		break;
+	}
+
+	if (bootverbose)
+		printf("\tsecbus=%d, subbus=%d\n", sec_bus, sub_bus);
+	if (sec_bus > 0 && sub_bus >= sec_bus) {
+		start = sec_bus;
+		end = sub_bus;
+		count = end - start + 1;
+
+		resource_list_add(rl, PCI_RES_BUS, 0, 0ul, ~0ul, count);
+
+		/*
+		 * If requested, clear secondary bus registers in
+		 * bridge devices to force a complete renumbering
+		 * rather than reserving the existing range.  However,
+		 * preserve the existing size.
+		 */
+		if (pci_clear_buses)
+			goto clear;
+
+		rid = 0;
+		res = resource_list_reserve(rl, bus, dev, PCI_RES_BUS, &rid,
+		    start, end, count, 0);
+		if (res != NULL)
+			return;
+
+		if (bootverbose)
+			device_printf(bus,
+			    "pci%d:%d:%d:%d secbus failed to allocate\n",
+			    pci_get_domain(dev), pci_get_bus(dev),
+			    pci_get_slot(dev), pci_get_function(dev));
+	}
+
+clear:
+	PCI_WRITE_CONFIG(bus, dev, sec_reg, 0, 1);
+	PCI_WRITE_CONFIG(bus, dev, sub_reg, 0, 1);
+}
+
+static struct resource *
+pci_alloc_secbus(device_t dev, device_t child, int *rid, u_long start,
+    u_long end, u_long count, u_int flags)
+{
+	struct pci_devinfo *dinfo;
+	pcicfgregs *cfg;
+	struct resource_list *rl;
+	struct resource *res;
+	int sec_reg, sub_reg;
+
+	dinfo = device_get_ivars(child);
+	cfg = &dinfo->cfg;
+	rl = &dinfo->resources;
+	switch (cfg->hdrtype & PCIM_HDRTYPE) {
+	case PCIM_HDRTYPE_BRIDGE:
+		sec_reg = PCIR_SECBUS_1;
+		sub_reg = PCIR_SUBBUS_1;
+		break;
+	case PCIM_HDRTYPE_CARDBUS:
+		sec_reg = PCIR_SECBUS_2;
+		sub_reg = PCIR_SUBBUS_2;
+		break;
+	default:
+		return (NULL);
+	}
+
+	if (*rid != 0)
+		return (NULL);
+
+	if (resource_list_find(rl, PCI_RES_BUS, *rid) == NULL)
+		resource_list_add(rl, PCI_RES_BUS, *rid, start, end, count);
+	if (!resource_list_reserved(rl, PCI_RES_BUS, *rid)) {
+		res = resource_list_reserve(rl, dev, child, PCI_RES_BUS, rid,
+		    start, end, count, flags & ~RF_ACTIVE);
+		if (res == NULL) {
+			resource_list_delete(rl, PCI_RES_BUS, *rid);
+			device_printf(child, "allocating %lu bus%s failed\n",
+			    count, count == 1 ? "" : "es");
+			return (NULL);
+		}
+		if (bootverbose)
+			device_printf(child,
+			    "Lazy allocation of %lu bus%s at %lu\n", count,
+			    count == 1 ? "" : "es", rman_get_start(res));
+		PCI_WRITE_CONFIG(dev, child, sec_reg, rman_get_start(res), 1);
+		PCI_WRITE_CONFIG(dev, child, sub_reg, rman_get_end(res), 1);
+	}
+	return (resource_list_alloc(rl, dev, child, PCI_RES_BUS, rid, start,
+	    end, count, flags));
+}
+#endif
+
 void
 pci_add_resources(device_t bus, device_t dev, int force, uint32_t prefetchmask)
 {
@@ -3120,8 +3598,29 @@
 		else if (pci_get_progif(dev) == PCIP_SERIALBUS_USB_UHCI)
 			uhci_early_takeover(dev);
 	}
+
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+	/*
+	 * Reserve resources for secondary bus ranges behind bridge
+	 * devices.
+	 */
+	pci_reserve_secbus(bus, dev, cfg, rl);
+#endif
 }
 
+static struct pci_devinfo *
+pci_identify_function(device_t pcib, device_t dev, int domain, int busno,
+    int slot, int func, size_t dinfo_size)
+{
+	struct pci_devinfo *dinfo;
+
+	dinfo = pci_read_device(pcib, domain, busno, slot, func, dinfo_size);
+	if (dinfo != NULL)
+		pci_add_child(dev, dinfo);
+
+	return (dinfo);
+}
+
 void
 pci_add_children(device_t dev, int domain, int busno, size_t dinfo_size)
 {
@@ -3131,11 +3630,29 @@
 	int maxslots;
 	int s, f, pcifunchigh;
 	uint8_t hdrtype;
+	int first_func;
 
+	/*
+	 * Try to detect a device at slot 0, function 0.  If it exists, try to
+	 * enable ARI.  We must enable ARI before detecting the rest of the
+	 * functions on this bus as ARI changes the set of slots and functions
+	 * that are legal on this bus.
+	 */
+	dinfo = pci_identify_function(pcib, dev, domain, busno, 0, 0,
+	    dinfo_size);
+	if (dinfo != NULL && pci_enable_ari)
+		PCIB_TRY_ENABLE_ARI(pcib, dinfo->cfg.dev);
+
+	/*
+	 * Start looking for new devices on slot 0 at function 1 because we
+	 * just identified the device at slot 0, function 0.
+	 */
+	first_func = 1;
+
 	KASSERT(dinfo_size >= sizeof(struct pci_devinfo),
 	    ("dinfo_size too small"));
 	maxslots = PCIB_MAXSLOTS(pcib);
-	for (s = 0; s <= maxslots; s++) {
+	for (s = 0; s <= maxslots; s++, first_func = 0) {
 		pcifunchigh = 0;
 		f = 0;
 		DELAY(1);
@@ -3143,14 +3660,10 @@
 		if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
 			continue;
 		if (hdrtype & PCIM_MFDEV)
-			pcifunchigh = PCI_FUNCMAX;
-		for (f = 0; f <= pcifunchigh; f++) {
-			dinfo = pci_read_device(pcib, domain, busno, s, f,
+			pcifunchigh = PCIB_MAXFUNCS(pcib);
+		for (f = first_func; f <= pcifunchigh; f++)
+			pci_identify_function(pcib, dev, domain, busno, s, f,
 			    dinfo_size);
-			if (dinfo != NULL) {
-				pci_add_child(dev, dinfo);
-			}
-		}
 	}
 #undef REG
 }
@@ -3165,8 +3678,15 @@
 	pci_cfg_restore(dinfo->cfg.dev, dinfo);
 	pci_print_verbose(dinfo);
 	pci_add_resources(bus, dinfo->cfg.dev, 0, 0);
+	pci_child_added(dinfo->cfg.dev);
 }
 
+void
+pci_child_added_method(device_t dev, device_t child)
+{
+
+}
+
 static int
 pci_probe(device_t dev)
 {
@@ -3185,10 +3705,22 @@
 #ifdef PCI_DMA_BOUNDARY
 	int error, tag_valid;
 #endif
+#ifdef PCI_RES_BUS
+	int rid;
+#endif
 
 	sc = device_get_softc(dev);
 	domain = pcib_get_domain(dev);
 	busno = pcib_get_bus(dev);
+#ifdef PCI_RES_BUS
+	rid = 0;
+	sc->sc_bus = bus_alloc_resource(dev, PCI_RES_BUS, &rid, busno, busno,
+	    1, 0);
+	if (sc->sc_bus == NULL) {
+		device_printf(dev, "failed to allocate bus number\n");
+		return (ENXIO);
+	}
+#endif
 	if (bootverbose)
 		device_printf(dev, "domain=%d, physical bus=%d\n",
 		    domain, busno);
@@ -3233,12 +3765,26 @@
 	return (bus_generic_attach(dev));
 }
 
+#ifdef PCI_RES_BUS
+static int
+pci_detach(device_t dev)
+{
+	struct pci_softc *sc;
+	int error;
+
+	error = bus_generic_detach(dev);
+	if (error)
+		return (error);
+	sc = device_get_softc(dev);
+	return (bus_release_resource(dev, PCI_RES_BUS, 0, sc->sc_bus));
+}
+#endif
+
 static void
 pci_set_power_children(device_t dev, device_t *devlist, int numdevs,
     int state)
 {
 	device_t child, pcib;
-	struct pci_devinfo *dinfo;
 	int dstate, i;
 
 	/*
@@ -3251,7 +3797,6 @@
 	pcib = device_get_parent(dev);
 	for (i = 0; i < numdevs; i++) {
 		child = devlist[i];
-		dinfo = device_get_ivars(child);
 		dstate = state;
 		if (device_is_attached(child) &&
 		    PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0)
@@ -3391,7 +3936,7 @@
 			pci_printf(&dinfo->cfg, "reprobing on driver added\n");
 		pci_cfg_restore(child, dinfo);
 		if (device_probe_and_attach(child) != 0)
-			pci_cfg_save(child, dinfo, 1);
+			pci_child_detached(dev, child);
 	}
 	free(devlist, M_TEMP);
 }
@@ -3467,16 +4012,32 @@
 				mv->mv_address = addr;
 				mv->mv_data = data;
 			}
-			if (mte->mte_handlers == 0) {
+
+			/*
+			 * The MSIX table entry must be made valid by
+			 * incrementing the mte_handlers before
+			 * calling pci_enable_msix() and
+			 * pci_resume_msix(). Else the MSIX rewrite
+			 * table quirk will not work as expected.
+			 */
+			mte->mte_handlers++;
+			if (mte->mte_handlers == 1) {
 				pci_enable_msix(child, rid - 1, mv->mv_address,
 				    mv->mv_data);
 				pci_unmask_msix(child, rid - 1);
 			}
-			mte->mte_handlers++;
 		}
 
-		/* Make sure that INTx is disabled if we are using MSI/MSIX */
-		pci_set_command_bit(dev, child, PCIM_CMD_INTxDIS);
+		/*
+		 * Make sure that INTx is disabled if we are using MSI/MSI-X,
+		 * unless the device is affected by PCI_QUIRK_MSI_INTX_BUG,
+		 * in which case we "enable" INTx so MSI/MSI-X actually works.
+		 */
+		if (!pci_has_quirk(pci_get_devid(child),
+		    PCI_QUIRK_MSI_INTX_BUG))
+			pci_set_command_bit(dev, child, PCIM_CMD_INTxDIS);
+		else
+			pci_clear_command_bit(dev, child, PCIM_CMD_INTxDIS);
 	bad:
 		if (error) {
 			(void)bus_generic_teardown_intr(dev, child, irq,
@@ -3568,6 +4129,7 @@
 	retval += printf(" at device %d.%d", pci_get_slot(child),
 	    pci_get_function(child));
 
+	retval += bus_print_child_domain(dev, child);
 	retval += bus_print_child_footer(dev, child);
 
 	return (retval);
@@ -3577,99 +4139,104 @@
 {
 	int		class;
 	int		subclass;
+	int		report; /* 0 = bootverbose, 1 = always */
 	const char	*desc;
 } pci_nomatch_tab[] = {
-	{PCIC_OLD,		-1,			"old"},
-	{PCIC_OLD,		PCIS_OLD_NONVGA,	"non-VGA display device"},
-	{PCIC_OLD,		PCIS_OLD_VGA,		"VGA-compatible display device"},
-	{PCIC_STORAGE,		-1,			"mass storage"},
-	{PCIC_STORAGE,		PCIS_STORAGE_SCSI,	"SCSI"},
-	{PCIC_STORAGE,		PCIS_STORAGE_IDE,	"ATA"},
-	{PCIC_STORAGE,		PCIS_STORAGE_FLOPPY,	"floppy disk"},
-	{PCIC_STORAGE,		PCIS_STORAGE_IPI,	"IPI"},
-	{PCIC_STORAGE,		PCIS_STORAGE_RAID,	"RAID"},
-	{PCIC_STORAGE,		PCIS_STORAGE_ATA_ADMA,	"ATA (ADMA)"},
-	{PCIC_STORAGE,		PCIS_STORAGE_SATA,	"SATA"},
-	{PCIC_STORAGE,		PCIS_STORAGE_SAS,	"SAS"},
-	{PCIC_STORAGE,		PCIS_STORAGE_NVM,	"NVM"},
-	{PCIC_NETWORK,		-1,			"network"},
-	{PCIC_NETWORK,		PCIS_NETWORK_ETHERNET,	"ethernet"},
-	{PCIC_NETWORK,		PCIS_NETWORK_TOKENRING,	"token ring"},
-	{PCIC_NETWORK,		PCIS_NETWORK_FDDI,	"fddi"},
-	{PCIC_NETWORK,		PCIS_NETWORK_ATM,	"ATM"},
-	{PCIC_NETWORK,		PCIS_NETWORK_ISDN,	"ISDN"},
-	{PCIC_DISPLAY,		-1,			"display"},
-	{PCIC_DISPLAY,		PCIS_DISPLAY_VGA,	"VGA"},
-	{PCIC_DISPLAY,		PCIS_DISPLAY_XGA,	"XGA"},
-	{PCIC_DISPLAY,		PCIS_DISPLAY_3D,	"3D"},
-	{PCIC_MULTIMEDIA,	-1,			"multimedia"},
-	{PCIC_MULTIMEDIA,	PCIS_MULTIMEDIA_VIDEO,	"video"},
-	{PCIC_MULTIMEDIA,	PCIS_MULTIMEDIA_AUDIO,	"audio"},
-	{PCIC_MULTIMEDIA,	PCIS_MULTIMEDIA_TELE,	"telephony"},
-	{PCIC_MULTIMEDIA,	PCIS_MULTIMEDIA_HDA,	"HDA"},
-	{PCIC_MEMORY,		-1,			"memory"},
-	{PCIC_MEMORY,		PCIS_MEMORY_RAM,	"RAM"},
-	{PCIC_MEMORY,		PCIS_MEMORY_FLASH,	"flash"},
-	{PCIC_BRIDGE,		-1,			"bridge"},
-	{PCIC_BRIDGE,		PCIS_BRIDGE_HOST,	"HOST-PCI"},
-	{PCIC_BRIDGE,		PCIS_BRIDGE_ISA,	"PCI-ISA"},
-	{PCIC_BRIDGE,		PCIS_BRIDGE_EISA,	"PCI-EISA"},
-	{PCIC_BRIDGE,		PCIS_BRIDGE_MCA,	"PCI-MCA"},
-	{PCIC_BRIDGE,		PCIS_BRIDGE_PCI,	"PCI-PCI"},
-	{PCIC_BRIDGE,		PCIS_BRIDGE_PCMCIA,	"PCI-PCMCIA"},
-	{PCIC_BRIDGE,		PCIS_BRIDGE_NUBUS,	"PCI-NuBus"},
-	{PCIC_BRIDGE,		PCIS_BRIDGE_CARDBUS,	"PCI-CardBus"},
-	{PCIC_BRIDGE,		PCIS_BRIDGE_RACEWAY,	"PCI-RACEway"},
-	{PCIC_SIMPLECOMM,	-1,			"simple comms"},
-	{PCIC_SIMPLECOMM,	PCIS_SIMPLECOMM_UART,	"UART"},	/* could detect 16550 */
-	{PCIC_SIMPLECOMM,	PCIS_SIMPLECOMM_PAR,	"parallel port"},
-	{PCIC_SIMPLECOMM,	PCIS_SIMPLECOMM_MULSER,	"multiport serial"},
-	{PCIC_SIMPLECOMM,	PCIS_SIMPLECOMM_MODEM,	"generic modem"},
-	{PCIC_BASEPERIPH,	-1,			"base peripheral"},
-	{PCIC_BASEPERIPH,	PCIS_BASEPERIPH_PIC,	"interrupt controller"},
-	{PCIC_BASEPERIPH,	PCIS_BASEPERIPH_DMA,	"DMA controller"},
-	{PCIC_BASEPERIPH,	PCIS_BASEPERIPH_TIMER,	"timer"},
-	{PCIC_BASEPERIPH,	PCIS_BASEPERIPH_RTC,	"realtime clock"},
-	{PCIC_BASEPERIPH,	PCIS_BASEPERIPH_PCIHOT,	"PCI hot-plug controller"},
-	{PCIC_BASEPERIPH,	PCIS_BASEPERIPH_SDHC,	"SD host controller"},
-	{PCIC_INPUTDEV,		-1,			"input device"},
-	{PCIC_INPUTDEV,		PCIS_INPUTDEV_KEYBOARD,	"keyboard"},
-	{PCIC_INPUTDEV,		PCIS_INPUTDEV_DIGITIZER,"digitizer"},
-	{PCIC_INPUTDEV,		PCIS_INPUTDEV_MOUSE,	"mouse"},
-	{PCIC_INPUTDEV,		PCIS_INPUTDEV_SCANNER,	"scanner"},
-	{PCIC_INPUTDEV,		PCIS_INPUTDEV_GAMEPORT,	"gameport"},
-	{PCIC_DOCKING,		-1,			"docking station"},
-	{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_SSA,	"SSA"},
-	{PCIC_SERIALBUS,	PCIS_SERIALBUS_USB,	"USB"},
-	{PCIC_SERIALBUS,	PCIS_SERIALBUS_FC,	"Fibre Channel"},
-	{PCIC_SERIALBUS,	PCIS_SERIALBUS_SMBUS,	"SMBus"},
-	{PCIC_WIRELESS,		-1,			"wireless controller"},
-	{PCIC_WIRELESS,		PCIS_WIRELESS_IRDA,	"iRDA"},
-	{PCIC_WIRELESS,		PCIS_WIRELESS_IR,	"IR"},
-	{PCIC_WIRELESS,		PCIS_WIRELESS_RF,	"RF"},
-	{PCIC_INTELLIIO,	-1,			"intelligent I/O controller"},
-	{PCIC_INTELLIIO,	PCIS_INTELLIIO_I2O,	"I2O"},
-	{PCIC_SATCOM,		-1,			"satellite communication"},
-	{PCIC_SATCOM,		PCIS_SATCOM_TV,		"sat TV"},
-	{PCIC_SATCOM,		PCIS_SATCOM_AUDIO,	"sat audio"},
-	{PCIC_SATCOM,		PCIS_SATCOM_VOICE,	"sat voice"},
-	{PCIC_SATCOM,		PCIS_SATCOM_DATA,	"sat data"},
-	{PCIC_CRYPTO,		-1,			"encrypt/decrypt"},
-	{PCIC_CRYPTO,		PCIS_CRYPTO_NETCOMP,	"network/computer crypto"},
-	{PCIC_CRYPTO,		PCIS_CRYPTO_ENTERTAIN,	"entertainment crypto"},
-	{PCIC_DASP,		-1,			"dasp"},
-	{PCIC_DASP,		PCIS_DASP_DPIO,		"DPIO module"},
-	{0, 0,		NULL}
+	{PCIC_OLD,		-1,			1, "old"},
+	{PCIC_OLD,		PCIS_OLD_NONVGA,	1, "non-VGA display device"},
+	{PCIC_OLD,		PCIS_OLD_VGA,		1, "VGA-compatible display device"},
+	{PCIC_STORAGE,		-1,			1, "mass storage"},
+	{PCIC_STORAGE,		PCIS_STORAGE_SCSI,	1, "SCSI"},
+	{PCIC_STORAGE,		PCIS_STORAGE_IDE,	1, "ATA"},
+	{PCIC_STORAGE,		PCIS_STORAGE_FLOPPY,	1, "floppy disk"},
+	{PCIC_STORAGE,		PCIS_STORAGE_IPI,	1, "IPI"},
+	{PCIC_STORAGE,		PCIS_STORAGE_RAID,	1, "RAID"},
+	{PCIC_STORAGE,		PCIS_STORAGE_ATA_ADMA,	1, "ATA (ADMA)"},
+	{PCIC_STORAGE,		PCIS_STORAGE_SATA,	1, "SATA"},
+	{PCIC_STORAGE,		PCIS_STORAGE_SAS,	1, "SAS"},
+	{PCIC_STORAGE,		PCIS_STORAGE_NVM,	1, "NVM"},
+	{PCIC_NETWORK,		-1,			1, "network"},
+	{PCIC_NETWORK,		PCIS_NETWORK_ETHERNET,	1, "ethernet"},
+	{PCIC_NETWORK,		PCIS_NETWORK_TOKENRING,	1, "token ring"},
+	{PCIC_NETWORK,		PCIS_NETWORK_FDDI,	1, "fddi"},
+	{PCIC_NETWORK,		PCIS_NETWORK_ATM,	1, "ATM"},
+	{PCIC_NETWORK,		PCIS_NETWORK_ISDN,	1, "ISDN"},
+	{PCIC_DISPLAY,		-1,			1, "display"},
+	{PCIC_DISPLAY,		PCIS_DISPLAY_VGA,	1, "VGA"},
+	{PCIC_DISPLAY,		PCIS_DISPLAY_XGA,	1, "XGA"},
+	{PCIC_DISPLAY,		PCIS_DISPLAY_3D,	1, "3D"},
+	{PCIC_MULTIMEDIA,	-1,			1, "multimedia"},
+	{PCIC_MULTIMEDIA,	PCIS_MULTIMEDIA_VIDEO,	1, "video"},
+	{PCIC_MULTIMEDIA,	PCIS_MULTIMEDIA_AUDIO,	1, "audio"},
+	{PCIC_MULTIMEDIA,	PCIS_MULTIMEDIA_TELE,	1, "telephony"},
+	{PCIC_MULTIMEDIA,	PCIS_MULTIMEDIA_HDA,	1, "HDA"},
+	{PCIC_MEMORY,		-1,			1, "memory"},
+	{PCIC_MEMORY,		PCIS_MEMORY_RAM,	1, "RAM"},
+	{PCIC_MEMORY,		PCIS_MEMORY_FLASH,	1, "flash"},
+	{PCIC_BRIDGE,		-1,			1, "bridge"},
+	{PCIC_BRIDGE,		PCIS_BRIDGE_HOST,	1, "HOST-PCI"},
+	{PCIC_BRIDGE,		PCIS_BRIDGE_ISA,	1, "PCI-ISA"},
+	{PCIC_BRIDGE,		PCIS_BRIDGE_EISA,	1, "PCI-EISA"},
+	{PCIC_BRIDGE,		PCIS_BRIDGE_MCA,	1, "PCI-MCA"},
+	{PCIC_BRIDGE,		PCIS_BRIDGE_PCI,	1, "PCI-PCI"},
+	{PCIC_BRIDGE,		PCIS_BRIDGE_PCMCIA,	1, "PCI-PCMCIA"},
+	{PCIC_BRIDGE,		PCIS_BRIDGE_NUBUS,	1, "PCI-NuBus"},
+	{PCIC_BRIDGE,		PCIS_BRIDGE_CARDBUS,	1, "PCI-CardBus"},
+	{PCIC_BRIDGE,		PCIS_BRIDGE_RACEWAY,	1, "PCI-RACEway"},
+	{PCIC_SIMPLECOMM,	-1,			1, "simple comms"},
+	{PCIC_SIMPLECOMM,	PCIS_SIMPLECOMM_UART,	1, "UART"},	/* could detect 16550 */
+	{PCIC_SIMPLECOMM,	PCIS_SIMPLECOMM_PAR,	1, "parallel port"},
+	{PCIC_SIMPLECOMM,	PCIS_SIMPLECOMM_MULSER,	1, "multiport serial"},
+	{PCIC_SIMPLECOMM,	PCIS_SIMPLECOMM_MODEM,	1, "generic modem"},
+	{PCIC_BASEPERIPH,	-1,			0, "base peripheral"},
+	{PCIC_BASEPERIPH,	PCIS_BASEPERIPH_PIC,	1, "interrupt controller"},
+	{PCIC_BASEPERIPH,	PCIS_BASEPERIPH_DMA,	1, "DMA controller"},
+	{PCIC_BASEPERIPH,	PCIS_BASEPERIPH_TIMER,	1, "timer"},
+	{PCIC_BASEPERIPH,	PCIS_BASEPERIPH_RTC,	1, "realtime clock"},
+	{PCIC_BASEPERIPH,	PCIS_BASEPERIPH_PCIHOT,	1, "PCI hot-plug controller"},
+	{PCIC_BASEPERIPH,	PCIS_BASEPERIPH_SDHC,	1, "SD host controller"},
+	{PCIC_BASEPERIPH,	PCIS_BASEPERIPH_IOMMU,	1, "IOMMU"},
+	{PCIC_INPUTDEV,		-1,			1, "input device"},
+	{PCIC_INPUTDEV,		PCIS_INPUTDEV_KEYBOARD,	1, "keyboard"},
+	{PCIC_INPUTDEV,		PCIS_INPUTDEV_DIGITIZER,1, "digitizer"},
+	{PCIC_INPUTDEV,		PCIS_INPUTDEV_MOUSE,	1, "mouse"},
+	{PCIC_INPUTDEV,		PCIS_INPUTDEV_SCANNER,	1, "scanner"},
+	{PCIC_INPUTDEV,		PCIS_INPUTDEV_GAMEPORT,	1, "gameport"},
+	{PCIC_DOCKING,		-1,			1, "docking station"},
+	{PCIC_PROCESSOR,	-1,			1, "processor"},
+	{PCIC_SERIALBUS,	-1,			1, "serial bus"},
+	{PCIC_SERIALBUS,	PCIS_SERIALBUS_FW,	1, "FireWire"},
+	{PCIC_SERIALBUS,	PCIS_SERIALBUS_ACCESS,	1, "AccessBus"},
+	{PCIC_SERIALBUS,	PCIS_SERIALBUS_SSA,	1, "SSA"},
+	{PCIC_SERIALBUS,	PCIS_SERIALBUS_USB,	1, "USB"},
+	{PCIC_SERIALBUS,	PCIS_SERIALBUS_FC,	1, "Fibre Channel"},
+	{PCIC_SERIALBUS,	PCIS_SERIALBUS_SMBUS,	0, "SMBus"},
+	{PCIC_WIRELESS,		-1,			1, "wireless controller"},
+	{PCIC_WIRELESS,		PCIS_WIRELESS_IRDA,	1, "iRDA"},
+	{PCIC_WIRELESS,		PCIS_WIRELESS_IR,	1, "IR"},
+	{PCIC_WIRELESS,		PCIS_WIRELESS_RF,	1, "RF"},
+	{PCIC_INTELLIIO,	-1,			1, "intelligent I/O controller"},
+	{PCIC_INTELLIIO,	PCIS_INTELLIIO_I2O,	1, "I2O"},
+	{PCIC_SATCOM,		-1,			1, "satellite communication"},
+	{PCIC_SATCOM,		PCIS_SATCOM_TV,		1, "sat TV"},
+	{PCIC_SATCOM,		PCIS_SATCOM_AUDIO,	1, "sat audio"},
+	{PCIC_SATCOM,		PCIS_SATCOM_VOICE,	1, "sat voice"},
+	{PCIC_SATCOM,		PCIS_SATCOM_DATA,	1, "sat data"},
+	{PCIC_CRYPTO,		-1,			1, "encrypt/decrypt"},
+	{PCIC_CRYPTO,		PCIS_CRYPTO_NETCOMP,	1, "network/computer crypto"},
+	{PCIC_CRYPTO,		PCIS_CRYPTO_ENTERTAIN,	1, "entertainment crypto"},
+	{PCIC_DASP,		-1,			0, "dasp"},
+	{PCIC_DASP,		PCIS_DASP_DPIO,		1, "DPIO module"},
+	{PCIC_DASP,		PCIS_DASP_PERFCNTRS,	1, "performance counters"},
+	{PCIC_DASP,		PCIS_DASP_COMM_SYNC,	1, "communication synchronizer"},
+	{PCIC_DASP,		PCIS_DASP_MGMT_CARD,	1, "signal processing management"},
+	{0, 0, 0,		NULL}
 };
 
 void
 pci_probe_nomatch(device_t dev, device_t child)
 {
-	int i;
+	int i, report;
 	const char *cp, *scp;
 	char *device;
 
@@ -3676,6 +4243,7 @@
 	/*
 	 * Look for a listing for this device in a loaded device database.
 	 */
+	report = 1;
 	if ((device = pci_describe_device(child)) != NULL) {
 		device_printf(dev, "<%s>", device);
 		free(device, M_DEVBUF);
@@ -3690,22 +4258,60 @@
 			if (pci_nomatch_tab[i].class == pci_get_class(child)) {
 				if (pci_nomatch_tab[i].subclass == -1) {
 					cp = pci_nomatch_tab[i].desc;
+					report = pci_nomatch_tab[i].report;
 				} else if (pci_nomatch_tab[i].subclass ==
 				    pci_get_subclass(child)) {
 					scp = pci_nomatch_tab[i].desc;
+					report = pci_nomatch_tab[i].report;
 				}
 			}
 		}
-		device_printf(dev, "<%s%s%s>",
-		    cp ? cp : "",
-		    ((cp != NULL) && (scp != NULL)) ? ", " : "",
-		    scp ? scp : "");
+		if (report || bootverbose) {
+			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 (report || bootverbose) {
+		printf(" at device %d.%d (no driver attached)\n",
+		    pci_get_slot(child), pci_get_function(child));
+	}
 	pci_cfg_save(child, device_get_ivars(child), 1);
 }
 
+void
+pci_child_detached(device_t dev, device_t child)
+{
+	struct pci_devinfo *dinfo;
+	struct resource_list *rl;
+
+	dinfo = device_get_ivars(child);
+	rl = &dinfo->resources;
+
+	/*
+	 * Have to deallocate IRQs before releasing any MSI messages and
+	 * have to release MSI messages before deallocating any memory
+	 * BARs.
+	 */
+	if (resource_list_release_active(rl, dev, child, SYS_RES_IRQ) != 0)
+		pci_printf(&dinfo->cfg, "Device leaked IRQ resources\n");
+	if (dinfo->cfg.msi.msi_alloc != 0 || dinfo->cfg.msix.msix_alloc != 0) {
+		pci_printf(&dinfo->cfg, "Device leaked MSI vectors\n");
+		(void)pci_release_msi(child);
+	}
+	if (resource_list_release_active(rl, dev, child, SYS_RES_MEMORY) != 0)
+		pci_printf(&dinfo->cfg, "Device leaked memory resources\n");
+	if (resource_list_release_active(rl, dev, child, SYS_RES_IOPORT) != 0)
+		pci_printf(&dinfo->cfg, "Device leaked I/O resources\n");
+#ifdef PCI_RES_BUS
+	if (resource_list_release_active(rl, dev, child, PCI_RES_BUS) != 0)
+		pci_printf(&dinfo->cfg, "Device leaked PCI bus numbers\n");
+#endif
+
+	pci_cfg_save(child, dinfo, 1);
+}
+
 /*
  * Parse the PCI device database, if loaded, and return a pointer to a
  * description of the device.
@@ -3902,9 +4508,17 @@
 		*result = cfg->cachelnsz;
 		break;
 	case PCI_IVAR_MINGNT:
+		if (cfg->hdrtype != PCIM_HDRTYPE_NORMAL) {
+			*result = -1;
+			return (EINVAL);
+		}
 		*result = cfg->mingnt;
 		break;
 	case PCI_IVAR_MAXLAT:
+		if (cfg->hdrtype != PCIM_HDRTYPE_NORMAL) {
+			*result = -1;
+			return (EINVAL);
+		}
 		*result = cfg->maxlat;
 		break;
 	case PCI_IVAR_LATTIMER:
@@ -4005,9 +4619,9 @@
 {
 	struct pci_devinfo *dinfo = device_get_ivars(child);
 	struct resource_list *rl = &dinfo->resources;
-	struct resource_list_entry *rle;
 	struct resource *res;
 	struct pci_map *pm;
+	uint16_t cmd;
 	pci_addr_t map, testval;
 	int mapsize;
 
@@ -4078,29 +4692,31 @@
 	 * Allocate enough resource, and then write back the
 	 * appropriate BAR for that resource.
 	 */
-	res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, type, rid,
-	    start, end, count, flags & ~RF_ACTIVE);
+	resource_list_add(rl, type, *rid, start, end, count);
+	res = resource_list_reserve(rl, dev, child, type, rid, start, end,
+	    count, flags & ~RF_ACTIVE);
 	if (res == NULL) {
+		resource_list_delete(rl, type, *rid);
 		device_printf(child,
 		    "%#lx bytes of rid %#x res %d failed (%#lx, %#lx).\n",
 		    count, *rid, type, start, end);
 		goto out;
 	}
-	resource_list_add(rl, type, *rid, start, end, count);
-	rle = resource_list_find(rl, type, *rid);
-	if (rle == NULL)
-		panic("pci_reserve_map: unexpectedly can't find resource.");
-	rle->res = res;
-	rle->start = rman_get_start(res);
-	rle->end = rman_get_end(res);
-	rle->count = count;
-	rle->flags = RLE_RESERVED;
 	if (bootverbose)
 		device_printf(child,
 		    "Lazy allocation of %#lx bytes rid %#x type %d at %#lx\n",
 		    count, *rid, type, rman_get_start(res));
+
+	/* Disable decoding via the CMD register before updating the BAR */
+	cmd = pci_read_config(child, PCIR_COMMAND, 2);
+	pci_write_config(child, PCIR_COMMAND,
+	    cmd & ~(PCI_BAR_MEM(map) ? PCIM_CMD_MEMEN : PCIM_CMD_PORTEN), 2);
+
 	map = rman_get_start(res);
 	pci_write_bar(child, pm, map);
+
+	/* Restore the original value of the CMD register */
+	pci_write_config(child, PCIR_COMMAND, cmd, 2);
 out:
 	return (res);
 }
@@ -4109,11 +4725,11 @@
 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)
 {
-	struct pci_devinfo *dinfo = device_get_ivars(child);
-	struct resource_list *rl = &dinfo->resources;
+	struct pci_devinfo *dinfo;
+	struct resource_list *rl;
 	struct resource_list_entry *rle;
 	struct resource *res;
-	pcicfgregs *cfg = &dinfo->cfg;
+	pcicfgregs *cfg;
 
 	if (device_get_parent(child) != dev)
 		return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
@@ -4122,7 +4738,15 @@
 	/*
 	 * Perform lazy resource allocation
 	 */
+	dinfo = device_get_ivars(child);
+	rl = &dinfo->resources;
+	cfg = &dinfo->cfg;
 	switch (type) {
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+	case PCI_RES_BUS:
+		return (pci_alloc_secbus(dev, child, rid, start, end, count,
+		    flags));
+#endif
 	case SYS_RES_IRQ:
 		/*
 		 * Can't alloc legacy interrupt once MSI messages have
@@ -4177,6 +4801,41 @@
 }
 
 int
+pci_release_resource(device_t dev, device_t child, int type, int rid,
+    struct resource *r)
+{
+	struct pci_devinfo *dinfo;
+	struct resource_list *rl;
+	pcicfgregs *cfg;
+
+	if (device_get_parent(child) != dev)
+		return (BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
+		    type, rid, r));
+
+	dinfo = device_get_ivars(child);
+	cfg = &dinfo->cfg;
+#ifdef NEW_PCIB
+	/*
+	 * PCI-PCI bridge I/O window resources are not BARs.  For
+	 * those allocations just pass the request up the tree.
+	 */
+	if (cfg->hdrtype == PCIM_HDRTYPE_BRIDGE &&
+	    (type == SYS_RES_IOPORT || type == SYS_RES_MEMORY)) {
+		switch (rid) {
+		case PCIR_IOBASEL_1:
+		case PCIR_MEMBASE_1:
+		case PCIR_PMBASEL_1:
+			return (bus_generic_release_resource(dev, child, type,
+			    rid, r));
+		}
+	}
+#endif
+
+	rl = &dinfo->resources;
+	return (resource_list_release(rl, dev, child, type, rid, r));
+}
+
+int
 pci_activate_resource(device_t dev, device_t child, int type, int rid,
     struct resource *r)
 {
@@ -4226,7 +4885,7 @@
 }
 
 void
-pci_delete_child(device_t dev, device_t child)
+pci_child_deleted(device_t dev, device_t child)
 {
 	struct resource_list_entry *rle;
 	struct resource_list *rl;
@@ -4235,13 +4894,14 @@
 	dinfo = device_get_ivars(child);
 	rl = &dinfo->resources;
 
-	if (device_is_attached(child))
-		device_detach(child);
-
 	/* Turn off access to resources we're about to free */
-	pci_write_config(child, PCIR_COMMAND, pci_read_config(child,
-	    PCIR_COMMAND, 2) & ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN), 2);
+	if (bus_child_present(child) != 0) {
+		pci_write_config(child, PCIR_COMMAND, pci_read_config(child,
+		    PCIR_COMMAND, 2) & ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN), 2);
 
+		pci_disable_busmaster(child);
+	}
+
 	/* Free all allocated resources */
 	STAILQ_FOREACH(rle, rl, link) {
 		if (rle->res) {
@@ -4261,11 +4921,20 @@
 	}
 	resource_list_free(rl);
 
-	device_delete_child(dev, child);
 	pci_freecfg(dinfo);
 }
 
+/* KBI compatability shim. */
+extern void pci_delete_child(device_t dev, device_t child);
+
 void
+pci_delete_child(device_t dev, device_t child)
+{
+
+	device_delete_child (dev, child);
+}
+
+void
 pci_delete_resource(device_t dev, device_t child, int type, int rid)
 {
 	struct pci_devinfo *dinfo;
@@ -4337,8 +5006,9 @@
     size_t buflen)
 {
 
-	snprintf(buf, buflen, "slot=%d function=%d", pci_get_slot(child),
-	    pci_get_function(child));
+	snprintf(buf, buflen, "slot=%d function=%d dbsf=pci%d:%d:%d:%d",
+	    pci_get_slot(child), pci_get_function(child), pci_get_domain(child),
+	    pci_get_bus(child), pci_get_slot(child), pci_get_function(child));
 	return (0);
 }
 
@@ -4368,10 +5038,60 @@
 	    cfg->intpin));
 }
 
+static void
+pci_lookup(void *arg, const char *name, device_t *dev)
+{
+	long val;
+	char *end;
+	int domain, bus, slot, func;
+
+	if (*dev != NULL)
+		return;
+
+	/*
+	 * Accept pciconf-style selectors of either pciD:B:S:F or
+	 * pciB:S:F.  In the latter case, the domain is assumed to
+	 * be zero.
+	 */
+	if (strncmp(name, "pci", 3) != 0)
+		return;
+	val = strtol(name + 3, &end, 10);
+	if (val < 0 || val > INT_MAX || *end != ':')
+		return;
+	domain = val;
+	val = strtol(end + 1, &end, 10);
+	if (val < 0 || val > INT_MAX || *end != ':')
+		return;
+	bus = val;
+	val = strtol(end + 1, &end, 10);
+	if (val < 0 || val > INT_MAX)
+		return;
+	slot = val;
+	if (*end == ':') {
+		val = strtol(end + 1, &end, 10);
+		if (val < 0 || val > INT_MAX || *end != '\0')
+			return;
+		func = val;
+	} else if (*end == '\0') {
+		func = slot;
+		slot = bus;
+		bus = domain;
+		domain = 0;
+	} else
+		return;
+
+	if (domain > PCI_DOMAINMAX || bus > PCI_BUSMAX || slot > PCI_SLOTMAX ||
+	    func > PCIE_ARI_FUNCMAX || (slot != 0 && func > PCI_FUNCMAX))
+		return;
+
+	*dev = pci_find_dbsf(domain, bus, slot, func);
+}
+
 static int
 pci_modevent(module_t mod, int what, void *arg)
 {
 	static struct cdev *pci_cdev;
+	static eventhandler_tag tag;
 
 	switch (what) {
 	case MOD_LOAD:
@@ -4380,9 +5100,13 @@
 		pci_cdev = make_dev(&pcicdev, 0, UID_ROOT, GID_WHEEL, 0644,
 		    "pci");
 		pci_load_vendor_data();
+		tag = EVENTHANDLER_REGISTER(dev_lookup, pci_lookup, NULL,
+		    1000);
 		break;
 
 	case MOD_UNLOAD:
+		if (tag != NULL)
+			EVENTHANDLER_DEREGISTER(dev_lookup, tag);
 		destroy_dev(pci_cdev);
 		break;
 	}
@@ -4390,6 +5114,49 @@
 	return (0);
 }
 
+static void
+pci_cfg_restore_pcie(device_t dev, struct pci_devinfo *dinfo)
+{
+#define	WREG(n, v)	pci_write_config(dev, pos + (n), (v), 2)
+	struct pcicfg_pcie *cfg;
+	int version, pos;
+
+	cfg = &dinfo->cfg.pcie;
+	pos = cfg->pcie_location;
+
+	version = cfg->pcie_flags & PCIEM_FLAGS_VERSION;
+
+	WREG(PCIER_DEVICE_CTL, cfg->pcie_device_ctl);
+
+	if (version > 1 || cfg->pcie_type == PCIEM_TYPE_ROOT_PORT ||
+	    cfg->pcie_type == PCIEM_TYPE_ENDPOINT ||
+	    cfg->pcie_type == PCIEM_TYPE_LEGACY_ENDPOINT)
+		WREG(PCIER_LINK_CTL, cfg->pcie_link_ctl);
+
+	if (version > 1 || (cfg->pcie_type == PCIEM_TYPE_ROOT_PORT ||
+	    (cfg->pcie_type == PCIEM_TYPE_DOWNSTREAM_PORT &&
+	     (cfg->pcie_flags & PCIEM_FLAGS_SLOT))))
+		WREG(PCIER_SLOT_CTL, cfg->pcie_slot_ctl);
+
+	if (version > 1 || cfg->pcie_type == PCIEM_TYPE_ROOT_PORT ||
+	    cfg->pcie_type == PCIEM_TYPE_ROOT_EC)
+		WREG(PCIER_ROOT_CTL, cfg->pcie_root_ctl);
+
+	if (version > 1) {
+		WREG(PCIER_DEVICE_CTL2, cfg->pcie_device_ctl2);
+		WREG(PCIER_LINK_CTL2, cfg->pcie_link_ctl2);
+		WREG(PCIER_SLOT_CTL2, cfg->pcie_slot_ctl2);
+	}
+#undef WREG
+}
+
+static void
+pci_cfg_restore_pcix(device_t dev, struct pci_devinfo *dinfo)
+{
+	pci_write_config(dev, dinfo->cfg.pcix.pcix_location + PCIXR_COMMAND,
+	    dinfo->cfg.pcix.pcix_command,  2);
+}
+
 void
 pci_cfg_restore(device_t dev, struct pci_devinfo *dinfo)
 {
@@ -4425,6 +5192,14 @@
 	pci_write_config(dev, PCIR_PROGIF, dinfo->cfg.progif, 1);
 	pci_write_config(dev, PCIR_REVID, dinfo->cfg.revid, 1);
 
+	/*
+	 * Restore extended capabilities for PCI-Express and PCI-X
+	 */
+	if (dinfo->cfg.pcie.pcie_location != 0)
+		pci_cfg_restore_pcie(dev, dinfo);
+	if (dinfo->cfg.pcix.pcix_location != 0)
+		pci_cfg_restore_pcix(dev, dinfo);
+
 	/* Restore MSI and MSI-X configurations if they are present. */
 	if (dinfo->cfg.msi.msi_location != 0)
 		pci_resume_msi(dev);
@@ -4432,6 +5207,51 @@
 		pci_resume_msix(dev);
 }
 
+static void
+pci_cfg_save_pcie(device_t dev, struct pci_devinfo *dinfo)
+{
+#define	RREG(n)	pci_read_config(dev, pos + (n), 2)
+	struct pcicfg_pcie *cfg;
+	int version, pos;
+
+	cfg = &dinfo->cfg.pcie;
+	pos = cfg->pcie_location;
+
+	cfg->pcie_flags = RREG(PCIER_FLAGS);
+
+	version = cfg->pcie_flags & PCIEM_FLAGS_VERSION;
+
+	cfg->pcie_device_ctl = RREG(PCIER_DEVICE_CTL);
+
+	if (version > 1 || cfg->pcie_type == PCIEM_TYPE_ROOT_PORT ||
+	    cfg->pcie_type == PCIEM_TYPE_ENDPOINT ||
+	    cfg->pcie_type == PCIEM_TYPE_LEGACY_ENDPOINT)
+		cfg->pcie_link_ctl = RREG(PCIER_LINK_CTL);
+
+	if (version > 1 || (cfg->pcie_type == PCIEM_TYPE_ROOT_PORT ||
+	    (cfg->pcie_type == PCIEM_TYPE_DOWNSTREAM_PORT &&
+	     (cfg->pcie_flags & PCIEM_FLAGS_SLOT))))
+		cfg->pcie_slot_ctl = RREG(PCIER_SLOT_CTL);
+
+	if (version > 1 || cfg->pcie_type == PCIEM_TYPE_ROOT_PORT ||
+	    cfg->pcie_type == PCIEM_TYPE_ROOT_EC)
+		cfg->pcie_root_ctl = RREG(PCIER_ROOT_CTL);
+
+	if (version > 1) {
+		cfg->pcie_device_ctl2 = RREG(PCIER_DEVICE_CTL2);
+		cfg->pcie_link_ctl2 = RREG(PCIER_LINK_CTL2);
+		cfg->pcie_slot_ctl2 = RREG(PCIER_SLOT_CTL2);
+	}
+#undef RREG
+}
+
+static void
+pci_cfg_save_pcix(device_t dev, struct pci_devinfo *dinfo)
+{
+	dinfo->cfg.pcix.pcix_command = pci_read_config(dev,
+	    dinfo->cfg.pcix.pcix_location + PCIXR_COMMAND, 2);
+}
+
 void
 pci_cfg_save(device_t dev, struct pci_devinfo *dinfo, int setstate)
 {
@@ -4474,6 +5294,12 @@
 	dinfo->cfg.progif = pci_read_config(dev, PCIR_PROGIF, 1);
 	dinfo->cfg.revid = pci_read_config(dev, PCIR_REVID, 1);
 
+	if (dinfo->cfg.pcie.pcie_location != 0)
+		pci_cfg_save_pcie(dev, dinfo);
+
+	if (dinfo->cfg.pcix.pcix_location != 0)
+		pci_cfg_save_pcix(dev, dinfo);
+
 	/*
 	 * don't set the state for display devices, base peripherals and
 	 * memory devices since bad things happen when they are powered down.
@@ -4530,3 +5356,213 @@
 	dinfo = device_get_ivars(dev);
 	pci_cfg_restore(dev, dinfo);
 }
+
+static uint16_t
+pci_get_rid_method(device_t dev, device_t child)
+{
+
+	return (PCIB_GET_RID(device_get_parent(dev), child));
+}
+
+/* Find the upstream port of a given PCI device in a root complex. */
+device_t
+pci_find_pcie_root_port(device_t dev)
+{
+	struct pci_devinfo *dinfo;
+	devclass_t pci_class;
+	device_t pcib, bus;
+
+	pci_class = devclass_find("pci");
+	KASSERT(device_get_devclass(device_get_parent(dev)) == pci_class,
+	    ("%s: non-pci device %s", __func__, device_get_nameunit(dev)));
+
+	/*
+	 * Walk the bridge hierarchy until we find a PCI-e root
+	 * port or a non-PCI device.
+	 */
+	for (;;) {
+		bus = device_get_parent(dev);
+		KASSERT(bus != NULL, ("%s: null parent of %s", __func__,
+		    device_get_nameunit(dev)));
+
+		pcib = device_get_parent(bus);
+		KASSERT(pcib != NULL, ("%s: null bridge of %s", __func__,
+		    device_get_nameunit(bus)));
+
+		/*
+		 * pcib's parent must be a PCI bus for this to be a
+		 * PCI-PCI bridge.
+		 */
+		if (device_get_devclass(device_get_parent(pcib)) != pci_class)
+			return (NULL);
+
+		dinfo = device_get_ivars(pcib);
+		if (dinfo->cfg.pcie.pcie_location != 0 &&
+		    dinfo->cfg.pcie.pcie_type == PCIEM_TYPE_ROOT_PORT)
+			return (pcib);
+
+		dev = pcib;
+	}
+}
+
+/*
+ * Wait for pending transactions to complete on a PCI-express function.
+ *
+ * The maximum delay is specified in milliseconds in max_delay.  Note
+ * that this function may sleep.
+ *
+ * Returns true if the function is idle and false if the timeout is
+ * exceeded.  If dev is not a PCI-express function, this returns true.
+ */
+bool
+pcie_wait_for_pending_transactions(device_t dev, u_int max_delay)
+{
+	struct pci_devinfo *dinfo = device_get_ivars(dev);
+	uint16_t sta;
+	int cap;
+
+	cap = dinfo->cfg.pcie.pcie_location;
+	if (cap == 0)
+		return (true);
+
+	sta = pci_read_config(dev, cap + PCIER_DEVICE_STA, 2);
+	while (sta & PCIEM_STA_TRANSACTION_PND) {
+		if (max_delay == 0)
+			return (false);
+
+		/* Poll once every 100 milliseconds up to the timeout. */
+		if (max_delay > 100) {
+			pause_sbt("pcietp", 100 * SBT_1MS, 0, C_HARDCLOCK);
+			max_delay -= 100;
+		} else {
+			pause_sbt("pcietp", max_delay * SBT_1MS, 0,
+			    C_HARDCLOCK);
+			max_delay = 0;
+		}
+		sta = pci_read_config(dev, cap + PCIER_DEVICE_STA, 2);
+	}
+
+	return (true);
+}
+
+/*
+ * Determine the maximum Completion Timeout in microseconds.
+ *
+ * For non-PCI-express functions this returns 0.
+ */
+int
+pcie_get_max_completion_timeout(device_t dev)
+{
+	struct pci_devinfo *dinfo = device_get_ivars(dev);
+	int cap;
+
+	cap = dinfo->cfg.pcie.pcie_location;
+	if (cap == 0)
+		return (0);
+
+	/*
+	 * Functions using the 1.x spec use the default timeout range of
+	 * 50 microseconds to 50 milliseconds.  Functions that do not
+	 * support programmable timeouts also use this range.
+	 */
+	if ((dinfo->cfg.pcie.pcie_flags & PCIEM_FLAGS_VERSION) < 2 ||
+	    (pci_read_config(dev, cap + PCIER_DEVICE_CAP2, 4) &
+	    PCIEM_CAP2_COMP_TIMO_RANGES) == 0)
+		return (50 * 1000);
+
+	switch (pci_read_config(dev, cap + PCIER_DEVICE_CTL2, 2) &
+	    PCIEM_CTL2_COMP_TIMO_VAL) {
+	case PCIEM_CTL2_COMP_TIMO_100US:
+		return (100);
+	case PCIEM_CTL2_COMP_TIMO_10MS:
+		return (10 * 1000);
+	case PCIEM_CTL2_COMP_TIMO_55MS:
+		return (55 * 1000);
+	case PCIEM_CTL2_COMP_TIMO_210MS:
+		return (210 * 1000);
+	case PCIEM_CTL2_COMP_TIMO_900MS:
+		return (900 * 1000);
+	case PCIEM_CTL2_COMP_TIMO_3500MS:
+		return (3500 * 1000);
+	case PCIEM_CTL2_COMP_TIMO_13S:
+		return (13 * 1000 * 1000);
+	case PCIEM_CTL2_COMP_TIMO_64S:
+		return (64 * 1000 * 1000);
+	default:
+		return (50 * 1000);
+	}
+}
+
+/*
+ * Perform a Function Level Reset (FLR) on a device.
+ *
+ * This function first waits for any pending transactions to complete
+ * within the timeout specified by max_delay.  If transactions are
+ * still pending, the function will return false without attempting a
+ * reset.
+ *
+ * If dev is not a PCI-express function or does not support FLR, this
+ * function returns false.
+ *
+ * Note that no registers are saved or restored.  The caller is
+ * responsible for saving and restoring any registers including
+ * PCI-standard registers via pci_save_state() and
+ * pci_restore_state().
+ */
+bool
+pcie_flr(device_t dev, u_int max_delay, bool force)
+{
+	struct pci_devinfo *dinfo = device_get_ivars(dev);
+	uint16_t cmd, ctl;
+	int compl_delay;
+	int cap;
+
+	cap = dinfo->cfg.pcie.pcie_location;
+	if (cap == 0)
+		return (false);
+
+	if (!(pci_read_config(dev, cap + PCIER_DEVICE_CAP, 4) & PCIEM_CAP_FLR))
+		return (false);
+
+	/*
+	 * Disable busmastering to prevent generation of new
+	 * transactions while waiting for the device to go idle.  If
+	 * the idle timeout fails, the command register is restored
+	 * which will re-enable busmastering.
+	 */
+	cmd = pci_read_config(dev, PCIR_COMMAND, 2);
+	pci_write_config(dev, PCIR_COMMAND, cmd & ~(PCIM_CMD_BUSMASTEREN), 2);
+	if (!pcie_wait_for_pending_transactions(dev, max_delay)) {
+		if (!force) {
+			pci_write_config(dev, PCIR_COMMAND, cmd, 2);
+			return (false);
+		}
+		pci_printf(&dinfo->cfg,
+		    "Resetting with transactions pending after %d ms\n",
+		    max_delay);
+
+		/*
+		 * Extend the post-FLR delay to cover the maximum
+		 * Completion Timeout delay of anything in flight
+		 * during the FLR delay.  Enforce a minimum delay of
+		 * at least 10ms.
+		 */
+		compl_delay = pcie_get_max_completion_timeout(dev) / 1000;
+		if (compl_delay < 10)
+			compl_delay = 10;
+	} else
+		compl_delay = 0;
+
+	/* Initiate the reset. */
+	ctl = pci_read_config(dev, cap + PCIER_DEVICE_CTL, 2);
+	pci_write_config(dev, cap + PCIER_DEVICE_CTL, ctl |
+	    PCIEM_CTL_INITIATE_FLR, 2);
+
+	/* Wait for 100ms. */
+	pause_sbt("pcieflr", (100 + compl_delay) * SBT_1MS, 0, C_HARDCLOCK);
+
+	if (pci_read_config(dev, cap + PCIER_DEVICE_STA, 2) &
+	    PCIEM_STA_TRANSACTION_PND)
+		pci_printf(&dinfo->cfg, "Transactions pending after FLR!\n");
+	return (true);
+}

Modified: trunk/sys/dev/pci/pci_if.m
===================================================================
--- trunk/sys/dev/pci/pci_if.m	2018-05-27 23:27:48 UTC (rev 10086)
+++ trunk/sys/dev/pci/pci_if.m	2018-05-27 23:28:52 UTC (rev 10087)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 #-
 # Copyright (c) 1998 Doug Rabson
 # All rights reserved.
@@ -23,7 +24,7 @@
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-# $MidnightBSD$
+# $FreeBSD: stable/10/sys/dev/pci/pci_if.m 294340 2016-01-19 21:08:31Z jhb $
 #
 
 #include <sys/bus.h>
@@ -36,6 +37,12 @@
 	{
 		return (0);
 	}
+
+	static int
+	null_msix_bar(device_t dev, device_t child)
+	{
+		return (-1);
+	}
 };
 
 
@@ -105,6 +112,13 @@
 	device_t	child;
 };
 
+METHOD int find_cap {
+	device_t	dev;
+	device_t	child;
+	int		capability;
+	int		*capreg;
+};
+
 METHOD int find_extcap {
 	device_t	dev;
 	device_t	child;
@@ -112,6 +126,13 @@
 	int		*capreg;
 };
 
+METHOD int find_htcap {
+	device_t	dev;
+	device_t	child;
+	int		capability;
+	int		*capreg;
+};
+
 METHOD int alloc_msi {
 	device_t	dev;
 	device_t	child;
@@ -124,6 +145,26 @@
 	int		*count;
 };
 
+METHOD void enable_msi {
+	device_t	dev;
+	device_t	child;
+	uint64_t	address;
+	uint16_t	data;
+};
+
+METHOD void enable_msix {
+	device_t	dev;
+	device_t	child;
+	u_int		index;
+	uint64_t	address;
+	uint32_t	data;
+};
+
+METHOD void disable_msi {
+	device_t	dev;
+	device_t	child;
+};
+
 METHOD int remap_msix {
 	device_t	dev;
 	device_t	child;
@@ -145,3 +186,23 @@
 	device_t	dev;
 	device_t	child;
 } DEFAULT null_msi_count;
+
+METHOD int msix_pba_bar {
+	device_t	dev;
+	device_t	child;
+} DEFAULT null_msix_bar;
+
+METHOD int msix_table_bar {
+	device_t	dev;
+	device_t	child;
+} DEFAULT null_msix_bar;
+
+METHOD uint16_t get_rid {
+	device_t	dev;
+	device_t	child;
+};
+
+METHOD void child_added {
+	device_t	dev;
+	device_t	child;
+};


Property changes on: trunk/sys/dev/pci/pci_if.m
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/sys/dev/pci/pci_pci.c
===================================================================
--- trunk/sys/dev/pci/pci_pci.c	2018-05-27 23:27:48 UTC (rev 10086)
+++ trunk/sys/dev/pci/pci_pci.c	2018-05-27 23:28:52 UTC (rev 10087)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier
  * Copyright (c) 2000 Michael Smith <msmith at freebsd.org>
@@ -29,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/pci/pci_pci.c 285863 2015-07-25 00:14:02Z jhb $");
 
 /*
  * PCI:PCI bridge support.
@@ -56,6 +57,14 @@
 static int		pcib_resume(device_t dev);
 static int		pcib_power_for_sleep(device_t pcib, device_t dev,
 			    int *pstate);
+static uint16_t		pcib_ari_get_rid(device_t pcib, device_t dev);
+static uint32_t		pcib_read_config(device_t dev, u_int b, u_int s, 
+    u_int f, u_int reg, int width);
+static void		pcib_write_config(device_t dev, u_int b, u_int s,
+    u_int f, u_int reg, uint32_t val, int width);
+static int		pcib_ari_maxslots(device_t dev);
+static int		pcib_ari_maxfuncs(device_t dev);
+static int		pcib_try_enable_ari(device_t pcib, device_t dev);
 
 static device_method_t pcib_methods[] = {
     /* Device interface */
@@ -83,7 +92,8 @@
     DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
 
     /* pcib interface */
-    DEVMETHOD(pcib_maxslots,		pcib_maxslots),
+    DEVMETHOD(pcib_maxslots,		pcib_ari_maxslots),
+    DEVMETHOD(pcib_maxfuncs,		pcib_ari_maxfuncs),
     DEVMETHOD(pcib_read_config,		pcib_read_config),
     DEVMETHOD(pcib_write_config,	pcib_write_config),
     DEVMETHOD(pcib_route_interrupt,	pcib_route_interrupt),
@@ -93,6 +103,8 @@
     DEVMETHOD(pcib_release_msix,	pcib_release_msix),
     DEVMETHOD(pcib_map_msi,		pcib_map_msi),
     DEVMETHOD(pcib_power_for_sleep,	pcib_power_for_sleep),
+    DEVMETHOD(pcib_get_rid,		pcib_ari_get_rid),
+    DEVMETHOD(pcib_try_enable_ari,	pcib_try_enable_ari),
 
     DEVMETHOD_END
 };
@@ -100,17 +112,16 @@
 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);
+DRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, NULL, NULL);
 
 #ifdef NEW_PCIB
-/*
- * XXX Todo:
- * - properly handle the ISA enable bit.  If it is set, we should change
- *   the behavior of the I/O window resource and rman to not allocate the
- *   blocked ranges (upper 768 bytes of each 1K in the first 64k of the
- *   I/O port address space).
- */
+SYSCTL_DECL(_hw_pci);
 
+static int pci_clear_pcib;
+TUNABLE_INT("hw.pci.clear_pcib", &pci_clear_pcib);
+SYSCTL_INT(_hw_pci, OID_AUTO, clear_pcib, CTLFLAG_RDTUN, &pci_clear_pcib, 0,
+    "Clear firmware-assigned resources for PCI-PCI bridge I/O windows.");
+
 /*
  * Is a resource from a child device sub-allocated from one of our
  * resource managers?
@@ -120,6 +131,10 @@
 {
 
 	switch (type) {
+#ifdef PCI_RES_BUS
+	case PCI_RES_BUS:
+		return (rman_is_region_manager(r, &sc->bus.rman));
+#endif
 	case SYS_RES_IOPORT:
 		return (rman_is_region_manager(r, &sc->io.rman));
 	case SYS_RES_MEMORY:
@@ -189,10 +204,183 @@
 	}
 }
 
+/*
+ * This is used to reject I/O port allocations that conflict with an
+ * ISA alias range.
+ */
+static int
+pcib_is_isa_range(struct pcib_softc *sc, u_long start, u_long end, u_long count)
+{
+	u_long next_alias;
+
+	if (!(sc->bridgectl & PCIB_BCR_ISA_ENABLE))
+		return (0);
+
+	/* Only check fixed ranges for overlap. */
+	if (start + count - 1 != end)
+		return (0);
+
+	/* ISA aliases are only in the lower 64KB of I/O space. */
+	if (start >= 65536)
+		return (0);
+
+	/* Check for overlap with 0x000 - 0x0ff as a special case. */
+	if (start < 0x100)
+		goto alias;
+
+	/*
+	 * If the start address is an alias, the range is an alias.
+	 * Otherwise, compute the start of the next alias range and
+	 * check if it is before the end of the candidate range.
+	 */
+	if ((start & 0x300) != 0)
+		goto alias;
+	next_alias = (start & ~0x3fful) | 0x100;
+	if (next_alias <= end)
+		goto alias;
+	return (0);
+
+alias:
+	if (bootverbose)
+		device_printf(sc->dev,
+		    "I/O range %#lx-%#lx overlaps with an ISA alias\n", start,
+		    end);
+	return (1);
+}
+
 static void
+pcib_add_window_resources(struct pcib_window *w, struct resource **res,
+    int count)
+{
+	struct resource **newarray;
+	int error, i;
+
+	newarray = malloc(sizeof(struct resource *) * (w->count + count),
+	    M_DEVBUF, M_WAITOK);
+	if (w->res != NULL)
+		bcopy(w->res, newarray, sizeof(struct resource *) * w->count);
+	bcopy(res, newarray + w->count, sizeof(struct resource *) * count);
+	free(w->res, M_DEVBUF);
+	w->res = newarray;
+	w->count += count;
+	
+	for (i = 0; i < count; i++) {
+		error = rman_manage_region(&w->rman, rman_get_start(res[i]),
+		    rman_get_end(res[i]));
+		if (error)
+			panic("Failed to add resource to rman");
+	}
+}
+
+typedef void (nonisa_callback)(u_long start, u_long end, void *arg);
+
+static void
+pcib_walk_nonisa_ranges(u_long start, u_long end, nonisa_callback *cb,
+    void *arg)
+{
+	u_long next_end;
+
+	/*
+	 * If start is within an ISA alias range, move up to the start
+	 * of the next non-alias range.  As a special case, addresses
+	 * in the range 0x000 - 0x0ff should also be skipped since
+	 * those are used for various system I/O devices in ISA
+	 * systems.
+	 */
+	if (start <= 65535) {
+		if (start < 0x100 || (start & 0x300) != 0) {
+			start &= ~0x3ff;
+			start += 0x400;
+		}
+	}
+
+	/* ISA aliases are only in the lower 64KB of I/O space. */
+	while (start <= MIN(end, 65535)) {
+		next_end = MIN(start | 0xff, end);
+		cb(start, next_end, arg);
+		start += 0x400;
+	}
+
+	if (start <= end)
+		cb(start, end, arg);
+}
+
+static void
+count_ranges(u_long start, u_long end, void *arg)
+{
+	int *countp;
+
+	countp = arg;
+	(*countp)++;
+}
+
+struct alloc_state {
+	struct resource **res;
+	struct pcib_softc *sc;
+	int count, error;
+};
+
+static void
+alloc_ranges(u_long start, u_long end, void *arg)
+{
+	struct alloc_state *as;
+	struct pcib_window *w;
+	int rid;
+
+	as = arg;
+	if (as->error != 0)
+		return;
+
+	w = &as->sc->io;
+	rid = w->reg;
+	if (bootverbose)
+		device_printf(as->sc->dev,
+		    "allocating non-ISA range %#lx-%#lx\n", start, end);
+	as->res[as->count] = bus_alloc_resource(as->sc->dev, SYS_RES_IOPORT,
+	    &rid, start, end, end - start + 1, 0);
+	if (as->res[as->count] == NULL)
+		as->error = ENXIO;
+	else
+		as->count++;
+}
+
+static int
+pcib_alloc_nonisa_ranges(struct pcib_softc *sc, u_long start, u_long end)
+{
+	struct alloc_state as;
+	int i, new_count;
+
+	/* First, see how many ranges we need. */
+	new_count = 0;
+	pcib_walk_nonisa_ranges(start, end, count_ranges, &new_count);
+
+	/* Second, allocate the ranges. */
+	as.res = malloc(sizeof(struct resource *) * new_count, M_DEVBUF,
+	    M_WAITOK);
+	as.sc = sc;
+	as.count = 0;
+	as.error = 0;
+	pcib_walk_nonisa_ranges(start, end, alloc_ranges, &as);
+	if (as.error != 0) {
+		for (i = 0; i < as.count; i++)
+			bus_release_resource(sc->dev, SYS_RES_IOPORT,
+			    sc->io.reg, as.res[i]);
+		free(as.res, M_DEVBUF);
+		return (as.error);
+	}
+	KASSERT(as.count == new_count, ("%s: count mismatch", __func__));
+
+	/* Third, add the ranges to the window. */
+	pcib_add_window_resources(&sc->io, as.res, as.count);
+	free(as.res, M_DEVBUF);
+	return (0);
+}
+
+static void
 pcib_alloc_window(struct pcib_softc *sc, struct pcib_window *w, int type,
     int flags, pci_addr_t max_address)
 {
+	struct resource *res;
 	char buf[64];
 	int error, rid;
 
@@ -217,9 +405,15 @@
 		    "initial %s window has too many bits, ignoring\n", w->name);
 		return;
 	}
-	rid = w->reg;
-	w->res = bus_alloc_resource(sc->dev, type, &rid, w->base, w->limit,
-	    w->limit - w->base + 1, flags);
+	if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE)
+		(void)pcib_alloc_nonisa_ranges(sc, w->base, w->limit);
+	else {
+		rid = w->reg;
+		res = bus_alloc_resource(sc->dev, type, &rid, w->base, w->limit,
+		    w->limit - w->base + 1, flags);
+		if (res != NULL)
+			pcib_add_window_resources(w, &res, 1);
+	}
 	if (w->res == NULL) {
 		device_printf(sc->dev,
 		    "failed to allocate initial %s window: %#jx-%#jx\n",
@@ -230,11 +424,6 @@
 		return;
 	}
 	pcib_activate_window(sc, type);
-
-	error = rman_manage_region(&w->rman, rman_get_start(w->res),
-	    rman_get_end(w->res));
-	if (error)
-		panic("Failed to initialize rman with resource");
 }
 
 /*
@@ -249,6 +438,19 @@
 
 	dev = sc->dev;
 
+	if (pci_clear_pcib) {
+		pci_write_config(dev, PCIR_IOBASEL_1, 0xff, 1);
+		pci_write_config(dev, PCIR_IOBASEH_1, 0xffff, 2);
+		pci_write_config(dev, PCIR_IOLIMITL_1, 0, 1);
+		pci_write_config(dev, PCIR_IOLIMITH_1, 0, 2);
+		pci_write_config(dev, PCIR_MEMBASE_1, 0xffff, 2);
+		pci_write_config(dev, PCIR_MEMLIMIT_1, 0, 2);
+		pci_write_config(dev, PCIR_PMBASEL_1, 0xffff, 2);
+		pci_write_config(dev, PCIR_PMBASEH_1, 0xffffffff, 4);
+		pci_write_config(dev, PCIR_PMLIMITL_1, 0, 2);
+		pci_write_config(dev, PCIR_PMLIMITH_1, 0, 4);
+	}
+
 	/* Determine if the I/O port window is implemented. */
 	val = pci_read_config(dev, PCIR_IOBASEL_1, 1);
 	if (val == 0) {
@@ -337,6 +539,173 @@
 	}
 }
 
+#ifdef PCI_RES_BUS
+/*
+ * Allocate a suitable secondary bus for this bridge if needed and
+ * initialize the resource manager for the secondary bus range.  Note
+ * that the minimum count is a desired value and this may allocate a
+ * smaller range.
+ */
+void
+pcib_setup_secbus(device_t dev, struct pcib_secbus *bus, int min_count)
+{
+	char buf[64];
+	int error, rid;
+
+	switch (pci_read_config(dev, PCIR_HDRTYPE, 1) & PCIM_HDRTYPE) {
+	case PCIM_HDRTYPE_BRIDGE:
+		bus->sub_reg = PCIR_SUBBUS_1;
+		break;
+	case PCIM_HDRTYPE_CARDBUS:
+		bus->sub_reg = PCIR_SUBBUS_2;
+		break;
+	default:
+		panic("not a PCI bridge");
+	}
+	bus->dev = dev;
+	bus->rman.rm_start = 0;
+	bus->rman.rm_end = PCI_BUSMAX;
+	bus->rman.rm_type = RMAN_ARRAY;
+	snprintf(buf, sizeof(buf), "%s bus numbers", device_get_nameunit(dev));
+	bus->rman.rm_descr = strdup(buf, M_DEVBUF);
+	error = rman_init(&bus->rman);
+	if (error)
+		panic("Failed to initialize %s bus number rman",
+		    device_get_nameunit(dev));
+
+	/*
+	 * Allocate a bus range.  This will return an existing bus range
+	 * if one exists, or a new bus range if one does not.
+	 */
+	rid = 0;
+	bus->res = bus_alloc_resource(dev, PCI_RES_BUS, &rid, 0ul, ~0ul,
+	    min_count, 0);
+	if (bus->res == NULL) {
+		/*
+		 * Fall back to just allocating a range of a single bus
+		 * number.
+		 */
+		bus->res = bus_alloc_resource(dev, PCI_RES_BUS, &rid, 0ul, ~0ul,
+		    1, 0);
+	} else if (rman_get_size(bus->res) < min_count)
+		/*
+		 * Attempt to grow the existing range to satisfy the
+		 * minimum desired count.
+		 */
+		(void)bus_adjust_resource(dev, PCI_RES_BUS, bus->res,
+		    rman_get_start(bus->res), rman_get_start(bus->res) +
+		    min_count - 1);
+
+	/*
+	 * Add the initial resource to the rman.
+	 */
+	if (bus->res != NULL) {
+		error = rman_manage_region(&bus->rman, rman_get_start(bus->res),
+		    rman_get_end(bus->res));
+		if (error)
+			panic("Failed to add resource to rman");
+		bus->sec = rman_get_start(bus->res);
+		bus->sub = rman_get_end(bus->res);
+	}
+}
+
+static struct resource *
+pcib_suballoc_bus(struct pcib_secbus *bus, device_t child, int *rid,
+    u_long start, u_long end, u_long count, u_int flags)
+{
+	struct resource *res;
+
+	res = rman_reserve_resource(&bus->rman, start, end, count, flags,
+	    child);
+	if (res == NULL)
+		return (NULL);
+
+	if (bootverbose)
+		device_printf(bus->dev,
+		    "allocated bus range (%lu-%lu) for rid %d of %s\n",
+		    rman_get_start(res), rman_get_end(res), *rid,
+		    pcib_child_name(child));
+	rman_set_rid(res, *rid);
+	return (res);
+}
+
+/*
+ * Attempt to grow the secondary bus range.  This is much simpler than
+ * for I/O windows as the range can only be grown by increasing
+ * subbus.
+ */
+static int
+pcib_grow_subbus(struct pcib_secbus *bus, u_long new_end)
+{
+	u_long old_end;
+	int error;
+
+	old_end = rman_get_end(bus->res);
+	KASSERT(new_end > old_end, ("attempt to shrink subbus"));
+	error = bus_adjust_resource(bus->dev, PCI_RES_BUS, bus->res,
+	    rman_get_start(bus->res), new_end);
+	if (error)
+		return (error);
+	if (bootverbose)
+		device_printf(bus->dev, "grew bus range to %lu-%lu\n",
+		    rman_get_start(bus->res), rman_get_end(bus->res));
+	error = rman_manage_region(&bus->rman, old_end + 1,
+	    rman_get_end(bus->res));
+	if (error)
+		panic("Failed to add resource to rman");
+	bus->sub = rman_get_end(bus->res);
+	pci_write_config(bus->dev, bus->sub_reg, bus->sub, 1);
+	return (0);
+}
+
+struct resource *
+pcib_alloc_subbus(struct pcib_secbus *bus, device_t child, int *rid,
+    u_long start, u_long end, u_long count, u_int flags)
+{
+	struct resource *res;
+	u_long start_free, end_free, new_end;
+
+	/*
+	 * First, see if the request can be satisified by the existing
+	 * bus range.
+	 */
+	res = pcib_suballoc_bus(bus, child, rid, start, end, count, flags);
+	if (res != NULL)
+		return (res);
+
+	/*
+	 * Figure out a range to grow the bus range.  First, find the
+	 * first bus number after the last allocated bus in the rman and
+	 * enforce that as a minimum starting point for the range.
+	 */
+	if (rman_last_free_region(&bus->rman, &start_free, &end_free) != 0 ||
+	    end_free != bus->sub)
+		start_free = bus->sub + 1;
+	if (start_free < start)
+		start_free = start;
+	new_end = start_free + count - 1;
+
+	/*
+	 * See if this new range would satisfy the request if it
+	 * succeeds.
+	 */
+	if (new_end > end)
+		return (NULL);
+
+	/* Finally, attempt to grow the existing resource. */
+	if (bootverbose) {
+		device_printf(bus->dev,
+		    "attempting to grow bus range for %lu buses\n", count);
+		printf("\tback candidate range: %lu-%lu\n", start_free,
+		    new_end);
+	}
+	if (pcib_grow_subbus(bus, new_end) == 0)
+		return (pcib_suballoc_bus(bus, child, rid, start, end, count,
+		    flags));
+	return (NULL);
+}
+#endif
+
 #else
 
 /*
@@ -483,8 +852,8 @@
 
 	sc->command = pci_read_config(dev, PCIR_COMMAND, 2);
 	sc->pribus = pci_read_config(dev, PCIR_PRIBUS_1, 1);
-	sc->secbus = pci_read_config(dev, PCIR_SECBUS_1, 1);
-	sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1);
+	sc->bus.sec = pci_read_config(dev, PCIR_SECBUS_1, 1);
+	sc->bus.sub = pci_read_config(dev, PCIR_SUBBUS_1, 1);
 	sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2);
 	sc->seclat = pci_read_config(dev, PCIR_SECLAT_1, 1);
 #ifndef NEW_PCIB
@@ -507,8 +876,8 @@
 
 	pci_write_config(dev, PCIR_COMMAND, sc->command, 2);
 	pci_write_config(dev, PCIR_PRIBUS_1, sc->pribus, 1);
-	pci_write_config(dev, PCIR_SECBUS_1, sc->secbus, 1);
-	pci_write_config(dev, PCIR_SUBBUS_1, sc->subbus, 1);
+	pci_write_config(dev, PCIR_SECBUS_1, sc->bus.sec, 1);
+	pci_write_config(dev, PCIR_SUBBUS_1, sc->bus.sub, 1);
 	pci_write_config(dev, PCIR_BRIDGECTL_1, sc->bridgectl, 2);
 	pci_write_config(dev, PCIR_SECLAT_1, sc->seclat, 1);
 #ifdef NEW_PCIB
@@ -541,6 +910,7 @@
     struct pcib_softc	*sc;
     struct sysctl_ctx_list *sctx;
     struct sysctl_oid	*soid;
+    int comma;
 
     sc = device_get_softc(dev);
     sc->dev = dev;
@@ -553,6 +923,13 @@
     pcib_cfg_save(sc);
 
     /*
+     * The primary bus register should always be the bus of the
+     * parent.
+     */
+    sc->pribus = pci_get_bus(dev);
+    pci_write_config(dev, PCIR_PRIBUS_1, sc->pribus, 1);
+
+    /*
      * Setup sysctl reporting nodes
      */
     sctx = device_get_sysctl_ctx(dev);
@@ -562,14 +939,15 @@
     SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pribus",
       CTLFLAG_RD, &sc->pribus, 0, "Primary bus number");
     SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus",
-      CTLFLAG_RD, &sc->secbus, 0, "Secondary bus number");
+      CTLFLAG_RD, &sc->bus.sec, 0, "Secondary bus number");
     SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus",
-      CTLFLAG_RD, &sc->subbus, 0, "Subordinate bus number");
+      CTLFLAG_RD, &sc->bus.sub, 0, "Subordinate bus number");
 
     /*
      * Quirk handling.
      */
     switch (pci_get_devid(dev)) {
+#if !(defined(NEW_PCIB) && defined(PCI_RES_BUS))
     case 0x12258086:		/* Intel 82454KX/GX (Orion) */
 	{
 	    uint8_t	supbus;
@@ -576,11 +954,12 @@
 
 	    supbus = pci_read_config(dev, 0x41, 1);
 	    if (supbus != 0xff) {
-		sc->secbus = supbus + 1;
-		sc->subbus = supbus + 1;
+		sc->bus.sec = supbus + 1;
+		sc->bus.sub = supbus + 1;
 	    }
 	    break;
 	}
+#endif
 
     /*
      * The i82380FB mobile docking controller is a PCI-PCI bridge,
@@ -594,6 +973,7 @@
 	sc->flags |= PCIB_SUBTRACTIVE;
 	break;
 
+#if !(defined(NEW_PCIB) && defined(PCI_RES_BUS))
     /* Compaq R3000 BIOS sets wrong subordinate bus number. */
     case 0x00dd10de:
 	{
@@ -613,17 +993,21 @@
 		break;
 	    }
 	    freeenv(cp);
-	    if (sc->subbus < 0xa) {
+	    if (sc->bus.sub < 0xa) {
 		pci_write_config(dev, PCIR_SUBBUS_1, 0xa, 1);
-		sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1);
+		sc->bus.sub = pci_read_config(dev, PCIR_SUBBUS_1, 1);
 	    }
 	    break;
 	}
+#endif
     }
 
     if (pci_msi_device_blacklisted(dev))
 	sc->flags |= PCIB_DISABLE_MSI;
 
+    if (pci_msix_device_blacklisted(dev))
+	sc->flags |= PCIB_DISABLE_MSIX;
+
     /*
      * 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,
@@ -637,12 +1021,15 @@
 	sc->flags |= PCIB_SUBTRACTIVE;
 
 #ifdef NEW_PCIB
+#ifdef PCI_RES_BUS
+    pcib_setup_secbus(dev, &sc->bus, 1);
+#endif
     pcib_probe_windows(sc);
 #endif
     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, "  secondary bus     %d\n", sc->bus.sec);
+	device_printf(dev, "  subordinate bus   %d\n", sc->bus.sub);
 #ifdef NEW_PCIB
 	if (pcib_is_window_open(&sc->io))
 	    device_printf(dev, "  I/O decode        0x%jx-0x%jx\n",
@@ -664,27 +1051,25 @@
 	    device_printf(dev, "  prefetched decode 0x%jx-0x%jx\n",
 	      (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit);
 #endif
-	else
-	    device_printf(dev, "  no prefetched decode\n");
-	if (sc->flags & PCIB_SUBTRACTIVE)
-	    device_printf(dev, "  Subtractively decoded bridge.\n");
+	if (sc->bridgectl & (PCIB_BCR_ISA_ENABLE | PCIB_BCR_VGA_ENABLE) ||
+	    sc->flags & PCIB_SUBTRACTIVE) {
+		device_printf(dev, "  special decode    ");
+		comma = 0;
+		if (sc->bridgectl & PCIB_BCR_ISA_ENABLE) {
+			printf("ISA");
+			comma = 1;
+		}
+		if (sc->bridgectl & PCIB_BCR_VGA_ENABLE) {
+			printf("%sVGA", comma ? ", " : "");
+			comma = 1;
+		}
+		if (sc->flags & PCIB_SUBTRACTIVE)
+			printf("%ssubtractive", comma ? ", " : "");
+		printf("\n");
+	}
     }
 
     /*
-     * XXX If the secondary bus number is zero, we should assign a bus number
-     *     since the BIOS hasn't, then initialise the bridge.  A simple
-     *     bus_alloc_resource with the a couple of busses seems like the right
-     *     approach, but we don't know what busses the BIOS might have already
-     *     assigned to other bridges on this bus that probe later than we do.
-     *
-     *     If the subordinate bus number is less than the secondary bus number,
-     *     we should pick a better value.  One sensible alternative would be to
-     *     pick 255; the only tradeoff here is that configuration transactions
-     *     would be more widely routed than absolutely necessary.  We could
-     *     then do a walk of the tree later and fix it.
-     */
-
-    /*
      * Always enable busmastering on bridges so that transactions
      * initiated on the secondary bus are passed through to the
      * primary bus.
@@ -700,8 +1085,8 @@
 
     pcib_attach_common(dev);
     sc = device_get_softc(dev);
-    if (sc->secbus != 0) {
-	child = device_add_child(dev, "pci", sc->secbus);
+    if (sc->bus.sec != 0) {
+	child = device_add_child(dev, "pci", sc->bus.sec);
 	if (child != NULL)
 	    return(bus_generic_attach(dev));
     }
@@ -713,30 +1098,15 @@
 int
 pcib_suspend(device_t dev)
 {
-	device_t	pcib;
-	int		dstate, error;
 
 	pcib_cfg_save(device_get_softc(dev));
-	error = bus_generic_suspend(dev);
-	if (error == 0 && pci_do_power_suspend) {
-		dstate = PCI_POWERSTATE_D3;
-		pcib = device_get_parent(device_get_parent(dev));
-		if (PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0)
-			pci_set_powerstate(dev, dstate);
-	}
-	return (error);
+	return (bus_generic_suspend(dev));
 }
 
 int
 pcib_resume(device_t dev)
 {
-	device_t	pcib;
 
-	if (pci_do_power_resume) {
-		pcib = device_get_parent(device_get_parent(dev));
-		if (PCIB_POWER_FOR_SLEEP(pcib, dev, NULL) == 0)
-			pci_set_powerstate(dev, PCI_POWERSTATE_D0);
-	}
 	pcib_cfg_restore(device_get_softc(dev));
 	return (bus_generic_resume(dev));
 }
@@ -751,7 +1121,7 @@
 	*result = sc->domain;
 	return(0);
     case PCIB_IVAR_BUS:
-	*result = sc->secbus;
+	*result = sc->bus.sec;
 	return(0);
     }
     return(ENOENT);
@@ -760,14 +1130,12 @@
 int
 pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
 {
-    struct pcib_softc	*sc = device_get_softc(dev);
 
     switch (which) {
     case PCIB_IVAR_DOMAIN:
 	return(EINVAL);
     case PCIB_IVAR_BUS:
-	sc->secbus = value;
-	return(0);
+	return(EINVAL);
     }
     return(ENOENT);
 }
@@ -814,9 +1182,177 @@
 	return (res);
 }
 
+/* Allocate a fresh resource range for an unconfigured window. */
+static int
+pcib_alloc_new_window(struct pcib_softc *sc, struct pcib_window *w, int type,
+    u_long start, u_long end, u_long count, u_int flags)
+{
+	struct resource *res;
+	u_long base, limit, wmask;
+	int rid;
+
+	/*
+	 * If this is an I/O window on a bridge with ISA enable set
+	 * and the start address is below 64k, then try to allocate an
+	 * initial window of 0x1000 bytes long starting at address
+	 * 0xf000 and walking down.  Note that if the original request
+	 * was larger than the non-aliased range size of 0x100 our
+	 * caller would have raised the start address up to 64k
+	 * already.
+	 */
+	if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE &&
+	    start < 65536) {
+		for (base = 0xf000; (long)base >= 0; base -= 0x1000) {
+			limit = base + 0xfff;
+
+			/*
+			 * Skip ranges that wouldn't work for the
+			 * original request.  Note that the actual
+			 * window that overlaps are the non-alias
+			 * ranges within [base, limit], so this isn't
+			 * quite a simple comparison.
+			 */
+			if (start + count > limit - 0x400)
+				continue;
+			if (base == 0) {
+				/*
+				 * The first open region for the window at
+				 * 0 is 0x400-0x4ff.
+				 */
+				if (end - count + 1 < 0x400)
+					continue;
+			} else {
+				if (end - count + 1 < base)
+					continue;
+			}
+
+			if (pcib_alloc_nonisa_ranges(sc, base, limit) == 0) {
+				w->base = base;
+				w->limit = limit;
+				return (0);
+			}
+		}
+		return (ENOSPC);		
+	}
+	
+	wmask = (1ul << w->step) - 1;
+	if (RF_ALIGNMENT(flags) < w->step) {
+		flags &= ~RF_ALIGNMENT_MASK;
+		flags |= RF_ALIGNMENT_LOG2(w->step);
+	}
+	start &= ~wmask;
+	end |= wmask;
+	count = roundup2(count, 1ul << w->step);
+	rid = w->reg;
+	res = bus_alloc_resource(sc->dev, type, &rid, start, end, count,
+	    flags & ~RF_ACTIVE);
+	if (res == NULL)
+		return (ENOSPC);
+	pcib_add_window_resources(w, &res, 1);
+	pcib_activate_window(sc, type);
+	w->base = rman_get_start(res);
+	w->limit = rman_get_end(res);
+	return (0);
+}
+
+/* Try to expand an existing window to the requested base and limit. */
+static int
+pcib_expand_window(struct pcib_softc *sc, struct pcib_window *w, int type,
+    u_long base, u_long limit)
+{
+	struct resource *res;
+	int error, i, force_64k_base;
+
+	KASSERT(base <= w->base && limit >= w->limit,
+	    ("attempting to shrink window"));
+
+	/*
+	 * XXX: pcib_grow_window() doesn't try to do this anyway and
+	 * the error handling for all the edge cases would be tedious.
+	 */
+	KASSERT(limit == w->limit || base == w->base,
+	    ("attempting to grow both ends of a window"));
+
+	/*
+	 * Yet more special handling for requests to expand an I/O
+	 * window behind an ISA-enabled bridge.  Since I/O windows
+	 * have to grow in 0x1000 increments and the end of the 0xffff
+	 * range is an alias, growing a window below 64k will always
+	 * result in allocating new resources and never adjusting an
+	 * existing resource.
+	 */
+	if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE &&
+	    (limit <= 65535 || (base <= 65535 && base != w->base))) {
+		KASSERT(limit == w->limit || limit <= 65535,
+		    ("attempting to grow both ends across 64k ISA alias"));
+
+		if (base != w->base)
+			error = pcib_alloc_nonisa_ranges(sc, base, w->base - 1);
+		else
+			error = pcib_alloc_nonisa_ranges(sc, w->limit + 1,
+			    limit);
+		if (error == 0) {
+			w->base = base;
+			w->limit = limit;
+		}
+		return (error);
+	}
+
+	/*
+	 * Find the existing resource to adjust.  Usually there is only one,
+	 * but for an ISA-enabled bridge we might be growing the I/O window
+	 * above 64k and need to find the existing resource that maps all
+	 * of the area above 64k.
+	 */
+	for (i = 0; i < w->count; i++) {
+		if (rman_get_end(w->res[i]) == w->limit)
+			break;
+	}
+	KASSERT(i != w->count, ("did not find existing resource"));
+	res = w->res[i];
+
+	/*
+	 * Usually the resource we found should match the window's
+	 * existing range.  The one exception is the ISA-enabled case
+	 * mentioned above in which case the resource should start at
+	 * 64k.
+	 */
+	if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE &&
+	    w->base <= 65535) {
+		KASSERT(rman_get_start(res) == 65536,
+		    ("existing resource mismatch"));
+		force_64k_base = 1;
+	} else {
+		KASSERT(w->base == rman_get_start(res),
+		    ("existing resource mismatch"));
+		force_64k_base = 0;
+	}	
+
+	error = bus_adjust_resource(sc->dev, type, res, force_64k_base ?
+	    rman_get_start(res) : base, limit);
+	if (error)
+		return (error);
+
+	/* Add the newly allocated region to the resource manager. */
+	if (w->base != base) {
+		error = rman_manage_region(&w->rman, base, w->base - 1);
+		w->base = base;
+	} else {
+		error = rman_manage_region(&w->rman, w->limit + 1, limit);
+		w->limit = limit;
+	}
+	if (error) {
+		if (bootverbose)
+			device_printf(sc->dev,
+			    "failed to expand %s resource manager\n", w->name);
+		(void)bus_adjust_resource(sc->dev, type, res, force_64k_base ?
+		    rman_get_start(res) : w->base, w->limit);
+	}
+	return (error);
+}
+
 /*
  * Attempt to grow a window to make room for a given resource request.
- * The 'step' parameter is log_2 of the desired I/O window's alignment.
  */
 static int
 pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type,
@@ -823,14 +1359,20 @@
     u_long start, u_long end, u_long count, u_int flags)
 {
 	u_long align, start_free, end_free, front, back, wmask;
-	int error, rid;
+	int error;
 
 	/*
 	 * Clamp the desired resource range to the maximum address
 	 * this window supports.  Reject impossible requests.
+	 *
+	 * For I/O port requests behind a bridge with the ISA enable
+	 * bit set, force large allocations to start above 64k.
 	 */
 	if (!w->valid)
 		return (EINVAL);
+	if (sc->bridgectl & PCIB_BCR_ISA_ENABLE && count > 0x100 &&
+	    start < 65536)
+		start = 65536;
 	if (end > w->rman.rm_end)
 		end = w->rman.rm_end;
 	if (start + count - 1 > end || start + count < start)
@@ -842,40 +1384,19 @@
 	 * aligned space for this resource.
 	 */
 	if (w->res == NULL) {
-		if (RF_ALIGNMENT(flags) < w->step) {
-			flags &= ~RF_ALIGNMENT_MASK;
-			flags |= RF_ALIGNMENT_LOG2(w->step);
-		}
-		start &= ~wmask;
-		end |= wmask;
-		count = roundup2(count, 1ul << w->step);
-		rid = w->reg;
-		w->res = bus_alloc_resource(sc->dev, type, &rid, start, end,
-		    count, flags & ~RF_ACTIVE);
-		if (w->res == NULL) {
+		error = pcib_alloc_new_window(sc, w, type, start, end, count,
+		    flags);
+		if (error) {
 			if (bootverbose)
 				device_printf(sc->dev,
 		    "failed to allocate initial %s window (%#lx-%#lx,%#lx)\n",
 				    w->name, start, end, count);
-			return (ENXIO);
+			return (error);
 		}
 		if (bootverbose)
 			device_printf(sc->dev,
-			    "allocated initial %s window of %#lx-%#lx\n",
-			    w->name, rman_get_start(w->res),
-			    rman_get_end(w->res));
-		error = rman_manage_region(&w->rman, rman_get_start(w->res),
-		    rman_get_end(w->res));
-		if (error) {
-			if (bootverbose)
-				device_printf(sc->dev,
-				    "failed to add initial %s window to rman\n",
-				    w->name);
-			bus_release_resource(sc->dev, type, w->reg, w->res);
-			w->res = NULL;
-			return (error);
-		}
-		pcib_activate_window(sc, type);
+			    "allocated initial %s window of %#jx-%#jx\n",
+			    w->name, (uintmax_t)w->base, (uintmax_t)w->limit);
 		goto updatewin;
 	}
 
@@ -889,6 +1410,11 @@
 	 * edge of the window, grow from the inner edge of the free
 	 * region.  Otherwise grow from the window boundary.
 	 *
+	 * Growing an I/O window below 64k for a bridge with the ISA
+	 * enable bit doesn't require any special magic as the step
+	 * size of an I/O window (1k) always includes multiple
+	 * non-alias ranges when it is grown in either direction.
+	 *
 	 * XXX: Special case: if w->res is completely empty and the
 	 * request size is larger than w->res, we should find the
 	 * optimal aligned buffer containing w->res and allocate that.
@@ -898,10 +1424,10 @@
 		    "attempting to grow %s window for (%#lx-%#lx,%#lx)\n",
 		    w->name, start, end, count);
 	align = 1ul << RF_ALIGNMENT(flags);
-	if (start < rman_get_start(w->res)) {
+	if (start < w->base) {
 		if (rman_first_free_region(&w->rman, &start_free, &end_free) !=
-		    0 || start_free != rman_get_start(w->res))
-			end_free = rman_get_start(w->res);
+		    0 || start_free != w->base)
+			end_free = w->base;
 		if (end_free > end)
 			end_free = end + 1;
 
@@ -922,15 +1448,15 @@
 				printf("\tfront candidate range: %#lx-%#lx\n",
 				    front, end_free);
 			front &= ~wmask;
-			front = rman_get_start(w->res) - front;
+			front = w->base - front;
 		} else
 			front = 0;
 	} else
 		front = 0;
-	if (end > rman_get_end(w->res)) {
+	if (end > w->limit) {
 		if (rman_last_free_region(&w->rman, &start_free, &end_free) !=
-		    0 || end_free != rman_get_end(w->res))
-			start_free = rman_get_end(w->res) + 1;
+		    0 || end_free != w->limit)
+			start_free = w->limit + 1;
 		if (start_free < start)
 			start_free = start;
 
@@ -950,7 +1476,7 @@
 				printf("\tback candidate range: %#lx-%#lx\n",
 				    start_free, back);
 			back |= wmask;
-			back -= rman_get_end(w->res);
+			back -= w->limit;
 		} else
 			back = 0;
 	} else
@@ -963,16 +1489,14 @@
 	error = ENOSPC;
 	while (front != 0 || back != 0) {
 		if (front != 0 && (front <= back || back == 0)) {
-			error = bus_adjust_resource(sc->dev, type, w->res,
-			    rman_get_start(w->res) - front,
-			    rman_get_end(w->res));
+			error = pcib_expand_window(sc, w, type, w->base - front,
+			    w->limit);
 			if (error == 0)
 				break;
 			front = 0;
 		} else {
-			error = bus_adjust_resource(sc->dev, type, w->res,
-			    rman_get_start(w->res),
-			    rman_get_end(w->res) + back);
+			error = pcib_expand_window(sc, w, type, w->base,
+			    w->limit + back);
 			if (error == 0)
 				break;
 			back = 0;
@@ -982,32 +1506,11 @@
 	if (error)
 		return (error);
 	if (bootverbose)
-		device_printf(sc->dev, "grew %s window to %#lx-%#lx\n",
-		    w->name, rman_get_start(w->res), rman_get_end(w->res));
+		device_printf(sc->dev, "grew %s window to %#jx-%#jx\n",
+		    w->name, (uintmax_t)w->base, (uintmax_t)w->limit);
 
-	/* Add the newly allocated region to the resource manager. */
-	if (w->base != rman_get_start(w->res)) {
-		KASSERT(w->limit == rman_get_end(w->res), ("both ends moved"));
-		error = rman_manage_region(&w->rman, rman_get_start(w->res),
-		    w->base - 1);
-	} else {
-		KASSERT(w->limit != rman_get_end(w->res),
-		    ("neither end moved"));
-		error = rman_manage_region(&w->rman, w->limit + 1,
-		    rman_get_end(w->res));
-	}
-	if (error) {
-		if (bootverbose)
-			device_printf(sc->dev,
-			    "failed to expand %s resource manager\n", w->name);
-		bus_adjust_resource(sc->dev, type, w->res, w->base, w->limit);
-		return (error);
-	}
-
 updatewin:
-	/* Save the new window. */
-	w->base = rman_get_start(w->res);
-	w->limit = rman_get_end(w->res);
+	/* Write the new window. */
 	KASSERT((w->base & wmask) == 0, ("start address is not aligned"));
 	KASSERT((w->limit & wmask) == wmask, ("end address is not aligned"));
 	pcib_write_windows(sc, w->mask);
@@ -1042,7 +1545,14 @@
 	}
 
 	switch (type) {
+#ifdef PCI_RES_BUS
+	case PCI_RES_BUS:
+		return (pcib_alloc_subbus(&sc->bus, child, rid, start, end,
+		    count, flags));
+#endif
 	case SYS_RES_IOPORT:
+		if (pcib_is_isa_range(sc, start, end, count))
+			return (NULL);
 		r = pcib_suballoc_resource(sc, &sc->io, child, type, rid, start,
 		    end, count, flags);
 		if (r != NULL || (sc->flags & PCIB_SUBTRACTIVE) != 0)
@@ -1289,27 +1799,94 @@
 #endif
 
 /*
+ * If ARI is enabled on this downstream port, translate the function number
+ * to the non-ARI slot/function.  The downstream port will convert it back in
+ * hardware.  If ARI is not enabled slot and func are not modified.
+ */
+static __inline void
+pcib_xlate_ari(device_t pcib, int bus, int *slot, int *func)
+{
+	struct pcib_softc *sc;
+	int ari_func;
+
+	sc = device_get_softc(pcib);
+	ari_func = *func;
+
+	if (sc->flags & PCIB_ENABLE_ARI) {
+		KASSERT(*slot == 0,
+		    ("Non-zero slot number with ARI enabled!"));
+		*slot = PCIE_ARI_SLOT(ari_func);
+		*func = PCIE_ARI_FUNC(ari_func);
+	}
+}
+
+
+static void
+pcib_enable_ari(struct pcib_softc *sc, uint32_t pcie_pos)
+{
+	uint32_t ctl2;
+
+	ctl2 = pci_read_config(sc->dev, pcie_pos + PCIER_DEVICE_CTL2, 4);
+	ctl2 |= PCIEM_CTL2_ARI;
+	pci_write_config(sc->dev, pcie_pos + PCIER_DEVICE_CTL2, ctl2, 4);
+
+	sc->flags |= PCIB_ENABLE_ARI;
+}
+
+/*
  * PCIB interface.
  */
 int
 pcib_maxslots(device_t dev)
 {
-    return(PCI_SLOTMAX);
+	return (PCI_SLOTMAX);
 }
 
+static int
+pcib_ari_maxslots(device_t dev)
+{
+	struct pcib_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	if (sc->flags & PCIB_ENABLE_ARI)
+		return (PCIE_ARI_SLOTMAX);
+	else
+		return (PCI_SLOTMAX);
+}
+
+static int
+pcib_ari_maxfuncs(device_t dev)
+{
+	struct pcib_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	if (sc->flags & PCIB_ENABLE_ARI)
+		return (PCIE_ARI_FUNCMAX);
+	else
+		return (PCI_FUNCMAX);
+}
+
 /*
  * Since we are a child of a PCI bus, its parent must support the pcib interface.
  */
-uint32_t
+static uint32_t
 pcib_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width)
 {
-    return(PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, width));
+
+	pcib_xlate_ari(dev, b, &s, &f);
+	return(PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b, s,
+	    f, reg, width));
 }
 
-void
+static void
 pcib_write_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, uint32_t val, int width)
 {
-    PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg, val, width);
+
+	pcib_xlate_ari(dev, b, &s, &f);
+	PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f,
+	    reg, val, width);
 }
 
 /*
@@ -1379,7 +1956,7 @@
 	struct pcib_softc *sc = device_get_softc(pcib);
 	device_t bus;
 
-	if (sc->flags & PCIB_DISABLE_MSI)
+	if (sc->flags & PCIB_DISABLE_MSIX)
 		return (ENXIO);
 	bus = device_get_parent(pcib);
 	return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq));
@@ -1421,3 +1998,83 @@
 	bus = device_get_parent(pcib);
 	return (PCIB_POWER_FOR_SLEEP(bus, dev, pstate));
 }
+
+static uint16_t
+pcib_ari_get_rid(device_t pcib, device_t dev)
+{
+	struct pcib_softc *sc;
+	uint8_t bus, slot, func;
+
+	sc = device_get_softc(pcib);
+
+	if (sc->flags & PCIB_ENABLE_ARI) {
+		bus = pci_get_bus(dev);
+		func = pci_get_function(dev);
+
+		return (PCI_ARI_RID(bus, func));
+	} else {
+		bus = pci_get_bus(dev);
+		slot = pci_get_slot(dev);
+		func = pci_get_function(dev);
+
+		return (PCI_RID(bus, slot, func));
+	}
+}
+
+/*
+ * Check that the downstream port (pcib) and the endpoint device (dev) both
+ * support ARI.  If so, enable it and return 0, otherwise return an error.
+ */
+static int
+pcib_try_enable_ari(device_t pcib, device_t dev)
+{
+	struct pcib_softc *sc;
+	int error;
+	uint32_t cap2;
+	int ari_cap_off;
+	uint32_t ari_ver;
+	uint32_t pcie_pos;
+
+	sc = device_get_softc(pcib);
+
+	/*
+	 * ARI is controlled in a register in the PCIe capability structure.
+	 * If the downstream port does not have the PCIe capability structure
+	 * then it does not support ARI.
+	 */
+	error = pci_find_cap(pcib, PCIY_EXPRESS, &pcie_pos);
+	if (error != 0)
+		return (ENODEV);
+
+	/* Check that the PCIe port advertises ARI support. */
+	cap2 = pci_read_config(pcib, pcie_pos + PCIER_DEVICE_CAP2, 4);
+	if (!(cap2 & PCIEM_CAP2_ARI))
+		return (ENODEV);
+
+	/*
+	 * Check that the endpoint device advertises ARI support via the ARI
+	 * extended capability structure.
+	 */
+	error = pci_find_extcap(dev, PCIZ_ARI, &ari_cap_off);
+	if (error != 0)
+		return (ENODEV);
+
+	/*
+	 * Finally, check that the endpoint device supports the same version
+	 * of ARI that we do.
+	 */
+	ari_ver = pci_read_config(dev, ari_cap_off, 4);
+	if (PCI_EXTCAP_VER(ari_ver) != PCIB_SUPPORTED_ARI_VER) {
+		if (bootverbose)
+			device_printf(pcib,
+			    "Unsupported version of ARI (%d) detected\n",
+			    PCI_EXTCAP_VER(ari_ver));
+
+		return (ENXIO);
+	}
+
+	pcib_enable_ari(sc, pcie_pos);
+
+	return (0);
+}
+

Modified: trunk/sys/dev/pci/pci_private.h
===================================================================
--- trunk/sys/dev/pci/pci_private.h	2018-05-27 23:27:48 UTC (rev 10086)
+++ trunk/sys/dev/pci/pci_private.h	2018-05-27 23:28:52 UTC (rev 10087)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1997, Stefan Esser <se at freebsd.org>
  * Copyright (c) 2000, Michael Smith <msmith at freebsd.org>
@@ -25,7 +26,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.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/pci/pci_private.h 330938 2018-03-14 19:04:40Z jhb $
  *
  */
 
@@ -40,6 +41,9 @@
 
 struct pci_softc {
 	bus_dma_tag_t sc_dma_tag;
+#ifdef PCI_RES_BUS
+	struct resource *sc_bus;
+#endif
 };
 
 extern int 	pci_do_power_resume;
@@ -51,7 +55,6 @@
 void		pci_add_resources(device_t bus, device_t dev, int force,
 		    uint32_t prefetchmask);
 int		pci_attach_common(device_t dev);
-void		pci_delete_child(device_t dev, device_t child);
 void		pci_driver_added(device_t dev, driver_t *driver);
 int		pci_print_child(device_t dev, device_t child);
 void		pci_probe_nomatch(device_t dev, device_t child);
@@ -79,18 +82,31 @@
 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_cap_method(device_t dev, device_t child,
+		    int capability, int *capreg);
 int		pci_find_extcap_method(device_t dev, device_t child,
 		    int capability, int *capreg);
+int		pci_find_htcap_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);
+void		pci_enable_msi_method(device_t dev, device_t child,
+		    uint64_t address, uint16_t data);
+void		pci_enable_msix_method(device_t dev, device_t child,
+		    u_int index, uint64_t address, uint32_t data);
+void		pci_disable_msi_method(device_t dev, device_t child);
 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);
+int		pci_msix_pba_bar_method(device_t dev, device_t child);
+int		pci_msix_table_bar_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);
+int		pci_release_resource(device_t dev, device_t child, int type,
+		    int rid, struct resource *r);
 int		pci_activate_resource(device_t dev, device_t child, int type,
 		    int rid, struct resource *r);
 int		pci_deactivate_resource(device_t dev, device_t child, int type,
@@ -102,6 +118,8 @@
 		    size_t size);
 void		pci_print_verbose(struct pci_devinfo *dinfo);
 int		pci_freecfg(struct pci_devinfo *dinfo);
+void		pci_child_deleted(device_t dev, device_t child);
+void		pci_child_detached(device_t dev, device_t child);
 int		pci_child_location_str_method(device_t cbdev, device_t child,
 		    char *buf, size_t buflen);
 int		pci_child_pnpinfo_str_method(device_t cbdev, device_t child,
@@ -109,6 +127,8 @@
 int		pci_assign_interrupt_method(device_t dev, device_t child);
 int		pci_resume(device_t dev);
 int		pci_suspend(device_t dev);
+bus_dma_tag_t pci_get_dma_tag(device_t bus, device_t dev);
+void		pci_child_added_method(device_t dev, device_t child);
 
 /** Restore the config register state.  The state must be previously
  * saved with pci_cfg_save.  However, the pci bus driver takes care of

Modified: trunk/sys/dev/pci/pci_subr.c
===================================================================
--- trunk/sys/dev/pci/pci_subr.c	2018-05-27 23:27:48 UTC (rev 10086)
+++ trunk/sys/dev/pci/pci_subr.c	2018-05-27 23:28:52 UTC (rev 10087)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 2011 Advanced Computing Technologies LLC
+ * Copyright (c) 2011 Hudson River Trading LLC
  * Written by: John H. Baldwin <jhb at FreeBSD.org>
  * All rights reserved.
  *
@@ -26,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/pci/pci_subr.c 283927 2015-06-02 19:20:39Z jhb $");
 
 /*
  * Support APIs for Host to PCI bridge drivers and drivers that
@@ -35,6 +36,7 @@
 
 #include <sys/param.h>
 #include <sys/bus.h>
+#include <sys/malloc.h>
 #include <sys/rman.h>
 #include <sys/systm.h>
 
@@ -282,4 +284,102 @@
 	}
 	return (ERANGE);
 }
+
+#ifdef PCI_RES_BUS
+struct pci_domain {
+	int	pd_domain;
+	struct rman pd_bus_rman;
+	TAILQ_ENTRY(pci_domain) pd_link;
+};
+
+static TAILQ_HEAD(, pci_domain) domains = TAILQ_HEAD_INITIALIZER(domains);
+
+/*
+ * Each PCI domain maintains its own resource manager for PCI bus
+ * numbers in that domain.  Domain objects are created on first use.
+ * Host to PCI bridge drivers and PCI-PCI bridge drivers should
+ * allocate their bus ranges from their domain.
+ */
+static struct pci_domain *
+pci_find_domain(int domain)
+{
+	struct pci_domain *d;
+	char buf[64];
+	int error;
+
+	TAILQ_FOREACH(d, &domains, pd_link) {
+		if (d->pd_domain == domain)
+			return (d);
+	}
+
+	snprintf(buf, sizeof(buf), "PCI domain %d bus numbers", domain);
+	d = malloc(sizeof(*d) + strlen(buf) + 1, M_DEVBUF, M_WAITOK | M_ZERO);
+	d->pd_domain = domain;
+	d->pd_bus_rman.rm_start = 0;
+	d->pd_bus_rman.rm_end = PCI_BUSMAX;
+	d->pd_bus_rman.rm_type = RMAN_ARRAY;
+	strcpy((char *)(d + 1), buf);
+	d->pd_bus_rman.rm_descr = (char *)(d + 1);
+	error = rman_init(&d->pd_bus_rman);
+	if (error == 0)
+		error = rman_manage_region(&d->pd_bus_rman, 0, PCI_BUSMAX);
+	if (error)
+		panic("Failed to initialize PCI domain %d rman", domain);
+	TAILQ_INSERT_TAIL(&domains, d, pd_link);
+	return (d);
+}
+
+struct resource *
+pci_domain_alloc_bus(int domain, device_t dev, int *rid, u_long start,
+    u_long end, u_long count, u_int flags)
+{
+	struct pci_domain *d;
+	struct resource *res;
+
+	if (domain < 0 || domain > PCI_DOMAINMAX)
+		return (NULL);
+	d = pci_find_domain(domain);
+	res = rman_reserve_resource(&d->pd_bus_rman, start, end, count, flags,
+	    dev);
+	if (res == NULL)
+		return (NULL);
+
+	rman_set_rid(res, *rid);
+	return (res);
+}
+
+int
+pci_domain_adjust_bus(int domain, device_t dev, struct resource *r,
+    u_long start, u_long end)
+{
+#ifdef INVARIANTS
+	struct pci_domain *d;
+#endif
+
+	if (domain < 0 || domain > PCI_DOMAINMAX)
+		return (EINVAL);
+#ifdef INVARIANTS
+	d = pci_find_domain(domain);
+	KASSERT(rman_is_region_manager(r, &d->pd_bus_rman), ("bad resource"));
+#endif
+	return (rman_adjust_resource(r, start, end));
+}
+
+int
+pci_domain_release_bus(int domain, device_t dev, int rid, struct resource *r)
+{
+#ifdef INVARIANTS
+	struct pci_domain *d;
+#endif
+
+	if (domain < 0 || domain > PCI_DOMAINMAX)
+		return (EINVAL);
+#ifdef INVARIANTS
+	d = pci_find_domain(domain);
+	KASSERT(rman_is_region_manager(r, &d->pd_bus_rman), ("bad resource"));
+#endif
+	return (rman_release_resource(r));
+}
+#endif /* PCI_RES_BUS */
+
 #endif /* NEW_PCIB */

Modified: trunk/sys/dev/pci/pci_user.c
===================================================================
--- trunk/sys/dev/pci/pci_user.c	2018-05-27 23:27:48 UTC (rev 10086)
+++ trunk/sys/dev/pci/pci_user.c	2018-05-27 23:28:52 UTC (rev 10087)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1997, Stefan Esser <se at freebsd.org>
  * All rights reserved.
@@ -25,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/pci/pci_user.c 306469 2016-09-30 01:13:57Z jhb $");
 
 #include "opt_bus.h"	/* XXX trim includes */
 #include "opt_compat.h"
@@ -225,6 +226,51 @@
 	u_int32_t	pi_data;	/* data to write or result of read */
 };
 
+#ifdef COMPAT_FREEBSD32
+struct pci_conf_old32 {
+	struct pcisel_old pc_sel;	/* bus+slot+function */
+	uint8_t		pc_hdr;		/* PCI header type */
+	uint16_t	pc_subvendor;	/* card vendor ID */
+	uint16_t	pc_subdevice;	/* card device ID, assigned by
+					   card vendor */
+	uint16_t	pc_vendor;	/* chip vendor ID */
+	uint16_t	pc_device;	/* chip device ID, assigned by
+					   chip vendor */
+	uint8_t		pc_class;	/* chip PCI class */
+	uint8_t		pc_subclass;	/* chip PCI subclass */
+	uint8_t		pc_progif;	/* chip PCI programming interface */
+	uint8_t		pc_revid;	/* chip revision ID */
+	char		pd_name[PCI_MAXNAMELEN + 1]; /* device name */
+	uint32_t	pd_unit;	/* device unit number (u_long) */
+};
+
+struct pci_match_conf_old32 {
+	struct pcisel_old pc_sel;	/* bus+slot+function */
+	char		pd_name[PCI_MAXNAMELEN + 1]; /* device name */
+	uint32_t	pd_unit;	/* Unit number (u_long) */
+	uint16_t	pc_vendor;	/* PCI Vendor ID */
+	uint16_t	pc_device;	/* PCI Device ID */
+	uint8_t		pc_class;	/* PCI class */
+	pci_getconf_flags_old flags;	/* Matching expression */
+};
+
+struct pci_conf_io32 {
+	uint32_t	pat_buf_len;	/* pattern buffer length */
+	uint32_t	num_patterns;	/* number of patterns */
+	uint32_t	patterns;	/* pattern buffer
+					   (struct pci_match_conf_old32 *) */
+	uint32_t	match_buf_len;	/* match buffer length */
+	uint32_t	num_matches;	/* number of matches returned */
+	uint32_t	matches;	/* match buffer
+					   (struct pci_conf_old32 *) */
+	uint32_t	offset;		/* offset into device list */
+	uint32_t	generation;	/* device list generation */
+	pci_getconf_status status;	/* request status */
+};
+
+#define	PCIOCGETCONF_OLD32	_IOWR('p', 1, struct pci_conf_io32)
+#endif	/* COMPAT_FREEBSD32 */
+
 #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)
@@ -295,9 +341,156 @@
 	return(1);
 }
 
-#endif
+#ifdef COMPAT_FREEBSD32
+static int
+pci_conf_match_old32(struct pci_match_conf_old32 *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) &&
+		    ((u_int32_t)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	/* COMPAT_FREEBSD32 */
+#endif	/* PRE7_COMPAT */
+
 static int
+pci_list_vpd(device_t dev, struct pci_list_vpd_io *lvio)
+{
+	struct pci_vpd_element vpd_element, *vpd_user;
+	struct pcicfg_vpd *vpd;
+	size_t len;
+	int error, i;
+
+	vpd = pci_fetch_vpd_list(dev);
+	if (vpd->vpd_reg == 0 || vpd->vpd_ident == NULL)
+		return (ENXIO);
+
+	/*
+	 * Calculate the amount of space needed in the data buffer.  An
+	 * identifier element is always present followed by the read-only
+	 * and read-write keywords.
+	 */
+	len = sizeof(struct pci_vpd_element) + strlen(vpd->vpd_ident);
+	for (i = 0; i < vpd->vpd_rocnt; i++)
+		len += sizeof(struct pci_vpd_element) + vpd->vpd_ros[i].len;
+	for (i = 0; i < vpd->vpd_wcnt; i++)
+		len += sizeof(struct pci_vpd_element) + vpd->vpd_w[i].len;
+
+	if (lvio->plvi_len == 0) {
+		lvio->plvi_len = len;
+		return (0);
+	}
+	if (lvio->plvi_len < len) {
+		lvio->plvi_len = len;
+		return (ENOMEM);
+	}
+
+	/*
+	 * Copyout the identifier string followed by each keyword and
+	 * value.
+	 */
+	vpd_user = lvio->plvi_data;
+	vpd_element.pve_keyword[0] = '\0';
+	vpd_element.pve_keyword[1] = '\0';
+	vpd_element.pve_flags = PVE_FLAG_IDENT;
+	vpd_element.pve_datalen = strlen(vpd->vpd_ident);
+	error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
+	if (error)
+		return (error);
+	error = copyout(vpd->vpd_ident, vpd_user->pve_data,
+	    strlen(vpd->vpd_ident));
+	if (error)
+		return (error);
+	vpd_user = PVE_NEXT(vpd_user);
+	vpd_element.pve_flags = 0;
+	for (i = 0; i < vpd->vpd_rocnt; i++) {
+		vpd_element.pve_keyword[0] = vpd->vpd_ros[i].keyword[0];
+		vpd_element.pve_keyword[1] = vpd->vpd_ros[i].keyword[1];
+		vpd_element.pve_datalen = vpd->vpd_ros[i].len;
+		error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
+		if (error)
+			return (error);
+		error = copyout(vpd->vpd_ros[i].value, vpd_user->pve_data,
+		    vpd->vpd_ros[i].len);
+		if (error)
+			return (error);
+		vpd_user = PVE_NEXT(vpd_user);
+	}
+	vpd_element.pve_flags = PVE_FLAG_RW;
+	for (i = 0; i < vpd->vpd_wcnt; i++) {
+		vpd_element.pve_keyword[0] = vpd->vpd_w[i].keyword[0];
+		vpd_element.pve_keyword[1] = vpd->vpd_w[i].keyword[1];
+		vpd_element.pve_datalen = vpd->vpd_w[i].len;
+		error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
+		if (error)
+			return (error);
+		error = copyout(vpd->vpd_w[i].value, vpd_user->pve_data,
+		    vpd->vpd_w[i].len);
+		if (error)
+			return (error);
+		vpd_user = PVE_NEXT(vpd_user);
+	}
+	KASSERT((char *)vpd_user - (char *)lvio->plvi_data == len,
+	    ("length mismatch"));
+	lvio->plvi_len = len;
+	return (0);
+}
+
+static int
 pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
 {
 	device_t pcidev, brdev;
@@ -304,39 +497,79 @@
 	void *confdata;
 	const char *name;
 	struct devlist *devlist_head;
-	struct pci_conf_io *cio;
+	struct pci_conf_io *cio = NULL;
 	struct pci_devinfo *dinfo;
 	struct pci_io *io;
 	struct pci_bar_io *bio;
+	struct pci_list_vpd_io *lvio;
 	struct pci_match_conf *pattern_buf;
 	struct pci_map *pm;
 	size_t confsz, iolen, pbufsz;
 	int error, ionum, i, num_patterns;
 #ifdef PRE7_COMPAT
+#ifdef COMPAT_FREEBSD32
+	struct pci_conf_io32 *cio32 = NULL;
+	struct pci_conf_old32 conf_old32;
+	struct pci_match_conf_old32 *pattern_buf_old32 = NULL;
+#endif
 	struct pci_conf_old conf_old;
 	struct pci_io iodata;
 	struct pci_io_old *io_old;
-	struct pci_match_conf_old *pattern_buf_old;
+	struct pci_match_conf_old *pattern_buf_old = NULL;
 
 	io_old = NULL;
-	pattern_buf_old = NULL;
+#endif
 
-	if (!(flag & FWRITE) && cmd != PCIOCGETBAR &&
-	    cmd != PCIOCGETCONF && cmd != PCIOCGETCONF_OLD)
-		return EPERM;
-#else
-	if (!(flag & FWRITE) && cmd != PCIOCGETBAR && cmd != PCIOCGETCONF)
-		return EPERM;
+	if (!(flag & FWRITE)) {
+		switch (cmd) {
+#ifdef PRE7_COMPAT
+#ifdef COMPAT_FREEBSD32
+		case PCIOCGETCONF_OLD32:
 #endif
+		case PCIOCGETCONF_OLD:
+#endif
+		case PCIOCGETCONF:
+		case PCIOCGETBAR:
+		case PCIOCLISTVPD:
+			break;
+		default:
+			return (EPERM);
+		}
+	}
 
-	switch(cmd) {
+	switch (cmd) {
 #ifdef PRE7_COMPAT
+#ifdef COMPAT_FREEBSD32
+	case PCIOCGETCONF_OLD32:
+               cio32 = (struct pci_conf_io32 *)data;
+               cio = malloc(sizeof(struct pci_conf_io), M_TEMP, M_WAITOK);
+               cio->pat_buf_len = cio32->pat_buf_len;
+               cio->num_patterns = cio32->num_patterns;
+               cio->patterns = (void *)(uintptr_t)cio32->patterns;
+               cio->match_buf_len = cio32->match_buf_len;
+               cio->num_matches = cio32->num_matches;
+               cio->matches = (void *)(uintptr_t)cio32->matches;
+               cio->offset = cio32->offset;
+               cio->generation = cio32->generation;
+               cio->status = cio32->status;
+               cio32->num_matches = 0;
+               break;
+#endif
 	case PCIOCGETCONF_OLD:
-		/* FALLTHROUGH */
 #endif
 	case PCIOCGETCONF:
 		cio = (struct pci_conf_io *)data;
+	}
 
+	switch (cmd) {
+#ifdef PRE7_COMPAT
+#ifdef COMPAT_FREEBSD32
+	case PCIOCGETCONF_OLD32:
+#endif
+	case PCIOCGETCONF_OLD:
+#endif
+	case PCIOCGETCONF:
+
 		pattern_buf = NULL;
 		num_patterns = 0;
 		dinfo = NULL;
@@ -353,7 +586,7 @@
 		 && (cio->generation != pci_generation)){
 			cio->status = PCI_GETCONF_LIST_CHANGED;
 			error = 0;
-			break;
+			goto getconfexit;
 		}
 
 		/*
@@ -363,7 +596,7 @@
 		if (cio->offset >= pci_numdevs) {
 			cio->status = PCI_GETCONF_LAST_DEVICE;
 			error = 0;
-			break;
+			goto getconfexit;
 		}
 
 		/* get the head of the device queue */
@@ -376,6 +609,11 @@
 		 * didn't specify a multiple of that size.
 		 */
 #ifdef PRE7_COMPAT
+#ifdef COMPAT_FREEBSD32
+		if (cmd == PCIOCGETCONF_OLD32)
+			confsz = sizeof(struct pci_conf_old32);
+		else
+#endif
 		if (cmd == PCIOCGETCONF_OLD)
 			confsz = sizeof(struct pci_conf_old);
 		else
@@ -410,6 +648,11 @@
 			 * updated their kernel but not their userland.
 			 */
 #ifdef PRE7_COMPAT
+#ifdef COMPAT_FREEBSD32
+			if (cmd == PCIOCGETCONF_OLD32)
+				pbufsz = sizeof(struct pci_match_conf_old32);
+			else
+#endif
 			if (cmd == PCIOCGETCONF_OLD)
 				pbufsz = sizeof(struct pci_match_conf_old);
 			else
@@ -419,7 +662,7 @@
 				/* The user made a mistake, return an error. */
 				cio->status = PCI_GETCONF_ERROR;
 				error = EINVAL;
-				break;
+				goto getconfexit;
 			}
 
 			/*
@@ -426,6 +669,14 @@
 			 * Allocate a buffer to hold the patterns.
 			 */
 #ifdef PRE7_COMPAT
+#ifdef COMPAT_FREEBSD32
+			if (cmd == PCIOCGETCONF_OLD32) {
+				pattern_buf_old32 = malloc(cio->pat_buf_len,
+				    M_TEMP, M_WAITOK);
+				error = copyin(cio->patterns,
+				    pattern_buf_old32, cio->pat_buf_len);
+			} else
+#endif /* COMPAT_FREEBSD32 */
 			if (cmd == PCIOCGETCONF_OLD) {
 				pattern_buf_old = malloc(cio->pat_buf_len,
 				    M_TEMP, M_WAITOK);
@@ -432,7 +683,7 @@
 				error = copyin(cio->patterns,
 				    pattern_buf_old, cio->pat_buf_len);
 			} else
-#endif
+#endif /* PRE7_COMPAT */
 			{
 				pattern_buf = malloc(cio->pat_buf_len, M_TEMP,
 				    M_WAITOK);
@@ -451,7 +702,7 @@
 			 */
 			cio->status = PCI_GETCONF_ERROR;
 			error = EINVAL;
-			break;
+                       goto getconfexit;
 		}
 
 		/*
@@ -458,10 +709,9 @@
 		 * Go through the list of devices and copy out the devices
 		 * that match the user's criteria.
 		 */
-		for (cio->num_matches = 0, error = 0, i = 0,
-		     dinfo = STAILQ_FIRST(devlist_head);
-		     (dinfo != NULL) && (cio->num_matches < ionum)
-		     && (error == 0) && (i < pci_numdevs) && (dinfo != NULL);
+		for (cio->num_matches = 0, i = 0,
+				 dinfo = STAILQ_FIRST(devlist_head);
+		     dinfo != NULL;
 		     dinfo = STAILQ_NEXT(dinfo, pci_links), i++) {
 
 			if (i < cio->offset)
@@ -483,7 +733,14 @@
 			}
 
 #ifdef PRE7_COMPAT
-			if ((cmd == PCIOCGETCONF_OLD &&
+			if (
+#ifdef COMPAT_FREEBSD32
+			    (cmd == PCIOCGETCONF_OLD32 &&
+			    (pattern_buf_old32 == NULL ||
+			    pci_conf_match_old32(pattern_buf_old32,
+			    num_patterns, &dinfo->conf) == 0)) ||
+#endif
+			    (cmd == PCIOCGETCONF_OLD &&
 			    (pattern_buf_old == NULL ||
 			    pci_conf_match_old(pattern_buf_old, num_patterns,
 			    &dinfo->conf) == 0)) ||
@@ -508,6 +765,40 @@
 					break;
 
 #ifdef PRE7_COMPAT
+#ifdef COMPAT_FREEBSD32
+				if (cmd == PCIOCGETCONF_OLD32) {
+					conf_old32.pc_sel.pc_bus =
+					    dinfo->conf.pc_sel.pc_bus;
+					conf_old32.pc_sel.pc_dev =
+					    dinfo->conf.pc_sel.pc_dev;
+					conf_old32.pc_sel.pc_func =
+					    dinfo->conf.pc_sel.pc_func;
+					conf_old32.pc_hdr = dinfo->conf.pc_hdr;
+					conf_old32.pc_subvendor =
+					    dinfo->conf.pc_subvendor;
+					conf_old32.pc_subdevice =
+					    dinfo->conf.pc_subdevice;
+					conf_old32.pc_vendor =
+					    dinfo->conf.pc_vendor;
+					conf_old32.pc_device =
+					    dinfo->conf.pc_device;
+					conf_old32.pc_class =
+					    dinfo->conf.pc_class;
+					conf_old32.pc_subclass =
+					    dinfo->conf.pc_subclass;
+					conf_old32.pc_progif =
+					    dinfo->conf.pc_progif;
+					conf_old32.pc_revid =
+					    dinfo->conf.pc_revid;
+					strncpy(conf_old32.pd_name,
+					    dinfo->conf.pd_name,
+					    sizeof(conf_old32.pd_name));
+					conf_old32.pd_name[PCI_MAXNAMELEN] = 0;
+					conf_old32.pd_unit =
+					    (uint32_t)dinfo->conf.pd_unit;
+					confdata = &conf_old32;
+				} else
+#endif /* COMPAT_FREEBSD32 */
 				if (cmd == PCIOCGETCONF_OLD) {
 					conf_old.pc_sel.pc_bus =
 					    dinfo->conf.pc_sel.pc_bus;
@@ -540,13 +831,14 @@
 					    dinfo->conf.pd_unit;
 					confdata = &conf_old;
 				} else
-#endif
+#endif /* PRE7_COMPAT */
 					confdata = &dinfo->conf;
-				/* Only if we can copy it out do we count it. */
-				if (!(error = copyout(confdata,
+				error = copyout(confdata,
 				    (caddr_t)cio->matches +
-				    confsz * cio->num_matches, confsz)))
-					cio->num_matches++;
+				    confsz * cio->num_matches, confsz);
+				if (error)
+					break;
+				cio->num_matches++;
 			}
 		}
 
@@ -574,12 +866,23 @@
 			cio->status = PCI_GETCONF_MORE_DEVS;
 
 getconfexit:
-		if (pattern_buf != NULL)
-			free(pattern_buf, M_TEMP);
 #ifdef PRE7_COMPAT
+#ifdef COMPAT_FREEBSD32
+		if (cmd == PCIOCGETCONF_OLD32) {
+			cio32->status = cio->status;
+			cio32->generation = cio->generation;
+			cio32->offset = cio->offset;
+			cio32->num_matches = cio->num_matches;
+			free(cio, M_TEMP);
+		}
+		if (pattern_buf_old32 != NULL)
+			free(pattern_buf_old32, M_TEMP);
+#endif
 		if (pattern_buf_old != NULL)
 			free(pattern_buf_old, M_TEMP);
 #endif
+		if (pattern_buf != NULL)
+			free(pattern_buf, M_TEMP);
 
 		break;
 
@@ -704,6 +1007,22 @@
 		else
 			error = ENODEV;
 		break;
+	case PCIOCLISTVPD:
+		lvio = (struct pci_list_vpd_io *)data;
+
+		/*
+		 * Assume that the user-level bus number is
+		 * in fact the physical PCI bus number.
+		 */
+		pcidev = pci_find_dbsf(lvio->plvi_sel.pc_domain,
+		    lvio->plvi_sel.pc_bus, lvio->plvi_sel.pc_dev,
+		    lvio->plvi_sel.pc_func);
+		if (pcidev == NULL) {
+			error = ENODEV;
+			break;
+		}
+		error = pci_list_vpd(pcidev, lvio);
+		break;
 	default:
 		error = ENOTTY;
 		break;

Modified: trunk/sys/dev/pci/pcib_if.m
===================================================================
--- trunk/sys/dev/pci/pcib_if.m	2018-05-27 23:27:48 UTC (rev 10086)
+++ trunk/sys/dev/pci/pcib_if.m	2018-05-27 23:28:52 UTC (rev 10087)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 #-
 # Copyright (c) 2000 Doug Rabson
 # All rights reserved.
@@ -23,11 +24,13 @@
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-# $MidnightBSD$
+# $FreeBSD: stable/10/sys/dev/pci/pcib_if.m 279472 2015-03-01 04:28:30Z rstone $
 #
 
 #include <sys/bus.h>
+#include <sys/rman.h>
 #include <dev/pci/pcivar.h>
+#include <dev/pci/pcib_private.h>
 
 INTERFACE pcib;
 
@@ -47,6 +50,14 @@
 };
 
 #
+#
+# Return the number of functions on the attached PCI bus.
+#
+METHOD int maxfuncs {
+	device_t	dev;
+} DEFAULT pcib_maxfuncs;
+
+#
 # Read configuration space on the PCI bus. The bus, slot and func
 # arguments determine the device which is being read and the reg
 # argument is a byte offset into configuration space for that
@@ -154,3 +165,21 @@
 	device_t	dev;
 	int		*pstate;
 };
+
+#
+# Return the PCI Routing Identifier (RID) for the device.
+#
+METHOD uint16_t get_rid {
+	device_t	pcib;
+	device_t	dev;
+} DEFAULT pcib_get_rid;
+
+#
+# Enable Alternative RID Interpretation if both the downstream port (pcib)
+# and the endpoint device (dev) both support it.
+#
+METHOD int try_enable_ari {
+	device_t	pcib;
+	device_t	dev;
+};
+


Property changes on: trunk/sys/dev/pci/pcib_if.m
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/sys/dev/pci/pcib_private.h
===================================================================
--- trunk/sys/dev/pci/pcib_private.h	2018-05-27 23:27:48 UTC (rev 10086)
+++ trunk/sys/dev/pci/pcib_private.h	2018-05-27 23:28:52 UTC (rev 10087)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier
  * Copyright (c) 2000 Michael Smith <msmith at freebsd.org>
@@ -27,7 +28,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/pci/pcib_private.h 285863 2015-07-25 00:14:02Z jhb $
  */
 
 #ifndef __PCIB_PRIVATE_H__
@@ -73,7 +74,8 @@
 	pci_addr_t	base;		/* base address */
 	pci_addr_t	limit;		/* topmost address */
 	struct rman	rman;
-	struct resource *res;
+	struct resource **res;
+	int		count;		/* size of 'res' array */
 	int		reg;		/* resource id from parent */
 	int		valid;
 	int		mask;		/* WIN_* bitmask of this window */
@@ -82,6 +84,18 @@
 };
 #endif
 
+struct pcib_secbus {
+	u_int		sec;
+	u_int		sub;
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+	device_t	dev;
+	struct rman	rman;
+	struct resource	*res;
+	const char	*name;
+	int		sub_reg;
+#endif
+};
+
 /*
  * Bridge-specific data.
  */
@@ -91,11 +105,12 @@
     uint32_t	flags;		/* flags */
 #define	PCIB_SUBTRACTIVE	0x1
 #define	PCIB_DISABLE_MSI	0x2
+#define	PCIB_DISABLE_MSIX	0x4
+#define	PCIB_ENABLE_ARI		0x8
     uint16_t	command;	/* command register */
     u_int	domain;		/* domain number */
     u_int	pribus;		/* primary bus number */
-    u_int	secbus;		/* secondary bus number */
-    u_int	subbus;		/* subordinate bus number */
+    struct pcib_secbus bus;	/* secondary bus numbers */
 #ifdef NEW_PCIB
     struct pcib_window io;	/* I/O port window */
     struct pcib_window mem;	/* memory window */
@@ -113,15 +128,30 @@
     uint8_t	seclat;		/* secondary bus latency timer */
 };
 
+#define	PCIB_SUPPORTED_ARI_VER	1
+
 typedef uint32_t pci_read_config_fn(int b, int s, int f, int reg, int width);
 
-#ifdef NEW_PCIB
-const char	*pcib_child_name(device_t child);
-#endif
 int		host_pcib_get_busno(pci_read_config_fn read_config, int bus,
     int slot, int func, uint8_t *busnum);
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+struct resource *pci_domain_alloc_bus(int domain, device_t dev, int *rid,
+		    u_long start, u_long end, u_long count, u_int flags);
+int		pci_domain_adjust_bus(int domain, device_t dev,
+		    struct resource *r, u_long start, u_long end);
+int		pci_domain_release_bus(int domain, device_t dev, int rid,
+		    struct resource *r);
+struct resource *pcib_alloc_subbus(struct pcib_secbus *bus, device_t child,
+		    int *rid, u_long start, u_long end, u_long count,
+		    u_int flags);
+void		pcib_setup_secbus(device_t dev, struct pcib_secbus *bus,
+    int min_count);
+#endif
 int		pcib_attach(device_t dev);
 void		pcib_attach_common(device_t dev);
+#ifdef NEW_PCIB
+const char	*pcib_child_name(device_t child);
+#endif
 int		pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result);
 int		pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value);
 struct resource *pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 
@@ -133,8 +163,7 @@
     struct resource *r);
 #endif
 int		pcib_maxslots(device_t dev);
-uint32_t	pcib_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width);
-void		pcib_write_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, uint32_t val, int width);
+int		pcib_maxfuncs(device_t dev);
 int		pcib_route_interrupt(device_t pcib, device_t dev, int pin);
 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);
@@ -141,5 +170,6 @@
 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);
+uint16_t	pcib_get_rid(device_t pcib, device_t dev);
 
 #endif

Added: trunk/sys/dev/pci/pcib_support.c
===================================================================
--- trunk/sys/dev/pci/pcib_support.c	                        (rev 0)
+++ trunk/sys/dev/pci/pcib_support.c	2018-05-27 23:28:52 UTC (rev 10087)
@@ -0,0 +1,69 @@
+/* $MidnightBSD$ */
+/*
+ * Copyright (c) 2014 Sandvine Inc.  All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/dev/pci/pcib_support.c 279470 2015-03-01 04:22:06Z rstone $");
+
+/*
+ * Support functions for the PCI:PCI bridge driver.  This has to be in a
+ * separate file because kernel configurations end up referencing the functions
+ * here even when pci support is compiled out of the kernel.
+ */
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcib_private.h>
+
+#include "pcib_if.h"
+
+int
+pcib_maxfuncs(device_t dev)
+{
+	return (PCI_FUNCMAX);
+}
+
+uint16_t
+pcib_get_rid(device_t pcib, device_t dev)
+{
+	uint8_t bus, slot, func;
+
+	bus = pci_get_bus(dev);
+	slot = pci_get_slot(dev);
+	func = pci_get_function(dev);
+
+	return (PCI_RID(bus, slot, func));
+}
+


Property changes on: trunk/sys/dev/pci/pcib_support.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/dev/pci/pcireg.h
===================================================================
--- trunk/sys/dev/pci/pcireg.h	2018-05-27 23:27:48 UTC (rev 10086)
+++ trunk/sys/dev/pci/pcireg.h	2018-05-27 23:28:52 UTC (rev 10087)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1997, Stefan Esser <se at freebsd.org>
  * All rights reserved.
@@ -23,7 +24,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: stable/9/sys/dev/pci/pcireg.h 257497 2013-11-01 07:03:44Z kib $
+ * $FreeBSD: stable/10/sys/dev/pci/pcireg.h 306520 2016-09-30 18:47:34Z jhb $
  *
  */
 
@@ -48,6 +49,29 @@
 #define	PCIE_REGMAX	4095	/* highest supported config register addr. */
 #define	PCI_MAXHDRTYPE	2
 
+#define	PCIE_ARI_SLOTMAX 0
+#define	PCIE_ARI_FUNCMAX 255
+
+#define	PCI_RID_BUS_SHIFT	8
+#define	PCI_RID_SLOT_SHIFT	3
+#define	PCI_RID_FUNC_SHIFT	0
+
+#define PCI_RID(bus, slot, func) \
+    ((((bus) & PCI_BUSMAX) << PCI_RID_BUS_SHIFT) | \
+    (((slot) & PCI_SLOTMAX) << PCI_RID_SLOT_SHIFT) | \
+    (((func) & PCI_FUNCMAX) << PCI_RID_FUNC_SHIFT))
+
+#define PCI_ARI_RID(bus, func) \
+    ((((bus) & PCI_BUSMAX) << PCI_RID_BUS_SHIFT) | \
+    (((func) & PCIE_ARI_FUNCMAX) << PCI_RID_FUNC_SHIFT))
+
+#define PCI_RID2BUS(rid) (((rid) >> PCI_RID_BUS_SHIFT) & PCI_BUSMAX)
+#define PCI_RID2SLOT(rid) (((rid) >> PCI_RID_SLOT_SHIFT) & PCI_SLOTMAX)
+#define PCI_RID2FUNC(rid) (((rid) >> PCI_RID_FUNC_SHIFT) & PCI_FUNCMAX)
+
+#define PCIE_ARI_SLOT(func) (((func) >> PCI_RID_SLOT_SHIFT) & PCI_SLOTMAX)
+#define PCIE_ARI_FUNC(func) (((func) >> PCI_RID_FUNC_SHIFT) & PCI_FUNCMAX)
+
 /* PCI config header registers for all devices */
 
 #define	PCIR_DEVVENDOR	0x00
@@ -132,7 +156,7 @@
 /* Extended Capability Identification Numbers */
 
 #define	PCIZ_AER	0x0001	/* Advanced Error Reporting */
-#define	PCIZ_VC		0x0002	/* Virtual Channel */
+#define	PCIZ_VC		0x0002	/* Virtual Channel if MFVC Ext Cap not set */
 #define	PCIZ_SERNUM	0x0003	/* Device Serial Number */
 #define	PCIZ_PWRBDGT	0x0004	/* Power Budgeting */
 #define	PCIZ_RCLINK_DCL	0x0005	/* Root Complex Link Declaration */
@@ -139,18 +163,28 @@
 #define	PCIZ_RCLINK_CTL	0x0006	/* Root Complex Internal Link Control */
 #define	PCIZ_RCEC_ASSOC	0x0007	/* Root Complex Event Collector Association */
 #define	PCIZ_MFVC	0x0008	/* Multi-Function Virtual Channel */
+#define	PCIZ_VC2	0x0009	/* Virtual Channel if MFVC Ext Cap set */
 #define	PCIZ_RCRB	0x000a	/* RCRB Header */
 #define	PCIZ_VENDOR	0x000b	/* Vendor Unique */
+#define	PCIZ_CAC	0x000c	/* Configuration Access Correction -- obsolete */
 #define	PCIZ_ACS	0x000d	/* Access Control Services */
 #define	PCIZ_ARI	0x000e	/* Alternative Routing-ID Interpretation */
 #define	PCIZ_ATS	0x000f	/* Address Translation Services */
 #define	PCIZ_SRIOV	0x0010	/* Single Root IO Virtualization */
+#define	PCIZ_MRIOV	0x0011	/* Multiple Root IO Virtualization */
 #define	PCIZ_MULTICAST	0x0012	/* Multicast */
+#define	PCIZ_PAGE_REQ	0x0013	/* Page Request */
+#define	PCIZ_AMD	0x0014	/* Reserved for AMD */
 #define	PCIZ_RESIZE_BAR	0x0015	/* Resizable BAR */
 #define	PCIZ_DPA	0x0016	/* Dynamic Power Allocation */
 #define	PCIZ_TPH_REQ	0x0017	/* TPH Requester */
 #define	PCIZ_LTR	0x0018	/* Latency Tolerance Reporting */
 #define	PCIZ_SEC_PCIE	0x0019	/* Secondary PCI Express */
+#define	PCIZ_PMUX	0x001a	/* Protocol Multiplexing */
+#define	PCIZ_PASID	0x001b	/* Process Address Space ID */
+#define	PCIZ_LN_REQ	0x001c	/* LN Requester */
+#define	PCIZ_DPC	0x001d	/* Downstream Porto Containment */
+#define	PCIZ_L1PM	0x001e	/* L1 PM Substates */
 
 /* config registers for header type 0 devices */
 
@@ -183,7 +217,7 @@
 #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	PCIM_CIS_CONFIG_MASK	0xff
 #define	PCIR_SUBVEND_0	0x2c
 #define	PCIR_SUBDEV_0	0x2e
 #define	PCIR_BIOS	0x30
@@ -227,6 +261,11 @@
 #define	PCIR_BIOS_1	0x38
 #define	PCIR_BRIDGECTL_1 0x3e
 
+#define	PCI_PPBMEMBASE(h,l)  ((((uint64_t)(h) << 32) + ((l)<<16)) & ~0xfffff)
+#define	PCI_PPBMEMLIMIT(h,l) ((((uint64_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)
+
 /* config registers for header type 2 (CardBus) devices */
 
 #define	PCIR_MAX_BAR_2	0
@@ -246,6 +285,9 @@
 #define	PCIR_IOLIMIT0_2	0x30
 #define	PCIR_IOBASE1_2	0x34
 #define	PCIR_IOLIMIT1_2	0x38
+#define	PCIM_CBBIO_16		0x0
+#define	PCIM_CBBIO_32		0x1
+#define	PCIM_CBBIO_MASK		0x3
 
 #define	PCIR_BRIDGECTL_2 0x3e
 
@@ -254,6 +296,11 @@
 
 #define	PCIR_PCCARDIF_2	0x44
 
+#define	PCI_CBBMEMBASE(l)  ((l) & ~0xfffff)
+#define	PCI_CBBMEMLIMIT(l) ((l) | 0xfffff)
+#define	PCI_CBBIOBASE(l)   ((l) & ~0x3)
+#define	PCI_CBBIOLIMIT(l)  ((l) | 0x3)
+
 /* PCI device class, subclass and programming interface definitions */
 
 #define	PCIC_OLD	0x00
@@ -351,6 +398,7 @@
 #define	PCIS_BASEPERIPH_RTC	0x03
 #define	PCIS_BASEPERIPH_PCIHOT	0x04
 #define	PCIS_BASEPERIPH_SDHC	0x05
+#define	PCIS_BASEPERIPH_IOMMU	0x06
 #define	PCIS_BASEPERIPH_OTHER	0x80
 
 #define	PCIC_INPUTDEV	0x09
@@ -440,6 +488,17 @@
 #define	PCIB_BCR_DISCARD_TIMER_STATUS	0x0400
 #define	PCIB_BCR_DISCARD_TIMER_SERREN	0x0800
 
+#define	CBB_BCR_PERR_ENABLE		0x0001
+#define	CBB_BCR_SERR_ENABLE		0x0002
+#define	CBB_BCR_ISA_ENABLE		0x0004
+#define	CBB_BCR_VGA_ENABLE		0x0008
+#define	CBB_BCR_MASTER_ABORT_MODE	0x0020
+#define	CBB_BCR_CARDBUS_RESET		0x0040
+#define	CBB_BCR_IREQ_INT_ENABLE		0x0080
+#define	CBB_BCR_PREFETCH_0_ENABLE	0x0100
+#define	CBB_BCR_PREFETCH_1_ENABLE	0x0200
+#define	CBB_BCR_WRITE_POSTING_ENABLE	0x0400
+
 /* PCI power manangement */
 #define	PCIR_POWER_CAP		0x2
 #define	PCIM_PCAP_SPEC			0x0007
@@ -764,9 +823,25 @@
 #define	PCIEM_ROOT_STA_PME_STATUS	0x00010000
 #define	PCIEM_ROOT_STA_PME_PEND		0x00020000
 #define	PCIER_DEVICE_CAP2	0x24
+#define	PCIEM_CAP2_COMP_TIMO_RANGES	0x0000000f
+#define	PCIEM_CAP2_COMP_TIMO_RANGE_A	0x00000001
+#define	PCIEM_CAP2_COMP_TIMO_RANGE_B	0x00000002
+#define	PCIEM_CAP2_COMP_TIMO_RANGE_C	0x00000004
+#define	PCIEM_CAP2_COMP_TIMO_RANGE_D	0x00000008
+#define	PCIEM_CAP2_COMP_TIMO_DISABLE	0x00000010
+#define	PCIEM_CAP2_ARI			0x00000020
 #define	PCIER_DEVICE_CTL2	0x28
-#define	PCIEM_CTL2_COMP_TIMEOUT_VAL	0x000f
-#define	PCIEM_CTL2_COMP_TIMEOUT_DIS	0x0010
+#define	PCIEM_CTL2_COMP_TIMO_VAL	0x000f
+#define	PCIEM_CTL2_COMP_TIMO_50MS	0x0000
+#define	PCIEM_CTL2_COMP_TIMO_100US	0x0001
+#define	PCIEM_CTL2_COMP_TIMO_10MS	0x0002
+#define	PCIEM_CTL2_COMP_TIMO_55MS	0x0005
+#define	PCIEM_CTL2_COMP_TIMO_210MS	0x0006
+#define	PCIEM_CTL2_COMP_TIMO_900MS	0x0009
+#define	PCIEM_CTL2_COMP_TIMO_3500MS	0x000a
+#define	PCIEM_CTL2_COMP_TIMO_13S	0x000d
+#define	PCIEM_CTL2_COMP_TIMO_64S	0x000e
+#define	PCIEM_CTL2_COMP_TIMO_DISABLE	0x0010
 #define	PCIEM_CTL2_ARI			0x0020
 #define	PCIEM_CTL2_ATOMIC_REQ_ENABLE	0x0040
 #define	PCIEM_CTL2_ATOMIC_EGR_BLOCK	0x0080
@@ -787,117 +862,6 @@
 #define	PCIER_SLOT_CTL2		0x38
 #define	PCIER_SLOT_STA2		0x3a
 
-/* Old compatibility definitions for PCI Express registers */
-#define	PCIR_EXPRESS_FLAGS		PCIER_FLAGS
-#define	PCIM_EXP_FLAGS_VERSION		PCIEM_FLAGS_VERSION	
-#define	PCIM_EXP_FLAGS_TYPE		PCIEM_FLAGS_TYPE	
-#define	PCIM_EXP_TYPE_ENDPOINT		PCIEM_TYPE_ENDPOINT	
-#define	PCIM_EXP_TYPE_LEGACY_ENDPOINT	PCIEM_TYPE_LEGACY_ENDPOINT
-#define	PCIM_EXP_TYPE_ROOT_PORT		PCIEM_TYPE_ROOT_PORT	
-#define	PCIM_EXP_TYPE_UPSTREAM_PORT	PCIEM_TYPE_UPSTREAM_PORT
-#define	PCIM_EXP_TYPE_DOWNSTREAM_PORT	PCIEM_TYPE_DOWNSTREAM_PORT
-#define	PCIM_EXP_TYPE_PCI_BRIDGE	PCIEM_TYPE_PCI_BRIDGE
-#define	PCIM_EXP_TYPE_PCIE_BRIDGE	PCIEM_TYPE_PCIE_BRIDGE
-#define	PCIM_EXP_TYPE_ROOT_INT_EP	PCIEM_TYPE_ROOT_INT_EP
-#define	PCIM_EXP_TYPE_ROOT_EC		PCIEM_TYPE_ROOT_EC	
-#define	PCIM_EXP_FLAGS_SLOT		PCIEM_FLAGS_SLOT	
-#define	PCIM_EXP_FLAGS_IRQ		PCIEM_FLAGS_IRQ	
-#define	PCIR_EXPRESS_DEVICE_CAP		PCIER_DEVICE_CAP
-#define	PCIM_EXP_CAP_MAX_PAYLOAD	PCIEM_CAP_MAX_PAYLOAD
-#define	PCIM_EXP_CAP_PHANTHOM_FUNCS	PCIEM_CAP_PHANTHOM_FUNCS
-#define	PCIM_EXP_CAP_EXT_TAG_FIELD	PCIEM_CAP_EXT_TAG_FIELD
-#define	PCIM_EXP_CAP_L0S_LATENCY	PCIEM_CAP_L0S_LATENCY
-#define	PCIM_EXP_CAP_L1_LATENCY		PCIEM_CAP_L1_LATENCY	
-#define	PCIM_EXP_CAP_ROLE_ERR_RPT	PCIEM_CAP_ROLE_ERR_RPT
-#define	PCIM_EXP_CAP_SLOT_PWR_LIM_VAL	PCIEM_CAP_SLOT_PWR_LIM_VAL
-#define	PCIM_EXP_CAP_SLOT_PWR_LIM_SCALE	PCIEM_CAP_SLOT_PWR_LIM_SCALE
-#define	PCIM_EXP_CAP_FLR		PCIEM_CAP_FLR	
-#define	PCIR_EXPRESS_DEVICE_CTL		PCIER_DEVICE_CTL
-#define	PCIM_EXP_CTL_COR_ENABLE		PCIEM_CTL_COR_ENABLE	
-#define	PCIM_EXP_CTL_NFER_ENABLE	PCIEM_CTL_NFER_ENABLE
-#define	PCIM_EXP_CTL_FER_ENABLE		PCIEM_CTL_FER_ENABLE	
-#define	PCIM_EXP_CTL_URR_ENABLE		PCIEM_CTL_URR_ENABLE	
-#define	PCIM_EXP_CTL_RELAXED_ORD_ENABLE	PCIEM_CTL_RELAXED_ORD_ENABLE
-#define	PCIM_EXP_CTL_MAX_PAYLOAD	PCIEM_CTL_MAX_PAYLOAD
-#define	PCIM_EXP_CTL_EXT_TAG_FIELD	PCIEM_CTL_EXT_TAG_FIELD
-#define	PCIM_EXP_CTL_PHANTHOM_FUNCS	PCIEM_CTL_PHANTHOM_FUNCS
-#define	PCIM_EXP_CTL_AUX_POWER_PM	PCIEM_CTL_AUX_POWER_PM
-#define	PCIM_EXP_CTL_NOSNOOP_ENABLE	PCIEM_CTL_NOSNOOP_ENABLE
-#define	PCIM_EXP_CTL_MAX_READ_REQUEST	PCIEM_CTL_MAX_READ_REQUEST
-#define	PCIM_EXP_CTL_BRDG_CFG_RETRY	PCIEM_CTL_BRDG_CFG_RETRY
-#define	PCIM_EXP_CTL_INITIATE_FLR	PCIEM_CTL_INITIATE_FLR
-#define	PCIR_EXPRESS_DEVICE_STA		PCIER_DEVICE_STA
-#define	PCIM_EXP_STA_CORRECTABLE_ERROR	PCIEM_STA_CORRECTABLE_ERROR
-#define	PCIM_EXP_STA_NON_FATAL_ERROR	PCIEM_STA_NON_FATAL_ERROR
-#define	PCIM_EXP_STA_FATAL_ERROR	PCIEM_STA_FATAL_ERROR
-#define	PCIM_EXP_STA_UNSUPPORTED_REQ	PCIEM_STA_UNSUPPORTED_REQ
-#define	PCIM_EXP_STA_AUX_POWER		PCIEM_STA_AUX_POWER	
-#define	PCIM_EXP_STA_TRANSACTION_PND	PCIEM_STA_TRANSACTION_PND
-#define	PCIR_EXPRESS_LINK_CAP		PCIER_LINK_CAP
-#define	PCIM_LINK_CAP_MAX_SPEED		PCIEM_LINK_CAP_MAX_SPEED	
-#define	PCIM_LINK_CAP_MAX_WIDTH		PCIEM_LINK_CAP_MAX_WIDTH	
-#define	PCIM_LINK_CAP_ASPM		PCIEM_LINK_CAP_ASPM	
-#define	PCIM_LINK_CAP_L0S_EXIT		PCIEM_LINK_CAP_L0S_EXIT	
-#define	PCIM_LINK_CAP_L1_EXIT		PCIEM_LINK_CAP_L1_EXIT	
-#define	PCIM_LINK_CAP_CLOCK_PM		PCIEM_LINK_CAP_CLOCK_PM	
-#define	PCIM_LINK_CAP_SURPRISE_DOWN	PCIEM_LINK_CAP_SURPRISE_DOWN
-#define	PCIM_LINK_CAP_DL_ACTIVE		PCIEM_LINK_CAP_DL_ACTIVE	
-#define	PCIM_LINK_CAP_LINK_BW_NOTIFY	PCIEM_LINK_CAP_LINK_BW_NOTIFY
-#define	PCIM_LINK_CAP_ASPM_COMPLIANCE	PCIEM_LINK_CAP_ASPM_COMPLIANCE
-#define	PCIM_LINK_CAP_PORT		PCIEM_LINK_CAP_PORT	
-#define	PCIR_EXPRESS_LINK_CTL		PCIER_LINK_CTL
-#define	PCIM_EXP_LINK_CTL_ASPMC_DIS	PCIEM_LINK_CTL_ASPMC_DIS
-#define	PCIM_EXP_LINK_CTL_ASPMC_L0S	PCIEM_LINK_CTL_ASPMC_L0S
-#define	PCIM_EXP_LINK_CTL_ASPMC_L1	PCIEM_LINK_CTL_ASPMC_L1
-#define	PCIM_EXP_LINK_CTL_ASPMC		PCIEM_LINK_CTL_ASPMC	
-#define	PCIM_EXP_LINK_CTL_RCB		PCIEM_LINK_CTL_RCB	
-#define	PCIM_EXP_LINK_CTL_LINK_DIS	PCIEM_LINK_CTL_LINK_DIS
-#define	PCIM_EXP_LINK_CTL_RETRAIN_LINK	PCIEM_LINK_CTL_RETRAIN_LINK
-#define	PCIM_EXP_LINK_CTL_COMMON_CLOCK	PCIEM_LINK_CTL_COMMON_CLOCK
-#define	PCIM_EXP_LINK_CTL_EXTENDED_SYNC	PCIEM_LINK_CTL_EXTENDED_SYNC
-#define	PCIM_EXP_LINK_CTL_ECPM		PCIEM_LINK_CTL_ECPM	
-#define	PCIM_EXP_LINK_CTL_HAWD		PCIEM_LINK_CTL_HAWD	
-#define	PCIM_EXP_LINK_CTL_LBMIE		PCIEM_LINK_CTL_LBMIE	
-#define	PCIM_EXP_LINK_CTL_LABIE		PCIEM_LINK_CTL_LABIE	
-#define	PCIR_EXPRESS_LINK_STA		PCIER_LINK_STA
-#define	PCIM_LINK_STA_SPEED		PCIEM_LINK_STA_SPEED	
-#define	PCIM_LINK_STA_WIDTH		PCIEM_LINK_STA_WIDTH	
-#define	PCIM_LINK_STA_TRAINING_ERROR	PCIEM_LINK_STA_TRAINING_ERROR
-#define	PCIM_LINK_STA_TRAINING		PCIEM_LINK_STA_TRAINING	
-#define	PCIM_LINK_STA_SLOT_CLOCK	PCIEM_LINK_STA_SLOT_CLOCK
-#define	PCIM_LINK_STA_DL_ACTIVE		PCIEM_LINK_STA_DL_ACTIVE	
-#define	PCIM_LINK_STA_LINK_BW_MGMT	PCIEM_LINK_STA_LINK_BW_MGMT
-#define	PCIM_LINK_STA_LINK_AUTO_BW	PCIEM_LINK_STA_LINK_AUTO_BW
-#define	PCIR_EXPRESS_SLOT_CAP		PCIER_SLOT_CAP
-#define	PCIR_EXPRESS_SLOT_CTL		PCIER_SLOT_CTL
-#define	PCIR_EXPRESS_SLOT_STA		PCIER_SLOT_STA
-#define	PCIR_EXPRESS_ROOT_CTL		PCIER_ROOT_CTL
-#define	PCIR_EXPRESS_ROOT_CAP		PCIER_ROOT_CAP
-#define	PCIR_EXPRESS_ROOT_STA		PCIER_ROOT_STA
-#define	PCIR_EXPRESS_DEVICE_CAP2	PCIER_DEVICE_CAP2
-#define	PCIR_EXPRESS_DEVICE_CTL2	PCIER_DEVICE_CTL2
-#define	PCIM_EXP_CTL2_COMP_TIMEOUT_VAL	PCIEM_CTL2_COMP_TIMEOUT_VAL
-#define	PCIM_EXP_CTL2_COMP_TIMEOUT_DIS	PCIEM_CTL2_COMP_TIMEOUT_DIS
-#define	PCIM_EXP_CTL2_ARI		PCIEM_CTL2_ARI	
-#define	PCIM_EXP_CTL2_ATOMIC_REQ_ENABLE	PCIEM_CTL2_ATOMIC_REQ_ENABLE
-#define	PCIM_EXP_CTL2_ATOMIC_EGR_BLOCK	PCIEM_CTL2_ATOMIC_EGR_BLOCK
-#define	PCIM_EXP_CTL2_ID_ORDERED_REQ_EN	PCIEM_CTL2_ID_ORDERED_REQ_EN
-#define	PCIM_EXP_CTL2_ID_ORDERED_CMP_EN	PCIEM_CTL2_ID_ORDERED_CMP_EN
-#define	PCIM_EXP_CTL2_LTR_ENABLE	PCIEM_CTL2_LTR_ENABLE
-#define	PCIM_EXP_CTL2_OBFF		PCIEM_CTL2_OBFF	
-#define	PCIM_EXP_OBFF_DISABLE		PCIEM_OBFF_DISABLE	
-#define	PCIM_EXP_OBFF_MSGA_ENABLE	PCIEM_OBFF_MSGA_ENABLE
-#define	PCIM_EXP_OBFF_MSGB_ENABLE	PCIEM_OBFF_MSGB_ENABLE
-#define	PCIM_EXP_OBFF_WAKE_ENABLE	PCIEM_OBFF_WAKE_ENABLE
-#define	PCIM_EXP_CTL2_END2END_TLP	PCIEM_CTL2_END2END_TLP
-#define	PCIR_EXPRESS_DEVICE_STA2	PCIER_DEVICE_STA2
-#define	PCIR_EXPRESS_LINK_CAP2		PCIER_LINK_CAP2
-#define	PCIR_EXPRESS_LINK_CTL2		PCIER_LINK_CTL2
-#define	PCIR_EXPRESS_LINK_STA2		PCIER_LINK_STA2
-#define	PCIR_EXPRESS_SLOT_CAP2		PCIER_SLOT_CAP2
-#define	PCIR_EXPRESS_SLOT_CTL2		PCIER_SLOT_CTL2
-#define	PCIR_EXPRESS_SLOT_STA2		PCIER_SLOT_STA2
-
 /* MSI-X definitions */
 #define	PCIR_MSIX_CTRL		0x2
 #define	PCIM_MSIXCTRL_MSIX_ENABLE	0x8000
@@ -995,3 +959,4 @@
 /* Serial Number definitions */
 #define	PCIR_SERIAL_LOW		0x04
 #define	PCIR_SERIAL_HIGH	0x08
+

Modified: trunk/sys/dev/pci/pcivar.h
===================================================================
--- trunk/sys/dev/pci/pcivar.h	2018-05-27 23:27:48 UTC (rev 10086)
+++ trunk/sys/dev/pci/pcivar.h	2018-05-27 23:28:52 UTC (rev 10087)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1997, Stefan Esser <se at freebsd.org>
  * All rights reserved.
@@ -23,7 +24,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.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/pci/pcivar.h 306520 2016-09-30 18:47:34Z jhb $
  *
  */
 
@@ -57,6 +58,7 @@
 struct vpd_readonly {
     char	keyword[2];
     char	*value;
+    int		len;
 };
 
 struct vpd_write {
@@ -123,6 +125,25 @@
     uint64_t	ht_msiaddr;	/* MSI mapping base address */
 };
 
+/* Interesting values for PCI-express */
+struct pcicfg_pcie {
+    uint8_t	pcie_location;	/* Offset of PCI-e capability registers. */
+    uint8_t	pcie_type;	/* Device type. */
+    uint16_t	pcie_flags;	/* Device capabilities register. */
+    uint16_t	pcie_device_ctl; /* Device control register. */
+    uint16_t	pcie_link_ctl;	/* Link control register. */
+    uint16_t	pcie_slot_ctl;	/* Slot control register. */
+    uint16_t	pcie_root_ctl;	/* Root control register. */
+    uint16_t	pcie_device_ctl2; /* Second device control register. */
+    uint16_t	pcie_link_ctl2;	/* Second link control register. */
+    uint16_t	pcie_slot_ctl2;	/* Second slot control register. */
+};
+
+struct pcicfg_pcix {
+    uint16_t	pcix_command;
+    uint8_t	pcix_location;	/* Offset of PCI-X capability registers. */
+};
+
 /* config header information common to all header types */
 typedef struct pcicfg {
     struct device *dev;		/* device which owns this */
@@ -164,15 +185,12 @@
     struct pcicfg_msi msi;	/* PCI MSI */
     struct pcicfg_msix msix;	/* PCI MSI-X */
     struct pcicfg_ht ht;	/* HyperTransport */
+    struct pcicfg_pcie pcie;	/* PCI Express */
+    struct pcicfg_pcix pcix;	/* PCI-X */
 } pcicfgregs;
 
 /* additional type 1 device config header information (PCI to PCI bridge) */
 
-#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 */
     pci_addr_t	pmemlimit;	/* topmost address of prefetchable memory */
@@ -350,9 +368,9 @@
 }
 
 static __inline int
-pci_get_vpd_readonly(device_t dev, const char *kw, const char **identptr)
+pci_get_vpd_readonly(device_t dev, const char *kw, const char **vptr)
 {
-    return(PCI_GET_VPD_READONLY(device_get_parent(dev), dev, kw, identptr));
+    return(PCI_GET_VPD_READONLY(device_get_parent(dev), dev, kw, vptr));
 }
 
 /*
@@ -409,7 +427,7 @@
 static __inline int
 pci_find_cap(device_t dev, int capability, int *capreg)
 {
-    return (PCI_FIND_EXTCAP(device_get_parent(dev), dev, capability, capreg));
+    return (PCI_FIND_CAP(device_get_parent(dev), dev, capability, capreg));
 }
 
 static __inline int
@@ -419,6 +437,12 @@
 }
 
 static __inline int
+pci_find_htcap(device_t dev, int capability, int *capreg)
+{
+    return (PCI_FIND_HTCAP(device_get_parent(dev), dev, capability, capreg));
+}
+
+static __inline int
 pci_alloc_msi(device_t dev, int *count)
 {
     return (PCI_ALLOC_MSI(device_get_parent(dev), dev, count));
@@ -430,6 +454,24 @@
     return (PCI_ALLOC_MSIX(device_get_parent(dev), dev, count));
 }
 
+static __inline void
+pci_enable_msi(device_t dev, uint64_t address, uint16_t data)
+{
+    PCI_ENABLE_MSI(device_get_parent(dev), dev, address, data);
+}
+
+static __inline void
+pci_enable_msix(device_t dev, u_int index, uint64_t address, uint32_t data)
+{
+    PCI_ENABLE_MSIX(device_get_parent(dev), dev, index, address, data);
+}
+
+static __inline void
+pci_disable_msi(device_t dev)
+{
+    PCI_DISABLE_MSI(device_get_parent(dev), dev);
+}
+
 static __inline int
 pci_remap_msix(device_t dev, int count, const u_int *vectors)
 {
@@ -454,6 +496,31 @@
     return (PCI_MSIX_COUNT(device_get_parent(dev), dev));
 }
 
+static __inline int
+pci_msix_pba_bar(device_t dev)
+{
+    return (PCI_MSIX_PBA_BAR(device_get_parent(dev), dev));
+}
+
+static __inline int
+pci_msix_table_bar(device_t dev)
+{
+    return (PCI_MSIX_TABLE_BAR(device_get_parent(dev), dev));
+}
+
+static __inline uint16_t
+pci_get_rid(device_t dev)
+{
+	return (PCI_GET_RID(device_get_parent(dev), dev));
+}
+
+static __inline void
+pci_child_added(device_t dev)
+{
+
+    return (PCI_CHILD_ADDED(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);
@@ -463,14 +530,32 @@
 int	pci_pending_msix(device_t dev, u_int index);
 
 int	pci_msi_device_blacklisted(device_t dev);
+int	pci_msix_device_blacklisted(device_t dev);
 
 void	pci_ht_map_msi(device_t dev, uint64_t addr);
 
+device_t pci_find_pcie_root_port(device_t dev);
+int	pci_get_max_payload(device_t dev);
 int	pci_get_max_read_req(device_t dev);
 void	pci_restore_state(device_t dev);
 void	pci_save_state(device_t dev);
 int	pci_set_max_read_req(device_t dev, int size);
+uint32_t pcie_read_config(device_t dev, int reg, int width);
+void	pcie_write_config(device_t dev, int reg, uint32_t value, int width);
+uint32_t pcie_adjust_config(device_t dev, int reg, uint32_t mask,
+	    uint32_t value, int width);
+bool	pcie_flr(device_t dev, u_int max_delay, bool force);
+int	pcie_get_max_completion_timeout(device_t dev);
+bool	pcie_wait_for_pending_transactions(device_t dev, u_int max_delay);
 
+#ifdef BUS_SPACE_MAXADDR
+#if (BUS_SPACE_MAXADDR > 0xFFFFFFFF)
+#define	PCI_DMA_BOUNDARY	0x100000000
+#else
+#define	PCI_DMA_BOUNDARY	0
+#endif
+#endif
+
 #endif	/* _SYS_BUS_H_ */
 
 /*
@@ -488,5 +573,13 @@
 
 struct pci_map *pci_find_bar(device_t dev, int reg);
 int	pci_bar_enabled(device_t dev, struct pci_map *pm);
+struct pcicfg_vpd *pci_fetch_vpd_list(device_t dev);
 
+#define	VGA_PCI_BIOS_SHADOW_ADDR	0xC0000
+#define	VGA_PCI_BIOS_SHADOW_SIZE	131072
+
+int	vga_pci_is_boot_display(device_t dev);
+void *	vga_pci_map_bios(device_t dev, size_t *size);
+void	vga_pci_unmap_bios(device_t dev, void *bios);
+
 #endif /* _PCIVAR_H_ */

Modified: trunk/sys/dev/pci/vga_pci.c
===================================================================
--- trunk/sys/dev/pci/vga_pci.c	2018-05-27 23:27:48 UTC (rev 10086)
+++ trunk/sys/dev/pci/vga_pci.c	2018-05-27 23:28:52 UTC (rev 10087)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2005 John Baldwin <jhb at FreeBSD.org>
  * All rights reserved.
@@ -10,9 +11,6 @@
  * 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
@@ -28,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/pci/vga_pci.c 284503 2015-06-17 07:41:53Z hselasky $");
 
 /*
  * Simple driver for PCI VGA display devices.  Drivers such as agp(4) and
@@ -46,6 +44,11 @@
 #include <sys/sysctl.h>
 #include <sys/systm.h>
 
+#if defined(__amd64__) || defined(__i386__) || defined(__ia64__)
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#endif
+
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
 
@@ -56,22 +59,153 @@
 
 struct vga_pci_softc {
 	device_t	vga_msi_child;	/* Child driver using MSI. */
-	struct vga_resource vga_res[PCIR_MAX_BAR_0 + 1];
+	struct vga_resource vga_bars[PCIR_MAX_BAR_0 + 1];
+	struct vga_resource vga_bios;
 };
 
 SYSCTL_DECL(_hw_pci);
 
+static struct vga_resource *lookup_res(struct vga_pci_softc *sc, int rid);
+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);
+static int	vga_pci_release_resource(device_t dev, device_t child, int type,
+    int rid, struct resource *r);
+
 int vga_pci_default_unit = -1;
 TUNABLE_INT("hw.pci.default_vgapci_unit", &vga_pci_default_unit);
 SYSCTL_INT(_hw_pci, OID_AUTO, default_vgapci_unit, CTLFLAG_RDTUN,
     &vga_pci_default_unit, -1, "Default VGA-compatible display");
 
+int
+vga_pci_is_boot_display(device_t dev)
+{
+	int unit;
+	device_t pcib;
+	uint16_t config;
+
+	/* Check that the given device is a video card */
+	if ((pci_get_class(dev) != PCIC_DISPLAY &&
+	    (pci_get_class(dev) != PCIC_OLD ||
+	     pci_get_subclass(dev) != PCIS_OLD_VGA)))
+		return (0);
+
+	unit = device_get_unit(dev);
+
+	if (vga_pci_default_unit >= 0) {
+		/*
+		 * The boot display device was determined by a previous
+		 * call to this function, or the user forced it using
+		 * the hw.pci.default_vgapci_unit tunable.
+		 */
+		return (vga_pci_default_unit == unit);
+	}
+
+	/*
+	 * The primary video card used as a boot display must have the
+	 * "I/O" and "Memory Address Space Decoding" bits set in its
+	 * Command register.
+	 *
+	 * Furthermore, if the card is attached to a bridge, instead of
+	 * the root PCI bus, the bridge must have the "VGA Enable" bit
+	 * set in its Control register.
+	 */
+
+	pcib = device_get_parent(device_get_parent(dev));
+	if (device_get_devclass(device_get_parent(pcib)) ==
+	    devclass_find("pci")) {
+		/*
+		 * The parent bridge is a PCI-to-PCI bridge: check the
+		 * value of the "VGA Enable" bit.
+		 */
+		config = pci_read_config(pcib, PCIR_BRIDGECTL_1, 2);
+		if ((config & PCIB_BCR_VGA_ENABLE) == 0)
+			return (0);
+	}
+
+	config = pci_read_config(dev, PCIR_COMMAND, 2);
+	if ((config & (PCIM_CMD_PORTEN | PCIM_CMD_MEMEN)) == 0)
+		return (0);
+
+	/*
+	 * Disable interrupts until a chipset driver is loaded for
+	 * this PCI device. Else unhandled display adapter interrupts
+	 * might freeze the CPU.
+	 */
+	pci_write_config(dev, PCIR_COMMAND, config | PCIM_CMD_INTxDIS, 2);
+
+	/* This video card is the boot display: record its unit number. */
+	vga_pci_default_unit = unit;
+	device_set_flags(dev, 1);
+
+	return (1);
+}
+
+void *
+vga_pci_map_bios(device_t dev, size_t *size)
+{
+	int rid;
+	struct resource *res;
+
+#if defined(__amd64__) || defined(__i386__) || defined(__ia64__)
+	if (vga_pci_is_boot_display(dev)) {
+		/*
+		 * On x86, the System BIOS copy the default display
+		 * device's Video BIOS at a fixed location in system
+		 * memory (0xC0000, 128 kBytes long) at boot time.
+		 *
+		 * We use this copy for the default boot device, because
+		 * the original ROM may not be valid after boot.
+		 */
+
+		*size = VGA_PCI_BIOS_SHADOW_SIZE;
+		return (pmap_mapbios(VGA_PCI_BIOS_SHADOW_ADDR, *size));
+	}
+#endif
+
+	rid = PCIR_BIOS;
+	res = vga_pci_alloc_resource(dev, NULL, SYS_RES_MEMORY, &rid, 0ul,
+	    ~0ul, 1, RF_ACTIVE);
+	if (res == NULL) {
+		return (NULL);
+	}
+
+	*size = rman_get_size(res);
+	return (rman_get_virtual(res));
+}
+
+void
+vga_pci_unmap_bios(device_t dev, void *bios)
+{
+	struct vga_resource *vr;
+
+	if (bios == NULL) {
+		return;
+	}
+
+#if defined(__amd64__) || defined(__i386__) || defined(__ia64__)
+	if (vga_pci_is_boot_display(dev)) {
+		/* We mapped the BIOS shadow copy located at 0xC0000. */
+		pmap_unmapdev((vm_offset_t)bios, VGA_PCI_BIOS_SHADOW_SIZE);
+
+		return;
+	}
+#endif
+
+	/*
+	 * Look up the PCIR_BIOS resource in our softc.  It should match
+	 * the address we returned previously.
+	 */
+	vr = lookup_res(device_get_softc(dev), PCIR_BIOS);
+	KASSERT(vr->vr_res != NULL, ("vga_pci_unmap_bios: bios not mapped"));
+	KASSERT(rman_get_virtual(vr->vr_res) == bios,
+	    ("vga_pci_unmap_bios: mismatch"));
+	vga_pci_release_resource(dev, NULL, SYS_RES_MEMORY, PCIR_BIOS,
+	    vr->vr_res);
+}
+
 static int
 vga_pci_probe(device_t dev)
 {
-	device_t bdev;
-	int unit;
-	uint16_t bctl;
 
 	switch (pci_get_class(dev)) {
 	case PCIC_DISPLAY:
@@ -85,13 +219,7 @@
 	}
 
 	/* Probe default display. */
-	unit = device_get_unit(dev);
-	bdev = device_get_parent(device_get_parent(dev));
-	bctl = pci_read_config(bdev, PCIR_BRIDGECTL_1, 2);
-	if (vga_pci_default_unit < 0 && (bctl & PCIB_BCR_VGA_ENABLE) != 0)
-		vga_pci_default_unit = unit;
-	if (vga_pci_default_unit == unit)
-		device_set_flags(dev, 1);
+	vga_pci_is_boot_display(dev);
 
 	device_set_desc(dev, "VGA-compatible display");
 	return (BUS_PROBE_GENERIC);
@@ -107,6 +235,10 @@
 	device_add_child(dev, "drm", -1);
 	device_add_child(dev, "drmn", -1);
 	bus_generic_attach(dev);
+
+	if (vga_pci_is_boot_display(dev))
+		device_printf(dev, "Boot video device\n");
+
 	return (0);
 }
 
@@ -156,12 +288,24 @@
 	return (BUS_TEARDOWN_INTR(device_get_parent(dev), dev, irq, cookie));
 }
 
+static struct vga_resource *
+lookup_res(struct vga_pci_softc *sc, int rid)
+{
+	int bar;
+
+	if (rid == PCIR_BIOS)
+		return (&sc->vga_bios);
+	bar = PCI_RID2BAR(rid);
+	if (bar >= 0 && bar <= PCIR_MAX_BAR_0)
+		return (&sc->vga_bars[bar]);
+	return (NULL);
+}
+
 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)
 {
-	struct vga_pci_softc *sc;
-	int bar;
+	struct vga_resource *vr;
 
 	switch (type) {
 	case SYS_RES_MEMORY:
@@ -170,16 +314,15 @@
 		 * For BARs, we cache the resource so that we only allocate it
 		 * from the PCI bus once.
 		 */
-		bar = PCI_RID2BAR(*rid);
-		if (bar < 0 || bar > PCIR_MAX_BAR_0)
+		vr = lookup_res(device_get_softc(dev), *rid);
+		if (vr == NULL)
 			return (NULL);
-		sc = device_get_softc(dev);
-		if (sc->vga_res[bar].vr_res == NULL)
-			sc->vga_res[bar].vr_res = bus_alloc_resource(dev, type,
-			    rid, start, end, count, flags);
-		if (sc->vga_res[bar].vr_res != NULL)
-			sc->vga_res[bar].vr_refs++;
-		return (sc->vga_res[bar].vr_res);
+		if (vr->vr_res == NULL)
+			vr->vr_res = bus_alloc_resource(dev, type, rid, start,
+			    end, count, flags);
+		if (vr->vr_res != NULL)
+			vr->vr_refs++;
+		return (vr->vr_res);
 	}
 	return (bus_alloc_resource(dev, type, rid, start, end, count, flags));
 }
@@ -188,8 +331,8 @@
 vga_pci_release_resource(device_t dev, device_t child, int type, int rid,
     struct resource *r)
 {
-	struct vga_pci_softc *sc;
-	int bar, error;
+	struct vga_resource *vr;
+	int error;
 
 	switch (type) {
 	case SYS_RES_MEMORY:
@@ -198,24 +341,22 @@
 		 * For BARs, we release the resource from the PCI bus
 		 * when the last child reference goes away.
 		 */
-		bar = PCI_RID2BAR(rid);
-		if (bar < 0 || bar > PCIR_MAX_BAR_0)
+		vr = lookup_res(device_get_softc(dev), rid);
+		if (vr == NULL)
 			return (EINVAL);
-		sc = device_get_softc(dev);
-		if (sc->vga_res[bar].vr_res == NULL)
+		if (vr->vr_res == NULL)
 			return (EINVAL);
-		KASSERT(sc->vga_res[bar].vr_res == r,
-		    ("vga_pci resource mismatch"));
-		if (sc->vga_res[bar].vr_refs > 1) {
-			sc->vga_res[bar].vr_refs--;
+		KASSERT(vr->vr_res == r, ("vga_pci resource mismatch"));
+		if (vr->vr_refs > 1) {
+			vr->vr_refs--;
 			return (0);
 		}
-		KASSERT(sc->vga_res[bar].vr_refs > 0,
+		KASSERT(vr->vr_refs > 0,
 		    ("vga_pci resource reference count underflow"));
 		error = bus_release_resource(dev, type, rid, r);
 		if (error == 0) {
-			sc->vga_res[bar].vr_res = NULL;
-			sc->vga_res[bar].vr_refs = 0;
+			vr->vr_res = NULL;
+			vr->vr_refs = 0;
 		}
 		return (error);
 	}
@@ -315,6 +456,14 @@
 }
 
 static int
+vga_pci_find_cap(device_t dev, device_t child, int capability,
+    int *capreg)
+{
+
+	return (pci_find_cap(dev, capability, capreg));
+}
+
+static int
 vga_pci_find_extcap(device_t dev, device_t child, int capability,
     int *capreg)
 {
@@ -323,6 +472,14 @@
 }
 
 static int
+vga_pci_find_htcap(device_t dev, device_t child, int capability,
+    int *capreg)
+{
+
+	return (pci_find_htcap(dev, capability, capreg));
+}
+
+static int
 vga_pci_alloc_msi(device_t dev, device_t child, int *count)
 {
 	struct vga_pci_softc *sc;
@@ -431,7 +588,9 @@
 	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_cap,		vga_pci_find_cap),
 	DEVMETHOD(pci_find_extcap,	vga_pci_find_extcap),
+	DEVMETHOD(pci_find_htcap,	vga_pci_find_htcap),
 	DEVMETHOD(pci_alloc_msi,	vga_pci_alloc_msi),
 	DEVMETHOD(pci_alloc_msix,	vga_pci_alloc_msix),
 	DEVMETHOD(pci_remap_msix,	vga_pci_remap_msix),



More information about the Midnightbsd-cvs mailing list