diff options
author | Russell King - ARM Linux | 2011-01-03 22:44:16 +0000 |
---|---|---|
committer | Dan Williams | 2011-01-04 19:16:14 -0800 |
commit | 3d992e1a6f8465db3921ef75bfc490fbd2f40cd3 (patch) | |
tree | 4d7935045ef1654777754360f319c093f5f041e8 /drivers/dma | |
parent | c04287948ec8308fceedda980373bc7d53620255 (diff) |
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 <rmk+kernel@arm.linux.org.uk>
Acked-by: Linus Walleij <linus.walleij@stericsson.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/dma')
-rw-r--r-- | drivers/dma/amba-pl08x.c | 52 |
1 files 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) |