usb: dwc3: gadget: delay clearing run/stop when setup just arrived
There still exists a small window in which dwc3_gadget_pullup()
is called while a new control transfer setup packet had newly
arrived. In the case where it needs to be delegated to the gadget
driver, it releases dwc3->lock and allows pullup() to proceed to
call run_stop() to attempt to stop the controller. The lock will
get released again when calling dwc3_stop_active_transfers()
which allows the gadget driver to meanwhile call ep_queue() for
a three-stage control transfer and sneak in a Start Transfer. By
the time the DCTL register is written, the controller will fail
to halt due to having an outstanding transfer in progress.
CPU0 CPU1
...dwc3->lock held...
dwc3_ep0_inspect_setup() dwc3_gadget_pullup()
dwc3_ep0_delegate_req() spin_lock_irq_save()
spin_unlock() ... unblocked
composite_setup() dwc3_gadget_run_stop()
usb_ep_queue() dwc3_stop_active_transfers()
dwc3_gadget_ep0_queue() dwc3_gadget_remove_requests()
spin_lock_irqsave() dwc3_gadget_giveback()
... unblocked spin_unlock()
__dwc3_ep0_do_control_data() spin_lock()
issues Start Transfer
spin_unlock_irqrestore() ... unblocked
spin_lock() clear DCTL_RUN_STOP
... wait for DSTS_DEVCTRLHLT
time out
This change attempts to fix the issue by additionally checking
the dwc->ep0_next_event state in dwc3_gadget_pullup() to catch
the case when a SETUP packet had just been received and handled
by dwc3_ep0_inspect_setup but is still waiting to proceed to
either a DATA or STATUS stage. This allows pullup() to wait for
completion of the transfer before moving on to clear run/stop.
Change-Id: Ib2da3c86213ade1a61fb82f95a1f7c9534d9df3f
Signed-off-by:
Jack Pham <jackp@codeaurora.org>
Loading
Please register or sign in to comment