diff options
-rw-r--r-- | drivers/usb/dwc2/core.h | 3 | ||||
-rw-r--r-- | drivers/usb/dwc2/hcd.c | 89 | ||||
-rw-r--r-- | drivers/usb/dwc2/hcd.h | 8 | ||||
-rw-r--r-- | drivers/usb/dwc2/hcd_intr.c | 8 | ||||
-rw-r--r-- | drivers/usb/dwc2/hcd_queue.c | 3 |
5 files changed, 106 insertions, 5 deletions
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 4a56ac772a3c..71b3b08ad516 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h | |||
@@ -1004,6 +1004,7 @@ struct dwc2_hregs_backup { | |||
1004 | * @frame_list_sz: Frame list size | 1004 | * @frame_list_sz: Frame list size |
1005 | * @desc_gen_cache: Kmem cache for generic descriptors | 1005 | * @desc_gen_cache: Kmem cache for generic descriptors |
1006 | * @desc_hsisoc_cache: Kmem cache for hs isochronous descriptors | 1006 | * @desc_hsisoc_cache: Kmem cache for hs isochronous descriptors |
1007 | * @unaligned_cache: Kmem cache for DMA mode to handle non-aligned buf | ||
1007 | * | 1008 | * |
1008 | * These are for peripheral mode: | 1009 | * These are for peripheral mode: |
1009 | * | 1010 | * |
@@ -1177,6 +1178,8 @@ struct dwc2_hsotg { | |||
1177 | u32 frame_list_sz; | 1178 | u32 frame_list_sz; |
1178 | struct kmem_cache *desc_gen_cache; | 1179 | struct kmem_cache *desc_gen_cache; |
1179 | struct kmem_cache *desc_hsisoc_cache; | 1180 | struct kmem_cache *desc_hsisoc_cache; |
1181 | struct kmem_cache *unaligned_cache; | ||
1182 | #define DWC2_KMEM_UNALIGNED_BUF_SIZE 1024 | ||
1180 | 1183 | ||
1181 | #endif /* CONFIG_USB_DWC2_HOST || CONFIG_USB_DWC2_DUAL_ROLE */ | 1184 | #endif /* CONFIG_USB_DWC2_HOST || CONFIG_USB_DWC2_DUAL_ROLE */ |
1182 | 1185 | ||
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index bae08a7d7abd..b1104be3429c 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c | |||
@@ -1567,11 +1567,20 @@ static void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg, | |||
1567 | } | 1567 | } |
1568 | 1568 | ||
1569 | if (hsotg->params.host_dma) { | 1569 | if (hsotg->params.host_dma) { |
1570 | dwc2_writel((u32)chan->xfer_dma, | 1570 | dma_addr_t dma_addr; |
1571 | hsotg->regs + HCDMA(chan->hc_num)); | 1571 | |
1572 | if (chan->align_buf) { | ||
1573 | if (dbg_hc(chan)) | ||
1574 | dev_vdbg(hsotg->dev, "align_buf\n"); | ||
1575 | dma_addr = chan->align_buf; | ||
1576 | } else { | ||
1577 | dma_addr = chan->xfer_dma; | ||
1578 | } | ||
1579 | dwc2_writel((u32)dma_addr, hsotg->regs + HCDMA(chan->hc_num)); | ||
1580 | |||
1572 | if (dbg_hc(chan)) | 1581 | if (dbg_hc(chan)) |
1573 | dev_vdbg(hsotg->dev, "Wrote %08lx to HCDMA(%d)\n", | 1582 | dev_vdbg(hsotg->dev, "Wrote %08lx to HCDMA(%d)\n", |
1574 | (unsigned long)chan->xfer_dma, chan->hc_num); | 1583 | (unsigned long)dma_addr, chan->hc_num); |
1575 | } | 1584 | } |
1576 | 1585 | ||
1577 | /* Start the split */ | 1586 | /* Start the split */ |
@@ -2625,6 +2634,35 @@ static void dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg, | |||
2625 | } | 2634 | } |
2626 | } | 2635 | } |
2627 | 2636 | ||
2637 | static int dwc2_alloc_split_dma_aligned_buf(struct dwc2_hsotg *hsotg, | ||
2638 | struct dwc2_qh *qh, | ||
2639 | struct dwc2_host_chan *chan) | ||
2640 | { | ||
2641 | if (!hsotg->unaligned_cache || | ||
2642 | chan->max_packet > DWC2_KMEM_UNALIGNED_BUF_SIZE) | ||
2643 | return -ENOMEM; | ||
2644 | |||
2645 | if (!qh->dw_align_buf) { | ||
2646 | qh->dw_align_buf = kmem_cache_alloc(hsotg->unaligned_cache, | ||
2647 | GFP_ATOMIC | GFP_DMA); | ||
2648 | if (!qh->dw_align_buf) | ||
2649 | return -ENOMEM; | ||
2650 | } | ||
2651 | |||
2652 | qh->dw_align_buf_dma = dma_map_single(hsotg->dev, qh->dw_align_buf, | ||
2653 | DWC2_KMEM_UNALIGNED_BUF_SIZE, | ||
2654 | DMA_FROM_DEVICE); | ||
2655 | |||
2656 | if (dma_mapping_error(hsotg->dev, qh->dw_align_buf_dma)) { | ||
2657 | dev_err(hsotg->dev, "can't map align_buf\n"); | ||
2658 | chan->align_buf = 0; | ||
2659 | return -EINVAL; | ||
2660 | } | ||
2661 | |||
2662 | chan->align_buf = qh->dw_align_buf_dma; | ||
2663 | return 0; | ||
2664 | } | ||
2665 | |||
2628 | #define DWC2_USB_DMA_ALIGN 4 | 2666 | #define DWC2_USB_DMA_ALIGN 4 |
2629 | 2667 | ||
2630 | struct dma_aligned_buffer { | 2668 | struct dma_aligned_buffer { |
@@ -2802,6 +2840,32 @@ static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) | |||
2802 | /* Set the transfer attributes */ | 2840 | /* Set the transfer attributes */ |
2803 | dwc2_hc_init_xfer(hsotg, chan, qtd); | 2841 | dwc2_hc_init_xfer(hsotg, chan, qtd); |
2804 | 2842 | ||
2843 | /* For non-dword aligned buffers */ | ||
2844 | if (hsotg->params.host_dma && qh->do_split && | ||
2845 | chan->ep_is_in && (chan->xfer_dma & 0x3)) { | ||
2846 | dev_vdbg(hsotg->dev, "Non-aligned buffer\n"); | ||
2847 | if (dwc2_alloc_split_dma_aligned_buf(hsotg, qh, chan)) { | ||
2848 | dev_err(hsotg->dev, | ||
2849 | "Failed to allocate memory to handle non-aligned buffer\n"); | ||
2850 | /* Add channel back to free list */ | ||
2851 | chan->align_buf = 0; | ||
2852 | chan->multi_count = 0; | ||
2853 | list_add_tail(&chan->hc_list_entry, | ||
2854 | &hsotg->free_hc_list); | ||
2855 | qtd->in_process = 0; | ||
2856 | qh->channel = NULL; | ||
2857 | return -ENOMEM; | ||
2858 | } | ||
2859 | } else { | ||
2860 | /* | ||
2861 | * We assume that DMA is always aligned in non-split | ||
2862 | * case or split out case. Warn if not. | ||
2863 | */ | ||
2864 | WARN_ON_ONCE(hsotg->params.host_dma && | ||
2865 | (chan->xfer_dma & 0x3)); | ||
2866 | chan->align_buf = 0; | ||
2867 | } | ||
2868 | |||
2805 | if (chan->ep_type == USB_ENDPOINT_XFER_INT || | 2869 | if (chan->ep_type == USB_ENDPOINT_XFER_INT || |
2806 | chan->ep_type == USB_ENDPOINT_XFER_ISOC) | 2870 | chan->ep_type == USB_ENDPOINT_XFER_ISOC) |
2807 | /* | 2871 | /* |
@@ -5246,6 +5310,19 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg) | |||
5246 | } | 5310 | } |
5247 | } | 5311 | } |
5248 | 5312 | ||
5313 | if (hsotg->params.host_dma) { | ||
5314 | /* | ||
5315 | * Create kmem caches to handle non-aligned buffer | ||
5316 | * in Buffer DMA mode. | ||
5317 | */ | ||
5318 | hsotg->unaligned_cache = kmem_cache_create("dwc2-unaligned-dma", | ||
5319 | DWC2_KMEM_UNALIGNED_BUF_SIZE, 4, | ||
5320 | SLAB_CACHE_DMA, NULL); | ||
5321 | if (!hsotg->unaligned_cache) | ||
5322 | dev_err(hsotg->dev, | ||
5323 | "unable to create dwc2 unaligned cache\n"); | ||
5324 | } | ||
5325 | |||
5249 | hsotg->otg_port = 1; | 5326 | hsotg->otg_port = 1; |
5250 | hsotg->frame_list = NULL; | 5327 | hsotg->frame_list = NULL; |
5251 | hsotg->frame_list_dma = 0; | 5328 | hsotg->frame_list_dma = 0; |
@@ -5280,8 +5357,9 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg) | |||
5280 | return 0; | 5357 | return 0; |
5281 | 5358 | ||
5282 | error4: | 5359 | error4: |
5283 | kmem_cache_destroy(hsotg->desc_gen_cache); | 5360 | kmem_cache_destroy(hsotg->unaligned_cache); |
5284 | kmem_cache_destroy(hsotg->desc_hsisoc_cache); | 5361 | kmem_cache_destroy(hsotg->desc_hsisoc_cache); |
5362 | kmem_cache_destroy(hsotg->desc_gen_cache); | ||
5285 | error3: | 5363 | error3: |
5286 | dwc2_hcd_release(hsotg); | 5364 | dwc2_hcd_release(hsotg); |
5287 | error2: | 5365 | error2: |
@@ -5322,8 +5400,9 @@ void dwc2_hcd_remove(struct dwc2_hsotg *hsotg) | |||
5322 | usb_remove_hcd(hcd); | 5400 | usb_remove_hcd(hcd); |
5323 | hsotg->priv = NULL; | 5401 | hsotg->priv = NULL; |
5324 | 5402 | ||
5325 | kmem_cache_destroy(hsotg->desc_gen_cache); | 5403 | kmem_cache_destroy(hsotg->unaligned_cache); |
5326 | kmem_cache_destroy(hsotg->desc_hsisoc_cache); | 5404 | kmem_cache_destroy(hsotg->desc_hsisoc_cache); |
5405 | kmem_cache_destroy(hsotg->desc_gen_cache); | ||
5327 | 5406 | ||
5328 | dwc2_hcd_release(hsotg); | 5407 | dwc2_hcd_release(hsotg); |
5329 | usb_put_hcd(hcd); | 5408 | usb_put_hcd(hcd); |
diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h index 7db1ee7e7a77..5502a501f516 100644 --- a/drivers/usb/dwc2/hcd.h +++ b/drivers/usb/dwc2/hcd.h | |||
@@ -76,6 +76,8 @@ struct dwc2_qh; | |||
76 | * (micro)frame | 76 | * (micro)frame |
77 | * @xfer_buf: Pointer to current transfer buffer position | 77 | * @xfer_buf: Pointer to current transfer buffer position |
78 | * @xfer_dma: DMA address of xfer_buf | 78 | * @xfer_dma: DMA address of xfer_buf |
79 | * @align_buf: In Buffer DMA mode this will be used if xfer_buf is not | ||
80 | * DWORD aligned | ||
79 | * @xfer_len: Total number of bytes to transfer | 81 | * @xfer_len: Total number of bytes to transfer |
80 | * @xfer_count: Number of bytes transferred so far | 82 | * @xfer_count: Number of bytes transferred so far |
81 | * @start_pkt_count: Packet count at start of transfer | 83 | * @start_pkt_count: Packet count at start of transfer |
@@ -133,6 +135,7 @@ struct dwc2_host_chan { | |||
133 | 135 | ||
134 | u8 *xfer_buf; | 136 | u8 *xfer_buf; |
135 | dma_addr_t xfer_dma; | 137 | dma_addr_t xfer_dma; |
138 | dma_addr_t align_buf; | ||
136 | u32 xfer_len; | 139 | u32 xfer_len; |
137 | u32 xfer_count; | 140 | u32 xfer_count; |
138 | u16 start_pkt_count; | 141 | u16 start_pkt_count; |
@@ -302,6 +305,9 @@ struct dwc2_hs_transfer_time { | |||
302 | * speed. Note that this is in "schedule slice" which | 305 | * speed. Note that this is in "schedule slice" which |
303 | * is tightly packed. | 306 | * is tightly packed. |
304 | * @ntd: Actual number of transfer descriptors in a list | 307 | * @ntd: Actual number of transfer descriptors in a list |
308 | * @dw_align_buf: Used instead of original buffer if its physical address | ||
309 | * is not dword-aligned | ||
310 | * @dw_align_buf_dma: DMA address for dw_align_buf | ||
305 | * @qtd_list: List of QTDs for this QH | 311 | * @qtd_list: List of QTDs for this QH |
306 | * @channel: Host channel currently processing transfers for this QH | 312 | * @channel: Host channel currently processing transfers for this QH |
307 | * @qh_list_entry: Entry for QH in either the periodic or non-periodic | 313 | * @qh_list_entry: Entry for QH in either the periodic or non-periodic |
@@ -350,6 +356,8 @@ struct dwc2_qh { | |||
350 | struct dwc2_hs_transfer_time hs_transfers[DWC2_HS_SCHEDULE_UFRAMES]; | 356 | struct dwc2_hs_transfer_time hs_transfers[DWC2_HS_SCHEDULE_UFRAMES]; |
351 | u32 ls_start_schedule_slice; | 357 | u32 ls_start_schedule_slice; |
352 | u16 ntd; | 358 | u16 ntd; |
359 | u8 *dw_align_buf; | ||
360 | dma_addr_t dw_align_buf_dma; | ||
353 | struct list_head qtd_list; | 361 | struct list_head qtd_list; |
354 | struct dwc2_host_chan *channel; | 362 | struct dwc2_host_chan *channel; |
355 | struct list_head qh_list_entry; | 363 | struct list_head qh_list_entry; |
diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c index fbea5e3fb947..f3429ac4a6bb 100644 --- a/drivers/usb/dwc2/hcd_intr.c +++ b/drivers/usb/dwc2/hcd_intr.c | |||
@@ -950,6 +950,14 @@ static int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg, | |||
950 | 950 | ||
951 | frame_desc->actual_length += len; | 951 | frame_desc->actual_length += len; |
952 | 952 | ||
953 | if (chan->align_buf) { | ||
954 | dev_vdbg(hsotg->dev, "non-aligned buffer\n"); | ||
955 | dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma, | ||
956 | DWC2_KMEM_UNALIGNED_BUF_SIZE, DMA_FROM_DEVICE); | ||
957 | memcpy(qtd->urb->buf + (chan->xfer_dma - qtd->urb->dma), | ||
958 | chan->qh->dw_align_buf, len); | ||
959 | } | ||
960 | |||
953 | qtd->isoc_split_offset += len; | 961 | qtd->isoc_split_offset += len; |
954 | 962 | ||
955 | hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum)); | 963 | hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum)); |
diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index 9c55d1addba9..301ced1618f8 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c | |||
@@ -1696,6 +1696,9 @@ void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) | |||
1696 | 1696 | ||
1697 | if (qh->desc_list) | 1697 | if (qh->desc_list) |
1698 | dwc2_hcd_qh_free_ddma(hsotg, qh); | 1698 | dwc2_hcd_qh_free_ddma(hsotg, qh); |
1699 | else if (hsotg->unaligned_cache && qh->dw_align_buf) | ||
1700 | kmem_cache_free(hsotg->unaligned_cache, qh->dw_align_buf); | ||
1701 | |||
1699 | kfree(qh); | 1702 | kfree(qh); |
1700 | } | 1703 | } |
1701 | 1704 | ||