Skip to content

Commit

Permalink
usb: dwc2: host: don't use dma_alloc_coherent with irqs disabled
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Gregory Herrero authored and Felipe Balbi committed Apr 29, 2015
1 parent 33ad261 commit db62b9a
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 22 deletions.
13 changes: 10 additions & 3 deletions drivers/usb/dwc2/hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down
53 changes: 38 additions & 15 deletions drivers/usb/dwc2/hcd_intr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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:
Expand All @@ -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 */
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
Expand Down
10 changes: 6 additions & 4 deletions drivers/usb/dwc2/hcd_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down

0 comments on commit db62b9a

Please sign in to comment.