svn commit: r284034 - in stable/10/sys/dev: pccbb pci

John Baldwin jhb at FreeBSD.org
Fri Jun 5 17:05:12 UTC 2015


Author: jhb
Date: Fri Jun  5 17:05:09 2015
New Revision: 284034
URL: https://svnweb.freebsd.org/changeset/base/284034

Log:
  MFC 274633,274639,274663,277233-277235,281870,281871,281873,281874:
  Various fixes for suspend and resume of PCI to PCI and PCI to Cardbus
  bridges.
  
  274633:
  
  Remove stray empty comment. The code is adequately explained in the
  block comment above, so there's nothing to add here.
  
  274639:
  
  Modernize comments about BIOSes being lame since in this detail they
  aren't lame, the rules changed along the way. Catch up to 1999 or so
  with the new rules.
  
  274663:
  
  Fix typo pointed out by avg@ and Joerg Sonnenberger. Add a clarifying
  sentence too.
  
  277233:
  
  Suspend and resume were the only two functions not to follow the brdev
  convention here, so fix that.
  
  277234:
  
  Move the suspsned and resume functions to the bus attachment. They
  were accessing PCI config registers, which won't work for the ISA
  version.
  
  277235:
  
  Always enable I/O, memory and dma cycles. Some BIOSes don't enable
  them, sometimes they are reset for power state transitions or during
  whatever happens while suspended. Also, it is good practice to always
  do this.
  
  281870:
  
  Cosmetic change: use PCIR_SECLAT_2 rather than PCIR_SECLAT_1.
  
  281871:
  
  The minimim grant and maximum latency PCI config registers are only valid
  for type 0 devices, not type 1 or 2 bridges.  Don't read them for bridge
  devices during bus scans and return an error when attempting to read them
  as ivars for bridge devices.
  
  281873:
  
  Don't explicitly manage power states for PCI-PCI bridge devices in the
  driver's suspend and resume routines.  These have been redundant no-ops
  since r214065 changed the PCI bus driver to manage power states for
  all devices (including type 1/2 bridge devices) during suspend and resume.
  
  281874:
  
  Update the pci_cfg_save/restore routines to operate on bridge devices
  (type 1 and type 2) as well as leaf devices (type 0).  In particular,
  this allows the existing PCI bus logic to save and restore capability
  registers such as MSI and PCI-express work for bridge devices rather than
  requiring that code to be duplicated in bridge drivers.  It also means
  that bridge drivers no longer need to save and restore basic registers
  such as the PCI command register or BARs nor manage powerstates for the
  bridge device.
  
  While here, pci_setup_secbus() has been changed to initialize the 'sec'
  and 'sub' fields in the 'secbus' structure instead of requiring the pcib
  and pccbb drivers to do this in the NEW_PCIB + PCI_RES_BUS case.

Modified:
  stable/10/sys/dev/pccbb/pccbb.c
  stable/10/sys/dev/pccbb/pccbb_isa.c
  stable/10/sys/dev/pccbb/pccbb_pci.c
  stable/10/sys/dev/pccbb/pccbbvar.h
  stable/10/sys/dev/pci/pci.c
  stable/10/sys/dev/pci/pci_pci.c
  stable/10/sys/dev/pci/pcib_private.h
  stable/10/sys/dev/pci/pcivar.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/dev/pccbb/pccbb.c
