summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJack Pham <jackp@codeaurora.org>2016-01-29 11:46:05 -0800
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 11:06:41 -0700
commitb0b1bb59407262e425fcb5a95f7df72a156c99ab (patch)
tree43567fd34e95e182ce61bbf59a84bd16c40e0349
parentc6d80a92b79d6b50129a27e8747c5a490da367e3 (diff)
usb: dwc3: gadget: Resolve recursive spinlock during remote wakeup
When a USB function wishes to send new data during USB suspend state, it needs to issue USB remote wakeup and send a function wakeup notification after then. This scenario leads to recursive spin locking inside the _usb_func_wakeup() function, because this function gets called recursively. This function issues remote wakeup, which internally calls the resume interrupt callback, which calls the _usb_func_wakeup() function again. This issue is resolved by performing the remote wakeup in a deferred work context, and this splits the recursion loop. CRs-fixed: 700667 Change-Id: I59c8efde098781587d29f08cd60e4aa3521949d8 Signed-off-by: Danny Segal <dsegal@codeaurora.org>
-rw-r--r--drivers/usb/dwc3/gadget.c28
1 files changed, 7 insertions, 21 deletions
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 12969d2fa688..d841f09ff378 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1263,27 +1263,9 @@ out:
static int dwc3_gadget_wakeup(struct usb_gadget *g)
{
struct dwc3 *dwc = gadget_to_dwc(g);
- unsigned long flags;
- int ret = 0;
- spin_lock_irqsave(&dwc->lock, flags);
-
- if (atomic_read(&dwc->in_lpm)) {
- schedule_work(&dwc->wakeup_work);
- pr_debug("Core is in low-power mode. Scheduling wakeup work.\n");
- ret = -EBUSY;
- } else {
- pr_debug("Core is active. Initiating remote wakeup.\n");
- ret = dwc3_gadget_wakeup_int(dwc);
- if (ret)
- pr_err("Remote wakeup failed. ret = %d\n", ret);
- else
- pr_debug("Remote wake up succeeded.\n");
- }
-
- spin_unlock_irqrestore(&dwc->lock, flags);
-
- return ret;
+ schedule_work(&dwc->wakeup_work);
+ return 0;
}
static inline enum dwc3_link_state dwc3_get_link_state(struct dwc3 *dwc)
@@ -1618,7 +1600,6 @@ static int dwc3_gadget_wakeup_int(struct dwc3 *dwc)
if (!link_recover_only)
dwc3_gadget_wakeup_interrupt(dwc);
out:
-
return ret;
}
@@ -1639,6 +1620,11 @@ static int dwc_gadget_func_wakeup(struct usb_gadget *g, int interface_id)
ret = dwc3_send_gadget_generic_command(dwc,
DWC3_DGCMD_XMIT_FUNCTION, interface_id);
+ if (ret)
+ pr_err("Function wakeup HW command failed.\n");
+ else
+ pr_debug("Function wakeup HW command succeeded.\n");
+
return ret;
}