aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Jarzmik <robert.jarzmik@free.fr>2015-05-26 17:06:33 -0400
committerVinod Koul <vinod.koul@intel.com>2015-06-17 12:45:59 -0400
commitb9855f03d560d351e95301b9de0bc3cad3b31fe9 (patch)
treee13e2f35ed86239fdd3fbf882023daff6802ca5c
parente1031dc1f7ba5c8724ba211062134076df292791 (diff)
dmaengine: virt-dma: don't always free descriptor upon completion
This patch attempts to enhance the case of a transfer submitted multiple times, and where the cost of creating the descriptors chain is not negligible. This happens with big video buffers (several megabytes, ie. several thousands of linked descriptors in one scatter-gather list). In these cases, a video driver would want to do : - tx = dmaengine_prep_slave_sg() - dma_engine_submit(tx); - dma_async_issue_pending() - wait for video completion - read video data (or not, skipping a frame is also possible) - dma_engine_submit(tx) => here, the descriptors chain recalculation will take time => the dma coherent allocation over and over might create holes in the dma pool, which is counter-productive. - dma_async_issue_pending() - etc ... In order to cope with this case, virt-dma is modified to prevent freeing the descriptors upon completion if DMA_CTRL_ACK flag is set in the transfer. Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
-rw-r--r--drivers/dma/virt-dma.c19
-rw-r--r--drivers/dma/virt-dma.h13
2 files changed, 25 insertions, 7 deletions
diff --git a/drivers/dma/virt-dma.c b/drivers/dma/virt-dma.c
index 6f80432a3f0a..7d2c17d8d30f 100644
--- a/drivers/dma/virt-dma.c
+++ b/drivers/dma/virt-dma.c
@@ -29,7 +29,7 @@ dma_cookie_t vchan_tx_submit(struct dma_async_tx_descriptor *tx)
29 spin_lock_irqsave(&vc->lock, flags); 29 spin_lock_irqsave(&vc->lock, flags);
30 cookie = dma_cookie_assign(tx); 30 cookie = dma_cookie_assign(tx);
31 31
32 list_add_tail(&vd->node, &vc->desc_submitted); 32 list_move_tail(&vd->node, &vc->desc_submitted);
33 spin_unlock_irqrestore(&vc->lock, flags); 33 spin_unlock_irqrestore(&vc->lock, flags);
34 34
35 dev_dbg(vc->chan.device->dev, "vchan %p: txd %p[%x]: submitted\n", 35 dev_dbg(vc->chan.device->dev, "vchan %p: txd %p[%x]: submitted\n",
@@ -83,8 +83,10 @@ static void vchan_complete(unsigned long arg)
83 cb_data = vd->tx.callback_param; 83 cb_data = vd->tx.callback_param;
84 84
85 list_del(&vd->node); 85 list_del(&vd->node);
86 86 if (async_tx_test_ack(&vd->tx))
87 vc->desc_free(vd); 87 list_add(&vd->node, &vc->desc_allocated);
88 else
89 vc->desc_free(vd);
88 90
89 if (cb) 91 if (cb)
90 cb(cb_data); 92 cb(cb_data);
@@ -96,9 +98,13 @@ void vchan_dma_desc_free_list(struct virt_dma_chan *vc, struct list_head *head)
96 while (!list_empty(head)) { 98 while (!list_empty(head)) {
97 struct virt_dma_desc *vd = list_first_entry(head, 99 struct virt_dma_desc *vd = list_first_entry(head,
98 struct virt_dma_desc, node); 100 struct virt_dma_desc, node);
99 list_del(&vd->node); 101 if (async_tx_test_ack(&vd->tx)) {
100 dev_dbg(vc->chan.device->dev, "txd %p: freeing\n", vd); 102 list_move_tail(&vd->node, &vc->desc_allocated);
101 vc->desc_free(vd); 103 } else {
104 dev_dbg(vc->chan.device->dev, "txd %p: freeing\n", vd);
105 list_del(&vd->node);
106 vc->desc_free(vd);
107 }
102 } 108 }
103} 109}
104EXPORT_SYMBOL_GPL(vchan_dma_desc_free_list); 110EXPORT_SYMBOL_GPL(vchan_dma_desc_free_list);
@@ -108,6 +114,7 @@ void vchan_init(struct virt_dma_chan *vc, struct dma_device *dmadev)
108 dma_cookie_init(&vc->chan); 114 dma_cookie_init(&vc->chan);
109 115
110 spin_lock_init(&vc->lock); 116 spin_lock_init(&vc->lock);
117 INIT_LIST_HEAD(&vc->desc_allocated);
111 INIT_LIST_HEAD(&vc->desc_submitted); 118 INIT_LIST_HEAD(&vc->desc_submitted);
112 INIT_LIST_HEAD(&vc->desc_issued); 119 INIT_LIST_HEAD(&vc->desc_issued);
113 INIT_LIST_HEAD(&vc->desc_completed); 120 INIT_LIST_HEAD(&vc->desc_completed);
diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h
index 181b95267866..189e75dbcb15 100644
--- a/drivers/dma/virt-dma.h
+++ b/drivers/dma/virt-dma.h
@@ -29,6 +29,7 @@ struct virt_dma_chan {
29 spinlock_t lock; 29 spinlock_t lock;
30 30
31 /* protected by vc.lock */ 31 /* protected by vc.lock */
32 struct list_head desc_allocated;
32 struct list_head desc_submitted; 33 struct list_head desc_submitted;
33 struct list_head desc_issued; 34 struct list_head desc_issued;
34 struct list_head desc_completed; 35 struct list_head desc_completed;
@@ -55,11 +56,16 @@ static inline struct dma_async_tx_descriptor *vchan_tx_prep(struct virt_dma_chan
55 struct virt_dma_desc *vd, unsigned long tx_flags) 56 struct virt_dma_desc *vd, unsigned long tx_flags)
56{ 57{
57 extern dma_cookie_t vchan_tx_submit(struct dma_async_tx_descriptor *); 58 extern dma_cookie_t vchan_tx_submit(struct dma_async_tx_descriptor *);
59 unsigned long flags;
58 60
59 dma_async_tx_descriptor_init(&vd->tx, &vc->chan); 61 dma_async_tx_descriptor_init(&vd->tx, &vc->chan);
60 vd->tx.flags = tx_flags; 62 vd->tx.flags = tx_flags;
61 vd->tx.tx_submit = vchan_tx_submit; 63 vd->tx.tx_submit = vchan_tx_submit;
62 64
65 spin_lock_irqsave(&vc->lock, flags);
66 list_add_tail(&vd->node, &vc->desc_allocated);
67 spin_unlock_irqrestore(&vc->lock, flags);
68
63 return &vd->tx; 69 return &vd->tx;
64} 70}
65 71
@@ -122,7 +128,8 @@ static inline struct virt_dma_desc *vchan_next_desc(struct virt_dma_chan *vc)
122} 128}
123 129
124/** 130/**
125 * vchan_get_all_descriptors - obtain all submitted and issued descriptors 131 * vchan_get_all_descriptors - obtain all allocated, submitted and issued
132 * descriptors
126 * vc: virtual channel to get descriptors from 133 * vc: virtual channel to get descriptors from
127 * head: list of descriptors found 134 * head: list of descriptors found
128 * 135 *
@@ -134,6 +141,7 @@ static inline struct virt_dma_desc *vchan_next_desc(struct virt_dma_chan *vc)
134static inline void vchan_get_all_descriptors(struct virt_dma_chan *vc, 141static inline void vchan_get_all_descriptors(struct virt_dma_chan *vc,
135 struct list_head *head) 142 struct list_head *head)
136{ 143{
144 list_splice_tail_init(&vc->desc_allocated, head);
137 list_splice_tail_init(&vc->desc_submitted, head); 145 list_splice_tail_init(&vc->desc_submitted, head);
138 list_splice_tail_init(&vc->desc_issued, head); 146 list_splice_tail_init(&vc->desc_issued, head);
139 list_splice_tail_init(&vc->desc_completed, head); 147 list_splice_tail_init(&vc->desc_completed, head);
@@ -141,11 +149,14 @@ static inline void vchan_get_all_descriptors(struct virt_dma_chan *vc,
141 149
142static inline void vchan_free_chan_resources(struct virt_dma_chan *vc) 150static inline void vchan_free_chan_resources(struct virt_dma_chan *vc)
143{ 151{
152 struct virt_dma_desc *vd;
144 unsigned long flags; 153 unsigned long flags;
145 LIST_HEAD(head); 154 LIST_HEAD(head);
146 155
147 spin_lock_irqsave(&vc->lock, flags); 156 spin_lock_irqsave(&vc->lock, flags);
148 vchan_get_all_descriptors(vc, &head); 157 vchan_get_all_descriptors(vc, &head);
158 list_for_each_entry(vd, &head, node)
159 async_tx_clear_ack(&vd->tx);
149 spin_unlock_irqrestore(&vc->lock, flags); 160 spin_unlock_irqrestore(&vc->lock, flags);
150 161
151 vchan_dma_desc_free_list(vc, &head); 162 vchan_dma_desc_free_list(vc, &head);