From 09c3ad5d253ab8c79824d796cd8eaea1f94ac733 Mon Sep 17 00:00:00 2001 From: AKASH KUMAR Date: Sun, 11 Dec 2022 15:12:02 +0530 Subject: [PATCH] USB: dwc3: gadget: Add stop transfer request for isoc transfers Currently,stop transfer is done based on missed isoc packets which can cause issue when software list is empty with no missed isoc. Issue stop active transfers if started list is empty. Also,Frame_number is set from XferNotReady and may be already out of date. DSTS only provides the lower 14 bit of the current frame number. So add the upper two bits of frame_number and handle a possible rollover. This will provide the correct frame_number unless more than rollover has happened since XferNotReady. Increase TX fifo size for isochronous endpoint in case maxburst is greater than 6 for better performance. Added Endtransfer logic to be called when BUS expiry happens due to frame mismatch. Change-Id: I672529f4a4fa2740b46febbe265cd386e5932017 Signed-off-by: AKASH KUMAR --- drivers/usb/dwc3/gadget.c | 54 +++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index dd12d4289479..5c23ef112656 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -30,6 +30,8 @@ #define DWC3_ALIGN_FRAME(d, n) (((d)->frame_number + ((d)->interval * (n))) \ & ~((d)->interval - 1)) +#define DWC3_FRAME_WRAP_AROUND_MASK (BIT(14) | BIT(15)) + static int __dwc3_gadget_start(struct dwc3 *dwc); static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc); static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc, bool remote_wakeup); @@ -228,6 +230,11 @@ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc, struct dwc3_ep *dep) && dwc3_is_usb31(dwc)) mult = 6; + if ((dep->endpoint.maxburst > 6) && + usb_endpoint_xfer_isoc(dep->endpoint.desc)) + mult = 6; + + tmp = ((max_packet + mdwidth) * mult) + mdwidth; fifo_size = DIV_ROUND_UP(tmp, mdwidth); dep->fifo_depth = fifo_size; @@ -1651,7 +1658,7 @@ static int __dwc3_gadget_start_isoc(struct dwc3_ep *dep) { struct dwc3 *dwc = dep->dwc; int ret; - int i; + u16 wraparound_bits, uf; if (list_empty(&dep->pending_list)) { dep->flags |= DWC3_EP_PENDING_REQUEST; @@ -1668,13 +1675,36 @@ static int __dwc3_gadget_start_isoc(struct dwc3_ep *dep) return dwc3_gadget_start_isoc_quirk(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); + wraparound_bits = dep->frame_number & DWC3_FRAME_WRAP_AROUND_MASK; + uf = dep->frame_number & ~DWC3_FRAME_WRAP_AROUND_MASK; - ret = __dwc3_gadget_kick_transfer(dep); - if (ret != -EAGAIN) - break; + /* if frame wrapped-around update wrap-around bits to reflect that */ + if (__dwc3_gadget_get_frame(dep->dwc) < uf) + wraparound_bits += BIT(14); + + uf = __dwc3_gadget_get_frame(dep->dwc) + max_t(u32, 16, 2 * dep->interval); + + /* align frame number to ep interval */ + dep->frame_number = (wraparound_bits + uf) & ~(dep->interval - 1); + + ret = __dwc3_gadget_kick_transfer(dep); + + if (ret == -EAGAIN) { + struct dwc3_gadget_ep_cmd_params params; + u32 cmd; + + dwc3_gadget_ep_get_transfer_index(dep); + dep->flags |= DWC3_EP_PENDING_REQUEST; + cmd = DWC3_DEPCMD_ENDTRANSFER | + DWC3_DEPCMD_CMDIOC | + DWC3_DEPCMD_PARAM(dep->resource_index); + + dep->resource_index = 0; + memset(¶ms, 0, sizeof(params)); + + ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); + if (!ret) + dep->flags |= DWC3_EP_END_TRANSFER_PENDING; } return ret; @@ -3406,12 +3436,14 @@ static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep, if (event->status & DEPEVT_STATUS_MISSED_ISOC) { status = -EXDEV; - dep->missed_isoc_packets++; - dbg_event(dep->number, "MISSEDISOC", 0); + dbg_event(dep->number, "MISSEDISOC", dep->missed_isoc_packets); + } - if (list_empty(&dep->started_list)) - stop = true; + if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && + (list_empty(&dep->started_list))) { + stop = true; + dbg_event(dep->number, "STOPXFER", dep->frame_number); } if (dep->flags & DWC3_EP_END_TRANSFER_PENDING)