linux-uconsole/include
Chris Bainbridge 0df34fd35c UPSTREAM: usb: core: hub: hub_port_init lock controller instead of bus
The XHCI controller presents two USB buses to the system - one for USB2
and one for USB3. The hub init code (hub_port_init) is reentrant but
only locks one bus per thread, leading to a race condition failure when
two threads attempt to simultaneously initialise a USB2 and USB3 device:

[    8.034843] xhci_hcd 0000:00:14.0: Timeout while waiting for setup device command
[   13.183701] usb 3-3: device descriptor read/all, error -110

On a test system this failure occurred on 6% of all boots.

The call traces at the point of failure are:

Call Trace:
 [<ffffffff81b9bab7>] schedule+0x37/0x90
 [<ffffffff817da7cd>] usb_kill_urb+0x8d/0xd0
 [<ffffffff8111e5e0>] ? wake_up_atomic_t+0x30/0x30
 [<ffffffff817dafbe>] usb_start_wait_urb+0xbe/0x150
 [<ffffffff817db10c>] usb_control_msg+0xbc/0xf0
 [<ffffffff817d07de>] hub_port_init+0x51e/0xb70
 [<ffffffff817d4697>] hub_event+0x817/0x1570
 [<ffffffff810f3e6f>] process_one_work+0x1ff/0x620
 [<ffffffff810f3dcf>] ? process_one_work+0x15f/0x620
 [<ffffffff810f4684>] worker_thread+0x64/0x4b0
 [<ffffffff810f4620>] ? rescuer_thread+0x390/0x390
 [<ffffffff810fa7f5>] kthread+0x105/0x120
 [<ffffffff810fa6f0>] ? kthread_create_on_node+0x200/0x200
 [<ffffffff81ba183f>] ret_from_fork+0x3f/0x70
 [<ffffffff810fa6f0>] ? kthread_create_on_node+0x200/0x200

Call Trace:
 [<ffffffff817fd36d>] xhci_setup_device+0x53d/0xa40
 [<ffffffff817fd87e>] xhci_address_device+0xe/0x10
 [<ffffffff817d047f>] hub_port_init+0x1bf/0xb70
 [<ffffffff811247ed>] ? trace_hardirqs_on+0xd/0x10
 [<ffffffff817d4697>] hub_event+0x817/0x1570
 [<ffffffff810f3e6f>] process_one_work+0x1ff/0x620
 [<ffffffff810f3dcf>] ? process_one_work+0x15f/0x620
 [<ffffffff810f4684>] worker_thread+0x64/0x4b0
 [<ffffffff810f4620>] ? rescuer_thread+0x390/0x390
 [<ffffffff810fa7f5>] kthread+0x105/0x120
 [<ffffffff810fa6f0>] ? kthread_create_on_node+0x200/0x200
 [<ffffffff81ba183f>] ret_from_fork+0x3f/0x70
 [<ffffffff810fa6f0>] ? kthread_create_on_node+0x200/0x200

Which results from the two call chains:

hub_port_init
 usb_get_device_descriptor
  usb_get_descriptor
   usb_control_msg
    usb_internal_control_msg
     usb_start_wait_urb
      usb_submit_urb / wait_for_completion_timeout / usb_kill_urb

hub_port_init
 hub_set_address
  xhci_address_device
   xhci_setup_device

Mathias Nyman explains the current behaviour violates the XHCI spec:

 hub_port_reset() will end up moving the corresponding xhci device slot
 to default state.

 As hub_port_reset() is called several times in hub_port_init() it
 sounds reasonable that we could end up with two threads having their
 xhci device slots in default state at the same time, which according to
 xhci 4.5.3 specs still is a big no no:

 "Note: Software shall not transition more than one Device Slot to the
  Default State at a time"

 So both threads fail at their next task after this.
 One fails to read the descriptor, and the other fails addressing the
 device.

Fix this in hub_port_init by locking the USB controller (instead of an
individual bus) to prevent simultaneous initialisation of both buses.

Fixes: 638139eb95 ("usb: hub: allow to process more usb hub events in parallel")
Link: https://lkml.org/lkml/2016/2/8/312
Link: https://lkml.org/lkml/2016/2/4/748

Conflicts:
        drivers/usb/core/hcd.c

Change-Id: I5f266198d32793ea3bc009f64ffc8b2a7744461a
Signed-off-by: Chris Bainbridge <chris.bainbridge@gmail.com>
Cc: stable <stable@vger.kernel.org>
Acked-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: William Wu <wulf@rock-chips.com>
(cherry picked from commit feb26ac31a)
2017-01-20 10:31:36 +08:00
..
acpi
asm-generic UPSTREAM: sched/preempt: Fix preempt_count manipulations 2016-11-08 10:21:07 +08:00
clocksource arm64: KVM: Implement timer save/restore 2016-11-09 22:15:41 +08:00
crypto crypto: ghash-generic - move common definitions to a new header file 2016-10-22 12:26:56 +02:00
drm UPSTREAM: drm: Add callbacks for late registering 2017-01-03 09:16:58 +08:00
dt-bindings clk: rk3288: correct cif_out to vip_out 2017-01-19 10:08:10 +08:00
keys
kvm KVM: arm/arm64: vgic-v3: Make the LR indexing macro public 2016-11-09 22:15:40 +08:00
linux UPSTREAM: usb: core: hub: hub_port_init lock controller instead of bus 2017-01-20 10:31:36 +08:00
math-emu
media isp10: rockchip: v0.1.6 2016-11-29 21:11:43 +08:00
memory
misc
net Merge branch 'linux-linaro-lsk-v4.4' into linux-linaro-lsk-v4.4-android 2017-01-10 12:01:14 +08:00
pcmcia
ras
rdma IB/cma: Fix a race condition in iboe_addr_get_sgid() 2017-01-09 08:07:51 +01:00
rxrpc
scsi
soc video: rockchip: lcdc: add support dmc 2016-08-25 21:22:12 +08:00
sound FROMLIST: ASoC: hdmi-codec: Use HDMI notifications to add jack support 2016-12-20 20:04:25 +08:00
target target: Make EXTENDED_COPY 0xe4 failure return COPY TARGET DEVICE NOT REACHABLE 2016-10-28 03:01:36 -04:00
trace Merge branch 'linux-linaro-lsk-v4.4-android' of git://git.linaro.org/kernel/linux-linaro-stable.git 2017-01-10 16:07:06 +08:00
uapi Merge branch 'linux-linaro-lsk-v4.4-android' of git://git.linaro.org/kernel/linux-linaro-stable.git 2017-01-10 16:07:06 +08:00
video video: rockchip: screen: add refresh mode for cmd mode screen 2016-10-26 16:54:56 +08:00
xen
Kbuild