crypto: gcm - Add RFC4543 wrapper for GCM
[safe/jmp/linux-2.6] / crypto / async_tx / async_xor.c
index 56b5f98..079ae8c 100644 (file)
@@ -44,20 +44,23 @@ do_async_xor(struct dma_chan *chan, struct page *dest, struct page **src_list,
        void *cb_param_orig = submit->cb_param;
        enum async_tx_flags flags_orig = submit->flags;
        enum dma_ctrl_flags dma_flags;
-       int xor_src_cnt;
+       int xor_src_cnt = 0;
        dma_addr_t dma_dest;
 
        /* map the dest bidrectional in case it is re-used as a source */
        dma_dest = dma_map_page(dma->dev, dest, offset, len, DMA_BIDIRECTIONAL);
        for (i = 0; i < src_cnt; i++) {
                /* only map the dest once */
+               if (!src_list[i])
+                       continue;
                if (unlikely(src_list[i] == dest)) {
-                       dma_src[i] = dma_dest;
+                       dma_src[xor_src_cnt++] = dma_dest;
                        continue;
                }
-               dma_src[i] = dma_map_page(dma->dev, src_list[i], offset,
-                                         len, DMA_TO_DEVICE);
+               dma_src[xor_src_cnt++] = dma_map_page(dma->dev, src_list[i], offset,
+                                                     len, DMA_TO_DEVICE);
        }
+       src_cnt = xor_src_cnt;
 
        while (src_cnt) {
                submit->flags = flags_orig;
@@ -69,6 +72,7 @@ do_async_xor(struct dma_chan *chan, struct page *dest, struct page **src_list,
                 */
                if (src_cnt > xor_src_cnt) {
                        submit->flags &= ~ASYNC_TX_ACK;
+                       submit->flags |= ASYNC_TX_FENCE;
                        dma_flags = DMA_COMPL_SKIP_DEST_UNMAP;
                        submit->cb_fn = NULL;
                        submit->cb_param = NULL;
@@ -78,7 +82,8 @@ do_async_xor(struct dma_chan *chan, struct page *dest, struct page **src_list,
                }
                if (submit->cb_fn)
                        dma_flags |= DMA_PREP_INTERRUPT;
-
+               if (submit->flags & ASYNC_TX_FENCE)
+                       dma_flags |= DMA_PREP_FENCE;
                /* Since we have clobbered the src_list we are committed
                 * to doing this asynchronously.  Drivers force forward progress
                 * in case they can not provide a descriptor
@@ -121,7 +126,7 @@ do_sync_xor(struct page *dest, struct page **src_list, unsigned int offset,
            int src_cnt, size_t len, struct async_submit_ctl *submit)
 {
        int i;
-       int xor_src_cnt;
+       int xor_src_cnt = 0;
        int src_off = 0;
        void *dest_buf;
        void **srcs;
@@ -133,8 +138,9 @@ do_sync_xor(struct page *dest, struct page **src_list, unsigned int offset,
 
        /* convert to buffer pointers */
        for (i = 0; i < src_cnt; i++)
-               srcs[i] = page_address(src_list[i]) + offset;
-
+               if (src_list[i])
+                       srcs[xor_src_cnt++] = page_address(src_list[i]) + offset;
+       src_cnt = xor_src_cnt;
        /* set destination address */
        dest_buf = page_address(dest) + offset;
 
@@ -191,7 +197,7 @@ async_xor(struct page *dest, struct page **src_list, unsigned int offset,
        else if (sizeof(dma_addr_t) <= sizeof(struct page *))
                dma_src = (dma_addr_t *) src_list;
 
-       if (dma_src && chan) {
+       if (dma_src && chan && is_dma_xor_aligned(chan->device, offset, 0, len)) {
                /* run the xor asynchronously */
                pr_debug("%s (async): len: %zu\n", __func__, len);
 
@@ -228,6 +234,17 @@ static int page_is_zero(struct page *p, unsigned int offset, size_t len)
                memcmp(a, a + 4, len - 4) == 0);
 }
 
+static inline struct dma_chan *
+xor_val_chan(struct async_submit_ctl *submit, struct page *dest,
+                struct page **src_list, int src_cnt, size_t len)
+{
+       #ifdef CONFIG_ASYNC_TX_DISABLE_XOR_VAL_DMA
+       return NULL;
+       #endif
+       return async_tx_find_channel(submit, DMA_XOR_VAL, &dest, 1, src_list,
+                                    src_cnt, len);
+}
+
 /**
  * async_xor_val - attempt a xor parity check with a dma engine.
  * @dest: destination page used if the xor is performed synchronously
@@ -249,9 +266,7 @@ async_xor_val(struct page *dest, struct page **src_list, unsigned int offset,
              int src_cnt, size_t len, enum sum_check_flags *result,
              struct async_submit_ctl *submit)
 {
-       struct dma_chan *chan = async_tx_find_channel(submit, DMA_XOR_VAL,
-                                                     &dest, 1, src_list,
-                                                     src_cnt, len);
+       struct dma_chan *chan = xor_val_chan(submit, dest, src_list, src_cnt, len);
        struct dma_device *device = chan ? chan->device : NULL;
        struct dma_async_tx_descriptor *tx = NULL;
        dma_addr_t *dma_src = NULL;
@@ -263,13 +278,17 @@ async_xor_val(struct page *dest, struct page **src_list, unsigned int offset,
        else if (sizeof(dma_addr_t) <= sizeof(struct page *))
                dma_src = (dma_addr_t *) src_list;
 
-       if (dma_src && device && src_cnt <= device->max_xor) {
-               unsigned long dma_prep_flags;
+       if (dma_src && device && src_cnt <= device->max_xor &&
+           is_dma_xor_aligned(device, offset, 0, len)) {
+               unsigned long dma_prep_flags = 0;
                int i;
 
                pr_debug("%s: (async) len: %zu\n", __func__, len);
 
-               dma_prep_flags = submit->cb_fn ? DMA_PREP_INTERRUPT : 0;
+               if (submit->cb_fn)
+                       dma_prep_flags |= DMA_PREP_INTERRUPT;
+               if (submit->flags & ASYNC_TX_FENCE)
+                       dma_prep_flags |= DMA_PREP_FENCE;
                for (i = 0; i < src_cnt; i++)
                        dma_src[i] = dma_map_page(device->dev, src_list[i],
                                                  offset, len, DMA_TO_DEVICE);