aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/amba-pl08x.c
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2012-05-26 09:42:23 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2012-07-01 09:16:01 -0400
commit18536134abd6b8157d5cb11162606cc264d07232 (patch)
treeda683ed8dd00138ac23884ebfaae1d4dccfb763d /drivers/dma/amba-pl08x.c
parent879f127bb2d0b604cf49f7682c0431d47f42f8f9 (diff)
dmaengine: PL08x: convert to use vchan done list
Convert to use the virtual dma channel done list, tasklet, and descriptor freeing. 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/amba-pl08x.c')
-rw-r--r--drivers/dma/amba-pl08x.c135
1 files changed, 54 insertions, 81 deletions
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 5333a91518ed..6a35e37d14bc 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -167,16 +167,16 @@ struct pl08x_sg {
167/** 167/**
168 * struct pl08x_txd - wrapper for struct dma_async_tx_descriptor 168 * struct pl08x_txd - wrapper for struct dma_async_tx_descriptor
169 * @vd: virtual DMA descriptor 169 * @vd: virtual DMA descriptor
170 * @node: node for txd list for channels
171 * @dsg_list: list of children sg's 170 * @dsg_list: list of children sg's
172 * @llis_bus: DMA memory address (physical) start for the LLIs 171 * @llis_bus: DMA memory address (physical) start for the LLIs
173 * @llis_va: virtual memory address start for the LLIs 172 * @llis_va: virtual memory address start for the LLIs
174 * @cctl: control reg values for current txd 173 * @cctl: control reg values for current txd
175 * @ccfg: config reg values for current txd 174 * @ccfg: config reg values for current txd
175 * @done: this marks completed descriptors, which should not have their
176 * mux released.
176 */ 177 */
177struct pl08x_txd { 178struct pl08x_txd {
178 struct virt_dma_desc vd; 179 struct virt_dma_desc vd;
179 struct list_head node;
180 struct list_head dsg_list; 180 struct list_head dsg_list;
181 dma_addr_t llis_bus; 181 dma_addr_t llis_bus;
182 struct pl08x_lli *llis_va; 182 struct pl08x_lli *llis_va;
@@ -187,6 +187,7 @@ struct pl08x_txd {
187 * trigger this txd. Other registers are in llis_va[0]. 187 * trigger this txd. Other registers are in llis_va[0].
188 */ 188 */
189 u32 ccfg; 189 u32 ccfg;
190 bool done;
190}; 191};
191 192
192/** 193/**
@@ -211,11 +212,9 @@ enum pl08x_dma_chan_state {
211 * struct pl08x_dma_chan - this structure wraps a DMA ENGINE channel 212 * struct pl08x_dma_chan - this structure wraps a DMA ENGINE channel
212 * @vc: wrappped virtual channel 213 * @vc: wrappped virtual channel
213 * @phychan: the physical channel utilized by this channel, if there is one 214 * @phychan: the physical channel utilized by this channel, if there is one
214 * @tasklet: tasklet scheduled by the IRQ to handle actual work etc
215 * @name: name of channel 215 * @name: name of channel
216 * @cd: channel platform data 216 * @cd: channel platform data
217 * @runtime_addr: address for RX/TX according to the runtime config 217 * @runtime_addr: address for RX/TX according to the runtime config
218 * @done_list: list of completed transactions
219 * @at: active transaction on this channel 218 * @at: active transaction on this channel
220 * @lock: a lock for this channel data 219 * @lock: a lock for this channel data
221 * @host: a pointer to the host (internal use) 220 * @host: a pointer to the host (internal use)
@@ -227,11 +226,9 @@ enum pl08x_dma_chan_state {
227struct pl08x_dma_chan { 226struct pl08x_dma_chan {
228 struct virt_dma_chan vc; 227 struct virt_dma_chan vc;
229 struct pl08x_phy_chan *phychan; 228 struct pl08x_phy_chan *phychan;
230 struct tasklet_struct tasklet;
231 const char *name; 229 const char *name;
232 const struct pl08x_channel_data *cd; 230 const struct pl08x_channel_data *cd;
233 struct dma_slave_config cfg; 231 struct dma_slave_config cfg;
234 struct list_head done_list;
235 struct pl08x_txd *at; 232 struct pl08x_txd *at;
236 struct pl08x_driver_data *host; 233 struct pl08x_driver_data *host;
237 enum pl08x_dma_chan_state state; 234 enum pl08x_dma_chan_state state;
@@ -1084,6 +1081,52 @@ static void pl08x_free_txd(struct pl08x_driver_data *pl08x,
1084 kfree(txd); 1081 kfree(txd);
1085} 1082}
1086 1083
1084static void pl08x_unmap_buffers(struct pl08x_txd *txd)
1085{
1086 struct device *dev = txd->vd.tx.chan->device->dev;
1087 struct pl08x_sg *dsg;
1088
1089 if (!(txd->vd.tx.flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
1090 if (txd->vd.tx.flags & DMA_COMPL_SRC_UNMAP_SINGLE)
1091 list_for_each_entry(dsg, &txd->dsg_list, node)
1092 dma_unmap_single(dev, dsg->src_addr, dsg->len,
1093 DMA_TO_DEVICE);
1094 else {
1095 list_for_each_entry(dsg, &txd->dsg_list, node)
1096 dma_unmap_page(dev, dsg->src_addr, dsg->len,
1097 DMA_TO_DEVICE);
1098 }
1099 }
1100 if (!(txd->vd.tx.flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
1101 if (txd->vd.tx.flags & DMA_COMPL_DEST_UNMAP_SINGLE)
1102 list_for_each_entry(dsg, &txd->dsg_list, node)
1103 dma_unmap_single(dev, dsg->dst_addr, dsg->len,
1104 DMA_FROM_DEVICE);
1105 else
1106 list_for_each_entry(dsg, &txd->dsg_list, node)
1107 dma_unmap_page(dev, dsg->dst_addr, dsg->len,
1108 DMA_FROM_DEVICE);
1109 }
1110}
1111
1112static void pl08x_desc_free(struct virt_dma_desc *vd)
1113{
1114 struct pl08x_txd *txd = to_pl08x_txd(&vd->tx);
1115 struct pl08x_dma_chan *plchan = to_pl08x_chan(vd->tx.chan);
1116 struct pl08x_driver_data *pl08x = plchan->host;
1117 unsigned long flags;
1118
1119 if (!plchan->slave)
1120 pl08x_unmap_buffers(txd);
1121
1122 if (!txd->done)
1123 pl08x_release_mux(plchan);
1124
1125 spin_lock_irqsave(&pl08x->lock, flags);
1126 pl08x_free_txd(plchan->host, txd);
1127 spin_unlock_irqrestore(&pl08x->lock, flags);
1128}
1129
1087static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x, 1130static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x,
1088 struct pl08x_dma_chan *plchan) 1131 struct pl08x_dma_chan *plchan)
1089{ 1132{
@@ -1094,9 +1137,8 @@ static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x,
1094 1137
1095 while (!list_empty(&head)) { 1138 while (!list_empty(&head)) {
1096 txd = list_first_entry(&head, struct pl08x_txd, vd.node); 1139 txd = list_first_entry(&head, struct pl08x_txd, vd.node);
1097 pl08x_release_mux(plchan);
1098 list_del(&txd->vd.node); 1140 list_del(&txd->vd.node);
1099 pl08x_free_txd(pl08x, txd); 1141 pl08x_desc_free(&txd->vd);
1100 } 1142 }
1101} 1143}
1102 1144
@@ -1541,9 +1583,7 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
1541 } 1583 }
1542 /* Dequeue jobs and free LLIs */ 1584 /* Dequeue jobs and free LLIs */
1543 if (plchan->at) { 1585 if (plchan->at) {
1544 /* Killing this one off, release its mux */ 1586 pl08x_desc_free(&plchan->at->vd);
1545 pl08x_release_mux(plchan);
1546 pl08x_free_txd(pl08x, plchan->at);
1547 plchan->at = NULL; 1587 plchan->at = NULL;
1548 } 1588 }
1549 /* Dequeue jobs not yet fired as well */ 1589 /* Dequeue jobs not yet fired as well */
@@ -1600,68 +1640,6 @@ static void pl08x_ensure_on(struct pl08x_driver_data *pl08x)
1600 writel(PL080_CONFIG_ENABLE, pl08x->base + PL080_CONFIG); 1640 writel(PL080_CONFIG_ENABLE, pl08x->base + PL080_CONFIG);
1601} 1641}
1602 1642
1603static void pl08x_unmap_buffers(struct pl08x_txd *txd)
1604{
1605 struct device *dev = txd->vd.tx.chan->device->dev;
1606 struct pl08x_sg *dsg;
1607
1608 if (!(txd->vd.tx.flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
1609 if (txd->vd.tx.flags & DMA_COMPL_SRC_UNMAP_SINGLE)
1610 list_for_each_entry(dsg, &txd->dsg_list, node)
1611 dma_unmap_single(dev, dsg->src_addr, dsg->len,
1612 DMA_TO_DEVICE);
1613 else {
1614 list_for_each_entry(dsg, &txd->dsg_list, node)
1615 dma_unmap_page(dev, dsg->src_addr, dsg->len,
1616 DMA_TO_DEVICE);
1617 }
1618 }
1619 if (!(txd->vd.tx.flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
1620 if (txd->vd.tx.flags & DMA_COMPL_DEST_UNMAP_SINGLE)
1621 list_for_each_entry(dsg, &txd->dsg_list, node)
1622 dma_unmap_single(dev, dsg->dst_addr, dsg->len,
1623 DMA_FROM_DEVICE);
1624 else
1625 list_for_each_entry(dsg, &txd->dsg_list, node)
1626 dma_unmap_page(dev, dsg->dst_addr, dsg->len,
1627 DMA_FROM_DEVICE);
1628 }
1629}
1630
1631static void pl08x_tasklet(unsigned long data)
1632{
1633 struct pl08x_dma_chan *plchan = (struct pl08x_dma_chan *) data;
1634 struct pl08x_driver_data *pl08x = plchan->host;
1635 unsigned long flags;
1636 LIST_HEAD(head);
1637
1638 spin_lock_irqsave(&plchan->vc.lock, flags);
1639 list_splice_tail_init(&plchan->done_list, &head);
1640 spin_unlock_irqrestore(&plchan->vc.lock, flags);
1641
1642 while (!list_empty(&head)) {
1643 struct pl08x_txd *txd = list_first_entry(&head,
1644 struct pl08x_txd, node);
1645 dma_async_tx_callback callback = txd->vd.tx.callback;
1646 void *callback_param = txd->vd.tx.callback_param;
1647
1648 list_del(&txd->node);
1649
1650 /* Don't try to unmap buffers on slave channels */
1651 if (!plchan->slave)
1652 pl08x_unmap_buffers(txd);
1653
1654 /* Free the descriptor */
1655 spin_lock_irqsave(&plchan->vc.lock, flags);
1656 pl08x_free_txd(pl08x, txd);
1657 spin_unlock_irqrestore(&plchan->vc.lock, flags);
1658
1659 /* Callback to signal completion */
1660 if (callback)
1661 callback(callback_param);
1662 }
1663}
1664
1665static irqreturn_t pl08x_irq(int irq, void *dev) 1643static irqreturn_t pl08x_irq(int irq, void *dev)
1666{ 1644{
1667 struct pl08x_driver_data *pl08x = dev; 1645 struct pl08x_driver_data *pl08x = dev;
@@ -1704,8 +1682,8 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
1704 * reservation. 1682 * reservation.
1705 */ 1683 */
1706 pl08x_release_mux(plchan); 1684 pl08x_release_mux(plchan);
1707 dma_cookie_complete(&tx->vd.tx); 1685 tx->done = true;
1708 list_add_tail(&tx->node, &plchan->done_list); 1686 vchan_cookie_complete(&tx->vd);
1709 1687
1710 /* 1688 /*
1711 * And start the next descriptor (if any), 1689 * And start the next descriptor (if any),
@@ -1718,8 +1696,6 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
1718 } 1696 }
1719 spin_unlock(&plchan->vc.lock); 1697 spin_unlock(&plchan->vc.lock);
1720 1698
1721 /* Schedule tasklet on this channel */
1722 tasklet_schedule(&plchan->tasklet);
1723 mask |= (1 << i); 1699 mask |= (1 << i);
1724 } 1700 }
1725 } 1701 }
@@ -1779,10 +1755,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
1779 "initialize virtual channel \"%s\"\n", 1755 "initialize virtual channel \"%s\"\n",
1780 chan->name); 1756 chan->name);
1781 1757
1782 INIT_LIST_HEAD(&chan->done_list); 1758 chan->vc.desc_free = pl08x_desc_free;
1783 tasklet_init(&chan->tasklet, pl08x_tasklet,
1784 (unsigned long) chan);
1785
1786 vchan_init(&chan->vc, dmadev); 1759 vchan_init(&chan->vc, dmadev);
1787 } 1760 }
1788 dev_info(&pl08x->adev->dev, "initialized %d virtual %s channels\n", 1761 dev_info(&pl08x->adev->dev, "initialized %d virtual %s channels\n",