return 1;
                return 0;
        }
+
+       /* All USB 3.0 must support LPM, but we need their max exit latency
+        * information from the SuperSpeed Extended Capabilities BOS descriptor.
+        */
+       if (!udev->bos->ss_cap) {
+               dev_warn(&udev->dev, "No LPM exit latency info found.  "
+                               "Power management will be impacted.\n");
+               return 0;
+       }
+       if (udev->parent->lpm_capable)
+               return 1;
+
+       dev_warn(&udev->dev, "Parent hub missing LPM exit latency info.  "
+                       "Power management will be impacted.\n");
        return 0;
 }
 
+/*
+ * Set the Maximum Exit Latency (MEL) for the host to initiate a transition from
+ * either U1 or U2.
+ */
+static void usb_set_lpm_mel(struct usb_device *udev,
+               struct usb3_lpm_parameters *udev_lpm_params,
+               unsigned int udev_exit_latency,
+               struct usb_hub *hub,
+               struct usb3_lpm_parameters *hub_lpm_params,
+               unsigned int hub_exit_latency)
+{
+       unsigned int total_mel;
+       unsigned int device_mel;
+       unsigned int hub_mel;
+
+       /*
+        * Calculate the time it takes to transition all links from the roothub
+        * to the parent hub into U0.  The parent hub must then decode the
+        * packet (hub header decode latency) to figure out which port it was
+        * bound for.
+        *
+        * The Hub Header decode latency is expressed in 0.1us intervals (0x1
+        * means 0.1us).  Multiply that by 100 to get nanoseconds.
+        */
+       total_mel = hub_lpm_params->mel +
+               (hub->descriptor->u.ss.bHubHdrDecLat * 100);
+
+       /*
+        * How long will it take to transition the downstream hub's port into
+        * U0?  The greater of either the hub exit latency or the device exit
+        * latency.
+        *
+        * The BOS U1/U2 exit latencies are expressed in 1us intervals.
+        * Multiply that by 1000 to get nanoseconds.
+        */
+       device_mel = udev_exit_latency * 1000;
+       hub_mel = hub_exit_latency * 1000;
+       if (device_mel > hub_mel)
+               total_mel += device_mel;
+       else
+               total_mel += hub_mel;
+
+       udev_lpm_params->mel = total_mel;
+}
+
+/*
+ * Set the maximum Device to Host Exit Latency (PEL) for the device to initiate
+ * a transition from either U1 or U2.
+ */
+static void usb_set_lpm_pel(struct usb_device *udev,
+               struct usb3_lpm_parameters *udev_lpm_params,
+               unsigned int udev_exit_latency,
+               struct usb_hub *hub,
+               struct usb3_lpm_parameters *hub_lpm_params,
+               unsigned int hub_exit_latency,
+               unsigned int port_to_port_exit_latency)
+{
+       unsigned int first_link_pel;
+       unsigned int hub_pel;
+
+       /*
+        * First, the device sends an LFPS to transition the link between the
+        * device and the parent hub into U0.  The exit latency is the bigger of
+        * the device exit latency or the hub exit latency.
+        */
+       if (udev_exit_latency > hub_exit_latency)
+               first_link_pel = udev_exit_latency * 1000;
+       else
+               first_link_pel = hub_exit_latency * 1000;
+
+       /*
+        * When the hub starts to receive the LFPS, there is a slight delay for
+        * it to figure out that one of the ports is sending an LFPS.  Then it
+        * will forward the LFPS to its upstream link.  The exit latency is the
+        * delay, plus the PEL that we calculated for this hub.
+        */
+       hub_pel = port_to_port_exit_latency * 1000 + hub_lpm_params->pel;
+
+       /*
+        * According to figure C-7 in the USB 3.0 spec, the PEL for this device
+        * is the greater of the two exit latencies.
+        */
+       if (first_link_pel > hub_pel)
+               udev_lpm_params->pel = first_link_pel;
+       else
+               udev_lpm_params->pel = hub_pel;
+}
+
+/*
+ * Set the System Exit Latency (SEL) to indicate the total worst-case time from
+ * when a device initiates a transition to U0, until when it will receive the
+ * first packet from the host controller.
+ *
+ * Section C.1.5.1 describes the four components to this:
+ *  - t1: device PEL
+ *  - t2: time for the ERDY to make it from the device to the host.
+ *  - t3: a host-specific delay to process the ERDY.
+ *  - t4: time for the packet to make it from the host to the device.
+ *
+ * t3 is specific to both the xHCI host and the platform the host is integrated
+ * into.  The Intel HW folks have said it's negligible, FIXME if a different
+ * vendor says otherwise.
+ */
+static void usb_set_lpm_sel(struct usb_device *udev,
+               struct usb3_lpm_parameters *udev_lpm_params)
+{
+       struct usb_device *parent;
+       unsigned int num_hubs;
+       unsigned int total_sel;
+
+       /* t1 = device PEL */
+       total_sel = udev_lpm_params->pel;
+       /* How many external hubs are in between the device & the root port. */
+       for (parent = udev->parent, num_hubs = 0; parent->parent;
+                       parent = parent->parent)
+               num_hubs++;
+       /* t2 = 2.1us + 250ns * (num_hubs - 1) */
+       if (num_hubs > 0)
+               total_sel += 2100 + 250 * (num_hubs - 1);
+
+       /* t4 = 250ns * num_hubs */
+       total_sel += 250 * num_hubs;
+
+       udev_lpm_params->sel = total_sel;
+}
+
+static void usb_set_lpm_parameters(struct usb_device *udev)
+{
+       struct usb_hub *hub;
+       unsigned int port_to_port_delay;
+       unsigned int udev_u1_del;
+       unsigned int udev_u2_del;
+       unsigned int hub_u1_del;
+       unsigned int hub_u2_del;
+
+       if (!udev->lpm_capable || udev->speed != USB_SPEED_SUPER)
+               return;
+
+       hub = hdev_to_hub(udev->parent);
+       /* It doesn't take time to transition the roothub into U0, since it
+        * doesn't have an upstream link.
+        */
+       if (!hub)
+               return;
+
+       udev_u1_del = udev->bos->ss_cap->bU1devExitLat;
+       udev_u2_del = udev->bos->ss_cap->bU2DevExitLat;
+       hub_u1_del = udev->parent->bos->ss_cap->bU1devExitLat;
+       hub_u2_del = udev->parent->bos->ss_cap->bU2DevExitLat;
+
+       usb_set_lpm_mel(udev, &udev->u1_params, udev_u1_del,
+                       hub, &udev->parent->u1_params, hub_u1_del);
+
+       usb_set_lpm_mel(udev, &udev->u2_params, udev_u2_del,
+                       hub, &udev->parent->u2_params, hub_u2_del);
+
+       /*
+        * Appendix C, section C.2.2.2, says that there is a slight delay from
+        * when the parent hub notices the downstream port is trying to
+        * transition to U0 to when the hub initiates a U0 transition on its
+        * upstream port.  The section says the delays are tPort2PortU1EL and
+        * tPort2PortU2EL, but it doesn't define what they are.
+        *
+        * The hub chapter, sections 10.4.2.4 and 10.4.2.5 seem to be talking
+        * about the same delays.  Use the maximum delay calculations from those
+        * sections.  For U1, it's tHubPort2PortExitLat, which is 1us max.  For
+        * U2, it's tHubPort2PortExitLat + U2DevExitLat - U1DevExitLat.  I
+        * assume the device exit latencies they are talking about are the hub
+        * exit latencies.
+        *
+        * What do we do if the U2 exit latency is less than the U1 exit
+        * latency?  It's possible, although not likely...
+        */
+       port_to_port_delay = 1;
+
+       usb_set_lpm_pel(udev, &udev->u1_params, udev_u1_del,
+                       hub, &udev->parent->u1_params, hub_u1_del,
+                       port_to_port_delay);
+
+       if (hub_u2_del > hub_u1_del)
+               port_to_port_delay = 1 + hub_u2_del - hub_u1_del;
+       else
+               port_to_port_delay = 1 + hub_u1_del;
+
+       usb_set_lpm_pel(udev, &udev->u2_params, udev_u2_del,
+                       hub, &udev->parent->u2_params, hub_u2_del,
+                       port_to_port_delay);
+
+       /* Now that we've got PEL, calculate SEL. */
+       usb_set_lpm_sel(udev, &udev->u1_params);
+       usb_set_lpm_sel(udev, &udev->u2_params);
+}
+
 /* USB 2.0 spec Section 11.24.4.5 */
 static int get_hub_descriptor(struct usb_device *hdev, void *data)
 {
 
        if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) {
                retval = usb_get_bos_descriptor(udev);
-               if (!retval)
+               if (!retval) {
                        udev->lpm_capable = usb_device_supports_lpm(udev);
+                       usb_set_lpm_parameters(udev);
+               }
        }
 
        retval = 0;
 
        USB_DEVICE_FIXED,
 };
 
