ANDROID: usb: dwc3: Fix gadget mis-merge from upstream The change https://r.android.com/c/2578319 was merged before it landed in the upstream 5.15 LTS kernel which resulted in merge conflicts when 5.15.128 was merged (https://r.android.com/2729653) that were not properly resolved. Later when 5.15.149 was merged (https://r.android.com/3044992), which had the backported change, the merge conflicts again were not properly resolved. As it stands today, the upstream change: commit 39674be56fba1cd3a03bf4617f523a35f85fd2c1 is partially reverted. Fix this to bring back the proper functionality. Bug: 364171072 Change-Id: I0957229f29ef6715dc3e88943e015e713a91ed71 Signed-off-by: Will McVicker <willmcvicker@google.com>
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index e22db0a..b57a761 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c
@@ -2524,6 +2524,8 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on) return 0; } +static void dwc3_gadget_disable_irq(struct dwc3 *dwc); +static void __dwc3_gadget_stop(struct dwc3 *dwc); static int __dwc3_gadget_start(struct dwc3 *dwc); static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc) @@ -2583,7 +2585,19 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc) * remaining event generated by the controller while polling for * DSTS.DEVCTLHLT. */ - return dwc3_gadget_run_stop(dwc, false); + ret = dwc3_gadget_run_stop(dwc, false); + + /* + * Stop the gadget after controller is halted, so that if needed, the + * events to update EP0 state can still occur while the run/stop + * routine polls for the halted state. DEVTEN is cleared as part of + * gadget stop. + */ + spin_lock_irqsave(&dwc->lock, flags); + __dwc3_gadget_stop(dwc); + spin_unlock_irqrestore(&dwc->lock, flags); + + return ret; } static int dwc3_gadget_soft_connect(struct dwc3 *dwc) @@ -2673,6 +2687,12 @@ static void dwc3_gadget_enable_irq(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_DEVTEN, reg); } +static void dwc3_gadget_disable_irq(struct dwc3 *dwc) +{ + /* mask all interrupts */ + dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00); +} + static irqreturn_t dwc3_interrupt(int irq, void *_dwc); static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc); @@ -2823,6 +2843,13 @@ static int dwc3_gadget_start(struct usb_gadget *g, return 0; } +static void __dwc3_gadget_stop(struct dwc3 *dwc) +{ + dwc3_gadget_disable_irq(dwc); + __dwc3_gadget_ep_disable(dwc->eps[0]); + __dwc3_gadget_ep_disable(dwc->eps[1]); +} + static int dwc3_gadget_stop(struct usb_gadget *g) { struct dwc3 *dwc = gadget_to_dwc(g);