[PATCH 3/3] usb: dwc3: gadget: check the whole started queue for missed requests in complete

From: Michael Grzeschik
Date: Thu Mar 07 2024 - 10:23:05 EST


The function dwc3_gadget_endpoint_trbs_complete will be called with the
interrupt event. This event is only representing the interrupt reason of
the exact trb that had IOC enabled. In the current approach the function
dwc3_gadget_ep_cleanup_completed_requests will give back and complete
the requests with the corresponding trb status and therefor will
correctly return the missed requests that are already finished.

Since inbetween those complete functioncalls of the properly
finished and the missed trbs, a missed transfer could get new
trbs enqueued with the updatecmd, this will just lead to more missed
trbs.

To break the cascading scenario this patch is checking all trbs from the
started list for any trb that has the missed trb status before even
calling the complete handler but stopping the transfer instead.

Signed-off-by: Michael Grzeschik <m.grzeschik@xxxxxxxxxxxxxx>
---
drivers/usb/dwc3/gadget.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index f22b68a0b2dac..ca87f4d988d41 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -3563,6 +3563,21 @@ static void dwc3_gadget_endpoint_frame_from_event(struct dwc3_ep *dep,
dep->frame_number = event->parameters;
}

+static int dwc3_gadget_ep_check_missed_requests(struct dwc3_ep *dep)
+{
+ struct dwc3_request *req;
+ struct dwc3_request *tmp;
+
+ list_for_each_entry_safe(req, tmp, &dep->started_list, list) {
+ struct dwc3_trb *trb = req->trb;
+
+ if (DWC3_TRB_SIZE_TRBSTS(trb->size) == DWC3_TRBSTS_MISSED_ISOC)
+ return -EXDEV;
+ }
+
+ return 0;
+}
+
static bool dwc3_gadget_endpoint_trbs_complete(struct dwc3_ep *dep,
const struct dwc3_event_depevt *event, int status)
{
@@ -3584,7 +3599,7 @@ static bool dwc3_gadget_endpoint_trbs_complete(struct dwc3_ep *dep,
transfer_in_flight = trb->ctrl & DWC3_TRB_CTRL_HWO;
}

- if (status == -EXDEV || !transfer_in_flight)
+ if (status == -EXDEV || !transfer_in_flight || dwc3_gadget_ep_check_missed_requests(dep))
dwc3_stop_active_transfer(dep, true, true);

dwc3_gadget_ep_cleanup_completed_requests(dep, event, status);

--
2.39.2