BACKPORT: FROMGIT: 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. Acked-by: Felipe Balbi <balbi@kernel.org> Signed-off-by: Wesley Cheng <wcheng@codeaurora.org> Link: https://lore.kernel.org/r/20210917021852.2037-1-wcheng@codeaurora.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Bug: 200287549 (cherry picked from commit 8217f07a50236779880f13e87f99224cd9117f83 https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing) [wcheng: Fixed KMI breakage by moving softconnect to a new parent structure] Change-Id: I9554933826710cc68136b08176290584f9ab74df Signed-off-by: Wesley Cheng <wcheng@codeaurora.org>
This commit is contained in:
parent
0671bafa24
commit
bb13ff0598
@ -1530,15 +1530,17 @@ static int dwc3_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res, dwc_res;
|
||||
struct dwc3_vendor *vdwc;
|
||||
struct dwc3 *dwc;
|
||||
|
||||
int ret;
|
||||
|
||||
void __iomem *regs;
|
||||
|
||||
dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
|
||||
if (!dwc)
|
||||
vdwc = devm_kzalloc(dev, sizeof(*vdwc), GFP_KERNEL);
|
||||
if (!vdwc)
|
||||
return -ENOMEM;
|
||||
dwc = &vdwc->dwc;
|
||||
|
||||
dwc->dev = dev;
|
||||
|
||||
|
@ -1319,6 +1319,16 @@ struct dwc3 {
|
||||
ANDROID_KABI_RESERVE(4);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dwc3_vendor - contains parameters without modifying the format of DWC3 core
|
||||
* @dwc: contains dwc3 core reference
|
||||
* @softconnect: true when gadget connect is called, false when disconnect runs
|
||||
*/
|
||||
struct dwc3_vendor {
|
||||
struct dwc3 dwc;
|
||||
unsigned softconnect:1;
|
||||
};
|
||||
|
||||
#define INCRX_BURST_MODE 0
|
||||
#define INCRX_UNDEF_LENGTH_BURST_MODE 1
|
||||
|
||||
|
@ -2411,10 +2411,12 @@ static int __dwc3_gadget_start(struct dwc3 *dwc);
|
||||
static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
|
||||
{
|
||||
struct dwc3 *dwc = gadget_to_dwc(g);
|
||||
struct dwc3_vendor *vdwc = container_of(dwc, struct dwc3_vendor, dwc);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
is_on = !!is_on;
|
||||
vdwc->softconnect = is_on;
|
||||
|
||||
/*
|
||||
* Per databook, when we want to stop the gadget, if a control transfer
|
||||
@ -4362,9 +4364,10 @@ int dwc3_gadget_suspend(struct dwc3 *dwc)
|
||||
|
||||
int dwc3_gadget_resume(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_vendor *vdwc = container_of(dwc, struct dwc3_vendor, dwc);
|
||||
int ret;
|
||||
|
||||
if (!dwc->gadget_driver)
|
||||
if (!dwc->gadget_driver || !vdwc->softconnect)
|
||||
return 0;
|
||||
|
||||
ret = __dwc3_gadget_start(dwc);
|
||||
|
Loading…
Reference in New Issue
Block a user