usb: dwc2: host: don't use dma_alloc_coherent with irqs disabled
authorGregory Herrero <gregory.herrero@intel.com>
Wed, 29 Apr 2015 20:09:16 +0000 (22:09 +0200)
committerFelipe Balbi <balbi@ti.com>
Wed, 29 Apr 2015 20:20:00 +0000 (15:20 -0500)
Align buffer must be allocated using kmalloc since irqs are disabled.
Coherency is handled through dma_map_single which can be used with irqs
disabled.

Reviewed-by: Julius Werner <jwerner@chromium.org>
Acked-by: John Youn <johnyoun@synopsys.com>
Signed-off-by: Gregory Herrero <gregory.herrero@intel.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/dwc2/hcd.c
drivers/usb/dwc2/hcd_intr.c
drivers/usb/dwc2/hcd_queue.c

index d72557cfc05280f53e66acf7298fef9c8c578955..745230d0d8b31091b0297608042aa28572d6872d 100644 (file)
@@ -719,9 +719,7 @@ static int dwc2_hc_setup_align_buf(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
                        /* 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);
+               qh->dw_align_buf = kmalloc(buf_size, GFP_ATOMIC | GFP_DMA);
                if (!qh->dw_align_buf)
                        return -ENOMEM;
                qh->dw_align_buf_size = buf_size;
@@ -746,6 +744,15 @@ static int dwc2_hc_setup_align_buf(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
                }
        }
 
+       qh->dw_align_buf_dma = dma_map_single(hsotg->dev,
+                       qh->dw_align_buf, qh->dw_align_buf_size,
+                       chan->ep_is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+       if (dma_mapping_error(hsotg->dev, qh->dw_align_buf_dma)) {
+               dev_err(hsotg->dev, "can't map align_buf\n");
+               chan->align_buf = (dma_addr_t)NULL;
+               return -EINVAL;
+       }
+
        chan->align_buf = qh->dw_align_buf_dma;
        return 0;
 }
index 6927bba86245844748e57e8d517bb3c2764d8763..6ea8eb6899f4d0716209b935a92e9366193703fa 100644 (file)
@@ -466,10 +466,15 @@ 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) {
+       if (chan->align_buf && xfer_length) {
                dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
-               memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
-                      xfer_length);
+               dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
+                               chan->qh->dw_align_buf_size,
+                               chan->ep_is_in ?
+                               DMA_FROM_DEVICE : DMA_TO_DEVICE);
+               if (chan->ep_is_in)
+                       memcpy(urb->buf + urb->actual_length,
+                                       chan->qh->dw_align_buf, xfer_length);
        }
 
        dev_vdbg(hsotg->dev, "urb->actual_length=%d xfer_length=%d\n",
@@ -555,13 +560,18 @@ static enum dwc2_halt_status dwc2_update_isoc_urb_state(
                                        chan, chnum, qtd, halt_status, NULL);
 
                /* Non DWORD-aligned buffer case handling */
-               if (chan->align_buf && frame_desc->actual_length &&
-                   chan->ep_is_in) {
+               if (chan->align_buf && frame_desc->actual_length) {
                        dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
                                 __func__);
-                       memcpy(urb->buf + frame_desc->offset +
-                              qtd->isoc_split_offset, chan->qh->dw_align_buf,
-                              frame_desc->actual_length);
+                       dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
+                                       chan->qh->dw_align_buf_size,
+                                       chan->ep_is_in ?
+                                       DMA_FROM_DEVICE : DMA_TO_DEVICE);
+                       if (chan->ep_is_in)
+                               memcpy(urb->buf + frame_desc->offset +
+                                       qtd->isoc_split_offset,
+                                       chan->qh->dw_align_buf,
+                                       frame_desc->actual_length);
                }
                break;
        case DWC2_HC_XFER_FRAME_OVERRUN:
@@ -584,13 +594,18 @@ static enum dwc2_halt_status dwc2_update_isoc_urb_state(
                                        chan, chnum, qtd, halt_status, NULL);
 
                /* Non DWORD-aligned buffer case handling */
-               if (chan->align_buf && frame_desc->actual_length &&
-                   chan->ep_is_in) {
+               if (chan->align_buf && frame_desc->actual_length) {
                        dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
                                 __func__);
-                       memcpy(urb->buf + frame_desc->offset +
-                              qtd->isoc_split_offset, chan->qh->dw_align_buf,
-                              frame_desc->actual_length);
+                       dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
+                                       chan->qh->dw_align_buf_size,
+                                       chan->ep_is_in ?
+                                       DMA_FROM_DEVICE : DMA_TO_DEVICE);
+                       if (chan->ep_is_in)
+                               memcpy(urb->buf + frame_desc->offset +
+                                       qtd->isoc_split_offset,
+                                       chan->qh->dw_align_buf,
+                                       frame_desc->actual_length);
                }
 
                /* Skip whole frame */
@@ -926,6 +941,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_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
+                               chan->qh->dw_align_buf_size, DMA_FROM_DEVICE);
                memcpy(qtd->urb->buf + frame_desc->offset +
                       qtd->isoc_split_offset, chan->qh->dw_align_buf, len);
        }
@@ -1155,8 +1172,14 @@ 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__);
-               memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
-                      xfer_length);
+               dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
+                               chan->qh->dw_align_buf_size,
+                               chan->ep_is_in ?
+                               DMA_FROM_DEVICE : DMA_TO_DEVICE);
+               if (chan->ep_is_in)
+                       memcpy(urb->buf + urb->actual_length,
+                                       chan->qh->dw_align_buf,
+                                       xfer_length);
        }
 
        urb->actual_length += xfer_length;
index 63207dc3cb22920319af022001495599e04e4398..9b5c36256627b0b163fb25fc7549c46e1944ed35 100644 (file)
@@ -229,11 +229,13 @@ 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)
 {
-       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)
-               dma_free_coherent(hsotg->dev, qh->dw_align_buf_size,
-                                 qh->dw_align_buf, qh->dw_align_buf_dma);
+       } else {
+               /* kfree(NULL) is safe */
+               kfree(qh->dw_align_buf);
+               qh->dw_align_buf_dma = (dma_addr_t)0;
+       }
        kfree(qh);
 }