Browse Source

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: John Youn <johnyoun@synopsys.com>
Signed-off-by: Gregory Herrero <gregory.herrero@intel.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Gregory Herrero 10 years ago
parent
commit
3eb42df3eb
1 changed files with 8 additions and 3 deletions
  1. 8 3
      drivers/usb/dwc2/core_intr.c

+ 8 - 3
drivers/usb/dwc2/core_intr.c

@@ -439,6 +439,12 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
 			if (!IS_ERR_OR_NULL(hsotg->uphy))
 				usb_phy_set_suspend(hsotg->uphy, true);
 skip_power_saving:
+			/*
+			 * Change to L2 (suspend) state before releasing
+			 * spinlock
+			 */
+			hsotg->lx_state = DWC2_L2;
+
 			/* Call gadget suspend callback */
 			call_gadget(hsotg, suspend);
 		}
@@ -446,6 +452,8 @@ skip_power_saving:
 		if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) {
 			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 */
 			spin_unlock(&hsotg->lock);
 			dwc2_hcd_start(hsotg);
@@ -454,9 +462,6 @@ skip_power_saving:
 		}
 	}
 
-	/* Change to L2 (suspend) state */
-	hsotg->lx_state = DWC2_L2;
-
 clear_int:
 	/* Clear interrupt */
 	writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);