diff options
author | Dan Williams <dan.j.williams@intel.com> | 2009-08-28 17:32:04 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2009-08-29 22:12:39 -0400 |
commit | 7bf649aee8ac93ecc280f8745dcf8ec19d7b9fb1 (patch) | |
tree | b35282323d278afb16c18a42c8c0db34508cef6c | |
parent | 72be12f0c39df46832403cbfd82e132a883f5ddc (diff) |
iop-adma: P+Q support for iop13xx adma engines
iop33x support is not included because that engine is a bit more awkward
to handle in that it can either be in xor mode or pq mode. The
dmaengine/async_tx layers currently only comprehend static capabilities.
Note iop13xx does not support hardware PQ continuation so the driver
must handle the DMA_PREP_CONTINUE flag for operations across > 16
sources. From the comment for dma_maxpq:
/* When an engine does not support native continuation we need 3 extra
* source slots to reuse P and Q with the following coefficients:
* 1/ {00} * P : remove P from Q', but use it as a source for P'
* 2/ {01} * Q : use Q to continue Q' calculation
* 3/ {00} * Q : subtract Q from P' to cancel (2)
*/
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r-- | arch/arm/include/asm/hardware/iop3xx-adma.h | 76 | ||||
-rw-r--r-- | arch/arm/include/asm/hardware/iop_adma.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-iop13xx/include/mach/adma.h | 107 | ||||
-rw-r--r-- | drivers/dma/iop-adma.c | 231 |
4 files changed, 381 insertions, 34 deletions
diff --git a/arch/arm/include/asm/hardware/iop3xx-adma.h b/arch/arm/include/asm/hardware/iop3xx-adma.h index 26eefea02314..1a8c7279a28b 100644 --- a/arch/arm/include/asm/hardware/iop3xx-adma.h +++ b/arch/arm/include/asm/hardware/iop3xx-adma.h | |||
@@ -187,11 +187,74 @@ union iop3xx_desc { | |||
187 | void *ptr; | 187 | void *ptr; |
188 | }; | 188 | }; |
189 | 189 | ||
190 | /* No support for p+q operations */ | ||
191 | static inline int | ||
192 | iop_chan_pq_slot_count(size_t len, int src_cnt, int *slots_per_op) | ||
193 | { | ||
194 | BUG(); | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | static inline void | ||
199 | iop_desc_init_pq(struct iop_adma_desc_slot *desc, int src_cnt, | ||
200 | unsigned long flags) | ||
201 | { | ||
202 | BUG(); | ||
203 | } | ||
204 | |||
205 | static inline void | ||
206 | iop_desc_set_pq_addr(struct iop_adma_desc_slot *desc, dma_addr_t *addr) | ||
207 | { | ||
208 | BUG(); | ||
209 | } | ||
210 | |||
211 | static inline void | ||
212 | iop_desc_set_pq_src_addr(struct iop_adma_desc_slot *desc, int src_idx, | ||
213 | dma_addr_t addr, unsigned char coef) | ||
214 | { | ||
215 | BUG(); | ||
216 | } | ||
217 | |||
218 | static inline int | ||
219 | iop_chan_pq_zero_sum_slot_count(size_t len, int src_cnt, int *slots_per_op) | ||
220 | { | ||
221 | BUG(); | ||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static inline void | ||
226 | iop_desc_init_pq_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt, | ||
227 | unsigned long flags) | ||
228 | { | ||
229 | BUG(); | ||
230 | } | ||
231 | |||
232 | static inline void | ||
233 | iop_desc_set_pq_zero_sum_byte_count(struct iop_adma_desc_slot *desc, u32 len) | ||
234 | { | ||
235 | BUG(); | ||
236 | } | ||
237 | |||
238 | #define iop_desc_set_pq_zero_sum_src_addr iop_desc_set_pq_src_addr | ||
239 | |||
240 | static inline void | ||
241 | iop_desc_set_pq_zero_sum_addr(struct iop_adma_desc_slot *desc, int pq_idx, | ||
242 | dma_addr_t *src) | ||
243 | { | ||
244 | BUG(); | ||
245 | } | ||
246 | |||
190 | static inline int iop_adma_get_max_xor(void) | 247 | static inline int iop_adma_get_max_xor(void) |
191 | { | 248 | { |
192 | return 32; | 249 | return 32; |
193 | } | 250 | } |
194 | 251 | ||
252 | static inline int iop_adma_get_max_pq(void) | ||
253 | { | ||
254 | BUG(); | ||
255 | return 0; | ||
256 | } | ||
257 | |||
195 | static inline u32 iop_chan_get_current_descriptor(struct iop_adma_chan *chan) | 258 | static inline u32 iop_chan_get_current_descriptor(struct iop_adma_chan *chan) |
196 | { | 259 | { |
197 | int id = chan->device->id; | 260 | int id = chan->device->id; |
@@ -332,6 +395,11 @@ static inline int iop_chan_zero_sum_slot_count(size_t len, int src_cnt, | |||
332 | return slot_cnt; | 395 | return slot_cnt; |
333 | } | 396 | } |
334 | 397 | ||
398 | static inline int iop_desc_is_pq(struct iop_adma_desc_slot *desc) | ||
399 | { | ||
400 | return 0; | ||
401 | } | ||
402 | |||
335 | static inline u32 iop_desc_get_dest_addr(struct iop_adma_desc_slot *desc, | 403 | static inline u32 iop_desc_get_dest_addr(struct iop_adma_desc_slot *desc, |
336 | struct iop_adma_chan *chan) | 404 | struct iop_adma_chan *chan) |
337 | { | 405 | { |
@@ -349,6 +417,14 @@ static inline u32 iop_desc_get_dest_addr(struct iop_adma_desc_slot *desc, | |||
349 | return 0; | 417 | return 0; |
350 | } | 418 | } |
351 | 419 | ||
420 | |||
421 | static inline u32 iop_desc_get_qdest_addr(struct iop_adma_desc_slot *desc, | ||
422 | struct iop_adma_chan *chan) | ||
423 | { | ||
424 | BUG(); | ||
425 | return 0; | ||
426 | } | ||
427 | |||
352 | static inline u32 iop_desc_get_byte_count(struct iop_adma_desc_slot *desc, | 428 | static inline u32 iop_desc_get_byte_count(struct iop_adma_desc_slot *desc, |
353 | struct iop_adma_chan *chan) | 429 | struct iop_adma_chan *chan) |
354 | { | 430 | { |
diff --git a/arch/arm/include/asm/hardware/iop_adma.h b/arch/arm/include/asm/hardware/iop_adma.h index 385c6e8cbbd2..bbe8a0475cad 100644 --- a/arch/arm/include/asm/hardware/iop_adma.h +++ b/arch/arm/include/asm/hardware/iop_adma.h | |||
@@ -106,6 +106,7 @@ struct iop_adma_desc_slot { | |||
106 | union { | 106 | union { |
107 | u32 *xor_check_result; | 107 | u32 *xor_check_result; |
108 | u32 *crc32_result; | 108 | u32 *crc32_result; |
109 | u32 *pq_check_result; | ||
109 | }; | 110 | }; |
110 | }; | 111 | }; |
111 | 112 | ||
diff --git a/arch/arm/mach-iop13xx/include/mach/adma.h b/arch/arm/mach-iop13xx/include/mach/adma.h index 1cd31df8924d..6d3782d85a9f 100644 --- a/arch/arm/mach-iop13xx/include/mach/adma.h +++ b/arch/arm/mach-iop13xx/include/mach/adma.h | |||
@@ -150,6 +150,8 @@ static inline int iop_adma_get_max_xor(void) | |||
150 | return 16; | 150 | return 16; |
151 | } | 151 | } |
152 | 152 | ||
153 | #define iop_adma_get_max_pq iop_adma_get_max_xor | ||
154 | |||
153 | static inline u32 iop_chan_get_current_descriptor(struct iop_adma_chan *chan) | 155 | static inline u32 iop_chan_get_current_descriptor(struct iop_adma_chan *chan) |
154 | { | 156 | { |
155 | return __raw_readl(ADMA_ADAR(chan)); | 157 | return __raw_readl(ADMA_ADAR(chan)); |
@@ -211,7 +213,10 @@ iop_chan_xor_slot_count(size_t len, int src_cnt, int *slots_per_op) | |||
211 | #define IOP_ADMA_MAX_BYTE_COUNT ADMA_MAX_BYTE_COUNT | 213 | #define IOP_ADMA_MAX_BYTE_COUNT ADMA_MAX_BYTE_COUNT |
212 | #define IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT ADMA_MAX_BYTE_COUNT | 214 | #define IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT ADMA_MAX_BYTE_COUNT |
213 | #define IOP_ADMA_XOR_MAX_BYTE_COUNT ADMA_MAX_BYTE_COUNT | 215 | #define IOP_ADMA_XOR_MAX_BYTE_COUNT ADMA_MAX_BYTE_COUNT |
216 | #define IOP_ADMA_PQ_MAX_BYTE_COUNT ADMA_MAX_BYTE_COUNT | ||
214 | #define iop_chan_zero_sum_slot_count(l, s, o) iop_chan_xor_slot_count(l, s, o) | 217 | #define iop_chan_zero_sum_slot_count(l, s, o) iop_chan_xor_slot_count(l, s, o) |
218 | #define iop_chan_pq_slot_count iop_chan_xor_slot_count | ||
219 | #define iop_chan_pq_zero_sum_slot_count iop_chan_xor_slot_count | ||
215 | 220 | ||
216 | static inline u32 iop_desc_get_dest_addr(struct iop_adma_desc_slot *desc, | 221 | static inline u32 iop_desc_get_dest_addr(struct iop_adma_desc_slot *desc, |
217 | struct iop_adma_chan *chan) | 222 | struct iop_adma_chan *chan) |
@@ -220,6 +225,13 @@ static inline u32 iop_desc_get_dest_addr(struct iop_adma_desc_slot *desc, | |||
220 | return hw_desc->dest_addr; | 225 | return hw_desc->dest_addr; |
221 | } | 226 | } |
222 | 227 | ||
228 | static inline u32 iop_desc_get_qdest_addr(struct iop_adma_desc_slot *desc, | ||
229 | struct iop_adma_chan *chan) | ||
230 | { | ||
231 | struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; | ||
232 | return hw_desc->q_dest_addr; | ||
233 | } | ||
234 | |||
223 | static inline u32 iop_desc_get_byte_count(struct iop_adma_desc_slot *desc, | 235 | static inline u32 iop_desc_get_byte_count(struct iop_adma_desc_slot *desc, |
224 | struct iop_adma_chan *chan) | 236 | struct iop_adma_chan *chan) |
225 | { | 237 | { |
@@ -319,6 +331,58 @@ iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt, | |||
319 | return 1; | 331 | return 1; |
320 | } | 332 | } |
321 | 333 | ||
334 | static inline void | ||
335 | iop_desc_init_pq(struct iop_adma_desc_slot *desc, int src_cnt, | ||
336 | unsigned long flags) | ||
337 | { | ||
338 | struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; | ||
339 | union { | ||
340 | u32 value; | ||
341 | struct iop13xx_adma_desc_ctrl field; | ||
342 | } u_desc_ctrl; | ||
343 | |||
344 | u_desc_ctrl.value = 0; | ||
345 | u_desc_ctrl.field.src_select = src_cnt - 1; | ||
346 | u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */ | ||
347 | u_desc_ctrl.field.pq_xfer_en = 1; | ||
348 | u_desc_ctrl.field.p_xfer_dis = !!(flags & DMA_PREP_PQ_DISABLE_P); | ||
349 | u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT; | ||
350 | hw_desc->desc_ctrl = u_desc_ctrl.value; | ||
351 | } | ||
352 | |||
353 | static inline int iop_desc_is_pq(struct iop_adma_desc_slot *desc) | ||
354 | { | ||
355 | struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; | ||
356 | union { | ||
357 | u32 value; | ||
358 | struct iop13xx_adma_desc_ctrl field; | ||
359 | } u_desc_ctrl; | ||
360 | |||
361 | u_desc_ctrl.value = hw_desc->desc_ctrl; | ||
362 | return u_desc_ctrl.field.pq_xfer_en; | ||
363 | } | ||
364 | |||
365 | static inline void | ||
366 | iop_desc_init_pq_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt, | ||
367 | unsigned long flags) | ||
368 | { | ||
369 | struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; | ||
370 | union { | ||
371 | u32 value; | ||
372 | struct iop13xx_adma_desc_ctrl field; | ||
373 | } u_desc_ctrl; | ||
374 | |||
375 | u_desc_ctrl.value = 0; | ||
376 | u_desc_ctrl.field.src_select = src_cnt - 1; | ||
377 | u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */ | ||
378 | u_desc_ctrl.field.zero_result = 1; | ||
379 | u_desc_ctrl.field.status_write_back_en = 1; | ||
380 | u_desc_ctrl.field.pq_xfer_en = 1; | ||
381 | u_desc_ctrl.field.p_xfer_dis = !!(flags & DMA_PREP_PQ_DISABLE_P); | ||
382 | u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT; | ||
383 | hw_desc->desc_ctrl = u_desc_ctrl.value; | ||
384 | } | ||
385 | |||
322 | static inline void iop_desc_set_byte_count(struct iop_adma_desc_slot *desc, | 386 | static inline void iop_desc_set_byte_count(struct iop_adma_desc_slot *desc, |
323 | struct iop_adma_chan *chan, | 387 | struct iop_adma_chan *chan, |
324 | u32 byte_count) | 388 | u32 byte_count) |
@@ -351,6 +415,7 @@ iop_desc_set_zero_sum_byte_count(struct iop_adma_desc_slot *desc, u32 len) | |||
351 | } | 415 | } |
352 | } | 416 | } |
353 | 417 | ||
418 | #define iop_desc_set_pq_zero_sum_byte_count iop_desc_set_zero_sum_byte_count | ||
354 | 419 | ||
355 | static inline void iop_desc_set_dest_addr(struct iop_adma_desc_slot *desc, | 420 | static inline void iop_desc_set_dest_addr(struct iop_adma_desc_slot *desc, |
356 | struct iop_adma_chan *chan, | 421 | struct iop_adma_chan *chan, |
@@ -361,6 +426,16 @@ static inline void iop_desc_set_dest_addr(struct iop_adma_desc_slot *desc, | |||
361 | hw_desc->upper_dest_addr = 0; | 426 | hw_desc->upper_dest_addr = 0; |
362 | } | 427 | } |
363 | 428 | ||
429 | static inline void | ||
430 | iop_desc_set_pq_addr(struct iop_adma_desc_slot *desc, dma_addr_t *addr) | ||
431 | { | ||
432 | struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc; | ||
433 | |||
434 | hw_desc->dest_addr = addr[0]; | ||
435 | hw_desc->q_dest_addr = addr[1]; | ||
436 | hw_desc->upper_dest_addr = 0; | ||
437 | } | ||
438 | |||
364 | static inline void iop_desc_set_memcpy_src_addr(struct iop_adma_desc_slot *desc, | 439 | static inline void iop_desc_set_memcpy_src_addr(struct iop_adma_desc_slot *desc, |
365 | dma_addr_t addr) | 440 | dma_addr_t addr) |
366 | { | 441 | { |
@@ -389,6 +464,29 @@ static inline void iop_desc_set_xor_src_addr(struct iop_adma_desc_slot *desc, | |||
389 | } | 464 | } |
390 | 465 | ||
391 | static inline void | 466 | static inline void |
467 | iop_desc_set_pq_src_addr(struct iop_adma_desc_slot *desc, int src_idx, | ||
468 | dma_addr_t addr, unsigned char coef) | ||
469 | { | ||
470 | int slot_cnt = desc->slot_cnt, slots_per_op = desc->slots_per_op; | ||
471 | struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc, *iter; | ||
472 | struct iop13xx_adma_src *src; | ||
473 | int i = 0; | ||
474 | |||
475 | do { | ||
476 | iter = iop_hw_desc_slot_idx(hw_desc, i); | ||
477 | src = &iter->src[src_idx]; | ||
478 | src->src_addr = addr; | ||
479 | src->pq_upper_src_addr = 0; | ||
480 | src->pq_dmlt = coef; | ||
481 | slot_cnt -= slots_per_op; | ||
482 | if (slot_cnt) { | ||
483 | i += slots_per_op; | ||
484 | addr += IOP_ADMA_PQ_MAX_BYTE_COUNT; | ||
485 | } | ||
486 | } while (slot_cnt); | ||
487 | } | ||
488 | |||
489 | static inline void | ||
392 | iop_desc_init_interrupt(struct iop_adma_desc_slot *desc, | 490 | iop_desc_init_interrupt(struct iop_adma_desc_slot *desc, |
393 | struct iop_adma_chan *chan) | 491 | struct iop_adma_chan *chan) |
394 | { | 492 | { |
@@ -399,6 +497,15 @@ iop_desc_init_interrupt(struct iop_adma_desc_slot *desc, | |||
399 | } | 497 | } |
400 | 498 | ||
401 | #define iop_desc_set_zero_sum_src_addr iop_desc_set_xor_src_addr | 499 | #define iop_desc_set_zero_sum_src_addr iop_desc_set_xor_src_addr |
500 | #define iop_desc_set_pq_zero_sum_src_addr iop_desc_set_pq_src_addr | ||
501 | |||
502 | static inline void | ||
503 | iop_desc_set_pq_zero_sum_addr(struct iop_adma_desc_slot *desc, int pq_idx, | ||
504 | dma_addr_t *src) | ||
505 | { | ||
506 | iop_desc_set_xor_src_addr(desc, pq_idx, src[pq_idx]); | ||
507 | iop_desc_set_xor_src_addr(desc, pq_idx+1, src[pq_idx+1]); | ||
508 | } | ||
402 | 509 | ||
403 | static inline void iop_desc_set_next_desc(struct iop_adma_desc_slot *desc, | 510 | static inline void iop_desc_set_next_desc(struct iop_adma_desc_slot *desc, |
404 | u32 next_desc_addr) | 511 | u32 next_desc_addr) |
diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c index 9c752bd295e1..5a0f4fe2ee6e 100644 --- a/drivers/dma/iop-adma.c +++ b/drivers/dma/iop-adma.c | |||
@@ -57,6 +57,80 @@ static void iop_adma_free_slots(struct iop_adma_desc_slot *slot) | |||
57 | } | 57 | } |
58 | } | 58 | } |
59 | 59 | ||
60 | static void | ||
61 | iop_desc_unmap(struct iop_adma_chan *iop_chan, struct iop_adma_desc_slot *desc) | ||
62 | { | ||
63 | struct dma_async_tx_descriptor *tx = &desc->async_tx; | ||
64 | struct iop_adma_desc_slot *unmap = desc->group_head; | ||
65 | struct device *dev = &iop_chan->device->pdev->dev; | ||
66 | u32 len = unmap->unmap_len; | ||
67 | enum dma_ctrl_flags flags = tx->flags; | ||
68 | u32 src_cnt; | ||
69 | dma_addr_t addr; | ||
70 | dma_addr_t dest; | ||
71 | |||
72 | src_cnt = unmap->unmap_src_cnt; | ||
73 | dest = iop_desc_get_dest_addr(unmap, iop_chan); | ||
74 | if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP)) { | ||
75 | enum dma_data_direction dir; | ||
76 | |||
77 | if (src_cnt > 1) /* is xor? */ | ||
78 | dir = DMA_BIDIRECTIONAL; | ||
79 | else | ||
80 | dir = DMA_FROM_DEVICE; | ||
81 | |||
82 | dma_unmap_page(dev, dest, len, dir); | ||
83 | } | ||
84 | |||
85 | if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) { | ||
86 | while (src_cnt--) { | ||
87 | addr = iop_desc_get_src_addr(unmap, iop_chan, src_cnt); | ||
88 | if (addr == dest) | ||
89 | continue; | ||
90 | dma_unmap_page(dev, addr, len, DMA_TO_DEVICE); | ||
91 | } | ||
92 | } | ||
93 | desc->group_head = NULL; | ||
94 | } | ||
95 | |||
96 | static void | ||
97 | iop_desc_unmap_pq(struct iop_adma_chan *iop_chan, struct iop_adma_desc_slot *desc) | ||
98 | { | ||
99 | struct dma_async_tx_descriptor *tx = &desc->async_tx; | ||
100 | struct iop_adma_desc_slot *unmap = desc->group_head; | ||
101 | struct device *dev = &iop_chan->device->pdev->dev; | ||
102 | u32 len = unmap->unmap_len; | ||
103 | enum dma_ctrl_flags flags = tx->flags; | ||
104 | u32 src_cnt = unmap->unmap_src_cnt; | ||
105 | dma_addr_t pdest = iop_desc_get_dest_addr(unmap, iop_chan); | ||
106 | dma_addr_t qdest = iop_desc_get_qdest_addr(unmap, iop_chan); | ||
107 | int i; | ||
108 | |||
109 | if (tx->flags & DMA_PREP_CONTINUE) | ||
110 | src_cnt -= 3; | ||
111 | |||
112 | if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP) && !desc->pq_check_result) { | ||
113 | dma_unmap_page(dev, pdest, len, DMA_BIDIRECTIONAL); | ||
114 | dma_unmap_page(dev, qdest, len, DMA_BIDIRECTIONAL); | ||
115 | } | ||
116 | |||
117 | if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) { | ||
118 | dma_addr_t addr; | ||
119 | |||
120 | for (i = 0; i < src_cnt; i++) { | ||
121 | addr = iop_desc_get_src_addr(unmap, iop_chan, i); | ||
122 | dma_unmap_page(dev, addr, len, DMA_TO_DEVICE); | ||
123 | } | ||
124 | if (desc->pq_check_result) { | ||
125 | dma_unmap_page(dev, pdest, len, DMA_TO_DEVICE); | ||
126 | dma_unmap_page(dev, qdest, len, DMA_TO_DEVICE); | ||
127 | } | ||
128 | } | ||
129 | |||
130 | desc->group_head = NULL; | ||
131 | } | ||
132 | |||
133 | |||
60 | static dma_cookie_t | 134 | static dma_cookie_t |
61 | iop_adma_run_tx_complete_actions(struct iop_adma_desc_slot *desc, | 135 | iop_adma_run_tx_complete_actions(struct iop_adma_desc_slot *desc, |
62 | struct iop_adma_chan *iop_chan, dma_cookie_t cookie) | 136 | struct iop_adma_chan *iop_chan, dma_cookie_t cookie) |
@@ -78,40 +152,10 @@ iop_adma_run_tx_complete_actions(struct iop_adma_desc_slot *desc, | |||
78 | * (unmap_single vs unmap_page?) | 152 | * (unmap_single vs unmap_page?) |
79 | */ | 153 | */ |
80 | if (desc->group_head && desc->unmap_len) { | 154 | if (desc->group_head && desc->unmap_len) { |
81 | struct iop_adma_desc_slot *unmap = desc->group_head; | 155 | if (iop_desc_is_pq(desc)) |
82 | struct device *dev = | 156 | iop_desc_unmap_pq(iop_chan, desc); |
83 | &iop_chan->device->pdev->dev; | 157 | else |
84 | u32 len = unmap->unmap_len; | 158 | iop_desc_unmap(iop_chan, desc); |
85 | enum dma_ctrl_flags flags = tx->flags; | ||
86 | u32 src_cnt; | ||
87 | dma_addr_t addr; | ||
88 | dma_addr_t dest; | ||
89 | |||
90 | src_cnt = unmap->unmap_src_cnt; | ||
91 | dest = iop_desc_get_dest_addr(unmap, iop_chan); | ||
92 | if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP)) { | ||
93 | enum dma_data_direction dir; | ||
94 | |||
95 | if (src_cnt > 1) /* is xor? */ | ||
96 | dir = DMA_BIDIRECTIONAL; | ||
97 | else | ||
98 | dir = DMA_FROM_DEVICE; | ||
99 | |||
100 | dma_unmap_page(dev, dest, len, dir); | ||
101 | } | ||
102 | |||
103 | if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) { | ||
104 | while (src_cnt--) { | ||
105 | addr = iop_desc_get_src_addr(unmap, | ||
106 | iop_chan, | ||
107 | src_cnt); | ||
108 | if (addr == dest) | ||
109 | continue; | ||
110 | dma_unmap_page(dev, addr, len, | ||
111 | DMA_TO_DEVICE); | ||
112 | } | ||
113 | } | ||
114 | desc->group_head = NULL; | ||
115 | } | 159 | } |
116 | } | 160 | } |
117 | 161 | ||
@@ -702,6 +746,118 @@ iop_adma_prep_dma_xor_val(struct dma_chan *chan, dma_addr_t *dma_src, | |||
702 | return sw_desc ? &sw_desc->async_tx : NULL; | 746 | return sw_desc ? &sw_desc->async_tx : NULL; |
703 | } | 747 | } |
704 | 748 | ||
749 | static struct dma_async_tx_descriptor * | ||
750 | iop_adma_prep_dma_pq(struct dma_chan *chan, dma_addr_t *dst, dma_addr_t *src, | ||
751 | unsigned int src_cnt, const unsigned char *scf, size_t len, | ||
752 | unsigned long flags) | ||
753 | { | ||
754 | struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan); | ||
755 | struct iop_adma_desc_slot *sw_desc, *g; | ||
756 | int slot_cnt, slots_per_op; | ||
757 | int continue_srcs; | ||
758 | |||
759 | if (unlikely(!len)) | ||
760 | return NULL; | ||
761 | BUG_ON(len > IOP_ADMA_XOR_MAX_BYTE_COUNT); | ||
762 | |||
763 | dev_dbg(iop_chan->device->common.dev, | ||
764 | "%s src_cnt: %d len: %u flags: %lx\n", | ||
765 | __func__, src_cnt, len, flags); | ||
766 | |||
767 | if (dmaf_p_disabled_continue(flags)) | ||
768 | continue_srcs = 1+src_cnt; | ||
769 | else if (dmaf_continue(flags)) | ||
770 | continue_srcs = 3+src_cnt; | ||
771 | else | ||
772 | continue_srcs = 0+src_cnt; | ||
773 | |||
774 | spin_lock_bh(&iop_chan->lock); | ||
775 | slot_cnt = iop_chan_pq_slot_count(len, continue_srcs, &slots_per_op); | ||
776 | sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op); | ||
777 | if (sw_desc) { | ||
778 | int i; | ||
779 | |||
780 | g = sw_desc->group_head; | ||
781 | iop_desc_set_byte_count(g, iop_chan, len); | ||
782 | |||
783 | /* even if P is disabled its destination address (bits | ||
784 | * [3:0]) must match Q. It is ok if P points to an | ||
785 | * invalid address, it won't be written. | ||
786 | */ | ||
787 | if (flags & DMA_PREP_PQ_DISABLE_P) | ||
788 | dst[0] = dst[1] & 0x7; | ||
789 | |||
790 | iop_desc_set_pq_addr(g, dst); | ||
791 | sw_desc->unmap_src_cnt = src_cnt; | ||
792 | sw_desc->unmap_len = len; | ||
793 | sw_desc->async_tx.flags = flags; | ||
794 | for (i = 0; i < src_cnt; i++) | ||
795 | iop_desc_set_pq_src_addr(g, i, src[i], scf[i]); | ||
796 | |||
797 | /* if we are continuing a previous operation factor in | ||
798 | * the old p and q values, see the comment for dma_maxpq | ||
799 | * in include/linux/dmaengine.h | ||
800 | */ | ||
801 | if (dmaf_p_disabled_continue(flags)) | ||
802 | iop_desc_set_pq_src_addr(g, i++, dst[1], 1); | ||
803 | else if (dmaf_continue(flags)) { | ||
804 | iop_desc_set_pq_src_addr(g, i++, dst[0], 0); | ||
805 | iop_desc_set_pq_src_addr(g, i++, dst[1], 1); | ||
806 | iop_desc_set_pq_src_addr(g, i++, dst[1], 0); | ||
807 | } | ||
808 | iop_desc_init_pq(g, i, flags); | ||
809 | } | ||
810 | spin_unlock_bh(&iop_chan->lock); | ||
811 | |||
812 | return sw_desc ? &sw_desc->async_tx : NULL; | ||
813 | } | ||
814 | |||
815 | static struct dma_async_tx_descriptor * | ||
816 | iop_adma_prep_dma_pq_val(struct dma_chan *chan, dma_addr_t *pq, dma_addr_t *src, | ||
817 | unsigned int src_cnt, const unsigned char *scf, | ||
818 | size_t len, enum sum_check_flags *pqres, | ||
819 | unsigned long flags) | ||
820 | { | ||
821 | struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan); | ||
822 | struct iop_adma_desc_slot *sw_desc, *g; | ||
823 | int slot_cnt, slots_per_op; | ||
824 | |||
825 | if (unlikely(!len)) | ||
826 | return NULL; | ||
827 | BUG_ON(len > IOP_ADMA_XOR_MAX_BYTE_COUNT); | ||
828 | |||
829 | dev_dbg(iop_chan->device->common.dev, "%s src_cnt: %d len: %u\n", | ||
830 | __func__, src_cnt, len); | ||
831 | |||
832 | spin_lock_bh(&iop_chan->lock); | ||
833 | slot_cnt = iop_chan_pq_zero_sum_slot_count(len, src_cnt + 2, &slots_per_op); | ||
834 | sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op); | ||
835 | if (sw_desc) { | ||
836 | /* for validate operations p and q are tagged onto the | ||
837 | * end of the source list | ||
838 | */ | ||
839 | int pq_idx = src_cnt; | ||
840 | |||
841 | g = sw_desc->group_head; | ||
842 | iop_desc_init_pq_zero_sum(g, src_cnt+2, flags); | ||
843 | iop_desc_set_pq_zero_sum_byte_count(g, len); | ||
844 | g->pq_check_result = pqres; | ||
845 | pr_debug("\t%s: g->pq_check_result: %p\n", | ||
846 | __func__, g->pq_check_result); | ||
847 | sw_desc->unmap_src_cnt = src_cnt+2; | ||
848 | sw_desc->unmap_len = len; | ||
849 | sw_desc->async_tx.flags = flags; | ||
850 | while (src_cnt--) | ||
851 | iop_desc_set_pq_zero_sum_src_addr(g, src_cnt, | ||
852 | src[src_cnt], | ||
853 | scf[src_cnt]); | ||
854 | iop_desc_set_pq_zero_sum_addr(g, pq_idx, src); | ||
855 | } | ||
856 | spin_unlock_bh(&iop_chan->lock); | ||
857 | |||
858 | return sw_desc ? &sw_desc->async_tx : NULL; | ||
859 | } | ||
860 | |||
705 | static void iop_adma_free_chan_resources(struct dma_chan *chan) | 861 | static void iop_adma_free_chan_resources(struct dma_chan *chan) |
706 | { | 862 | { |
707 | struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan); | 863 | struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan); |
@@ -1201,6 +1357,13 @@ static int __devinit iop_adma_probe(struct platform_device *pdev) | |||
1201 | if (dma_has_cap(DMA_XOR_VAL, dma_dev->cap_mask)) | 1357 | if (dma_has_cap(DMA_XOR_VAL, dma_dev->cap_mask)) |
1202 | dma_dev->device_prep_dma_xor_val = | 1358 | dma_dev->device_prep_dma_xor_val = |
1203 | iop_adma_prep_dma_xor_val; | 1359 | iop_adma_prep_dma_xor_val; |
1360 | if (dma_has_cap(DMA_PQ, dma_dev->cap_mask)) { | ||
1361 | dma_set_maxpq(dma_dev, iop_adma_get_max_pq(), 0); | ||
1362 | dma_dev->device_prep_dma_pq = iop_adma_prep_dma_pq; | ||
1363 | } | ||
1364 | if (dma_has_cap(DMA_PQ_VAL, dma_dev->cap_mask)) | ||
1365 | dma_dev->device_prep_dma_pq_val = | ||
1366 | iop_adma_prep_dma_pq_val; | ||
1204 | if (dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask)) | 1367 | if (dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask)) |
1205 | dma_dev->device_prep_dma_interrupt = | 1368 | dma_dev->device_prep_dma_interrupt = |
1206 | iop_adma_prep_dma_interrupt; | 1369 | iop_adma_prep_dma_interrupt; |