Commit a06d568f7c5e40e34ea64881842deb8f4382babf

Authored by Dan Williams
1 parent b0b42b16ff

async_xor: dma_map destination DMA_BIDIRECTIONAL

Mapping the destination multiple times is a misuse of the dma-api.
Since the destination may be reused as a source, ensure that it is only
mapped once and that it is mapped bidirectionally.  This appears to add
ugliness on the unmap side in that it always reads back the destination
address from the descriptor, but gcc can determine that dma_unmap is a
nop and not emit the code that calculates its arguments.

Cc: <stable@kernel.org>
Cc: Saeed Bishara <saeed@marvell.com>
Acked-by: Yuri Tikhonov <yur@emcraft.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>

Showing 3 changed files with 34 additions and 8 deletions Side-by-side Diff

crypto/async_tx/async_xor.c
... ... @@ -53,10 +53,17 @@
53 53 int xor_src_cnt;
54 54 dma_addr_t dma_dest;
55 55  
56   - dma_dest = dma_map_page(dma->dev, dest, offset, len, DMA_FROM_DEVICE);
57   - for (i = 0; i < src_cnt; i++)
  56 + /* map the dest bidrectional in case it is re-used as a source */
  57 + dma_dest = dma_map_page(dma->dev, dest, offset, len, DMA_BIDIRECTIONAL);
  58 + for (i = 0; i < src_cnt; i++) {
  59 + /* only map the dest once */
  60 + if (unlikely(src_list[i] == dest)) {
  61 + dma_src[i] = dma_dest;
  62 + continue;
  63 + }
58 64 dma_src[i] = dma_map_page(dma->dev, src_list[i], offset,
59 65 len, DMA_TO_DEVICE);
  66 + }
60 67  
61 68 while (src_cnt) {
62 69 async_flags = flags;
drivers/dma/iop-adma.c
... ... @@ -85,18 +85,28 @@
85 85 enum dma_ctrl_flags flags = desc->async_tx.flags;
86 86 u32 src_cnt;
87 87 dma_addr_t addr;
  88 + dma_addr_t dest;
88 89  
  90 + src_cnt = unmap->unmap_src_cnt;
  91 + dest = iop_desc_get_dest_addr(unmap, iop_chan);
89 92 if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
90   - addr = iop_desc_get_dest_addr(unmap, iop_chan);
91   - dma_unmap_page(dev, addr, len, DMA_FROM_DEVICE);
  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);
92 101 }
93 102  
94 103 if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
95   - src_cnt = unmap->unmap_src_cnt;
96 104 while (src_cnt--) {
97 105 addr = iop_desc_get_src_addr(unmap,
98 106 iop_chan,
99 107 src_cnt);
  108 + if (addr == dest)
  109 + continue;
100 110 dma_unmap_page(dev, addr, len,
101 111 DMA_TO_DEVICE);
102 112 }
drivers/dma/mv_xor.c
... ... @@ -311,17 +311,26 @@
311 311 enum dma_ctrl_flags flags = desc->async_tx.flags;
312 312 u32 src_cnt;
313 313 dma_addr_t addr;
  314 + dma_addr_t dest;
314 315  
  316 + src_cnt = unmap->unmap_src_cnt;
  317 + dest = mv_desc_get_dest_addr(unmap);
315 318 if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
316   - addr = mv_desc_get_dest_addr(unmap);
317   - dma_unmap_page(dev, addr, len, DMA_FROM_DEVICE);
  319 + enum dma_data_direction dir;
  320 +
  321 + if (src_cnt > 1) /* is xor ? */
  322 + dir = DMA_BIDIRECTIONAL;
  323 + else
  324 + dir = DMA_FROM_DEVICE;
  325 + dma_unmap_page(dev, dest, len, dir);
318 326 }
319 327  
320 328 if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
321   - src_cnt = unmap->unmap_src_cnt;
322 329 while (src_cnt--) {
323 330 addr = mv_desc_get_src_addr(unmap,
324 331 src_cnt);
  332 + if (addr == dest)
  333 + continue;
325 334 dma_unmap_page(dev, addr, len,
326 335 DMA_TO_DEVICE);
327 336 }