From 3d992e1a6f8465db3921ef75bfc490fbd2f40cd3 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:44:16 +0000 Subject: [PATCH] ARM: PL08x: implement unmapping of memcpy buffers The DMA engine API requires DMA engine implementations to unmap buffers passed into the non-slave DMA methods unless the relevant completion flag is set. We aren't doing this, so implement this facility. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 52 ++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 00058e30a9c3..fb469dedcdf3 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1527,13 +1527,33 @@ static void pl08x_ensure_on(struct pl08x_driver_data *pl08x) writel(val, pl08x->base + PL080_CONFIG); } +static void pl08x_unmap_buffers(struct pl08x_txd *txd) +{ + struct device *dev = txd->tx.chan->device->dev; + + if (!(txd->tx.flags & DMA_COMPL_SKIP_SRC_UNMAP)) { + if (txd->tx.flags & DMA_COMPL_SRC_UNMAP_SINGLE) + dma_unmap_single(dev, txd->src_addr, txd->len, + DMA_TO_DEVICE); + else + dma_unmap_page(dev, txd->src_addr, txd->len, + DMA_TO_DEVICE); + } + if (!(txd->tx.flags & DMA_COMPL_SKIP_DEST_UNMAP)) { + if (txd->tx.flags & DMA_COMPL_DEST_UNMAP_SINGLE) + dma_unmap_single(dev, txd->dst_addr, txd->len, + DMA_FROM_DEVICE); + else + dma_unmap_page(dev, txd->dst_addr, txd->len, + DMA_FROM_DEVICE); + } +} + static void pl08x_tasklet(unsigned long data) { struct pl08x_dma_chan *plchan = (struct pl08x_dma_chan *) data; struct pl08x_driver_data *pl08x = plchan->host; struct pl08x_txd *txd; - dma_async_tx_callback callback = NULL; - void *callback_param = NULL; unsigned long flags; spin_lock_irqsave(&plchan->lock, flags); @@ -1542,18 +1562,10 @@ static void pl08x_tasklet(unsigned long data) plchan->at = NULL; if (txd) { - callback = txd->tx.callback; - callback_param = txd->tx.callback_param; - /* * Update last completed */ plchan->lc = txd->tx.cookie; - - /* - * Free the descriptor - */ - pl08x_free_txd(pl08x, txd); } /* * If a new descriptor is queued, set it up @@ -1605,9 +1617,23 @@ static void pl08x_tasklet(unsigned long data) spin_unlock_irqrestore(&plchan->lock, flags); - /* Callback to signal completion */ - if (callback) - callback(callback_param); + if (txd) { + dma_async_tx_callback callback = txd->tx.callback; + void *callback_param = txd->tx.callback_param; + + /* Don't try to unmap buffers on slave channels */ + if (!plchan->slave) + pl08x_unmap_buffers(txd); + + /* Free the descriptor */ + spin_lock_irqsave(&plchan->lock, flags); + pl08x_free_txd(pl08x, txd); + spin_unlock_irqrestore(&plchan->lock, flags); + + /* Callback to signal completion */ + if (callback) + callback(callback_param); + } } static irqreturn_t pl08x_irq(int irq, void *dev) -- 2.20.1