]> git.baikalelectronics.ru Git - kernel.git/commit
xhci: Fix lost USB 2 remote wake
authorMathias Nyman <mathias.nyman@linux.intel.com>
Thu, 15 Jul 2021 15:06:51 +0000 (18:06 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 21 Jul 2021 07:10:20 +0000 (09:10 +0200)
commit33d236f3c1f1b611f19dc1e2da0e42902eba8296
tree4bd2f7392bde5aba75acc80b9b2dbe7157a4e01f
parent777237a2269517794cf2de5e150b910c91cc50c0
xhci: Fix lost USB 2 remote wake

There's a small window where a USB 2 remote wake may be left unhandled
due to a race between hub thread and xhci port event interrupt handler.

When the resume event is detected in the xhci interrupt handler it kicks
the hub timer, which should move the port from resume to U0 once resume
has been signalled for long enough.

To keep the hub "thread" running we set a bus_state->resuming_ports flag.
This flag makes sure hub timer function kicks itself.

checking this flag was not properly protected by the spinlock. Flag was
copied to a local variable before lock was taken. The local variable was
then checked later with spinlock held.

If interrupt is handled right after copying the flag to the local variable
we end up stopping the hub thread before it can handle the USB 2 resume.

CPU0 CPU1
(hub thread) (xhci event handler)

xhci_hub_status_data()
status = bus_state->resuming_ports;
<Interrupt>
handle_port_status()
spin_lock()
bus_state->resuming_ports = 1
set_flag(HCD_FLAG_POLL_RH)
spin_unlock()
spin_lock()
if (!status)
  clear_flag(HCD_FLAG_POLL_RH)
spin_unlock()

Fix this by taking the lock a bit earlier so that it covers
the resuming_ports flag copy in the hub thread

Cc: <stable@vger.kernel.org>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20210715150651.1996099-2-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/host/xhci-hub.c