From c4b2f05b5f7ef898f61990fe5ddbeb9d1bcb59c5 Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Thu, 20 May 2021 12:31:08 +0530 Subject: [PATCH] USB: dwc3: gadget: Queue data for 16 micro frames ahead in future While starting transfer for isochronous endpoints, make sure first request is queued for 16 microframes ahead in future. Also set PENDING_REQUEST flag before giving back usb request if started_list is empty to avoid queuing in same context. Else it leads to request getting queued for micro frame interval which might have expired and resulting USB HW retiring TRB without sending data to host. Change-Id: Ia5e4512fa2a3ae6637f2be7ef2f102c26d56213c Signed-off-by: Vijayavardhan Vennapusa Signed-off-by: AKASH KUMAR --- drivers/usb/dwc3/core.h | 2 ++ drivers/usb/dwc3/debug_ipc.c | 6 ++++-- drivers/usb/dwc3/gadget.c | 18 ++++++++++++++++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index c555ebb0b223..d7fe83efabbd 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -738,6 +738,7 @@ struct dwc3_ep_events { * @desc: usb_endpoint_descriptor pointer * @dwc: pointer to DWC controller * @saved_state: ep state saved during hibernation + * @missed_isoc_packets: counter for missed packets sent * @flags: endpoint flags (wedged, stalled, ...) * @number: endpoint number (1 - 15) * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK @@ -771,6 +772,7 @@ struct dwc3_ep { struct dwc3 *dwc; u32 saved_state; + u32 missed_isoc_packets; unsigned flags; #define DWC3_EP_ENABLED BIT(0) #define DWC3_EP_STALL BIT(1) diff --git a/drivers/usb/dwc3/debug_ipc.c b/drivers/usb/dwc3/debug_ipc.c index 4126936aed87..f475b0622edb 100644 --- a/drivers/usb/dwc3/debug_ipc.c +++ b/drivers/usb/dwc3/debug_ipc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved. */ #include "debug.h" @@ -150,10 +151,11 @@ void dwc3_dbg_dma_unmap(struct dwc3 *dwc, u8 ep_num, struct dwc3_request *req) req->trb->ctrl & DWC3_TRB_CTRL_HWO); } else { ipc_log_string(dwc->dwc_dma_ipc_log_ctxt, - "%02X-%-3.3s %-25.25s 0x%pK 0x%lx %u 0x%lx %d", + "%02X-%-3.3s %-25.25s 0x%pK 0x%lx %u 0x%lx %d %u", ep_num >> 1, ep_num & 1 ? "IN":"OUT", "UNMAP", &req->request, req->request.dma, req->request.length, - req->trb_dma, req->trb->ctrl & DWC3_TRB_CTRL_HWO); + req->trb_dma, req->trb->ctrl & DWC3_TRB_CTRL_HWO, + req->request.actual); } } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 0e17387167d5..dd12d4289479 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -308,6 +308,12 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, dwc3_gadget_del_and_unmap_request(dep, req, status); req->status = DWC3_REQUEST_STATUS_COMPLETED; + if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && + (list_empty(&dep->started_list))) { + dep->flags |= DWC3_EP_PENDING_REQUEST; + dbg_event(dep->number, "STARTEDLISTEMPTY", 0); + } + spin_unlock(&dwc->lock); usb_gadget_giveback_request(&dep->endpoint, &req->request); spin_lock(&dwc->lock); @@ -983,6 +989,8 @@ static int dwc3_gadget_ep_disable(struct usb_ep *ep) spin_lock_irqsave(&dwc->lock, flags); ret = __dwc3_gadget_ep_disable(dep); dbg_event(dep->number, "DISABLE", ret); + dbg_event(dep->number, "MISSEDISOCPKTS", dep->missed_isoc_packets); + dep->missed_isoc_packets = 0; spin_unlock_irqrestore(&dwc->lock, flags); return ret; @@ -1661,6 +1669,7 @@ static int __dwc3_gadget_start_isoc(struct dwc3_ep *dep) } for (i = 0; i < DWC3_ISOC_MAX_RETRIES; i++) { + dep->frame_number = __dwc3_gadget_get_frame(dep->dwc) + 16; dep->frame_number = DWC3_ALIGN_FRAME(dep, i + 1); ret = __dwc3_gadget_kick_transfer(dep); @@ -1727,8 +1736,10 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) if ((dep->flags & DWC3_EP_PENDING_REQUEST)) { if (!(dep->flags & DWC3_EP_TRANSFER_STARTED)) { + dep->flags &= ~DWC3_EP_PENDING_REQUEST; return __dwc3_gadget_start_isoc(dep); } + return 0; } } @@ -3391,15 +3402,18 @@ static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep, if (event->status & DEPEVT_STATUS_BUSERR) status = -ECONNRESET; + dwc3_gadget_ep_cleanup_completed_requests(dep, event, status); + if (event->status & DEPEVT_STATUS_MISSED_ISOC) { status = -EXDEV; + dep->missed_isoc_packets++; + dbg_event(dep->number, "MISSEDISOC", 0); + if (list_empty(&dep->started_list)) stop = true; } - dwc3_gadget_ep_cleanup_completed_requests(dep, event, status); - if (dep->flags & DWC3_EP_END_TRANSFER_PENDING) goto out;