diff options
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/async_tx/async_memcpy.c | 26 | ||||
-rw-r--r-- | crypto/async_tx/async_memset.c | 25 | ||||
-rw-r--r-- | crypto/async_tx/async_tx.c | 51 | ||||
-rw-r--r-- | crypto/async_tx/async_xor.c | 123 |
4 files changed, 111 insertions, 114 deletions
diff --git a/crypto/async_tx/async_memcpy.c b/crypto/async_tx/async_memcpy.c index 7117ec6f1b74..89e05556f3df 100644 --- a/crypto/async_tx/async_memcpy.c +++ b/crypto/async_tx/async_memcpy.c | |||
@@ -33,28 +33,28 @@ | |||
33 | * async_memcpy - attempt to copy memory with a dma engine. | 33 | * async_memcpy - attempt to copy memory with a dma engine. |
34 | * @dest: destination page | 34 | * @dest: destination page |
35 | * @src: src page | 35 | * @src: src page |
36 | * @offset: offset in pages to start transaction | 36 | * @dest_offset: offset into 'dest' to start transaction |
37 | * @src_offset: offset into 'src' to start transaction | ||
37 | * @len: length in bytes | 38 | * @len: length in bytes |
38 | * @flags: ASYNC_TX_ACK | 39 | * @submit: submission / completion modifiers |
39 | * @depend_tx: memcpy depends on the result of this transaction | 40 | * |
40 | * @cb_fn: function to call when the memcpy completes | 41 | * honored flags: ASYNC_TX_ACK |
41 | * @cb_param: parameter to pass to the callback routine | ||
42 | */ | 42 | */ |
43 | struct dma_async_tx_descriptor * | 43 | struct dma_async_tx_descriptor * |
44 | async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset, | 44 | async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset, |
45 | unsigned int src_offset, size_t len, enum async_tx_flags flags, | 45 | unsigned int src_offset, size_t len, |
46 | struct dma_async_tx_descriptor *depend_tx, | 46 | struct async_submit_ctl *submit) |
47 | dma_async_tx_callback cb_fn, void *cb_param) | ||
48 | { | 47 | { |
49 | struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_MEMCPY, | 48 | struct dma_chan *chan = async_tx_find_channel(submit, DMA_MEMCPY, |
50 | &dest, 1, &src, 1, len); | 49 | &dest, 1, &src, 1, len); |
51 | struct dma_device *device = chan ? chan->device : NULL; | 50 | struct dma_device *device = chan ? chan->device : NULL; |
52 | struct dma_async_tx_descriptor *tx = NULL; | 51 | struct dma_async_tx_descriptor *tx = NULL; |
53 | 52 | ||
54 | if (device) { | 53 | if (device) { |
55 | dma_addr_t dma_dest, dma_src; | 54 | dma_addr_t dma_dest, dma_src; |
56 | unsigned long dma_prep_flags = cb_fn ? DMA_PREP_INTERRUPT : 0; | 55 | unsigned long dma_prep_flags; |
57 | 56 | ||
57 | dma_prep_flags = submit->cb_fn ? DMA_PREP_INTERRUPT : 0; | ||
58 | dma_dest = dma_map_page(device->dev, dest, dest_offset, len, | 58 | dma_dest = dma_map_page(device->dev, dest, dest_offset, len, |
59 | DMA_FROM_DEVICE); | 59 | DMA_FROM_DEVICE); |
60 | 60 | ||
@@ -67,13 +67,13 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset, | |||
67 | 67 | ||
68 | if (tx) { | 68 | if (tx) { |
69 | pr_debug("%s: (async) len: %zu\n", __func__, len); | 69 | pr_debug("%s: (async) len: %zu\n", __func__, len); |
70 | async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param); | 70 | async_tx_submit(chan, tx, submit); |
71 | } else { | 71 | } else { |
72 | void *dest_buf, *src_buf; | 72 | void *dest_buf, *src_buf; |
73 | pr_debug("%s: (sync) len: %zu\n", __func__, len); | 73 | pr_debug("%s: (sync) len: %zu\n", __func__, len); |
74 | 74 | ||
75 | /* wait for any prerequisite operations */ | 75 | /* wait for any prerequisite operations */ |
76 | async_tx_quiesce(&depend_tx); | 76 | async_tx_quiesce(&submit->depend_tx); |
77 | 77 | ||
78 | dest_buf = kmap_atomic(dest, KM_USER0) + dest_offset; | 78 | dest_buf = kmap_atomic(dest, KM_USER0) + dest_offset; |
79 | src_buf = kmap_atomic(src, KM_USER1) + src_offset; | 79 | src_buf = kmap_atomic(src, KM_USER1) + src_offset; |
@@ -83,7 +83,7 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset, | |||
83 | kunmap_atomic(dest_buf, KM_USER0); | 83 | kunmap_atomic(dest_buf, KM_USER0); |
84 | kunmap_atomic(src_buf, KM_USER1); | 84 | kunmap_atomic(src_buf, KM_USER1); |
85 | 85 | ||
86 | async_tx_sync_epilog(cb_fn, cb_param); | 86 | async_tx_sync_epilog(submit); |
87 | } | 87 | } |
88 | 88 | ||
89 | return tx; | 89 | return tx; |
diff --git a/crypto/async_tx/async_memset.c b/crypto/async_tx/async_memset.c index b2f133885b7f..c14437238f4c 100644 --- a/crypto/async_tx/async_memset.c +++ b/crypto/async_tx/async_memset.c | |||
@@ -35,26 +35,23 @@ | |||
35 | * @val: fill value | 35 | * @val: fill value |
36 | * @offset: offset in pages to start transaction | 36 | * @offset: offset in pages to start transaction |
37 | * @len: length in bytes | 37 | * @len: length in bytes |
38 | * @flags: ASYNC_TX_ACK | 38 | * |
39 | * @depend_tx: memset depends on the result of this transaction | 39 | * honored flags: ASYNC_TX_ACK |
40 | * @cb_fn: function to call when the memcpy completes | ||
41 | * @cb_param: parameter to pass to the callback routine | ||
42 | */ | 40 | */ |
43 | struct dma_async_tx_descriptor * | 41 | struct dma_async_tx_descriptor * |
44 | async_memset(struct page *dest, int val, unsigned int offset, | 42 | async_memset(struct page *dest, int val, unsigned int offset, size_t len, |
45 | size_t len, enum async_tx_flags flags, | 43 | struct async_submit_ctl *submit) |
46 | struct dma_async_tx_descriptor *depend_tx, | ||
47 | dma_async_tx_callback cb_fn, void *cb_param) | ||
48 | { | 44 | { |
49 | struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_MEMSET, | 45 | struct dma_chan *chan = async_tx_find_channel(submit, DMA_MEMSET, |
50 | &dest, 1, NULL, 0, len); | 46 | &dest, 1, NULL, 0, len); |
51 | struct dma_device *device = chan ? chan->device : NULL; | 47 | struct dma_device *device = chan ? chan->device : NULL; |
52 | struct dma_async_tx_descriptor *tx = NULL; | 48 | struct dma_async_tx_descriptor *tx = NULL; |
53 | 49 | ||
54 | if (device) { | 50 | if (device) { |
55 | dma_addr_t dma_dest; | 51 | dma_addr_t dma_dest; |
56 | unsigned long dma_prep_flags = cb_fn ? DMA_PREP_INTERRUPT : 0; | 52 | unsigned long dma_prep_flags; |
57 | 53 | ||
54 | dma_prep_flags = submit->cb_fn ? DMA_PREP_INTERRUPT : 0; | ||
58 | dma_dest = dma_map_page(device->dev, dest, offset, len, | 55 | dma_dest = dma_map_page(device->dev, dest, offset, len, |
59 | DMA_FROM_DEVICE); | 56 | DMA_FROM_DEVICE); |
60 | 57 | ||
@@ -64,19 +61,19 @@ async_memset(struct page *dest, int val, unsigned int offset, | |||
64 | 61 | ||
65 | if (tx) { | 62 | if (tx) { |
66 | pr_debug("%s: (async) len: %zu\n", __func__, len); | 63 | pr_debug("%s: (async) len: %zu\n", __func__, len); |
67 | async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param); | 64 | async_tx_submit(chan, tx, submit); |
68 | } else { /* run the memset synchronously */ | 65 | } else { /* run the memset synchronously */ |
69 | void *dest_buf; | 66 | void *dest_buf; |
70 | pr_debug("%s: (sync) len: %zu\n", __func__, len); | 67 | pr_debug("%s: (sync) len: %zu\n", __func__, len); |
71 | 68 | ||
72 | dest_buf = (void *) (((char *) page_address(dest)) + offset); | 69 | dest_buf = page_address(dest) + offset; |
73 | 70 | ||
74 | /* wait for any prerequisite operations */ | 71 | /* wait for any prerequisite operations */ |
75 | async_tx_quiesce(&depend_tx); | 72 | async_tx_quiesce(&submit->depend_tx); |
76 | 73 | ||
77 | memset(dest_buf, val, len); | 74 | memset(dest_buf, val, len); |
78 | 75 | ||
79 | async_tx_sync_epilog(cb_fn, cb_param); | 76 | async_tx_sync_epilog(submit); |
80 | } | 77 | } |
81 | 78 | ||
82 | return tx; | 79 | return tx; |
diff --git a/crypto/async_tx/async_tx.c b/crypto/async_tx/async_tx.c index 3766bc3d7d89..802a5ce437d9 100644 --- a/crypto/async_tx/async_tx.c +++ b/crypto/async_tx/async_tx.c | |||
@@ -45,13 +45,15 @@ static void __exit async_tx_exit(void) | |||
45 | /** | 45 | /** |
46 | * __async_tx_find_channel - find a channel to carry out the operation or let | 46 | * __async_tx_find_channel - find a channel to carry out the operation or let |
47 | * the transaction execute synchronously | 47 | * the transaction execute synchronously |
48 | * @depend_tx: transaction dependency | 48 | * @submit: transaction dependency and submission modifiers |
49 | * @tx_type: transaction type | 49 | * @tx_type: transaction type |
50 | */ | 50 | */ |
51 | struct dma_chan * | 51 | struct dma_chan * |
52 | __async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx, | 52 | __async_tx_find_channel(struct async_submit_ctl *submit, |
53 | enum dma_transaction_type tx_type) | 53 | enum dma_transaction_type tx_type) |
54 | { | 54 | { |
55 | struct dma_async_tx_descriptor *depend_tx = submit->depend_tx; | ||
56 | |||
55 | /* see if we can keep the chain on one channel */ | 57 | /* see if we can keep the chain on one channel */ |
56 | if (depend_tx && | 58 | if (depend_tx && |
57 | dma_has_cap(tx_type, depend_tx->chan->device->cap_mask)) | 59 | dma_has_cap(tx_type, depend_tx->chan->device->cap_mask)) |
@@ -144,13 +146,14 @@ async_tx_channel_switch(struct dma_async_tx_descriptor *depend_tx, | |||
144 | 146 | ||
145 | 147 | ||
146 | /** | 148 | /** |
147 | * submit_disposition - while holding depend_tx->lock we must avoid submitting | 149 | * submit_disposition - flags for routing an incoming operation |
148 | * new operations to prevent a circular locking dependency with | ||
149 | * drivers that already hold a channel lock when calling | ||
150 | * async_tx_run_dependencies. | ||
151 | * @ASYNC_TX_SUBMITTED: we were able to append the new operation under the lock | 150 | * @ASYNC_TX_SUBMITTED: we were able to append the new operation under the lock |
152 | * @ASYNC_TX_CHANNEL_SWITCH: when the lock is dropped schedule a channel switch | 151 | * @ASYNC_TX_CHANNEL_SWITCH: when the lock is dropped schedule a channel switch |
153 | * @ASYNC_TX_DIRECT_SUBMIT: when the lock is dropped submit directly | 152 | * @ASYNC_TX_DIRECT_SUBMIT: when the lock is dropped submit directly |
153 | * | ||
154 | * while holding depend_tx->lock we must avoid submitting new operations | ||
155 | * to prevent a circular locking dependency with drivers that already | ||
156 | * hold a channel lock when calling async_tx_run_dependencies. | ||
154 | */ | 157 | */ |
155 | enum submit_disposition { | 158 | enum submit_disposition { |
156 | ASYNC_TX_SUBMITTED, | 159 | ASYNC_TX_SUBMITTED, |
@@ -160,11 +163,12 @@ enum submit_disposition { | |||
160 | 163 | ||
161 | void | 164 | void |
162 | async_tx_submit(struct dma_chan *chan, struct dma_async_tx_descriptor *tx, | 165 | async_tx_submit(struct dma_chan *chan, struct dma_async_tx_descriptor *tx, |
163 | enum async_tx_flags flags, struct dma_async_tx_descriptor *depend_tx, | 166 | struct async_submit_ctl *submit) |
164 | dma_async_tx_callback cb_fn, void *cb_param) | ||
165 | { | 167 | { |
166 | tx->callback = cb_fn; | 168 | struct dma_async_tx_descriptor *depend_tx = submit->depend_tx; |
167 | tx->callback_param = cb_param; | 169 | |
170 | tx->callback = submit->cb_fn; | ||
171 | tx->callback_param = submit->cb_param; | ||
168 | 172 | ||
169 | if (depend_tx) { | 173 | if (depend_tx) { |
170 | enum submit_disposition s; | 174 | enum submit_disposition s; |
@@ -220,7 +224,7 @@ async_tx_submit(struct dma_chan *chan, struct dma_async_tx_descriptor *tx, | |||
220 | tx->tx_submit(tx); | 224 | tx->tx_submit(tx); |
221 | } | 225 | } |
222 | 226 | ||
223 | if (flags & ASYNC_TX_ACK) | 227 | if (submit->flags & ASYNC_TX_ACK) |
224 | async_tx_ack(tx); | 228 | async_tx_ack(tx); |
225 | 229 | ||
226 | if (depend_tx) | 230 | if (depend_tx) |
@@ -229,21 +233,20 @@ async_tx_submit(struct dma_chan *chan, struct dma_async_tx_descriptor *tx, | |||
229 | EXPORT_SYMBOL_GPL(async_tx_submit); | 233 | EXPORT_SYMBOL_GPL(async_tx_submit); |
230 | 234 | ||
231 | /** | 235 | /** |
232 | * async_trigger_callback - schedules the callback function to be run after | 236 | * async_trigger_callback - schedules the callback function to be run |
233 | * any dependent operations have been completed. | 237 | * @submit: submission and completion parameters |
234 | * @flags: ASYNC_TX_ACK | 238 | * |
235 | * @depend_tx: 'callback' requires the completion of this transaction | 239 | * honored flags: ASYNC_TX_ACK |
236 | * @cb_fn: function to call after depend_tx completes | 240 | * |
237 | * @cb_param: parameter to pass to the callback routine | 241 | * The callback is run after any dependent operations have completed. |
238 | */ | 242 | */ |
239 | struct dma_async_tx_descriptor * | 243 | struct dma_async_tx_descriptor * |
240 | async_trigger_callback(enum async_tx_flags flags, | 244 | async_trigger_callback(struct async_submit_ctl *submit) |
241 | struct dma_async_tx_descriptor *depend_tx, | ||
242 | dma_async_tx_callback cb_fn, void *cb_param) | ||
243 | { | 245 | { |
244 | struct dma_chan *chan; | 246 | struct dma_chan *chan; |
245 | struct dma_device *device; | 247 | struct dma_device *device; |
246 | struct dma_async_tx_descriptor *tx; | 248 | struct dma_async_tx_descriptor *tx; |
249 | struct dma_async_tx_descriptor *depend_tx = submit->depend_tx; | ||
247 | 250 | ||
248 | if (depend_tx) { | 251 | if (depend_tx) { |
249 | chan = depend_tx->chan; | 252 | chan = depend_tx->chan; |
@@ -262,14 +265,14 @@ async_trigger_callback(enum async_tx_flags flags, | |||
262 | if (tx) { | 265 | if (tx) { |
263 | pr_debug("%s: (async)\n", __func__); | 266 | pr_debug("%s: (async)\n", __func__); |
264 | 267 | ||
265 | async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param); | 268 | async_tx_submit(chan, tx, submit); |
266 | } else { | 269 | } else { |
267 | pr_debug("%s: (sync)\n", __func__); | 270 | pr_debug("%s: (sync)\n", __func__); |
268 | 271 | ||
269 | /* wait for any prerequisite operations */ | 272 | /* wait for any prerequisite operations */ |
270 | async_tx_quiesce(&depend_tx); | 273 | async_tx_quiesce(&submit->depend_tx); |
271 | 274 | ||
272 | async_tx_sync_epilog(cb_fn, cb_param); | 275 | async_tx_sync_epilog(submit); |
273 | } | 276 | } |
274 | 277 | ||
275 | return tx; | 278 | return tx; |
diff --git a/crypto/async_tx/async_xor.c b/crypto/async_tx/async_xor.c index 3cc5dc763b54..691fa98a18c4 100644 --- a/crypto/async_tx/async_xor.c +++ b/crypto/async_tx/async_xor.c | |||
@@ -34,18 +34,16 @@ | |||
34 | static __async_inline struct dma_async_tx_descriptor * | 34 | static __async_inline struct dma_async_tx_descriptor * |
35 | do_async_xor(struct dma_chan *chan, struct page *dest, struct page **src_list, | 35 | do_async_xor(struct dma_chan *chan, struct page *dest, struct page **src_list, |
36 | unsigned int offset, int src_cnt, size_t len, | 36 | unsigned int offset, int src_cnt, size_t len, |
37 | enum async_tx_flags flags, | 37 | struct async_submit_ctl *submit) |
38 | struct dma_async_tx_descriptor *depend_tx, | ||
39 | dma_async_tx_callback cb_fn, void *cb_param) | ||
40 | { | 38 | { |
41 | struct dma_device *dma = chan->device; | 39 | struct dma_device *dma = chan->device; |
42 | dma_addr_t *dma_src = (dma_addr_t *) src_list; | 40 | dma_addr_t *dma_src = (dma_addr_t *) src_list; |
43 | struct dma_async_tx_descriptor *tx = NULL; | 41 | struct dma_async_tx_descriptor *tx = NULL; |
44 | int src_off = 0; | 42 | int src_off = 0; |
45 | int i; | 43 | int i; |
46 | dma_async_tx_callback _cb_fn; | 44 | dma_async_tx_callback cb_fn_orig = submit->cb_fn; |
47 | void *_cb_param; | 45 | void *cb_param_orig = submit->cb_param; |
48 | enum async_tx_flags async_flags; | 46 | enum async_tx_flags flags_orig = submit->flags; |
49 | enum dma_ctrl_flags dma_flags; | 47 | enum dma_ctrl_flags dma_flags; |
50 | int xor_src_cnt; | 48 | int xor_src_cnt; |
51 | dma_addr_t dma_dest; | 49 | dma_addr_t dma_dest; |
@@ -63,7 +61,7 @@ do_async_xor(struct dma_chan *chan, struct page *dest, struct page **src_list, | |||
63 | } | 61 | } |
64 | 62 | ||
65 | while (src_cnt) { | 63 | while (src_cnt) { |
66 | async_flags = flags; | 64 | submit->flags = flags_orig; |
67 | dma_flags = 0; | 65 | dma_flags = 0; |
68 | xor_src_cnt = min(src_cnt, dma->max_xor); | 66 | xor_src_cnt = min(src_cnt, dma->max_xor); |
69 | /* if we are submitting additional xors, leave the chain open, | 67 | /* if we are submitting additional xors, leave the chain open, |
@@ -71,15 +69,15 @@ do_async_xor(struct dma_chan *chan, struct page *dest, struct page **src_list, | |||
71 | * buffer mapped | 69 | * buffer mapped |
72 | */ | 70 | */ |
73 | if (src_cnt > xor_src_cnt) { | 71 | if (src_cnt > xor_src_cnt) { |
74 | async_flags &= ~ASYNC_TX_ACK; | 72 | submit->flags &= ~ASYNC_TX_ACK; |
75 | dma_flags = DMA_COMPL_SKIP_DEST_UNMAP; | 73 | dma_flags = DMA_COMPL_SKIP_DEST_UNMAP; |
76 | _cb_fn = NULL; | 74 | submit->cb_fn = NULL; |
77 | _cb_param = NULL; | 75 | submit->cb_param = NULL; |
78 | } else { | 76 | } else { |
79 | _cb_fn = cb_fn; | 77 | submit->cb_fn = cb_fn_orig; |
80 | _cb_param = cb_param; | 78 | submit->cb_param = cb_param_orig; |
81 | } | 79 | } |
82 | if (_cb_fn) | 80 | if (submit->cb_fn) |
83 | dma_flags |= DMA_PREP_INTERRUPT; | 81 | dma_flags |= DMA_PREP_INTERRUPT; |
84 | 82 | ||
85 | /* Since we have clobbered the src_list we are committed | 83 | /* Since we have clobbered the src_list we are committed |
@@ -90,7 +88,7 @@ do_async_xor(struct dma_chan *chan, struct page *dest, struct page **src_list, | |||
90 | xor_src_cnt, len, dma_flags); | 88 | xor_src_cnt, len, dma_flags); |
91 | 89 | ||
92 | if (unlikely(!tx)) | 90 | if (unlikely(!tx)) |
93 | async_tx_quiesce(&depend_tx); | 91 | async_tx_quiesce(&submit->depend_tx); |
94 | 92 | ||
95 | /* spin wait for the preceeding transactions to complete */ | 93 | /* spin wait for the preceeding transactions to complete */ |
96 | while (unlikely(!tx)) { | 94 | while (unlikely(!tx)) { |
@@ -101,10 +99,8 @@ do_async_xor(struct dma_chan *chan, struct page *dest, struct page **src_list, | |||
101 | dma_flags); | 99 | dma_flags); |
102 | } | 100 | } |
103 | 101 | ||
104 | async_tx_submit(chan, tx, async_flags, depend_tx, _cb_fn, | 102 | async_tx_submit(chan, tx, submit); |
105 | _cb_param); | 103 | submit->depend_tx = tx; |
106 | |||
107 | depend_tx = tx; | ||
108 | 104 | ||
109 | if (src_cnt > xor_src_cnt) { | 105 | if (src_cnt > xor_src_cnt) { |
110 | /* drop completed sources */ | 106 | /* drop completed sources */ |
@@ -123,8 +119,7 @@ do_async_xor(struct dma_chan *chan, struct page *dest, struct page **src_list, | |||
123 | 119 | ||
124 | static void | 120 | static void |
125 | do_sync_xor(struct page *dest, struct page **src_list, unsigned int offset, | 121 | do_sync_xor(struct page *dest, struct page **src_list, unsigned int offset, |
126 | int src_cnt, size_t len, enum async_tx_flags flags, | 122 | int src_cnt, size_t len, struct async_submit_ctl *submit) |
127 | dma_async_tx_callback cb_fn, void *cb_param) | ||
128 | { | 123 | { |
129 | int i; | 124 | int i; |
130 | int xor_src_cnt; | 125 | int xor_src_cnt; |
@@ -139,7 +134,7 @@ do_sync_xor(struct page *dest, struct page **src_list, unsigned int offset, | |||
139 | /* set destination address */ | 134 | /* set destination address */ |
140 | dest_buf = page_address(dest) + offset; | 135 | dest_buf = page_address(dest) + offset; |
141 | 136 | ||
142 | if (flags & ASYNC_TX_XOR_ZERO_DST) | 137 | if (submit->flags & ASYNC_TX_XOR_ZERO_DST) |
143 | memset(dest_buf, 0, len); | 138 | memset(dest_buf, 0, len); |
144 | 139 | ||
145 | while (src_cnt > 0) { | 140 | while (src_cnt > 0) { |
@@ -152,33 +147,35 @@ do_sync_xor(struct page *dest, struct page **src_list, unsigned int offset, | |||
152 | src_off += xor_src_cnt; | 147 | src_off += xor_src_cnt; |
153 | } | 148 | } |
154 | 149 | ||
155 | async_tx_sync_epilog(cb_fn, cb_param); | 150 | async_tx_sync_epilog(submit); |
156 | } | 151 | } |
157 | 152 | ||
158 | /** | 153 | /** |
159 | * async_xor - attempt to xor a set of blocks with a dma engine. | 154 | * async_xor - attempt to xor a set of blocks with a dma engine. |
160 | * xor_blocks always uses the dest as a source so the ASYNC_TX_XOR_ZERO_DST | ||
161 | * flag must be set to not include dest data in the calculation. The | ||
162 | * assumption with dma eninges is that they only use the destination | ||
163 | * buffer as a source when it is explicity specified in the source list. | ||
164 | * @dest: destination page | 155 | * @dest: destination page |
165 | * @src_list: array of source pages (if the dest is also a source it must be | 156 | * @src_list: array of source pages |
166 | * at index zero). The contents of this array may be overwritten. | 157 | * @offset: common src/dst offset to start transaction |
167 | * @offset: offset in pages to start transaction | ||
168 | * @src_cnt: number of source pages | 158 | * @src_cnt: number of source pages |
169 | * @len: length in bytes | 159 | * @len: length in bytes |
170 | * @flags: ASYNC_TX_XOR_ZERO_DST, ASYNC_TX_XOR_DROP_DEST, ASYNC_TX_ACK | 160 | * @submit: submission / completion modifiers |
171 | * @depend_tx: xor depends on the result of this transaction. | 161 | * |
172 | * @cb_fn: function to call when the xor completes | 162 | * honored flags: ASYNC_TX_ACK, ASYNC_TX_XOR_ZERO_DST, ASYNC_TX_XOR_DROP_DST |
173 | * @cb_param: parameter to pass to the callback routine | 163 | * |
164 | * xor_blocks always uses the dest as a source so the | ||
165 | * ASYNC_TX_XOR_ZERO_DST flag must be set to not include dest data in | ||
166 | * the calculation. The assumption with dma eninges is that they only | ||
167 | * use the destination buffer as a source when it is explicity specified | ||
168 | * in the source list. | ||
169 | * | ||
170 | * src_list note: if the dest is also a source it must be at index zero. | ||
171 | * The contents of this array will be overwritten if a scribble region | ||
172 | * is not specified. | ||
174 | */ | 173 | */ |
175 | struct dma_async_tx_descriptor * | 174 | struct dma_async_tx_descriptor * |
176 | async_xor(struct page *dest, struct page **src_list, unsigned int offset, | 175 | async_xor(struct page *dest, struct page **src_list, unsigned int offset, |
177 | int src_cnt, size_t len, enum async_tx_flags flags, | 176 | int src_cnt, size_t len, struct async_submit_ctl *submit) |
178 | struct dma_async_tx_descriptor *depend_tx, | ||
179 | dma_async_tx_callback cb_fn, void *cb_param) | ||
180 | { | 177 | { |
181 | struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_XOR, | 178 | struct dma_chan *chan = async_tx_find_channel(submit, DMA_XOR, |
182 | &dest, 1, src_list, | 179 | &dest, 1, src_list, |
183 | src_cnt, len); | 180 | src_cnt, len); |
184 | BUG_ON(src_cnt <= 1); | 181 | BUG_ON(src_cnt <= 1); |
@@ -188,7 +185,7 @@ async_xor(struct page *dest, struct page **src_list, unsigned int offset, | |||
188 | pr_debug("%s (async): len: %zu\n", __func__, len); | 185 | pr_debug("%s (async): len: %zu\n", __func__, len); |
189 | 186 | ||
190 | return do_async_xor(chan, dest, src_list, offset, src_cnt, len, | 187 | return do_async_xor(chan, dest, src_list, offset, src_cnt, len, |
191 | flags, depend_tx, cb_fn, cb_param); | 188 | submit); |
192 | } else { | 189 | } else { |
193 | /* run the xor synchronously */ | 190 | /* run the xor synchronously */ |
194 | pr_debug("%s (sync): len: %zu\n", __func__, len); | 191 | pr_debug("%s (sync): len: %zu\n", __func__, len); |
@@ -196,16 +193,15 @@ async_xor(struct page *dest, struct page **src_list, unsigned int offset, | |||
196 | /* in the sync case the dest is an implied source | 193 | /* in the sync case the dest is an implied source |
197 | * (assumes the dest is the first source) | 194 | * (assumes the dest is the first source) |
198 | */ | 195 | */ |
199 | if (flags & ASYNC_TX_XOR_DROP_DST) { | 196 | if (submit->flags & ASYNC_TX_XOR_DROP_DST) { |
200 | src_cnt--; | 197 | src_cnt--; |
201 | src_list++; | 198 | src_list++; |
202 | } | 199 | } |
203 | 200 | ||
204 | /* wait for any prerequisite operations */ | 201 | /* wait for any prerequisite operations */ |
205 | async_tx_quiesce(&depend_tx); | 202 | async_tx_quiesce(&submit->depend_tx); |
206 | 203 | ||
207 | do_sync_xor(dest, src_list, offset, src_cnt, len, | 204 | do_sync_xor(dest, src_list, offset, src_cnt, len, submit); |
208 | flags, cb_fn, cb_param); | ||
209 | 205 | ||
210 | return NULL; | 206 | return NULL; |
211 | } | 207 | } |
@@ -222,25 +218,25 @@ static int page_is_zero(struct page *p, unsigned int offset, size_t len) | |||
222 | /** | 218 | /** |
223 | * async_xor_val - attempt a xor parity check with a dma engine. | 219 | * async_xor_val - attempt a xor parity check with a dma engine. |
224 | * @dest: destination page used if the xor is performed synchronously | 220 | * @dest: destination page used if the xor is performed synchronously |
225 | * @src_list: array of source pages. The dest page must be listed as a source | 221 | * @src_list: array of source pages |
226 | * at index zero. The contents of this array may be overwritten. | ||
227 | * @offset: offset in pages to start transaction | 222 | * @offset: offset in pages to start transaction |
228 | * @src_cnt: number of source pages | 223 | * @src_cnt: number of source pages |
229 | * @len: length in bytes | 224 | * @len: length in bytes |
230 | * @result: 0 if sum == 0 else non-zero | 225 | * @result: 0 if sum == 0 else non-zero |
231 | * @flags: ASYNC_TX_ACK | 226 | * @submit: submission / completion modifiers |
232 | * @depend_tx: xor depends on the result of this transaction. | 227 | * |
233 | * @cb_fn: function to call when the xor completes | 228 | * honored flags: ASYNC_TX_ACK |
234 | * @cb_param: parameter to pass to the callback routine | 229 | * |
230 | * src_list note: if the dest is also a source it must be at index zero. | ||
231 | * The contents of this array will be overwritten if a scribble region | ||
232 | * is not specified. | ||
235 | */ | 233 | */ |
236 | struct dma_async_tx_descriptor * | 234 | struct dma_async_tx_descriptor * |
237 | async_xor_val(struct page *dest, struct page **src_list, | 235 | async_xor_val(struct page *dest, struct page **src_list, unsigned int offset, |
238 | unsigned int offset, int src_cnt, size_t len, | 236 | int src_cnt, size_t len, u32 *result, |
239 | u32 *result, enum async_tx_flags flags, | 237 | struct async_submit_ctl *submit) |
240 | struct dma_async_tx_descriptor *depend_tx, | ||
241 | dma_async_tx_callback cb_fn, void *cb_param) | ||
242 | { | 238 | { |
243 | struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_XOR_VAL, | 239 | struct dma_chan *chan = async_tx_find_channel(submit, DMA_XOR_VAL, |
244 | &dest, 1, src_list, | 240 | &dest, 1, src_list, |
245 | src_cnt, len); | 241 | src_cnt, len); |
246 | struct dma_device *device = chan ? chan->device : NULL; | 242 | struct dma_device *device = chan ? chan->device : NULL; |
@@ -250,11 +246,12 @@ async_xor_val(struct page *dest, struct page **src_list, | |||
250 | 246 | ||
251 | if (device && src_cnt <= device->max_xor) { | 247 | if (device && src_cnt <= device->max_xor) { |
252 | dma_addr_t *dma_src = (dma_addr_t *) src_list; | 248 | dma_addr_t *dma_src = (dma_addr_t *) src_list; |
253 | unsigned long dma_prep_flags = cb_fn ? DMA_PREP_INTERRUPT : 0; | 249 | unsigned long dma_prep_flags; |
254 | int i; | 250 | int i; |
255 | 251 | ||
256 | pr_debug("%s: (async) len: %zu\n", __func__, len); | 252 | pr_debug("%s: (async) len: %zu\n", __func__, len); |
257 | 253 | ||
254 | dma_prep_flags = submit->cb_fn ? DMA_PREP_INTERRUPT : 0; | ||
258 | for (i = 0; i < src_cnt; i++) | 255 | for (i = 0; i < src_cnt; i++) |
259 | dma_src[i] = dma_map_page(device->dev, src_list[i], | 256 | dma_src[i] = dma_map_page(device->dev, src_list[i], |
260 | offset, len, DMA_TO_DEVICE); | 257 | offset, len, DMA_TO_DEVICE); |
@@ -263,7 +260,7 @@ async_xor_val(struct page *dest, struct page **src_list, | |||
263 | len, result, | 260 | len, result, |
264 | dma_prep_flags); | 261 | dma_prep_flags); |
265 | if (unlikely(!tx)) { | 262 | if (unlikely(!tx)) { |
266 | async_tx_quiesce(&depend_tx); | 263 | async_tx_quiesce(&submit->depend_tx); |
267 | 264 | ||
268 | while (!tx) { | 265 | while (!tx) { |
269 | dma_async_issue_pending(chan); | 266 | dma_async_issue_pending(chan); |
@@ -273,23 +270,23 @@ async_xor_val(struct page *dest, struct page **src_list, | |||
273 | } | 270 | } |
274 | } | 271 | } |
275 | 272 | ||
276 | async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param); | 273 | async_tx_submit(chan, tx, submit); |
277 | } else { | 274 | } else { |
278 | unsigned long xor_flags = flags; | 275 | enum async_tx_flags flags_orig = submit->flags; |
279 | 276 | ||
280 | pr_debug("%s: (sync) len: %zu\n", __func__, len); | 277 | pr_debug("%s: (sync) len: %zu\n", __func__, len); |
281 | 278 | ||
282 | xor_flags |= ASYNC_TX_XOR_DROP_DST; | 279 | submit->flags |= ASYNC_TX_XOR_DROP_DST; |
283 | xor_flags &= ~ASYNC_TX_ACK; | 280 | submit->flags &= ~ASYNC_TX_ACK; |
284 | 281 | ||
285 | tx = async_xor(dest, src_list, offset, src_cnt, len, xor_flags, | 282 | tx = async_xor(dest, src_list, offset, src_cnt, len, submit); |
286 | depend_tx, NULL, NULL); | ||
287 | 283 | ||
288 | async_tx_quiesce(&tx); | 284 | async_tx_quiesce(&tx); |
289 | 285 | ||
290 | *result = page_is_zero(dest, offset, len) ? 0 : 1; | 286 | *result = page_is_zero(dest, offset, len) ? 0 : 1; |
291 | 287 | ||
292 | async_tx_sync_epilog(cb_fn, cb_param); | 288 | async_tx_sync_epilog(submit); |
289 | submit->flags = flags_orig; | ||
293 | } | 290 | } |
294 | 291 | ||
295 | return tx; | 292 | return tx; |