lkml.org 
[lkml]   [2020]   [Apr]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.6 094/167] USB: hub: Fix handling of connect changes during sleep
    Date
    From: Alan Stern <stern@rowland.harvard.edu>

    commit 9f952e26295d977dbfc6fedeaf8c4f112c818d37 upstream.

    Commit 8099f58f1ecd ("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 <peter.chen@nxp.com>
    Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
    Fixes: 8099f58f1ecd ("USB: hub: Don't record a connect-change event during reset-resume")
    Tested-by: Paul Zimmerman <pauldzim@gmail.com>
    CC: <stable@vger.kernel.org>
    Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.2004221602480.11262-100000@iolanthe.rowland.org
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/usb/core/hub.c | 14 ++++++++++++++
    1 file changed, 14 insertions(+)

    --- a/drivers/usb/core/hub.c
    +++ b/drivers/usb/core/hub.c
    @@ -1223,6 +1223,11 @@ static void hub_activate(struct usb_hub
    #ifdef CONFIG_PM
    udev->reset_resume = 1;
    #endif
    + /* Don't set the change_bits when the device
    + * was powered off.
    + */
    + if (test_bit(port1, hub->power_bits))
    + set_bit(port1, hub->change_bits);

    } else {
    /* The power session is gone; tell hub_wq */
    @@ -3088,6 +3093,15 @@ static int check_port_resume_type(struct
    if (portchange & USB_PORT_STAT_C_ENABLE)
    usb_clear_port_feature(hub->hdev, port1,
    USB_PORT_FEAT_C_ENABLE);
    +
    + /*
    + * Whatever made this reset-resume necessary may have
    + * turned on the port1 bit in hub->change_bits. But after
    + * a successful reset-resume we want the bit to be clear;
    + * if it was on it would indicate that something happened
    + * following the reset-resume.
    + */
    + clear_bit(port1, hub->change_bits);
    }

    return status;

    \
     
     \ /
      Last update: 2020-04-28 20:32    [W:3.930 / U:0.096 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site