Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 655fe4ef authored by Kevin Strasser's avatar Kevin Strasser Committed by Greg Kroah-Hartman
Browse files

usbcore: add sysfs support to xHCI usb3 hardware LPM



Add a sysfs node to make it easier to verify if LPM is supported and being
enabled for USB 3.0 devices.

Signed-off-by: default avatarKevin Strasser <kevin.strasser@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent eb4861c3
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -114,6 +114,20 @@ Description:
		enabled for the device. Developer can write y/Y/1 or n/N/0 to
		the file to enable/disable the feature.

What:		/sys/bus/usb/devices/.../power/usb3_hardware_lpm
Date:		June 2015
Contact:	Kevin Strasser <kevin.strasser@linux.intel.com>
Description:
		If CONFIG_PM_RUNTIME is set and a USB 3.0 lpm-capable device is
		plugged in to a xHCI host which supports link PM, it will check
		if U1 and U2 exit latencies have been set in the BOS
		descriptor; if the check is is passed and the host supports
		USB3 hardware LPM, USB3 hardware LPM will be enabled for the
		device and the USB device directory will contain a file named
		power/usb3_hardware_lpm. The file holds a string value (enable
		or disable) indicating whether or not USB3 hardware LPM is
		enabled for the device.

What:		/sys/bus/usb/devices/.../removable
Date:		February 2012
Contact:	Matthew Garrett <mjg@redhat.com>
+13 −2
Original line number Diff line number Diff line
@@ -521,10 +521,10 @@ 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
The user interface for controlling 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.
relevant attribute files are usb2_hardware_lpm and usb3_hardware_lpm.

	power/usb2_hardware_lpm

@@ -537,6 +537,17 @@ relevant attribute files is usb2_hardware_lpm.
		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.

	power/usb3_hardware_lpm

		When a USB 3.0 lpm-capable device is plugged in to a
		xHCI host which supports link PM, it will check if U1
		and U2 exit latencies have been set in the BOS
		descriptor; if the check is is passed and the host
		supports USB3 hardware LPM, USB3 hardware LPM will be
		enabled for the device and this file will be created.
		The file holds a string value (enable or disable)
		indicating whether or not USB3 hardware LPM is
		enabled for the device.

	USB Port Power Control
	----------------------
+4 −0
Original line number Diff line number Diff line
@@ -3950,6 +3950,8 @@ int usb_disable_lpm(struct usb_device *udev)
	if (usb_disable_link_state(hcd, udev, USB3_LPM_U2))
		goto enable_lpm;

	udev->usb3_lpm_enabled = 0;

	return 0;

enable_lpm:
@@ -4007,6 +4009,8 @@ void usb_enable_lpm(struct usb_device *udev)

	usb_enable_link_state(hcd, udev, USB3_LPM_U1);
	usb_enable_link_state(hcd, udev, USB3_LPM_U2);

	udev->usb3_lpm_enabled = 1;
}
EXPORT_SYMBOL_GPL(usb_enable_lpm);

+31 −0
Original line number Diff line number Diff line
@@ -531,6 +531,25 @@ static ssize_t usb2_lpm_besl_store(struct device *dev,
}
static DEVICE_ATTR_RW(usb2_lpm_besl);

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

	usb_lock_device(udev);

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

	usb_unlock_device(udev);

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

static struct attribute *usb2_hardware_lpm_attr[] = {
	&dev_attr_usb2_hardware_lpm.attr,
	&dev_attr_usb2_lpm_l1_timeout.attr,
@@ -542,6 +561,15 @@ static struct attribute_group usb2_hardware_lpm_attr_group = {
	.attrs	= usb2_hardware_lpm_attr,
};

static struct attribute *usb3_hardware_lpm_attr[] = {
	&dev_attr_usb3_hardware_lpm.attr,
	NULL,
};
static struct attribute_group usb3_hardware_lpm_attr_group = {
	.name	= power_group_name,
	.attrs	= usb3_hardware_lpm_attr,
};

static struct attribute *power_attrs[] = {
	&dev_attr_autosuspend.attr,
	&dev_attr_level.attr,
@@ -564,6 +592,9 @@ static int add_power_attributes(struct device *dev)
		if (udev->usb2_hw_lpm_capable == 1)
			rc = sysfs_merge_group(&dev->kobj,
					&usb2_hardware_lpm_attr_group);
		if (udev->lpm_capable == 1)
			rc = sysfs_merge_group(&dev->kobj,
					&usb3_hardware_lpm_attr_group);
	}

	return rc;