diff options
Diffstat (limited to 'drivers/usb/dwc2/hcd_intr.c')
-rw-r--r-- | drivers/usb/dwc2/hcd_intr.c | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c index fbea5e3..8ce10ca 100644 --- a/drivers/usb/dwc2/hcd_intr.c +++ b/drivers/usb/dwc2/hcd_intr.c @@ -942,14 +942,21 @@ static int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg, frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; len = dwc2_get_actual_xfer_length(hsotg, chan, chnum, qtd, DWC2_HC_XFER_COMPLETE, NULL); - if (!len) { + if (!len && !qtd->isoc_split_offset) { qtd->complete_split = 0; - qtd->isoc_split_offset = 0; return 0; } frame_desc->actual_length += len; + if (chan->align_buf) { + dev_vdbg(hsotg->dev, "non-aligned buffer\n"); + dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma, + DWC2_KMEM_UNALIGNED_BUF_SIZE, DMA_FROM_DEVICE); + memcpy(qtd->urb->buf + (chan->xfer_dma - qtd->urb->dma), + chan->qh->dw_align_buf, len); + } + qtd->isoc_split_offset += len; hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum)); @@ -1224,7 +1231,10 @@ static void dwc2_hc_nak_intr(struct dwc2_hsotg *hsotg, * avoid interrupt storms we'll wait before retrying if we've got * several NAKs. If we didn't do this we'd retry directly from the * interrupt handler and could end up quickly getting another - * interrupt (another NAK), which we'd retry. + * interrupt (another NAK), which we'd retry. Note that we do not + * delay retries for IN parts of control requests, as those are expected + * to complete fairly quickly, and if we delay them we risk confusing + * the device and cause it issue STALL. * * Note that in DMA mode software only gets involved to re-send NAKed * transfers for split transactions, so we only need to apply this @@ -1237,7 +1247,9 @@ static void dwc2_hc_nak_intr(struct dwc2_hsotg *hsotg, qtd->error_count = 0; qtd->complete_split = 0; qtd->num_naks++; - qtd->qh->want_wait = qtd->num_naks >= DWC2_NAKS_BEFORE_DELAY; + qtd->qh->want_wait = qtd->num_naks >= DWC2_NAKS_BEFORE_DELAY && + !(chan->ep_type == USB_ENDPOINT_XFER_CONTROL && + chan->ep_is_in); dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK); goto handle_nak_done; } |