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

Commit 0c8d6ae7 authored by Tarun Gupta's avatar Tarun Gupta
Browse files

usb: dwc3: gadget: Avoid unclocked access due to pm_runtime_get failure



If remote wakeup request is received during system resume where
resume_early is still processing, pm_runtime_get_sync returns -EACCES error
as pm_runtime framework is disabled between late_suspend and early_resume.
Due to failure of this API controller did not exit LPM. This leads to
unclocked access of registers as part of remote wakeup processing causing
target to crash.

Fix this by checking for return value of pm_runtime_get_sync, and queuing
dwc3_gadget_wakeup_work again with intermediate delay of 100ms for maximum
of 20 times.

Change-Id: I8e2215ef9ee708e86356622e85fd2f23a18f7944
Signed-off-by: default avatarTarun Gupta <tarung@codeaurora.org>
parent d4bc64ea
Loading
Loading
Loading
Loading
+25 −1
Original line number Diff line number Diff line
@@ -1603,14 +1603,38 @@ static int dwc3_gadget_get_frame(struct usb_gadget *g)
	return DWC3_DSTS_SOFFN(reg);
}

#define DWC3_PM_RESUME_RETRIES		20    /* Max Number of retries */
#define DWC3_PM_RESUME_DELAY		100   /* 100 msec */

static void dwc3_gadget_wakeup_work(struct work_struct *w)
{
	struct dwc3		*dwc;
	int			ret;
	static int		retry_count;

	dwc = container_of(w, struct dwc3, wakeup_work);

	pm_runtime_get_sync(dwc->dev);
	ret = pm_runtime_get_sync(dwc->dev);
	if (ret) {
		/* pm_runtime_get_sync returns -EACCES error between
		 * late_suspend and early_resume, wait for system resume to
		 * finish and queue work again
		 */
		pr_debug("PM runtime get sync failed, ret %d\n", ret);
		if (ret == -EACCES) {
			pm_runtime_put_noidle(dwc->dev);
			if (retry_count == DWC3_PM_RESUME_RETRIES) {
				retry_count = 0;
				pr_err("pm_runtime_get_sync timed out\n");
				return;
			}
			msleep(DWC3_PM_RESUME_DELAY);
			retry_count++;
			schedule_work(&dwc->wakeup_work);
			return;
		}
	}
	retry_count = 0;
	dbg_event(0xFF, "Gdgwake gsyn",
		atomic_read(&dwc->dev->power.usage_count));