From ad8d260c33a20f195477436ab74ab59a28d772fe Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Thu, 23 Jul 2020 12:17:30 -0700 Subject: [PATCH] usb: dwc3: gadget: Check controller status with endpoint enable/disable Some USB function driver (e.g. mass storage) performs USB endpoint enable and disable functionality from worker thread context instead of composite/ controller work context. This may result into endpoint enable/disable racing against USB controller low power mode functionality with USB cable disconnect. This race may result into unclock register access. Hence fix this issue by checking USB controller status and perform resume/autosuspend with endpoint disable whereas return -EINVAL with endpoint enable if USB controller is suspended (in low power mode). Change-Id: I76cd75fc90b52ceefe099f48be6c880c04136301 Signed-off-by: Mayank Rana --- drivers/usb/dwc3/gadget.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 9f11cd633469..ff11e0529b84 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -914,6 +914,12 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep, dep->name)) return 0; + if (pm_runtime_suspended(dwc->sysdev)) { + dev_err(dwc->dev, "fail ep_enable %s device is into LPM\n", + dep->name); + return -EINVAL; + } + spin_lock_irqsave(&dwc->lock, flags); ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT); dbg_event(dep->number, "ENABLE", ret); @@ -942,10 +948,13 @@ static int dwc3_gadget_ep_disable(struct usb_ep *ep) dep->name)) return 0; + pm_runtime_get_sync(dwc->dev); spin_lock_irqsave(&dwc->lock, flags); ret = __dwc3_gadget_ep_disable(dep); dbg_event(dep->number, "DISABLE", ret); spin_unlock_irqrestore(&dwc->lock, flags); + pm_runtime_mark_last_busy(dwc->dev); + pm_runtime_put_sync_autosuspend(dwc->dev); return ret; }