==============================================================================
--- stable/10/sys/dev/pccbb/pccbb.c	Fri Jun  5 17:04:50 2015	(r284033)
+++ stable/10/sys/dev/pccbb/pccbb.c	Fri Jun  5 17:05:09 2015	(r284034)
@@ -996,8 +996,6 @@ cbb_cardbus_reset_power(device_t brdev, 
 	 * a cardbus bus, so that's the only register we check here.
 	 */
 	if (on && CBB_CARD_PRESENT(cbb_get(sc, CBB_SOCKET_STATE))) {
-		/*
-		 */
 		PCI_MASK_CONFIG(brdev, CBBR_BRIDGECTRL,
 		    &~CBBM_BRIDGECTRL_RESET, 2);
 		b = pcib_get_bus(child);
@@ -1569,57 +1567,6 @@ cbb_write_ivar(device_t brdev, device_t 
 }
 
 int
-cbb_suspend(device_t self)
-{
-	int			error = 0;
-	struct cbb_softc	*sc = device_get_softc(self);
-
-	error = bus_generic_suspend(self);
-	if (error != 0)
-		return (error);
-	cbb_set(sc, CBB_SOCKET_MASK, 0);	/* Quiet hardware */
-	sc->cardok = 0;				/* Card is bogus now */
-	return (0);
-}
-
-int
-cbb_resume(device_t self)
-{
-	int	error = 0;
-	struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(self);
-	uint32_t tmp;
-
-	/*
-	 * Some BIOSes will not save the BARs for the pci chips, so we
-	 * must do it ourselves.  If the BAR is reset to 0 for an I/O
-	 * device, it will read back as 0x1, so no explicit test for
-	 * memory devices are needed.
-	 *
-	 * Note: The PCI bus code should do this automatically for us on
-	 * suspend/resume, but until it does, we have to cope.
-	 */
-	pci_write_config(self, CBBR_SOCKBASE, rman_get_start(sc->base_res), 4);
-	DEVPRINTF((self, "PCI Memory allocated: %08lx\n",
-	    rman_get_start(sc->base_res)));
-
-	sc->chipinit(sc);
-
-	/* reset interrupt -- Do we really need to do this? */
-	tmp = cbb_get(sc, CBB_SOCKET_EVENT);
-	cbb_set(sc, CBB_SOCKET_EVENT, tmp);
-
-	/* CSC Interrupt: Card detect interrupt on */
-	cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD);
-
-	/* Signal the thread to wakeup. */
-	wakeup(&sc->intrhand);
-
-	error = bus_generic_resume(self);
-
-	return (error);
-}
-
-int
 cbb_child_present(device_t parent, device_t child)
 {
 	struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(parent);

Modified: stable/10/sys/dev/pccbb/pccbb_isa.c
==============================================================================
--- stable/10/sys/dev/pccbb/pccbb_isa.c	Fri Jun  5 17:04:50 2015	(r284033)
+++ stable/10/sys/dev/pccbb/pccbb_isa.c	Fri Jun  5 17:05:09 2015	(r284034)
@@ -205,13 +205,25 @@ cbb_isa_attach(device_t dev)
 	return (ENOMEM);
 }
 
+static int
+cbb_isa_suspend(device_t dev)
+{
+	return (0);
+}
+
+static int
+cbb_isa_resume(device_t dev)
+{
+	return (0);
+}
+
 static device_method_t cbb_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,			cbb_isa_probe),
 	DEVMETHOD(device_attach,		cbb_isa_attach),
 	DEVMETHOD(device_detach,		cbb_detach),
-	DEVMETHOD(device_suspend,		cbb_suspend),
-	DEVMETHOD(device_resume,		cbb_resume),
+	DEVMETHOD(device_suspend,		cbb_isa_suspend),
+	DEVMETHOD(device_resume,		cbb_isa_resume),
 
 	/* bus methods */
 	DEVMETHOD(bus_read_ivar,		cbb_read_ivar),

Modified: stable/10/sys/dev/pccbb/pccbb_pci.c
==============================================================================
--- stable/10/sys/dev/pccbb/pccbb_pci.c	Fri Jun  5 17:04:50 2015	(r284033)
+++ stable/10/sys/dev/pccbb/pccbb_pci.c	Fri Jun  5 17:05:09 2015	(r284034)
@@ -259,32 +259,6 @@ cbb_pci_probe(device_t brdev)
 }
 
 /*
- * Still need this because the pci code only does power for type 0
- * header devices.
- */
-static void
-cbb_powerstate_d0(device_t dev)
-{
-	u_int32_t membase, irq;
-
-	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
-		/* Save important PCI config data. */
-		membase = pci_read_config(dev, CBBR_SOCKBASE, 4);
-		irq = pci_read_config(dev, PCIR_INTLINE, 4);
-
-		/* Reset the power state. */
-		device_printf(dev, "chip is in D%d power mode "
-		    "-- setting to D0\n", pci_get_powerstate(dev));
-
-		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
-
-		/* Restore PCI config data. */
-		pci_write_config(dev, CBBR_SOCKBASE, membase, 4);
-		pci_write_config(dev, PCIR_INTLINE, irq, 4);
-	}
-}
-
-/*
  * Print out the config space
  */
 static void
