Crypto/chcr: Calculate src and dst sg lengths separately for dma map
[sfrench/cifs-2.6.git] / drivers / crypto / chelsio / chcr_algo.c
index f26a7a15551a22960b46427d1788106d7cfbeaa9..f8b55137cf7da9e3a173a02a2b6ed1d055f55a92 100644 (file)
@@ -2590,11 +2590,22 @@ int chcr_aead_dma_map(struct device *dev,
        struct chcr_aead_reqctx  *reqctx = aead_request_ctx(req);
        struct crypto_aead *tfm = crypto_aead_reqtfm(req);
        unsigned int authsize = crypto_aead_authsize(tfm);
-       int dst_size;
+       int src_len, dst_len;
 
-       dst_size = req->assoclen + req->cryptlen + (op_type ?
-                               0 : authsize);
-       if (!req->cryptlen || !dst_size)
+       /* calculate and handle src and dst sg length separately
+        * for inplace and out-of place operations
+        */
+       if (req->src == req->dst) {
+               src_len = req->assoclen + req->cryptlen + (op_type ?
+                                                       0 : authsize);
+               dst_len = src_len;
+       } else {
+               src_len = req->assoclen + req->cryptlen;
+               dst_len = req->assoclen + req->cryptlen + (op_type ?
+                                                       -authsize : authsize);
+       }
+
+       if (!req->cryptlen || !src_len || !dst_len)
                return 0;
        reqctx->iv_dma = dma_map_single(dev, reqctx->iv, (IV + reqctx->b0_len),
                                        DMA_BIDIRECTIONAL);
@@ -2606,20 +2617,23 @@ int chcr_aead_dma_map(struct device *dev,
                reqctx->b0_dma = 0;
        if (req->src == req->dst) {
                error = dma_map_sg(dev, req->src,
-                               sg_nents_for_len(req->src, dst_size),
+                               sg_nents_for_len(req->src, src_len),
                                        DMA_BIDIRECTIONAL);
                if (!error)
                        goto err;
        } else {
-               error = dma_map_sg(dev, req->src, sg_nents(req->src),
+               error = dma_map_sg(dev, req->src,
+                                  sg_nents_for_len(req->src, src_len),
                                   DMA_TO_DEVICE);
                if (!error)
                        goto err;
-               error = dma_map_sg(dev, req->dst, sg_nents(req->dst),
+               error = dma_map_sg(dev, req->dst,
+                                  sg_nents_for_len(req->dst, dst_len),
                                   DMA_FROM_DEVICE);
                if (!error) {
-                       dma_unmap_sg(dev, req->src, sg_nents(req->src),
-                                  DMA_TO_DEVICE);
+                       dma_unmap_sg(dev, req->src,
+                                    sg_nents_for_len(req->src, src_len),
+                                    DMA_TO_DEVICE);
                        goto err;
                }
        }
@@ -2637,24 +2651,37 @@ void chcr_aead_dma_unmap(struct device *dev,
        struct chcr_aead_reqctx  *reqctx = aead_request_ctx(req);
        struct crypto_aead *tfm = crypto_aead_reqtfm(req);
        unsigned int authsize = crypto_aead_authsize(tfm);
-       int dst_size;
+       int src_len, dst_len;
 
-       dst_size = req->assoclen + req->cryptlen + (op_type ?
-                                       0 : authsize);
-       if (!req->cryptlen || !dst_size)
+       /* calculate and handle src and dst sg length separately
+        * for inplace and out-of place operations
+        */
+       if (req->src == req->dst) {
+               src_len = req->assoclen + req->cryptlen + (op_type ?
+                                                       0 : authsize);
+               dst_len = src_len;
+       } else {
+               src_len = req->assoclen + req->cryptlen;
+               dst_len = req->assoclen + req->cryptlen + (op_type ?
+                                               -authsize : authsize);
+       }
+
+       if (!req->cryptlen || !src_len || !dst_len)
                return;
 
        dma_unmap_single(dev, reqctx->iv_dma, (IV + reqctx->b0_len),
                                        DMA_BIDIRECTIONAL);
        if (req->src == req->dst) {
                dma_unmap_sg(dev, req->src,
-                            sg_nents_for_len(req->src, dst_size),
+                            sg_nents_for_len(req->src, src_len),
                             DMA_BIDIRECTIONAL);
        } else {
-               dma_unmap_sg(dev, req->src, sg_nents(req->src),
-                                  DMA_TO_DEVICE);
-               dma_unmap_sg(dev, req->dst, sg_nents(req->dst),
-                                  DMA_FROM_DEVICE);
+               dma_unmap_sg(dev, req->src,
+                            sg_nents_for_len(req->src, src_len),
+                            DMA_TO_DEVICE);
+               dma_unmap_sg(dev, req->dst,
+                            sg_nents_for_len(req->dst, dst_len),
+                            DMA_FROM_DEVICE);
        }
 }