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