Skip to content

Commit d04ba4c

Browse files
Thinh Nguyengregkh
authored andcommitted
usb: core: hub: Disable hub-initiated U1/U2
[ Upstream commit 5617592 ] If the device rejects the control transfer to enable device-initiated U1/U2 entry, then the device will not initiate U1/U2 transition. To improve the performance, the downstream port should not initate transition to U1/U2 to avoid the delay from the device link command response (no packet can be transmitted while waiting for a response from the device). If the device has some quirks and does not implement U1/U2, it may reject all the link state change requests, and the downstream port may resend and flood the bus with more requests. This will affect the device performance even further. This patch disables the hub-initated U1/U2 if the device-initiated U1/U2 entry fails. Reference: USB 3.2 spec 7.2.4.2.3 Signed-off-by: Thinh Nguyen <thinhn@synopsys.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 309e886 commit d04ba4c

1 file changed

Lines changed: 16 additions & 12 deletions

File tree

drivers/usb/core/hub.c

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3823,6 +3823,9 @@ static int usb_set_lpm_timeout(struct usb_device *udev,
38233823
* control transfers to set the hub timeout or enable device-initiated U1/U2
38243824
* will be successful.
38253825
*
3826+
* If the control transfer to enable device-initiated U1/U2 entry fails, then
3827+
* hub-initiated U1/U2 will be disabled.
3828+
*
38263829
* If we cannot set the parent hub U1/U2 timeout, we attempt to let the xHCI
38273830
* driver know about it. If that call fails, it should be harmless, and just
38283831
* take up more slightly more bus bandwidth for unnecessary U1/U2 exit latency.
@@ -3877,23 +3880,24 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
38773880
* host know that this link state won't be enabled.
38783881
*/
38793882
hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
3880-
} else {
3881-
/* Only a configured device will accept the Set Feature
3882-
* U1/U2_ENABLE
3883-
*/
3884-
if (udev->actconfig)
3885-
usb_set_device_initiated_lpm(udev, state, true);
3883+
return;
3884+
}
38863885

3887-
/* As soon as usb_set_lpm_timeout(timeout) returns 0, the
3888-
* hub-initiated LPM is enabled. Thus, LPM is enabled no
3889-
* matter the result of usb_set_device_initiated_lpm().
3890-
* The only difference is whether device is able to initiate
3891-
* LPM.
3892-
*/
3886+
/* Only a configured device will accept the Set Feature
3887+
* U1/U2_ENABLE
3888+
*/
3889+
if (udev->actconfig &&
3890+
usb_set_device_initiated_lpm(udev, state, true) == 0) {
38933891
if (state == USB3_LPM_U1)
38943892
udev->usb3_lpm_u1_enabled = 1;
38953893
else if (state == USB3_LPM_U2)
38963894
udev->usb3_lpm_u2_enabled = 1;
3895+
} else {
3896+
/* Don't request U1/U2 entry if the device
3897+
* cannot transition to U1/U2.
3898+
*/
3899+
usb_set_lpm_timeout(udev, state, 0);
3900+
hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
38973901
}
38983902
}
38993903

0 commit comments

Comments
 (0)