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

Commit 7d8c659c authored by Ido Shayevitz's avatar Ido Shayevitz
Browse files

usb: dwc3-msm: Fix LPM race condition on cable disconnect



In some cases, the pm_runtime_suspend may be called by the usb_bam.c
when there is pending lpm flag set after waiting IPA resource manager
to release the consumer resource. However, if this is done when the
usb cable was disconnected and otg state has not yet changed to IDLE,
it can lead to a crash due to access to a core register while in LPM.

The reason is that when usb cable was disconnected and otg state
has not yet changed to IDLE, it means that the otg state machine
is still running or about to run and we race against it. When the
otg state machine will complete the transition to IDLE state, it
will invoke the LPM separately. The specific crash was in the
function msm_ssusb_qmp_enable_autonomous(), which is invoked
up the SW sequence by the otg state machine function which does
start_peripheral(0).

Therefore, if we catch such a case, fix it by cancel the LPM for now,
and the otg state machine will go to LPM later.

CRs-Fixed: 687668
Change-Id: Iaf2d8bd3156245c83a1b9bab4b9d62c82f16a7c2
Signed-off-by: default avatarIdo Shayevitz <idos@codeaurora.org>
parent 110f3df6
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -1596,6 +1596,23 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
		return -EBUSY;
	}

	if (!cable_connected && mdwc->otg_xceiv &&
		mdwc->otg_xceiv->state == OTG_STATE_B_PERIPHERAL) {
		/*
		 * In some cases, the pm_runtime_suspend may be called by
		 * usb_bam when there is pending lpm flag. However, if this is
		 * done when cable was disconnected and otg state has not
		 * yet changed to IDLE, then it means OTG state machine
		 * is running and we race against it. So cancel LPM for now,
		 * and OTG state machine will go for LPM later, after completing
		 * transition to IDLE state.
		*/
		dev_dbg(mdwc->dev,
			"%s: cable disconnected while not in idle otg state\n",
			__func__);
		return -EBUSY;
	}

	host_ss_active = dwc3_msm_read_reg(mdwc->base, USB3_PORTSC) & PORT_PE;
	if (mdwc->hs_phy_irq)
		disable_irq(mdwc->hs_phy_irq);