Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
usb: dwc3: keep a copy of IDDIG status for DRD mode switch
In some conditions of DRD mode switching transition, for example plugging in or remove the USB cable slowly, the DWC3 controller can trigger multiple otg interrupts while the ID status is not changed when reading the OSTS register bit0. Then dwc3_otg_thread_interrupt() then will try to stop the hcd or udc multiple times while processing these OTG events, in which the second time teardown causes kernel crash since the resource is no longer available. Following is an exmaple of crash log, while removing the microA-typeA adaptor cable triggers the following two interrupts and hangs the kernel. [ 40.010169] dwc3 48390000.usb: OTG thread interrupt, OSTS 0x180f [ 40.020738] xhci-hcd xhci-hcd.0.auto: remove, state 4 [ 40.026847] usb usb2: USB disconnect, device number 1 [ 40.055775] xhci-hcd xhci-hcd.0.auto: USB bus 2 deregistered [ 40.067580] xhci-hcd xhci-hcd.0.auto: remove, state 1 [ 40.073122] usb usb1: USB disconnect, device number 1 [ 40.080046] usb 1-1: USB disconnect, device number 2 [ 40.169225] xhci-hcd xhci-hcd.0.auto: USB bus 1 deregistered [ 40.183931] dwc3 48390000.usb: OTG thread interrupt, OSTS 0x819 [ 40.194340] kobject (eb5e4c48): tried to init an initialized object, something is seriously wrong. [ 40.203831] CPU: 0 PID: 1018 Comm: irq/204-dwc3-ot Not tainted 3.14.26-dirty #10 [ 40.211653] [<c0015ecc>] (unwind_backtrace) from [<c0012a10>] (show_stack+0x10/0x14) [ 40.219874] [<c0012a10>] (show_stack) from [<c0571244>] (dump_stack+0x78/0x94) [ 40.227556] [<c0571244>] (dump_stack) from [<c02e8e88>] (kobject_init+0x74/0x94) [ 40.235404] [<c02e8e88>] (kobject_init) from [<c036ab18>] (device_initialize+0x20/0xcc) [ 40.243878] [<c036ab18>] (device_initialize) from [<c036bf8c>] (device_register+0xc/0x18) [ 40.252578] [<c036bf8c>] (device_register) from [<c042bcec>] (usb_add_gadget_udc_release+0xbc/0x1ec) [ 40.262276] [<c042bcec>] (usb_add_gadget_udc_release) from [<c042c43c>] (usb_drd_start_udc+0x54/0x9c) [ 40.272056] [<c042c43c>] (usb_drd_start_udc) from [<bf1b3708>] (dwc3_otg_thread_interrupt+0x178/0x198 [dwc3]) [ 40.282611] [<bf1b3708>] (dwc3_otg_thread_interrupt [dwc3]) from [<c0095f54>] (irq_thread_fn+0x1c/0x34) [ 40.292584] [<c0095f54>] (irq_thread_fn) from [<c00960e0>] (irq_thread+0x120/0x180) [ 40.300691] [<c00960e0>] (irq_thread) from [<c00650e0>] (kthread+0xc4/0xe0) [ 40.308098] [<c00650e0>] (kthread) from [<c000f068>] (ret_from_fork+0x14/0x2c) The fix is to add a local copy of iddig in struct dwc3, and dwc3_otg_thread_interrupt() will not take any action if the iddig is not changed. Signed-off-by: Bin Liu <[email protected]> [[email protected]: line over 80 char checkpatch warning fix] Signed-off-by: Sekhar Nori <[email protected]>
- Loading branch information