On Mon, Mar 23, 2015 at 8:22 AM, Mian Yousaf Kaukab
<[email protected]> wrote:
> From: Gregory Herrero <[email protected]>
>
> 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 <[email protected]>
> ---
> 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 <[email protected]>
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html