Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 18 Aug 2016 22:01:52 +0000 (UTC)
From:      Eric van Gyzen <vangyzen@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-releng@freebsd.org
Subject:   svn commit: r304434 - releng/11.0/sys/dev/pci
Message-ID:  <201608182201.u7IM1qhx082060@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: vangyzen
Date: Thu Aug 18 22:01:52 2016
New Revision: 304434
URL: https://svnweb.freebsd.org/changeset/base/304434

Log:
  MFC r304433
  
  PCIe HotPlug: Detect bridges that are not really HotPlug capable
  
  Some devices report that they have an MRL when they actually
  do not.  Since they always report that the MRL is open, child
  devices would be ignored.  Try to detect these devices and
  ignore their claim of HotPlug support.  Specifically,
  if there is an open MRL but the Data Link Layer is active,
  the MRL is not real.
  
  Revert r303645 to re-enable HotPlug support for slots with
  power controllers, since it works correctly in my testing.
  
  Start the DLL state-change timer if Presence /or/ MRL state changes,
  along with other conditions.  Previously, we started the timer iff
  Presence changed.  If there is an MRL, it must be closed for power
  to be turned on, so Presence is unlikely to change on an MRL-close event.
  
  Add a printf() of interesting registers on HotPlug interrupts and
  commands (one from erj@).  These were very useful for debugging.
  Guard them with bootverbose, since they're spam in normal operation.
  
  In collaboration with:	jhb
  Relnotes:	yes (re-enable HotPlug support for slots with power controllers)
  Approved by:	re (gjb)
  Sponsored by:	Dell Inc.
  Differential Revision:	https://reviews.freebsd.org/D7509

Modified:
  releng/11.0/sys/dev/pci/pci_pci.c
Directory Properties:
  releng/11.0/   (props changed)

Modified: releng/11.0/sys/dev/pci/pci_pci.c
==============================================================================
--- releng/11.0/sys/dev/pci/pci_pci.c	Thu Aug 18 21:47:00 2016	(r304433)
+++ releng/11.0/sys/dev/pci/pci_pci.c	Thu Aug 18 22:01:52 2016	(r304434)
@@ -918,6 +918,7 @@ static void
 pcib_probe_hotplug(struct pcib_softc *sc)
 {
 	device_t dev;
+	uint16_t link_sta, slot_sta;
 
 	if (!pci_enable_pcie_hp)
 		return;
@@ -932,15 +933,29 @@ pcib_probe_hotplug(struct pcib_softc *sc
 	sc->pcie_link_cap = pcie_read_config(dev, PCIER_LINK_CAP, 4);
 	sc->pcie_slot_cap = pcie_read_config(dev, PCIER_SLOT_CAP, 4);
 
+	if ((sc->pcie_slot_cap & PCIEM_SLOT_CAP_HPC) == 0)
+		return;
+
 	/*
-	 * XXX: Handling of slots with a power controller needs to be
-	 * reexamined.  Ignore hotplug on such slots for now.
+	 * Some devices report that they have an MRL when they actually
+	 * do not.  Since they always report that the MRL is open, child
+	 * devices would be ignored.  Try to detect these devices and
+	 * ignore their claim of HotPlug support.
+	 *
+	 * If there is an open MRL but the Data Link Layer is active,
+	 * the MRL is not real.
 	 */
-	if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_PCP)
-		return;
-	
-	if (sc->pcie_slot_cap & PCIEM_SLOT_CAP_HPC)
-		sc->flags |= PCIB_HOTPLUG;
+	if ((sc->pcie_slot_cap & PCIEM_SLOT_CAP_MRLSP) != 0 &&
+	    (sc->pcie_link_cap & PCIEM_LINK_CAP_DL_ACTIVE) != 0) {
+		link_sta = pcie_read_config(dev, PCIER_LINK_STA, 2);
+		slot_sta = pcie_read_config(dev, PCIER_SLOT_STA, 2);
+		if ((slot_sta & PCIEM_SLOT_STA_MRLSS) != 0 &&
+		    (link_sta & PCIEM_LINK_STA_DL_ACTIVE) != 0) {
+			return;
+		}
+	}
+
+	sc->flags |= PCIB_HOTPLUG;
 }
 
 /*
@@ -966,6 +981,8 @@ pcib_pcie_hotplug_command(struct pcib_so
 	new = (ctl & ~mask) | val;
 	if (new == ctl)
 		return;
+	if (bootverbose)
+		device_printf(dev, "HotPlug command: %04x -> %04x\n", ctl, new);
 	pcie_write_config(dev, PCIER_SLOT_CTL, new, 2);
 	if (!(sc->pcie_slot_cap & PCIEM_SLOT_CAP_NCCS) &&
 	    (ctl & new) & PCIEM_SLOT_CTL_CCIE) {
@@ -1028,9 +1045,6 @@ pcib_hotplug_inserted(struct pcib_softc 
 static int
 pcib_hotplug_present(struct pcib_softc *sc)
 {
-	device_t dev;
-
-	dev = sc->dev;
 
 	/* Card must be inserted. */
 	if (!pcib_hotplug_inserted(sc))
