diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-05-25 05:51:19 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-07-01 09:15:51 -0400 |
commit | a936e793136b4238ef287cfbbdd25ebb78214529 (patch) | |
tree | ca2d59b06aa7f3cb9c5830b77eaf00375c980f1b /drivers/dma | |
parent | 5e2479bd0e0dc41f2b9f6b4345bc5d4557837056 (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.c | 30 |
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 | ||