usb: dwc3: gadget: Avoid starting DWC3 gadget during UDC unbind
Subsystems (2)
PATCH 1/1 usb: dwc3: gadget: Avoid starting DWC3 gadget during UDC unbind
There is a race present where the DWC3 runtime resume runs in parallel to the UDC unbind sequence. This will eventually lead to a possible scenario where we are enabling the run/stop bit, without a valid composition defined.
Thread#1 (handling UDC unbind):usb_gadget_remove_driver()
-->usb_gadget_disconnect()
-->dwc3_gadget_pullup(0)
--> continue UDC unbind sequence
-->Thread#2 is running in parallel here
Thread#2 (handing next cable connect)__dwc3_set_mode()
-->pm_runtime_get_sync()
-->dwc3_gadget_resume()
-->dwc->gadget_driver is NOT NULL yet
-->dwc3_gadget_run_stop(1)
--> _dwc3gadget_start()...
Fix this by tracking the pullup disable routine, and avoiding resuming of the DWC3 gadget. Once the UDC is re-binded, that will trigger the pullup enable routine, which would handle enabling the DWC3 gadget.
--- drivers/usb/dwc3/core.h | 2 ++ drivers/usb/dwc3/gadget.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-)
drivers/usb/dwc3/core.h +2 -0
@@ -1032,6 +1032,7 @@ struct dwc3_scratchpad_array {* @tx_fifo_resize_max_num: max number of fifos allocated during txfifo resize * @hsphy_interface: "utmi" or "ulpi" * @connected: true when we're connected to a host, false otherwise +* @softconnect: true when gadget connect is called, false when disconnect runs * @delayed_status: true when gadget driver asks for delayed status * @ep0_bounced: true when we used bounce buffer * @ep0_expect_in: true when we expect a DATA IN transfer
@@ -1252,6 +1253,7 @@ struct dwc3 {const char *hsphy_interface; unsigned connected:1; + unsigned softconnect:1; unsigned delayed_status:1; unsigned ep0_bounced:1; unsigned ep0_expect_in:1;
drivers/usb/dwc3/gadget.c +2 -2
@@ -2418,7 +2418,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)int ret; is_on = !!is_on; - + dwc->softconnect = is_on;/* * Per databook, when we want to stop the gadget, if a control transfer * is still in process, complete it and get the core into setup phase.
@@ -4352,7 +4352,7 @@ int dwc3_gadget_resume(struct dwc3 *dwc) {int ret; -if (!dwc->gadget_driver) +if (!dwc->gadget_driver || !dwc->softconnect)return 0 ; ret =__dwc3_gadget_start (dwc);
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Hi,
Quoted 19 lines · Wesley Cheng
There is a race present where the DWC3 runtime resume runs in parallel to the UDC unbind sequence. This will eventually lead to a possible scenario where we are enabling the run/stop bit, without a valid composition defined.
Thread#1 (handling UDC unbind):
usb_gadget_remove_driver()
-->usb_gadget_disconnect()
-->dwc3_gadget_pullup(0)
--> continue UDC unbind sequence
-->Thread#2 is running in parallel hereThread#2 (handing next cable connect)
__dwc3_set_mode()
-->pm_runtime_get_sync()-->dwc3_gadget_resume() -->dwc->gadget_driver is NOT NULL yet -->dwc3_gadget_run_stop(1) --> _dwc3gadget_start()
Quoted 7 lines
...
Fix this by tracking the pullup disable routine, and avoiding resuming of the DWC3 gadget. Once the UDC is re-binded, that will trigger the pullup enable routine, which would handle enabling the DWC3 gadget.
Signed-off-by Wesley Cheng <[email protected]>
This looks okay to me, but needs to be tested by a few folks ;-)
Signature · 1 line
balbi
Hi,
Quoted 31 lines · Felipe Balbi
Hi,
Quoted 26 lines · Wesley Cheng
There is a race present where the DWC3 runtime resume runs in parallel to the UDC unbind sequence. This will eventually lead to a possible scenario where we are enabling the run/stop bit, without a valid composition defined.
Thread#1 (handling UDC unbind):
usb_gadget_remove_driver()
-->usb_gadget_disconnect()
-->dwc3_gadget_pullup(0)
--> continue UDC unbind sequence
-->Thread#2 is running in parallel hereThread#2 (handing next cable connect)
__dwc3_set_mode()
-->pm_runtime_get_sync()-->dwc3_gadget_resume() -->dwc->gadget_driver is NOT NULL yet -->dwc3_gadget_run_stop(1) --> _dwc3gadget_start()...
Fix this by tracking the pullup disable routine, and avoiding resuming of the DWC3 gadget. Once the UDC is re-binded, that will trigger the pullup enable routine, which would handle enabling the DWC3 gadget.
Signed-off-by Wesley Cheng <[email protected]>
Thanks, Felipe!
Quoted 5 lines
This looks okay to me, but needs to be tested by a few folks ;-)
Acked-by Felipe Balbi <[email protected]>
Yes, would be good to get some functions using usb_gadget_activate/deactivate(). It should be OK for those situations as well, but just to make sure :)
Thanks
Wesley Cheng
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Quoted 38 lines · Wesley Cheng
Hi,
Quoted 31 lines · Felipe Balbi
Hi,
Quoted 26 lines · Wesley Cheng
There is a race present where the DWC3 runtime resume runs in parallel to the UDC unbind sequence. This will eventually lead to a possible scenario where we are enabling the run/stop bit, without a valid composition defined.
Thread#1 (handling UDC unbind):
usb_gadget_remove_driver()
-->usb_gadget_disconnect()
-->dwc3_gadget_pullup(0)
--> continue UDC unbind sequence
-->Thread#2 is running in parallel hereThread#2 (handing next cable connect)
__dwc3_set_mode()
-->pm_runtime_get_sync()-->dwc3_gadget_resume() -->dwc->gadget_driver is NOT NULL yet -->dwc3_gadget_run_stop(1) --> _dwc3gadget_start()...
Fix this by tracking the pullup disable routine, and avoiding resuming of the DWC3 gadget. Once the UDC is re-binded, that will trigger the pullup enable routine, which would handle enabling the DWC3 gadget.
Signed-off-by Wesley Cheng <[email protected]>Thanks, Felipe!
Quoted 1 line
Quoted 7 lines
Quoted 4 lines
This looks okay to me, but needs to be tested by a few folks ;-)
Acked-by Felipe Balbi <[email protected]>Yes, would be good to get some functions using usb_gadget_activate/deactivate(). It should be OK for those situations as well, but just to make sure :)
IIRC, the UVC function relies on those. You could give it a shot ;-)
Signature · 1 line
balbi