Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 25 Jul 2015 00:14:03 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r285863 - in stable/10/sys/dev: pccbb pci
Message-ID:  <201507250014.t6P0E3DZ009969@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Sat Jul 25 00:14:02 2015
New Revision: 285863
URL: https://svnweb.freebsd.org/changeset/base/285863

Log:
  Partially revert r284034.  In particular, revert the final change in this
  MFC (281874).  It broke suspend and resume on several Thinkpads (though not
  all) in 10 even though it works fine on the same laptops in HEAD.
  
  PR:		201239
  Reported by:	Kevin Oberman and several others

Modified:
  stable/10/sys/dev/pccbb/pccbb_pci.c
  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_pci.c
==============================================================================
--- stable/10/sys/dev/pccbb/pccbb_pci.c	Fri Jul 24 22:13:39 2015	(r285862)
+++ stable/10/sys/dev/pccbb/pccbb_pci.c	Sat Jul 25 00:14:02 2015	(r285863)
@@ -259,6 +259,32 @@ 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
@@ -295,15 +321,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,
@@ -448,6 +474,11 @@ cbb_chipinit(struct cbb_softc *sc)
 	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 DMA, memory access for this card and I/O acces for children */
 	pci_enable_busmaster(sc->dev);
 	pci_enable_io(sc->dev, SYS_RES_IOPORT);
@@ -875,10 +906,15 @@ cbb_pci_resume(device_t brdev)
 	 * 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.
+	 * For most drivers, the PCI layer handles this saving. However, since
+	 * there's much black magic and arcane art hidden in these few lines of
+	 * code that would be difficult to transition into the PCI
+	 * layer. chipinit was several years of trial and error to write.
 	 */
+	pci_write_config(brdev, CBBR_SOCKBASE, rman_get_start(sc->base_res), 4);
+	DEVPRINTF((brdev, "PCI Memory allocated: %08lx\n",
+	    rman_get_start(sc->base_res)));
+
 	sc->chipinit(sc);
 
 	/* reset interrupt -- Do we really need to do this? */

Modified: stable/10/sys/dev/pci/pci.c
==============================================================================
--- stable/10/sys/dev/pci/pci.c	Fri Jul 24 22:13:39 2015	(r285862)
+++ stable/10/sys/dev/pci/pci.c	Sat Jul 25 00:14:02 2015	(r285863)
@@ -590,19 +590,9 @@ pci_hdrtypedata(device_t pcib, int b, in
 		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;
@@ -4948,6 +4938,16 @@ 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
@@ -4957,44 +4957,16 @@ 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
@@ -5063,57 +5035,40 @@ 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/1/2 headers.
+	 * 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.
 	 */
+	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 Jul 24 22:13:39 2015	(r285862)
+++ stable/10/sys/dev/pci/pci_pci.c	Sat Jul 25 00:14:02 2015	(r285863)
@@ -549,22 +549,18 @@ void
 pcib_setup_secbus(device_t dev, struct pcib_secbus *bus, int min_count)
 {
 	char buf[64];
-	int error, rid, sec_reg;
+	int error, rid;
 
 	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;
@@ -849,16 +845,20 @@ 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;
 
-	command = pci_read_config(dev, PCIR_COMMAND, 2);
-	if (command & PCIM_CMD_PORTEN)
+	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)
 		pcib_get_io_decode(sc);
-	if (command & PCIM_CMD_MEMEN)
+	if (sc->command & PCIM_CMD_MEMEN)
 		pcib_get_mem_decode(sc);
 #endif
 }
@@ -870,18 +870,21 @@ 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
-	command = pci_read_config(dev, PCIR_COMMAND, 2);
-	if (command & PCIM_CMD_PORTEN)
+	if (sc->command & PCIM_CMD_PORTEN)
 		pcib_set_io_decode(sc);
-	if (command & PCIM_CMD_MEMEN)
+	if (sc->command & PCIM_CMD_MEMEN)
 		pcib_set_mem_decode(sc);
 #endif
 }
@@ -915,11 +918,7 @@ pcib_attach_common(device_t dev)
      * Get current bridge configuration.
      */
     sc->domain = pci_get_domain(dev);
-#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);
+    sc->secstat = pci_read_config(dev, PCIR_SECSTAT_1, 2);
     pcib_cfg_save(sc);
 
     /*

Modified: stable/10/sys/dev/pci/pcib_private.h
==============================================================================
--- stable/10/sys/dev/pci/pcib_private.h	Fri Jul 24 22:13:39 2015	(r285862)
+++ stable/10/sys/dev/pci/pcib_private.h	Sat Jul 25 00:14:02 2015	(r285863)
@@ -106,6 +106,7 @@ 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 */
@@ -121,7 +122,9 @@ 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 Jul 24 22:13:39 2015	(r285862)
+++ stable/10/sys/dev/pci/pcivar.h	Sat Jul 25 00:14:02 2015	(r285863)
@@ -39,15 +39,6 @@
 
 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 */
@@ -188,7 +179,6 @@ 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 */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201507250014.t6P0E3DZ009969>