diff options
-rw-r--r-- | crypto/async_tx/async_tx.c | 46 | ||||
-rw-r--r-- | drivers/dma/dmaengine.c | 16 | ||||
-rw-r--r-- | include/linux/dmaengine.h | 60 |
3 files changed, 88 insertions, 34 deletions
diff --git a/crypto/async_tx/async_tx.c b/crypto/async_tx/async_tx.c index f9cdf04fe7c0..7f2c00a45205 100644 --- a/crypto/async_tx/async_tx.c +++ b/crypto/async_tx/async_tx.c | |||
@@ -81,18 +81,13 @@ async_tx_channel_switch(struct dma_async_tx_descriptor *depend_tx, | |||
81 | struct dma_device *device = chan->device; | 81 | struct dma_device *device = chan->device; |
82 | struct dma_async_tx_descriptor *intr_tx = (void *) ~0; | 82 | struct dma_async_tx_descriptor *intr_tx = (void *) ~0; |
83 | 83 | ||
84 | #ifdef CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH | ||
85 | BUG(); | ||
86 | #endif | ||
87 | |||
88 | /* first check to see if we can still append to depend_tx */ | 84 | /* first check to see if we can still append to depend_tx */ |
89 | spin_lock_bh(&depend_tx->lock); | 85 | txd_lock(depend_tx); |
90 | if (depend_tx->parent && depend_tx->chan == tx->chan) { | 86 | if (txd_parent(depend_tx) && depend_tx->chan == tx->chan) { |
91 | tx->parent = depend_tx; | 87 | txd_chain(depend_tx, tx); |
92 | depend_tx->next = tx; | ||
93 | intr_tx = NULL; | 88 | intr_tx = NULL; |
94 | } | 89 | } |
95 | spin_unlock_bh(&depend_tx->lock); | 90 | txd_unlock(depend_tx); |
96 | 91 | ||
97 | /* attached dependency, flush the parent channel */ | 92 | /* attached dependency, flush the parent channel */ |
98 | if (!intr_tx) { | 93 | if (!intr_tx) { |
@@ -111,24 +106,22 @@ async_tx_channel_switch(struct dma_async_tx_descriptor *depend_tx, | |||
111 | if (intr_tx) { | 106 | if (intr_tx) { |
112 | intr_tx->callback = NULL; | 107 | intr_tx->callback = NULL; |
113 | intr_tx->callback_param = NULL; | 108 | intr_tx->callback_param = NULL; |
114 | tx->parent = intr_tx; | 109 | /* safe to chain outside the lock since we know we are |
115 | /* safe to set ->next outside the lock since we know we are | ||
116 | * not submitted yet | 110 | * not submitted yet |
117 | */ | 111 | */ |
118 | intr_tx->next = tx; | 112 | txd_chain(intr_tx, tx); |
119 | 113 | ||
120 | /* check if we need to append */ | 114 | /* check if we need to append */ |
121 | spin_lock_bh(&depend_tx->lock); | 115 | txd_lock(depend_tx); |
122 | if (depend_tx->parent) { | 116 | if (txd_parent(depend_tx)) { |
123 | intr_tx->parent = depend_tx; | 117 | txd_chain(depend_tx, intr_tx); |
124 | depend_tx->next = intr_tx; | ||
125 | async_tx_ack(intr_tx); | 118 | async_tx_ack(intr_tx); |
126 | intr_tx = NULL; | 119 | intr_tx = NULL; |
127 | } | 120 | } |
128 | spin_unlock_bh(&depend_tx->lock); | 121 | txd_unlock(depend_tx); |
129 | 122 | ||
130 | if (intr_tx) { | 123 | if (intr_tx) { |
131 | intr_tx->parent = NULL; | 124 | txd_clear_parent(intr_tx); |
132 | intr_tx->tx_submit(intr_tx); | 125 | intr_tx->tx_submit(intr_tx); |
133 | async_tx_ack(intr_tx); | 126 | async_tx_ack(intr_tx); |
134 | } | 127 | } |
@@ -176,21 +169,20 @@ async_tx_submit(struct dma_chan *chan, struct dma_async_tx_descriptor *tx, | |||
176 | * 2/ dependencies are 1:1 i.e. two transactions can | 169 | * 2/ dependencies are 1:1 i.e. two transactions can |
177 | * not depend on the same parent | 170 | * not depend on the same parent |
178 | */ | 171 | */ |
179 | BUG_ON(async_tx_test_ack(depend_tx) || depend_tx->next || | 172 | BUG_ON(async_tx_test_ack(depend_tx) || txd_next(depend_tx) || |
180 | tx->parent); | 173 | txd_parent(tx)); |
181 | 174 | ||
182 | /* the lock prevents async_tx_run_dependencies from missing | 175 | /* the lock prevents async_tx_run_dependencies from missing |
183 | * the setting of ->next when ->parent != NULL | 176 | * the setting of ->next when ->parent != NULL |
184 | */ | 177 | */ |
185 | spin_lock_bh(&depend_tx->lock); | 178 | txd_lock(depend_tx); |
186 | if (depend_tx->parent) { | 179 | if (txd_parent(depend_tx)) { |
187 | /* we have a parent so we can not submit directly | 180 | /* we have a parent so we can not submit directly |
188 | * if we are staying on the same channel: append | 181 | * if we are staying on the same channel: append |
189 | * else: channel switch | 182 | * else: channel switch |
190 | */ | 183 | */ |
191 | if (depend_tx->chan == chan) { | 184 | if (depend_tx->chan == chan) { |
192 | tx->parent = depend_tx; | 185 | txd_chain(depend_tx, tx); |
193 | depend_tx->next = tx; | ||
194 | s = ASYNC_TX_SUBMITTED; | 186 | s = ASYNC_TX_SUBMITTED; |
195 | } else | 187 | } else |
196 | s = ASYNC_TX_CHANNEL_SWITCH; | 188 | s = ASYNC_TX_CHANNEL_SWITCH; |
@@ -203,7 +195,7 @@ async_tx_submit(struct dma_chan *chan, struct dma_async_tx_descriptor *tx, | |||
203 | else | 195 | else |
204 | s = ASYNC_TX_CHANNEL_SWITCH; | 196 | s = ASYNC_TX_CHANNEL_SWITCH; |
205 | } | 197 | } |
206 | spin_unlock_bh(&depend_tx->lock); | 198 | txd_unlock(depend_tx); |
207 | 199 | ||
208 | switch (s) { | 200 | switch (s) { |
209 | case ASYNC_TX_SUBMITTED: | 201 | case ASYNC_TX_SUBMITTED: |
@@ -212,12 +204,12 @@ async_tx_submit(struct dma_chan *chan, struct dma_async_tx_descriptor *tx, | |||
212 | async_tx_channel_switch(depend_tx, tx); | 204 | async_tx_channel_switch(depend_tx, tx); |
213 | break; | 205 | break; |
214 | case ASYNC_TX_DIRECT_SUBMIT: | 206 | case ASYNC_TX_DIRECT_SUBMIT: |
215 | tx->parent = NULL; | 207 | txd_clear_parent(tx); |
216 | tx->tx_submit(tx); | 208 | tx->tx_submit(tx); |
217 | break; | 209 | break; |
218 | } | 210 | } |
219 | } else { | 211 | } else { |
220 | tx->parent = NULL; | 212 | txd_clear_parent(tx); |
221 | tx->tx_submit(tx); | 213 | tx->tx_submit(tx); |
222 | } | 214 | } |
223 | 215 | ||
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index d18b5d069d7e..fcfe1a62ffa5 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c | |||
@@ -978,7 +978,9 @@ void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx, | |||
978 | struct dma_chan *chan) | 978 | struct dma_chan *chan) |
979 | { | 979 | { |
980 | tx->chan = chan; | 980 | tx->chan = chan; |
981 | #ifndef CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH | ||
981 | spin_lock_init(&tx->lock); | 982 | spin_lock_init(&tx->lock); |
983 | #endif | ||
982 | } | 984 | } |
983 | EXPORT_SYMBOL(dma_async_tx_descriptor_init); | 985 | EXPORT_SYMBOL(dma_async_tx_descriptor_init); |
984 | 986 | ||
@@ -1011,7 +1013,7 @@ EXPORT_SYMBOL_GPL(dma_wait_for_async_tx); | |||
1011 | */ | 1013 | */ |
1012 | void dma_run_dependencies(struct dma_async_tx_descriptor *tx) | 1014 | void dma_run_dependencies(struct dma_async_tx_descriptor *tx) |
1013 | { | 1015 | { |
1014 | struct dma_async_tx_descriptor *dep = tx->next; | 1016 | struct dma_async_tx_descriptor *dep = txd_next(tx); |
1015 | struct dma_async_tx_descriptor *dep_next; | 1017 | struct dma_async_tx_descriptor *dep_next; |
1016 | struct dma_chan *chan; | 1018 | struct dma_chan *chan; |
1017 | 1019 | ||
@@ -1019,7 +1021,7 @@ void dma_run_dependencies(struct dma_async_tx_descriptor *tx) | |||
1019 | return; | 1021 | return; |
1020 | 1022 | ||
1021 | /* we'll submit tx->next now, so clear the link */ | 1023 | /* we'll submit tx->next now, so clear the link */ |
1022 | tx->next = NULL; | 1024 | txd_clear_next(tx); |
1023 | chan = dep->chan; | 1025 | chan = dep->chan; |
1024 | 1026 | ||
1025 | /* keep submitting up until a channel switch is detected | 1027 | /* keep submitting up until a channel switch is detected |
@@ -1027,14 +1029,14 @@ void dma_run_dependencies(struct dma_async_tx_descriptor *tx) | |||
1027 | * processing the interrupt from async_tx_channel_switch | 1029 | * processing the interrupt from async_tx_channel_switch |
1028 | */ | 1030 | */ |
1029 | for (; dep; dep = dep_next) { | 1031 | for (; dep; dep = dep_next) { |
1030 | spin_lock_bh(&dep->lock); | 1032 | txd_lock(dep); |
1031 | dep->parent = NULL; | 1033 | txd_clear_parent(dep); |
1032 | dep_next = dep->next; | 1034 | dep_next = txd_next(dep); |
1033 | if (dep_next && dep_next->chan == chan) | 1035 | if (dep_next && dep_next->chan == chan) |
1034 | dep->next = NULL; /* ->next will be submitted */ | 1036 | txd_clear_next(dep); /* ->next will be submitted */ |
1035 | else | 1037 | else |
1036 | dep_next = NULL; /* submit current dep and terminate */ | 1038 | dep_next = NULL; /* submit current dep and terminate */ |
1037 | spin_unlock_bh(&dep->lock); | 1039 | txd_unlock(dep); |
1038 | 1040 | ||
1039 | dep->tx_submit(dep); | 1041 | dep->tx_submit(dep); |
1040 | } | 1042 | } |
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 20ea12c86fd0..cb234979fc6b 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h | |||
@@ -230,11 +230,71 @@ struct dma_async_tx_descriptor { | |||
230 | dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx); | 230 | dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx); |
231 | dma_async_tx_callback callback; | 231 | dma_async_tx_callback callback; |
232 | void *callback_param; | 232 | void *callback_param; |
233 | #ifndef CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH | ||
233 | struct dma_async_tx_descriptor *next; | 234 | struct dma_async_tx_descriptor *next; |
234 | struct dma_async_tx_descriptor *parent; | 235 | struct dma_async_tx_descriptor *parent; |
235 | spinlock_t lock; | 236 | spinlock_t lock; |
237 | #endif | ||
236 | }; | 238 | }; |
237 | 239 | ||
240 | #ifdef CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH | ||
241 | static inline void txd_lock(struct dma_async_tx_descriptor *txd) | ||
242 | { | ||
243 | } | ||
244 | static inline void txd_unlock(struct dma_async_tx_descriptor *txd) | ||
245 | { | ||
246 | } | ||
247 | static inline void txd_chain(struct dma_async_tx_descriptor *txd, struct dma_async_tx_descriptor *next) | ||
248 | { | ||
249 | BUG(); | ||
250 | } | ||
251 | static inline void txd_clear_parent(struct dma_async_tx_descriptor *txd) | ||
252 | { | ||
253 | } | ||
254 | static inline void txd_clear_next(struct dma_async_tx_descriptor *txd) | ||
255 | { | ||
256 | } | ||
257 | static inline struct dma_async_tx_descriptor *txd_next(struct dma_async_tx_descriptor *txd) | ||
258 | { | ||
259 | return NULL; | ||
260 | } | ||
261 | static inline struct dma_async_tx_descriptor *txd_parent(struct dma_async_tx_descriptor *txd) | ||
262 | { | ||
263 | return NULL; | ||
264 | } | ||
265 | |||
266 | #else | ||
267 | static inline void txd_lock(struct dma_async_tx_descriptor *txd) | ||
268 | { | ||
269 | spin_lock_bh(&txd->lock); | ||
270 | } | ||
271 | static inline void txd_unlock(struct dma_async_tx_descriptor *txd) | ||
272 | { | ||
273 | spin_unlock_bh(&txd->lock); | ||
274 | } | ||
275 | static inline void txd_chain(struct dma_async_tx_descriptor *txd, struct dma_async_tx_descriptor *next) | ||
276 | { | ||
277 | txd->next = next; | ||
278 | next->parent = txd; | ||
279 | } | ||
280 | static inline void txd_clear_parent(struct dma_async_tx_descriptor *txd) | ||
281 | { | ||
282 | txd->parent = NULL; | ||
283 | } | ||
284 | static inline void txd_clear_next(struct dma_async_tx_descriptor *txd) | ||
285 | { | ||
286 | txd->next = NULL; | ||
287 | } | ||
288 | static inline struct dma_async_tx_descriptor *txd_parent(struct dma_async_tx_descriptor *txd) | ||
289 | { | ||
290 | return txd->parent; | ||
291 | } | ||
292 | static inline struct dma_async_tx_descriptor *txd_next(struct dma_async_tx_descriptor *txd) | ||
293 | { | ||
294 | return txd->next; | ||
295 | } | ||
296 | #endif | ||
297 | |||
238 | /** | 298 | /** |
239 | * struct dma_device - info on the entity supplying DMA services | 299 | * struct dma_device - info on the entity supplying DMA services |
240 | * @chancnt: how many DMA channels are supported | 300 | * @chancnt: how many DMA channels are supported |