Skip to content

Commit 9f952e2

Browse files
AlanSterngregkh
authored andcommitted
USB: hub: Fix handling of connect changes during sleep
Commit 8099f58 ("USB: hub: Don't record a connect-change event during reset-resume") wasn't very well conceived. The problem it tried to fix was that if a connect-change event occurred while the system was asleep (such as a device disconnecting itself from the bus when it is suspended and then reconnecting when it resumes) requiring a reset-resume during the system wakeup transition, the hub port's change_bit entry would remain set afterward. This would cause the hub driver to believe another connect-change event had occurred after the reset-resume, which was wrong and would lead the driver to send unnecessary requests to the device (which could interfere with a firmware update). The commit tried to fix this by not setting the change_bit during the wakeup. But this was the wrong thing to do; it means that when a device is unplugged while the system is asleep, the hub driver doesn't realize anything has happened: The change_bit flag which would tell it to handle the disconnect event is clear. The commit needs to be reverted and the problem fixed in a different way. Fortunately an alternative solution was noted in the commit's Changelog: We can continue to set the change_bit entry in hub_activate() but then clear it when a reset-resume occurs. That way the the hub driver will see the change_bit when a device is disconnected but won't see it when the device is still present. That's what this patch does. Reported-and-tested-by: Peter Chen <[email protected]> Signed-off-by: Alan Stern <[email protected]> Fixes: 8099f58 ("USB: hub: Don't record a connect-change event during reset-resume") Tested-by: Paul Zimmerman <[email protected]> CC: <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 0df9433 commit 9f952e2

File tree

1 file changed

+14
-0
lines changed

1 file changed

+14
-0
lines changed

drivers/usb/core/hub.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,6 +1223,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
12231223
#ifdef CONFIG_PM
12241224
udev->reset_resume = 1;
12251225
#endif
1226+
/* Don't set the change_bits when the device
1227+
* was powered off.
1228+
*/
1229+
if (test_bit(port1, hub->power_bits))
1230+
set_bit(port1, hub->change_bits);
12261231

12271232
} else {
12281233
/* The power session is gone; tell hub_wq */
@@ -3088,6 +3093,15 @@ static int check_port_resume_type(struct usb_device *udev,
30883093
if (portchange & USB_PORT_STAT_C_ENABLE)
30893094
usb_clear_port_feature(hub->hdev, port1,
30903095
USB_PORT_FEAT_C_ENABLE);
3096+
3097+
/*
3098+
* Whatever made this reset-resume necessary may have
3099+
* turned on the port1 bit in hub->change_bits. But after
3100+
* a successful reset-resume we want the bit to be clear;
3101+
* if it was on it would indicate that something happened
3102+
* following the reset-resume.
3103+
*/
3104+
clear_bit(port1, hub->change_bits);
30913105
}
30923106

30933107
return status;

0 commit comments

Comments
 (0)