xhci: Report USB 2.1 link status for L1
authorSarah Sharp <sarah.a.sharp@linux.intel.com>
Tue, 2 Apr 2013 16:23:42 +0000 (09:23 -0700)
committerSarah Sharp <sarah.a.sharp@linux.intel.com>
Tue, 23 Jul 2013 21:19:19 +0000 (14:19 -0700)
USB 2.1 devices can go into a lower power link state, L1.  When they are
active, they are in the L0 state.  The L1 transition can be purely
driven by software, or some USB host controllers (including some xHCI
1.0 hosts) allow the host hardware to track idleness and automatically
place a port into L1.

The USB 2.1 Link Power Management ECN gives a way for USB 2.1 hubs that
support LPM to report that a port is in L1.  The port status bit 5 will
be set when the port is in L1.  The xHCI host reports the root port as
being in 'U2' when the devices is in L1, and as being in 'U0' when the
port is active (in L0).

Translate the xHCI USB 2.1 link status into the format external hubs
use, and pass the L1 status up to the USB core and tools like lsusb.

Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
drivers/usb/host/xhci-hub.c

index 83fc636fa254e9a6bbd48d1f3173eaad59902b92..93f3fdf0ff0a1620c07d56a078c69605823f66c7 100644 (file)
@@ -461,8 +461,15 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
        }
 }
 
+/* Updates Link Status for USB 2.1 port */
+static void xhci_hub_report_usb2_link_state(u32 *status, u32 status_reg)
+{
+       if ((status_reg & PORT_PLS_MASK) == XDEV_U2)
+               *status |= USB_PORT_STAT_L1;
+}
+
 /* Updates Link Status for super Speed port */
-static void xhci_hub_report_link_state(u32 *status, u32 status_reg)
+static void xhci_hub_report_usb3_link_state(u32 *status, u32 status_reg)
 {
        u32 pls = status_reg & PORT_PLS_MASK;
 
@@ -631,14 +638,16 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
                else
                        status |= USB_PORT_STAT_POWER;
        }
-       /* Update Port Link State for super speed ports*/
+       /* Update Port Link State */
        if (hcd->speed == HCD_USB3) {
-               xhci_hub_report_link_state(&status, raw_port_status);
+               xhci_hub_report_usb3_link_state(&status, raw_port_status);
                /*
                 * Verify if all USB3 Ports Have entered U0 already.
                 * Delete Compliance Mode Timer if so.
                 */
                xhci_del_comp_mod_timer(xhci, raw_port_status, wIndex);
+       } else {
+               xhci_hub_report_usb2_link_state(&status, raw_port_status);
        }
        if (bus_state->port_c_suspend & (1 << wIndex))
                status |= 1 << USB_PORT_FEAT_C_SUSPEND;