dwc2_hc_setup_align_buf() does a DMA allocation if it needs to allocate a buffer to handle non-aligned transfers. Pass the gfp_t flags down the call chain to this function, instead of hard-coding a GFP_ATOMIC allocation. Also reduce the size of the 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@xxxxxxxxxxxx> --- drivers/usb/dwc2/hcd.c | 34 +++++++++++++++++++++------------- drivers/usb/dwc2/hcd.h | 6 ++++-- drivers/usb/dwc2/hcd_ddma.c | 2 +- drivers/usb/dwc2/hcd_intr.c | 4 ++-- drivers/usb/dwc2/hcd_queue.c | 16 ++++------------ 5 files changed, 32 insertions(+), 30 deletions(-) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 4d918ed..6a9d1c1 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -404,7 +404,7 @@ static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg, return 0; spin_lock_irqsave(&hsotg->lock, flags); - tr_type = dwc2_hcd_select_transactions(hsotg); + tr_type = dwc2_hcd_select_transactions(hsotg, mem_flags); if (tr_type != DWC2_TRANSACTION_NONE) dwc2_hcd_queue_transactions(hsotg, tr_type); spin_unlock_irqrestore(&hsotg->lock, flags); @@ -697,21 +697,27 @@ static void *dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg, } static int dwc2_hc_setup_align_buf(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, - struct dwc2_host_chan *chan, void *bufptr) + struct dwc2_host_chan *chan, + struct dwc2_hcd_urb *urb, void *bufptr, + gfp_t mem_flags) { u32 buf_size; - if (chan->ep_type != USB_ENDPOINT_XFER_ISOC) - buf_size = hsotg->core_params->max_transfer_size; - else - buf_size = 4096; - if (!qh->dw_align_buf) { + if (chan->ep_type != USB_ENDPOINT_XFER_ISOC) + buf_size = hsotg->core_params->max_transfer_size; + else + /* 3072 = 3 max-size Isoc packets */ + buf_size = 3072; + qh->dw_align_buf = dma_alloc_coherent(hsotg->dev, buf_size, &qh->dw_align_buf_dma, - GFP_ATOMIC); + mem_flags); if (!qh->dw_align_buf) return -ENOMEM; + qh->dw_align_buf_size = buf_size; + } else { + buf_size = qh->dw_align_buf_size; } if (!chan->ep_is_in && chan->xfer_len) { @@ -735,7 +741,8 @@ static int dwc2_hc_setup_align_buf(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, * @qh: Transactions from the first QTD for this QH are selected and assigned * to a free host channel */ -static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) +static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, + gfp_t mem_flags) { struct dwc2_host_chan *chan; struct dwc2_hcd_urb *urb; @@ -828,7 +835,8 @@ static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) /* Non DWORD-aligned buffer case */ if (bufptr) { dev_vdbg(hsotg->dev, "Non-aligned buffer\n"); - if (dwc2_hc_setup_align_buf(hsotg, qh, chan, bufptr)) { + if (dwc2_hc_setup_align_buf(hsotg, qh, chan, urb, bufptr, + mem_flags)) { dev_err(hsotg->dev, "%s: Failed to allocate memory to handle non-dword aligned buffer\n", __func__); @@ -872,7 +880,7 @@ static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) * Return: The types of new transactions that were assigned to host channels */ enum dwc2_transaction_type dwc2_hcd_select_transactions( - struct dwc2_hsotg *hsotg) + struct dwc2_hsotg *hsotg, gfp_t mem_flags) { enum dwc2_transaction_type ret_val = DWC2_TRANSACTION_NONE; struct list_head *qh_ptr; @@ -894,7 +902,7 @@ enum dwc2_transaction_type dwc2_hcd_select_transactions( hsotg->available_host_channels--; } qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry); - if (dwc2_assign_and_init_hc(hsotg, qh)) + if (dwc2_assign_and_init_hc(hsotg, qh, mem_flags)) break; /* @@ -927,7 +935,7 @@ enum dwc2_transaction_type dwc2_hcd_select_transactions( hsotg->available_host_channels--; } - if (dwc2_assign_and_init_hc(hsotg, qh)) + if (dwc2_assign_and_init_hc(hsotg, qh, mem_flags)) break; /* diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h index fdc6d48..efd48e2 100644 --- a/drivers/usb/dwc2/hcd.h +++ b/drivers/usb/dwc2/hcd.h @@ -243,7 +243,8 @@ enum dwc2_transaction_type { * @ntd: Actual number of transfer descriptors in a list * @dw_align_buf: Used instead of original buffer if its physical address * is not dword-aligned - * @dw_align_buf_dma: DMA address for align_buf + * @dw_align_buf_size: Size of dw_align_buf + * @dw_align_buf_dma: DMA address for dw_align_buf * @qtd_list: List of QTDs for this QH * @channel: Host channel currently processing transfers for this QH * @qh_list_entry: Entry for QH in either the periodic or non-periodic @@ -276,6 +277,7 @@ struct dwc2_qh { u16 start_split_frame; u16 ntd; u8 *dw_align_buf; + int dw_align_buf_size; dma_addr_t dw_align_buf_dma; struct list_head qtd_list; struct dwc2_host_chan *channel; @@ -459,7 +461,7 @@ extern int dwc2_get_hwparams(struct dwc2_hsotg *hsotg); /* Transaction Execution Functions */ extern enum dwc2_transaction_type dwc2_hcd_select_transactions( - struct dwc2_hsotg *hsotg); + struct dwc2_hsotg *hsotg, gfp_t mem_flags); extern void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg, enum dwc2_transaction_type tr_type); diff --git a/drivers/usb/dwc2/hcd_ddma.c b/drivers/usb/dwc2/hcd_ddma.c index 3376177..9ead1f1 100644 --- a/drivers/usb/dwc2/hcd_ddma.c +++ b/drivers/usb/dwc2/hcd_ddma.c @@ -1199,7 +1199,7 @@ void dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg, } } - tr_type = dwc2_hcd_select_transactions(hsotg); + tr_type = dwc2_hcd_select_transactions(hsotg, GFP_ATOMIC); if (tr_type != DWC2_TRANSACTION_NONE || continue_isoc_xfer) { if (continue_isoc_xfer) { if (tr_type == DWC2_TRANSACTION_NONE) diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c index f06249c..fd6699d 100644 --- a/drivers/usb/dwc2/hcd_intr.c +++ b/drivers/usb/dwc2/hcd_intr.c @@ -143,7 +143,7 @@ static void dwc2_sof_intr(struct dwc2_hsotg *hsotg) list_move(&qh->qh_list_entry, &hsotg->periodic_sched_ready); } - tr_type = dwc2_hcd_select_transactions(hsotg); + tr_type = dwc2_hcd_select_transactions(hsotg, GFP_ATOMIC); if (tr_type != DWC2_TRANSACTION_NONE) dwc2_hcd_queue_transactions(hsotg, tr_type); @@ -772,7 +772,7 @@ cleanup: writel(haintmsk, hsotg->regs + HAINTMSK); /* Try to queue more transfers now that there's a free channel */ - tr_type = dwc2_hcd_select_transactions(hsotg); + tr_type = dwc2_hcd_select_transactions(hsotg, GFP_ATOMIC); if (tr_type != DWC2_TRANSACTION_NONE) dwc2_hcd_queue_transactions(hsotg, tr_type); } diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index 9540f7e..bb97838 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c @@ -229,19 +229,11 @@ static struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg, */ void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) { - u32 buf_size; - - if (hsotg->core_params->dma_desc_enable > 0) { + if (hsotg->core_params->dma_desc_enable > 0) dwc2_hcd_qh_free_ddma(hsotg, qh); - } else if (qh->dw_align_buf) { - if (qh->ep_type == USB_ENDPOINT_XFER_ISOC) - buf_size = 4096; - else - buf_size = hsotg->core_params->max_transfer_size; - dma_free_coherent(hsotg->dev, buf_size, qh->dw_align_buf, - qh->dw_align_buf_dma); - } - + else if (qh->dw_align_buf) + dma_free_coherent(hsotg->dev, qh->dw_align_buf_size, + qh->dw_align_buf, qh->dw_align_buf_dma); kfree(qh); } -- 2.1.0.24.g4109c28 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html