Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: core: lpm: fix usb3_hardware_lpm sysfs node

Commit 655fe4effe0f ("usbcore: add sysfs support to xHCI usb3
hardware LPM") introduced usb3_hardware_lpm sysfs node. This
doesn't show the correct status of USB3 U1 and U2 LPM status.

This patch fixes this by replacing usb3_hardware_lpm with two
nodes, usb3_hardware_lpm_u1 (for U1) and usb3_hardware_lpm_u2
(for U2), and recording the U1/U2 LPM status in right places.

This patch should be back-ported to kernels as old as 4.3,
that contains Commit 655fe4effe0f ("usbcore: add sysfs support
to xHCI usb3 hardware LPM").

Cc: stable@vger.kernel.org
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Lu Baolu and committed by
Greg Kroah-Hartman
bf5ce5bf c56a2b2b

+75 -26
+9 -7
Documentation/ABI/testing/sysfs-bus-usb
··· 134 134 enabled for the device. Developer can write y/Y/1 or n/N/0 to 135 135 the file to enable/disable the feature. 136 136 137 - What: /sys/bus/usb/devices/.../power/usb3_hardware_lpm 138 - Date: June 2015 137 + What: /sys/bus/usb/devices/.../power/usb3_hardware_lpm_u1 138 + /sys/bus/usb/devices/.../power/usb3_hardware_lpm_u2 139 + Date: November 2015 139 140 Contact: Kevin Strasser <kevin.strasser@linux.intel.com> 141 + Lu Baolu <baolu.lu@linux.intel.com> 140 142 Description: 141 143 If CONFIG_PM is set and a USB 3.0 lpm-capable device is plugged 142 144 in to a xHCI host which supports link PM, it will check if U1 143 145 and U2 exit latencies have been set in the BOS descriptor; if 144 - the check is is passed and the host supports USB3 hardware LPM, 146 + the check is passed and the host supports USB3 hardware LPM, 145 147 USB3 hardware LPM will be enabled for the device and the USB 146 - device directory will contain a file named 147 - power/usb3_hardware_lpm. The file holds a string value (enable 148 - or disable) indicating whether or not USB3 hardware LPM is 149 - enabled for the device. 148 + device directory will contain two files named 149 + power/usb3_hardware_lpm_u1 and power/usb3_hardware_lpm_u2. These 150 + files hold a string value (enable or disable) indicating whether 151 + or not USB3 hardware LPM U1 or U2 is enabled for the device. 150 152 151 153 What: /sys/bus/usb/devices/.../removable 152 154 Date: February 2012
+6 -5
Documentation/usb/power-management.txt
··· 537 537 can write y/Y/1 or n/N/0 to the file to enable/disable 538 538 USB2 hardware LPM manually. This is for test purpose mainly. 539 539 540 - power/usb3_hardware_lpm 540 + power/usb3_hardware_lpm_u1 541 + power/usb3_hardware_lpm_u2 541 542 542 543 When a USB 3.0 lpm-capable device is plugged in to a 543 544 xHCI host which supports link PM, it will check if U1 544 545 and U2 exit latencies have been set in the BOS 545 546 descriptor; if the check is is passed and the host 546 547 supports USB3 hardware LPM, USB3 hardware LPM will be 547 - enabled for the device and this file will be created. 548 - The file holds a string value (enable or disable) 549 - indicating whether or not USB3 hardware LPM is 550 - enabled for the device. 548 + enabled for the device and these files will be created. 549 + The files hold a string value (enable or disable) 550 + indicating whether or not USB3 hardware LPM U1 or U2 551 + is enabled for the device. 551 552 552 553 USB Port Power Control 553 554 ----------------------
+30 -9
drivers/usb/core/hub.c
··· 3875 3875 return; 3876 3876 } 3877 3877 3878 - if (usb_set_lpm_timeout(udev, state, timeout)) 3878 + if (usb_set_lpm_timeout(udev, state, timeout)) { 3879 3879 /* If we can't set the parent hub U1/U2 timeout, 3880 3880 * device-initiated LPM won't be allowed either, so let the xHCI 3881 3881 * host know that this link state won't be enabled. 3882 3882 */ 3883 3883 hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state); 3884 + } else { 3885 + /* Only a configured device will accept the Set Feature 3886 + * U1/U2_ENABLE 3887 + */ 3888 + if (udev->actconfig) 3889 + usb_set_device_initiated_lpm(udev, state, true); 3884 3890 3885 - /* Only a configured device will accept the Set Feature U1/U2_ENABLE */ 3886 - else if (udev->actconfig) 3887 - usb_set_device_initiated_lpm(udev, state, true); 3888 - 3891 + /* As soon as usb_set_lpm_timeout(timeout) returns 0, the 3892 + * hub-initiated LPM is enabled. Thus, LPM is enabled no 3893 + * matter the result of usb_set_device_initiated_lpm(). 3894 + * The only difference is whether device is able to initiate 3895 + * LPM. 3896 + */ 3897 + if (state == USB3_LPM_U1) 3898 + udev->usb3_lpm_u1_enabled = 1; 3899 + else if (state == USB3_LPM_U2) 3900 + udev->usb3_lpm_u2_enabled = 1; 3901 + } 3889 3902 } 3890 3903 3891 3904 /* ··· 3938 3925 dev_warn(&udev->dev, "Could not disable xHCI %s timeout, " 3939 3926 "bus schedule bandwidth may be impacted.\n", 3940 3927 usb3_lpm_names[state]); 3928 + 3929 + /* As soon as usb_set_lpm_timeout(0) return 0, hub initiated LPM 3930 + * is disabled. Hub will disallows link to enter U1/U2 as well, 3931 + * even device is initiating LPM. Hence LPM is disabled if hub LPM 3932 + * timeout set to 0, no matter device-initiated LPM is disabled or 3933 + * not. 3934 + */ 3935 + if (state == USB3_LPM_U1) 3936 + udev->usb3_lpm_u1_enabled = 0; 3937 + else if (state == USB3_LPM_U2) 3938 + udev->usb3_lpm_u2_enabled = 0; 3939 + 3941 3940 return 0; 3942 3941 } 3943 3942 ··· 3983 3958 goto enable_lpm; 3984 3959 if (usb_disable_link_state(hcd, udev, USB3_LPM_U2)) 3985 3960 goto enable_lpm; 3986 - 3987 - udev->usb3_lpm_enabled = 0; 3988 3961 3989 3962 return 0; 3990 3963 ··· 4041 4018 4042 4019 usb_enable_link_state(hcd, udev, USB3_LPM_U1); 4043 4020 usb_enable_link_state(hcd, udev, USB3_LPM_U2); 4044 - 4045 - udev->usb3_lpm_enabled = 1; 4046 4021 } 4047 4022 EXPORT_SYMBOL_GPL(usb_enable_lpm); 4048 4023
+26 -5
drivers/usb/core/sysfs.c
··· 531 531 } 532 532 static DEVICE_ATTR_RW(usb2_lpm_besl); 533 533 534 - static ssize_t usb3_hardware_lpm_show(struct device *dev, 534 + static ssize_t usb3_hardware_lpm_u1_show(struct device *dev, 535 535 struct device_attribute *attr, char *buf) 536 536 { 537 537 struct usb_device *udev = to_usb_device(dev); ··· 539 539 540 540 usb_lock_device(udev); 541 541 542 - if (udev->usb3_lpm_enabled) 542 + if (udev->usb3_lpm_u1_enabled) 543 543 p = "enabled"; 544 544 else 545 545 p = "disabled"; ··· 548 548 549 549 return sprintf(buf, "%s\n", p); 550 550 } 551 - static DEVICE_ATTR_RO(usb3_hardware_lpm); 551 + static DEVICE_ATTR_RO(usb3_hardware_lpm_u1); 552 + 553 + static ssize_t usb3_hardware_lpm_u2_show(struct device *dev, 554 + struct device_attribute *attr, char *buf) 555 + { 556 + struct usb_device *udev = to_usb_device(dev); 557 + const char *p; 558 + 559 + usb_lock_device(udev); 560 + 561 + if (udev->usb3_lpm_u2_enabled) 562 + p = "enabled"; 563 + else 564 + p = "disabled"; 565 + 566 + usb_unlock_device(udev); 567 + 568 + return sprintf(buf, "%s\n", p); 569 + } 570 + static DEVICE_ATTR_RO(usb3_hardware_lpm_u2); 552 571 553 572 static struct attribute *usb2_hardware_lpm_attr[] = { 554 573 &dev_attr_usb2_hardware_lpm.attr, ··· 581 562 }; 582 563 583 564 static struct attribute *usb3_hardware_lpm_attr[] = { 584 - &dev_attr_usb3_hardware_lpm.attr, 565 + &dev_attr_usb3_hardware_lpm_u1.attr, 566 + &dev_attr_usb3_hardware_lpm_u2.attr, 585 567 NULL, 586 568 }; 587 569 static struct attribute_group usb3_hardware_lpm_attr_group = { ··· 612 592 if (udev->usb2_hw_lpm_capable == 1) 613 593 rc = sysfs_merge_group(&dev->kobj, 614 594 &usb2_hardware_lpm_attr_group); 615 - if (udev->lpm_capable == 1) 595 + if (udev->speed == USB_SPEED_SUPER && 596 + udev->lpm_capable == 1) 616 597 rc = sysfs_merge_group(&dev->kobj, 617 598 &usb3_hardware_lpm_attr_group); 618 599 }
+4
include/linux/usb.h
··· 511 511 * @usb2_hw_lpm_enabled: USB2 hardware LPM is enabled 512 512 * @usb2_hw_lpm_allowed: Userspace allows USB 2.0 LPM to be enabled 513 513 * @usb3_lpm_enabled: USB3 hardware LPM enabled 514 + * @usb3_lpm_u1_enabled: USB3 hardware U1 LPM enabled 515 + * @usb3_lpm_u2_enabled: USB3 hardware U2 LPM enabled 514 516 * @string_langid: language ID for strings 515 517 * @product: iProduct string, if present (static) 516 518 * @manufacturer: iManufacturer string, if present (static) ··· 586 584 unsigned usb2_hw_lpm_enabled:1; 587 585 unsigned usb2_hw_lpm_allowed:1; 588 586 unsigned usb3_lpm_enabled:1; 587 + unsigned usb3_lpm_u1_enabled:1; 588 + unsigned usb3_lpm_u2_enabled:1; 589 589 int string_langid; 590 590 591 591 /* static strings from the device */