usb: dwc2: host: don't use dma_alloc_coherent with irqs disabled

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>
This commit is contained in:
Gregory Herrero 2015-04-29 22:09:16 +02:00 committed by Felipe Balbi
parent 33ad261aa6
commit db62b9a804
3 changed files with 54 additions and 22 deletions

View 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 */ /* 3072 = 3 max-size Isoc packets */
buf_size = 3072; buf_size = 3072;
qh->dw_align_buf = dma_alloc_coherent(hsotg->dev, buf_size, qh->dw_align_buf = kmalloc(buf_size, GFP_ATOMIC | GFP_DMA);
&qh->dw_align_buf_dma,
GFP_ATOMIC);
if (!qh->dw_align_buf) if (!qh->dw_align_buf)
return -ENOMEM; return -ENOMEM;
qh->dw_align_buf_size = buf_size; 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; chan->align_buf = qh->dw_align_buf_dma;
return 0; return 0;
} }

View File

@ -466,10 +466,15 @@ static int dwc2_update_urb_state(struct dwc2_hsotg *hsotg,
} }
/* Non DWORD-aligned buffer case handling */ /* 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__); dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf, dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
xfer_length); 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", 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); chan, chnum, qtd, halt_status, NULL);
/* Non DWORD-aligned buffer case handling */ /* Non DWORD-aligned buffer case handling */
if (chan->align_buf && frame_desc->actual_length && if (chan->align_buf && frame_desc->actual_length) {
chan->ep_is_in) {
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
__func__); __func__);
memcpy(urb->buf + frame_desc->offset + dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
qtd->isoc_split_offset, chan->qh->dw_align_buf, chan->qh->dw_align_buf_size,
frame_desc->actual_length); 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; break;
case DWC2_HC_XFER_FRAME_OVERRUN: 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); chan, chnum, qtd, halt_status, NULL);
/* Non DWORD-aligned buffer case handling */ /* Non DWORD-aligned buffer case handling */
if (chan->align_buf && frame_desc->actual_length && if (chan->align_buf && frame_desc->actual_length) {
chan->ep_is_in) {
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
__func__); __func__);
memcpy(urb->buf + frame_desc->offset + dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
qtd->isoc_split_offset, chan->qh->dw_align_buf, chan->qh->dw_align_buf_size,
frame_desc->actual_length); 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 */ /* Skip whole frame */
@ -926,6 +941,8 @@ static int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg,
if (chan->align_buf) { if (chan->align_buf) {
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__); 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 + memcpy(qtd->urb->buf + frame_desc->offset +
qtd->isoc_split_offset, chan->qh->dw_align_buf, len); 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 */ /* Non DWORD-aligned buffer case handling */
if (chan->align_buf && xfer_length && chan->ep_is_in) { if (chan->align_buf && xfer_length && chan->ep_is_in) {
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__); dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf, dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
xfer_length); 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; urb->actual_length += xfer_length;

View 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) 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); dwc2_hcd_qh_free_ddma(hsotg, qh);
else if (qh->dw_align_buf) } else {
dma_free_coherent(hsotg->dev, qh->dw_align_buf_size, /* kfree(NULL) is safe */
qh->dw_align_buf, qh->dw_align_buf_dma); kfree(qh->dw_align_buf);
qh->dw_align_buf_dma = (dma_addr_t)0;
}
kfree(qh); kfree(qh);
} }