blob: de7dac656c13c7dca298506b13cdbee12b5f4f3e [file] [log] [blame]
From d9bcaf6868ca8f304dd76246251154cfd2bd0b50 Mon Sep 17 00:00:00 2001
From: Mathias Nyman <mathias.nyman@linux.intel.com>
Date: Thu, 23 May 2013 17:14:31 +0300
Subject: usb: add usb2 Link PM variables to sysfs and usb_device
Adds abitilty to tune L1 timeout (inactivity timer for usb2 link sleep)
and BESL (best effort service latency)via sysfs.
This also adds a new usb2_lpm_parameters structure with those variables to
struct usb_device.
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
(cherry picked from commit 17f34867e98d2fb0c03918faab79efb989fa134b)
Signed-off-by: Benson Leung <bleung@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/169213
Reviewed-by: Julius Werner <jwerner@chromium.org>
Commit-Queue: Benson Leung <bleung@chromium.org>
Tested-by: Benson Leung <bleung@chromium.org>
Signed-off-by: Darren Hart <dvhart@linux.intel.com>
---
Documentation/ABI/testing/sysfs-bus-usb | 27 ++++++++++++++++
drivers/usb/core/sysfs.c | 54 ++++++++++++++++++++++++++++++++
drivers/usb/host/xhci.c | 6 ++-
include/linux/usb.h | 18 ++++++++++
4 files changed, 103 insertions(+), 2 deletions(-)
--- a/Documentation/ABI/testing/sysfs-bus-usb
+++ b/Documentation/ABI/testing/sysfs-bus-usb
@@ -236,3 +236,30 @@ Description:
This attribute is to expose these information to user space.
The file will read "hotplug", "wired" and "not used" if the
information is available, and "unknown" otherwise.
+
+What: /sys/bus/usb/devices/.../power/usb2_lpm_l1_timeout
+Date: May 2013
+Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
+Description:
+ USB 2.0 devices may support hardware link power management (LPM)
+ L1 sleep state. The usb2_lpm_l1_timeout attribute allows
+ tuning the timeout for L1 inactivity timer (LPM timer), e.g.
+ needed inactivity time before host requests the device to go to L1 sleep.
+ Useful for power management tuning.
+ Supported values are 0 - 65535 microseconds.
+
+What: /sys/bus/usb/devices/.../power/usb2_lpm_besl
+Date: May 2013
+Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
+Description:
+ USB 2.0 devices that support hardware link power management (LPM)
+ L1 sleep state now use a best effort service latency value (BESL) to
+ indicate the best effort to resumption of service to the device after the
+ initiation of the resume event.
+ If the device does not have a preferred besl value then the host can select
+ one instead. This usb2_lpm_besl attribute allows to tune the host selected besl
+ value in order to tune power saving and service latency.
+
+ Supported values are 0 - 15.
+ More information on how besl values map to microseconds can be found in
+ USB 2.0 ECN Errata for Link Power Management, section 4.10)
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -497,8 +497,62 @@ set_usb2_hardware_lpm(struct device *dev
static DEVICE_ATTR(usb2_hardware_lpm, S_IRUGO | S_IWUSR, show_usb2_hardware_lpm,
set_usb2_hardware_lpm);
+static ssize_t
+show_usb2_lpm_l1_timeout(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ return sprintf(buf, "%d\n", udev->l1_params.timeout);
+}
+
+static ssize_t
+set_usb2_lpm_l1_timeout(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ u16 timeout;
+
+ if (kstrtou16(buf, 0, &timeout))
+ return -EINVAL;
+
+ udev->l1_params.timeout = timeout;
+
+ return count;
+}
+
+static DEVICE_ATTR(usb2_lpm_l1_timeout, S_IRUGO | S_IWUSR,
+ show_usb2_lpm_l1_timeout, set_usb2_lpm_l1_timeout);
+
+static ssize_t
+show_usb2_lpm_besl(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ return sprintf(buf, "%d\n", udev->l1_params.besl);
+}
+
+static ssize_t
+set_usb2_lpm_besl(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ u8 besl;
+
+ if (kstrtou8(buf, 0, &besl) || besl > 15)
+ return -EINVAL;
+
+ udev->l1_params.besl = besl;
+
+ return count;
+}
+
+static DEVICE_ATTR(usb2_lpm_besl, S_IRUGO | S_IWUSR,
+ show_usb2_lpm_besl, set_usb2_lpm_besl);
+
static struct attribute *usb2_hardware_lpm_attr[] = {
&dev_attr_usb2_hardware_lpm.attr,
+ &dev_attr_usb2_lpm_l1_timeout.attr,
+ &dev_attr_usb2_lpm_besl.attr,
NULL,
};
static struct attribute_group usb2_hardware_lpm_attr_group = {
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -3957,7 +3957,7 @@ static int xhci_calculate_usb2_hw_lpm_pa
field = le32_to_cpu(udev->bos->ext_cap->bmAttributes);
/* xHCI l1 is set in steps of 256us, xHCI 1.0 section 5.4.11.2 */
- l1 = XHCI_L1_TIMEOUT / 256;
+ l1 = udev->l1_params.timeout / 256;
/* device has preferred BESLD */
if (field & USB_BESL_DEEP_VALID) {
@@ -4141,7 +4141,7 @@ int xhci_set_usb2_hardware_lpm(struct us
(field & USB_BESL_BASELINE_VALID))
hird = USB_GET_BESL_BASELINE(field);
else
- hird = XHCI_DEFAULT_BESL;
+ hird = udev->l1_params.besl;
exit_latency = xhci_besl_encoding[hird];
spin_unlock_irqrestore(&xhci->lock, flags);
@@ -4231,6 +4231,8 @@ int xhci_update_device(struct usb_hcd *h
if (xhci->hw_lpm_support == 1 &&
xhci_check_usb2_port_capability(xhci, portnum, XHCI_HLC)) {
udev->usb2_hw_lpm_capable = 1;
+ udev->l1_params.timeout = XHCI_L1_TIMEOUT;
+ udev->l1_params.besl = XHCI_DEFAULT_BESL;
if (xhci_check_usb2_port_capability(xhci, portnum,
XHCI_BLC))
udev->usb2_hw_lpm_besl_capable = 1;
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -420,6 +420,22 @@ enum usb_port_connect_type {
};
/*
+ * USB 2.0 Link Power Management (LPM) parameters.
+ */
+struct usb2_lpm_parameters {
+ /* Best effort service latency indicate how long the host will drive
+ * resume on an exit from L1.
+ */
+ unsigned int besl;
+
+ /* Timeout value in microseconds for the L1 inactivity (LPM) timer.
+ * When the timer counts to zero, the parent hub will initiate a LPM
+ * transition to L1.
+ */
+ int timeout;
+};
+
+/*
* USB 3.0 Link Power Management (LPM) parameters.
*
* PEL and SEL are USB 3.0 Link PM latencies for device-initiated LPM exit.
@@ -514,6 +530,7 @@ struct usb3_lpm_parameters {
* specific data for the device.
* @slot_id: Slot ID assigned by xHCI
* @removable: Device can be physically removed from this port
+ * @l1_params: best effor service latency for USB2 L1 LPM state, and L1 timeout.
* @u1_params: exit latencies for USB3 U1 LPM state, and hub-initiated timeout.
* @u2_params: exit latencies for USB3 U2 LPM state, and hub-initiated timeout.
* @lpm_disable_count: Ref count used by usb_disable_lpm() and usb_enable_lpm()
@@ -594,6 +611,7 @@ struct usb_device {
struct wusb_dev *wusb_dev;
int slot_id;
enum usb_device_removable removable;
+ struct usb2_lpm_parameters l1_params;
struct usb3_lpm_parameters u1_params;
struct usb3_lpm_parameters u2_params;
unsigned lpm_disable_count;