usb: dwc2: handle DMA buffer unmapping sanely
The driver's handling of DMA buffers for non-aligned transfers was kind of nuts. For IN transfers, it left the URB DMA buffer mapped until the transfer completed, then synced it, copied the data from the bounce buffer, then synced it again. Instead of that, just call usb_hcd_unmap_urb_for_dma() to unmap the buffer before starting the transfer. Then no syncing is required when doing the copy. This should also allow handling of other types of mappings besides just dma_map_single() ones. Also reduce the size of the bounce buffer allocation for Isoc endpoints to 3K, since that's the largest possible transfer size. Tested on Raspberry Pi and Altera SOCFPGA. Signed-off-by: Paul Zimmerman <paulz@synopsys.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
e8f8c14d9d
commit
5dce95554a
@@ -465,12 +465,8 @@ static int dwc2_update_urb_state(struct dwc2_hsotg *hsotg,
|
||||
/* Non DWORD-aligned buffer case handling */
|
||||
if (chan->align_buf && xfer_length && chan->ep_is_in) {
|
||||
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
|
||||
dma_sync_single_for_cpu(hsotg->dev, urb->dma, urb->length,
|
||||
DMA_FROM_DEVICE);
|
||||
memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
|
||||
xfer_length);
|
||||
dma_sync_single_for_device(hsotg->dev, urb->dma, urb->length,
|
||||
DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
dev_vdbg(hsotg->dev, "urb->actual_length=%d xfer_length=%d\n",
|
||||
@@ -560,14 +556,9 @@ static enum dwc2_halt_status dwc2_update_isoc_urb_state(
|
||||
chan->ep_is_in) {
|
||||
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
|
||||
__func__);
|
||||
dma_sync_single_for_cpu(hsotg->dev, urb->dma,
|
||||
urb->length, DMA_FROM_DEVICE);
|
||||
memcpy(urb->buf + frame_desc->offset +
|
||||
qtd->isoc_split_offset, chan->qh->dw_align_buf,
|
||||
frame_desc->actual_length);
|
||||
dma_sync_single_for_device(hsotg->dev, urb->dma,
|
||||
urb->length,
|
||||
DMA_FROM_DEVICE);
|
||||
}
|
||||
break;
|
||||
case DWC2_HC_XFER_FRAME_OVERRUN:
|
||||
@@ -594,14 +585,9 @@ static enum dwc2_halt_status dwc2_update_isoc_urb_state(
|
||||
chan->ep_is_in) {
|
||||
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
|
||||
__func__);
|
||||
dma_sync_single_for_cpu(hsotg->dev, urb->dma,
|
||||
urb->length, DMA_FROM_DEVICE);
|
||||
memcpy(urb->buf + frame_desc->offset +
|
||||
qtd->isoc_split_offset, chan->qh->dw_align_buf,
|
||||
frame_desc->actual_length);
|
||||
dma_sync_single_for_device(hsotg->dev, urb->dma,
|
||||
urb->length,
|
||||
DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
/* Skip whole frame */
|
||||
@@ -937,12 +923,8 @@ static int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg,
|
||||
|
||||
if (chan->align_buf) {
|
||||
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
|
||||
dma_sync_single_for_cpu(hsotg->dev, qtd->urb->dma,
|
||||
qtd->urb->length, DMA_FROM_DEVICE);
|
||||
memcpy(qtd->urb->buf + frame_desc->offset +
|
||||
qtd->isoc_split_offset, chan->qh->dw_align_buf, len);
|
||||
dma_sync_single_for_device(hsotg->dev, qtd->urb->dma,
|
||||
qtd->urb->length, DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
qtd->isoc_split_offset += len;
|
||||
@@ -1170,12 +1152,8 @@ static void dwc2_update_urb_state_abn(struct dwc2_hsotg *hsotg,
|
||||
/* Non DWORD-aligned buffer case handling */
|
||||
if (chan->align_buf && xfer_length && chan->ep_is_in) {
|
||||
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
|
||||
dma_sync_single_for_cpu(hsotg->dev, urb->dma, urb->length,
|
||||
DMA_FROM_DEVICE);
|
||||
memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
|
||||
xfer_length);
|
||||
dma_sync_single_for_device(hsotg->dev, urb->dma, urb->length,
|
||||
DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
urb->actual_length += xfer_length;
|
||||
|
Reference in New Issue
Block a user