Skip to content

Commit

Permalink
usbcore: add sysfs support to xHCI usb2 hardware LPM
Browse files Browse the repository at this point in the history
This patch adds sysfs support to xHCI usb2 hardware LPM, so developer can
enable and disable usb2 hardware LPM manually for test purpose.

Signed-off-by: Andiry Xu <andiry.xu@amd.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Andiry Xu authored and Greg Kroah-Hartman committed Sep 26, 2011
1 parent 65580b4 commit c1045e8
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 1 deletion.
15 changes: 15 additions & 0 deletions Documentation/ABI/testing/sysfs-bus-usb
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,18 @@ Description:
such devices.
Users:
usb_modeswitch

What: /sys/bus/usb/devices/.../power/usb2_hardware_lpm
Date: September 2011
Contact: Andiry Xu <andiry.xu@amd.com>
Description:
If CONFIG_USB_SUSPEND is set and a USB 2.0 lpm-capable device
is plugged in to a xHCI host which support link PM, it will
perform a LPM test; if the test is passed and host supports
USB2 hardware LPM (xHCI 1.0 feature), USB2 hardware LPM will
be enabled for the device and the USB device directory will
contain a file named power/usb2_hardware_lpm. The file holds
a string value (enable or disable) indicating whether or not
USB2 hardware LPM is enabled for the device. Developer can
write y/Y/1 or n/N/0 to the file to enable/disable the
feature.
26 changes: 26 additions & 0 deletions Documentation/usb/power-management.txt
Original file line number Diff line number Diff line change
Expand Up @@ -487,3 +487,29 @@ succeed, it may still remain active and thus cause the system to
resume as soon as the system suspend is complete. Or the remote
wakeup may fail and get lost. Which outcome occurs depends on timing
and on the hardware and firmware design.


xHCI hardware link PM
---------------------

xHCI host controller provides hardware link power management to usb2.0
(xHCI 1.0 feature) and usb3.0 devices which support link PM. By
enabling hardware LPM, the host can automatically put the device into
lower power state(L1 for usb2.0 devices, or U1/U2 for usb3.0 devices),
which state device can enter and resume very quickly.

The user interface for controlling USB2 hardware LPM is located in the
power/ subdirectory of each USB device's sysfs directory, that is, in
/sys/bus/usb/devices/.../power/ where "..." is the device's ID. The
relevant attribute files is usb2_hardware_lpm.

power/usb2_hardware_lpm

When a USB2 device which support LPM is plugged to a
xHCI host root hub which support software LPM, the
host will run a software LPM test for it; if the device
enters L1 state and resume successfully and the host
supports USB2 hardware LPM, this file will show up and
driver will enable hardware LPM for the device. You
can write y/Y/1 or n/N/0 to the file to enable/disable
USB2 hardware LPM manually. This is for test purpose mainly.
59 changes: 58 additions & 1 deletion drivers/usb/core/sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,56 @@ set_level(struct device *dev, struct device_attribute *attr,

static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level);

static ssize_t
show_usb2_hardware_lpm(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct usb_device *udev = to_usb_device(dev);
const char *p;

if (udev->usb2_hw_lpm_enabled == 1)
p = "enabled";
else
p = "disabled";

return sprintf(buf, "%s\n", p);
}

static ssize_t
set_usb2_hardware_lpm(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
bool value;
int ret;

usb_lock_device(udev);

ret = strtobool(buf, &value);

if (!ret)
ret = usb_set_usb2_hardware_lpm(udev, value);

usb_unlock_device(udev);

if (!ret)
return count;

return ret;
}

static DEVICE_ATTR(usb2_hardware_lpm, S_IRUGO | S_IWUSR, show_usb2_hardware_lpm,
set_usb2_hardware_lpm);

static struct attribute *usb2_hardware_lpm_attr[] = {
&dev_attr_usb2_hardware_lpm.attr,
NULL,
};
static struct attribute_group usb2_hardware_lpm_attr_group = {
.name = power_group_name,
.attrs = usb2_hardware_lpm_attr,
};

static struct attribute *power_attrs[] = {
&dev_attr_autosuspend.attr,
&dev_attr_level.attr,
Expand All @@ -428,13 +478,20 @@ static int add_power_attributes(struct device *dev)
{
int rc = 0;

if (is_usb_device(dev))
if (is_usb_device(dev)) {
struct usb_device *udev = to_usb_device(dev);
rc = sysfs_merge_group(&dev->kobj, &power_attr_group);
if (udev->usb2_hw_lpm_capable == 1)
rc = sysfs_merge_group(&dev->kobj,
&usb2_hardware_lpm_attr_group);
}

return rc;
}

static void remove_power_attributes(struct device *dev)
{
sysfs_unmerge_group(&dev->kobj, &usb2_hardware_lpm_attr_group);
sysfs_unmerge_group(&dev->kobj, &power_attr_group);
}

Expand Down

0 comments on commit c1045e8

Please sign in to comment.