Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 23bafa2f authored by Manu Gautam's avatar Manu Gautam
Browse files

USB: phy-msm-usb: Avoid race b/w sm_work and set_suspend



OTG's set_suspend routine is used by host controller (EHCI)
driver to suspend or resume USB OTG/PHY hardware from its
runtime suspend/resume callbacks. OTG set_suspend routine
uses sm_workqueue to put hardware in LPM (or suspend it).
As there is no synchronization between sm_work and
set_suspend, this results in both racing with each other.
Sometimes with fast back to back set_suspend calls, PHY LPM
state goes out of sync than what requested by host driver.
Fix this by flushing work from set_suspend to complete
event processing by sm_work.

CRs-fixed: 654489
Change-Id: I5e0bfa3bc6c12af23fd26b2496c7ee5b7fc1488e
Signed-off-by: default avatarManu Gautam <mgautam@codeaurora.org>
parent 1e733ca9
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -786,6 +786,9 @@ static int msm_otg_set_suspend(struct usb_phy *phy, int suspend)
	if (aca_enabled())
		return 0;

	pr_debug("%s(%d) in %s state\n", __func__, suspend,
				usb_otg_state_string(phy->state));

	/*
	 * UDC and HCD call usb_phy_set_suspend() to enter/exit LPM
	 * during bus suspend/resume.  Update the relevant state
@@ -801,8 +804,13 @@ static int msm_otg_set_suspend(struct usb_phy *phy, int suspend)
		case OTG_STATE_A_HOST:
			pr_debug("host bus suspend\n");
			clear_bit(A_BUS_REQ, &motg->inputs);
			if (!atomic_read(&motg->in_lpm))
			if (!atomic_read(&motg->in_lpm)) {
				queue_work(system_nrt_wq, &motg->sm_work);
				/* Flush sm_work to avoid it race with
				 * subsequent calls of set_suspend.
				 */
				flush_work(&motg->sm_work);
			}
			break;
		case OTG_STATE_B_PERIPHERAL:
			pr_debug("peripheral bus suspend\n");