| From 4fe4f9fecc36956fd53c8edf96dd0c691ef98ff9 Mon Sep 17 00:00:00 2001 |
| From: Minas Harutyunyan <minas.harutyunyan@synopsys.com> |
| Date: Mon, 10 Dec 2018 18:09:32 +0400 |
| Subject: usb: dwc2: Fix disable all EP's on disconnect |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Minas Harutyunyan <minas.harutyunyan@synopsys.com> |
| |
| commit 4fe4f9fecc36956fd53c8edf96dd0c691ef98ff9 upstream. |
| |
| Disabling all EP's allow to reset EP's to initial state. |
| Introduced new function dwc2_hsotg_ep_disable_lock() which |
| before calling dwc2_hsotg_ep_disable() function acquire |
| hsotg->lock and release on exiting. |
| From dwc2_hsotg_ep_disable() function removed acquiring |
| hsotg->lock. |
| In dwc2_hsotg_core_init_disconnected() function when USB |
| reset interrupt asserted disabling all ep’s by |
| dwc2_hsotg_ep_disable() function. |
| This updates eliminating sparse imbalance warnings. |
| |
| Reverted changes in dwc2_hostg_disconnect() function. |
| Introduced new function dwc2_hsotg_ep_disable_lock(). |
| Changed dwc2_hsotg_ep_ops. Now disable point to |
| dwc2_hsotg_ep_disable_lock() function. |
| In functions dwc2_hsotg_udc_stop() and dwc2_hsotg_suspend() |
| dwc2_hsotg_ep_disable() function replaced by |
| dwc2_hsotg_ep_disable_lock() function. |
| In dwc2_hsotg_ep_disable() function removed acquiring |
| of hsotg->lock. |
| |
| Fixes: dccf1bad4be7 ("usb: dwc2: Disable all EP's on disconnect") |
| Signed-off-by: Minas Harutyunyan <hminas@synopsys.com> |
| Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com> |
| Signed-off-by: Amit Pundir <amit.pundir@linaro.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/usb/dwc2/gadget.c | 41 +++++++++++++++++++++++------------------ |
| 1 file changed, 23 insertions(+), 18 deletions(-) |
| |
| --- a/drivers/usb/dwc2/gadget.c |
| +++ b/drivers/usb/dwc2/gadget.c |
| @@ -3107,8 +3107,6 @@ static void kill_all_requests(struct dwc |
| dwc2_hsotg_txfifo_flush(hsotg, ep->fifo_index); |
| } |
| |
| -static int dwc2_hsotg_ep_disable(struct usb_ep *ep); |
| - |
| /** |
| * dwc2_hsotg_disconnect - disconnect service |
| * @hsotg: The device state. |
| @@ -3130,9 +3128,11 @@ void dwc2_hsotg_disconnect(struct dwc2_h |
| /* all endpoints should be shutdown */ |
| for (ep = 0; ep < hsotg->num_of_eps; ep++) { |
| if (hsotg->eps_in[ep]) |
| - dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); |
| + kill_all_requests(hsotg, hsotg->eps_in[ep], |
| + -ESHUTDOWN); |
| if (hsotg->eps_out[ep]) |
| - dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); |
| + kill_all_requests(hsotg, hsotg->eps_out[ep], |
| + -ESHUTDOWN); |
| } |
| |
| call_gadget(hsotg, disconnect); |
| @@ -3176,6 +3176,7 @@ static void dwc2_hsotg_irq_fifoempty(str |
| GINTSTS_PTXFEMP | \ |
| GINTSTS_RXFLVL) |
| |
| +static int dwc2_hsotg_ep_disable(struct usb_ep *ep); |
| /** |
| * dwc2_hsotg_core_init - issue softreset to the core |
| * @hsotg: The device state |
| @@ -4004,10 +4005,8 @@ static int dwc2_hsotg_ep_disable(struct |
| struct dwc2_hsotg *hsotg = hs_ep->parent; |
| int dir_in = hs_ep->dir_in; |
| int index = hs_ep->index; |
| - unsigned long flags; |
| u32 epctrl_reg; |
| u32 ctrl; |
| - int locked; |
| |
| dev_dbg(hsotg->dev, "%s(ep %p)\n", __func__, ep); |
| |
| @@ -4023,10 +4022,6 @@ static int dwc2_hsotg_ep_disable(struct |
| |
| epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); |
| |
| - locked = spin_is_locked(&hsotg->lock); |
| - if (!locked) |
| - spin_lock_irqsave(&hsotg->lock, flags); |
| - |
| ctrl = dwc2_readl(hsotg, epctrl_reg); |
| |
| if (ctrl & DXEPCTL_EPENA) |
| @@ -4049,12 +4044,22 @@ static int dwc2_hsotg_ep_disable(struct |
| hs_ep->fifo_index = 0; |
| hs_ep->fifo_size = 0; |
| |
| - if (!locked) |
| - spin_unlock_irqrestore(&hsotg->lock, flags); |
| - |
| return 0; |
| } |
| |
| +static int dwc2_hsotg_ep_disable_lock(struct usb_ep *ep) |
| +{ |
| + struct dwc2_hsotg_ep *hs_ep = our_ep(ep); |
| + struct dwc2_hsotg *hsotg = hs_ep->parent; |
| + unsigned long flags; |
| + int ret; |
| + |
| + spin_lock_irqsave(&hsotg->lock, flags); |
| + ret = dwc2_hsotg_ep_disable(ep); |
| + spin_unlock_irqrestore(&hsotg->lock, flags); |
| + return ret; |
| +} |
| + |
| /** |
| * on_list - check request is on the given endpoint |
| * @ep: The endpoint to check. |
| @@ -4202,7 +4207,7 @@ static int dwc2_hsotg_ep_sethalt_lock(st |
| |
| static const struct usb_ep_ops dwc2_hsotg_ep_ops = { |
| .enable = dwc2_hsotg_ep_enable, |
| - .disable = dwc2_hsotg_ep_disable, |
| + .disable = dwc2_hsotg_ep_disable_lock, |
| .alloc_request = dwc2_hsotg_ep_alloc_request, |
| .free_request = dwc2_hsotg_ep_free_request, |
| .queue = dwc2_hsotg_ep_queue_lock, |
| @@ -4342,9 +4347,9 @@ static int dwc2_hsotg_udc_stop(struct us |
| /* all endpoints should be shutdown */ |
| for (ep = 1; ep < hsotg->num_of_eps; ep++) { |
| if (hsotg->eps_in[ep]) |
| - dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); |
| + dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep); |
| if (hsotg->eps_out[ep]) |
| - dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); |
| + dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep); |
| } |
| |
| spin_lock_irqsave(&hsotg->lock, flags); |
| @@ -4792,9 +4797,9 @@ int dwc2_hsotg_suspend(struct dwc2_hsotg |
| |
| for (ep = 0; ep < hsotg->num_of_eps; ep++) { |
| if (hsotg->eps_in[ep]) |
| - dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); |
| + dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep); |
| if (hsotg->eps_out[ep]) |
| - dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); |
| + dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep); |
| } |
| } |
| |