USB: dwc3-msm: Protect enabling phy irqs with mutex
Currently driver is enabling hsphy_irq and ssphy_irq at the end
of dwc3_msm_suspend() without any spinlock/mutex protection. But
if it happens that hsphy_irq or ssphy_irq gets fired right after
enablement of irqs, there is a chance that we might see warnings
related to unbalanced irq enable. This could happen due to flag
is not yet set to indicate phy irqs enabled in suspend(). This
might cause phy irq left enabled after resume and could cause
crash due to unclocked access in host mode. Fix the unbalance irq
enable by having mutex protection and also extend mutex protection
for dwc3_msm_suspend() and dwc3_msm_resume().
Change-Id: I8c2d26f82feb235add64305c1d0e5b686993e9e9
Signed-off-by: Vijayavardhan Vennapusa <vvreddy@codeaurora.org>
Signed-off-by: Mayank Rana <mrana@codeaurora.org>
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index d0fc511..0801f9f 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -266,6 +266,7 @@ struct dwc3_msm {
struct pm_qos_request pm_qos_req_dma;
struct delayed_work perf_vote_work;
struct delayed_work sdp_check;
+ struct mutex suspend_resume_mutex;
};
#define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */
@@ -2157,8 +2158,10 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
struct dwc3_event_buffer *evt;
struct usb_irq *uirq;
+ mutex_lock(&mdwc->suspend_resume_mutex);
if (atomic_read(&dwc->in_lpm)) {
dev_dbg(mdwc->dev, "%s: Already suspended\n", __func__);
+ mutex_unlock(&mdwc->suspend_resume_mutex);
return 0;
}
@@ -2171,6 +2174,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
dev_dbg(mdwc->dev,
"%s: %d device events pending, abort suspend\n",
__func__, evt->count / 4);
+ mutex_unlock(&mdwc->suspend_resume_mutex);
return -EBUSY;
}
}
@@ -2189,6 +2193,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
dev_dbg(mdwc->dev,
"%s: cable disconnected while not in idle otg state\n",
__func__);
+ mutex_unlock(&mdwc->suspend_resume_mutex);
return -EBUSY;
}
@@ -2202,12 +2207,15 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
pr_err("%s(): Trying to go in LPM with state:%d\n",
__func__, dwc->gadget.state);
pr_err("%s(): LPM is not performed.\n", __func__);
+ mutex_unlock(&mdwc->suspend_resume_mutex);
return -EBUSY;
}
ret = dwc3_msm_prepare_suspend(mdwc);
- if (ret)
+ if (ret) {
+ mutex_unlock(&mdwc->suspend_resume_mutex);
return ret;
+ }
/* Disable core irq */
if (dwc->irq)
@@ -2315,6 +2323,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
}
dev_info(mdwc->dev, "DWC3 in low power mode\n");
+ mutex_unlock(&mdwc->suspend_resume_mutex);
return 0;
}
@@ -2327,8 +2336,10 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc)
dev_dbg(mdwc->dev, "%s: exiting lpm\n", __func__);
+ mutex_lock(&mdwc->suspend_resume_mutex);
if (!atomic_read(&dwc->in_lpm)) {
dev_dbg(mdwc->dev, "%s: Already resumed\n", __func__);
+ mutex_unlock(&mdwc->suspend_resume_mutex);
return 0;
}
@@ -2479,6 +2490,8 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc)
msecs_to_jiffies(1000 * PM_QOS_SAMPLE_SEC));
dbg_event(0xFF, "Ctl Res", atomic_read(&dwc->in_lpm));
+ mutex_unlock(&mdwc->suspend_resume_mutex);
+
return 0;
}
@@ -3422,6 +3435,7 @@ static int dwc3_msm_probe(struct platform_device *pdev)
POWER_SUPPLY_PROP_PRESENT, &pval);
}
+ mutex_init(&mdwc->suspend_resume_mutex);
/* Update initial VBUS/ID state from extcon */
if (mdwc->extcon_vbus && extcon_get_state(mdwc->extcon_vbus,
EXTCON_USB))