aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2012-05-25 05:51:19 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2012-07-01 09:15:51 -0400
commita936e793136b4238ef287cfbbdd25ebb78214529 (patch)
treeca2d59b06aa7f3cb9c5830b77eaf00375c980f1b /drivers/dma
parent5e2479bd0e0dc41f2b9f6b4345bc5d4557837056 (diff)
dmaengine: PL08x: convert to a list of completed descriptors
Convert PL08x to use a list of completed descriptors rather than merely relying upon a single pointer. This makes it possible to schedule the tasklet for other purposes, and makes our behaviour similar to virt-dma. Acked-by: Linus Walleij <linus.walleij@linaro.org> Tested-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/amba-pl08x.c30
1 files changed, 20 insertions, 10 deletions
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index ac9fdccb2c19..54e3eb0b3723 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -219,6 +219,7 @@ enum pl08x_dma_chan_state {
219 * @cd: channel platform data 219 * @cd: channel platform data
220 * @runtime_addr: address for RX/TX according to the runtime config 220 * @runtime_addr: address for RX/TX according to the runtime config
221 * @pend_list: queued transactions pending on this channel 221 * @pend_list: queued transactions pending on this channel
222 * @done_list: list of completed transactions
222 * @at: active transaction on this channel 223 * @at: active transaction on this channel
223 * @lock: a lock for this channel data 224 * @lock: a lock for this channel data
224 * @host: a pointer to the host (internal use) 225 * @host: a pointer to the host (internal use)
@@ -238,6 +239,7 @@ struct pl08x_dma_chan {
238 const struct pl08x_channel_data *cd; 239 const struct pl08x_channel_data *cd;
239 struct dma_slave_config cfg; 240 struct dma_slave_config cfg;
240 struct list_head pend_list; 241 struct list_head pend_list;
242 struct list_head done_list;
241 struct pl08x_txd *at; 243 struct pl08x_txd *at;
242 spinlock_t lock; 244 spinlock_t lock;
243 struct pl08x_driver_data *host; 245 struct pl08x_driver_data *host;
@@ -1673,18 +1675,11 @@ static void pl08x_tasklet(unsigned long data)
1673{ 1675{
1674 struct pl08x_dma_chan *plchan = (struct pl08x_dma_chan *) data; 1676 struct pl08x_dma_chan *plchan = (struct pl08x_dma_chan *) data;
1675 struct pl08x_driver_data *pl08x = plchan->host; 1677 struct pl08x_driver_data *pl08x = plchan->host;
1676 struct pl08x_txd *txd;
1677 unsigned long flags; 1678 unsigned long flags;
1679 LIST_HEAD(head);
1678 1680
1679 spin_lock_irqsave(&plchan->lock, flags); 1681 spin_lock_irqsave(&plchan->lock, flags);
1680 1682 list_splice_tail_init(&plchan->done_list, &head);
1681 txd = plchan->at;
1682 plchan->at = NULL;
1683
1684 if (txd) {
1685 /* Update last completed */
1686 dma_cookie_complete(&txd->tx);
1687 }
1688 1683
1689 /* If a new descriptor is queued, set it up plchan->at is NULL here */ 1684 /* If a new descriptor is queued, set it up plchan->at is NULL here */
1690 if (!list_empty(&plchan->pend_list)) { 1685 if (!list_empty(&plchan->pend_list)) {
@@ -1739,10 +1734,14 @@ static void pl08x_tasklet(unsigned long data)
1739 1734
1740 spin_unlock_irqrestore(&plchan->lock, flags); 1735 spin_unlock_irqrestore(&plchan->lock, flags);
1741 1736
1742 if (txd) { 1737 while (!list_empty(&head)) {
1738 struct pl08x_txd *txd = list_first_entry(&head,
1739 struct pl08x_txd, node);
1743 dma_async_tx_callback callback = txd->tx.callback; 1740 dma_async_tx_callback callback = txd->tx.callback;
1744 void *callback_param = txd->tx.callback_param; 1741 void *callback_param = txd->tx.callback_param;
1745 1742
1743 list_del(&txd->node);
1744
1746 /* Don't try to unmap buffers on slave channels */ 1745 /* Don't try to unmap buffers on slave channels */
1747 if (!plchan->slave) 1746 if (!plchan->slave)
1748 pl08x_unmap_buffers(txd); 1747 pl08x_unmap_buffers(txd);
@@ -1782,6 +1781,7 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
1782 /* Locate physical channel */ 1781 /* Locate physical channel */
1783 struct pl08x_phy_chan *phychan = &pl08x->phy_chans[i]; 1782 struct pl08x_phy_chan *phychan = &pl08x->phy_chans[i];
1784 struct pl08x_dma_chan *plchan = phychan->serving; 1783 struct pl08x_dma_chan *plchan = phychan->serving;
1784 struct pl08x_txd *tx;
1785 1785
1786 if (!plchan) { 1786 if (!plchan) {
1787 dev_err(&pl08x->adev->dev, 1787 dev_err(&pl08x->adev->dev,
@@ -1790,6 +1790,15 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
1790 continue; 1790 continue;
1791 } 1791 }
1792 1792
1793 spin_lock(&plchan->lock);
1794 tx = plchan->at;
1795 if (tx) {
1796 plchan->at = NULL;
1797 dma_cookie_complete(&tx->tx);
1798 list_add_tail(&tx->node, &plchan->done_list);
1799 }
1800 spin_unlock(&plchan->lock);
1801
1793 /* Schedule tasklet on this channel */ 1802 /* Schedule tasklet on this channel */
1794 tasklet_schedule(&plchan->tasklet); 1803 tasklet_schedule(&plchan->tasklet);
1795 mask |= (1 << i); 1804 mask |= (1 << i);
@@ -1856,6 +1865,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
1856 1865
1857 spin_lock_init(&chan->lock); 1866 spin_lock_init(&chan->lock);
1858 INIT_LIST_HEAD(&chan->pend_list); 1867 INIT_LIST_HEAD(&chan->pend_list);
1868 INIT_LIST_HEAD(&chan->done_list);
1859 tasklet_init(&chan->tasklet, pl08x_tasklet, 1869 tasklet_init(&chan->tasklet, pl08x_tasklet,
1860 (unsigned long) chan); 1870 (unsigned long) chan);
1861 1871