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

Commit 245d7605 authored by Thinh Nguyen's avatar Thinh Nguyen Committed by Srinivasarao P
Browse files

usb: dwc3: gadget: Properly handle ClearFeature(halt)



[ Upstream commit cb11ea56f37a36288cdd0a4799a983ee3aa437dd ]

DWC3 must not issue CLEAR_STALL command to control endpoints. The
controller automatically clears the STALL when it receives the SETUP
token. Also, when the driver receives ClearFeature(halt_ep), DWC3 must
stop any active transfer from the endpoint and give back all the
requests to the function drivers.

Change-Id: Iccf1e148c74bbe194702e3e7a620f0fef5a9b183
Fixes: 72246da4 ("usb: Introduce DesignWare USB3 DRD Driver")
Signed-off-by: default avatarThinh Nguyen <thinhn@synopsys.com>
Signed-off-by: default avatarFelipe Balbi <balbi@kernel.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Git-commit: 1bfa0914
Git-repo: https://android.googlesource.com/kernel/common/


Signed-off-by: default avatarSrinivasarao P <spathi@codeaurora.org>
parent 0456270e
Loading
Loading
Loading
Loading
+33 −3
Original line number Diff line number Diff line
@@ -1685,6 +1685,10 @@ static void dwc3_gadget_ep_skip_trbs(struct dwc3_ep *dep, struct dwc3_request *r
{
	int i;

	/* If req->trb is not set, then the request has not started */
	if (!req->trb)
		return;

	/*
	 * If request was already started, this means we had to
	 * stop the transfer. With that we also need to ignore
@@ -1796,6 +1800,8 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
{
	struct dwc3_gadget_ep_cmd_params	params;
	struct dwc3				*dwc = dep->dwc;
	struct dwc3_request			*req;
	struct dwc3_request			*tmp;
	int					ret;

	if (!dep->endpoint.desc) {
@@ -1841,13 +1847,37 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
		else
			dep->flags |= DWC3_EP_STALL;
	} else {
		/*
		 * Don't issue CLEAR_STALL command to control endpoints. The
		 * controller automatically clears the STALL when it receives
		 * the SETUP token.
		 */
		if (dep->number <= 1) {
			dep->flags &= ~(DWC3_EP_STALL | DWC3_EP_WEDGE);
			return 0;
		}

		ret = dwc3_send_clear_stall_ep_cmd(dep);
		if (ret)
		if (ret) {
			dev_err(dwc->dev, "failed to clear STALL on %s\n",
					dep->name);
		else
			return ret;
		}

		dep->flags &= ~(DWC3_EP_STALL | DWC3_EP_WEDGE);

		dwc3_stop_active_transfer(dep, true, true);

		list_for_each_entry_safe(req, tmp, &dep->started_list, list)
			dwc3_gadget_move_cancelled_request(req);

		list_for_each_entry_safe(req, tmp, &dep->pending_list, list)
			dwc3_gadget_move_cancelled_request(req);

		if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING)) {
			dep->flags &= ~DWC3_EP_DELAY_START;
			dwc3_gadget_ep_cleanup_cancelled_requests(dep);
		}
	}

	return ret;