@@ -1059,7 +1073,7 @@ pcib_pcie_hotplug_update(struct pcib_sof
 {
 	bool card_inserted, ei_engaged;
 
-	/* Clear DETACHING if Present Detect has cleared. */
+	/* Clear DETACHING if Presence Detect has cleared. */
 	if ((sc->pcie_slot_sta & (PCIEM_SLOT_STA_PDC | PCIEM_SLOT_STA_PDS)) ==
 	    PCIEM_SLOT_STA_PDC)
 		sc->flags &= ~PCIB_DETACHING;
@@ -1101,14 +1115,15 @@ pcib_pcie_hotplug_update(struct pcib_sof
 
 	/*
 	 * Start a timer to see if the Data Link Layer times out.
-	 * Note that we only start the timer if Presence Detect
+	 * Note that we only start the timer if Presence Detect or MRL Sensor
 	 * changed on this interrupt.  Stop any scheduled timer if
 	 * the Data Link Layer is active.
 	 */
 	if (sc->pcie_link_cap & PCIEM_LINK_CAP_DL_ACTIVE) {
 		if (card_inserted &&
 		    !(sc->pcie_link_sta & PCIEM_LINK_STA_DL_ACTIVE) &&
-		    sc->pcie_slot_sta & PCIEM_SLOT_STA_PDC) {
+		    sc->pcie_slot_sta &
+		    (PCIEM_SLOT_STA_MRLSC | PCIEM_SLOT_STA_PDC)) {
 			if (cold)
 				device_printf(sc->dev,
 				    "Data Link Layer inactive\n");
@@ -1144,6 +1159,10 @@ pcib_pcie_intr(void *arg)
 	/* Clear the events just reported. */
 	pcie_write_config(dev, PCIER_SLOT_STA, sc->pcie_slot_sta, 2);
 
+	if (bootverbose)
+		device_printf(dev, "HotPlug interrupt: %#x\n",
+		    sc->pcie_slot_sta);
+
 	if (sc->pcie_slot_sta & PCIEM_SLOT_STA_ABP) {
 		if (sc->flags & PCIB_DETACH_PENDING) {	
 			device_printf(dev,
@@ -1165,7 +1184,7 @@ pcib_pcie_intr(void *arg)
 		    sc->pcie_slot_sta & PCIEM_SLOT_STA_MRLSS ? "open" :
 		    "closed");
 	if (bootverbose && sc->pcie_slot_sta & PCIEM_SLOT_STA_PDC)
-		device_printf(dev, "Present Detect Changed to %s\n",
+		device_printf(dev, "Presence Detect Changed to %s\n",
 		    sc->pcie_slot_sta & PCIEM_SLOT_STA_PDS ? "card present" :
 		    "empty");
 	if (sc->pcie_slot_sta & PCIEM_SLOT_STA_CC)
@@ -1234,7 +1253,7 @@ pcib_pcie_cc_timeout(void *arg)
 	sta = pcie_read_config(dev, PCIER_SLOT_STA, 2);
 	if (!(sta & PCIEM_SLOT_STA_CC)) {
 		device_printf(dev,
-		    "Hotplug Command Timed Out - forcing detach\n");
+		    "HotPlug Command Timed Out - forcing detach\n");
 		sc->flags &= ~(PCIB_HOTPLUG_CMD_PENDING | PCIB_DETACH_PENDING);
 		sc->flags |= PCIB_DETACHING;
 		pcib_pcie_hotplug_update(sc, 0, 0, true);



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