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

Commit 7b7e0654 authored by Hemant Kumar's avatar Hemant Kumar
Browse files

usb: dwc3: Disable ep cmd completion events before clearing R/S



Stopping the endpoints (end transfer command) before halting the
controller can generate asynchronous events and can prevent halting
the controller (due to pending events that needs to be acked). As
driver is not taking any action in end transfer command completion,
issue end transfer command without setting IOC(interrupt on complete)
bit to prevent any events generated from command completion. For GSI
endpoints ack the pending events which are posted during end transfer
command and block ringing of GSI doorbell after halting the controller.

Change-Id: I538c12ca91ff095ac6d26a597fd0ed779327a91a
Signed-off-by: default avatarHemant Kumar <hemantk@codeaurora.org>
parent c3c0fff6
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -968,8 +968,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

+9 −0
Original line number Diff line number Diff line
@@ -2022,6 +2022,15 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event,
							evt->buf, evt->dma);
		}
		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_CONTROLLER_NOTIFY_DISABLE_UPDXFER:
		dwc3_msm_dbm_disable_updxfer(dwc, value);
		break;
+68 −1
Original line number Diff line number Diff line
@@ -868,6 +868,42 @@ static void dwc3_stop_active_transfers(struct dwc3 *dwc)
	dbg_log_string("DONE");
}

static void dwc3_stop_active_transfers_to_halt(struct dwc3 *dwc)
{
	u32 epnum;
	struct dwc3_request *req;
	struct dwc3_ep *dep;

	dbg_log_string("START");
	for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
		dep = dwc->eps[epnum];
		if (!dep)
			continue;

		if (!(dep->flags & DWC3_EP_ENABLED))
			continue;

		dwc3_stop_active_transfer_noioc(dwc, dep->number, true);

		/* - giveback all requests to gadget driver */
		while (!list_empty(&dep->started_list)) {
			req = next_request(&dep->started_list);
			if (req)
				dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
		}

		while (!list_empty(&dep->pending_list)) {
			req = next_request(&dep->pending_list);
			if (req)
				dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
		}
	}

	dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_CLEAR, 0);

	dbg_log_string("DONE");
}

/**
 * __dwc3_gadget_ep_disable - disables a hw endpoint
 * @dep: the endpoint to disable
@@ -2138,7 +2174,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
		 * call dwc3_stop_active_transfers() API before stopping USB
		 * device controller.
		 */
		dwc3_stop_active_transfers(dwc);
		dwc3_stop_active_transfers_to_halt(dwc);

		reg &= ~DWC3_DCTL_RUN_STOP;

@@ -2153,6 +2189,9 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
		reg &= DWC3_DSTS_DEVCTRLHLT;
	} while (--timeout && !(!is_on ^ !reg));

	if (!is_on)
		dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_CLEAR_DB, 0);

	if (!timeout) {
		dev_err(dwc->dev, "failed to %s controller\n",
				is_on ? "start" : "stop");
@@ -3095,6 +3134,34 @@ void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
			dep->name, dep->number, ret);
}

void dwc3_stop_active_transfer_noioc(struct dwc3 *dwc, u32 epnum, bool force)
{
	struct dwc3_ep *dep;
	struct dwc3_gadget_ep_cmd_params params;
	u32 cmd;
	int ret;

	dep = dwc->eps[epnum];

	if (!dep->resource_index)
		return;

	if (dep->endpoint.endless)
		dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER,
								dep->number);

	cmd = DWC3_DEPCMD_ENDTRANSFER;
	cmd |= force ? DWC3_DEPCMD_HIPRI_FORCERM : 0;
	cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);
	memset(&params, 0, sizeof(params));
	ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
	WARN_ON_ONCE(ret);
	dep->resource_index = 0;

	dbg_log_string("%s(%d): endxfer ret:%d)",
			dep->name, dep->number, ret);
}

static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
{
	u32 epnum;
+1 −0
Original line number Diff line number Diff line
@@ -111,6 +111,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
		gfp_t gfp_flags);
int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol);
void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force);
void dwc3_stop_active_transfer_noioc(struct dwc3 *dwc, u32 epnum, bool force);
void dwc3_ep_inc_enq(struct dwc3_ep *dep);
void dwc3_ep_inc_deq(struct dwc3_ep *dep);