You've already forked linux-rockchip
mirror of
https://github.com/armbian/linux-rockchip.git
synced 2026-01-06 11:08:10 -08:00
usb: dwc3: gadget: fix deadlock in kick transfer
If kick transfer command fail and the return value isn't
EAGAIN, the current code will issue end transfer command
to stop the active transfer, and only set dep->flags with
DWC3_EP_END_TRANSFER_PENDING if the end transfer command
is done successfully. If the DWC3_EP_END_TRANSFER_PENDING
isn't set, it cleanup the cancelled requests and give the
request back to the gadget layer immediately.
For uvc gadget, the uvc gadget driver hold spinlock and
then call usb_ep_queue() to submit uvc usb request to dwc3
controller. The dwc3 controller may kick transfer for the
request sequentially, if the kick transfer command and
the end transfer command all failed, the dwc3 will give
the request back to the uvc gadget driver via the request
complete function uvc_video_complete(), in this function,
it try to get the spinlock again that lead to deadlock.
This case always happens with the following warning log:
WARNING: CPU: 0 PID: 14450 at drivers/usb/dwc3/gadget.c:1839 __dwc3_gadget_kick_transfer+0x3a0/0x3b0
...
Workqueue: events uvcg_video_pump
...
Call trace:
__dwc3_gadget_kick_transfer+0x3a0/0x3b0
__dwc3_gadget_ep_queue+0x128/0x1f0
dwc3_gadget_ep_queue+0x40/0x6c
usb_ep_queue+0x44/0x100
uvcg_video_pump+0xd0/0x1d4
process_one_work+0x1f4/0x490
worker_thread+0x278/0x4dc
kthread+0x13c/0x344
ret_from_fork+0x10/0x30
Fixes: 0ec00e864a ("UPSTREAM: usb: dwc3: gadget: move cmd_endtransfer to extra function")
Change-Id: I43d455a45d542efcaa9234de60e37277611b3c47
Signed-off-by: William Wu <william.wu@rock-chips.com>
This commit is contained in:
@@ -1851,7 +1851,7 @@ static int __dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool int
|
||||
|
||||
if (!interrupt)
|
||||
dep->flags &= ~DWC3_EP_TRANSFER_STARTED;
|
||||
else if (!ret)
|
||||
else
|
||||
dep->flags |= DWC3_EP_END_TRANSFER_PENDING;
|
||||
|
||||
return ret;
|
||||
@@ -2032,8 +2032,11 @@ static int __dwc3_gadget_start_isoc(struct dwc3_ep *dep)
|
||||
* status, issue END_TRANSFER command and retry on the next XferNotReady
|
||||
* event.
|
||||
*/
|
||||
if (ret == -EAGAIN)
|
||||
if (ret == -EAGAIN) {
|
||||
ret = __dwc3_stop_active_transfer(dep, false, true);
|
||||
if (ret)
|
||||
dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user