Commit 3eb42df3 authored by Gregory Herrero's avatar Gregory Herrero Committed by Felipe Balbi

usb: dwc2: controller must update lx_state before releasing lock

During suspend, there could a race condition between ep_queue and
suspend interrupt if lx_state is updated after releasing spinlock in
call_gadget(hsotg, suspend).
Acked-by: default avatarJohn Youn <johnyoun@synopsys.com>
Signed-off-by: default avatarGregory Herrero <gregory.herrero@intel.com>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent f81f46e1
...@@ -439,6 +439,12 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) ...@@ -439,6 +439,12 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
if (!IS_ERR_OR_NULL(hsotg->uphy)) if (!IS_ERR_OR_NULL(hsotg->uphy))
usb_phy_set_suspend(hsotg->uphy, true); usb_phy_set_suspend(hsotg->uphy, true);
skip_power_saving: skip_power_saving:
/*
* Change to L2 (suspend) state before releasing
* spinlock
*/
hsotg->lx_state = DWC2_L2;
/* Call gadget suspend callback */ /* Call gadget suspend callback */
call_gadget(hsotg, suspend); call_gadget(hsotg, suspend);
} }
...@@ -446,6 +452,8 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) ...@@ -446,6 +452,8 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) { if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) {
dev_dbg(hsotg->dev, "a_peripheral->a_host\n"); dev_dbg(hsotg->dev, "a_peripheral->a_host\n");
/* Change to L2 (suspend) state */
hsotg->lx_state = DWC2_L2;
/* Clear the a_peripheral flag, back to a_host */ /* Clear the a_peripheral flag, back to a_host */
spin_unlock(&hsotg->lock); spin_unlock(&hsotg->lock);
dwc2_hcd_start(hsotg); dwc2_hcd_start(hsotg);
...@@ -454,9 +462,6 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) ...@@ -454,9 +462,6 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
} }
} }
/* Change to L2 (suspend) state */
hsotg->lx_state = DWC2_L2;
clear_int: clear_int:
/* Clear interrupt */ /* Clear interrupt */
writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS); writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment