diff options
Diffstat (limited to 'crypto/async_tx/async_pq.c')
-rw-r--r-- | crypto/async_tx/async_pq.c | 174 |
1 files changed, 99 insertions, 75 deletions
diff --git a/crypto/async_tx/async_pq.c b/crypto/async_tx/async_pq.c index 91d5d385899e..d05327caf69d 100644 --- a/crypto/async_tx/async_pq.c +++ b/crypto/async_tx/async_pq.c | |||
@@ -46,49 +46,24 @@ static struct page *pq_scribble_page; | |||
46 | * do_async_gen_syndrome - asynchronously calculate P and/or Q | 46 | * do_async_gen_syndrome - asynchronously calculate P and/or Q |
47 | */ | 47 | */ |
48 | static __async_inline struct dma_async_tx_descriptor * | 48 | static __async_inline struct dma_async_tx_descriptor * |
49 | do_async_gen_syndrome(struct dma_chan *chan, struct page **blocks, | 49 | do_async_gen_syndrome(struct dma_chan *chan, |
50 | const unsigned char *scfs, unsigned int offset, int disks, | 50 | const unsigned char *scfs, int disks, |
51 | size_t len, dma_addr_t *dma_src, | 51 | struct dmaengine_unmap_data *unmap, |
52 | enum dma_ctrl_flags dma_flags, | ||
52 | struct async_submit_ctl *submit) | 53 | struct async_submit_ctl *submit) |
53 | { | 54 | { |
54 | struct dma_async_tx_descriptor *tx = NULL; | 55 | struct dma_async_tx_descriptor *tx = NULL; |
55 | struct dma_device *dma = chan->device; | 56 | struct dma_device *dma = chan->device; |
56 | enum dma_ctrl_flags dma_flags = 0; | ||
57 | enum async_tx_flags flags_orig = submit->flags; | 57 | enum async_tx_flags flags_orig = submit->flags; |
58 | dma_async_tx_callback cb_fn_orig = submit->cb_fn; | 58 | dma_async_tx_callback cb_fn_orig = submit->cb_fn; |
59 | dma_async_tx_callback cb_param_orig = submit->cb_param; | 59 | dma_async_tx_callback cb_param_orig = submit->cb_param; |
60 | int src_cnt = disks - 2; | 60 | int src_cnt = disks - 2; |
61 | unsigned char coefs[src_cnt]; | ||
62 | unsigned short pq_src_cnt; | 61 | unsigned short pq_src_cnt; |
63 | dma_addr_t dma_dest[2]; | 62 | dma_addr_t dma_dest[2]; |
64 | int src_off = 0; | 63 | int src_off = 0; |
65 | int idx; | ||
66 | int i; | ||
67 | 64 | ||
68 | /* DMAs use destinations as sources, so use BIDIRECTIONAL mapping */ | 65 | if (submit->flags & ASYNC_TX_FENCE) |
69 | if (P(blocks, disks)) | 66 | dma_flags |= DMA_PREP_FENCE; |
70 | dma_dest[0] = dma_map_page(dma->dev, P(blocks, disks), offset, | ||
71 | len, DMA_BIDIRECTIONAL); | ||
72 | else | ||
73 | dma_flags |= DMA_PREP_PQ_DISABLE_P; | ||
74 | if (Q(blocks, disks)) | ||
75 | dma_dest[1] = dma_map_page(dma->dev, Q(blocks, disks), offset, | ||
76 | len, DMA_BIDIRECTIONAL); | ||
77 | else | ||
78 | dma_flags |= DMA_PREP_PQ_DISABLE_Q; | ||
79 | |||
80 | /* convert source addresses being careful to collapse 'empty' | ||
81 | * sources and update the coefficients accordingly | ||
82 | */ | ||
83 | for (i = 0, idx = 0; i < src_cnt; i++) { | ||
84 | if (blocks[i] == NULL) | ||
85 | continue; | ||
86 | dma_src[idx] = dma_map_page(dma->dev, blocks[i], offset, len, | ||
87 | DMA_TO_DEVICE); | ||
88 | coefs[idx] = scfs[i]; | ||
89 | idx++; | ||
90 | } | ||
91 | src_cnt = idx; | ||
92 | 67 | ||
93 | while (src_cnt > 0) { | 68 | while (src_cnt > 0) { |
94 | submit->flags = flags_orig; | 69 | submit->flags = flags_orig; |
@@ -100,28 +75,25 @@ do_async_gen_syndrome(struct dma_chan *chan, struct page **blocks, | |||
100 | if (src_cnt > pq_src_cnt) { | 75 | if (src_cnt > pq_src_cnt) { |
101 | submit->flags &= ~ASYNC_TX_ACK; | 76 | submit->flags &= ~ASYNC_TX_ACK; |
102 | submit->flags |= ASYNC_TX_FENCE; | 77 | submit->flags |= ASYNC_TX_FENCE; |
103 | dma_flags |= DMA_COMPL_SKIP_DEST_UNMAP; | ||
104 | submit->cb_fn = NULL; | 78 | submit->cb_fn = NULL; |
105 | submit->cb_param = NULL; | 79 | submit->cb_param = NULL; |
106 | } else { | 80 | } else { |
107 | dma_flags &= ~DMA_COMPL_SKIP_DEST_UNMAP; | ||
108 | submit->cb_fn = cb_fn_orig; | 81 | submit->cb_fn = cb_fn_orig; |
109 | submit->cb_param = cb_param_orig; | 82 | submit->cb_param = cb_param_orig; |
110 | if (cb_fn_orig) | 83 | if (cb_fn_orig) |
111 | dma_flags |= DMA_PREP_INTERRUPT; | 84 | dma_flags |= DMA_PREP_INTERRUPT; |
112 | } | 85 | } |
113 | if (submit->flags & ASYNC_TX_FENCE) | ||
114 | dma_flags |= DMA_PREP_FENCE; | ||
115 | 86 | ||
116 | /* Since we have clobbered the src_list we are committed | 87 | /* Drivers force forward progress in case they can not provide |
117 | * to doing this asynchronously. Drivers force forward | 88 | * a descriptor |
118 | * progress in case they can not provide a descriptor | ||
119 | */ | 89 | */ |
120 | for (;;) { | 90 | for (;;) { |
91 | dma_dest[0] = unmap->addr[disks - 2]; | ||
92 | dma_dest[1] = unmap->addr[disks - 1]; | ||
121 | tx = dma->device_prep_dma_pq(chan, dma_dest, | 93 | tx = dma->device_prep_dma_pq(chan, dma_dest, |
122 | &dma_src[src_off], | 94 | &unmap->addr[src_off], |
123 | pq_src_cnt, | 95 | pq_src_cnt, |
124 | &coefs[src_off], len, | 96 | &scfs[src_off], unmap->len, |
125 | dma_flags); | 97 | dma_flags); |
126 | if (likely(tx)) | 98 | if (likely(tx)) |
127 | break; | 99 | break; |
@@ -129,6 +101,7 @@ do_async_gen_syndrome(struct dma_chan *chan, struct page **blocks, | |||
129 | dma_async_issue_pending(chan); | 101 | dma_async_issue_pending(chan); |
130 | } | 102 | } |
131 | 103 | ||
104 | dma_set_unmap(tx, unmap); | ||
132 | async_tx_submit(chan, tx, submit); | 105 | async_tx_submit(chan, tx, submit); |
133 | submit->depend_tx = tx; | 106 | submit->depend_tx = tx; |
134 | 107 | ||
@@ -188,10 +161,6 @@ do_sync_gen_syndrome(struct page **blocks, unsigned int offset, int disks, | |||
188 | * set to NULL those buffers will be replaced with the raid6_zero_page | 161 | * set to NULL those buffers will be replaced with the raid6_zero_page |
189 | * in the synchronous path and omitted in the hardware-asynchronous | 162 | * in the synchronous path and omitted in the hardware-asynchronous |
190 | * path. | 163 | * path. |
191 | * | ||
192 | * 'blocks' note: if submit->scribble is NULL then the contents of | ||
193 | * 'blocks' may be overwritten to perform address conversions | ||
194 | * (dma_map_page() or page_address()). | ||
195 | */ | 164 | */ |
196 | struct dma_async_tx_descriptor * | 165 | struct dma_async_tx_descriptor * |
197 | async_gen_syndrome(struct page **blocks, unsigned int offset, int disks, | 166 | async_gen_syndrome(struct page **blocks, unsigned int offset, int disks, |
@@ -202,26 +171,69 @@ async_gen_syndrome(struct page **blocks, unsigned int offset, int disks, | |||
202 | &P(blocks, disks), 2, | 171 | &P(blocks, disks), 2, |
203 | blocks, src_cnt, len); | 172 | blocks, src_cnt, len); |
204 | struct dma_device *device = chan ? chan->device : NULL; | 173 | struct dma_device *device = chan ? chan->device : NULL; |
205 | dma_addr_t *dma_src = NULL; | 174 | struct dmaengine_unmap_data *unmap = NULL; |
206 | 175 | ||
207 | BUG_ON(disks > 255 || !(P(blocks, disks) || Q(blocks, disks))); | 176 | BUG_ON(disks > 255 || !(P(blocks, disks) || Q(blocks, disks))); |
208 | 177 | ||
209 | if (submit->scribble) | 178 | if (device) |
210 | dma_src = submit->scribble; | 179 | unmap = dmaengine_get_unmap_data(device->dev, disks, GFP_NOIO); |
211 | else if (sizeof(dma_addr_t) <= sizeof(struct page *)) | ||
212 | dma_src = (dma_addr_t *) blocks; | ||
213 | 180 | ||
214 | if (dma_src && device && | 181 | if (unmap && |
215 | (src_cnt <= dma_maxpq(device, 0) || | 182 | (src_cnt <= dma_maxpq(device, 0) || |
216 | dma_maxpq(device, DMA_PREP_CONTINUE) > 0) && | 183 | dma_maxpq(device, DMA_PREP_CONTINUE) > 0) && |
217 | is_dma_pq_aligned(device, offset, 0, len)) { | 184 | is_dma_pq_aligned(device, offset, 0, len)) { |
185 | struct dma_async_tx_descriptor *tx; | ||
186 | enum dma_ctrl_flags dma_flags = 0; | ||
187 | unsigned char coefs[src_cnt]; | ||
188 | int i, j; | ||
189 | |||
218 | /* run the p+q asynchronously */ | 190 | /* run the p+q asynchronously */ |
219 | pr_debug("%s: (async) disks: %d len: %zu\n", | 191 | pr_debug("%s: (async) disks: %d len: %zu\n", |
220 | __func__, disks, len); | 192 | __func__, disks, len); |
221 | return do_async_gen_syndrome(chan, blocks, raid6_gfexp, offset, | 193 | |
222 | disks, len, dma_src, submit); | 194 | /* convert source addresses being careful to collapse 'empty' |
195 | * sources and update the coefficients accordingly | ||
196 | */ | ||
197 | unmap->len = len; | ||
198 | for (i = 0, j = 0; i < src_cnt; i++) { | ||
199 | if (blocks[i] == NULL) | ||
200 | continue; | ||
201 | unmap->addr[j] = dma_map_page(device->dev, blocks[i], offset, | ||
202 | len, DMA_TO_DEVICE); | ||
203 | coefs[j] = raid6_gfexp[i]; | ||
204 | unmap->to_cnt++; | ||
205 | j++; | ||
206 | } | ||
207 | |||
208 | /* | ||
209 | * DMAs use destinations as sources, | ||
210 | * so use BIDIRECTIONAL mapping | ||
211 | */ | ||
212 | unmap->bidi_cnt++; | ||
213 | if (P(blocks, disks)) | ||
214 | unmap->addr[j++] = dma_map_page(device->dev, P(blocks, disks), | ||
215 | offset, len, DMA_BIDIRECTIONAL); | ||
216 | else { | ||
217 | unmap->addr[j++] = 0; | ||
218 | dma_flags |= DMA_PREP_PQ_DISABLE_P; | ||
219 | } | ||
220 | |||
221 | unmap->bidi_cnt++; | ||
222 | if (Q(blocks, disks)) | ||
223 | unmap->addr[j++] = dma_map_page(device->dev, Q(blocks, disks), | ||
224 | offset, len, DMA_BIDIRECTIONAL); | ||
225 | else { | ||
226 | unmap->addr[j++] = 0; | ||
227 | dma_flags |= DMA_PREP_PQ_DISABLE_Q; | ||
228 | } | ||
229 | |||
230 | tx = do_async_gen_syndrome(chan, coefs, j, unmap, dma_flags, submit); | ||
231 | dmaengine_unmap_put(unmap); | ||
232 | return tx; | ||
223 | } | 233 | } |
224 | 234 | ||
235 | dmaengine_unmap_put(unmap); | ||
236 | |||
225 | /* run the pq synchronously */ | 237 | /* run the pq synchronously */ |
226 | pr_debug("%s: (sync) disks: %d len: %zu\n", __func__, disks, len); | 238 | pr_debug("%s: (sync) disks: %d len: %zu\n", __func__, disks, len); |
227 | 239 | ||
@@ -277,50 +289,60 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks, | |||
277 | struct dma_async_tx_descriptor *tx; | 289 | struct dma_async_tx_descriptor *tx; |
278 | unsigned char coefs[disks-2]; | 290 | unsigned char coefs[disks-2]; |
279 | enum dma_ctrl_flags dma_flags = submit->cb_fn ? DMA_PREP_INTERRUPT : 0; | 291 | enum dma_ctrl_flags dma_flags = submit->cb_fn ? DMA_PREP_INTERRUPT : 0; |
280 | dma_addr_t *dma_src = NULL; | 292 | struct dmaengine_unmap_data *unmap = NULL; |
281 | int src_cnt = 0; | ||
282 | 293 | ||
283 | BUG_ON(disks < 4); | 294 | BUG_ON(disks < 4); |
284 | 295 | ||
285 | if (submit->scribble) | 296 | if (device) |
286 | dma_src = submit->scribble; | 297 | unmap = dmaengine_get_unmap_data(device->dev, disks, GFP_NOIO); |
287 | else if (sizeof(dma_addr_t) <= sizeof(struct page *)) | ||
288 | dma_src = (dma_addr_t *) blocks; | ||
289 | 298 | ||
290 | if (dma_src && device && disks <= dma_maxpq(device, 0) && | 299 | if (unmap && disks <= dma_maxpq(device, 0) && |
291 | is_dma_pq_aligned(device, offset, 0, len)) { | 300 | is_dma_pq_aligned(device, offset, 0, len)) { |
292 | struct device *dev = device->dev; | 301 | struct device *dev = device->dev; |
293 | dma_addr_t *pq = &dma_src[disks-2]; | 302 | dma_addr_t pq[2]; |
294 | int i; | 303 | int i, j = 0, src_cnt = 0; |
295 | 304 | ||
296 | pr_debug("%s: (async) disks: %d len: %zu\n", | 305 | pr_debug("%s: (async) disks: %d len: %zu\n", |
297 | __func__, disks, len); | 306 | __func__, disks, len); |
298 | if (!P(blocks, disks)) | 307 | |
308 | unmap->len = len; | ||
309 | for (i = 0; i < disks-2; i++) | ||
310 | if (likely(blocks[i])) { | ||
311 | unmap->addr[j] = dma_map_page(dev, blocks[i], | ||
312 | offset, len, | ||
313 | DMA_TO_DEVICE); | ||
314 | coefs[j] = raid6_gfexp[i]; | ||
315 | unmap->to_cnt++; | ||
316 | src_cnt++; | ||
317 | j++; | ||
318 | } | ||
319 | |||
320 | if (!P(blocks, disks)) { | ||
321 | pq[0] = 0; | ||
299 | dma_flags |= DMA_PREP_PQ_DISABLE_P; | 322 | dma_flags |= DMA_PREP_PQ_DISABLE_P; |
300 | else | 323 | } else { |
301 | pq[0] = dma_map_page(dev, P(blocks, disks), | 324 | pq[0] = dma_map_page(dev, P(blocks, disks), |
302 | offset, len, | 325 | offset, len, |
303 | DMA_TO_DEVICE); | 326 | DMA_TO_DEVICE); |
304 | if (!Q(blocks, disks)) | 327 | unmap->addr[j++] = pq[0]; |
328 | unmap->to_cnt++; | ||
329 | } | ||
330 | if (!Q(blocks, disks)) { | ||
331 | pq[1] = 0; | ||
305 | dma_flags |= DMA_PREP_PQ_DISABLE_Q; | 332 | dma_flags |= DMA_PREP_PQ_DISABLE_Q; |
306 | else | 333 | } else { |
307 | pq[1] = dma_map_page(dev, Q(blocks, disks), | 334 | pq[1] = dma_map_page(dev, Q(blocks, disks), |
308 | offset, len, | 335 | offset, len, |
309 | DMA_TO_DEVICE); | 336 | DMA_TO_DEVICE); |
337 | unmap->addr[j++] = pq[1]; | ||
338 | unmap->to_cnt++; | ||
339 | } | ||
310 | 340 | ||
311 | if (submit->flags & ASYNC_TX_FENCE) | 341 | if (submit->flags & ASYNC_TX_FENCE) |
312 | dma_flags |= DMA_PREP_FENCE; | 342 | dma_flags |= DMA_PREP_FENCE; |
313 | for (i = 0; i < disks-2; i++) | ||
314 | if (likely(blocks[i])) { | ||
315 | dma_src[src_cnt] = dma_map_page(dev, blocks[i], | ||
316 | offset, len, | ||
317 | DMA_TO_DEVICE); | ||
318 | coefs[src_cnt] = raid6_gfexp[i]; | ||
319 | src_cnt++; | ||
320 | } | ||
321 | |||
322 | for (;;) { | 343 | for (;;) { |
323 | tx = device->device_prep_dma_pq_val(chan, pq, dma_src, | 344 | tx = device->device_prep_dma_pq_val(chan, pq, |
345 | unmap->addr, | ||
324 | src_cnt, | 346 | src_cnt, |
325 | coefs, | 347 | coefs, |
326 | len, pqres, | 348 | len, pqres, |
@@ -330,6 +352,8 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks, | |||
330 | async_tx_quiesce(&submit->depend_tx); | 352 | async_tx_quiesce(&submit->depend_tx); |
331 | dma_async_issue_pending(chan); | 353 | dma_async_issue_pending(chan); |
332 | } | 354 | } |
355 | |||
356 | dma_set_unmap(tx, unmap); | ||
333 | async_tx_submit(chan, tx, submit); | 357 | async_tx_submit(chan, tx, submit); |
334 | 358 | ||
335 | return tx; | 359 | return tx; |