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 */
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,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;
}

View File

@ -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;

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)
{
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);
}