+/*
+ * USB 3.0 Link Power Management (LPM) parameters.
+ *
+ * PEL and SEL are USB 3.0 Link PM latencies for device-initiated LPM exit.
+ * MEL is the USB 3.0 Link PM latency for host-initiated LPM exit.
+ * All three are stored in nanoseconds.
+ */
+struct usb3_lpm_parameters {
+       /*
+        * Maximum exit latency (MEL) for the host to send a packet to the
+        * device (either a Ping for isoc endpoints, or a data packet for
+        * interrupt endpoints), the hubs to decode the packet, and for all hubs
+        * in the path to transition the links to U0.
+        */
+       unsigned int mel;
+       /*
+        * Maximum exit latency for a device-initiated LPM transition to bring
+        * all links into U0.  Abbreviated as "PEL" in section 9.4.12 of the USB
+        * 3.0 spec, with no explanation of what "P" stands for.  "Path"?
+        */
+       unsigned int pel;
+
+       /*
+        * The System Exit Latency (SEL) includes PEL, and three other
+        * latencies.  After a device initiates a U0 transition, it will take
+        * some time from when the device sends the ERDY to when it will finally
+        * receive the data packet.  Basically, SEL should be the worse-case
+        * latency from when a device starts initiating a U0 transition to when
+        * it will get data.
+        */
+       unsigned int sel;
+};
+
 /**
  * struct usb_device - kernel's representation of a USB device
  * @devnum: device number; address on a USB bus
  *     specific data for the device.
  * @slot_id: Slot ID assigned by xHCI
  * @removable: Device can be physically removed from this port
+ * @u1_params: exit latencies for U1 (USB 3.0 LPM).
+ * @u2_params: exit latencies for U2 (USB 3.0 LPM).
  *
  * Notes:
  * Usbcore drivers should not set usbdev->state directly.  Instead use
        struct wusb_dev *wusb_dev;
        int slot_id;
        enum usb_device_removable removable;
+       struct usb3_lpm_parameters u1_params;
+       struct usb3_lpm_parameters u2_params;
 };
 #define        to_usb_device(d) container_of(d, struct usb_device, dev)