Oliver Neukum 73a340
From c7428dbddcf4ea1919e1c8e15f715b94ca359268 Mon Sep 17 00:00:00 2001
Oliver Neukum 73a340
From: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
Oliver Neukum 73a340
Date: Fri, 22 Apr 2022 17:36:28 -0700
Oliver Neukum 73a340
Subject: [PATCH] usb: dwc3: gadget: Return proper request status
Oliver Neukum 73a340
Git-commit: c7428dbddcf4ea1919e1c8e15f715b94ca359268
Oliver Neukum 73a340
References: git-fixes
Oliver Neukum 73a340
Patch-mainline: v5.18-rc5
Oliver Neukum 73a340
Oliver Neukum 73a340
If the user sets the usb_request's no_interrupt, then there will be no
Oliver Neukum 73a340
completion event for the request. Currently the driver incorrectly uses
Oliver Neukum 73a340
the event status of a different request to report the status for a
Oliver Neukum 73a340
request with no_interrupt. The dwc3 driver needs to check the TRB status
Oliver Neukum 73a340
associated with the request when reporting its status.
Oliver Neukum 73a340
Oliver Neukum 73a340
Note: this is only applicable to missed_isoc TRB completion status, but
Oliver Neukum 73a340
the other status are also listed for completeness/documentation.
Oliver Neukum 73a340
Oliver Neukum 73a340
Fixes: 6d8a019614f3 ("usb: dwc3: gadget: check for Missed Isoc from event status")
Oliver Neukum 73a340
Cc: <stable@vger.kernel.org>
Oliver Neukum 73a340
Signed-off-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
Oliver Neukum 73a340
Link: https://lore.kernel.org/r/db2c80108286cfd108adb05bad52138b78d7c3a7.1650673655.git.Thinh.Nguyen@synopsys.com
Oliver Neukum 73a340
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Oliver Neukum 73a340
Signed-off-by: Oliver Neukum <oneukum@suse.com>
Oliver Neukum 73a340
---
Oliver Neukum 73a340
 drivers/usb/dwc3/gadget.c | 31 ++++++++++++++++++++++++++++++-
Oliver Neukum 73a340
 1 file changed, 30 insertions(+), 1 deletion(-)
Oliver Neukum 73a340
Oliver Neukum 73a340
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
Oliver Neukum 73a340
index ab725d2262d6..0b9c2493844a 100644
Oliver Neukum 73a340
--- a/drivers/usb/dwc3/gadget.c
Oliver Neukum 73a340
+++ b/drivers/usb/dwc3/gadget.c
Oliver Neukum 73a340
@@ -3274,6 +3274,7 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep,
Oliver Neukum 73a340
 		const struct dwc3_event_depevt *event,
Oliver Neukum 73a340
 		struct dwc3_request *req, int status)
Oliver Neukum 73a340
 {
Oliver Neukum 73a340
+	int request_status;
Oliver Neukum 73a340
 	int ret;
Oliver Neukum 73a340
 
Oliver Neukum 73a340
 	if (req->request.num_mapped_sgs)
Oliver Neukum 73a340
@@ -3294,7 +3295,35 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep,
Oliver Neukum 73a340
 		req->needs_extra_trb = false;
Oliver Neukum 73a340
 	}
Oliver Neukum 73a340
 
Oliver Neukum 73a340
-	dwc3_gadget_giveback(dep, req, status);
Oliver Neukum 73a340
+	/*
Oliver Neukum 73a340
+	 * The event status only reflects the status of the TRB with IOC set.
Oliver Neukum 73a340
+	 * For the requests that don't set interrupt on completion, the driver
Oliver Neukum 73a340
+	 * needs to check and return the status of the completed TRBs associated
Oliver Neukum 73a340
+	 * with the request. Use the status of the last TRB of the request.
Oliver Neukum 73a340
+	 */
Oliver Neukum 73a340
+	if (req->request.no_interrupt) {
Oliver Neukum 73a340
+		struct dwc3_trb *trb;
Oliver Neukum 73a340
+
Oliver Neukum 73a340
+		trb = dwc3_ep_prev_trb(dep, dep->trb_dequeue);
Oliver Neukum 73a340
+		switch (DWC3_TRB_SIZE_TRBSTS(trb->size)) {
Oliver Neukum 73a340
+		case DWC3_TRBSTS_MISSED_ISOC:
Oliver Neukum 73a340
+			/* Isoc endpoint only */
Oliver Neukum 73a340
+			request_status = -EXDEV;
Oliver Neukum 73a340
+			break;
Oliver Neukum 73a340
+		case DWC3_TRB_STS_XFER_IN_PROG:
Oliver Neukum 73a340
+			/* Applicable when End Transfer with ForceRM=0 */
Oliver Neukum 73a340
+		case DWC3_TRBSTS_SETUP_PENDING:
Oliver Neukum 73a340
+			/* Control endpoint only */
Oliver Neukum 73a340
+		case DWC3_TRBSTS_OK:
Oliver Neukum 73a340
+		default:
Oliver Neukum 73a340
+			request_status = 0;
Oliver Neukum 73a340
+			break;
Oliver Neukum 73a340
+		}
Oliver Neukum 73a340
+	} else {
Oliver Neukum 73a340
+		request_status = status;
Oliver Neukum 73a340
+	}
Oliver Neukum 73a340
+
Oliver Neukum 73a340
+	dwc3_gadget_giveback(dep, req, request_status);
Oliver Neukum 73a340
 
Oliver Neukum 73a340
 out:
Oliver Neukum 73a340
 	return ret;
Oliver Neukum 73a340
-- 
Oliver Neukum 73a340
2.35.3
Oliver Neukum 73a340