@@ -321,15 +295,15 @@ cbb_pci_attach(device_t brdev)
 	sc->cbdev = NULL;
 	sc->exca[0].pccarddev = NULL;
 	sc->domain = pci_get_domain(brdev);
-	sc->bus.sec = pci_read_config(brdev, PCIR_SECBUS_2, 1);
-	sc->bus.sub = pci_read_config(brdev, PCIR_SUBBUS_2, 1);
 	sc->pribus = pcib_get_bus(parent);
 #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
 	pci_write_config(brdev, PCIR_PRIBUS_2, sc->pribus, 1);
 	pcib_setup_secbus(brdev, &sc->bus, 1);
+#else
+	sc->bus.sec = pci_read_config(brdev, PCIR_SECBUS_2, 1);
+	sc->bus.sub = pci_read_config(brdev, PCIR_SUBBUS_2, 1);
 #endif
 	SLIST_INIT(&sc->rl);
-	cbb_powerstate_d0(brdev);
 
 	rid = CBBR_SOCKBASE;
 	sc->base_res = bus_alloc_resource_any(brdev, SYS_RES_MEMORY, &rid,
@@ -467,22 +441,17 @@ cbb_chipinit(struct cbb_softc *sc)
 	uint32_t mux, sysctrl, reg;
 
 	/* Set CardBus latency timer */
-	if (pci_read_config(sc->dev, PCIR_SECLAT_1, 1) < 0x20)
-		pci_write_config(sc->dev, PCIR_SECLAT_1, 0x20, 1);
+	if (pci_read_config(sc->dev, PCIR_SECLAT_2, 1) < 0x20)
+		pci_write_config(sc->dev, PCIR_SECLAT_2, 0x20, 1);
 
 	/* Set PCI latency timer */
 	if (pci_read_config(sc->dev, PCIR_LATTIMER, 1) < 0x20)
 		pci_write_config(sc->dev, PCIR_LATTIMER, 0x20, 1);
 
-	/* Restore bus configuration */
-	pci_write_config(sc->dev, PCIR_PRIBUS_2, sc->pribus, 1);
-	pci_write_config(sc->dev, PCIR_SECBUS_2, sc->bus.sec, 1);
-	pci_write_config(sc->dev, PCIR_SUBBUS_2, sc->bus.sub, 1);
-
-	/* Enable memory access */
+	/* Enable DMA, memory access for this card and I/O acces for children */
 	pci_enable_busmaster(sc->dev);
-	/* XXX: This should not be necessary, but some chipsets require it */
-	PCI_MASK_CONFIG(sc->dev, PCIR_COMMAND, | PCIM_CMD_PORTEN, 2);
+	pci_enable_io(sc->dev, SYS_RES_IOPORT);
+	pci_enable_io(sc->dev, SYS_RES_MEMORY);
 
 	/* disable Legacy IO */
 	switch (sc->chipset) {
@@ -877,14 +846,64 @@ cbb_write_config(device_t brdev, u_int b
 	    b, s, f, reg, val, width);
 }
 
+static int
+cbb_pci_suspend(device_t brdev)
+{
+	int			error = 0;
+	struct cbb_softc	*sc = device_get_softc(brdev);
+
+	error = bus_generic_suspend(brdev);
+	if (error != 0)
+		return (error);
+	cbb_set(sc, CBB_SOCKET_MASK, 0);	/* Quiet hardware */
+	sc->cardok = 0;				/* Card is bogus now */
+	return (0);
+}
+
+static int
+cbb_pci_resume(device_t brdev)
+{
+	int	error = 0;
+	struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(brdev);
+	uint32_t tmp;
+
+	/*
+	 * In the APM and early ACPI era, BIOSes saved the PCI config
+	 * registers. As chips became more complicated, that functionality moved
+	 * into the ACPI code / tables. We must therefore, restore the settings
+	 * we made here to make sure the device come back. Transitions to Dx
+	 * from D0 and back to D0 cause the bridge to lose its config space, so
+	 * all the bus mappings and such are preserved.
+	 *
+	 * The PCI layer handles standard PCI registers like the
+	 * command register and BARs, but cbb-specific registers are
+	 * handled here.
+	 */
+	sc->chipinit(sc);
+
+	/* reset interrupt -- Do we really need to do this? */
+	tmp = cbb_get(sc, CBB_SOCKET_EVENT);
+	cbb_set(sc, CBB_SOCKET_EVENT, tmp);
+
+	/* CSC Interrupt: Card detect interrupt on */
+	cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD);
+
+	/* Signal the thread to wakeup. */
+	wakeup(&sc->intrhand);
+
+	error = bus_generic_resume(brdev);
+
+	return (error);
+}
+
 static device_method_t cbb_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,			cbb_pci_probe),
 	DEVMETHOD(device_attach,		cbb_pci_attach),
 	DEVMETHOD(device_detach,		cbb_detach),
 	DEVMETHOD(device_shutdown,		cbb_pci_shutdown),
