lkml.org 
[lkml]   [2022]   [Jan]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.16 17/37] USB: core: Fix bug in resuming hubs handling of wakeup requests
    Date
    From: Alan Stern <stern@rowland.harvard.edu>

    commit 0f663729bb4afc92a9986b66131ebd5b8a9254d1 upstream.

    Bugzilla #213839 reports a 7-port hub that doesn't work properly when
    devices are plugged into some of the ports; the kernel goes into an
    unending disconnect/reinitialize loop as shown in the bug report.

    This "7-port hub" comprises two four-port hubs with one plugged into
    the other; the failures occur when a device is plugged into one of the
    downstream hub's ports. (These hubs have other problems too. For
    example, they bill themselves as USB-2.0 compliant but they only run
    at full speed.)

    It turns out that the failures are caused by bugs in both the kernel
    and the hub. The hub's bug is that it reports a different
    bmAttributes value in its configuration descriptor following a remote
    wakeup (0xe0 before, 0xc0 after -- the wakeup-support bit has
    changed).

    The kernel's bug is inside the hub driver's resume handler. When
    hub_activate() sees that one of the hub's downstream ports got a
    wakeup request from a child device, it notes this fact by setting the
    corresponding bit in the hub->change_bits variable. But this variable
    is meant for connection changes, not wakeup events; setting it causes
    the driver to believe the downstream port has been disconnected and
    then connected again (in addition to having received a wakeup
    request).

    Because of this, the hub driver then tries to check whether the device
    currently plugged into the downstream port is the same as the device
    that had been attached there before. Normally this check succeeds and
    wakeup handling continues with no harm done (which is why the bug
    remained undetected until now). But with these dodgy hubs, the check
    fails because the config descriptor has changed. This causes the hub
    driver to reinitialize the child device, leading to the
    disconnect/reinitialize loop described in the bug report.

    The proper way to note reception of a downstream wakeup request is
    to set a bit in the hub->event_bits variable instead of
    hub->change_bits. That way the hub driver will realize that something
    has happened to the port but will not think the port and child device
    have been disconnected. This patch makes that change.

    Cc: <stable@vger.kernel.org>
    Tested-by: Jonathan McDowell <noodles@earth.li>
    Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
    Link: https://lore.kernel.org/r/YdCw7nSfWYPKWQoD@rowland.harvard.edu
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    drivers/usb/core/hub.c | 2 +-
    1 file changed, 1 insertion(+), 1 deletion(-)

    --- a/drivers/usb/core/hub.c
    +++ b/drivers/usb/core/hub.c
    @@ -1225,7 +1225,7 @@ static void hub_activate(struct usb_hub
    */
    if (portchange || (hub_is_superspeed(hub->hdev) &&
    port_resumed))
    - set_bit(port1, hub->change_bits);
    + set_bit(port1, hub->event_bits);

    } else if (udev->persist_enabled) {
    #ifdef CONFIG_PM

    \
     
     \ /
      Last update: 2022-01-14 09:39    [W:3.210 / U:0.436 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site