Blame view
crypto/async_tx/async_tx.c
7.63 KB
9bc89cd82 async_tx: add the... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
/* * core routines for the asynchronous memory transfer/transform api * * Copyright © 2006, Intel Corporation. * * Dan Williams <dan.j.williams@intel.com> * * with architecture considerations by: * Neil Brown <neilb@suse.de> * Jeff Garzik <jeff@garzik.org> * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * */ |
82524746c rcu: split list.h... |
26 |
#include <linux/rculist.h> |
4bb33cc89 crypto: add modul... |
27 |
#include <linux/module.h> |
9bc89cd82 async_tx: add the... |
28 29 30 31 |
#include <linux/kernel.h> #include <linux/async_tx.h> #ifdef CONFIG_DMA_ENGINE |
bec085134 dmaengine: centra... |
32 |
static int __init async_tx_init(void) |
9bc89cd82 async_tx: add the... |
33 |
{ |
729b5d1b8 dmaengine: allow ... |
34 |
async_dmaengine_get(); |
9bc89cd82 async_tx: add the... |
35 36 37 38 39 |
printk(KERN_INFO "async_tx: api initialized (async) "); return 0; |
9bc89cd82 async_tx: add the... |
40 41 42 43 |
} static void __exit async_tx_exit(void) { |
729b5d1b8 dmaengine: allow ... |
44 |
async_dmaengine_put(); |
9bc89cd82 async_tx: add the... |
45 |
} |
af1f951eb async_tx: kill ne... |
46 47 |
module_init(async_tx_init); module_exit(async_tx_exit); |
9bc89cd82 async_tx: add the... |
48 |
/** |
47437b2c9 async_tx: allow a... |
49 |
* __async_tx_find_channel - find a channel to carry out the operation or let |
9bc89cd82 async_tx: add the... |
50 |
* the transaction execute synchronously |
a08abd8ca async_tx: structi... |
51 |
* @submit: transaction dependency and submission modifiers |
9bc89cd82 async_tx: add the... |
52 53 54 |
* @tx_type: transaction type */ struct dma_chan * |
a08abd8ca async_tx: structi... |
55 56 |
__async_tx_find_channel(struct async_submit_ctl *submit, enum dma_transaction_type tx_type) |
9bc89cd82 async_tx: add the... |
57 |
{ |
a08abd8ca async_tx: structi... |
58 |
struct dma_async_tx_descriptor *depend_tx = submit->depend_tx; |
9bc89cd82 async_tx: add the... |
59 60 |
/* see if we can keep the chain on one channel */ if (depend_tx && |
bec085134 dmaengine: centra... |
61 |
dma_has_cap(tx_type, depend_tx->chan->device->cap_mask)) |
9bc89cd82 async_tx: add the... |
62 |
return depend_tx->chan; |
729b5d1b8 dmaengine: allow ... |
63 |
return async_dma_find_channel(tx_type); |
9bc89cd82 async_tx: add the... |
64 |
} |
47437b2c9 async_tx: allow a... |
65 |
EXPORT_SYMBOL_GPL(__async_tx_find_channel); |
9bc89cd82 async_tx: add the... |
66 |
#endif |
19242d723 async_tx: fix mul... |
67 68 69 70 71 72 73 74 75 76 77 |
/** * async_tx_channel_switch - queue an interrupt descriptor with a dependency * pre-attached. * @depend_tx: the operation that must finish before the new operation runs * @tx: the new operation */ static void async_tx_channel_switch(struct dma_async_tx_descriptor *depend_tx, struct dma_async_tx_descriptor *tx) { |
95475e571 async_tx: remove ... |
78 79 |
struct dma_chan *chan = depend_tx->chan; struct dma_device *device = chan->device; |
19242d723 async_tx: fix mul... |
80 81 82 |
struct dma_async_tx_descriptor *intr_tx = (void *) ~0; /* first check to see if we can still append to depend_tx */ |
caa20d974 async_tx: trim dm... |
83 84 85 |
txd_lock(depend_tx); if (txd_parent(depend_tx) && depend_tx->chan == tx->chan) { txd_chain(depend_tx, tx); |
19242d723 async_tx: fix mul... |
86 87 |
intr_tx = NULL; } |
caa20d974 async_tx: trim dm... |
88 |
txd_unlock(depend_tx); |
19242d723 async_tx: fix mul... |
89 |
|
95475e571 async_tx: remove ... |
90 91 92 |
/* attached dependency, flush the parent channel */ if (!intr_tx) { device->device_issue_pending(chan); |
19242d723 async_tx: fix mul... |
93 |
return; |
95475e571 async_tx: remove ... |
94 |
} |
19242d723 async_tx: fix mul... |
95 96 97 98 99 |
/* see if we can schedule an interrupt * otherwise poll for completion */ if (dma_has_cap(DMA_INTERRUPT, device->cap_mask)) |
636bdeaa1 dmaengine: ack to... |
100 |
intr_tx = device->device_prep_dma_interrupt(chan, 0); |
19242d723 async_tx: fix mul... |
101 102 103 104 105 106 |
else intr_tx = NULL; if (intr_tx) { intr_tx->callback = NULL; intr_tx->callback_param = NULL; |
caa20d974 async_tx: trim dm... |
107 |
/* safe to chain outside the lock since we know we are |
19242d723 async_tx: fix mul... |
108 109 |
* not submitted yet */ |
caa20d974 async_tx: trim dm... |
110 |
txd_chain(intr_tx, tx); |
19242d723 async_tx: fix mul... |
111 112 |
/* check if we need to append */ |
caa20d974 async_tx: trim dm... |
113 114 115 |
txd_lock(depend_tx); if (txd_parent(depend_tx)) { txd_chain(depend_tx, intr_tx); |
19242d723 async_tx: fix mul... |
116 117 118 |
async_tx_ack(intr_tx); intr_tx = NULL; } |
caa20d974 async_tx: trim dm... |
119 |
txd_unlock(depend_tx); |
19242d723 async_tx: fix mul... |
120 121 |
if (intr_tx) { |
caa20d974 async_tx: trim dm... |
122 |
txd_clear_parent(intr_tx); |
19242d723 async_tx: fix mul... |
123 124 125 |
intr_tx->tx_submit(intr_tx); async_tx_ack(intr_tx); } |
95475e571 async_tx: remove ... |
126 |
device->device_issue_pending(chan); |
19242d723 async_tx: fix mul... |
127 128 129 130 131 132 133 134 135 136 137 |
} else { if (dma_wait_for_async_tx(depend_tx) == DMA_ERROR) panic("%s: DMA_ERROR waiting for depend_tx ", __func__); tx->tx_submit(tx); } } /** |
a08abd8ca async_tx: structi... |
138 |
* submit_disposition - flags for routing an incoming operation |
19242d723 async_tx: fix mul... |
139 140 141 |
* @ASYNC_TX_SUBMITTED: we were able to append the new operation under the lock * @ASYNC_TX_CHANNEL_SWITCH: when the lock is dropped schedule a channel switch * @ASYNC_TX_DIRECT_SUBMIT: when the lock is dropped submit directly |
a08abd8ca async_tx: structi... |
142 143 144 145 |
* * while holding depend_tx->lock we must avoid submitting new operations * to prevent a circular locking dependency with drivers that already * hold a channel lock when calling async_tx_run_dependencies. |
19242d723 async_tx: fix mul... |
146 147 148 149 150 151 |
*/ enum submit_disposition { ASYNC_TX_SUBMITTED, ASYNC_TX_CHANNEL_SWITCH, ASYNC_TX_DIRECT_SUBMIT, }; |
9bc89cd82 async_tx: add the... |
152 153 |
void async_tx_submit(struct dma_chan *chan, struct dma_async_tx_descriptor *tx, |
a08abd8ca async_tx: structi... |
154 |
struct async_submit_ctl *submit) |
9bc89cd82 async_tx: add the... |
155 |
{ |
a08abd8ca async_tx: structi... |
156 157 158 159 |
struct dma_async_tx_descriptor *depend_tx = submit->depend_tx; tx->callback = submit->cb_fn; tx->callback_param = submit->cb_param; |
9bc89cd82 async_tx: add the... |
160 |
|
19242d723 async_tx: fix mul... |
161 162 163 164 165 |
if (depend_tx) { enum submit_disposition s; /* sanity check the dependency chain: * 1/ if ack is already set then we cannot be sure |
9bc89cd82 async_tx: add the... |
166 |
* we are referring to the correct operation |
19242d723 async_tx: fix mul... |
167 168 |
* 2/ dependencies are 1:1 i.e. two transactions can * not depend on the same parent |
9bc89cd82 async_tx: add the... |
169 |
*/ |
caa20d974 async_tx: trim dm... |
170 171 |
BUG_ON(async_tx_test_ack(depend_tx) || txd_next(depend_tx) || txd_parent(tx)); |
9bc89cd82 async_tx: add the... |
172 |
|
19242d723 async_tx: fix mul... |
173 174 175 |
/* the lock prevents async_tx_run_dependencies from missing * the setting of ->next when ->parent != NULL */ |
caa20d974 async_tx: trim dm... |
176 177 |
txd_lock(depend_tx); if (txd_parent(depend_tx)) { |
19242d723 async_tx: fix mul... |
178 179 180 181 182 |
/* we have a parent so we can not submit directly * if we are staying on the same channel: append * else: channel switch */ if (depend_tx->chan == chan) { |
caa20d974 async_tx: trim dm... |
183 |
txd_chain(depend_tx, tx); |
19242d723 async_tx: fix mul... |
184 185 186 187 188 189 190 191 192 193 194 |
s = ASYNC_TX_SUBMITTED; } else s = ASYNC_TX_CHANNEL_SWITCH; } else { /* we do not have a parent so we may be able to submit * directly if we are staying on the same channel */ if (depend_tx->chan == chan) s = ASYNC_TX_DIRECT_SUBMIT; else s = ASYNC_TX_CHANNEL_SWITCH; |
9bc89cd82 async_tx: add the... |
195 |
} |
caa20d974 async_tx: trim dm... |
196 |
txd_unlock(depend_tx); |
9bc89cd82 async_tx: add the... |
197 |
|
19242d723 async_tx: fix mul... |
198 199 200 201 202 203 204 |
switch (s) { case ASYNC_TX_SUBMITTED: break; case ASYNC_TX_CHANNEL_SWITCH: async_tx_channel_switch(depend_tx, tx); break; case ASYNC_TX_DIRECT_SUBMIT: |
caa20d974 async_tx: trim dm... |
205 |
txd_clear_parent(tx); |
19242d723 async_tx: fix mul... |
206 207 208 |
tx->tx_submit(tx); break; } |
9bc89cd82 async_tx: add the... |
209 |
} else { |
caa20d974 async_tx: trim dm... |
210 |
txd_clear_parent(tx); |
9bc89cd82 async_tx: add the... |
211 212 |
tx->tx_submit(tx); } |
a08abd8ca async_tx: structi... |
213 |
if (submit->flags & ASYNC_TX_ACK) |
9bc89cd82 async_tx: add the... |
214 |
async_tx_ack(tx); |
88ba2aa58 async_tx: kill AS... |
215 |
if (depend_tx) |
9bc89cd82 async_tx: add the... |
216 217 218 219 220 |
async_tx_ack(depend_tx); } EXPORT_SYMBOL_GPL(async_tx_submit); /** |
a08abd8ca async_tx: structi... |
221 222 223 224 225 226 |
* async_trigger_callback - schedules the callback function to be run * @submit: submission and completion parameters * * honored flags: ASYNC_TX_ACK * * The callback is run after any dependent operations have completed. |
9bc89cd82 async_tx: add the... |
227 228 |
*/ struct dma_async_tx_descriptor * |
a08abd8ca async_tx: structi... |
229 |
async_trigger_callback(struct async_submit_ctl *submit) |
9bc89cd82 async_tx: add the... |
230 231 232 233 |
{ struct dma_chan *chan; struct dma_device *device; struct dma_async_tx_descriptor *tx; |
a08abd8ca async_tx: structi... |
234 |
struct dma_async_tx_descriptor *depend_tx = submit->depend_tx; |
9bc89cd82 async_tx: add the... |
235 236 237 238 239 240 241 242 243 244 |
if (depend_tx) { chan = depend_tx->chan; device = chan->device; /* see if we can schedule an interrupt * otherwise poll for completion */ if (device && !dma_has_cap(DMA_INTERRUPT, device->cap_mask)) device = NULL; |
636bdeaa1 dmaengine: ack to... |
245 |
tx = device ? device->device_prep_dma_interrupt(chan, 0) : NULL; |
9bc89cd82 async_tx: add the... |
246 247 248 249 |
} else tx = NULL; if (tx) { |
3280ab3e8 async_tx: checkpa... |
250 251 |
pr_debug("%s: (async) ", __func__); |
9bc89cd82 async_tx: add the... |
252 |
|
a08abd8ca async_tx: structi... |
253 |
async_tx_submit(chan, tx, submit); |
9bc89cd82 async_tx: add the... |
254 |
} else { |
3280ab3e8 async_tx: checkpa... |
255 256 |
pr_debug("%s: (sync) ", __func__); |
9bc89cd82 async_tx: add the... |
257 258 |
/* wait for any prerequisite operations */ |
a08abd8ca async_tx: structi... |
259 |
async_tx_quiesce(&submit->depend_tx); |
9bc89cd82 async_tx: add the... |
260 |
|
a08abd8ca async_tx: structi... |
261 |
async_tx_sync_epilog(submit); |
9bc89cd82 async_tx: add the... |
262 263 264 265 266 |
} return tx; } EXPORT_SYMBOL_GPL(async_trigger_callback); |
d2c52b798 async_tx: export ... |
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
/** * async_tx_quiesce - ensure tx is complete and freeable upon return * @tx - transaction to quiesce */ void async_tx_quiesce(struct dma_async_tx_descriptor **tx) { if (*tx) { /* if ack is already set then we cannot be sure * we are referring to the correct operation */ BUG_ON(async_tx_test_ack(*tx)); if (dma_wait_for_async_tx(*tx) == DMA_ERROR) panic("DMA_ERROR waiting for transaction "); async_tx_ack(*tx); *tx = NULL; } } EXPORT_SYMBOL_GPL(async_tx_quiesce); |
9bc89cd82 async_tx: add the... |
286 287 288 |
MODULE_AUTHOR("Intel Corporation"); MODULE_DESCRIPTION("Asynchronous Bulk Memory Transactions API"); MODULE_LICENSE("GPL"); |