-	DEVMETHOD(device_suspend,		cbb_suspend),
-	DEVMETHOD(device_resume,		cbb_resume),
+	DEVMETHOD(device_suspend,		cbb_pci_suspend),
+	DEVMETHOD(device_resume,		cbb_pci_resume),
 
 	/* bus methods */
 	DEVMETHOD(bus_read_ivar,		cbb_read_ivar),

Modified: stable/10/sys/dev/pccbb/pccbbvar.h
==============================================================================
--- stable/10/sys/dev/pccbb/pccbbvar.h	Fri Jun  5 17:04:50 2015	(r284033)
+++ stable/10/sys/dev/pccbb/pccbbvar.h	Fri Jun  5 17:05:09 2015	(r284034)
@@ -134,11 +134,9 @@ int	cbb_read_ivar(device_t brdev, device
 	    uintptr_t *result);
 int	cbb_release_resource(device_t brdev, device_t child,
 	    int type, int rid, struct resource *r);
-int	cbb_resume(device_t self);
 int	cbb_setup_intr(device_t dev, device_t child, struct resource *irq,
 	    int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg,
 	    void **cookiep);
-int	cbb_suspend(device_t self);
 int	cbb_teardown_intr(device_t dev, device_t child, struct resource *irq,
 	    void *cookie);
 int	cbb_write_ivar(device_t brdev, device_t child, int which,

Modified: stable/10/sys/dev/pci/pci.c
==============================================================================
--- stable/10/sys/dev/pci/pci.c	Fri Jun  5 17:04:50 2015	(r284033)
+++ stable/10/sys/dev/pci/pci.c	Fri Jun  5 17:05:09 2015	(r284034)
@@ -585,12 +585,24 @@ pci_hdrtypedata(device_t pcib, int b, in
 	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:
+		cfg->bridge.br_seclat = REG(PCIR_SECLAT_1, 1);
+		cfg->bridge.br_subbus = REG(PCIR_SUBBUS_1, 1);
+		cfg->bridge.br_secbus = REG(PCIR_SECBUS_1, 1);
+		cfg->bridge.br_pribus = REG(PCIR_PRIBUS_1, 1);
+		cfg->bridge.br_control = REG(PCIR_BRIDGECTL_1, 2);
 		cfg->nummaps	    = PCI_MAXMAPS_1;
 		break;
 	case PCIM_HDRTYPE_CARDBUS:
+		cfg->bridge.br_seclat = REG(PCIR_SECLAT_2, 1);
+		cfg->bridge.br_subbus = REG(PCIR_SUBBUS_2, 1);
+		cfg->bridge.br_secbus = REG(PCIR_SECBUS_2, 1);
+		cfg->bridge.br_pribus = REG(PCIR_PRIBUS_2, 1);
+		cfg->bridge.br_control = REG(PCIR_BRIDGECTL_2, 2);
 		cfg->subvendor      = REG(PCIR_SUBVEND_2, 2);
 		cfg->subdevice      = REG(PCIR_SUBDEV_2, 2);
 		cfg->nummaps	    = PCI_MAXMAPS_2;
@@ -637,9 +649,6 @@ pci_read_device(device_t pcib, int d, in
 		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);
@@ -4360,9 +4369,17 @@ pci_read_ivar(device_t dev, device_t chi
 		*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:
@@ -4931,16 +4948,6 @@ pci_cfg_restore(device_t dev, struct pci
 {
 
 	/*
-	 * Only do header type 0 devices.  Type 1 devices are bridges,
-	 * which we know need special treatment.  Type 2 devices are
-	 * cardbus bridges which also require special treatment.
-	 * Other types are unknown, and we err on the side of safety
-	 * by ignoring them.
-	 */
-	if ((dinfo->cfg.hdrtype & PCIM_HDRTYPE) != PCIM_HDRTYPE_NORMAL)
-		return;
-
-	/*
 	 * Restore the device to full power mode.  We must do this
 	 * before we restore the registers because moving from D3 to
 	 * D0 will cause the chip's BARs and some other registers to
@@ -4950,16 +4957,44 @@ pci_cfg_restore(device_t dev, struct pci
 	 */
 	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0)
 		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
-	pci_restore_bars(dev);
 	pci_write_config(dev, PCIR_COMMAND, dinfo->cfg.cmdreg, 2);
 	pci_write_config(dev, PCIR_INTLINE, dinfo->cfg.intline, 1);
 	pci_write_config(dev, PCIR_INTPIN, dinfo->cfg.intpin, 1);
-	pci_write_config(dev, PCIR_MINGNT, dinfo->cfg.mingnt, 1);
-	pci_write_config(dev, PCIR_MAXLAT, dinfo->cfg.maxlat, 1);
 	pci_write_config(dev, PCIR_CACHELNSZ, dinfo->cfg.cachelnsz, 1);
 	pci_write_config(dev, PCIR_LATTIMER, dinfo->cfg.lattimer, 1);
 	pci_write_config(dev, PCIR_PROGIF, dinfo->cfg.progif, 1);
 	pci_write_config(dev, PCIR_REVID, dinfo->cfg.revid, 1);
+	switch (dinfo->cfg.hdrtype & PCIM_HDRTYPE) {
+	case PCIM_HDRTYPE_NORMAL:
+		pci_write_config(dev, PCIR_MINGNT, dinfo->cfg.mingnt, 1);
+		pci_write_config(dev, PCIR_MAXLAT, dinfo->cfg.maxlat, 1);
+		break;
+	case PCIM_HDRTYPE_BRIDGE:
+		pci_write_config(dev, PCIR_SECLAT_1,
+		    dinfo->cfg.bridge.br_seclat, 1);
+		pci_write_config(dev, PCIR_SUBBUS_1,
+		    dinfo->cfg.bridge.br_subbus, 1);
+		pci_write_config(dev, PCIR_SECBUS_1,
+		    dinfo->cfg.bridge.br_secbus, 1);
+		pci_write_config(dev, PCIR_PRIBUS_1,
+		    dinfo->cfg.bridge.br_pribus, 1);
+		pci_write_config(dev, PCIR_BRIDGECTL_1,
+		    dinfo->cfg.bridge.br_control, 2);
+		break;
+	case PCIM_HDRTYPE_CARDBUS:
+		pci_write_config(dev, PCIR_SECLAT_2,
+		    dinfo->cfg.bridge.br_seclat, 1);
+		pci_write_config(dev, PCIR_SUBBUS_2,
+		    dinfo->cfg.bridge.br_subbus, 1);
+		pci_write_config(dev, PCIR_SECBUS_2,
+		    dinfo->cfg.bridge.br_secbus, 1);
+		pci_write_config(dev, PCIR_PRIBUS_2,
+		    dinfo->cfg.bridge.br_pribus, 1);
+		pci_write_config(dev, PCIR_BRIDGECTL_2,
+		    dinfo->cfg.bridge.br_control, 2);
+		break;
+	}
+	pci_restore_bars(dev);
 
 	/*
 	 * Restore extended capabilities for PCI-Express and PCI-X
@@ -5028,40 +5063,57 @@ pci_cfg_save(device_t dev, struct pci_de
 	int ps;
 
 	/*
-	 * Only do header type 0 devices.  Type 1 devices are bridges, which
-	 * we know need special treatment.  Type 2 devices are cardbus bridges
-	 * which also require special treatment.  Other types are unknown, and
-	 * we err on the side of safety by ignoring them.  Powering down
-	 * bridges should not be undertaken lightly.
-	 */
-	if ((dinfo->cfg.hdrtype & PCIM_HDRTYPE) != PCIM_HDRTYPE_NORMAL)
-		return;
-
-	/*
 	 * Some drivers apparently write to these registers w/o updating our
 	 * cached copy.  No harm happens if we update the copy, so do so here
 	 * so we can restore them.  The COMMAND register is modified by the
 	 * bus w/o updating the cache.  This should represent the normally
-	 * writable portion of the 'defined' part of type 0 headers.  In
-	 * theory we also need to save/restore the PCI capability structures
-	 * we know about, but apart from power we don't know any that are
-	 * writable.
+	 * writable portion of the 'defined' part of type 0/1/2 headers.
 	 */
-	dinfo->cfg.subvendor = pci_read_config(dev, PCIR_SUBVEND_0, 2);
-	dinfo->cfg.subdevice = pci_read_config(dev, PCIR_SUBDEV_0, 2);
 	dinfo->cfg.vendor = pci_read_config(dev, PCIR_VENDOR, 2);
 	dinfo->cfg.device = pci_read_config(dev, PCIR_DEVICE, 2);
 	dinfo->cfg.cmdreg = pci_read_config(dev, PCIR_COMMAND, 2);
 	dinfo->cfg.intline = pci_read_config(dev, PCIR_INTLINE, 1);
 	dinfo->cfg.intpin = pci_read_config(dev, PCIR_INTPIN, 1);
-	dinfo->cfg.mingnt = pci_read_config(dev, PCIR_MINGNT, 1);
-	dinfo->cfg.maxlat = pci_read_config(dev, PCIR_MAXLAT, 1);
 	dinfo->cfg.cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1);
 	dinfo->cfg.lattimer = pci_read_config(dev, PCIR_LATTIMER, 1);
 	dinfo->cfg.baseclass = pci_read_config(dev, PCIR_CLASS, 1);
 	dinfo->cfg.subclass = pci_read_config(dev, PCIR_SUBCLASS, 1);
 	dinfo->cfg.progif = pci_read_config(dev, PCIR_PROGIF, 1);
 	dinfo->cfg.revid = pci_read_config(dev, PCIR_REVID, 1);
+	switch (dinfo->cfg.hdrtype & PCIM_HDRTYPE) {
+	case PCIM_HDRTYPE_NORMAL:
+		dinfo->cfg.subvendor = pci_read_config(dev, PCIR_SUBVEND_0, 2);
+		dinfo->cfg.subdevice = pci_read_config(dev, PCIR_SUBDEV_0, 2);
+		dinfo->cfg.mingnt = pci_read_config(dev, PCIR_MINGNT, 1);
+		dinfo->cfg.maxlat = pci_read_config(dev, PCIR_MAXLAT, 1);
+		break;
+	case PCIM_HDRTYPE_BRIDGE:
+		dinfo->cfg.bridge.br_seclat = pci_read_config(dev,
+		    PCIR_SECLAT_1, 1);
+		dinfo->cfg.bridge.br_subbus = pci_read_config(dev,
+		    PCIR_SUBBUS_1, 1);
+		dinfo->cfg.bridge.br_secbus = pci_read_config(dev,
+		    PCIR_SECBUS_1, 1);
+		dinfo->cfg.bridge.br_pribus = pci_read_config(dev,
+		    PCIR_PRIBUS_1, 1);
+		dinfo->cfg.bridge.br_control = pci_read_config(dev,
+		    PCIR_BRIDGECTL_1, 2);
+		break;
+	case PCIM_HDRTYPE_CARDBUS:
+		dinfo->cfg.bridge.br_seclat = pci_read_config(dev,
+		    PCIR_SECLAT_2, 1);
+		dinfo->cfg.bridge.br_subbus = pci_read_config(dev,
+		    PCIR_SUBBUS_2, 1);
+		dinfo->cfg.bridge.br_secbus = pci_read_config(dev,
+		    PCIR_SECBUS_2, 1);
+		dinfo->cfg.bridge.br_pribus = pci_read_config(dev,
+		    PCIR_PRIBUS_2, 1);
+		dinfo->cfg.bridge.br_control = pci_read_config(dev,
+		    PCIR_BRIDGECTL_2, 2);
+		dinfo->cfg.subvendor = pci_read_config(dev, PCIR_SUBVEND_2, 2);
+		dinfo->cfg.subdevice = pci_read_config(dev, PCIR_SUBDEV_2, 2);
+		break;
+	}
 
 	if (dinfo->cfg.pcie.pcie_location != 0)
 		pci_cfg_save_pcie(dev, dinfo);

Modified: stable/10/sys/dev/pci/pci_pci.c
==============================================================================
--- stable/10/sys/dev/pci/pci_pci.c	Fri Jun  5 17:04:50 2015	(r284033)
+++ stable/10/sys/dev/pci/pci_pci.c	Fri Jun  5 17:05:09 2015	(r284034)
@@ -549,18 +549,22 @@ void
 pcib_setup_secbus(device_t dev, struct pcib_secbus *bus, int min_count)
 {
 	char buf[64];
-	int error, rid;
+	int error, rid, sec_reg;
 
 	switch (pci_read_config(dev, PCIR_HDRTYPE, 1) & PCIM_HDRTYPE) {
 	case PCIM_HDRTYPE_BRIDGE:
+		sec_reg = PCIR_SECBUS_1;
 		bus->sub_reg = PCIR_SUBBUS_1;
 		break;
 	case PCIM_HDRTYPE_CARDBUS:
+		sec_reg = PCIR_SECBUS_2;
 		bus->sub_reg = PCIR_SUBBUS_2;
 		break;
 	default:
 		panic("not a PCI bridge");
 	}
+	bus->sec = pci_read_config(dev, sec_reg, 1);
+	bus->sub = pci_read_config(dev, bus->sub_reg, 1);
 	bus->dev = dev;
 	bus->rman.rm_start = 0;
 	bus->rman.rm_end = PCI_BUSMAX;
@@ -845,20 +849,16 @@ pcib_set_mem_decode(struct pcib_softc *s
 static void
 pcib_cfg_save(struct pcib_softc *sc)
 {
+#ifndef NEW_PCIB
 	device_t	dev;
+	uint16_t command;
 
 	dev = sc->dev;
 
-	sc->command = pci_read_config(dev, PCIR_COMMAND, 2);
-	sc->pribus = pci_read_config(dev, PCIR_PRIBUS_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
-	if (sc->command & PCIM_CMD_PORTEN)
+	command = pci_read_config(dev, PCIR_COMMAND, 2);
+	if (command & PCIM_CMD_PORTEN)
 		pcib_get_io_decode(sc);
-	if (sc->command & PCIM_CMD_MEMEN)
+	if (command & PCIM_CMD_MEMEN)
 		pcib_get_mem_decode(sc);
 #endif
 }
@@ -870,21 +870,18 @@ static void
 pcib_cfg_restore(struct pcib_softc *sc)
 {
 	device_t	dev;
-
+#ifndef NEW_PCIB
+	uint16_t command;
+#endif
 	dev = sc->dev;
 
-	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->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
 	pcib_write_windows(sc, WIN_IO | WIN_MEM | WIN_PMEM);
 #else
-	if (sc->command & PCIM_CMD_PORTEN)
+	command = pci_read_config(dev, PCIR_COMMAND, 2);
+	if (command & PCIM_CMD_PORTEN)
 		pcib_set_io_decode(sc);
-	if (sc->command & PCIM_CMD_MEMEN)
+	if (command & PCIM_CMD_MEMEN)
 		pcib_set_mem_decode(sc);
 #endif
 }
@@ -918,7 +915,11 @@ pcib_attach_common(device_t dev)
      * Get current bridge configuration.
      */
     sc->domain = pci_get_domain(dev);
-    sc->secstat = pci_read_config(dev, PCIR_SECSTAT_1, 2);
+#if !(defined(NEW_PCIB) && defined(PCI_RES_BUS))
+    sc->bus.sec = pci_read_config(dev, PCIR_SECBUS_1, 1);
+    sc->bus.sub = pci_read_config(dev, PCIR_SUBBUS_1, 1);
+#endif
+    sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2);
     pcib_cfg_save(sc);
 
     /*
@@ -1097,32 +1098,15 @@ pcib_attach(device_t dev)
 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;
-	int dstate;
 
-	if (pci_do_power_resume) {
-		pcib = device_get_parent(device_get_parent(dev));
-		dstate = PCI_POWERSTATE_D0;
-		if (PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0)
-			pci_set_powerstate(dev, dstate);
-	}
 	pcib_cfg_restore(device_get_softc(dev));
 	return (bus_generic_resume(dev));
 }

Modified: stable/10/sys/dev/pci/pcib_private.h
==============================================================================
--- stable/10/sys/dev/pci/pcib_private.h	Fri Jun  5 17:04:50 2015	(r284033)
+++ stable/10/sys/dev/pci/pcib_private.h	Fri Jun  5 17:05:09 2015	(r284034)
@@ -106,7 +106,6 @@ struct pcib_softc 
 #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 */
     struct pcib_secbus bus;	/* secondary bus numbers */
@@ -122,9 +121,7 @@ struct pcib_softc 
     uint32_t	iobase;		/* base address of port window */
     uint32_t	iolimit;	/* topmost address of port window */
 #endif
-    uint16_t	secstat;	/* secondary bus status register */
     uint16_t	bridgectl;	/* bridge control register */
-    uint8_t	seclat;		/* secondary bus latency timer */
 };
 
 #define	PCIB_SUPPORTED_ARI_VER	1

Modified: stable/10/sys/dev/pci/pcivar.h
==============================================================================
--- stable/10/sys/dev/pci/pcivar.h	Fri Jun  5 17:04:50 2015	(r284033)
+++ stable/10/sys/dev/pci/pcivar.h	Fri Jun  5 17:05:09 2015	(r284034)
@@ -39,6 +39,15 @@
 
 typedef uint64_t pci_addr_t;
 
+/* Config registers for PCI-PCI and PCI-Cardbus bridges. */
+struct pcicfg_bridge {
+    uint8_t	br_seclat;
+    uint8_t	br_subbus;
+    uint8_t	br_secbus;
+    uint8_t	br_pribus;
+    uint16_t	br_control;
+};
+
 /* Interesting values for PCI power management */
 struct pcicfg_pp {
     uint16_t	pp_cap;		/* PCI power management capabilities */
@@ -179,6 +188,7 @@ typedef struct pcicfg {
     uint8_t	slot;		/* config space slot address */
     uint8_t	func;		/* config space function number */
 
+    struct pcicfg_bridge bridge; /* Bridges */
     struct pcicfg_pp pp;	/* Power management */
     struct pcicfg_vpd vpd;	/* Vital product data */
     struct pcicfg_msi msi;	/* PCI MSI */


More information about the svn-src-all mailing list