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

Commit 09be76b1 authored by Jack Pham's avatar Jack Pham Committed by Ajay Agarwal
Browse files

usb: dwc3: gadget: Clear pending events when stopping controller



Just prior to stopping the controller, we may have issued stop
transfer commands to any endpoints with any pending transfers.
This will result in EP Command Complete events being generated.
However, as per the Databook, the controller will not assert the
halt status bit after clearing the run/stop bit if there are any
pending events in the GEVNTCOUNT(n) registers, so this results
in a timeout error. Fix this by simply clearing GEVNTCOUNT(n)
by reading and writing back the counts.

Change-Id: I2fd0b161b08048072aa7fcea8c636662bcd76bd4
Signed-off-by: default avatarJack Pham <jackp@codeaurora.org>
Signed-off-by: default avatarAjay Agarwal <ajaya@codeaurora.org>
parent c6a57da2
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -845,8 +845,9 @@ struct dwc3_scratchpad_array {
#define DWC3_GSI_EVT_BUF_ALLOC			10
#define DWC3_GSI_EVT_BUF_SETUP			11
#define DWC3_GSI_EVT_BUF_CLEANUP		12
#define DWC3_GSI_EVT_BUF_FREE			13
#define DWC3_CONTROLLER_NOTIFY_CLEAR_DB		14
#define DWC3_GSI_EVT_BUF_CLEAR			13
#define DWC3_GSI_EVT_BUF_FREE			14
#define DWC3_CONTROLLER_NOTIFY_CLEAR_DB		15

#define MAX_INTR_STATS				10

+10 −1
Original line number Diff line number Diff line
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -2023,6 +2023,15 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event,
			dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT((i+1)), 0);
		}
		break;
	case DWC3_GSI_EVT_BUF_CLEAR:
		dev_dbg(mdwc->dev, "DWC3_GSI_EVT_BUF_CLEAR\n");
		for (i = 0; i < mdwc->num_gsi_event_buffers; i++) {
			reg = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT((i+1)));
			reg &= DWC3_GEVNTCOUNT_MASK;
			dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT((i+1)), reg);
			dbg_log_string("remaining EVNTCOUNT(%d)=%d", i+1, reg);
		}
		break;
	case DWC3_GSI_EVT_BUF_FREE:
		dev_dbg(mdwc->dev, "DWC3_GSI_EVT_BUF_FREE\n");
		if (!mdwc->gsi_ev_buff)
+11 −1
Original line number Diff line number Diff line
@@ -2008,7 +2008,7 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
#define DWC3_SOFT_RESET_TIMEOUT		10  /* 10 msec */
static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
{
	u32			reg;
	u32			reg, reg1;
	u32			timeout = 1500;

	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
@@ -2046,6 +2046,16 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
		 */
		dwc3_stop_active_transfers(dwc);

		/*
		 * Clear out any pending events (i.e. End Transfer Command
		 * Complete) before clearing run/stop
		 */
		reg1 = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
		reg1 &= DWC3_GEVNTCOUNT_MASK;
		dbg_log_string("remaining EVNTCOUNT(0)=%d", reg1);
		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), reg1);
		dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_CLEAR, 0);

		reg &= ~DWC3_DCTL_RUN_STOP;

		if (dwc->has_hibernation && !suspend)