Re: [PATCH v3 18/22] usb: dwc2: host: don't use dma_alloc_coherent with irqs disabled

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Mar 23, 2015 at 8:22 AM, Mian Yousaf Kaukab
<yousaf.kaukab@xxxxxxxxx> wrote:
> From: Gregory Herrero <gregory.herrero@xxxxxxxxx>
>
> 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.
>
> Signed-off-by: Gregory Herrero <gregory.herrero@xxxxxxxxx>
> ---
>  drivers/usb/dwc2/hcd.c       | 16 ++++++++++---
>  drivers/usb/dwc2/hcd_intr.c  | 53 +++++++++++++++++++++++++++++++-------------
>  drivers/usb/dwc2/hcd_queue.c |  7 +++---
>  3 files changed, 55 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
> index 763b63b..dec97cc 100644
> --- a/drivers/usb/dwc2/hcd.c
> +++ b/drivers/usb/dwc2/hcd.c
> @@ -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,18 @@ 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;
> +               dma_unmap_single(hsotg->dev, qh->dw_align_buf_dma,
> +                               qh->dw_align_buf_size, chan->ep_is_in ?
> +                               DMA_FROM_DEVICE : DMA_TO_DEVICE);

Judging from other examples in the kernel I think you're not supposed
to call dma_unmap_single() in this case. If dma_mapping_error() is
true, the mapping has failed and there is nothing to unmap.

> +               return -EINVAL;
> +       }
> +
>         chan->align_buf = qh->dw_align_buf_dma;
>         return 0;
>  }
> diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c
> index 6927bba..6ea8eb6 100644
> --- a/drivers/usb/dwc2/hcd_intr.c
> +++ b/drivers/usb/dwc2/hcd_intr.c
> @@ -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;
> diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c
> index 63207dc..3735ae6 100644
> --- a/drivers/usb/dwc2/hcd_queue.c
> +++ b/drivers/usb/dwc2/hcd_queue.c
> @@ -231,9 +231,10 @@ void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
>  {
>         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 if (qh->dw_align_buf) {
> +               kfree(qh->dw_align_buf);
> +               qh->dw_align_buf_dma = (dma_addr_t)0;
> +       }
>         kfree(qh);
>  }
>
> --
> 2.3.3

Otherwise, I think this looks good now, thanks!

Reviewed-by: Julius Werner <jwerner@xxxxxxxxxxxx>
--
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




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux