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 <pa...@synopsys.com>
---
 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to