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

Commit 863d575e authored by Mayank Rana's avatar Mayank Rana Committed by Ajay Agarwal
Browse files

dwc3: gadget: Don't queue USB request if pull up is getting disable



There is possible race as below:
a. pull up disable vs ep_queue() API
b. pull up disable vs kick transfer from completion context to queue
next request

pull up disable sends END transfer command to per endpoint, and give
back started request and pending request back to function driver.
dwc3_gadget_giveback() API does release spinlock which may allow
ep_queue() or completion handling to queue next request. This results
into TRB pending without invoking end transfer command, whereas request
is being given back to function driver and being freed. Hence on setting
next pull up enable, USB controller accesses previous stale TRB causing
unmapped page fault. Fix this issue by checking pull up disable or not
while handling ep_queue() or kicking any new transfer from other
transfer completion context.

Change-Id: I391aed05cbfe183cd3e2fe2f1aa335e4fd9ec37c
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
Signed-off-by: default avatarAjay Agarwal <ajaya@codeaurora.org>
parent 15d09a3c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -240,7 +240,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
	u32				reg;

	spin_lock_irqsave(&dwc->lock, flags);
	if (!dep->endpoint.desc) {
	if (!dep->endpoint.desc || !dwc->pullups_connected) {
		dwc3_trace(trace_dwc3_ep0,
				"trying to queue request %pK to disabled %s",
				request, dep->name);
+7 −7
Original line number Diff line number Diff line
@@ -1291,7 +1291,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
	struct dwc3		*dwc = dep->dwc;
	int			ret;

	if (!dep->endpoint.desc) {
	if (!dep->endpoint.desc || !dwc->pullups_connected) {
		dwc3_trace(trace_dwc3_gadget,
				"trying to queue request %pK to disabled %s",
				&req->request, dep->endpoint.name);
@@ -2032,6 +2032,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
	} else {
		dbg_event(0xFF, "Pullup_disable", is_on);
		dwc3_gadget_disable_irq(dwc);
		dwc->pullups_connected = false;
		__dwc3_gadget_ep_disable(dwc->eps[0]);
		__dwc3_gadget_ep_disable(dwc->eps[1]);

@@ -2047,8 +2048,6 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)

		if (dwc->has_hibernation && !suspend)
			reg &= ~DWC3_DCTL_KEEP_CONNECT;

		dwc->pullups_connected = false;
	}

	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
@@ -2804,11 +2803,12 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
	}

	/*
	 * Our endpoint might get disabled by another thread during
	 * dwc3_gadget_giveback(). If that happens, we're just gonna return 1
	 * early on so DWC3_EP_BUSY flag gets cleared
	 * Our endpoint might get disabled by another thread or stop
	 * active transfer is invoked with pull up disable during
	 * dwc3_gadget_giveback(). If that happens, we're just gonna
	 * return 1 early on so DWC3_EP_BUSY flag gets cleared.
	 */
	if (!dep->endpoint.desc)
	if (!dep->endpoint.desc || !dwc->pullups_connected)
		return;

	if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {