diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-05-26 09:42:23 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-07-01 09:16:01 -0400 |
commit | 18536134abd6b8157d5cb11162606cc264d07232 (patch) | |
tree | da683ed8dd00138ac23884ebfaae1d4dccfb763d /drivers/dma/amba-pl08x.c | |
parent | 879f127bb2d0b604cf49f7682c0431d47f42f8f9 (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.c | 135 |
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 | */ |
177 | struct pl08x_txd { | 178 | struct 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 { | |||
227 | struct pl08x_dma_chan { | 226 | struct 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 | ||
1084 | static 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 | |||
1112 | static 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 | |||
1087 | static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x, | 1130 | static 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 | ||
1603 | static 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 | |||
1631 | static 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 | |||
1665 | static irqreturn_t pl08x_irq(int irq, void *dev) | 1643 | static 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", |