[RFC 5/7] USB/xHCI: USB 3.0 link PM change bit means port resume.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



USB 3.0 hubs don't have a port suspend change bit (that bit is now
reserved).  Instead, when a port resumes, the hub sets the port link
state change bit.  (An xHCI roothub does have a resume change bit, but
we don't pass it up to the USB core because it's different behavior from
external USB 3.0 hubs.)

The xHCI driver was initially trying to sweep the port resume under the
rug, by setting the link state to U0 when a resume was detected,
clearing the link state change, and asking the hub driver to poll the
roothub.  That works fine if there's a resuming USB 3.0 device attached
to the roothub.  However, if the resuming device is behind an external
USB 3.0 hub, khubd looks at the root ports, notices there's no new
changes to the port status bits, and then suspends the USB 3.0 hub
again.

Change the xHCI driver and hub port initialization to pass on the port
link state change to hub_events().  Make sure that function will treat
the hub as having children that need resumed if the link state change
bit is set, just like it would if a USB 2.0 hub had the port suspend
change bit set.

There are specific error cases where the xHCI roothub will set PLC, but
I don't think that will cause issues.

XXX: We could clear PLC in hub_activate() when hub_activate() is called for a
hub resume only (HUB_RESUME).  I'm not sure about the port state machine here.
Alan?

Signed-off-by: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx>
Cc: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>
---
 drivers/usb/core/hub.c       |   24 +++++++++++++-----------
 drivers/usb/host/xhci-ring.c |    3 ---
 2 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 39f3e4c..3ad7e89 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -807,11 +807,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
 			clear_port_feature(hub->hdev, port1,
 					USB_PORT_FEAT_C_ENABLE);
 		}
-		if (portchange & USB_PORT_STAT_C_LINK_STATE) {
+		/* We can't clear the link state change here because it's the
+		 * only indication we have a resume on a port!
+		 */
+		if (portchange & USB_PORT_STAT_C_LINK_STATE)
 			need_debounce_delay = true;
-			clear_port_feature(hub->hdev, port1,
-					USB_PORT_FEAT_C_PORT_LINK_STATE);
-		}
 
 		if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
 				hub_is_superspeed(hub->hdev)) {
@@ -3569,11 +3569,17 @@ static void hub_events(void)
 				}
 			}
 
-			if (portchange & USB_PORT_STAT_C_SUSPEND) {
+			if ((portchange & USB_PORT_STAT_C_SUSPEND) ||
+					(hub_is_superspeed(hdev) &&
+					 (portchange & USB_PORT_STAT_C_LINK_STATE))) {
 				struct usb_device *udev;
 
-				clear_port_feature(hdev, i,
-					USB_PORT_FEAT_C_SUSPEND);
+				if (!hub_is_superspeed(hdev))
+					clear_port_feature(hdev, i,
+							USB_PORT_FEAT_C_SUSPEND);
+				else
+					clear_port_feature(hdev, i,
+							USB_PORT_FEAT_C_PORT_LINK_STATE);
 				udev = hdev->children[i-1];
 				if (udev) {
 					/* TRSMRCY = 10 msec */
@@ -3625,10 +3631,6 @@ static void hub_events(void)
 				clear_port_feature(hdev, i,
 					USB_PORT_FEAT_C_BH_PORT_RESET);
 			}
-			if (portchange & USB_PORT_STAT_C_LINK_STATE) {
-				clear_port_feature(hub->hdev, i,
-						USB_PORT_FEAT_C_PORT_LINK_STATE);
-			}
 			if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) {
 				dev_warn(hub_dev,
 					"config error on port %d\n",
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 1ef2bf1..d532f0c 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1350,9 +1350,6 @@ static void handle_port_status(struct xhci_hcd *xhci,
 			}
 			xhci_ring_device(xhci, slot_id);
 			xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
-			/* Clear PORT_PLC */
-			xhci_test_and_clear_bit(xhci, port_array,
-						faked_port_index, PORT_PLC);
 		} else {
 			xhci_dbg(xhci, "resume HS port %d\n", port_id);
 			bus_state->resume_done[faked_port_index] = jiffies +
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux