From 8d8d2bea771e1ecef2ea1cb136088e72053c9067 Mon Sep 17 00:00:00 2001 From: Tarun Gupta Date: Wed, 10 Jun 2015 19:28:49 +0530 Subject: usb: dwc3: gadget: Avoid unclocked access due to pm_runtime_get failure If remote wakeup request is received during system resume where resume_early is still processing, pm_runtime_get_sync returns -EACCES error as pm_runtime framework is disabled between late_suspend and early_resume. Due to failure of this API controller did not exit LPM. This leads to unclocked access of registers as part of remote wakeup processing causing target to crash. Fix this by checking for return value of pm_runtime_get_sync, and queuing dwc3_gadget_wakeup_work again with intermediate delay of 100ms for maximum of 20 times. Change-Id: I8e2215ef9ee708e86356622e85fd2f23a18f7944 Signed-off-by: Tarun Gupta --- drivers/usb/dwc3/gadget.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index c615d5917867..63f90080cb49 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1505,14 +1505,38 @@ static int dwc3_gadget_get_frame(struct usb_gadget *g) return DWC3_DSTS_SOFFN(reg); } +#define DWC3_PM_RESUME_RETRIES 20 /* Max Number of retries */ +#define DWC3_PM_RESUME_DELAY 100 /* 100 msec */ + static void dwc3_gadget_wakeup_work(struct work_struct *w) { struct dwc3 *dwc; int ret; + static int retry_count; dwc = container_of(w, struct dwc3, wakeup_work); - pm_runtime_get_sync(dwc->dev); + ret = pm_runtime_get_sync(dwc->dev); + if (ret) { + /* pm_runtime_get_sync returns -EACCES error between + * late_suspend and early_resume, wait for system resume to + * finish and queue work again + */ + pr_debug("PM runtime get sync failed, ret %d\n", ret); + if (ret == -EACCES) { + pm_runtime_put_noidle(dwc->dev); + if (retry_count == DWC3_PM_RESUME_RETRIES) { + retry_count = 0; + pr_err("pm_runtime_get_sync timed out\n"); + return; + } + msleep(DWC3_PM_RESUME_DELAY); + retry_count++; + schedule_work(&dwc->wakeup_work); + return; + } + } + retry_count = 0; dbg_event(0xFF, "Gdgwake gsyn", atomic_read(&dwc->dev->power.usage_count)); -- cgit v1.2.3