Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 17 May 2016 16:33:39 +0000 (09:33 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 17 May 2016 16:33:39 +0000 (09:33 -0700)
Pull crypto update from Herbert Xu:
 "API:

   - Crypto self tests can now be disabled at boot/run time.
   - Add async support to algif_aead.

  Algorithms:

   - A large number of fixes to MPI from Nicolai Stange.
   - Performance improvement for HMAC DRBG.

  Drivers:

   - Use generic crypto engine in omap-des.
   - Merge ppc4xx-rng and crypto4xx drivers.
   - Fix lockups in sun4i-ss driver by disabling IRQs.
   - Add DMA engine support to ccp.
   - Reenable talitos hash algorithms.
   - Add support for Hisilicon SoC RNG.
   - Add basic crypto driver for the MXC SCC.

  Others:

   - Do not allocate crypto hash tfm in NORECLAIM context in ecryptfs"

* 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6: (77 commits)
  crypto: qat - change the adf_ctl_stop_devices to void
  crypto: caam - fix caam_jr_alloc() ret code
  crypto: vmx - comply with ABIs that specify vrsave as reserved.
  crypto: testmgr - Add a flag allowing the self-tests to be disabled at runtime.
  crypto: ccp - constify ccp_actions structure
  crypto: marvell/cesa - Use dma_pool_zalloc
  crypto: qat - make adf_vf_isr.c dependant on IOV config
  crypto: qat - Fix typo in comments
  lib: asn1_decoder - add MODULE_LICENSE("GPL")
  crypto: omap-sham - Use dma_request_chan() for requesting DMA channel
  crypto: omap-des - Use dma_request_chan() for requesting DMA channel
  crypto: omap-aes - Use dma_request_chan() for requesting DMA channel
  crypto: omap-des - Integrate with the crypto engine framework
  crypto: s5p-sss - fix incorrect usage of scatterlists api
  crypto: s5p-sss - Fix missed interrupts when working with 8 kB blocks
  crypto: s5p-sss - Use common BIT macro
  crypto: mxc-scc - fix unwinding in mxc_scc_crypto_register()
  crypto: mxc-scc - signedness bugs in mxc_scc_ablkcipher_req_init()
  crypto: talitos - fix ahash algorithms registration
  crypto: ccp - Ensure all dependencies are specified
  ...

76 files changed:
Documentation/DocBook/crypto-API.tmpl
Documentation/devicetree/bindings/crypto/fsl-imx-scc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/crypto/samsung-sss.txt
Documentation/devicetree/bindings/rng/hisi-rng.txt [new file with mode: 0644]
Documentation/kernel-parameters.txt
MAINTAINERS
arch/arm/boot/dts/imx25.dtsi
crypto/algif_aead.c
crypto/asymmetric_keys/pkcs7_parser.c
crypto/drbg.c
crypto/lzo.c
crypto/testmgr.c
drivers/char/hw_random/Kconfig
drivers/char/hw_random/Makefile
drivers/char/hw_random/exynos-rng.c
drivers/char/hw_random/hisi-rng.c [new file with mode: 0644]
drivers/char/hw_random/ppc4xx-rng.c [deleted file]
drivers/crypto/Kconfig
drivers/crypto/Makefile
drivers/crypto/amcc/Makefile
drivers/crypto/amcc/crypto4xx_core.c
drivers/crypto/amcc/crypto4xx_core.h
drivers/crypto/amcc/crypto4xx_reg_def.h
drivers/crypto/amcc/crypto4xx_trng.c [new file with mode: 0644]
drivers/crypto/amcc/crypto4xx_trng.h [new file with mode: 0644]
drivers/crypto/caam/jr.c
drivers/crypto/ccp/Kconfig
drivers/crypto/ccp/Makefile
drivers/crypto/ccp/ccp-dev-v3.c
drivers/crypto/ccp/ccp-dev.c
drivers/crypto/ccp/ccp-dev.h
drivers/crypto/ccp/ccp-dmaengine.c [new file with mode: 0644]
drivers/crypto/ccp/ccp-ops.c
drivers/crypto/marvell/cesa.c
drivers/crypto/marvell/hash.c
drivers/crypto/marvell/tdma.c
drivers/crypto/mxc-scc.c [new file with mode: 0644]
drivers/crypto/n2_core.c
drivers/crypto/omap-aes.c
drivers/crypto/omap-des.c
drivers/crypto/omap-sham.c
drivers/crypto/qat/qat_c3xxx/adf_drv.c
drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c
drivers/crypto/qat/qat_c3xxxvf/adf_drv.c
drivers/crypto/qat/qat_c62x/adf_drv.c
drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c
drivers/crypto/qat/qat_c62xvf/adf_drv.c
drivers/crypto/qat/qat_common/Makefile
drivers/crypto/qat/qat_common/adf_admin.c
drivers/crypto/qat/qat_common/adf_cfg_strings.h
drivers/crypto/qat/qat_common/adf_common_drv.h
drivers/crypto/qat/qat_common/adf_ctl_drv.c
drivers/crypto/qat/qat_common/adf_init.c
drivers/crypto/qat/qat_common/adf_isr.c
drivers/crypto/qat/qat_common/adf_sriov.c
drivers/crypto/qat/qat_common/adf_vf2pf_msg.c [new file with mode: 0644]
drivers/crypto/qat/qat_common/adf_vf_isr.c
drivers/crypto/qat/qat_common/qat_asym_algs.c
drivers/crypto/qat/qat_dh895xcc/adf_drv.c
drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c
drivers/crypto/qat/qat_dh895xccvf/adf_drv.c
drivers/crypto/s5p-sss.c
drivers/crypto/sunxi-ss/sun4i-ss-cipher.c
drivers/crypto/talitos.c
drivers/crypto/vmx/ppc-xlate.pl
fs/ecryptfs/crypto.c
fs/ecryptfs/ecryptfs_kernel.h
fs/ecryptfs/inode.c
fs/ecryptfs/super.c
include/crypto/aead.h
include/crypto/hash.h
include/crypto/skcipher.h
include/linux/ccp.h
include/linux/crypto.h
lib/asn1_decoder.c
lib/mpi/mpicoder.c

index 348619fcafb817e87876fd7a874b27d617900acf..d55dc5a39bad9abe20e4ca5060d7a1cd479ea3ee 100644 (file)
@@ -1936,9 +1936,9 @@ static int test_skcipher(void)
        }
 
        req = skcipher_request_alloc(skcipher, GFP_KERNEL);
-       if (IS_ERR(req)) {
-               pr_info("could not allocate request queue\n");
-               ret = PTR_ERR(req);
+       if (!req) {
+               pr_info("could not allocate skcipher request\n");
+               ret = -ENOMEM;
                goto out;
        }
 
diff --git a/Documentation/devicetree/bindings/crypto/fsl-imx-scc.txt b/Documentation/devicetree/bindings/crypto/fsl-imx-scc.txt
new file mode 100644 (file)
index 0000000..7aad448
--- /dev/null
@@ -0,0 +1,21 @@
+Freescale Security Controller (SCC)
+
+Required properties:
+- compatible : Should be "fsl,imx25-scc".
+- reg : Should contain register location and length.
+- interrupts : Should contain interrupt numbers for SCM IRQ and SMN IRQ.
+- interrupt-names : Should specify the names "scm" and "smn" for the
+                   SCM IRQ and SMN IRQ.
+- clocks: Should contain the clock driving the SCC core.
+- clock-names: Should be set to "ipg".
+
+Example:
+
+       scc: crypto@53fac000 {
+               compatible = "fsl,imx25-scc";
+               reg = <0x53fac000 0x4000>;
+               clocks = <&clks 111>;
+               clock-names = "ipg";
+               interrupts = <49>, <50>;
+               interrupt-names = "scm", "smn";
+       };
index a6dafa83c6dfcf3341a8062277ad729af8cbf065..7a5ca56683cc99cd68ca910277081168a24fb791 100644 (file)
@@ -23,10 +23,8 @@ Required properties:
   - "samsung,exynos4210-secss" for Exynos4210, Exynos4212, Exynos4412, Exynos5250,
                Exynos5260 and Exynos5420 SoCs.
 - reg : Offset and length of the register set for the module
-- interrupts : interrupt specifiers of SSS module interrupts, should contain
-               following entries:
-               - first : feed control interrupt (required for all variants),
-               - second : hash interrupt (required only for samsung,s5pv210-secss).
+- interrupts : interrupt specifiers of SSS module interrupts (one feed
+               control interrupt).
 
 - clocks : list of clock phandle and specifier pairs for all clocks  listed in
                clock-names property.
diff --git a/Documentation/devicetree/bindings/rng/hisi-rng.txt b/Documentation/devicetree/bindings/rng/hisi-rng.txt
new file mode 100644 (file)
index 0000000..d04d55a
--- /dev/null
@@ -0,0 +1,12 @@
+Hisilicon Random Number Generator
+
+Required properties:
+- compatible : Should be "hisilicon,hip04-rng" or "hisilicon,hip05-rng"
+- reg : Offset and length of the register set of this block
+
+Example:
+
+rng@d1010000 {
+       compatible = "hisilicon,hip05-rng";
+       reg = <0xd1010000 0x100>;
+};
index d3240feef367c7cacd5e64d380dc1ba3ad7eb5ff..a2d51d81ff5dac5d1d30c7f73fef1e322ac59cc8 100644 (file)
@@ -838,6 +838,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        It will be ignored when crashkernel=X,high is not used
                        or memory reserved is below 4G.
 
+       cryptomgr.notests
+                        [KNL] Disable crypto self-tests
+
        cs89x0_dma=     [HW,NET]
                        Format: <dma>
 
index f40d40d42030774f79ebdce8104c68f85b5bef31..20e634627a109ef1eb5594d2930c3cc017317a58 100644 (file)
@@ -627,6 +627,7 @@ F:  include/linux/altera_jtaguart.h
 
 AMD CRYPTOGRAPHIC COPROCESSOR (CCP) DRIVER
 M:     Tom Lendacky <thomas.lendacky@amd.com>
+M:     Gary Hook <gary.hook@amd.com>
 L:     linux-crypto@vger.kernel.org
 S:     Supported
 F:     drivers/crypto/ccp/
index 6b1f4bbe6ec6eedf59795b07495ee18ed35730ea..af6af8741fe57098680c6fdd94494bd95ac76534 100644 (file)
                                interrupts = <41>;
                        };
 
+                       scc: crypto@53fac000 {
+                               compatible = "fsl,imx25-scc";
+                               reg = <0x53fac000 0x4000>;
+                               clocks = <&clks 111>;
+                               clock-names = "ipg";
+                               interrupts = <49>, <50>;
+                               interrupt-names = "scm", "smn";
+                       };
+
                        esdhc1: esdhc@53fb4000 {
                                compatible = "fsl,imx25-esdhc";
                                reg = <0x53fb4000 0x4000>;
index 147069c9afd02aca7b1d7833f1bbe0084d4bf874..80a0f1a7855181930afa0a545f5bf79584141e5c 100644 (file)
@@ -13,7 +13,7 @@
  * any later version.
  */
 
-#include <crypto/aead.h>
+#include <crypto/internal/aead.h>
 #include <crypto/scatterwalk.h>
 #include <crypto/if_alg.h>
 #include <linux/init.h>
@@ -29,15 +29,24 @@ struct aead_sg_list {
        struct scatterlist sg[ALG_MAX_PAGES];
 };
 
+struct aead_async_rsgl {
+       struct af_alg_sgl sgl;
+       struct list_head list;
+};
+
+struct aead_async_req {
+       struct scatterlist *tsgl;
+       struct aead_async_rsgl first_rsgl;
+       struct list_head list;
+       struct kiocb *iocb;
+       unsigned int tsgls;
+       char iv[];
+};
+
 struct aead_ctx {
        struct aead_sg_list tsgl;
-       /*
-        * RSGL_MAX_ENTRIES is an artificial limit where user space at maximum
-        * can cause the kernel to allocate RSGL_MAX_ENTRIES * ALG_MAX_PAGES
-        * pages
-        */
-#define RSGL_MAX_ENTRIES ALG_MAX_PAGES
-       struct af_alg_sgl rsgl[RSGL_MAX_ENTRIES];
+       struct aead_async_rsgl first_rsgl;
+       struct list_head list;
 
        void *iv;
 
@@ -75,6 +84,17 @@ static inline bool aead_sufficient_data(struct aead_ctx *ctx)
        return ctx->used >= ctx->aead_assoclen + as;
 }
 
+static void aead_reset_ctx(struct aead_ctx *ctx)
+{
+       struct aead_sg_list *sgl = &ctx->tsgl;
+
+       sg_init_table(sgl->sg, ALG_MAX_PAGES);
+       sgl->cur = 0;
+       ctx->used = 0;
+       ctx->more = 0;
+       ctx->merge = 0;
+}
+
 static void aead_put_sgl(struct sock *sk)
 {
        struct alg_sock *ask = alg_sk(sk);
@@ -90,11 +110,7 @@ static void aead_put_sgl(struct sock *sk)
                put_page(sg_page(sg + i));
                sg_assign_page(sg + i, NULL);
        }
-       sg_init_table(sg, ALG_MAX_PAGES);
-       sgl->cur = 0;
-       ctx->used = 0;
-       ctx->more = 0;
-       ctx->merge = 0;
+       aead_reset_ctx(ctx);
 }
 
 static void aead_wmem_wakeup(struct sock *sk)
@@ -349,23 +365,188 @@ unlock:
        return err ?: size;
 }
 
-static int aead_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored, int flags)
+#define GET_ASYM_REQ(req, tfm) (struct aead_async_req *) \
+               ((char *)req + sizeof(struct aead_request) + \
+                crypto_aead_reqsize(tfm))
+
+ #define GET_REQ_SIZE(tfm) sizeof(struct aead_async_req) + \
+       crypto_aead_reqsize(tfm) + crypto_aead_ivsize(tfm) + \
+       sizeof(struct aead_request)
+
+static void aead_async_cb(struct crypto_async_request *_req, int err)
+{
+       struct sock *sk = _req->data;
+       struct alg_sock *ask = alg_sk(sk);
+       struct aead_ctx *ctx = ask->private;
+       struct crypto_aead *tfm = crypto_aead_reqtfm(&ctx->aead_req);
+       struct aead_request *req = aead_request_cast(_req);
+       struct aead_async_req *areq = GET_ASYM_REQ(req, tfm);
+       struct scatterlist *sg = areq->tsgl;
+       struct aead_async_rsgl *rsgl;
+       struct kiocb *iocb = areq->iocb;
+       unsigned int i, reqlen = GET_REQ_SIZE(tfm);
+
+       list_for_each_entry(rsgl, &areq->list, list) {
+               af_alg_free_sg(&rsgl->sgl);
+               if (rsgl != &areq->first_rsgl)
+                       sock_kfree_s(sk, rsgl, sizeof(*rsgl));
+       }
+
+       for (i = 0; i < areq->tsgls; i++)
+               put_page(sg_page(sg + i));
+
+       sock_kfree_s(sk, areq->tsgl, sizeof(*areq->tsgl) * areq->tsgls);
+       sock_kfree_s(sk, req, reqlen);
+       __sock_put(sk);
+       iocb->ki_complete(iocb, err, err);
+}
+
+static int aead_recvmsg_async(struct socket *sock, struct msghdr *msg,
+                             int flags)
+{
+       struct sock *sk = sock->sk;
+       struct alg_sock *ask = alg_sk(sk);
+       struct aead_ctx *ctx = ask->private;
+       struct crypto_aead *tfm = crypto_aead_reqtfm(&ctx->aead_req);
+       struct aead_async_req *areq;
+       struct aead_request *req = NULL;
+       struct aead_sg_list *sgl = &ctx->tsgl;
+       struct aead_async_rsgl *last_rsgl = NULL, *rsgl;
+       unsigned int as = crypto_aead_authsize(tfm);
+       unsigned int i, reqlen = GET_REQ_SIZE(tfm);
+       int err = -ENOMEM;
+       unsigned long used;
+       size_t outlen;
+       size_t usedpages = 0;
+
+       lock_sock(sk);
+       if (ctx->more) {
+               err = aead_wait_for_data(sk, flags);
+               if (err)
+                       goto unlock;
+       }
+
+       used = ctx->used;
+       outlen = used;
+
+       if (!aead_sufficient_data(ctx))
+               goto unlock;
+
+       req = sock_kmalloc(sk, reqlen, GFP_KERNEL);
+       if (unlikely(!req))
+               goto unlock;
+
+       areq = GET_ASYM_REQ(req, tfm);
+       memset(&areq->first_rsgl, '\0', sizeof(areq->first_rsgl));
+       INIT_LIST_HEAD(&areq->list);
+       areq->iocb = msg->msg_iocb;
+       memcpy(areq->iv, ctx->iv, crypto_aead_ivsize(tfm));
+       aead_request_set_tfm(req, tfm);
+       aead_request_set_ad(req, ctx->aead_assoclen);
+       aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+                                 aead_async_cb, sk);
+       used -= ctx->aead_assoclen + (ctx->enc ? as : 0);
+
+       /* take over all tx sgls from ctx */
+       areq->tsgl = sock_kmalloc(sk, sizeof(*areq->tsgl) * sgl->cur,
+                                 GFP_KERNEL);
+       if (unlikely(!areq->tsgl))
+               goto free;
+
+       sg_init_table(areq->tsgl, sgl->cur);
+       for (i = 0; i < sgl->cur; i++)
+               sg_set_page(&areq->tsgl[i], sg_page(&sgl->sg[i]),
+                           sgl->sg[i].length, sgl->sg[i].offset);
+
+       areq->tsgls = sgl->cur;
+
+       /* create rx sgls */
+       while (iov_iter_count(&msg->msg_iter)) {
+               size_t seglen = min_t(size_t, iov_iter_count(&msg->msg_iter),
+                                     (outlen - usedpages));
+
+               if (list_empty(&areq->list)) {
+                       rsgl = &areq->first_rsgl;
+
+               } else {
+                       rsgl = sock_kmalloc(sk, sizeof(*rsgl), GFP_KERNEL);
+                       if (unlikely(!rsgl)) {
+                               err = -ENOMEM;
+                               goto free;
+                       }
+               }
+               rsgl->sgl.npages = 0;
+               list_add_tail(&rsgl->list, &areq->list);
+
+               /* make one iovec available as scatterlist */
+               err = af_alg_make_sg(&rsgl->sgl, &msg->msg_iter, seglen);
+               if (err < 0)
+                       goto free;
+
+               usedpages += err;
+
+               /* chain the new scatterlist with previous one */
+               if (last_rsgl)
+                       af_alg_link_sg(&last_rsgl->sgl, &rsgl->sgl);
+
+               last_rsgl = rsgl;
+
+               /* we do not need more iovecs as we have sufficient memory */
+               if (outlen <= usedpages)
+                       break;
+
+               iov_iter_advance(&msg->msg_iter, err);
+       }
+       err = -EINVAL;
+       /* ensure output buffer is sufficiently large */
+       if (usedpages < outlen)
+               goto free;
+
+       aead_request_set_crypt(req, areq->tsgl, areq->first_rsgl.sgl.sg, used,
+                              areq->iv);
+       err = ctx->enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req);
+       if (err) {
+               if (err == -EINPROGRESS) {
+                       sock_hold(sk);
+                       err = -EIOCBQUEUED;
+                       aead_reset_ctx(ctx);
+                       goto unlock;
+               } else if (err == -EBADMSG) {
+                       aead_put_sgl(sk);
+               }
+               goto free;
+       }
+       aead_put_sgl(sk);
+
+free:
+       list_for_each_entry(rsgl, &areq->list, list) {
+               af_alg_free_sg(&rsgl->sgl);
+               if (rsgl != &areq->first_rsgl)
+                       sock_kfree_s(sk, rsgl, sizeof(*rsgl));
+       }
+       if (areq->tsgl)
+               sock_kfree_s(sk, areq->tsgl, sizeof(*areq->tsgl) * areq->tsgls);
+       if (req)
+               sock_kfree_s(sk, req, reqlen);
+unlock:
+       aead_wmem_wakeup(sk);
+       release_sock(sk);
+       return err ? err : outlen;
+}
+
+static int aead_recvmsg_sync(struct socket *sock, struct msghdr *msg, int flags)
 {
        struct sock *sk = sock->sk;
        struct alg_sock *ask = alg_sk(sk);
        struct aead_ctx *ctx = ask->private;
        unsigned as = crypto_aead_authsize(crypto_aead_reqtfm(&ctx->aead_req));
        struct aead_sg_list *sgl = &ctx->tsgl;
-       unsigned int i = 0;
+       struct aead_async_rsgl *last_rsgl = NULL;
+       struct aead_async_rsgl *rsgl, *tmp;
        int err = -EINVAL;
        unsigned long used = 0;
        size_t outlen = 0;
        size_t usedpages = 0;
-       unsigned int cnt = 0;
-
-       /* Limit number of IOV blocks to be accessed below */
-       if (msg->msg_iter.nr_segs > RSGL_MAX_ENTRIES)
-               return -ENOMSG;
 
        lock_sock(sk);
 
@@ -417,21 +598,33 @@ static int aead_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored,
                size_t seglen = min_t(size_t, iov_iter_count(&msg->msg_iter),
                                      (outlen - usedpages));
 
+               if (list_empty(&ctx->list)) {
+                       rsgl = &ctx->first_rsgl;
+               } else {
+                       rsgl = sock_kmalloc(sk, sizeof(*rsgl), GFP_KERNEL);
+                       if (unlikely(!rsgl)) {
+                               err = -ENOMEM;
+                               goto unlock;
+                       }
+               }
+               rsgl->sgl.npages = 0;
+               list_add_tail(&rsgl->list, &ctx->list);
+
                /* make one iovec available as scatterlist */
-               err = af_alg_make_sg(&ctx->rsgl[cnt], &msg->msg_iter,
-                                    seglen);
+               err = af_alg_make_sg(&rsgl->sgl, &msg->msg_iter, seglen);
                if (err < 0)
                        goto unlock;
                usedpages += err;
                /* chain the new scatterlist with previous one */
-               if (cnt)
-                       af_alg_link_sg(&ctx->rsgl[cnt-1], &ctx->rsgl[cnt]);
+               if (last_rsgl)
+                       af_alg_link_sg(&last_rsgl->sgl, &rsgl->sgl);
+
+               last_rsgl = rsgl;
 
                /* we do not need more iovecs as we have sufficient memory */
                if (outlen <= usedpages)
                        break;
                iov_iter_advance(&msg->msg_iter, err);
-               cnt++;
        }
 
        err = -EINVAL;
@@ -440,8 +633,7 @@ static int aead_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored,
                goto unlock;
 
        sg_mark_end(sgl->sg + sgl->cur - 1);
-
-       aead_request_set_crypt(&ctx->aead_req, sgl->sg, ctx->rsgl[0].sg,
+       aead_request_set_crypt(&ctx->aead_req, sgl->sg, ctx->first_rsgl.sgl.sg,
                               used, ctx->iv);
        aead_request_set_ad(&ctx->aead_req, ctx->aead_assoclen);
 
@@ -454,23 +646,35 @@ static int aead_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored,
                /* EBADMSG implies a valid cipher operation took place */
                if (err == -EBADMSG)
                        aead_put_sgl(sk);
+
                goto unlock;
        }
 
        aead_put_sgl(sk);
-
        err = 0;
 
 unlock:
-       for (i = 0; i < cnt; i++)
-               af_alg_free_sg(&ctx->rsgl[i]);
-
+       list_for_each_entry_safe(rsgl, tmp, &ctx->list, list) {
+               af_alg_free_sg(&rsgl->sgl);
+               if (rsgl != &ctx->first_rsgl)
+                       sock_kfree_s(sk, rsgl, sizeof(*rsgl));
+               list_del(&rsgl->list);
+       }
+       INIT_LIST_HEAD(&ctx->list);
        aead_wmem_wakeup(sk);
        release_sock(sk);
 
        return err ? err : outlen;
 }
 
+static int aead_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored,
+                       int flags)
+{
+       return (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) ?
+               aead_recvmsg_async(sock, msg, flags) :
+               aead_recvmsg_sync(sock, msg, flags);
+}
+
 static unsigned int aead_poll(struct file *file, struct socket *sock,
                              poll_table *wait)
 {
@@ -540,6 +744,7 @@ static void aead_sock_destruct(struct sock *sk)
        unsigned int ivlen = crypto_aead_ivsize(
                                crypto_aead_reqtfm(&ctx->aead_req));
 
+       WARN_ON(atomic_read(&sk->sk_refcnt) != 0);
        aead_put_sgl(sk);
        sock_kzfree_s(sk, ctx->iv, ivlen);
        sock_kfree_s(sk, ctx, ctx->len);
@@ -574,6 +779,7 @@ static int aead_accept_parent(void *private, struct sock *sk)
        ctx->aead_assoclen = 0;
        af_alg_init_completion(&ctx->completion);
        sg_init_table(ctx->tsgl.sg, ALG_MAX_PAGES);
+       INIT_LIST_HEAD(&ctx->list);
 
        ask->private = ctx;
 
index 40de03f49ff8d612df32e57a07987d65210eccdf..bdd0d753ce5d15e3946ffc852b3e42aaea7b6f68 100644 (file)
@@ -237,6 +237,7 @@ int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen,
                break;
        case OID_sha224:
                ctx->sinfo->sig.hash_algo = "sha224";
+               break;
        default:
                printk("Unsupported digest algo: %u\n", ctx->last_oid);
                return -ENOPKG;
index 1b86310db7b1e9aca14e5c4151a34ccdf6c375cd..0a3538f6cf22bfe2597689e19679c1f27a058ac9 100644 (file)
@@ -592,8 +592,10 @@ static const struct drbg_state_ops drbg_ctr_ops = {
  ******************************************************************/
 
 #if defined(CONFIG_CRYPTO_DRBG_HASH) || defined(CONFIG_CRYPTO_DRBG_HMAC)
-static int drbg_kcapi_hash(struct drbg_state *drbg, const unsigned char *key,
-                          unsigned char *outval, const struct list_head *in);
+static int drbg_kcapi_hash(struct drbg_state *drbg, unsigned char *outval,
+                          const struct list_head *in);
+static void drbg_kcapi_hmacsetkey(struct drbg_state *drbg,
+                                 const unsigned char *key);
 static int drbg_init_hash_kernel(struct drbg_state *drbg);
 static int drbg_fini_hash_kernel(struct drbg_state *drbg);
 #endif /* (CONFIG_CRYPTO_DRBG_HASH || CONFIG_CRYPTO_DRBG_HMAC) */
@@ -619,9 +621,11 @@ static int drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed,
        LIST_HEAD(seedlist);
        LIST_HEAD(vdatalist);
 
-       if (!reseed)
+       if (!reseed) {
                /* 10.1.2.3 step 2 -- memset(0) of C is implicit with kzalloc */
                memset(drbg->V, 1, drbg_statelen(drbg));
+               drbg_kcapi_hmacsetkey(drbg, drbg->C);
+       }
 
        drbg_string_fill(&seed1, drbg->V, drbg_statelen(drbg));
        list_add_tail(&seed1.list, &seedlist);
@@ -641,12 +645,13 @@ static int drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed,
                        prefix = DRBG_PREFIX1;
                /* 10.1.2.2 step 1 and 4 -- concatenation and HMAC for key */
                seed2.buf = &prefix;
-               ret = drbg_kcapi_hash(drbg, drbg->C, drbg->C, &seedlist);
+               ret = drbg_kcapi_hash(drbg, drbg->C, &seedlist);
                if (ret)
                        return ret;
+               drbg_kcapi_hmacsetkey(drbg, drbg->C);
 
                /* 10.1.2.2 step 2 and 5 -- HMAC for V */
-               ret = drbg_kcapi_hash(drbg, drbg->C, drbg->V, &vdatalist);
+               ret = drbg_kcapi_hash(drbg, drbg->V, &vdatalist);
                if (ret)
                        return ret;
 
@@ -681,7 +686,7 @@ static int drbg_hmac_generate(struct drbg_state *drbg,
        while (len < buflen) {
                unsigned int outlen = 0;
                /* 10.1.2.5 step 4.1 */
-               ret = drbg_kcapi_hash(drbg, drbg->C, drbg->V, &datalist);
+               ret = drbg_kcapi_hash(drbg, drbg->V, &datalist);
                if (ret)
                        return ret;
                outlen = (drbg_blocklen(drbg) < (buflen - len)) ?
@@ -796,7 +801,7 @@ static int drbg_hash_df(struct drbg_state *drbg,
        while (len < outlen) {
                short blocklen = 0;
                /* 10.4.1 step 4.1 */
-               ret = drbg_kcapi_hash(drbg, NULL, tmp, entropylist);
+               ret = drbg_kcapi_hash(drbg, tmp, entropylist);
                if (ret)
                        goto out;
                /* 10.4.1 step 4.2 */
@@ -874,7 +879,7 @@ static int drbg_hash_process_addtl(struct drbg_state *drbg,
        list_add_tail(&data1.list, &datalist);
        list_add_tail(&data2.list, &datalist);
        list_splice_tail(addtl, &datalist);
-       ret = drbg_kcapi_hash(drbg, NULL, drbg->scratchpad, &datalist);
+       ret = drbg_kcapi_hash(drbg, drbg->scratchpad, &datalist);
        if (ret)
                goto out;
 
@@ -907,7 +912,7 @@ static int drbg_hash_hashgen(struct drbg_state *drbg,
        while (len < buflen) {
                unsigned int outlen = 0;
                /* 10.1.1.4 step hashgen 4.1 */
-               ret = drbg_kcapi_hash(drbg, NULL, dst, &datalist);
+               ret = drbg_kcapi_hash(drbg, dst, &datalist);
                if (ret) {
                        len = ret;
                        goto out;
@@ -956,7 +961,7 @@ static int drbg_hash_generate(struct drbg_state *drbg,
        list_add_tail(&data1.list, &datalist);
        drbg_string_fill(&data2, drbg->V, drbg_statelen(drbg));
        list_add_tail(&data2.list, &datalist);
-       ret = drbg_kcapi_hash(drbg, NULL, drbg->scratchpad, &datalist);
+       ret = drbg_kcapi_hash(drbg, drbg->scratchpad, &datalist);
        if (ret) {
                len = ret;
                goto out;
@@ -1600,14 +1605,20 @@ static int drbg_fini_hash_kernel(struct drbg_state *drbg)
        return 0;
 }
 
-static int drbg_kcapi_hash(struct drbg_state *drbg, const unsigned char *key,
-                          unsigned char *outval, const struct list_head *in)
+static void drbg_kcapi_hmacsetkey(struct drbg_state *drbg,
+                                 const unsigned char *key)
+{
+       struct sdesc *sdesc = (struct sdesc *)drbg->priv_data;
+
+       crypto_shash_setkey(sdesc->shash.tfm, key, drbg_statelen(drbg));
+}
+
+static int drbg_kcapi_hash(struct drbg_state *drbg, unsigned char *outval,
+                          const struct list_head *in)
 {
        struct sdesc *sdesc = (struct sdesc *)drbg->priv_data;
        struct drbg_string *input = NULL;
 
-       if (key)
-               crypto_shash_setkey(sdesc->shash.tfm, key, drbg_statelen(drbg));
        crypto_shash_init(&sdesc->shash);
        list_for_each_entry(input, in, list)
                crypto_shash_update(&sdesc->shash, input->buf, input->len);
index 4b3e92525dac5a47f3415f46c9eb403813b44275..c3f3dd9a28c5eb1ca8546272ebec13f3f0a84cc3 100644 (file)
@@ -32,7 +32,7 @@ static int lzo_init(struct crypto_tfm *tfm)
        struct lzo_ctx *ctx = crypto_tfm_ctx(tfm);
 
        ctx->lzo_comp_mem = kmalloc(LZO1X_MEM_COMPRESS,
-                                   GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
+                                   GFP_KERNEL | __GFP_NOWARN);
        if (!ctx->lzo_comp_mem)
                ctx->lzo_comp_mem = vmalloc(LZO1X_MEM_COMPRESS);
        if (!ctx->lzo_comp_mem)
index 7d4acc4492338921dd1307c1cc4d4a252130b36a..c727fb0cb021595afcfee0d9df271f5558c5f16d 100644 (file)
 
 #include "internal.h"
 
+static bool notests;
+module_param(notests, bool, 0644);
+MODULE_PARM_DESC(notests, "disable crypto self-tests");
+
 #ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
 
 /* a perfect nop */
@@ -3885,6 +3889,11 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
        int j;
        int rc;
 
+       if (!fips_enabled && notests) {
+               printk_once(KERN_INFO "alg: self-tests disabled\n");
+               return 0;
+       }
+
        alg_test_descs_check_order();
 
        if ((type & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_CIPHER) {
index 67ee8b08ab5318dca13054e6e1e65da9dcd1c000..ac51149e977758beb8db91e159175be9525fc13c 100644 (file)
@@ -268,19 +268,6 @@ config HW_RANDOM_NOMADIK
 
          If unsure, say Y.
 
-config HW_RANDOM_PPC4XX
-       tristate "PowerPC 4xx generic true random number generator support"
-       depends on PPC && 4xx
-       default HW_RANDOM
-       ---help---
-        This driver provides the kernel-side support for the TRNG hardware
-        found in the security function of some PowerPC 4xx SoCs.
-
-        To compile this driver as a module, choose M here: the
-        module will be called ppc4xx-rng.
-
-        If unsure, say N.
-
 config HW_RANDOM_PSERIES
        tristate "pSeries HW Random Number Generator support"
        depends on PPC64 && IBMVIO
@@ -309,7 +296,8 @@ config HW_RANDOM_POWERNV
 
 config HW_RANDOM_EXYNOS
        tristate "EXYNOS HW random number generator support"
-       depends on ARCH_EXYNOS
+       depends on ARCH_EXYNOS || COMPILE_TEST
+       depends on HAS_IOMEM
        default HW_RANDOM
        ---help---
          This driver provides kernel-side support for the Random Number
@@ -333,6 +321,19 @@ config HW_RANDOM_TPM
 
          If unsure, say Y.
 
+config HW_RANDOM_HISI
+       tristate "Hisilicon Random Number Generator support"
+       depends on HW_RANDOM && ARCH_HISI
+       default HW_RANDOM
+       ---help---
+         This driver provides kernel-side support for the Random Number
+         Generator hardware found on Hisilicon Hip04 and Hip05 SoC.
+
+         To compile this driver as a module, choose M here: the
+         module will be called hisi-rng.
+
+         If unsure, say Y.
+
 config HW_RANDOM_MSM
        tristate "Qualcomm SoCs Random Number Generator support"
        depends on HW_RANDOM && ARCH_QCOM
index f5a6fa7690e7f1b361ed51c3e2736141f80451eb..63022b49f160a191c4e7d1b34f10c1fce0d0ed39 100644 (file)
@@ -22,10 +22,10 @@ obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o
 obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o
 obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o
 obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
-obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o
 obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
 obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
 obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o
+obj-$(CONFIG_HW_RANDOM_HISI)   += hisi-rng.o
 obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o
 obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
 obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
index ada08123252856aeec0314e5d4905e532b850899..ed44561ea64755e3a02ad0834a4757171c4e10a3 100644 (file)
@@ -2,7 +2,7 @@
  * exynos-rng.c - Random Number Generator driver for the exynos
  *
  * Copyright (C) 2012 Samsung Electronics
- * Jonghwa Lee <jonghwa3.lee@smasung.com>
+ * Jonghwa Lee <jonghwa3.lee@samsung.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -77,7 +77,8 @@ static int exynos_init(struct hwrng *rng)
 
        pm_runtime_get_sync(exynos_rng->dev);
        ret = exynos_rng_configure(exynos_rng);
-       pm_runtime_put_noidle(exynos_rng->dev);
+       pm_runtime_mark_last_busy(exynos_rng->dev);
+       pm_runtime_put_autosuspend(exynos_rng->dev);
 
        return ret;
 }
@@ -89,6 +90,7 @@ static int exynos_read(struct hwrng *rng, void *buf,
                                                struct exynos_rng, rng);
        u32 *data = buf;
        int retry = 100;
+       int ret = 4;
 
        pm_runtime_get_sync(exynos_rng->dev);
 
@@ -97,23 +99,27 @@ static int exynos_read(struct hwrng *rng, void *buf,
        while (!(exynos_rng_readl(exynos_rng,
                        EXYNOS_PRNG_STATUS_OFFSET) & PRNG_DONE) && --retry)
                cpu_relax();
-       if (!retry)
-               return -ETIMEDOUT;
+       if (!retry) {
+               ret = -ETIMEDOUT;
+               goto out;
+       }
 
        exynos_rng_writel(exynos_rng, PRNG_DONE, EXYNOS_PRNG_STATUS_OFFSET);
 
        *data = exynos_rng_readl(exynos_rng, EXYNOS_PRNG_OUT1_OFFSET);
 
+out:
        pm_runtime_mark_last_busy(exynos_rng->dev);
        pm_runtime_put_sync_autosuspend(exynos_rng->dev);
 
-       return 4;
+       return ret;
 }
 
 static int exynos_rng_probe(struct platform_device *pdev)
 {
        struct exynos_rng *exynos_rng;
        struct resource *res;
+       int ret;
 
        exynos_rng = devm_kzalloc(&pdev->dev, sizeof(struct exynos_rng),
                                        GFP_KERNEL);
@@ -141,7 +147,21 @@ static int exynos_rng_probe(struct platform_device *pdev)
        pm_runtime_use_autosuspend(&pdev->dev);
        pm_runtime_enable(&pdev->dev);
 
-       return devm_hwrng_register(&pdev->dev, &exynos_rng->rng);
+       ret = devm_hwrng_register(&pdev->dev, &exynos_rng->rng);
+       if (ret) {
+               pm_runtime_dont_use_autosuspend(&pdev->dev);
+               pm_runtime_disable(&pdev->dev);
+       }
+
+       return ret;
+}
+
+static int exynos_rng_remove(struct platform_device *pdev)
+{
+       pm_runtime_dont_use_autosuspend(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+
+       return 0;
 }
 
 static int __maybe_unused exynos_rng_runtime_suspend(struct device *dev)
@@ -201,6 +221,7 @@ static struct platform_driver exynos_rng_driver = {
                .of_match_table = exynos_rng_dt_match,
        },
        .probe          = exynos_rng_probe,
+       .remove         = exynos_rng_remove,
 };
 
 module_platform_driver(exynos_rng_driver);
diff --git a/drivers/char/hw_random/hisi-rng.c b/drivers/char/hw_random/hisi-rng.c
new file mode 100644 (file)
index 0000000..40d9657
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2016 HiSilicon Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/hw_random.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/random.h>
+
+#define RNG_SEED       0x0
+#define RNG_CTRL       0x4
+  #define RNG_SEED_SEL BIT(2)
+  #define RNG_RING_EN  BIT(1)
+  #define RNG_EN       BIT(0)
+#define RNG_RAN_NUM    0x10
+#define RNG_PHY_SEED   0x14
+
+#define to_hisi_rng(p) container_of(p, struct hisi_rng, rng)
+
+static int seed_sel;
+module_param(seed_sel, int, S_IRUGO);
+MODULE_PARM_DESC(seed_sel, "Auto reload seed. 0, use LFSR(default); 1, use ring oscillator.");
+
+struct hisi_rng {
+       void __iomem *base;
+       struct hwrng rng;
+};
+
+static int hisi_rng_init(struct hwrng *rng)
+{
+       struct hisi_rng *hrng = to_hisi_rng(rng);
+       int val = RNG_EN;
+       u32 seed;
+
+       /* get a random number as initial seed */
+       get_random_bytes(&seed, sizeof(seed));
+
+       writel_relaxed(seed, hrng->base + RNG_SEED);
+
+       /**
+        * The seed is reload periodically, there are two choice
+        * of seeds, default seed using the value from LFSR, or
+        * will use seed generated by ring oscillator.
+        */
+       if (seed_sel == 1)
+               val |= RNG_RING_EN | RNG_SEED_SEL;
+
+       writel_relaxed(val, hrng->base + RNG_CTRL);
+       return 0;
+}
+
+static void hisi_rng_cleanup(struct hwrng *rng)
+{
+       struct hisi_rng *hrng = to_hisi_rng(rng);
+
+       writel_relaxed(0, hrng->base + RNG_CTRL);
+}
+
+static int hisi_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+{
+       struct hisi_rng *hrng = to_hisi_rng(rng);
+       u32 *data = buf;
+
+       *data = readl_relaxed(hrng->base + RNG_RAN_NUM);
+       return 4;
+}
+
+static int hisi_rng_probe(struct platform_device *pdev)
+{
+       struct hisi_rng *rng;
+       struct resource *res;
+       int ret;
+
+       rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
+       if (!rng)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, rng);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       rng->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(rng->base))
+               return PTR_ERR(rng->base);
+
+       rng->rng.name = pdev->name;
+       rng->rng.init = hisi_rng_init;
+       rng->rng.cleanup = hisi_rng_cleanup;
+       rng->rng.read = hisi_rng_read;
+
+       ret = devm_hwrng_register(&pdev->dev, &rng->rng);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register hwrng\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct of_device_id hisi_rng_dt_ids[] = {
+       { .compatible = "hisilicon,hip04-rng" },
+       { .compatible = "hisilicon,hip05-rng" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, hisi_rng_dt_ids);
+
+static struct platform_driver hisi_rng_driver = {
+       .probe          = hisi_rng_probe,
+       .driver         = {
+               .name   = "hisi-rng",
+               .of_match_table = of_match_ptr(hisi_rng_dt_ids),
+       },
+};
+
+module_platform_driver(hisi_rng_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kefeng Wang <wangkefeng.wang@huawei>");
+MODULE_DESCRIPTION("Hisilicon random number generator driver");
diff --git a/drivers/char/hw_random/ppc4xx-rng.c b/drivers/char/hw_random/ppc4xx-rng.c
deleted file mode 100644 (file)
index c0db438..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Generic PowerPC 44x RNG driver
- *
- * Copyright 2011 IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; version 2 of the License.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/hw_random.h>
-#include <linux/delay.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <asm/io.h>
-
-#define PPC4XX_TRNG_DEV_CTRL 0x60080
-
-#define PPC4XX_TRNGE 0x00020000
-#define PPC4XX_TRNG_CTRL 0x0008
-#define PPC4XX_TRNG_CTRL_DALM 0x20
-#define PPC4XX_TRNG_STAT 0x0004
-#define PPC4XX_TRNG_STAT_B 0x1
-#define PPC4XX_TRNG_DATA 0x0000
-
-#define MODULE_NAME "ppc4xx_rng"
-
-static int ppc4xx_rng_data_present(struct hwrng *rng, int wait)
-{
-       void __iomem *rng_regs = (void __iomem *) rng->priv;
-       int busy, i, present = 0;
-
-       for (i = 0; i < 20; i++) {
-               busy = (in_le32(rng_regs + PPC4XX_TRNG_STAT) & PPC4XX_TRNG_STAT_B);
-               if (!busy || !wait) {
-                       present = 1;
-                       break;
-               }
-               udelay(10);
-       }
-       return present;
-}
-
-static int ppc4xx_rng_data_read(struct hwrng *rng, u32 *data)
-{
-       void __iomem *rng_regs = (void __iomem *) rng->priv;
-       *data = in_le32(rng_regs + PPC4XX_TRNG_DATA);
-       return 4;
-}
-
-static int ppc4xx_rng_enable(int enable)
-{
-       struct device_node *ctrl;
-       void __iomem *ctrl_reg;
-       int err = 0;
-       u32 val;
-
-       /* Find the main crypto device node and map it to turn the TRNG on */
-       ctrl = of_find_compatible_node(NULL, NULL, "amcc,ppc4xx-crypto");
-       if (!ctrl)
-               return -ENODEV;
-
-       ctrl_reg = of_iomap(ctrl, 0);
-       if (!ctrl_reg) {
-               err = -ENODEV;
-               goto out;
-       }
-
-       val = in_le32(ctrl_reg + PPC4XX_TRNG_DEV_CTRL);
-
-       if (enable)
-               val |= PPC4XX_TRNGE;
-       else
-               val = val & ~PPC4XX_TRNGE;
-
-       out_le32(ctrl_reg + PPC4XX_TRNG_DEV_CTRL, val);
-       iounmap(ctrl_reg);
-
-out:
-       of_node_put(ctrl);
-
-       return err;
-}
-
-static struct hwrng ppc4xx_rng = {
-       .name = MODULE_NAME,
-       .data_present = ppc4xx_rng_data_present,
-       .data_read = ppc4xx_rng_data_read,
-};
-
-static int ppc4xx_rng_probe(struct platform_device *dev)
-{
-       void __iomem *rng_regs;
-       int err = 0;
-
-       rng_regs = of_iomap(dev->dev.of_node, 0);
-       if (!rng_regs)
-               return -ENODEV;
-
-       err = ppc4xx_rng_enable(1);
-       if (err)
-               return err;
-
-       out_le32(rng_regs + PPC4XX_TRNG_CTRL, PPC4XX_TRNG_CTRL_DALM);
-       ppc4xx_rng.priv = (unsigned long) rng_regs;
-
-       err = hwrng_register(&ppc4xx_rng);
-
-       return err;
-}
-
-static int ppc4xx_rng_remove(struct platform_device *dev)
-{
-       void __iomem *rng_regs = (void __iomem *) ppc4xx_rng.priv;
-
-       hwrng_unregister(&ppc4xx_rng);
-       ppc4xx_rng_enable(0);
-       iounmap(rng_regs);
-
-       return 0;
-}
-
-static const struct of_device_id ppc4xx_rng_match[] = {
-       { .compatible = "ppc4xx-rng", },
-       { .compatible = "amcc,ppc460ex-rng", },
-       { .compatible = "amcc,ppc440epx-rng", },
-       {},
-};
-MODULE_DEVICE_TABLE(of, ppc4xx_rng_match);
-
-static struct platform_driver ppc4xx_rng_driver = {
-       .driver = {
-               .name = MODULE_NAME,
-               .of_match_table = ppc4xx_rng_match,
-       },
-       .probe = ppc4xx_rng_probe,
-       .remove = ppc4xx_rng_remove,
-};
-
-module_platform_driver(ppc4xx_rng_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Josh Boyer <jwboyer@linux.vnet.ibm.com>");
-MODULE_DESCRIPTION("HW RNG driver for PPC 4xx processors");
index 477fffdb4f491170a1debb7b4fa6efe10d4a9553..d77ba2f122427e54c8f7343b758609baac80bf3d 100644 (file)
@@ -279,6 +279,14 @@ config CRYPTO_DEV_PPC4XX
        help
          This option allows you to have support for AMCC crypto acceleration.
 
+config HW_RANDOM_PPC4XX
+       bool "PowerPC 4xx generic true random number generator support"
+       depends on CRYPTO_DEV_PPC4XX && HW_RANDOM
+       default y
+       ---help---
+        This option provides the kernel-side support for the TRNG hardware
+        found in the security function of some PowerPC 4xx SoCs.
+
 config CRYPTO_DEV_OMAP_SHAM
        tristate "Support for OMAP MD5/SHA1/SHA2 hw accelerator"
        depends on ARCH_OMAP2PLUS
@@ -302,15 +310,16 @@ config CRYPTO_DEV_OMAP_AES
          want to use the OMAP module for AES algorithms.
 
 config CRYPTO_DEV_OMAP_DES
-       tristate "Support for OMAP DES3DES hw engine"
+       tristate "Support for OMAP DES/3DES hw engine"
        depends on ARCH_OMAP2PLUS
        select CRYPTO_DES
        select CRYPTO_BLKCIPHER
+       select CRYPTO_ENGINE
        help
          OMAP processors have DES/3DES module accelerator. Select this if you
          want to use the OMAP module for DES and 3DES algorithms. Currently
-         the ECB and CBC modes of operation supported by the driver. Also
-         accesses made on unaligned boundaries are also supported.
+         the ECB and CBC modes of operation are supported by the driver. Also
+         accesses made on unaligned boundaries are supported.
 
 config CRYPTO_DEV_PICOXCELL
        tristate "Support for picoXcell IPSEC and Layer2 crypto engines"
@@ -340,9 +349,19 @@ config CRYPTO_DEV_SAHARA
          This option enables support for the SAHARA HW crypto accelerator
          found in some Freescale i.MX chips.
 
+config CRYPTO_DEV_MXC_SCC
+       tristate "Support for Freescale Security Controller (SCC)"
+       depends on ARCH_MXC && OF
+       select CRYPTO_BLKCIPHER
+       select CRYPTO_DES
+       help
+         This option enables support for the Security Controller (SCC)
+         found in Freescale i.MX25 chips.
+
 config CRYPTO_DEV_S5P
        tristate "Support for Samsung S5PV210/Exynos crypto accelerator"
-       depends on ARCH_S5PV210 || ARCH_EXYNOS
+       depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
+       depends on HAS_IOMEM && HAS_DMA
        select CRYPTO_AES
        select CRYPTO_BLKCIPHER
        help
index 713de9d11148ff60cc0693a2c93dff3adc5919d5..3c6432dd09d9de8e6ec499a1ab7454b2c3e8f395 100644 (file)
@@ -23,6 +23,7 @@ obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
 obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/
 obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
 obj-$(CONFIG_CRYPTO_DEV_SAHARA) += sahara.o
+obj-$(CONFIG_CRYPTO_DEV_MXC_SCC) += mxc-scc.o
 obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
 obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/
 obj-$(CONFIG_CRYPTO_DEV_QAT) += qat/
index 5c0c62b65d6933c64bea281ecd5f21bc60b3a89c..b95539928fdfd6499da0536dfb1b16846d59ffce 100644 (file)
@@ -1,2 +1,3 @@
 obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += crypto4xx.o
 crypto4xx-y :=  crypto4xx_core.o crypto4xx_alg.o crypto4xx_sa.o
+crypto4xx-$(CONFIG_HW_RANDOM_PPC4XX) += crypto4xx_trng.o
index 62134c8a226091c1a57d3d1687acd26e84ee3dcd..dae1e39139e9a19bb0155f42d5ccf233d6c15dd4 100644 (file)
@@ -40,6 +40,7 @@
 #include "crypto4xx_reg_def.h"
 #include "crypto4xx_core.h"
 #include "crypto4xx_sa.h"
+#include "crypto4xx_trng.h"
 
 #define PPC4XX_SEC_VERSION_STR                 "0.5"
 
@@ -1225,6 +1226,7 @@ static int crypto4xx_probe(struct platform_device *ofdev)
        if (rc)
                goto err_start_dev;
 
+       ppc4xx_trng_probe(core_dev);
        return 0;
 
 err_start_dev:
@@ -1252,6 +1254,8 @@ static int crypto4xx_remove(struct platform_device *ofdev)
        struct device *dev = &ofdev->dev;
        struct crypto4xx_core_device *core_dev = dev_get_drvdata(dev);
 
+       ppc4xx_trng_remove(core_dev);
+
        free_irq(core_dev->irq, dev);
        irq_dispose_mapping(core_dev->irq);
 
@@ -1272,7 +1276,7 @@ MODULE_DEVICE_TABLE(of, crypto4xx_match);
 
 static struct platform_driver crypto4xx_driver = {
        .driver = {
-               .name = "crypto4xx",
+               .name = MODULE_NAME,
                .of_match_table = crypto4xx_match,
        },
        .probe          = crypto4xx_probe,
@@ -1284,4 +1288,3 @@ module_platform_driver(crypto4xx_driver);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("James Hsiao <jhsiao@amcc.com>");
 MODULE_DESCRIPTION("Driver for AMCC PPC4xx crypto accelerator");
-
index bac0bdeb4b5f9955c193e6896a7f5bb182c19e63..ecfdcfe3698d62204ffa3f4f9096d0769c4094b5 100644 (file)
@@ -24,6 +24,8 @@
 
 #include <crypto/internal/hash.h>
 
+#define MODULE_NAME "crypto4xx"
+
 #define PPC460SX_SDR0_SRST                      0x201
 #define PPC405EX_SDR0_SRST                      0x200
 #define PPC460EX_SDR0_SRST                      0x201
@@ -72,6 +74,7 @@ struct crypto4xx_device {
        char *name;
        u64  ce_phy_address;
        void __iomem *ce_base;
+       void __iomem *trng_base;
 
        void *pdr;                      /* base address of packet
                                        descriptor ring */
@@ -106,6 +109,7 @@ struct crypto4xx_core_device {
        struct device *device;
        struct platform_device *ofdev;
        struct crypto4xx_device *dev;
+       struct hwrng *trng;
        u32 int_status;
        u32 irq;
        struct tasklet_struct tasklet;
index 5f5fbc0716ff1b28e43986faa6f18e918cb43ddc..46fe57c8f6eb9a89a81131a8fa3273b89ac034ab 100644 (file)
 #define PPC4XX_INTERRUPT_CLR                   0x3ffff
 #define PPC4XX_PRNG_CTRL_AUTO_EN               0x3
 #define PPC4XX_DC_3DES_EN                      1
+#define PPC4XX_TRNG_EN                         0x00020000
 #define PPC4XX_INT_DESCR_CNT                   4
 #define PPC4XX_INT_TIMEOUT_CNT                 0
 #define PPC4XX_INT_CFG                         1
diff --git a/drivers/crypto/amcc/crypto4xx_trng.c b/drivers/crypto/amcc/crypto4xx_trng.c
new file mode 100644 (file)
index 0000000..677ca17
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Generic PowerPC 44x RNG driver
+ *
+ * Copyright 2011 IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+#include <linux/delay.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+
+#include "crypto4xx_core.h"
+#include "crypto4xx_trng.h"
+#include "crypto4xx_reg_def.h"
+
+#define PPC4XX_TRNG_CTRL       0x0008
+#define PPC4XX_TRNG_CTRL_DALM  0x20
+#define PPC4XX_TRNG_STAT       0x0004
+#define PPC4XX_TRNG_STAT_B     0x1
+#define PPC4XX_TRNG_DATA       0x0000
+
+static int ppc4xx_trng_data_present(struct hwrng *rng, int wait)
+{
+       struct crypto4xx_device *dev = (void *)rng->priv;
+       int busy, i, present = 0;
+
+       for (i = 0; i < 20; i++) {
+               busy = (in_le32(dev->trng_base + PPC4XX_TRNG_STAT) &
+                       PPC4XX_TRNG_STAT_B);
+               if (!busy || !wait) {
+                       present = 1;
+                       break;
+               }
+               udelay(10);
+       }
+       return present;
+}
+
+static int ppc4xx_trng_data_read(struct hwrng *rng, u32 *data)
+{
+       struct crypto4xx_device *dev = (void *)rng->priv;
+       *data = in_le32(dev->trng_base + PPC4XX_TRNG_DATA);
+       return 4;
+}
+
+static void ppc4xx_trng_enable(struct crypto4xx_device *dev, bool enable)
+{
+       u32 device_ctrl;
+
+       device_ctrl = readl(dev->ce_base + CRYPTO4XX_DEVICE_CTRL);
+       if (enable)
+               device_ctrl |= PPC4XX_TRNG_EN;
+       else
+               device_ctrl &= ~PPC4XX_TRNG_EN;
+       writel(device_ctrl, dev->ce_base + CRYPTO4XX_DEVICE_CTRL);
+}
+
+static const struct of_device_id ppc4xx_trng_match[] = {
+       { .compatible = "ppc4xx-rng", },
+       { .compatible = "amcc,ppc460ex-rng", },
+       { .compatible = "amcc,ppc440epx-rng", },
+       {},
+};
+
+void ppc4xx_trng_probe(struct crypto4xx_core_device *core_dev)
+{
+       struct crypto4xx_device *dev = core_dev->dev;
+       struct device_node *trng = NULL;
+       struct hwrng *rng = NULL;
+       int err;
+
+       /* Find the TRNG device node and map it */
+       trng = of_find_matching_node(NULL, ppc4xx_trng_match);
+       if (!trng || !of_device_is_available(trng))
+               return;
+
+       dev->trng_base = of_iomap(trng, 0);
+       of_node_put(trng);
+       if (!dev->trng_base)
+               goto err_out;
+
+       rng = kzalloc(sizeof(*rng), GFP_KERNEL);
+       if (!rng)
+               goto err_out;
+
+       rng->name = MODULE_NAME;
+       rng->data_present = ppc4xx_trng_data_present;
+       rng->data_read = ppc4xx_trng_data_read;
+       rng->priv = (unsigned long) dev;
+       core_dev->trng = rng;
+       ppc4xx_trng_enable(dev, true);
+       out_le32(dev->trng_base + PPC4XX_TRNG_CTRL, PPC4XX_TRNG_CTRL_DALM);
+       err = devm_hwrng_register(core_dev->device, core_dev->trng);
+       if (err) {
+               ppc4xx_trng_enable(dev, false);
+               dev_err(core_dev->device, "failed to register hwrng (%d).\n",
+                       err);
+               goto err_out;
+       }
+       return;
+
+err_out:
+       of_node_put(trng);
+       iounmap(dev->trng_base);
+       kfree(rng);
+       dev->trng_base = NULL;
+       core_dev->trng = NULL;
+}
+
+void ppc4xx_trng_remove(struct crypto4xx_core_device *core_dev)
+{
+       if (core_dev && core_dev->trng) {
+               struct crypto4xx_device *dev = core_dev->dev;
+
+               devm_hwrng_unregister(core_dev->device, core_dev->trng);
+               ppc4xx_trng_enable(dev, false);
+               iounmap(dev->trng_base);
+               kfree(core_dev->trng);
+       }
+}
+
+MODULE_ALIAS("ppc4xx_rng");
diff --git a/drivers/crypto/amcc/crypto4xx_trng.h b/drivers/crypto/amcc/crypto4xx_trng.h
new file mode 100644 (file)
index 0000000..931d225
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * AMCC SoC PPC4xx Crypto Driver
+ *
+ * Copyright (c) 2008 Applied Micro Circuits Corporation.
+ * All rights reserved. James Hsiao <jhsiao@amcc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * This file defines the security context
+ * associate format.
+ */
+
+#ifndef __CRYPTO4XX_TRNG_H__
+#define __CRYPTO4XX_TRNG_H__
+
+#ifdef CONFIG_HW_RANDOM_PPC4XX
+void ppc4xx_trng_probe(struct crypto4xx_core_device *core_dev);
+void ppc4xx_trng_remove(struct crypto4xx_core_device *core_dev);
+#else
+static inline void ppc4xx_trng_probe(
+       struct crypto4xx_device *dev __maybe_unused) { }
+static inline void ppc4xx_trng_remove(
+       struct crypto4xx_device *dev __maybe_unused) { }
+#endif
+
+#endif
index 6fd63a600614e39f4893634eda28792f64fedda4..5ef4be22eb8099573fd4d35f62d24143d29ea043 100644 (file)
@@ -248,7 +248,7 @@ static void caam_jr_dequeue(unsigned long devarg)
 struct device *caam_jr_alloc(void)
 {
        struct caam_drv_private_jr *jrpriv, *min_jrpriv = NULL;
-       struct device *dev = NULL;
+       struct device *dev = ERR_PTR(-ENODEV);
        int min_tfm_cnt = INT_MAX;
        int tfm_cnt;
 
index 6e37845abf8f68fcb3b128a86c3839154cc86d14..2238f77aa248948de9f2319b520e4b890d44ae0e 100644 (file)
@@ -3,6 +3,8 @@ config CRYPTO_DEV_CCP_DD
        depends on CRYPTO_DEV_CCP
        default m
        select HW_RANDOM
+       select DMA_ENGINE
+       select DMADEVICES
        select CRYPTO_SHA1
        select CRYPTO_SHA256
        help
index b750592cc936d68e3aad084763633ea901ce9a44..ee4d2741b3abfc4a68155512bbd4e5bcc13c514b 100644 (file)
@@ -1,5 +1,9 @@
 obj-$(CONFIG_CRYPTO_DEV_CCP_DD) += ccp.o
-ccp-objs := ccp-dev.o ccp-ops.o ccp-dev-v3.o ccp-platform.o
+ccp-objs := ccp-dev.o \
+           ccp-ops.o \
+           ccp-dev-v3.o \
+           ccp-platform.o \
+           ccp-dmaengine.o
 ccp-$(CONFIG_PCI) += ccp-pci.o
 
 obj-$(CONFIG_CRYPTO_DEV_CCP_CRYPTO) += ccp-crypto.o
index 7d5eab49179e6b5513a3a5d41874c039c3090045..d7a71034796705c4c98f7f56b796fe80628bfc94 100644 (file)
@@ -406,6 +406,11 @@ static int ccp_init(struct ccp_device *ccp)
                goto e_kthread;
        }
 
+       /* Register the DMA engine support */
+       ret = ccp_dmaengine_register(ccp);
+       if (ret)
+               goto e_hwrng;
+
        ccp_add_device(ccp);
 
        /* Enable interrupts */
@@ -413,6 +418,9 @@ static int ccp_init(struct ccp_device *ccp)
 
        return 0;
 
+e_hwrng:
+       hwrng_unregister(&ccp->hwrng);
+
 e_kthread:
        for (i = 0; i < ccp->cmd_q_count; i++)
                if (ccp->cmd_q[i].kthread)
@@ -436,6 +444,9 @@ static void ccp_destroy(struct ccp_device *ccp)
        /* Remove this device from the list of available units first */
        ccp_del_device(ccp);
 
+       /* Unregister the DMA engine */
+       ccp_dmaengine_unregister(ccp);
+
        /* Unregister the RNG */
        hwrng_unregister(&ccp->hwrng);
 
@@ -515,7 +526,7 @@ static irqreturn_t ccp_irq_handler(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static struct ccp_actions ccp3_actions = {
+static const struct ccp_actions ccp3_actions = {
        .perform_aes = ccp_perform_aes,
        .perform_xts_aes = ccp_perform_xts_aes,
        .perform_sha = ccp_perform_sha,
index 4dbc187272358414e108143a0561940676de0341..87b9f2bfa623b1c6a2752519fffcdb5957646874 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
-#include <linux/rwlock_types.h>
+#include <linux/spinlock_types.h>
 #include <linux/types.h>
 #include <linux/mutex.h>
 #include <linux/delay.h>
index 7745d0be491dfe7cdb09157cb56da5b936d641b3..bd41ffceff82fecacfd878bfddd0056067cf7632 100644 (file)
@@ -22,6 +22,9 @@
 #include <linux/dmapool.h>
 #include <linux/hw_random.h>
 #include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/irqreturn.h>
+#include <linux/dmaengine.h>
 
 #define MAX_CCP_NAME_LEN               16
 #define MAX_DMAPOOL_NAME_LEN           32
@@ -159,7 +162,7 @@ struct ccp_actions {
 /* Structure to hold CCP version-specific values */
 struct ccp_vdata {
        unsigned int version;
-       struct ccp_actions *perform;
+       const struct ccp_actions *perform;
 };
 
 extern struct ccp_vdata ccpv3;
@@ -167,6 +170,39 @@ extern struct ccp_vdata ccpv3;
 struct ccp_device;
 struct ccp_cmd;
 
+struct ccp_dma_cmd {
+       struct list_head entry;
+
+       struct ccp_cmd ccp_cmd;
+};
+
+struct ccp_dma_desc {
+       struct list_head entry;
+
+       struct ccp_device *ccp;
+
+       struct list_head pending;
+       struct list_head active;
+
+       enum dma_status status;
+       struct dma_async_tx_descriptor tx_desc;
+       size_t len;
+};
+
+struct ccp_dma_chan {
+       struct ccp_device *ccp;
+
+       spinlock_t lock;
+       struct list_head pending;
+       struct list_head active;
+       struct list_head complete;
+
+       struct tasklet_struct cleanup_tasklet;
+
+       enum dma_status status;
+       struct dma_chan dma_chan;
+};
+
 struct ccp_cmd_queue {
        struct ccp_device *ccp;
 
@@ -260,6 +296,14 @@ struct ccp_device {
        struct hwrng hwrng;
        unsigned int hwrng_retries;
 
+       /*
+        * Support for the CCP DMA capabilities
+        */
+       struct dma_device dma_dev;
+       struct ccp_dma_chan *ccp_dma_chan;
+       struct kmem_cache *dma_cmd_cache;
+       struct kmem_cache *dma_desc_cache;
+
        /*
         * A counter used to generate job-ids for cmds submitted to the CCP
         */
@@ -418,4 +462,7 @@ int ccp_cmd_queue_thread(void *data);
 
 int ccp_run_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd);
 
+int ccp_dmaengine_register(struct ccp_device *ccp);
+void ccp_dmaengine_unregister(struct ccp_device *ccp);
+
 #endif
diff --git a/drivers/crypto/ccp/ccp-dmaengine.c b/drivers/crypto/ccp/ccp-dmaengine.c
new file mode 100644 (file)
index 0000000..94f77b0
--- /dev/null
@@ -0,0 +1,727 @@
+/*
+ * AMD Cryptographic Coprocessor (CCP) driver
+ *
+ * Copyright (C) 2016 Advanced Micro Devices, Inc.
+ *
+ * Author: Gary R Hook <gary.hook@amd.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/dmaengine.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/ccp.h>
+
+#include "ccp-dev.h"
+#include "../../dma/dmaengine.h"
+
+#define CCP_DMA_WIDTH(_mask)           \
+({                                     \
+       u64 mask = _mask + 1;           \
+       (mask == 0) ? 64 : fls64(mask); \
+})
+
+static void ccp_free_cmd_resources(struct ccp_device *ccp,
+                                  struct list_head *list)
+{
+       struct ccp_dma_cmd *cmd, *ctmp;
+
+       list_for_each_entry_safe(cmd, ctmp, list, entry) {
+               list_del(&cmd->entry);
+               kmem_cache_free(ccp->dma_cmd_cache, cmd);
+       }
+}
+
+static void ccp_free_desc_resources(struct ccp_device *ccp,
+                                   struct list_head *list)
+{
+       struct ccp_dma_desc *desc, *dtmp;
+
+       list_for_each_entry_safe(desc, dtmp, list, entry) {
+               ccp_free_cmd_resources(ccp, &desc->active);
+               ccp_free_cmd_resources(ccp, &desc->pending);
+
+               list_del(&desc->entry);
+               kmem_cache_free(ccp->dma_desc_cache, desc);
+       }
+}
+
+static void ccp_free_chan_resources(struct dma_chan *dma_chan)
+{
+       struct ccp_dma_chan *chan = container_of(dma_chan, struct ccp_dma_chan,
+                                                dma_chan);
+       unsigned long flags;
+
+       dev_dbg(chan->ccp->dev, "%s - chan=%p\n", __func__, chan);
+
+       spin_lock_irqsave(&chan->lock, flags);
+
+       ccp_free_desc_resources(chan->ccp, &chan->complete);
+       ccp_free_desc_resources(chan->ccp, &chan->active);
+       ccp_free_desc_resources(chan->ccp, &chan->pending);
+
+       spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+static void ccp_cleanup_desc_resources(struct ccp_device *ccp,
+                                      struct list_head *list)
+{
+       struct ccp_dma_desc *desc, *dtmp;
+
+       list_for_each_entry_safe_reverse(desc, dtmp, list, entry) {
+               if (!async_tx_test_ack(&desc->tx_desc))
+                       continue;
+
+               dev_dbg(ccp->dev, "%s - desc=%p\n", __func__, desc);
+
+               ccp_free_cmd_resources(ccp, &desc->active);
+               ccp_free_cmd_resources(ccp, &desc->pending);
+
+               list_del(&desc->entry);
+               kmem_cache_free(ccp->dma_desc_cache, desc);
+       }
+}
+
+static void ccp_do_cleanup(unsigned long data)
+{
+       struct ccp_dma_chan *chan = (struct ccp_dma_chan *)data;
+       unsigned long flags;
+
+       dev_dbg(chan->ccp->dev, "%s - chan=%s\n", __func__,
+               dma_chan_name(&chan->dma_chan));
+
+       spin_lock_irqsave(&chan->lock, flags);
+
+       ccp_cleanup_desc_resources(chan->ccp, &chan->complete);
+
+       spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+static int ccp_issue_next_cmd(struct ccp_dma_desc *desc)
+{
+       struct ccp_dma_cmd *cmd;
+       int ret;
+
+       cmd = list_first_entry(&desc->pending, struct ccp_dma_cmd, entry);
+       list_move(&cmd->entry, &desc->active);
+
+       dev_dbg(desc->ccp->dev, "%s - tx %d, cmd=%p\n", __func__,
+               desc->tx_desc.cookie, cmd);
+
+       ret = ccp_enqueue_cmd(&cmd->ccp_cmd);
+       if (!ret || (ret == -EINPROGRESS) || (ret == -EBUSY))
+               return 0;
+
+       dev_dbg(desc->ccp->dev, "%s - error: ret=%d, tx %d, cmd=%p\n", __func__,
+               ret, desc->tx_desc.cookie, cmd);
+
+       return ret;
+}
+
+static void ccp_free_active_cmd(struct ccp_dma_desc *desc)
+{
+       struct ccp_dma_cmd *cmd;
+
+       cmd = list_first_entry_or_null(&desc->active, struct ccp_dma_cmd,
+                                      entry);
+       if (!cmd)
+               return;
+
+       dev_dbg(desc->ccp->dev, "%s - freeing tx %d cmd=%p\n",
+               __func__, desc->tx_desc.cookie, cmd);
+
+       list_del(&cmd->entry);
+       kmem_cache_free(desc->ccp->dma_cmd_cache, cmd);
+}
+
+static struct ccp_dma_desc *__ccp_next_dma_desc(struct ccp_dma_chan *chan,
+                                               struct ccp_dma_desc *desc)
+{
+       /* Move current DMA descriptor to the complete list */
+       if (desc)
+               list_move(&desc->entry, &chan->complete);
+
+       /* Get the next DMA descriptor on the active list */
+       desc = list_first_entry_or_null(&chan->active, struct ccp_dma_desc,
+                                       entry);
+
+       return desc;
+}
+
+static struct ccp_dma_desc *ccp_handle_active_desc(struct ccp_dma_chan *chan,
+                                                  struct ccp_dma_desc *desc)
+{
+       struct dma_async_tx_descriptor *tx_desc;
+       unsigned long flags;
+
+       /* Loop over descriptors until one is found with commands */
+       do {
+               if (desc) {
+                       /* Remove the DMA command from the list and free it */
+                       ccp_free_active_cmd(desc);
+
+                       if (!list_empty(&desc->pending)) {
+                               /* No errors, keep going */
+                               if (desc->status != DMA_ERROR)
+                                       return desc;
+
+                               /* Error, free remaining commands and move on */
+                               ccp_free_cmd_resources(desc->ccp,
+                                                      &desc->pending);
+                       }
+
+                       tx_desc = &desc->tx_desc;
+               } else {
+                       tx_desc = NULL;
+               }
+
+               spin_lock_irqsave(&chan->lock, flags);
+
+               if (desc) {
+                       if (desc->status != DMA_ERROR)
+                               desc->status = DMA_COMPLETE;
+
+                       dev_dbg(desc->ccp->dev,
+                               "%s - tx %d complete, status=%u\n", __func__,
+                               desc->tx_desc.cookie, desc->status);
+
+                       dma_cookie_complete(tx_desc);
+               }
+
+               desc = __ccp_next_dma_desc(chan, desc);
+
+               spin_unlock_irqrestore(&chan->lock, flags);
+
+               if (tx_desc) {
+                       if (tx_desc->callback &&
+                           (tx_desc->flags & DMA_PREP_INTERRUPT))
+                               tx_desc->callback(tx_desc->callback_param);
+
+                       dma_run_dependencies(tx_desc);
+               }
+       } while (desc);
+
+       return NULL;
+}
+
+static struct ccp_dma_desc *__ccp_pending_to_active(struct ccp_dma_chan *chan)
+{
+       struct ccp_dma_desc *desc;
+
+       if (list_empty(&chan->pending))
+               return NULL;
+
+       desc = list_empty(&chan->active)
+               ? list_first_entry(&chan->pending, struct ccp_dma_desc, entry)
+               : NULL;
+
+       list_splice_tail_init(&chan->pending, &chan->active);
+
+       return desc;
+}
+
+static void ccp_cmd_callback(void *data, int err)
+{
+       struct ccp_dma_desc *desc = data;
+       struct ccp_dma_chan *chan;
+       int ret;
+
+       if (err == -EINPROGRESS)
+               return;
+
+       chan = container_of(desc->tx_desc.chan, struct ccp_dma_chan,
+                           dma_chan);
+
+       dev_dbg(chan->ccp->dev, "%s - tx %d callback, err=%d\n",
+               __func__, desc->tx_desc.cookie, err);
+
+       if (err)
+               desc->status = DMA_ERROR;
+
+       while (true) {
+               /* Check for DMA descriptor completion */
+               desc = ccp_handle_active_desc(chan, desc);
+
+               /* Don't submit cmd if no descriptor or DMA is paused */
+               if (!desc || (chan->status == DMA_PAUSED))
+                       break;
+
+               ret = ccp_issue_next_cmd(desc);
+               if (!ret)
+                       break;
+
+               desc->status = DMA_ERROR;
+       }
+
+       tasklet_schedule(&chan->cleanup_tasklet);
+}
+
+static dma_cookie_t ccp_tx_submit(struct dma_async_tx_descriptor *tx_desc)
+{
+       struct ccp_dma_desc *desc = container_of(tx_desc, struct ccp_dma_desc,
+                                                tx_desc);
+       struct ccp_dma_chan *chan;
+       dma_cookie_t cookie;
+       unsigned long flags;
+
+       chan = container_of(tx_desc->chan, struct ccp_dma_chan, dma_chan);
+
+       spin_lock_irqsave(&chan->lock, flags);
+
+       cookie = dma_cookie_assign(tx_desc);
+       list_add_tail(&desc->entry, &chan->pending);
+
+       spin_unlock_irqrestore(&chan->lock, flags);
+
+       dev_dbg(chan->ccp->dev, "%s - added tx descriptor %d to pending list\n",
+               __func__, cookie);
+
+       return cookie;
+}
+
+static struct ccp_dma_cmd *ccp_alloc_dma_cmd(struct ccp_dma_chan *chan)
+{
+       struct ccp_dma_cmd *cmd;
+
+       cmd = kmem_cache_alloc(chan->ccp->dma_cmd_cache, GFP_NOWAIT);
+       if (cmd)
+               memset(cmd, 0, sizeof(*cmd));
+
+       return cmd;
+}
+
+static struct ccp_dma_desc *ccp_alloc_dma_desc(struct ccp_dma_chan *chan,
+                                              unsigned long flags)
+{
+       struct ccp_dma_desc *desc;
+
+       desc = kmem_cache_alloc(chan->ccp->dma_desc_cache, GFP_NOWAIT);
+       if (!desc)
+               return NULL;
+
+       memset(desc, 0, sizeof(*desc));
+
+       dma_async_tx_descriptor_init(&desc->tx_desc, &chan->dma_chan);
+       desc->tx_desc.flags = flags;
+       desc->tx_desc.tx_submit = ccp_tx_submit;
+       desc->ccp = chan->ccp;
+       INIT_LIST_HEAD(&desc->pending);
+       INIT_LIST_HEAD(&desc->active);
+       desc->status = DMA_IN_PROGRESS;
+
+       return desc;
+}
+
+static struct ccp_dma_desc *ccp_create_desc(struct dma_chan *dma_chan,
+                                           struct scatterlist *dst_sg,
+                                           unsigned int dst_nents,
+                                           struct scatterlist *src_sg,
+                                           unsigned int src_nents,
+                                           unsigned long flags)
+{
+       struct ccp_dma_chan *chan = container_of(dma_chan, struct ccp_dma_chan,
+                                                dma_chan);
+       struct ccp_device *ccp = chan->ccp;
+       struct ccp_dma_desc *desc;
+       struct ccp_dma_cmd *cmd;
+       struct ccp_cmd *ccp_cmd;
+       struct ccp_passthru_nomap_engine *ccp_pt;
+       unsigned int src_offset, src_len;
+       unsigned int dst_offset, dst_len;
+       unsigned int len;
+       unsigned long sflags;
+       size_t total_len;
+
+       if (!dst_sg || !src_sg)
+               return NULL;
+
+       if (!dst_nents || !src_nents)
+               return NULL;
+
+       desc = ccp_alloc_dma_desc(chan, flags);
+       if (!desc)
+               return NULL;
+
+       total_len = 0;
+
+       src_len = sg_dma_len(src_sg);
+       src_offset = 0;
+
+       dst_len = sg_dma_len(dst_sg);
+       dst_offset = 0;
+
+       while (true) {
+               if (!src_len) {
+                       src_nents--;
+                       if (!src_nents)
+                               break;
+
+                       src_sg = sg_next(src_sg);
+                       if (!src_sg)
+                               break;
+
+                       src_len = sg_dma_len(src_sg);
+                       src_offset = 0;
+                       continue;
+               }
+
+               if (!dst_len) {
+                       dst_nents--;
+                       if (!dst_nents)
+                               break;
+
+                       dst_sg = sg_next(dst_sg);
+                       if (!dst_sg)
+                               break;
+
+                       dst_len = sg_dma_len(dst_sg);
+                       dst_offset = 0;
+                       continue;
+               }
+
+               len = min(dst_len, src_len);
+
+               cmd = ccp_alloc_dma_cmd(chan);
+               if (!cmd)
+                       goto err;
+
+               ccp_cmd = &cmd->ccp_cmd;
+               ccp_pt = &ccp_cmd->u.passthru_nomap;
+               ccp_cmd->flags = CCP_CMD_MAY_BACKLOG;
+               ccp_cmd->flags |= CCP_CMD_PASSTHRU_NO_DMA_MAP;
+               ccp_cmd->engine = CCP_ENGINE_PASSTHRU;
+               ccp_pt->bit_mod = CCP_PASSTHRU_BITWISE_NOOP;
+               ccp_pt->byte_swap = CCP_PASSTHRU_BYTESWAP_NOOP;
+               ccp_pt->src_dma = sg_dma_address(src_sg) + src_offset;
+               ccp_pt->dst_dma = sg_dma_address(dst_sg) + dst_offset;
+               ccp_pt->src_len = len;
+               ccp_pt->final = 1;
+               ccp_cmd->callback = ccp_cmd_callback;
+               ccp_cmd->data = desc;
+
+               list_add_tail(&cmd->entry, &desc->pending);
+
+               dev_dbg(ccp->dev,
+                       "%s - cmd=%p, src=%pad, dst=%pad, len=%llu\n", __func__,
+                       cmd, &ccp_pt->src_dma,
+                       &ccp_pt->dst_dma, ccp_pt->src_len);
+
+               total_len += len;
+
+               src_len -= len;
+               src_offset += len;
+
+               dst_len -= len;
+               dst_offset += len;
+       }
+
+       desc->len = total_len;
+
+       if (list_empty(&desc->pending))
+               goto err;
+
+       dev_dbg(ccp->dev, "%s - desc=%p\n", __func__, desc);
+
+       spin_lock_irqsave(&chan->lock, sflags);
+
+       list_add_tail(&desc->entry, &chan->pending);
+
+       spin_unlock_irqrestore(&chan->lock, sflags);
+
+       return desc;
+
+err:
+       ccp_free_cmd_resources(ccp, &desc->pending);
+       kmem_cache_free(ccp->dma_desc_cache, desc);
+
+       return NULL;
+}
+
+static struct dma_async_tx_descriptor *ccp_prep_dma_memcpy(
+       struct dma_chan *dma_chan, dma_addr_t dst, dma_addr_t src, size_t len,
+       unsigned long flags)
+{
+       struct ccp_dma_chan *chan = container_of(dma_chan, struct ccp_dma_chan,
+                                                dma_chan);
+       struct ccp_dma_desc *desc;
+       struct scatterlist dst_sg, src_sg;
+
+       dev_dbg(chan->ccp->dev,
+               "%s - src=%pad, dst=%pad, len=%zu, flags=%#lx\n",
+               __func__, &src, &dst, len, flags);
+
+       sg_init_table(&dst_sg, 1);
+       sg_dma_address(&dst_sg) = dst;
+       sg_dma_len(&dst_sg) = len;
+
+       sg_init_table(&src_sg, 1);
+       sg_dma_address(&src_sg) = src;
+       sg_dma_len(&src_sg) = len;
+
+       desc = ccp_create_desc(dma_chan, &dst_sg, 1, &src_sg, 1, flags);
+       if (!desc)
+               return NULL;
+
+       return &desc->tx_desc;
+}
+
+static struct dma_async_tx_descriptor *ccp_prep_dma_sg(
+       struct dma_chan *dma_chan, struct scatterlist *dst_sg,
+       unsigned int dst_nents, struct scatterlist *src_sg,
+       unsigned int src_nents, unsigned long flags)
+{
+       struct ccp_dma_chan *chan = container_of(dma_chan, struct ccp_dma_chan,
+                                                dma_chan);
+       struct ccp_dma_desc *desc;
+
+       dev_dbg(chan->ccp->dev,
+               "%s - src=%p, src_nents=%u dst=%p, dst_nents=%u, flags=%#lx\n",
+               __func__, src_sg, src_nents, dst_sg, dst_nents, flags);
+
+       desc = ccp_create_desc(dma_chan, dst_sg, dst_nents, src_sg, src_nents,
+                              flags);
+       if (!desc)
+               return NULL;
+
+       return &desc->tx_desc;
+}
+
+static struct dma_async_tx_descriptor *ccp_prep_dma_interrupt(
+       struct dma_chan *dma_chan, unsigned long flags)
+{
+       struct ccp_dma_chan *chan = container_of(dma_chan, struct ccp_dma_chan,
+                                                dma_chan);
+       struct ccp_dma_desc *desc;
+
+       desc = ccp_alloc_dma_desc(chan, flags);
+       if (!desc)
+               return NULL;
+
+       return &desc->tx_desc;
+}
+
+static void ccp_issue_pending(struct dma_chan *dma_chan)
+{
+       struct ccp_dma_chan *chan = container_of(dma_chan, struct ccp_dma_chan,
+                                                dma_chan);
+       struct ccp_dma_desc *desc;
+       unsigned long flags;
+
+       dev_dbg(chan->ccp->dev, "%s\n", __func__);
+
+       spin_lock_irqsave(&chan->lock, flags);
+
+       desc = __ccp_pending_to_active(chan);
+
+       spin_unlock_irqrestore(&chan->lock, flags);
+
+       /* If there was nothing active, start processing */
+       if (desc)
+               ccp_cmd_callback(desc, 0);
+}
+
+static enum dma_status ccp_tx_status(struct dma_chan *dma_chan,
+                                    dma_cookie_t cookie,
+                                    struct dma_tx_state *state)
+{
+       struct ccp_dma_chan *chan = container_of(dma_chan, struct ccp_dma_chan,
+                                                dma_chan);
+       struct ccp_dma_desc *desc;
+       enum dma_status ret;
+       unsigned long flags;
+
+       if (chan->status == DMA_PAUSED) {
+               ret = DMA_PAUSED;
+               goto out;
+       }
+
+       ret = dma_cookie_status(dma_chan, cookie, state);
+       if (ret == DMA_COMPLETE) {
+               spin_lock_irqsave(&chan->lock, flags);
+
+               /* Get status from complete chain, if still there */
+               list_for_each_entry(desc, &chan->complete, entry) {
+                       if (desc->tx_desc.cookie != cookie)
+                               continue;
+
+                       ret = desc->status;
+                       break;
+               }
+
+               spin_unlock_irqrestore(&chan->lock, flags);
+       }
+
+out:
+       dev_dbg(chan->ccp->dev, "%s - %u\n", __func__, ret);
+
+       return ret;
+}
+
+static int ccp_pause(struct dma_chan *dma_chan)
+{
+       struct ccp_dma_chan *chan = container_of(dma_chan, struct ccp_dma_chan,
+                                                dma_chan);
+
+       chan->status = DMA_PAUSED;
+
+       /*TODO: Wait for active DMA to complete before returning? */
+
+       return 0;
+}
+
+static int ccp_resume(struct dma_chan *dma_chan)
+{
+       struct ccp_dma_chan *chan = container_of(dma_chan, struct ccp_dma_chan,
+                                                dma_chan);
+       struct ccp_dma_desc *desc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&chan->lock, flags);
+
+       desc = list_first_entry_or_null(&chan->active, struct ccp_dma_desc,
+                                       entry);
+
+       spin_unlock_irqrestore(&chan->lock, flags);
+
+       /* Indicate the channel is running again */
+       chan->status = DMA_IN_PROGRESS;
+
+       /* If there was something active, re-start */
+       if (desc)
+               ccp_cmd_callback(desc, 0);
+
+       return 0;
+}
+
+static int ccp_terminate_all(struct dma_chan *dma_chan)
+{
+       struct ccp_dma_chan *chan = container_of(dma_chan, struct ccp_dma_chan,
+                                                dma_chan);
+       unsigned long flags;
+
+       dev_dbg(chan->ccp->dev, "%s\n", __func__);
+
+       /*TODO: Wait for active DMA to complete before continuing */
+
+       spin_lock_irqsave(&chan->lock, flags);
+
+       /*TODO: Purge the complete list? */
+       ccp_free_desc_resources(chan->ccp, &chan->active);
+       ccp_free_desc_resources(chan->ccp, &chan->pending);
+
+       spin_unlock_irqrestore(&chan->lock, flags);
+
+       return 0;
+}
+
+int ccp_dmaengine_register(struct ccp_device *ccp)
+{
+       struct ccp_dma_chan *chan;
+       struct dma_device *dma_dev = &ccp->dma_dev;
+       struct dma_chan *dma_chan;
+       char *dma_cmd_cache_name;
+       char *dma_desc_cache_name;
+       unsigned int i;
+       int ret;
+
+       ccp->ccp_dma_chan = devm_kcalloc(ccp->dev, ccp->cmd_q_count,
+                                        sizeof(*(ccp->ccp_dma_chan)),
+                                        GFP_KERNEL);
+       if (!ccp->ccp_dma_chan)
+               return -ENOMEM;
+
+       dma_cmd_cache_name = devm_kasprintf(ccp->dev, GFP_KERNEL,
+                                           "%s-dmaengine-cmd-cache",
+                                           ccp->name);
+       if (!dma_cmd_cache_name)
+               return -ENOMEM;
+
+       ccp->dma_cmd_cache = kmem_cache_create(dma_cmd_cache_name,
+                                              sizeof(struct ccp_dma_cmd),
+                                              sizeof(void *),
+                                              SLAB_HWCACHE_ALIGN, NULL);
+       if (!ccp->dma_cmd_cache)
+               return -ENOMEM;
+
+       dma_desc_cache_name = devm_kasprintf(ccp->dev, GFP_KERNEL,
+                                            "%s-dmaengine-desc-cache",
+                                            ccp->name);
+       if (!dma_cmd_cache_name)
+               return -ENOMEM;
+       ccp->dma_desc_cache = kmem_cache_create(dma_desc_cache_name,
+                                               sizeof(struct ccp_dma_desc),
+                                               sizeof(void *),
+                                               SLAB_HWCACHE_ALIGN, NULL);
+       if (!ccp->dma_desc_cache) {
+               ret = -ENOMEM;
+               goto err_cache;
+       }
+
+       dma_dev->dev = ccp->dev;
+       dma_dev->src_addr_widths = CCP_DMA_WIDTH(dma_get_mask(ccp->dev));
+       dma_dev->dst_addr_widths = CCP_DMA_WIDTH(dma_get_mask(ccp->dev));
+       dma_dev->directions = DMA_MEM_TO_MEM;
+       dma_dev->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
+       dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask);
+       dma_cap_set(DMA_SG, dma_dev->cap_mask);
+       dma_cap_set(DMA_INTERRUPT, dma_dev->cap_mask);
+
+       INIT_LIST_HEAD(&dma_dev->channels);
+       for (i = 0; i < ccp->cmd_q_count; i++) {
+               chan = ccp->ccp_dma_chan + i;
+               dma_chan = &chan->dma_chan;
+
+               chan->ccp = ccp;
+
+               spin_lock_init(&chan->lock);
+               INIT_LIST_HEAD(&chan->pending);
+               INIT_LIST_HEAD(&chan->active);
+               INIT_LIST_HEAD(&chan->complete);
+
+               tasklet_init(&chan->cleanup_tasklet, ccp_do_cleanup,
+                            (unsigned long)chan);
+
+               dma_chan->device = dma_dev;
+               dma_cookie_init(dma_chan);
+
+               list_add_tail(&dma_chan->device_node, &dma_dev->channels);
+       }
+
+       dma_dev->device_free_chan_resources = ccp_free_chan_resources;
+       dma_dev->device_prep_dma_memcpy = ccp_prep_dma_memcpy;
+       dma_dev->device_prep_dma_sg = ccp_prep_dma_sg;
+       dma_dev->device_prep_dma_interrupt = ccp_prep_dma_interrupt;
+       dma_dev->device_issue_pending = ccp_issue_pending;
+       dma_dev->device_tx_status = ccp_tx_status;
+       dma_dev->device_pause = ccp_pause;
+       dma_dev->device_resume = ccp_resume;
+       dma_dev->device_terminate_all = ccp_terminate_all;
+
+       ret = dma_async_device_register(dma_dev);
+       if (ret)
+               goto err_reg;
+
+       return 0;
+
+err_reg:
+       kmem_cache_destroy(ccp->dma_desc_cache);
+
+err_cache:
+       kmem_cache_destroy(ccp->dma_cmd_cache);
+
+       return ret;
+}
+
+void ccp_dmaengine_unregister(struct ccp_device *ccp)
+{
+       struct dma_device *dma_dev = &ccp->dma_dev;
+
+       dma_async_device_unregister(dma_dev);
+
+       kmem_cache_destroy(ccp->dma_desc_cache);
+       kmem_cache_destroy(ccp->dma_cmd_cache);
+}
index eefdf595f75879ca1af01c2052f76c7d9b9170bf..ffa2891035ac4210ec2c0efab78d6bd1affec240 100644 (file)
@@ -1427,6 +1427,70 @@ e_mask:
        return ret;
 }
 
+static int ccp_run_passthru_nomap_cmd(struct ccp_cmd_queue *cmd_q,
+                                     struct ccp_cmd *cmd)
+{
+       struct ccp_passthru_nomap_engine *pt = &cmd->u.passthru_nomap;
+       struct ccp_dm_workarea mask;
+       struct ccp_op op;
+       int ret;
+
+       if (!pt->final && (pt->src_len & (CCP_PASSTHRU_BLOCKSIZE - 1)))
+               return -EINVAL;
+
+       if (!pt->src_dma || !pt->dst_dma)
+               return -EINVAL;
+
+       if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP) {
+               if (pt->mask_len != CCP_PASSTHRU_MASKSIZE)
+                       return -EINVAL;
+               if (!pt->mask)
+                       return -EINVAL;
+       }
+
+       BUILD_BUG_ON(CCP_PASSTHRU_KSB_COUNT != 1);
+
+       memset(&op, 0, sizeof(op));
+       op.cmd_q = cmd_q;
+       op.jobid = ccp_gen_jobid(cmd_q->ccp);
+
+       if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP) {
+               /* Load the mask */
+               op.ksb_key = cmd_q->ksb_key;
+
+               mask.length = pt->mask_len;
+               mask.dma.address = pt->mask;
+               mask.dma.length = pt->mask_len;
+
+               ret = ccp_copy_to_ksb(cmd_q, &mask, op.jobid, op.ksb_key,
+                                    CCP_PASSTHRU_BYTESWAP_NOOP);
+               if (ret) {
+                       cmd->engine_error = cmd_q->cmd_error;
+                       return ret;
+               }
+       }
+
+       /* Send data to the CCP Passthru engine */
+       op.eom = 1;
+       op.soc = 1;
+
+       op.src.type = CCP_MEMTYPE_SYSTEM;
+       op.src.u.dma.address = pt->src_dma;
+       op.src.u.dma.offset = 0;
+       op.src.u.dma.length = pt->src_len;
+
+       op.dst.type = CCP_MEMTYPE_SYSTEM;
+       op.dst.u.dma.address = pt->dst_dma;
+       op.dst.u.dma.offset = 0;
+       op.dst.u.dma.length = pt->src_len;
+
+       ret = cmd_q->ccp->vdata->perform->perform_passthru(&op);
+       if (ret)
+               cmd->engine_error = cmd_q->cmd_error;
+
+       return ret;
+}
+
 static int ccp_run_ecc_mm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
 {
        struct ccp_ecc_engine *ecc = &cmd->u.ecc;
@@ -1762,7 +1826,10 @@ int ccp_run_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
                ret = ccp_run_rsa_cmd(cmd_q, cmd);
                break;
        case CCP_ENGINE_PASSTHRU:
-               ret = ccp_run_passthru_cmd(cmd_q, cmd);
+               if (cmd->flags & CCP_CMD_PASSTHRU_NO_DMA_MAP)
+                       ret = ccp_run_passthru_nomap_cmd(cmd_q, cmd);
+               else
+                       ret = ccp_run_passthru_cmd(cmd_q, cmd);
                break;
        case CCP_ENGINE_ECC:
                ret = ccp_run_ecc_cmd(cmd_q, cmd);
index 80239ae69527210ef9cabf53267d40907a8df871..e8ef9fd24a166a104a4e1742c59b06b633eaf79f 100644 (file)
@@ -475,18 +475,18 @@ static int mv_cesa_probe(struct platform_device *pdev)
                engine->regs = cesa->regs + CESA_ENGINE_OFF(i);
 
                if (dram && cesa->caps->has_tdma)
-                       mv_cesa_conf_mbus_windows(&cesa->engines[i], dram);
+                       mv_cesa_conf_mbus_windows(engine, dram);
 
-               writel(0, cesa->engines[i].regs + CESA_SA_INT_STATUS);
+               writel(0, engine->regs + CESA_SA_INT_STATUS);
                writel(CESA_SA_CFG_STOP_DIG_ERR,
-                      cesa->engines[i].regs + CESA_SA_CFG);
+                      engine->regs + CESA_SA_CFG);
                writel(engine->sram_dma & CESA_SA_SRAM_MSK,
-                      cesa->engines[i].regs + CESA_SA_DESC_P0);
+                      engine->regs + CESA_SA_DESC_P0);
 
                ret = devm_request_threaded_irq(dev, irq, NULL, mv_cesa_int,
                                                IRQF_ONESHOT,
                                                dev_name(&pdev->dev),
-                                               &cesa->engines[i]);
+                                               engine);
                if (ret)
                        goto err_cleanup;
        }
index 7ca2e0f9dc2ef983d47e1a67f1cb142ef35e2e3a..7a5058da9151797cc95f48c5131a1ccedb2c1361 100644 (file)
@@ -768,8 +768,7 @@ static int mv_cesa_ahash_export(struct ahash_request *req, void *hash,
        *len = creq->len;
        memcpy(hash, creq->state, digsize);
        memset(cache, 0, blocksize);
-       if (creq->cache)
-               memcpy(cache, creq->cache, creq->cache_ptr);
+       memcpy(cache, creq->cache, creq->cache_ptr);
 
        return 0;
 }
index 76427981275b025dfee52a87e4850981ac159f0f..0ad8f1ecf17593acaa6e3bc986f999e8f734ffaf 100644 (file)
@@ -99,12 +99,11 @@ mv_cesa_dma_add_desc(struct mv_cesa_tdma_chain *chain, gfp_t flags)
        struct mv_cesa_tdma_desc *new_tdma = NULL;
        dma_addr_t dma_handle;
 
-       new_tdma = dma_pool_alloc(cesa_dev->dma->tdma_desc_pool, flags,
-                                 &dma_handle);
+       new_tdma = dma_pool_zalloc(cesa_dev->dma->tdma_desc_pool, flags,
+                                  &dma_handle);
        if (!new_tdma)
                return ERR_PTR(-ENOMEM);
 
-       memset(new_tdma, 0, sizeof(*new_tdma));
        new_tdma->cur_dma = dma_handle;
        if (chain->last) {
                chain->last->next_dma = cpu_to_le32(dma_handle);
diff --git a/drivers/crypto/mxc-scc.c b/drivers/crypto/mxc-scc.c
new file mode 100644 (file)
index 0000000..ff383ef
--- /dev/null
@@ -0,0 +1,765 @@
+/*
+ * Copyright (C) 2016 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de>
+ *
+ * The driver is based on information gathered from
+ * drivers/mxc/security/mxc_scc.c which can be found in
+ * the Freescale linux-2.6-imx.git in the imx_2.6.35_maintain branch.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/clk.h>
+#include <linux/crypto.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include <crypto/algapi.h>
+#include <crypto/des.h>
+
+/* Secure Memory (SCM) registers */
+#define SCC_SCM_RED_START              0x0000
+#define SCC_SCM_BLACK_START            0x0004
+#define SCC_SCM_LENGTH                 0x0008
+#define SCC_SCM_CTRL                   0x000C
+#define SCC_SCM_STATUS                 0x0010
+#define SCC_SCM_ERROR_STATUS           0x0014
+#define SCC_SCM_INTR_CTRL              0x0018
+#define SCC_SCM_CFG                    0x001C
+#define SCC_SCM_INIT_VECTOR_0          0x0020
+#define SCC_SCM_INIT_VECTOR_1          0x0024
+#define SCC_SCM_RED_MEMORY             0x0400
+#define SCC_SCM_BLACK_MEMORY           0x0800
+
+/* Security Monitor (SMN) Registers */
+#define SCC_SMN_STATUS                 0x1000
+#define SCC_SMN_COMMAND                0x1004
+#define SCC_SMN_SEQ_START              0x1008
+#define SCC_SMN_SEQ_END                0x100C
+#define SCC_SMN_SEQ_CHECK              0x1010
+#define SCC_SMN_BIT_COUNT              0x1014
+#define SCC_SMN_BITBANK_INC_SIZE       0x1018
+#define SCC_SMN_BITBANK_DECREMENT      0x101C
+#define SCC_SMN_COMPARE_SIZE           0x1020
+#define SCC_SMN_PLAINTEXT_CHECK        0x1024
+#define SCC_SMN_CIPHERTEXT_CHECK       0x1028
+#define SCC_SMN_TIMER_IV               0x102C
+#define SCC_SMN_TIMER_CONTROL          0x1030
+#define SCC_SMN_DEBUG_DETECT_STAT      0x1034
+#define SCC_SMN_TIMER                  0x1038
+
+#define SCC_SCM_CTRL_START_CIPHER      BIT(2)
+#define SCC_SCM_CTRL_CBC_MODE          BIT(1)
+#define SCC_SCM_CTRL_DECRYPT_MODE      BIT(0)
+
+#define SCC_SCM_STATUS_LEN_ERR         BIT(12)
+#define SCC_SCM_STATUS_SMN_UNBLOCKED   BIT(11)
+#define SCC_SCM_STATUS_CIPHERING_DONE  BIT(10)
+#define SCC_SCM_STATUS_ZEROIZING_DONE  BIT(9)
+#define SCC_SCM_STATUS_INTR_STATUS     BIT(8)
+#define SCC_SCM_STATUS_SEC_KEY         BIT(7)
+#define SCC_SCM_STATUS_INTERNAL_ERR    BIT(6)
+#define SCC_SCM_STATUS_BAD_SEC_KEY     BIT(5)
+#define SCC_SCM_STATUS_ZEROIZE_FAIL    BIT(4)
+#define SCC_SCM_STATUS_SMN_BLOCKED     BIT(3)
+#define SCC_SCM_STATUS_CIPHERING       BIT(2)
+#define SCC_SCM_STATUS_ZEROIZING       BIT(1)
+#define SCC_SCM_STATUS_BUSY            BIT(0)
+
+#define SCC_SMN_STATUS_STATE_MASK      0x0000001F
+#define SCC_SMN_STATE_START            0x0
+/* The SMN is zeroizing its RAM during reset */
+#define SCC_SMN_STATE_ZEROIZE_RAM      0x5
+/* SMN has passed internal checks */
+#define SCC_SMN_STATE_HEALTH_CHECK     0x6
+/* Fatal Security Violation. SMN is locked, SCM is inoperative. */
+#define SCC_SMN_STATE_FAIL             0x9
+/* SCC is in secure state. SCM is using secret key. */
+#define SCC_SMN_STATE_SECURE           0xA
+/* SCC is not secure. SCM is using default key. */
+#define SCC_SMN_STATE_NON_SECURE       0xC
+
+#define SCC_SCM_INTR_CTRL_ZEROIZE_MEM  BIT(2)
+#define SCC_SCM_INTR_CTRL_CLR_INTR     BIT(1)
+#define SCC_SCM_INTR_CTRL_MASK_INTR    BIT(0)
+
+/* Size, in blocks, of Red memory. */
+#define SCC_SCM_CFG_BLACK_SIZE_MASK    0x07fe0000
+#define SCC_SCM_CFG_BLACK_SIZE_SHIFT   17
+/* Size, in blocks, of Black memory. */
+#define SCC_SCM_CFG_RED_SIZE_MASK      0x0001ff80
+#define SCC_SCM_CFG_RED_SIZE_SHIFT     7
+/* Number of bytes per block. */
+#define SCC_SCM_CFG_BLOCK_SIZE_MASK    0x0000007f
+
+#define SCC_SMN_COMMAND_TAMPER_LOCK    BIT(4)
+#define SCC_SMN_COMMAND_CLR_INTR       BIT(3)
+#define SCC_SMN_COMMAND_CLR_BIT_BANK   BIT(2)
+#define SCC_SMN_COMMAND_EN_INTR        BIT(1)
+#define SCC_SMN_COMMAND_SET_SOFTWARE_ALARM  BIT(0)
+
+#define SCC_KEY_SLOTS                  20
+#define SCC_MAX_KEY_SIZE               32
+#define SCC_KEY_SLOT_SIZE              32
+
+#define SCC_CRC_CCITT_START            0xFFFF
+
+/*
+ * Offset into each RAM of the base of the area which is not
+ * used for Stored Keys.
+ */
+#define SCC_NON_RESERVED_OFFSET        (SCC_KEY_SLOTS * SCC_KEY_SLOT_SIZE)
+
+/* Fixed padding for appending to plaintext to fill out a block */
+static char scc_block_padding[8] = { 0x80, 0, 0, 0, 0, 0, 0, 0 };
+
+enum mxc_scc_state {
+       SCC_STATE_OK,
+       SCC_STATE_UNIMPLEMENTED,
+       SCC_STATE_FAILED
+};
+
+struct mxc_scc {
+       struct device           *dev;
+       void __iomem            *base;
+       struct clk              *clk;
+       bool                    hw_busy;
+       spinlock_t              lock;
+       struct crypto_queue     queue;
+       struct crypto_async_request *req;
+       int                     block_size_bytes;
+       int                     black_ram_size_blocks;
+       int                     memory_size_bytes;
+       int                     bytes_remaining;
+
+       void __iomem            *red_memory;
+       void __iomem            *black_memory;
+};
+
+struct mxc_scc_ctx {
+       struct mxc_scc          *scc;
+       struct scatterlist      *sg_src;
+       size_t                  src_nents;
+       struct scatterlist      *sg_dst;
+       size_t                  dst_nents;
+       unsigned int            offset;
+       unsigned int            size;
+       unsigned int            ctrl;
+};
+
+struct mxc_scc_crypto_tmpl {
+       struct mxc_scc *scc;
+       struct crypto_alg alg;
+};
+
+static int mxc_scc_get_data(struct mxc_scc_ctx *ctx,
+                           struct crypto_async_request *req)
+{
+       struct ablkcipher_request *ablkreq = ablkcipher_request_cast(req);
+       struct mxc_scc *scc = ctx->scc;
+       size_t len;
+       void __iomem *from;
+
+       if (ctx->ctrl & SCC_SCM_CTRL_DECRYPT_MODE)
+               from = scc->red_memory;
+       else
+               from = scc->black_memory;
+
+       dev_dbg(scc->dev, "pcopy: from 0x%p %d bytes\n", from,
+               ctx->dst_nents * 8);
+       len = sg_pcopy_from_buffer(ablkreq->dst, ctx->dst_nents,
+                                  from, ctx->size, ctx->offset);
+       if (!len) {
+               dev_err(scc->dev, "pcopy err from 0x%p (len=%d)\n", from, len);
+               return -EINVAL;
+       }
+
+#ifdef DEBUG
+       print_hex_dump(KERN_ERR,
+                      "red memory@"__stringify(__LINE__)": ",
+                      DUMP_PREFIX_ADDRESS, 16, 4,
+                      scc->red_memory, ctx->size, 1);
+       print_hex_dump(KERN_ERR,
+                      "black memory@"__stringify(__LINE__)": ",
+                      DUMP_PREFIX_ADDRESS, 16, 4,
+                      scc->black_memory, ctx->size, 1);
+#endif
+
+       ctx->offset += len;
+
+       if (ctx->offset < ablkreq->nbytes)
+               return -EINPROGRESS;
+
+       return 0;
+}
+
+static int mxc_scc_ablkcipher_req_init(struct ablkcipher_request *req,
+                                      struct mxc_scc_ctx *ctx)
+{
+       struct mxc_scc *scc = ctx->scc;
+       int nents;
+
+       nents = sg_nents_for_len(req->src, req->nbytes);
+       if (nents < 0) {
+               dev_err(scc->dev, "Invalid number of src SC");
+               return nents;
+       }
+       ctx->src_nents = nents;
+
+       nents = sg_nents_for_len(req->dst, req->nbytes);
+       if (nents < 0) {
+               dev_err(scc->dev, "Invalid number of dst SC");
+               return nents;
+       }
+       ctx->dst_nents = nents;
+
+       ctx->size = 0;
+       ctx->offset = 0;
+
+       return 0;
+}
+
+static int mxc_scc_ablkcipher_req_complete(struct crypto_async_request *req,
+                                          struct mxc_scc_ctx *ctx,
+                                          int result)
+{
+       struct ablkcipher_request *ablkreq = ablkcipher_request_cast(req);
+       struct mxc_scc *scc = ctx->scc;
+
+       scc->req = NULL;
+       scc->bytes_remaining = scc->memory_size_bytes;
+
+       if (ctx->ctrl & SCC_SCM_CTRL_CBC_MODE)
+               memcpy(ablkreq->info, scc->base + SCC_SCM_INIT_VECTOR_0,
+                      scc->block_size_bytes);
+
+       req->complete(req, result);
+       scc->hw_busy = false;
+
+       return 0;
+}
+
+static int mxc_scc_put_data(struct mxc_scc_ctx *ctx,
+                            struct ablkcipher_request *req)
+{
+       u8 padding_buffer[sizeof(u16) + sizeof(scc_block_padding)];
+       size_t len = min_t(size_t, req->nbytes - ctx->offset,
+                          ctx->scc->bytes_remaining);
+       unsigned int padding_byte_count = 0;
+       struct mxc_scc *scc = ctx->scc;
+       void __iomem *to;
+
+       if (ctx->ctrl & SCC_SCM_CTRL_DECRYPT_MODE)
+               to = scc->black_memory;
+       else
+               to = scc->red_memory;
+
+       if (ctx->ctrl & SCC_SCM_CTRL_CBC_MODE && req->info)
+               memcpy(scc->base + SCC_SCM_INIT_VECTOR_0, req->info,
+                      scc->block_size_bytes);
+
+       len = sg_pcopy_to_buffer(req->src, ctx->src_nents,
+                                to, len, ctx->offset);
+       if (!len) {
+               dev_err(scc->dev, "pcopy err to 0x%p (len=%d)\n", to, len);
+               return -EINVAL;
+       }
+
+       ctx->size = len;
+
+#ifdef DEBUG
+       dev_dbg(scc->dev, "copied %d bytes to 0x%p\n", len, to);
+       print_hex_dump(KERN_ERR,
+                      "init vector0@"__stringify(__LINE__)": ",
+                      DUMP_PREFIX_ADDRESS, 16, 4,
+                      scc->base + SCC_SCM_INIT_VECTOR_0, scc->block_size_bytes,
+                      1);
+       print_hex_dump(KERN_ERR,
+                      "red memory@"__stringify(__LINE__)": ",
+                      DUMP_PREFIX_ADDRESS, 16, 4,
+                      scc->red_memory, ctx->size, 1);
+       print_hex_dump(KERN_ERR,
+                      "black memory@"__stringify(__LINE__)": ",
+                      DUMP_PREFIX_ADDRESS, 16, 4,
+                      scc->black_memory, ctx->size, 1);
+#endif
+
+       scc->bytes_remaining -= len;
+
+       padding_byte_count = len % scc->block_size_bytes;
+
+       if (padding_byte_count) {
+               memcpy(padding_buffer, scc_block_padding, padding_byte_count);
+               memcpy(to + len, padding_buffer, padding_byte_count);
+               ctx->size += padding_byte_count;
+       }
+
+#ifdef DEBUG
+       print_hex_dump(KERN_ERR,
+                      "data to encrypt@"__stringify(__LINE__)": ",
+                      DUMP_PREFIX_ADDRESS, 16, 4,
+                      to, ctx->size, 1);
+#endif
+
+       return 0;
+}
+
+static void mxc_scc_ablkcipher_next(struct mxc_scc_ctx *ctx,
+                                   struct crypto_async_request *req)
+{
+       struct ablkcipher_request *ablkreq = ablkcipher_request_cast(req);
+       struct mxc_scc *scc = ctx->scc;
+       int err;
+
+       dev_dbg(scc->dev, "dispatch request (nbytes=%d, src=%p, dst=%p)\n",
+               ablkreq->nbytes, ablkreq->src, ablkreq->dst);
+
+       writel(0, scc->base + SCC_SCM_ERROR_STATUS);
+
+       err = mxc_scc_put_data(ctx, ablkreq);
+       if (err) {
+               mxc_scc_ablkcipher_req_complete(req, ctx, err);
+               return;
+       }
+
+       dev_dbg(scc->dev, "Start encryption (0x%p/0x%p)\n",
+               (void *)readl(scc->base + SCC_SCM_RED_START),
+               (void *)readl(scc->base + SCC_SCM_BLACK_START));
+
+       /* clear interrupt control registers */
+       writel(SCC_SCM_INTR_CTRL_CLR_INTR,
+              scc->base + SCC_SCM_INTR_CTRL);
+
+       writel((ctx->size / ctx->scc->block_size_bytes) - 1,
+              scc->base + SCC_SCM_LENGTH);
+
+       dev_dbg(scc->dev, "Process %d block(s) in 0x%p\n",
+               ctx->size / ctx->scc->block_size_bytes,
+               (ctx->ctrl & SCC_SCM_CTRL_DECRYPT_MODE) ? scc->black_memory :
+               scc->red_memory);
+
+       writel(ctx->ctrl, scc->base + SCC_SCM_CTRL);
+}
+
+static irqreturn_t mxc_scc_int(int irq, void *priv)
+{
+       struct crypto_async_request *req;
+       struct mxc_scc_ctx *ctx;
+       struct mxc_scc *scc = priv;
+       int status;
+       int ret;
+
+       status = readl(scc->base + SCC_SCM_STATUS);
+
+       /* clear interrupt control registers */
+       writel(SCC_SCM_INTR_CTRL_CLR_INTR, scc->base + SCC_SCM_INTR_CTRL);
+
+       if (status & SCC_SCM_STATUS_BUSY)
+               return IRQ_NONE;
+
+       req = scc->req;
+       if (req) {
+               ctx = crypto_tfm_ctx(req->tfm);
+               ret = mxc_scc_get_data(ctx, req);
+               if (ret != -EINPROGRESS)
+                       mxc_scc_ablkcipher_req_complete(req, ctx, ret);
+               else
+                       mxc_scc_ablkcipher_next(ctx, req);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int mxc_scc_cra_init(struct crypto_tfm *tfm)
+{
+       struct mxc_scc_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct crypto_alg *alg = tfm->__crt_alg;
+       struct mxc_scc_crypto_tmpl *algt;
+
+       algt = container_of(alg, struct mxc_scc_crypto_tmpl, alg);
+
+       ctx->scc = algt->scc;
+       return 0;
+}
+
+static void mxc_scc_dequeue_req_unlocked(struct mxc_scc_ctx *ctx)
+{
+       struct crypto_async_request *req, *backlog;
+
+       if (ctx->scc->hw_busy)
+               return;
+
+       spin_lock_bh(&ctx->scc->lock);
+       backlog = crypto_get_backlog(&ctx->scc->queue);
+       req = crypto_dequeue_request(&ctx->scc->queue);
+       ctx->scc->req = req;
+       ctx->scc->hw_busy = true;
+       spin_unlock_bh(&ctx->scc->lock);
+
+       if (!req)
+               return;
+
+       if (backlog)
+               backlog->complete(backlog, -EINPROGRESS);
+
+       mxc_scc_ablkcipher_next(ctx, req);
+}
+
+static int mxc_scc_queue_req(struct mxc_scc_ctx *ctx,
+                            struct crypto_async_request *req)
+{
+       int ret;
+
+       spin_lock_bh(&ctx->scc->lock);
+       ret = crypto_enqueue_request(&ctx->scc->queue, req);
+       spin_unlock_bh(&ctx->scc->lock);
+
+       if (ret != -EINPROGRESS)
+               return ret;
+
+       mxc_scc_dequeue_req_unlocked(ctx);
+
+       return -EINPROGRESS;
+}
+
+static int mxc_scc_des3_op(struct mxc_scc_ctx *ctx,
+                          struct ablkcipher_request *req)
+{
+       int err;
+
+       err = mxc_scc_ablkcipher_req_init(req, ctx);
+       if (err)
+               return err;
+
+       return mxc_scc_queue_req(ctx, &req->base);
+}
+
+static int mxc_scc_ecb_des_encrypt(struct ablkcipher_request *req)
+{
+       struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(req);
+       struct mxc_scc_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+
+       ctx->ctrl = SCC_SCM_CTRL_START_CIPHER;
+
+       return mxc_scc_des3_op(ctx, req);
+}
+
+static int mxc_scc_ecb_des_decrypt(struct ablkcipher_request *req)
+{
+       struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(req);
+       struct mxc_scc_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+
+       ctx->ctrl = SCC_SCM_CTRL_START_CIPHER;
+       ctx->ctrl |= SCC_SCM_CTRL_DECRYPT_MODE;
+
+       return mxc_scc_des3_op(ctx, req);
+}
+
+static int mxc_scc_cbc_des_encrypt(struct ablkcipher_request *req)
+{
+       struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(req);
+       struct mxc_scc_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+
+       ctx->ctrl = SCC_SCM_CTRL_START_CIPHER;
+       ctx->ctrl |= SCC_SCM_CTRL_CBC_MODE;
+
+       return mxc_scc_des3_op(ctx, req);
+}
+
+static int mxc_scc_cbc_des_decrypt(struct ablkcipher_request *req)
+{
+       struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(req);
+       struct mxc_scc_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+
+       ctx->ctrl = SCC_SCM_CTRL_START_CIPHER;
+       ctx->ctrl |= SCC_SCM_CTRL_CBC_MODE;
+       ctx->ctrl |= SCC_SCM_CTRL_DECRYPT_MODE;
+
+       return mxc_scc_des3_op(ctx, req);
+}
+
+static void mxc_scc_hw_init(struct mxc_scc *scc)
+{
+       int offset;
+
+       offset = SCC_NON_RESERVED_OFFSET / scc->block_size_bytes;
+
+       /* Fill the RED_START register */
+       writel(offset, scc->base + SCC_SCM_RED_START);
+
+       /* Fill the BLACK_START register */
+       writel(offset, scc->base + SCC_SCM_BLACK_START);
+
+       scc->red_memory = scc->base + SCC_SCM_RED_MEMORY +
+                         SCC_NON_RESERVED_OFFSET;
+
+       scc->black_memory = scc->base + SCC_SCM_BLACK_MEMORY +
+                           SCC_NON_RESERVED_OFFSET;
+
+       scc->bytes_remaining = scc->memory_size_bytes;
+}
+
+static int mxc_scc_get_config(struct mxc_scc *scc)
+{
+       int config;
+
+       config = readl(scc->base + SCC_SCM_CFG);
+
+       scc->block_size_bytes = config & SCC_SCM_CFG_BLOCK_SIZE_MASK;
+
+       scc->black_ram_size_blocks = config & SCC_SCM_CFG_BLACK_SIZE_MASK;
+
+       scc->memory_size_bytes = (scc->block_size_bytes *
+                                 scc->black_ram_size_blocks) -
+                                 SCC_NON_RESERVED_OFFSET;
+
+       return 0;
+}
+
+static enum mxc_scc_state mxc_scc_get_state(struct mxc_scc *scc)
+{
+       enum mxc_scc_state state;
+       int status;
+
+       status = readl(scc->base + SCC_SMN_STATUS) &
+                      SCC_SMN_STATUS_STATE_MASK;
+
+       /* If in Health Check, try to bringup to secure state */
+       if (status & SCC_SMN_STATE_HEALTH_CHECK) {
+               /*
+                * Write a simple algorithm to the Algorithm Sequence
+                * Checker (ASC)
+                */
+               writel(0xaaaa, scc->base + SCC_SMN_SEQ_START);
+               writel(0x5555, scc->base + SCC_SMN_SEQ_END);
+               writel(0x5555, scc->base + SCC_SMN_SEQ_CHECK);
+
+               status = readl(scc->base + SCC_SMN_STATUS) &
+                              SCC_SMN_STATUS_STATE_MASK;
+       }
+
+       switch (status) {
+       case SCC_SMN_STATE_NON_SECURE:
+       case SCC_SMN_STATE_SECURE:
+               state = SCC_STATE_OK;
+               break;
+       case SCC_SMN_STATE_FAIL:
+               state = SCC_STATE_FAILED;
+               break;
+       default:
+               state = SCC_STATE_UNIMPLEMENTED;
+               break;
+       }
+
+       return state;
+}
+
+static struct mxc_scc_crypto_tmpl scc_ecb_des = {
+       .alg = {
+               .cra_name = "ecb(des3_ede)",
+               .cra_driver_name = "ecb-des3-scc",
+               .cra_priority = 300,
+               .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER,
+               .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+               .cra_ctxsize = sizeof(struct mxc_scc_ctx),
+               .cra_alignmask = 0,
+               .cra_type = &crypto_ablkcipher_type,
+               .cra_module = THIS_MODULE,
+               .cra_init = mxc_scc_cra_init,
+               .cra_u.ablkcipher = {
+                       .min_keysize = DES3_EDE_KEY_SIZE,
+                       .max_keysize = DES3_EDE_KEY_SIZE,
+                       .encrypt = mxc_scc_ecb_des_encrypt,
+                       .decrypt = mxc_scc_ecb_des_decrypt,
+               }
+       }
+};
+
+static struct mxc_scc_crypto_tmpl scc_cbc_des = {
+       .alg = {
+               .cra_name = "cbc(des3_ede)",
+               .cra_driver_name = "cbc-des3-scc",
+               .cra_priority = 300,
+               .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER,
+               .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+               .cra_ctxsize = sizeof(struct mxc_scc_ctx),
+               .cra_alignmask = 0,
+               .cra_type = &crypto_ablkcipher_type,
+               .cra_module = THIS_MODULE,
+               .cra_init = mxc_scc_cra_init,
+               .cra_u.ablkcipher = {
+                       .min_keysize = DES3_EDE_KEY_SIZE,
+                       .max_keysize = DES3_EDE_KEY_SIZE,
+                       .encrypt = mxc_scc_cbc_des_encrypt,
+                       .decrypt = mxc_scc_cbc_des_decrypt,
+               }
+       }
+};
+
+static struct mxc_scc_crypto_tmpl *scc_crypto_algs[] = {
+       &scc_ecb_des,
+       &scc_cbc_des,
+};
+
+static int mxc_scc_crypto_register(struct mxc_scc *scc)
+{
+       int i;
+       int err = 0;
+
+       for (i = 0; i < ARRAY_SIZE(scc_crypto_algs); i++) {
+               scc_crypto_algs[i]->scc = scc;
+               err = crypto_register_alg(&scc_crypto_algs[i]->alg);
+               if (err)
+                       goto err_out;
+       }
+
+       return 0;
+
+err_out:
+       while (--i >= 0)
+               crypto_unregister_alg(&scc_crypto_algs[i]->alg);
+
+       return err;
+}
+
+static void mxc_scc_crypto_unregister(void)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(scc_crypto_algs); i++)
+               crypto_unregister_alg(&scc_crypto_algs[i]->alg);
+}
+
+static int mxc_scc_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       struct mxc_scc *scc;
+       enum mxc_scc_state state;
+       int irq;
+       int ret;
+       int i;
+
+       scc = devm_kzalloc(dev, sizeof(*scc), GFP_KERNEL);
+       if (!scc)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       scc->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(scc->base))
+               return PTR_ERR(scc->base);
+
+       scc->clk = devm_clk_get(&pdev->dev, "ipg");
+       if (IS_ERR(scc->clk)) {
+               dev_err(dev, "Could not get ipg clock\n");
+               return PTR_ERR(scc->clk);
+       }
+
+       clk_prepare_enable(scc->clk);
+
+       /* clear error status register */
+       writel(0x0, scc->base + SCC_SCM_ERROR_STATUS);
+
+       /* clear interrupt control registers */
+       writel(SCC_SCM_INTR_CTRL_CLR_INTR |
+              SCC_SCM_INTR_CTRL_MASK_INTR,
+              scc->base + SCC_SCM_INTR_CTRL);
+
+       writel(SCC_SMN_COMMAND_CLR_INTR |
+              SCC_SMN_COMMAND_EN_INTR,
+              scc->base + SCC_SMN_COMMAND);
+
+       scc->dev = dev;
+       platform_set_drvdata(pdev, scc);
+
+       ret = mxc_scc_get_config(scc);
+       if (ret)
+               goto err_out;
+
+       state = mxc_scc_get_state(scc);
+
+       if (state != SCC_STATE_OK) {
+               dev_err(dev, "SCC in unusable state %d\n", state);
+               ret = -EINVAL;
+               goto err_out;
+       }
+
+       mxc_scc_hw_init(scc);
+
+       spin_lock_init(&scc->lock);
+       /* FIXME: calculate queue from RAM slots */
+       crypto_init_queue(&scc->queue, 50);
+
+       for (i = 0; i < 2; i++) {
+               irq = platform_get_irq(pdev, i);
+               if (irq < 0) {
+                       dev_err(dev, "failed to get irq resource\n");
+                       ret = -EINVAL;
+                       goto err_out;
+               }
+
+               ret = devm_request_threaded_irq(dev, irq, NULL, mxc_scc_int,
+                                               IRQF_ONESHOT, dev_name(dev), scc);
+               if (ret)
+                       goto err_out;
+       }
+
+       ret = mxc_scc_crypto_register(scc);
+       if (ret) {
+               dev_err(dev, "could not register algorithms");
+               goto err_out;
+       }
+
+       dev_info(dev, "registered successfully.\n");
+
+       return 0;
+
+err_out:
+       clk_disable_unprepare(scc->clk);
+
+       return ret;
+}
+
+static int mxc_scc_remove(struct platform_device *pdev)
+{
+       struct mxc_scc *scc = platform_get_drvdata(pdev);
+
+       mxc_scc_crypto_unregister();
+
+       clk_disable_unprepare(scc->clk);
+
+       return 0;
+}
+
+static const struct of_device_id mxc_scc_dt_ids[] = {
+       { .compatible = "fsl,imx25-scc", .data = NULL, },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxc_scc_dt_ids);
+
+static struct platform_driver mxc_scc_driver = {
+       .probe  = mxc_scc_probe,
+       .remove = mxc_scc_remove,
+       .driver = {
+               .name           = "mxc-scc",
+               .of_match_table = mxc_scc_dt_ids,
+       },
+};
+
+module_platform_driver(mxc_scc_driver);
+MODULE_AUTHOR("Steffen Trumtrar <kernel@pengutronix.de>");
+MODULE_DESCRIPTION("Freescale i.MX25 SCC Crypto driver");
+MODULE_LICENSE("GPL v2");
index b85a7a7dbf63b0dce993eb707c2d1c8c6d030985..c5aac25a57380ba8e6976538cb76ee5b72e6429c 100644 (file)
@@ -1598,7 +1598,7 @@ static void *new_queue(unsigned long q_type)
 
 static void free_queue(void *p, unsigned long q_type)
 {
-       return kmem_cache_free(queue_cache[q_type - 1], p);
+       kmem_cache_free(queue_cache[q_type - 1], p);
 }
 
 static int queue_cache_init(void)
index d420ec751c7c9e090710f568f9b4370591c09110..ce174d3b842ceadcd0fa88577c090b150584b187 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/scatterlist.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
-#include <linux/omap-dma.h>
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -176,9 +175,7 @@ struct omap_aes_dev {
 
        struct scatter_walk             in_walk;
        struct scatter_walk             out_walk;
-       int                     dma_in;
        struct dma_chan         *dma_lch_in;
-       int                     dma_out;
        struct dma_chan         *dma_lch_out;
        int                     in_sg_len;
        int                     out_sg_len;
@@ -351,30 +348,21 @@ static void omap_aes_dma_out_callback(void *data)
 
 static int omap_aes_dma_init(struct omap_aes_dev *dd)
 {
-       int err = -ENOMEM;
-       dma_cap_mask_t mask;
+       int err;
 
        dd->dma_lch_out = NULL;
        dd->dma_lch_in = NULL;
 
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-
-       dd->dma_lch_in = dma_request_slave_channel_compat(mask,
-                                                         omap_dma_filter_fn,
-                                                         &dd->dma_in,
-                                                         dd->dev, "rx");
-       if (!dd->dma_lch_in) {
+       dd->dma_lch_in = dma_request_chan(dd->dev, "rx");
+       if (IS_ERR(dd->dma_lch_in)) {
                dev_err(dd->dev, "Unable to request in DMA channel\n");
-               goto err_dma_in;
+               return PTR_ERR(dd->dma_lch_in);
        }
 
-       dd->dma_lch_out = dma_request_slave_channel_compat(mask,
-                                                          omap_dma_filter_fn,
-                                                          &dd->dma_out,
-                                                          dd->dev, "tx");
-       if (!dd->dma_lch_out) {
+       dd->dma_lch_out = dma_request_chan(dd->dev, "tx");
+       if (IS_ERR(dd->dma_lch_out)) {
                dev_err(dd->dev, "Unable to request out DMA channel\n");
+               err = PTR_ERR(dd->dma_lch_out);
                goto err_dma_out;
        }
 
@@ -382,14 +370,15 @@ static int omap_aes_dma_init(struct omap_aes_dev *dd)
 
 err_dma_out:
        dma_release_channel(dd->dma_lch_in);
-err_dma_in:
-       if (err)
-               pr_err("error: %d\n", err);
+
        return err;
 }
 
 static void omap_aes_dma_cleanup(struct omap_aes_dev *dd)
 {
+       if (dd->pio_only)
+               return;
+
        dma_release_channel(dd->dma_lch_out);
        dma_release_channel(dd->dma_lch_in);
 }
@@ -1080,9 +1069,6 @@ static int omap_aes_get_res_of(struct omap_aes_dev *dd,
                goto err;
        }
 
-       dd->dma_out = -1; /* Dummy value that's unused */
-       dd->dma_in = -1; /* Dummy value that's unused */
-
        dd->pdata = match->data;
 
 err:
@@ -1116,24 +1102,6 @@ static int omap_aes_get_res_pdev(struct omap_aes_dev *dd,
        }
        memcpy(res, r, sizeof(*res));
 
-       /* Get the DMA out channel */
-       r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!r) {
-               dev_err(dev, "no DMA out resource info\n");
-               err = -ENODEV;
-               goto err;
-       }
-       dd->dma_out = r->start;
-
-       /* Get the DMA in channel */
-       r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-       if (!r) {
-               dev_err(dev, "no DMA in resource info\n");
-               err = -ENODEV;
-               goto err;
-       }
-       dd->dma_in = r->start;
-
        /* Only OMAP2/3 can be non-DT */
        dd->pdata = &omap_aes_pdata_omap2;
 
@@ -1191,7 +1159,9 @@ static int omap_aes_probe(struct platform_device *pdev)
        tasklet_init(&dd->done_task, omap_aes_done_task, (unsigned long)dd);
 
        err = omap_aes_dma_init(dd);
-       if (err && AES_REG_IRQ_STATUS(dd) && AES_REG_IRQ_ENABLE(dd)) {
+       if (err == -EPROBE_DEFER) {
+               goto err_irq;
+       } else if (err && AES_REG_IRQ_STATUS(dd) && AES_REG_IRQ_ENABLE(dd)) {
                dd->pio_only = 1;
 
                irq = platform_get_irq(pdev, 0);
@@ -1248,8 +1218,8 @@ err_algs:
                for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
                        crypto_unregister_alg(
                                        &dd->pdata->algs_info[i].algs_list[j]);
-       if (!dd->pio_only)
-               omap_aes_dma_cleanup(dd);
+
+       omap_aes_dma_cleanup(dd);
 err_irq:
        tasklet_kill(&dd->done_task);
        pm_runtime_disable(dev);
index dd7b93f2f94ce3a527ad019dd8735fcadc39b83d..3eedb03111ba9fa01cecf5b437168cb40c89a806 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/scatterlist.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
-#include <linux/omap-dma.h>
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -39,6 +38,7 @@
 #include <linux/interrupt.h>
 #include <crypto/scatterwalk.h>
 #include <crypto/des.h>
+#include <crypto/algapi.h>
 
 #define DST_MAXBURST                   2
 
@@ -132,14 +132,10 @@ struct omap_des_dev {
        unsigned long           flags;
        int                     err;
 
-       /* spinlock used for queues */
-       spinlock_t              lock;
-       struct crypto_queue     queue;
-
        struct tasklet_struct   done_task;
-       struct tasklet_struct   queue_task;
 
        struct ablkcipher_request       *req;
+       struct crypto_engine            *engine;
        /*
         * total is used by PIO mode for book keeping so introduce
         * variable total_save as need it to calc page_order
@@ -158,9 +154,7 @@ struct omap_des_dev {
 
        struct scatter_walk             in_walk;
        struct scatter_walk             out_walk;
-       int                     dma_in;
        struct dma_chan         *dma_lch_in;
-       int                     dma_out;
        struct dma_chan         *dma_lch_out;
        int                     in_sg_len;
        int                     out_sg_len;
@@ -340,30 +334,21 @@ static void omap_des_dma_out_callback(void *data)
 
 static int omap_des_dma_init(struct omap_des_dev *dd)
 {
-       int err = -ENOMEM;
-       dma_cap_mask_t mask;
+       int err;
 
        dd->dma_lch_out = NULL;
        dd->dma_lch_in = NULL;
 
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-
-       dd->dma_lch_in = dma_request_slave_channel_compat(mask,
-                                                         omap_dma_filter_fn,
-                                                         &dd->dma_in,
-                                                         dd->dev, "rx");
-       if (!dd->dma_lch_in) {
+       dd->dma_lch_in = dma_request_chan(dd->dev, "rx");
+       if (IS_ERR(dd->dma_lch_in)) {
                dev_err(dd->dev, "Unable to request in DMA channel\n");
-               goto err_dma_in;
+               return PTR_ERR(dd->dma_lch_in);
        }
 
-       dd->dma_lch_out = dma_request_slave_channel_compat(mask,
-                                                          omap_dma_filter_fn,
-                                                          &dd->dma_out,
-                                                          dd->dev, "tx");
-       if (!dd->dma_lch_out) {
+       dd->dma_lch_out = dma_request_chan(dd->dev, "tx");
+       if (IS_ERR(dd->dma_lch_out)) {
                dev_err(dd->dev, "Unable to request out DMA channel\n");
+               err = PTR_ERR(dd->dma_lch_out);
                goto err_dma_out;
        }
 
@@ -371,14 +356,15 @@ static int omap_des_dma_init(struct omap_des_dev *dd)
 
 err_dma_out:
        dma_release_channel(dd->dma_lch_in);
-err_dma_in:
-       if (err)
-               pr_err("error: %d\n", err);
+
        return err;
 }
 
 static void omap_des_dma_cleanup(struct omap_des_dev *dd)
 {
+       if (dd->pio_only)
+               return;
+
        dma_release_channel(dd->dma_lch_out);
        dma_release_channel(dd->dma_lch_in);
 }
@@ -520,9 +506,7 @@ static void omap_des_finish_req(struct omap_des_dev *dd, int err)
        pr_debug("err: %d\n", err);
 
        pm_runtime_put(dd->dev);
-       dd->flags &= ~FLAGS_BUSY;
-
-       req->base.complete(&req->base, err);
+       crypto_finalize_request(dd->engine, req, err);
 }
 
 static int omap_des_crypt_dma_stop(struct omap_des_dev *dd)
@@ -585,34 +569,24 @@ static int omap_des_copy_sgs(struct omap_des_dev *dd)
 }
 
 static int omap_des_handle_queue(struct omap_des_dev *dd,
-                              struct ablkcipher_request *req)
+                                struct ablkcipher_request *req)
 {
-       struct crypto_async_request *async_req, *backlog;
-       struct omap_des_ctx *ctx;
-       struct omap_des_reqctx *rctx;
-       unsigned long flags;
-       int err, ret = 0;
-
-       spin_lock_irqsave(&dd->lock, flags);
        if (req)
-               ret = ablkcipher_enqueue_request(&dd->queue, req);
-       if (dd->flags & FLAGS_BUSY) {
-               spin_unlock_irqrestore(&dd->lock, flags);
-               return ret;
-       }
-       backlog = crypto_get_backlog(&dd->queue);
-       async_req = crypto_dequeue_request(&dd->queue);
-       if (async_req)
-               dd->flags |= FLAGS_BUSY;
-       spin_unlock_irqrestore(&dd->lock, flags);
+               return crypto_transfer_request_to_engine(dd->engine, req);
 
-       if (!async_req)
-               return ret;
+       return 0;
+}
 
-       if (backlog)
-               backlog->complete(backlog, -EINPROGRESS);
+static int omap_des_prepare_req(struct crypto_engine *engine,
+                               struct ablkcipher_request *req)
+{
+       struct omap_des_ctx *ctx = crypto_ablkcipher_ctx(
+                       crypto_ablkcipher_reqtfm(req));
+       struct omap_des_dev *dd = omap_des_find_dev(ctx);
+       struct omap_des_reqctx *rctx;
 
-       req = ablkcipher_request_cast(async_req);
+       if (!dd)
+               return -ENODEV;
 
        /* assign new request to device */
        dd->req = req;
@@ -642,16 +616,20 @@ static int omap_des_handle_queue(struct omap_des_dev *dd,
        dd->ctx = ctx;
        ctx->dd = dd;
 
-       err = omap_des_write_ctrl(dd);
-       if (!err)
-               err = omap_des_crypt_dma_start(dd);
-       if (err) {
-               /* des_task will not finish it, so do it here */
-               omap_des_finish_req(dd, err);
-               tasklet_schedule(&dd->queue_task);
-       }
+       return omap_des_write_ctrl(dd);
+}
+
+static int omap_des_crypt_req(struct crypto_engine *engine,
+                             struct ablkcipher_request *req)
+{
+       struct omap_des_ctx *ctx = crypto_ablkcipher_ctx(
+                       crypto_ablkcipher_reqtfm(req));
+       struct omap_des_dev *dd = omap_des_find_dev(ctx);
+
+       if (!dd)
+               return -ENODEV;
 
-       return ret; /* return ret, which is enqueue return value */
+       return omap_des_crypt_dma_start(dd);
 }
 
 static void omap_des_done_task(unsigned long data)
@@ -683,18 +661,10 @@ static void omap_des_done_task(unsigned long data)
        }
 
        omap_des_finish_req(dd, 0);
-       omap_des_handle_queue(dd, NULL);
 
        pr_debug("exit\n");
 }
 
-static void omap_des_queue_task(unsigned long data)
-{
-       struct omap_des_dev *dd = (struct omap_des_dev *)data;
-
-       omap_des_handle_queue(dd, NULL);
-}
-
 static int omap_des_crypt(struct ablkcipher_request *req, unsigned long mode)
 {
        struct omap_des_ctx *ctx = crypto_ablkcipher_ctx(
@@ -999,8 +969,6 @@ static int omap_des_get_of(struct omap_des_dev *dd,
                return -EINVAL;
        }
 
-       dd->dma_out = -1; /* Dummy value that's unused */
-       dd->dma_in = -1; /* Dummy value that's unused */
        dd->pdata = match->data;
 
        return 0;
@@ -1016,33 +984,10 @@ static int omap_des_get_of(struct omap_des_dev *dd,
 static int omap_des_get_pdev(struct omap_des_dev *dd,
                struct platform_device *pdev)
 {
-       struct device *dev = &pdev->dev;
-       struct resource *r;
-       int err = 0;
-
-       /* Get the DMA out channel */
-       r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!r) {
-               dev_err(dev, "no DMA out resource info\n");
-               err = -ENODEV;
-               goto err;
-       }
-       dd->dma_out = r->start;
-
-       /* Get the DMA in channel */
-       r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-       if (!r) {
-               dev_err(dev, "no DMA in resource info\n");
-               err = -ENODEV;
-               goto err;
-       }
-       dd->dma_in = r->start;
-
        /* non-DT devices get pdata from pdev */
        dd->pdata = pdev->dev.platform_data;
 
-err:
-       return err;
+       return 0;
 }
 
 static int omap_des_probe(struct platform_device *pdev)
@@ -1062,9 +1007,6 @@ static int omap_des_probe(struct platform_device *pdev)
        dd->dev = dev;
        platform_set_drvdata(pdev, dd);
 
-       spin_lock_init(&dd->lock);
-       crypto_init_queue(&dd->queue, OMAP_DES_QUEUE_LENGTH);
-
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                dev_err(dev, "no MEM resource info\n");
@@ -1103,10 +1045,11 @@ static int omap_des_probe(struct platform_device *pdev)
                 (reg & dd->pdata->minor_mask) >> dd->pdata->minor_shift);
 
        tasklet_init(&dd->done_task, omap_des_done_task, (unsigned long)dd);
-       tasklet_init(&dd->queue_task, omap_des_queue_task, (unsigned long)dd);
 
        err = omap_des_dma_init(dd);
-       if (err && DES_REG_IRQ_STATUS(dd) && DES_REG_IRQ_ENABLE(dd)) {
+       if (err == -EPROBE_DEFER) {
+               goto err_irq;
+       } else if (err && DES_REG_IRQ_STATUS(dd) && DES_REG_IRQ_ENABLE(dd)) {
                dd->pio_only = 1;
 
                irq = platform_get_irq(pdev, 0);
@@ -1144,17 +1087,30 @@ static int omap_des_probe(struct platform_device *pdev)
                }
        }
 
+       /* Initialize des crypto engine */
+       dd->engine = crypto_engine_alloc_init(dev, 1);
+       if (!dd->engine)
+               goto err_algs;
+
+       dd->engine->prepare_request = omap_des_prepare_req;
+       dd->engine->crypt_one_request = omap_des_crypt_req;
+       err = crypto_engine_start(dd->engine);
+       if (err)
+               goto err_engine;
+
        return 0;
+
+err_engine:
+       crypto_engine_exit(dd->engine);
 err_algs:
        for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
                for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
                        crypto_unregister_alg(
                                        &dd->pdata->algs_info[i].algs_list[j]);
-       if (!dd->pio_only)
-               omap_des_dma_cleanup(dd);
+
+       omap_des_dma_cleanup(dd);
 err_irq:
        tasklet_kill(&dd->done_task);
-       tasklet_kill(&dd->queue_task);
 err_get:
        pm_runtime_disable(dev);
 err_res:
@@ -1182,7 +1138,6 @@ static int omap_des_remove(struct platform_device *pdev)
                                        &dd->pdata->algs_info[i].algs_list[j]);
 
        tasklet_kill(&dd->done_task);
-       tasklet_kill(&dd->queue_task);
        omap_des_dma_cleanup(dd);
        pm_runtime_disable(dd->dev);
        dd = NULL;
index 48adb2a0903e52a9567682430e5035b50487f6ae..6eefaa2fe58f990ce39ca1d7c7078a3d65eeafa6 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/scatterlist.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
-#include <linux/omap-dma.h>
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -219,7 +218,6 @@ struct omap_sham_dev {
        int                     irq;
        spinlock_t              lock;
        int                     err;
-       unsigned int            dma;
        struct dma_chan         *dma_lch;
        struct tasklet_struct   done_task;
        u8                      polling_mode;
@@ -1842,7 +1840,6 @@ static int omap_sham_get_res_of(struct omap_sham_dev *dd,
                goto err;
        }
 
-       dd->dma = -1; /* Dummy value that's unused */
        dd->pdata = match->data;
 
 err:
@@ -1884,15 +1881,6 @@ static int omap_sham_get_res_pdev(struct omap_sham_dev *dd,
                goto err;
        }
 
-       /* Get the DMA */
-       r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!r) {
-               dev_err(dev, "no DMA resource info\n");
-               err = -ENODEV;
-               goto err;
-       }
-       dd->dma = r->start;
-
        /* Only OMAP2/3 can be non-DT */
        dd->pdata = &omap_sham_pdata_omap2;
 
@@ -1946,9 +1934,12 @@ static int omap_sham_probe(struct platform_device *pdev)
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);
 
-       dd->dma_lch = dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
-                                                      &dd->dma, dev, "rx");
-       if (!dd->dma_lch) {
+       dd->dma_lch = dma_request_chan(dev, "rx");
+       if (IS_ERR(dd->dma_lch)) {
+               err = PTR_ERR(dd->dma_lch);
+               if (err == -EPROBE_DEFER)
+                       goto data_err;
+
                dd->polling_mode = 1;
                dev_dbg(dev, "using polling mode instead of dma\n");
        }
@@ -1995,7 +1986,7 @@ err_algs:
                                        &dd->pdata->algs_info[i].algs_list[j]);
 err_pm:
        pm_runtime_disable(dev);
-       if (dd->dma_lch)
+       if (dd->polling_mode)
                dma_release_channel(dd->dma_lch);
 data_err:
        dev_err(dev, "initialization failed.\n");
@@ -2021,7 +2012,7 @@ static int omap_sham_remove(struct platform_device *pdev)
        tasklet_kill(&dd->done_task);
        pm_runtime_disable(&pdev->dev);
 
-       if (dd->dma_lch)
+       if (!dd->polling_mode)
                dma_release_channel(dd->dma_lch);
 
        return 0;
index e13bd08ddd1e43a1fa14621feec1a16dd910d771..640c3fc870fdc1d911c79a0000b3c72c13efc8e4 100644 (file)
@@ -300,9 +300,7 @@ static void adf_remove(struct pci_dev *pdev)
                pr_err("QAT: Driver removal failed\n");
                return;
        }
-       if (adf_dev_stop(accel_dev))
-               dev_err(&GET_DEV(accel_dev), "Failed to stop QAT accel dev\n");
-
+       adf_dev_stop(accel_dev);
        adf_dev_shutdown(accel_dev);
        adf_disable_aer(accel_dev);
        adf_cleanup_accel(accel_dev);
index 1af321c2ce1acb80c85202a990dfc111d8941bce..d2d0ae445fd89c6cdb42cee71e5b216c82e6e6dc 100644 (file)
@@ -109,29 +109,6 @@ static void adf_vf_void_noop(struct adf_accel_dev *accel_dev)
 {
 }
 
-static int adf_vf2pf_init(struct adf_accel_dev *accel_dev)
-{
-       u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM |
-               (ADF_VF2PF_MSGTYPE_INIT << ADF_VF2PF_MSGTYPE_SHIFT));
-
-       if (adf_iov_putmsg(accel_dev, msg, 0)) {
-               dev_err(&GET_DEV(accel_dev),
-                       "Failed to send Init event to PF\n");
-               return -EFAULT;
-       }
-       return 0;
-}
-
-static void adf_vf2pf_shutdown(struct adf_accel_dev *accel_dev)
-{
-       u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM |
-           (ADF_VF2PF_MSGTYPE_SHUTDOWN << ADF_VF2PF_MSGTYPE_SHIFT));
-
-       if (adf_iov_putmsg(accel_dev, msg, 0))
-               dev_err(&GET_DEV(accel_dev),
-                       "Failed to send Shutdown event to PF\n");
-}
-
 void adf_init_hw_data_c3xxxiov(struct adf_hw_device_data *hw_data)
 {
        hw_data->dev_class = &c3xxxiov_class;
index 1ac4ae90e072cd4a298a378858a0280510f1dd4d..949d77b79fbe3d5cbf7ea92c7f2ae6dbfe43d97f 100644 (file)
@@ -238,6 +238,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (ret)
                goto out_err_free_reg;
 
+       set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status);
+
        ret = adf_dev_init(accel_dev);
        if (ret)
                goto out_err_dev_shutdown;
@@ -270,9 +272,7 @@ static void adf_remove(struct pci_dev *pdev)
                pr_err("QAT: Driver removal failed\n");
                return;
        }
-       if (adf_dev_stop(accel_dev))
-               dev_err(&GET_DEV(accel_dev), "Failed to stop QAT accel dev\n");
-
+       adf_dev_stop(accel_dev);
        adf_dev_shutdown(accel_dev);
        adf_cleanup_accel(accel_dev);
        adf_cleanup_pci_dev(accel_dev);
index 512c56509718007f64b2c13c12d27c00e051d1bb..bc5cbc193aae5c6167559ea3d2b9975acc7e6a5a 100644 (file)
@@ -300,9 +300,7 @@ static void adf_remove(struct pci_dev *pdev)
                pr_err("QAT: Driver removal failed\n");
                return;
        }
-       if (adf_dev_stop(accel_dev))
-               dev_err(&GET_DEV(accel_dev), "Failed to stop QAT accel dev\n");
-
+       adf_dev_stop(accel_dev);
        adf_dev_shutdown(accel_dev);
        adf_disable_aer(accel_dev);
        adf_cleanup_accel(accel_dev);
index baf4b509c892ac00669501fe2f1c0adb273a9794..38e4bc04f407bead0d604ff8930205bcee0b19a1 100644 (file)
@@ -109,29 +109,6 @@ static void adf_vf_void_noop(struct adf_accel_dev *accel_dev)
 {
 }
 
-static int adf_vf2pf_init(struct adf_accel_dev *accel_dev)
-{
-       u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM |
-               (ADF_VF2PF_MSGTYPE_INIT << ADF_VF2PF_MSGTYPE_SHIFT));
-
-       if (adf_iov_putmsg(accel_dev, msg, 0)) {
-               dev_err(&GET_DEV(accel_dev),
-                       "Failed to send Init event to PF\n");
-               return -EFAULT;
-       }
-       return 0;
-}
-
-static void adf_vf2pf_shutdown(struct adf_accel_dev *accel_dev)
-{
-       u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM |
-           (ADF_VF2PF_MSGTYPE_SHUTDOWN << ADF_VF2PF_MSGTYPE_SHIFT));
-
-       if (adf_iov_putmsg(accel_dev, msg, 0))
-               dev_err(&GET_DEV(accel_dev),
-                       "Failed to send Shutdown event to PF\n");
-}
-
 void adf_init_hw_data_c62xiov(struct adf_hw_device_data *hw_data)
 {
        hw_data->dev_class = &c62xiov_class;
index d2e4b928f3bee28af8873582fa71c56fa6f31460..7540ce13b0d067dd2d6b27bb53bf23e4e50f334f 100644 (file)
@@ -238,6 +238,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (ret)
                goto out_err_free_reg;
 
+       set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status);
+
        ret = adf_dev_init(accel_dev);
        if (ret)
                goto out_err_dev_shutdown;
@@ -270,9 +272,7 @@ static void adf_remove(struct pci_dev *pdev)
                pr_err("QAT: Driver removal failed\n");
                return;
        }
-       if (adf_dev_stop(accel_dev))
-               dev_err(&GET_DEV(accel_dev), "Failed to stop QAT accel dev\n");
-
+       adf_dev_stop(accel_dev);
        adf_dev_shutdown(accel_dev);
        adf_cleanup_accel(accel_dev);
        adf_cleanup_pci_dev(accel_dev);
index 29c7c53d2845673caf6a68e52380368ad4ecd602..6d74b91f2152807a0f65470dd799aa5080a3c111 100644 (file)
@@ -9,7 +9,6 @@ clean-files += qat_rsaprivkey-asn1.c qat_rsaprivkey-asn1.h
 obj-$(CONFIG_CRYPTO_DEV_QAT) += intel_qat.o
 intel_qat-objs := adf_cfg.o \
        adf_isr.o \
-       adf_vf_isr.o \
        adf_ctl_drv.o \
        adf_dev_mgr.o \
        adf_init.o \
@@ -27,4 +26,5 @@ intel_qat-objs := adf_cfg.o \
        qat_hal.o
 
 intel_qat-$(CONFIG_DEBUG_FS) += adf_transport_debug.o
-intel_qat-$(CONFIG_PCI_IOV) += adf_sriov.o adf_pf2vf_msg.o
+intel_qat-$(CONFIG_PCI_IOV) += adf_sriov.o adf_pf2vf_msg.o \
+                              adf_vf2pf_msg.o adf_vf_isr.o
index eb557f69e367efd8a86bc1770bd5ae9c230feac1..ce7c4626c983b66a7da42b24a7f136f7ebe6353d 100644 (file)
@@ -61,7 +61,7 @@
 #define ADF_DH895XCC_MAILBOX_STRIDE 0x1000
 #define ADF_ADMINMSG_LEN 32
 
-static const u8 const_tab[1024] = {
+static const u8 const_tab[1024] __aligned(1024) = {
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
index 13575111382c47d10ef55ab87c25a7829b8b42b4..7632ed0f25c55c32bbd707a5a0170e58971f1aea 100644 (file)
 #define ADF_RING_DC_SIZE "NumConcurrentRequests"
 #define ADF_RING_ASYM_TX "RingAsymTx"
 #define ADF_RING_SYM_TX "RingSymTx"
-#define ADF_RING_RND_TX "RingNrbgTx"
 #define ADF_RING_ASYM_RX "RingAsymRx"
 #define ADF_RING_SYM_RX "RingSymRx"
-#define ADF_RING_RND_RX "RingNrbgRx"
 #define ADF_RING_DC_TX "RingTx"
 #define ADF_RING_DC_RX "RingRx"
 #define ADF_ETRMGR_BANK "Bank"
index 976b01e58afbfd7f6690b47108232540aac0ad6e..75faa39bc8d04f14b915fe956246008bcf110c4a 100644 (file)
@@ -67,7 +67,7 @@
 #define ADF_STATUS_AE_INITIALISED 4
 #define ADF_STATUS_AE_UCODE_LOADED 5
 #define ADF_STATUS_AE_STARTED 6
-#define ADF_STATUS_ORPHAN_TH_RUNNING 7
+#define ADF_STATUS_PF_RUNNING 7
 #define ADF_STATUS_IRQ_ALLOCATED 8
 
 enum adf_dev_reset_mode {
@@ -103,7 +103,7 @@ int adf_service_unregister(struct service_hndl *service);
 
 int adf_dev_init(struct adf_accel_dev *accel_dev);
 int adf_dev_start(struct adf_accel_dev *accel_dev);
-int adf_dev_stop(struct adf_accel_dev *accel_dev);
+void adf_dev_stop(struct adf_accel_dev *accel_dev);
 void adf_dev_shutdown(struct adf_accel_dev *accel_dev);
 
 int adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr);
@@ -236,8 +236,13 @@ void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev,
                                 uint32_t vf_mask);
 void adf_enable_pf2vf_interrupts(struct adf_accel_dev *accel_dev);
 void adf_disable_pf2vf_interrupts(struct adf_accel_dev *accel_dev);
+
+int adf_vf2pf_init(struct adf_accel_dev *accel_dev);
+void adf_vf2pf_shutdown(struct adf_accel_dev *accel_dev);
 int adf_init_pf_wq(void);
 void adf_exit_pf_wq(void);
+int adf_init_vf_wq(void);
+void adf_exit_vf_wq(void);
 #else
 static inline int adf_sriov_configure(struct pci_dev *pdev, int numvfs)
 {
@@ -256,6 +261,15 @@ static inline void adf_disable_pf2vf_interrupts(struct adf_accel_dev *accel_dev)
 {
 }
 
+static inline int adf_vf2pf_init(struct adf_accel_dev *accel_dev)
+{
+       return 0;
+}
+
+static inline void adf_vf2pf_shutdown(struct adf_accel_dev *accel_dev)
+{
+}
+
 static inline int adf_init_pf_wq(void)
 {
        return 0;
@@ -264,5 +278,15 @@ static inline int adf_init_pf_wq(void)
 static inline void adf_exit_pf_wq(void)
 {
 }
+
+static inline int adf_init_vf_wq(void)
+{
+       return 0;
+}
+
+static inline void adf_exit_vf_wq(void)
+{
+}
+
 #endif
 #endif
index 3c3f948290ca057c29edc1297f731abe3b9ebc63..abc7a7f64d645237b66376cbe0c8f1b8301e3be6 100644 (file)
@@ -270,26 +270,33 @@ static int adf_ctl_is_device_in_use(int id)
        return 0;
 }
 
-static int adf_ctl_stop_devices(uint32_t id)
+static void adf_ctl_stop_devices(uint32_t id)
 {
        struct adf_accel_dev *accel_dev;
-       int ret = 0;
 
-       list_for_each_entry_reverse(accel_dev, adf_devmgr_get_head(), list) {
+       list_for_each_entry(accel_dev, adf_devmgr_get_head(), list) {
                if (id == accel_dev->accel_id || id == ADF_CFG_ALL_DEVICES) {
                        if (!adf_dev_started(accel_dev))
                                continue;
 
-                       if (adf_dev_stop(accel_dev)) {
-                               dev_err(&GET_DEV(accel_dev),
-                                       "Failed to stop qat_dev%d\n", id);
-                               ret = -EFAULT;
-                       } else {
-                               adf_dev_shutdown(accel_dev);
-                       }
+                       /* First stop all VFs */
+                       if (!accel_dev->is_vf)
+                               continue;
+
+                       adf_dev_stop(accel_dev);
+                       adf_dev_shutdown(accel_dev);
+               }
+       }
+
+       list_for_each_entry(accel_dev, adf_devmgr_get_head(), list) {
+               if (id == accel_dev->accel_id || id == ADF_CFG_ALL_DEVICES) {
+                       if (!adf_dev_started(accel_dev))
+                               continue;
+
+                       adf_dev_stop(accel_dev);
+                       adf_dev_shutdown(accel_dev);
                }
        }
-       return ret;
 }
 
 static int adf_ctl_ioctl_dev_stop(struct file *fp, unsigned int cmd,
@@ -318,9 +325,8 @@ static int adf_ctl_ioctl_dev_stop(struct file *fp, unsigned int cmd,
                pr_info("QAT: Stopping acceleration device qat_dev%d.\n",
                        ctl_data->device_id);
 
-       ret = adf_ctl_stop_devices(ctl_data->device_id);
-       if (ret)
-               pr_err("QAT: failed to stop device.\n");
+       adf_ctl_stop_devices(ctl_data->device_id);
+
 out:
        kfree(ctl_data);
        return ret;
@@ -465,12 +471,17 @@ static int __init adf_register_ctl_device_driver(void)
        if (adf_init_pf_wq())
                goto err_pf_wq;
 
+       if (adf_init_vf_wq())
+               goto err_vf_wq;
+
        if (qat_crypto_register())
                goto err_crypto_register;
 
        return 0;
 
 err_crypto_register:
+       adf_exit_vf_wq();
+err_vf_wq:
        adf_exit_pf_wq();
 err_pf_wq:
        adf_exit_aer();
@@ -485,6 +496,7 @@ static void __exit adf_unregister_ctl_device_driver(void)
 {
        adf_chr_drv_destroy();
        adf_exit_aer();
+       adf_exit_vf_wq();
        adf_exit_pf_wq();
        qat_crypto_unregister();
        adf_clean_vf_map(false);
index ef5575e4a215a64c4292cd23c3b8bf2d501b4e83..888c6675e7e548ab51ada1db95f73c15d3e490aa 100644 (file)
@@ -236,9 +236,9 @@ EXPORT_SYMBOL_GPL(adf_dev_start);
  * is shuting down.
  * To be used by QAT device specific drivers.
  *
- * Return: 0 on success, error code otherwise.
+ * Return: void
  */
-int adf_dev_stop(struct adf_accel_dev *accel_dev)
+void adf_dev_stop(struct adf_accel_dev *accel_dev)
 {
        struct service_hndl *service;
        struct list_head *list_itr;
@@ -246,9 +246,9 @@ int adf_dev_stop(struct adf_accel_dev *accel_dev)
        int ret;
 
        if (!adf_dev_started(accel_dev) &&
-           !test_bit(ADF_STATUS_STARTING, &accel_dev->status)) {
-               return 0;
-       }
+           !test_bit(ADF_STATUS_STARTING, &accel_dev->status))
+               return;
+
        clear_bit(ADF_STATUS_STARTING, &accel_dev->status);
        clear_bit(ADF_STATUS_STARTED, &accel_dev->status);
 
@@ -279,8 +279,6 @@ int adf_dev_stop(struct adf_accel_dev *accel_dev)
                else
                        clear_bit(ADF_STATUS_AE_STARTED, &accel_dev->status);
        }
-
-       return 0;
 }
 EXPORT_SYMBOL_GPL(adf_dev_stop);
 
@@ -329,6 +327,8 @@ void adf_dev_shutdown(struct adf_accel_dev *accel_dev)
                        clear_bit(accel_dev->accel_id, &service->init_status);
        }
 
+       hw_data->disable_iov(accel_dev);
+
        if (test_bit(ADF_STATUS_IRQ_ALLOCATED, &accel_dev->status)) {
                hw_data->free_irq(accel_dev);
                clear_bit(ADF_STATUS_IRQ_ALLOCATED, &accel_dev->status);
@@ -344,7 +344,6 @@ void adf_dev_shutdown(struct adf_accel_dev *accel_dev)
        if (hw_data->exit_admin_comms)
                hw_data->exit_admin_comms(accel_dev);
 
-       hw_data->disable_iov(accel_dev);
        adf_cleanup_etr_data(accel_dev);
        adf_dev_restore(accel_dev);
 }
index b81f79acc4ea71a68e83f29c16d93a74cf30bcbe..06d49017a52b7ddeb8737833293e2295b84637df 100644 (file)
@@ -302,7 +302,7 @@ static void adf_cleanup_bh(struct adf_accel_dev *accel_dev)
 }
 
 /**
- * adf_vf_isr_resource_free() - Free IRQ for acceleration device
+ * adf_isr_resource_free() - Free IRQ for acceleration device
  * @accel_dev:  Pointer to acceleration device.
  *
  * Function frees interrupts for acceleration device.
@@ -317,7 +317,7 @@ void adf_isr_resource_free(struct adf_accel_dev *accel_dev)
 EXPORT_SYMBOL_GPL(adf_isr_resource_free);
 
 /**
- * adf_vf_isr_resource_alloc() - Allocate IRQ for acceleration device
+ * adf_isr_resource_alloc() - Allocate IRQ for acceleration device
  * @accel_dev:  Pointer to acceleration device.
  *
  * Function allocates interrupts for acceleration device.
index 38a0415e767da3dea08e673eab1b402d0a978a71..4a526e2f1d7ff926fe57ea3f3ff36a02bd952de3 100644 (file)
@@ -249,13 +249,7 @@ int adf_sriov_configure(struct pci_dev *pdev, int numvfs)
                        return -EBUSY;
                }
 
-               if (adf_dev_stop(accel_dev)) {
-                       dev_err(&GET_DEV(accel_dev),
-                               "Failed to stop qat_dev%d\n",
-                               accel_dev->accel_id);
-                       return -EFAULT;
-               }
-
+               adf_dev_stop(accel_dev);
                adf_dev_shutdown(accel_dev);
        }
 
diff --git a/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c b/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c
new file mode 100644 (file)
index 0000000..cd5f37d
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+  This file is provided under a dual BSD/GPLv2 license.  When using or
+  redistributing this file, you may do so under either license.
+
+  GPL LICENSE SUMMARY
+  Copyright(c) 2015 Intel Corporation.
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  Contact Information:
+  qat-linux@intel.com
+
+  BSD LICENSE
+  Copyright(c) 2015 Intel Corporation.
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "adf_accel_devices.h"
+#include "adf_common_drv.h"
+#include "adf_pf2vf_msg.h"
+
+/**
+ * adf_vf2pf_init() - send init msg to PF
+ * @accel_dev:  Pointer to acceleration VF device.
+ *
+ * Function sends an init messge from the VF to a PF
+ *
+ * Return: 0 on success, error code otherwise.
+ */
+int adf_vf2pf_init(struct adf_accel_dev *accel_dev)
+{
+       u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM |
+               (ADF_VF2PF_MSGTYPE_INIT << ADF_VF2PF_MSGTYPE_SHIFT));
+
+       if (adf_iov_putmsg(accel_dev, msg, 0)) {
+               dev_err(&GET_DEV(accel_dev),
+                       "Failed to send Init event to PF\n");
+               return -EFAULT;
+       }
+       set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(adf_vf2pf_init);
+
+/**
+ * adf_vf2pf_shutdown() - send shutdown msg to PF
+ * @accel_dev:  Pointer to acceleration VF device.
+ *
+ * Function sends a shutdown messge from the VF to a PF
+ *
+ * Return: void
+ */
+void adf_vf2pf_shutdown(struct adf_accel_dev *accel_dev)
+{
+       u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM |
+           (ADF_VF2PF_MSGTYPE_SHUTDOWN << ADF_VF2PF_MSGTYPE_SHIFT));
+
+       if (test_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status))
+               if (adf_iov_putmsg(accel_dev, msg, 0))
+                       dev_err(&GET_DEV(accel_dev),
+                               "Failed to send Shutdown event to PF\n");
+}
+EXPORT_SYMBOL_GPL(adf_vf2pf_shutdown);
index 09427b3d4d55e6765433c54280d3a094868946bb..aa689cabedb4b598fc9517b1f3b07e07b823447c 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
+#include <linux/workqueue.h>
 #include "adf_accel_devices.h"
 #include "adf_common_drv.h"
 #include "adf_cfg.h"
 #define ADF_VINTSOU_BUN                BIT(0)
 #define ADF_VINTSOU_PF2VF      BIT(1)
 
+static struct workqueue_struct *adf_vf_stop_wq;
+
+struct adf_vf_stop_data {
+       struct adf_accel_dev *accel_dev;
+       struct work_struct work;
+};
+
 static int adf_enable_msi(struct adf_accel_dev *accel_dev)
 {
        struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev;
@@ -90,6 +98,20 @@ static void adf_disable_msi(struct adf_accel_dev *accel_dev)
        pci_disable_msi(pdev);
 }
 
+static void adf_dev_stop_async(struct work_struct *work)
+{
+       struct adf_vf_stop_data *stop_data =
+               container_of(work, struct adf_vf_stop_data, work);
+       struct adf_accel_dev *accel_dev = stop_data->accel_dev;
+
+       adf_dev_stop(accel_dev);
+       adf_dev_shutdown(accel_dev);
+
+       /* Re-enable PF2VF interrupts */
+       adf_enable_pf2vf_interrupts(accel_dev);
+       kfree(stop_data);
+}
+
 static void adf_pf2vf_bh_handler(void *data)
 {
        struct adf_accel_dev *accel_dev = data;
@@ -107,11 +129,29 @@ static void adf_pf2vf_bh_handler(void *data)
                goto err;
 
        switch ((msg & ADF_PF2VF_MSGTYPE_MASK) >> ADF_PF2VF_MSGTYPE_SHIFT) {
-       case ADF_PF2VF_MSGTYPE_RESTARTING:
+       case ADF_PF2VF_MSGTYPE_RESTARTING: {
+               struct adf_vf_stop_data *stop_data;
+
                dev_dbg(&GET_DEV(accel_dev),
                        "Restarting msg received from PF 0x%x\n", msg);
-               adf_dev_stop(accel_dev);
-               break;
+
+               clear_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status);
+
+               stop_data = kzalloc(sizeof(*stop_data), GFP_ATOMIC);
+               if (!stop_data) {
+                       dev_err(&GET_DEV(accel_dev),
+                               "Couldn't schedule stop for vf_%d\n",
+                               accel_dev->accel_id);
+                       return;
+               }
+               stop_data->accel_dev = accel_dev;
+               INIT_WORK(&stop_data->work, adf_dev_stop_async);
+               queue_work(adf_vf_stop_wq, &stop_data->work);
+               /* To ack, clear the PF2VFINT bit */
+               msg &= ~BIT(0);
+               ADF_CSR_WR(pmisc_bar_addr, hw_data->get_pf2vf_offset(0), msg);
+               return;
+       }
        case ADF_PF2VF_MSGTYPE_VERSION_RESP:
                dev_dbg(&GET_DEV(accel_dev),
                        "Version resp received from PF 0x%x\n", msg);
@@ -278,3 +318,18 @@ err_out:
        return -EFAULT;
 }
 EXPORT_SYMBOL_GPL(adf_vf_isr_resource_alloc);
+
+int __init adf_init_vf_wq(void)
+{
+       adf_vf_stop_wq = create_workqueue("adf_vf_stop_wq");
+
+       return !adf_vf_stop_wq ? -EFAULT : 0;
+}
+
+void adf_exit_vf_wq(void)
+{
+       if (adf_vf_stop_wq)
+               destroy_workqueue(adf_vf_stop_wq);
+
+       adf_vf_stop_wq = NULL;
+}
index e5c0727d48767fb638cb52541601c0fd55c0471a..05f49d4f94b2701f5a1adf9d1eb7c349a6372632 100644 (file)
@@ -593,7 +593,7 @@ int qat_rsa_get_d(void *context, size_t hdrlen, unsigned char tag,
 
        ret = -ENOMEM;
        ctx->d = dma_zalloc_coherent(dev, ctx->key_sz, &ctx->dma_d, GFP_KERNEL);
-       if (!ctx->n)
+       if (!ctx->d)
                goto err;
 
        memcpy(ctx->d + (ctx->key_sz - vlen), ptr, vlen);
@@ -711,7 +711,7 @@ static void qat_rsa_exit_tfm(struct crypto_akcipher *tfm)
        }
        qat_crypto_put_instance(ctx->inst);
        ctx->n = NULL;
-       ctx->d = NULL;
+       ctx->e = NULL;
        ctx->d = NULL;
 }
 
index a8c4b92a7cbd6fadd300bf3f4fd3f17390e6834c..4d2de28384513d8c56c521d30ae17f34002d95ae 100644 (file)
@@ -302,9 +302,7 @@ static void adf_remove(struct pci_dev *pdev)
                pr_err("QAT: Driver removal failed\n");
                return;
        }
-       if (adf_dev_stop(accel_dev))
-               dev_err(&GET_DEV(accel_dev), "Failed to stop QAT accel dev\n");
-
+       adf_dev_stop(accel_dev);
        adf_dev_shutdown(accel_dev);
        adf_disable_aer(accel_dev);
        adf_cleanup_accel(accel_dev);
index dc04ab68d24dd9155645d74b0793e440e563aba0..a3b4dd8099a7b09d56de7fdbdbe8bfa7aadcce4f 100644 (file)
@@ -109,29 +109,6 @@ static void adf_vf_void_noop(struct adf_accel_dev *accel_dev)
 {
 }
 
-static int adf_vf2pf_init(struct adf_accel_dev *accel_dev)
-{
-       u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM |
-               (ADF_VF2PF_MSGTYPE_INIT << ADF_VF2PF_MSGTYPE_SHIFT));
-
-       if (adf_iov_putmsg(accel_dev, msg, 0)) {
-               dev_err(&GET_DEV(accel_dev),
-                       "Failed to send Init event to PF\n");
-               return -EFAULT;
-       }
-       return 0;
-}
-
-static void adf_vf2pf_shutdown(struct adf_accel_dev *accel_dev)
-{
-       u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM |
-           (ADF_VF2PF_MSGTYPE_SHUTDOWN << ADF_VF2PF_MSGTYPE_SHIFT));
-
-       if (adf_iov_putmsg(accel_dev, msg, 0))
-               dev_err(&GET_DEV(accel_dev),
-                       "Failed to send Shutdown event to PF\n");
-}
-
 void adf_init_hw_data_dh895xcciov(struct adf_hw_device_data *hw_data)
 {
        hw_data->dev_class = &dh895xcciov_class;
index f8cc4bf0a50cd3c9240565ec36f66fe202315c8e..60df98632fa2dc2d40f9e6e400f5b129cf300ae1 100644 (file)
@@ -238,6 +238,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (ret)
                goto out_err_free_reg;
 
+       set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status);
+
        ret = adf_dev_init(accel_dev);
        if (ret)
                goto out_err_dev_shutdown;
@@ -270,9 +272,7 @@ static void adf_remove(struct pci_dev *pdev)
                pr_err("QAT: Driver removal failed\n");
                return;
        }
-       if (adf_dev_stop(accel_dev))
-               dev_err(&GET_DEV(accel_dev), "Failed to stop QAT accel dev\n");
-
+       adf_dev_stop(accel_dev);
        adf_dev_shutdown(accel_dev);
        adf_cleanup_accel(accel_dev);
        adf_cleanup_pci_dev(accel_dev);
index 5f161a9777e3f32f6e37aa67f607efc9d234b445..2b3a0cfe3331577b2fb12733bafea71bbc59375e 100644 (file)
  *
  */
 
-#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/crypto.h>
+#include <linux/dma-mapping.h>
 #include <linux/err.h>
-#include <linux/module.h>
-#include <linux/init.h>
 #include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
-#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/scatterlist.h>
-#include <linux/dma-mapping.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/crypto.h>
-#include <linux/interrupt.h>
 
-#include <crypto/algapi.h>
-#include <crypto/aes.h>
 #include <crypto/ctr.h>
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <crypto/scatterwalk.h>
 
 #define _SBF(s, v)                      ((v) << (s))
-#define _BIT(b)                         _SBF(b, 1)
 
 /* Feed control registers */
 #define SSS_REG_FCINTSTAT               0x0000
-#define SSS_FCINTSTAT_BRDMAINT          _BIT(3)
-#define SSS_FCINTSTAT_BTDMAINT          _BIT(2)
-#define SSS_FCINTSTAT_HRDMAINT          _BIT(1)
-#define SSS_FCINTSTAT_PKDMAINT          _BIT(0)
+#define SSS_FCINTSTAT_BRDMAINT          BIT(3)
+#define SSS_FCINTSTAT_BTDMAINT          BIT(2)
+#define SSS_FCINTSTAT_HRDMAINT          BIT(1)
+#define SSS_FCINTSTAT_PKDMAINT          BIT(0)
 
 #define SSS_REG_FCINTENSET              0x0004
-#define SSS_FCINTENSET_BRDMAINTENSET    _BIT(3)
-#define SSS_FCINTENSET_BTDMAINTENSET    _BIT(2)
-#define SSS_FCINTENSET_HRDMAINTENSET    _BIT(1)
-#define SSS_FCINTENSET_PKDMAINTENSET    _BIT(0)
+#define SSS_FCINTENSET_BRDMAINTENSET    BIT(3)
+#define SSS_FCINTENSET_BTDMAINTENSET    BIT(2)
+#define SSS_FCINTENSET_HRDMAINTENSET    BIT(1)
+#define SSS_FCINTENSET_PKDMAINTENSET    BIT(0)
 
 #define SSS_REG_FCINTENCLR              0x0008
-#define SSS_FCINTENCLR_BRDMAINTENCLR    _BIT(3)
-#define SSS_FCINTENCLR_BTDMAINTENCLR    _BIT(2)
-#define SSS_FCINTENCLR_HRDMAINTENCLR    _BIT(1)
-#define SSS_FCINTENCLR_PKDMAINTENCLR    _BIT(0)
+#define SSS_FCINTENCLR_BRDMAINTENCLR    BIT(3)
+#define SSS_FCINTENCLR_BTDMAINTENCLR    BIT(2)
+#define SSS_FCINTENCLR_HRDMAINTENCLR    BIT(1)
+#define SSS_FCINTENCLR_PKDMAINTENCLR    BIT(0)
 
 #define SSS_REG_FCINTPEND               0x000C
-#define SSS_FCINTPEND_BRDMAINTP         _BIT(3)
-#define SSS_FCINTPEND_BTDMAINTP         _BIT(2)
-#define SSS_FCINTPEND_HRDMAINTP         _BIT(1)
-#define SSS_FCINTPEND_PKDMAINTP         _BIT(0)
+#define SSS_FCINTPEND_BRDMAINTP         BIT(3)
+#define SSS_FCINTPEND_BTDMAINTP         BIT(2)
+#define SSS_FCINTPEND_HRDMAINTP         BIT(1)
+#define SSS_FCINTPEND_PKDMAINTP         BIT(0)
 
 #define SSS_REG_FCFIFOSTAT              0x0010
-#define SSS_FCFIFOSTAT_BRFIFOFUL        _BIT(7)
-#define SSS_FCFIFOSTAT_BRFIFOEMP        _BIT(6)
-#define SSS_FCFIFOSTAT_BTFIFOFUL        _BIT(5)
-#define SSS_FCFIFOSTAT_BTFIFOEMP        _BIT(4)
-#define SSS_FCFIFOSTAT_HRFIFOFUL        _BIT(3)
-#define SSS_FCFIFOSTAT_HRFIFOEMP        _BIT(2)
-#define SSS_FCFIFOSTAT_PKFIFOFUL        _BIT(1)
-#define SSS_FCFIFOSTAT_PKFIFOEMP        _BIT(0)
+#define SSS_FCFIFOSTAT_BRFIFOFUL        BIT(7)
+#define SSS_FCFIFOSTAT_BRFIFOEMP        BIT(6)
+#define SSS_FCFIFOSTAT_BTFIFOFUL        BIT(5)
+#define SSS_FCFIFOSTAT_BTFIFOEMP        BIT(4)
+#define SSS_FCFIFOSTAT_HRFIFOFUL        BIT(3)
+#define SSS_FCFIFOSTAT_HRFIFOEMP        BIT(2)
+#define SSS_FCFIFOSTAT_PKFIFOFUL        BIT(1)
+#define SSS_FCFIFOSTAT_PKFIFOEMP        BIT(0)
 
 #define SSS_REG_FCFIFOCTRL              0x0014
-#define SSS_FCFIFOCTRL_DESSEL           _BIT(2)
+#define SSS_FCFIFOCTRL_DESSEL           BIT(2)
 #define SSS_HASHIN_INDEPENDENT          _SBF(0, 0x00)
 #define SSS_HASHIN_CIPHER_INPUT         _SBF(0, 0x01)
 #define SSS_HASHIN_CIPHER_OUTPUT        _SBF(0, 0x02)
 #define SSS_REG_FCBRDMAS                0x0020
 #define SSS_REG_FCBRDMAL                0x0024
 #define SSS_REG_FCBRDMAC                0x0028
-#define SSS_FCBRDMAC_BYTESWAP           _BIT(1)
-#define SSS_FCBRDMAC_FLUSH              _BIT(0)
+#define SSS_FCBRDMAC_BYTESWAP           BIT(1)
+#define SSS_FCBRDMAC_FLUSH              BIT(0)
 
 #define SSS_REG_FCBTDMAS                0x0030
 #define SSS_REG_FCBTDMAL                0x0034
 #define SSS_REG_FCBTDMAC                0x0038
-#define SSS_FCBTDMAC_BYTESWAP           _BIT(1)
-#define SSS_FCBTDMAC_FLUSH              _BIT(0)
+#define SSS_FCBTDMAC_BYTESWAP           BIT(1)
+#define SSS_FCBTDMAC_FLUSH              BIT(0)
 
 #define SSS_REG_FCHRDMAS                0x0040
 #define SSS_REG_FCHRDMAL                0x0044
 #define SSS_REG_FCHRDMAC                0x0048
-#define SSS_FCHRDMAC_BYTESWAP           _BIT(1)
-#define SSS_FCHRDMAC_FLUSH              _BIT(0)
+#define SSS_FCHRDMAC_BYTESWAP           BIT(1)
+#define SSS_FCHRDMAC_FLUSH              BIT(0)
 
 #define SSS_REG_FCPKDMAS                0x0050
 #define SSS_REG_FCPKDMAL                0x0054
 #define SSS_REG_FCPKDMAC                0x0058
-#define SSS_FCPKDMAC_BYTESWAP           _BIT(3)
-#define SSS_FCPKDMAC_DESCEND            _BIT(2)
-#define SSS_FCPKDMAC_TRANSMIT           _BIT(1)
-#define SSS_FCPKDMAC_FLUSH              _BIT(0)
+#define SSS_FCPKDMAC_BYTESWAP           BIT(3)
+#define SSS_FCPKDMAC_DESCEND            BIT(2)
+#define SSS_FCPKDMAC_TRANSMIT           BIT(1)
+#define SSS_FCPKDMAC_FLUSH              BIT(0)
 
 #define SSS_REG_FCPKDMAO                0x005C
 
 /* AES registers */
 #define SSS_REG_AES_CONTROL            0x00
-#define SSS_AES_BYTESWAP_DI             _BIT(11)
-#define SSS_AES_BYTESWAP_DO             _BIT(10)
-#define SSS_AES_BYTESWAP_IV             _BIT(9)
-#define SSS_AES_BYTESWAP_CNT            _BIT(8)
-#define SSS_AES_BYTESWAP_KEY            _BIT(7)
-#define SSS_AES_KEY_CHANGE_MODE         _BIT(6)
+#define SSS_AES_BYTESWAP_DI             BIT(11)
+#define SSS_AES_BYTESWAP_DO             BIT(10)
+#define SSS_AES_BYTESWAP_IV             BIT(9)
+#define SSS_AES_BYTESWAP_CNT            BIT(8)
+#define SSS_AES_BYTESWAP_KEY            BIT(7)
+#define SSS_AES_KEY_CHANGE_MODE         BIT(6)
 #define SSS_AES_KEY_SIZE_128            _SBF(4, 0x00)
 #define SSS_AES_KEY_SIZE_192            _SBF(4, 0x01)
 #define SSS_AES_KEY_SIZE_256            _SBF(4, 0x02)
-#define SSS_AES_FIFO_MODE               _BIT(3)
+#define SSS_AES_FIFO_MODE               BIT(3)
 #define SSS_AES_CHAIN_MODE_ECB          _SBF(1, 0x00)
 #define SSS_AES_CHAIN_MODE_CBC          _SBF(1, 0x01)
 #define SSS_AES_CHAIN_MODE_CTR          _SBF(1, 0x02)
-#define SSS_AES_MODE_DECRYPT            _BIT(0)
+#define SSS_AES_MODE_DECRYPT            BIT(0)
 
 #define SSS_REG_AES_STATUS             0x04
-#define SSS_AES_BUSY                    _BIT(2)
-#define SSS_AES_INPUT_READY             _BIT(1)
-#define SSS_AES_OUTPUT_READY            _BIT(0)
+#define SSS_AES_BUSY                    BIT(2)
+#define SSS_AES_INPUT_READY             BIT(1)
+#define SSS_AES_OUTPUT_READY            BIT(0)
 
 #define SSS_REG_AES_IN_DATA(s)         (0x10 + (s << 2))
 #define SSS_REG_AES_OUT_DATA(s)                (0x20 + (s << 2))
                                                SSS_AES_REG(dev, reg))
 
 /* HW engine modes */
-#define FLAGS_AES_DECRYPT               _BIT(0)
+#define FLAGS_AES_DECRYPT               BIT(0)
 #define FLAGS_AES_MODE_MASK             _SBF(1, 0x03)
 #define FLAGS_AES_CBC                   _SBF(1, 0x01)
 #define FLAGS_AES_CTR                   _SBF(1, 0x02)
 
 /**
  * struct samsung_aes_variant - platform specific SSS driver data
- * @has_hash_irq: true if SSS module uses hash interrupt, false otherwise
  * @aes_offset: AES register offset from SSS module's base.
  *
  * Specifies platform specific configuration of SSS module.
  * expansion of its usage.
  */
 struct samsung_aes_variant {
-       bool                        has_hash_irq;
        unsigned int                aes_offset;
 };
 
@@ -178,7 +175,6 @@ struct s5p_aes_dev {
        struct clk                 *clk;
        void __iomem               *ioaddr;
        void __iomem               *aes_ioaddr;
-       int                         irq_hash;
        int                         irq_fc;
 
        struct ablkcipher_request  *req;
@@ -186,6 +182,10 @@ struct s5p_aes_dev {
        struct scatterlist         *sg_src;
        struct scatterlist         *sg_dst;
 
+       /* In case of unaligned access: */
+       struct scatterlist         *sg_src_cpy;
+       struct scatterlist         *sg_dst_cpy;
+
        struct tasklet_struct       tasklet;
        struct crypto_queue         queue;
        bool                        busy;
@@ -197,12 +197,10 @@ struct s5p_aes_dev {
 static struct s5p_aes_dev *s5p_dev;
 
 static const struct samsung_aes_variant s5p_aes_data = {
-       .has_hash_irq   = true,
        .aes_offset     = 0x4000,
 };
 
 static const struct samsung_aes_variant exynos_aes_data = {
-       .has_hash_irq   = false,
        .aes_offset     = 0x200,
 };
 
@@ -245,8 +243,45 @@ static void s5p_set_dma_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg)
        SSS_WRITE(dev, FCBTDMAL, sg_dma_len(sg));
 }
 
+static void s5p_free_sg_cpy(struct s5p_aes_dev *dev, struct scatterlist **sg)
+{
+       int len;
+
+       if (!*sg)
+               return;
+
+       len = ALIGN(dev->req->nbytes, AES_BLOCK_SIZE);
+       free_pages((unsigned long)sg_virt(*sg), get_order(len));
+
+       kfree(*sg);
+       *sg = NULL;
+}
+
+static void s5p_sg_copy_buf(void *buf, struct scatterlist *sg,
+                           unsigned int nbytes, int out)
+{
+       struct scatter_walk walk;
+
+       if (!nbytes)
+               return;
+
+       scatterwalk_start(&walk, sg);
+       scatterwalk_copychunks(buf, &walk, nbytes, out);
+       scatterwalk_done(&walk, out, 0);
+}
+
 static void s5p_aes_complete(struct s5p_aes_dev *dev, int err)
 {
+       if (dev->sg_dst_cpy) {
+               dev_dbg(dev->dev,
+                       "Copying %d bytes of output data back to original place\n",
+                       dev->req->nbytes);
+               s5p_sg_copy_buf(sg_virt(dev->sg_dst_cpy), dev->req->dst,
+                               dev->req->nbytes, 1);
+       }
+       s5p_free_sg_cpy(dev, &dev->sg_src_cpy);
+       s5p_free_sg_cpy(dev, &dev->sg_dst_cpy);
+
        /* holding a lock outside */
        dev->req->base.complete(&dev->req->base, err);
        dev->busy = false;
@@ -262,15 +297,37 @@ static void s5p_unset_indata(struct s5p_aes_dev *dev)
        dma_unmap_sg(dev->dev, dev->sg_src, 1, DMA_TO_DEVICE);
 }
 
+static int s5p_make_sg_cpy(struct s5p_aes_dev *dev, struct scatterlist *src,
+                           struct scatterlist **dst)
+{
+       void *pages;
+       int len;
+
+       *dst = kmalloc(sizeof(**dst), GFP_ATOMIC);
+       if (!*dst)
+               return -ENOMEM;
+
+       len = ALIGN(dev->req->nbytes, AES_BLOCK_SIZE);
+       pages = (void *)__get_free_pages(GFP_ATOMIC, get_order(len));
+       if (!pages) {
+               kfree(*dst);
+               *dst = NULL;
+               return -ENOMEM;
+       }
+
+       s5p_sg_copy_buf(pages, src, dev->req->nbytes, 0);
+
+       sg_init_table(*dst, 1);
+       sg_set_buf(*dst, pages, len);
+
+       return 0;
+}
+
 static int s5p_set_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg)
 {
        int err;
 
-       if (!IS_ALIGNED(sg_dma_len(sg), AES_BLOCK_SIZE)) {
-               err = -EINVAL;
-               goto exit;
-       }
-       if (!sg_dma_len(sg)) {
+       if (!sg->length) {
                err = -EINVAL;
                goto exit;
        }
@@ -284,7 +341,7 @@ static int s5p_set_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg)
        dev->sg_dst = sg;
        err = 0;
 
- exit:
+exit:
        return err;
 }
 
@@ -292,11 +349,7 @@ static int s5p_set_indata(struct s5p_aes_dev *dev, struct scatterlist *sg)
 {
        int err;
 
-       if (!IS_ALIGNED(sg_dma_len(sg), AES_BLOCK_SIZE)) {
-               err = -EINVAL;
-               goto exit;
-       }
-       if (!sg_dma_len(sg)) {
+       if (!sg->length) {
                err = -EINVAL;
                goto exit;
        }
@@ -310,47 +363,59 @@ static int s5p_set_indata(struct s5p_aes_dev *dev, struct scatterlist *sg)
        dev->sg_src = sg;
        err = 0;
 
- exit:
+exit:
        return err;
 }
 
-static void s5p_aes_tx(struct s5p_aes_dev *dev)
+/*
+ * Returns true if new transmitting (output) data is ready and its
+ * address+length have to be written to device (by calling
+ * s5p_set_dma_outdata()). False otherwise.
+ */
+static bool s5p_aes_tx(struct s5p_aes_dev *dev)
 {
        int err = 0;
+       bool ret = false;
 
        s5p_unset_outdata(dev);
 
        if (!sg_is_last(dev->sg_dst)) {
                err = s5p_set_outdata(dev, sg_next(dev->sg_dst));
-               if (err) {
+               if (err)
                        s5p_aes_complete(dev, err);
-                       return;
-               }
-
-               s5p_set_dma_outdata(dev, dev->sg_dst);
+               else
+                       ret = true;
        } else {
                s5p_aes_complete(dev, err);
 
                dev->busy = true;
                tasklet_schedule(&dev->tasklet);
        }
+
+       return ret;
 }
 
-static void s5p_aes_rx(struct s5p_aes_dev *dev)
+/*
+ * Returns true if new receiving (input) data is ready and its
+ * address+length have to be written to device (by calling
+ * s5p_set_dma_indata()). False otherwise.
+ */
+static bool s5p_aes_rx(struct s5p_aes_dev *dev)
 {
        int err;
+       bool ret = false;
 
        s5p_unset_indata(dev);
 
        if (!sg_is_last(dev->sg_src)) {
                err = s5p_set_indata(dev, sg_next(dev->sg_src));
-               if (err) {
+               if (err)
                        s5p_aes_complete(dev, err);
-                       return;
-               }
-
-               s5p_set_dma_indata(dev, dev->sg_src);
+               else
+                       ret = true;
        }
+
+       return ret;
 }
 
 static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id)
@@ -359,18 +424,29 @@ static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id)
        struct s5p_aes_dev     *dev  = platform_get_drvdata(pdev);
        uint32_t                status;
        unsigned long           flags;
+       bool                    set_dma_tx = false;
+       bool                    set_dma_rx = false;
 
        spin_lock_irqsave(&dev->lock, flags);
 
-       if (irq == dev->irq_fc) {
-               status = SSS_READ(dev, FCINTSTAT);
-               if (status & SSS_FCINTSTAT_BRDMAINT)
-                       s5p_aes_rx(dev);
-               if (status & SSS_FCINTSTAT_BTDMAINT)
-                       s5p_aes_tx(dev);
-
-               SSS_WRITE(dev, FCINTPEND, status);
-       }
+       status = SSS_READ(dev, FCINTSTAT);
+       if (status & SSS_FCINTSTAT_BRDMAINT)
+               set_dma_rx = s5p_aes_rx(dev);
+       if (status & SSS_FCINTSTAT_BTDMAINT)
+               set_dma_tx = s5p_aes_tx(dev);
+
+       SSS_WRITE(dev, FCINTPEND, status);
+
+       /*
+        * Writing length of DMA block (either receiving or transmitting)
+        * will start the operation immediately, so this should be done
+        * at the end (even after clearing pending interrupts to not miss the
+        * interrupt).
+        */
+       if (set_dma_tx)
+               s5p_set_dma_outdata(dev, dev->sg_dst);
+       if (set_dma_rx)
+               s5p_set_dma_indata(dev, dev->sg_src);
 
        spin_unlock_irqrestore(&dev->lock, flags);
 
@@ -395,6 +471,71 @@ static void s5p_set_aes(struct s5p_aes_dev *dev,
        memcpy_toio(keystart, key, keylen);
 }
 
+static bool s5p_is_sg_aligned(struct scatterlist *sg)
+{
+       while (sg) {
+               if (!IS_ALIGNED(sg->length, AES_BLOCK_SIZE))
+                       return false;
+               sg = sg_next(sg);
+       }
+
+       return true;
+}
+
+static int s5p_set_indata_start(struct s5p_aes_dev *dev,
+                               struct ablkcipher_request *req)
+{
+       struct scatterlist *sg;
+       int err;
+
+       dev->sg_src_cpy = NULL;
+       sg = req->src;
+       if (!s5p_is_sg_aligned(sg)) {
+               dev_dbg(dev->dev,
+                       "At least one unaligned source scatter list, making a copy\n");
+               err = s5p_make_sg_cpy(dev, sg, &dev->sg_src_cpy);
+               if (err)
+                       return err;
+
+               sg = dev->sg_src_cpy;
+       }
+
+       err = s5p_set_indata(dev, sg);
+       if (err) {
+               s5p_free_sg_cpy(dev, &dev->sg_src_cpy);
+               return err;
+       }
+
+       return 0;
+}
+
+static int s5p_set_outdata_start(struct s5p_aes_dev *dev,
+                               struct ablkcipher_request *req)
+{
+       struct scatterlist *sg;
+       int err;
+
+       dev->sg_dst_cpy = NULL;
+       sg = req->dst;
+       if (!s5p_is_sg_aligned(sg)) {
+               dev_dbg(dev->dev,
+                       "At least one unaligned dest scatter list, making a copy\n");
+               err = s5p_make_sg_cpy(dev, sg, &dev->sg_dst_cpy);
+               if (err)
+                       return err;
+
+               sg = dev->sg_dst_cpy;
+       }
+
+       err = s5p_set_outdata(dev, sg);
+       if (err) {
+               s5p_free_sg_cpy(dev, &dev->sg_dst_cpy);
+               return err;
+       }
+
+       return 0;
+}
+
 static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
 {
        struct ablkcipher_request  *req = dev->req;
@@ -431,19 +572,19 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
                  SSS_FCINTENCLR_BTDMAINTENCLR | SSS_FCINTENCLR_BRDMAINTENCLR);
        SSS_WRITE(dev, FCFIFOCTRL, 0x00);
 
-       err = s5p_set_indata(dev, req->src);
+       err = s5p_set_indata_start(dev, req);
        if (err)
                goto indata_error;
 
-       err = s5p_set_outdata(dev, req->dst);
+       err = s5p_set_outdata_start(dev, req);
        if (err)
                goto outdata_error;
 
        SSS_AES_WRITE(dev, AES_CONTROL, aes_control);
        s5p_set_aes(dev, dev->ctx->aes_key, req->info, dev->ctx->keylen);
 
-       s5p_set_dma_indata(dev,  req->src);
-       s5p_set_dma_outdata(dev, req->dst);
+       s5p_set_dma_indata(dev,  dev->sg_src);
+       s5p_set_dma_outdata(dev, dev->sg_dst);
 
        SSS_WRITE(dev, FCINTENSET,
                  SSS_FCINTENSET_BTDMAINTENSET | SSS_FCINTENSET_BRDMAINTENSET);
@@ -452,10 +593,10 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
 
        return;
 
- outdata_error:
+outdata_error:
        s5p_unset_indata(dev);
 
- indata_error:
+indata_error:
        s5p_aes_complete(dev, err);
        spin_unlock_irqrestore(&dev->lock, flags);
 }
@@ -506,7 +647,7 @@ static int s5p_aes_handle_req(struct s5p_aes_dev *dev,
 
        tasklet_schedule(&dev->tasklet);
 
- exit:
+exit:
        return err;
 }
 
@@ -671,21 +812,6 @@ static int s5p_aes_probe(struct platform_device *pdev)
                goto err_irq;
        }
 
-       if (variant->has_hash_irq) {
-               pdata->irq_hash = platform_get_irq(pdev, 1);
-               if (pdata->irq_hash < 0) {
-                       err = pdata->irq_hash;
-                       dev_warn(dev, "hash interrupt is not available.\n");
-                       goto err_irq;
-               }
-               err = devm_request_irq(dev, pdata->irq_hash, s5p_aes_interrupt,
-                                      IRQF_SHARED, pdev->name, pdev);
-               if (err < 0) {
-                       dev_warn(dev, "hash interrupt is not available.\n");
-                       goto err_irq;
-               }
-       }
-
        pdata->busy = false;
        pdata->variant = variant;
        pdata->dev = dev;
@@ -705,7 +831,7 @@ static int s5p_aes_probe(struct platform_device *pdev)
 
        return 0;
 
- err_algs:
+err_algs:
        dev_err(dev, "can't register '%s': %d\n", algs[i].cra_name, err);
 
        for (j = 0; j < i; j++)
@@ -713,7 +839,7 @@ static int s5p_aes_probe(struct platform_device *pdev)
 
        tasklet_kill(&pdata->tasklet);
 
- err_irq:
+err_irq:
        clk_disable_unprepare(pdata->clk);
 
        s5p_dev = NULL;
index 7be3fbcd8d78a6b5c0968a4b0846694313989d6b..3830d7c4e138180e90c342dbb7adc59a2b03f067 100644 (file)
@@ -35,6 +35,7 @@ static int sun4i_ss_opti_poll(struct ablkcipher_request *areq)
        unsigned int todo;
        struct sg_mapping_iter mi, mo;
        unsigned int oi, oo; /* offset for in and out */
+       unsigned long flags;
 
        if (areq->nbytes == 0)
                return 0;
@@ -49,7 +50,7 @@ static int sun4i_ss_opti_poll(struct ablkcipher_request *areq)
                return -EINVAL;
        }
 
-       spin_lock_bh(&ss->slock);
+       spin_lock_irqsave(&ss->slock, flags);
 
        for (i = 0; i < op->keylen; i += 4)
                writel(*(op->key + i / 4), ss->base + SS_KEY0 + i);
@@ -117,7 +118,7 @@ release_ss:
        sg_miter_stop(&mi);
        sg_miter_stop(&mo);
        writel(0, ss->base + SS_CTL);
-       spin_unlock_bh(&ss->slock);
+       spin_unlock_irqrestore(&ss->slock, flags);
        return err;
 }
 
@@ -149,6 +150,7 @@ static int sun4i_ss_cipher_poll(struct ablkcipher_request *areq)
        unsigned int ob = 0;    /* offset in buf */
        unsigned int obo = 0;   /* offset in bufo*/
        unsigned int obl = 0;   /* length of data in bufo */
+       unsigned long flags;
 
        if (areq->nbytes == 0)
                return 0;
@@ -181,7 +183,7 @@ static int sun4i_ss_cipher_poll(struct ablkcipher_request *areq)
        if (no_chunk == 1)
                return sun4i_ss_opti_poll(areq);
 
-       spin_lock_bh(&ss->slock);
+       spin_lock_irqsave(&ss->slock, flags);
 
        for (i = 0; i < op->keylen; i += 4)
                writel(*(op->key + i / 4), ss->base + SS_KEY0 + i);
@@ -307,7 +309,7 @@ release_ss:
        sg_miter_stop(&mi);
        sg_miter_stop(&mo);
        writel(0, ss->base + SS_CTL);
-       spin_unlock_bh(&ss->slock);
+       spin_unlock_irqrestore(&ss->slock, flags);
 
        return err;
 }
index aae05547b924bf86b518245ced599e02c787bf35..b7ee8d30147df02371337a0c48501e9c02f7a9e7 100644 (file)
@@ -835,6 +835,16 @@ struct talitos_ahash_req_ctx {
        struct scatterlist *psrc;
 };
 
+struct talitos_export_state {
+       u32 hw_context[TALITOS_MDEU_MAX_CONTEXT_SIZE / sizeof(u32)];
+       u8 buf[HASH_MAX_BLOCK_SIZE];
+       unsigned int swinit;
+       unsigned int first;
+       unsigned int last;
+       unsigned int to_hash_later;
+       unsigned int nbuf;
+};
+
 static int aead_setkey(struct crypto_aead *authenc,
                       const u8 *key, unsigned int keylen)
 {
@@ -1981,6 +1991,46 @@ static int ahash_digest(struct ahash_request *areq)
        return ahash_process_req(areq, areq->nbytes);
 }
 
+static int ahash_export(struct ahash_request *areq, void *out)
+{
+       struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+       struct talitos_export_state *export = out;
+
+       memcpy(export->hw_context, req_ctx->hw_context,
+              req_ctx->hw_context_size);
+       memcpy(export->buf, req_ctx->buf, req_ctx->nbuf);
+       export->swinit = req_ctx->swinit;
+       export->first = req_ctx->first;
+       export->last = req_ctx->last;
+       export->to_hash_later = req_ctx->to_hash_later;
+       export->nbuf = req_ctx->nbuf;
+
+       return 0;
+}
+
+static int ahash_import(struct ahash_request *areq, const void *in)
+{
+       struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       const struct talitos_export_state *export = in;
+
+       memset(req_ctx, 0, sizeof(*req_ctx));
+       req_ctx->hw_context_size =
+               (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
+                       ? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
+                       : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
+       memcpy(req_ctx->hw_context, export->hw_context,
+              req_ctx->hw_context_size);
+       memcpy(req_ctx->buf, export->buf, export->nbuf);
+       req_ctx->swinit = export->swinit;
+       req_ctx->first = export->first;
+       req_ctx->last = export->last;
+       req_ctx->to_hash_later = export->to_hash_later;
+       req_ctx->nbuf = export->nbuf;
+
+       return 0;
+}
+
 struct keyhash_result {
        struct completion completion;
        int err;
@@ -2458,6 +2508,7 @@ static struct talitos_alg_template driver_algs[] = {
        {       .type = CRYPTO_ALG_TYPE_AHASH,
                .alg.hash = {
                        .halg.digestsize = MD5_DIGEST_SIZE,
+                       .halg.statesize = sizeof(struct talitos_export_state),
                        .halg.base = {
                                .cra_name = "md5",
                                .cra_driver_name = "md5-talitos",
@@ -2473,6 +2524,7 @@ static struct talitos_alg_template driver_algs[] = {
        {       .type = CRYPTO_ALG_TYPE_AHASH,
                .alg.hash = {
                        .halg.digestsize = SHA1_DIGEST_SIZE,
+                       .halg.statesize = sizeof(struct talitos_export_state),
                        .halg.base = {
                                .cra_name = "sha1",
                                .cra_driver_name = "sha1-talitos",
@@ -2488,6 +2540,7 @@ static struct talitos_alg_template driver_algs[] = {
        {       .type = CRYPTO_ALG_TYPE_AHASH,
                .alg.hash = {
                        .halg.digestsize = SHA224_DIGEST_SIZE,
+                       .halg.statesize = sizeof(struct talitos_export_state),
                        .halg.base = {
                                .cra_name = "sha224",
                                .cra_driver_name = "sha224-talitos",
@@ -2503,6 +2556,7 @@ static struct talitos_alg_template driver_algs[] = {
        {       .type = CRYPTO_ALG_TYPE_AHASH,
                .alg.hash = {
                        .halg.digestsize = SHA256_DIGEST_SIZE,
+                       .halg.statesize = sizeof(struct talitos_export_state),
                        .halg.base = {
                                .cra_name = "sha256",
                                .cra_driver_name = "sha256-talitos",
@@ -2518,6 +2572,7 @@ static struct talitos_alg_template driver_algs[] = {
        {       .type = CRYPTO_ALG_TYPE_AHASH,
                .alg.hash = {
                        .halg.digestsize = SHA384_DIGEST_SIZE,
+                       .halg.statesize = sizeof(struct talitos_export_state),
                        .halg.base = {
                                .cra_name = "sha384",
                                .cra_driver_name = "sha384-talitos",
@@ -2533,6 +2588,7 @@ static struct talitos_alg_template driver_algs[] = {
        {       .type = CRYPTO_ALG_TYPE_AHASH,
                .alg.hash = {
                        .halg.digestsize = SHA512_DIGEST_SIZE,
+                       .halg.statesize = sizeof(struct talitos_export_state),
                        .halg.base = {
                                .cra_name = "sha512",
                                .cra_driver_name = "sha512-talitos",
@@ -2548,6 +2604,7 @@ static struct talitos_alg_template driver_algs[] = {
        {       .type = CRYPTO_ALG_TYPE_AHASH,
                .alg.hash = {
                        .halg.digestsize = MD5_DIGEST_SIZE,
+                       .halg.statesize = sizeof(struct talitos_export_state),
                        .halg.base = {
                                .cra_name = "hmac(md5)",
                                .cra_driver_name = "hmac-md5-talitos",
@@ -2563,6 +2620,7 @@ static struct talitos_alg_template driver_algs[] = {
        {       .type = CRYPTO_ALG_TYPE_AHASH,
                .alg.hash = {
                        .halg.digestsize = SHA1_DIGEST_SIZE,
+                       .halg.statesize = sizeof(struct talitos_export_state),
                        .halg.base = {
                                .cra_name = "hmac(sha1)",
                                .cra_driver_name = "hmac-sha1-talitos",
@@ -2578,6 +2636,7 @@ static struct talitos_alg_template driver_algs[] = {
        {       .type = CRYPTO_ALG_TYPE_AHASH,
                .alg.hash = {
                        .halg.digestsize = SHA224_DIGEST_SIZE,
+                       .halg.statesize = sizeof(struct talitos_export_state),
                        .halg.base = {
                                .cra_name = "hmac(sha224)",
                                .cra_driver_name = "hmac-sha224-talitos",
@@ -2593,6 +2652,7 @@ static struct talitos_alg_template driver_algs[] = {
        {       .type = CRYPTO_ALG_TYPE_AHASH,
                .alg.hash = {
                        .halg.digestsize = SHA256_DIGEST_SIZE,
+                       .halg.statesize = sizeof(struct talitos_export_state),
                        .halg.base = {
                                .cra_name = "hmac(sha256)",
                                .cra_driver_name = "hmac-sha256-talitos",
@@ -2608,6 +2668,7 @@ static struct talitos_alg_template driver_algs[] = {
        {       .type = CRYPTO_ALG_TYPE_AHASH,
                .alg.hash = {
                        .halg.digestsize = SHA384_DIGEST_SIZE,
+                       .halg.statesize = sizeof(struct talitos_export_state),
                        .halg.base = {
                                .cra_name = "hmac(sha384)",
                                .cra_driver_name = "hmac-sha384-talitos",
@@ -2623,6 +2684,7 @@ static struct talitos_alg_template driver_algs[] = {
        {       .type = CRYPTO_ALG_TYPE_AHASH,
                .alg.hash = {
                        .halg.digestsize = SHA512_DIGEST_SIZE,
+                       .halg.statesize = sizeof(struct talitos_export_state),
                        .halg.base = {
                                .cra_name = "hmac(sha512)",
                                .cra_driver_name = "hmac-sha512-talitos",
@@ -2814,6 +2876,8 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
                t_alg->algt.alg.hash.finup = ahash_finup;
                t_alg->algt.alg.hash.digest = ahash_digest;
                t_alg->algt.alg.hash.setkey = ahash_setkey;
+               t_alg->algt.alg.hash.import = ahash_import;
+               t_alg->algt.alg.hash.export = ahash_export;
 
                if (!(priv->features & TALITOS_FTR_HMAC_OK) &&
                    !strncmp(alg->cra_name, "hmac", 4)) {
index b9997335f1937eb8694321ef0e37c66c8877a6c2..9f4994cabcc7f44af299a8c8d3fbd90c41982fa4 100644 (file)
@@ -139,6 +139,26 @@ my $vmr = sub {
     "  vor     $vx,$vy,$vy";
 };
 
+# Some ABIs specify vrsave, special-purpose register #256, as reserved
+# for system use.
+my $no_vrsave = ($flavour =~ /aix|linux64le/);
+my $mtspr = sub {
+    my ($f,$idx,$ra) = @_;
+    if ($idx == 256 && $no_vrsave) {
+       "       or      $ra,$ra,$ra";
+    } else {
+       "       mtspr   $idx,$ra";
+    }
+};
+my $mfspr = sub {
+    my ($f,$rd,$idx) = @_;
+    if ($idx == 256 && $no_vrsave) {
+       "       li      $rd,-1";
+    } else {
+       "       mfspr   $rd,$idx";
+    }
+};
+
 # PowerISA 2.06 stuff
 sub vsxmem_op {
     my ($f, $vrt, $ra, $rb, $op) = @_;
index d09cb4cdd09f18e56e0f4135d810c732cc609365..9b4713c25db727b902a2c3779e0be7dcbee12562 100644 (file)
@@ -105,19 +105,7 @@ static int ecryptfs_calculate_md5(char *dst,
        struct crypto_shash *tfm;
        int rc = 0;
 
-       mutex_lock(&crypt_stat->cs_hash_tfm_mutex);
        tfm = crypt_stat->hash_tfm;
-       if (!tfm) {
-               tfm = crypto_alloc_shash(ECRYPTFS_DEFAULT_HASH, 0, 0);
-               if (IS_ERR(tfm)) {
-                       rc = PTR_ERR(tfm);
-                       ecryptfs_printk(KERN_ERR, "Error attempting to "
-                                       "allocate crypto context; rc = [%d]\n",
-                                       rc);
-                       goto out;
-               }
-               crypt_stat->hash_tfm = tfm;
-       }
        rc = ecryptfs_hash_digest(tfm, src, len, dst);
        if (rc) {
                printk(KERN_ERR
@@ -126,7 +114,6 @@ static int ecryptfs_calculate_md5(char *dst,
                goto out;
        }
 out:
-       mutex_unlock(&crypt_stat->cs_hash_tfm_mutex);
        return rc;
 }
 
@@ -207,16 +194,29 @@ out:
  *
  * Initialize the crypt_stat structure.
  */
-void
-ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)
+int ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)
 {
+       struct crypto_shash *tfm;
+       int rc;
+
+       tfm = crypto_alloc_shash(ECRYPTFS_DEFAULT_HASH, 0, 0);
+       if (IS_ERR(tfm)) {
+               rc = PTR_ERR(tfm);
+               ecryptfs_printk(KERN_ERR, "Error attempting to "
+                               "allocate crypto context; rc = [%d]\n",
+                               rc);
+               return rc;
+       }
+
        memset((void *)crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat));
        INIT_LIST_HEAD(&crypt_stat->keysig_list);
        mutex_init(&crypt_stat->keysig_list_mutex);
        mutex_init(&crypt_stat->cs_mutex);
        mutex_init(&crypt_stat->cs_tfm_mutex);
-       mutex_init(&crypt_stat->cs_hash_tfm_mutex);
+       crypt_stat->hash_tfm = tfm;
        crypt_stat->flags |= ECRYPTFS_STRUCT_INITIALIZED;
+
+       return 0;
 }
 
 /**
index d123fbaa28e000246cfab9829e444f60e49a6843..c7761a91cc2ca636b048f7d67165d46aa2a9818e 100644 (file)
@@ -242,7 +242,6 @@ struct ecryptfs_crypt_stat {
        struct list_head keysig_list;
        struct mutex keysig_list_mutex;
        struct mutex cs_tfm_mutex;
-       struct mutex cs_hash_tfm_mutex;
        struct mutex cs_mutex;
 };
 
@@ -577,7 +576,7 @@ int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,
                        int sg_size);
 int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat);
 void ecryptfs_rotate_iv(unsigned char *iv);
-void ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);
+int ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);
 void ecryptfs_destroy_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);
 void ecryptfs_destroy_mount_crypt_stat(
        struct ecryptfs_mount_crypt_stat *mount_crypt_stat);
index 224b49e71aa437ff36aa79bf111c1e536a9a625d..3ce01dd4a371b9590e70ba4d5389a8da55e6aa90 100644 (file)
@@ -898,8 +898,11 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
        struct ecryptfs_crypt_stat *crypt_stat;
 
        crypt_stat = &ecryptfs_inode_to_private(d_inode(dentry))->crypt_stat;
-       if (!(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED))
-               ecryptfs_init_crypt_stat(crypt_stat);
+       if (!(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED)) {
+               rc = ecryptfs_init_crypt_stat(crypt_stat);
+               if (rc)
+                       return rc;
+       }
        inode = d_inode(dentry);
        lower_inode = ecryptfs_inode_to_lower(inode);
        lower_dentry = ecryptfs_dentry_to_lower(dentry);
index 77a486d3a51b600265a0fc1a1a0134ae74ff5ab9..85411ceb0508bbd2af9286a300377fc243efd994 100644 (file)
@@ -55,7 +55,10 @@ static struct inode *ecryptfs_alloc_inode(struct super_block *sb)
        inode_info = kmem_cache_alloc(ecryptfs_inode_info_cache, GFP_KERNEL);
        if (unlikely(!inode_info))
                goto out;
-       ecryptfs_init_crypt_stat(&inode_info->crypt_stat);
+       if (ecryptfs_init_crypt_stat(&inode_info->crypt_stat)) {
+               kmem_cache_free(ecryptfs_inode_info_cache, inode_info);
+               goto out;
+       }
        mutex_init(&inode_info->lower_file_mutex);
        atomic_set(&inode_info->lower_file_count, 0);
        inode_info->lower_file = NULL;
index 957bb87632197f25a162440c9eb9b8c673ec7239..75174f80a1063d67ef4db86ec2d22634ed2da583 100644 (file)
@@ -405,8 +405,7 @@ static inline void aead_request_set_tfm(struct aead_request *req,
  * encrypt and decrypt API calls. During the allocation, the provided aead
  * handle is registered in the request data structure.
  *
- * Return: allocated request handle in case of success; IS_ERR() is true in case
- *        of an error, PTR_ERR() returns the error code.
+ * Return: allocated request handle in case of success, or NULL if out of memory
  */
 static inline struct aead_request *aead_request_alloc(struct crypto_aead *tfm,
                                                      gfp_t gfp)
index 1969f1416658babc28dd6d2a75363b93da36ac63..26605888a199ed0446d27268844ea5bff09b8aaa 100644 (file)
@@ -547,8 +547,7 @@ static inline void ahash_request_set_tfm(struct ahash_request *req,
  * the allocation, the provided ahash handle
  * is registered in the request data structure.
  *
- * Return: allocated request handle in case of success; IS_ERR() is true in case
- *        of an error, PTR_ERR() returns the error code.
+ * Return: allocated request handle in case of success, or NULL if out of memory
  */
 static inline struct ahash_request *ahash_request_alloc(
        struct crypto_ahash *tfm, gfp_t gfp)
index 905490c1da89b30ab1cf05b7a4aeaf1962e4e6ce..0f987f50bb52c67a9a731ef549fa317e3fe52cbd 100644 (file)
@@ -425,8 +425,7 @@ static inline struct skcipher_request *skcipher_request_cast(
  * encrypt and decrypt API calls. During the allocation, the provided skcipher
  * handle is registered in the request data structure.
  *
- * Return: allocated request handle in case of success; IS_ERR() is true in case
- *        of an error, PTR_ERR() returns the error code.
+ * Return: allocated request handle in case of success, or NULL if out of memory
  */
 static inline struct skcipher_request *skcipher_request_alloc(
        struct crypto_skcipher *tfm, gfp_t gfp)
index 915af3095b39c60cbcb658bf0f1a05de18c67431..7c2bb27c067ce847ed19f5bdac29a17ddce39c4b 100644 (file)
@@ -1,9 +1,10 @@
 /*
  * AMD Cryptographic Coprocessor (CCP) driver
  *
- * Copyright (C) 2013 Advanced Micro Devices, Inc.
+ * Copyright (C) 2013,2016 Advanced Micro Devices, Inc.
  *
  * Author: Tom Lendacky <thomas.lendacky@amd.com>
+ * Author: Gary R Hook <gary.hook@amd.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -381,6 +382,35 @@ struct ccp_passthru_engine {
        u32 final;
 };
 
+/**
+ * struct ccp_passthru_nomap_engine - CCP pass-through operation
+ *   without performing DMA mapping
+ * @bit_mod: bitwise operation to perform
+ * @byte_swap: byteswap operation to perform
+ * @mask: mask to be applied to data
+ * @mask_len: length in bytes of mask
+ * @src: data to be used for this operation
+ * @dst: data produced by this operation
+ * @src_len: length in bytes of data used for this operation
+ * @final: indicate final pass-through operation
+ *
+ * Variables required to be set when calling ccp_enqueue_cmd():
+ *   - bit_mod, byte_swap, src, dst, src_len
+ *   - mask, mask_len if bit_mod is not CCP_PASSTHRU_BITWISE_NOOP
+ */
+struct ccp_passthru_nomap_engine {
+       enum ccp_passthru_bitwise bit_mod;
+       enum ccp_passthru_byteswap byte_swap;
+
+       dma_addr_t mask;
+       u32 mask_len;           /* In bytes */
+
+       dma_addr_t src_dma, dst_dma;
+       u64 src_len;            /* In bytes */
+
+       u32 final;
+};
+
 /***** ECC engine *****/
 #define CCP_ECC_MODULUS_BYTES  48      /* 384-bits */
 #define CCP_ECC_MAX_OPERANDS   6
@@ -522,7 +552,8 @@ enum ccp_engine {
 };
 
 /* Flag values for flags member of ccp_cmd */
-#define CCP_CMD_MAY_BACKLOG    0x00000001
+#define CCP_CMD_MAY_BACKLOG            0x00000001
+#define CCP_CMD_PASSTHRU_NO_DMA_MAP    0x00000002
 
 /**
  * struct ccp_cmd - CPP operation request
@@ -562,6 +593,7 @@ struct ccp_cmd {
                struct ccp_sha_engine sha;
                struct ccp_rsa_engine rsa;
                struct ccp_passthru_engine passthru;
+               struct ccp_passthru_nomap_engine passthru_nomap;
                struct ccp_ecc_engine ecc;
        } u;
 
index 99c94899ad0fef73d8c7854c247e5cd109ebe241..6e28c895c37691879400957e997f9cb0b916fbda 100644 (file)
@@ -948,8 +948,7 @@ static inline struct ablkcipher_request *ablkcipher_request_cast(
  * encrypt and decrypt API calls. During the allocation, the provided ablkcipher
  * handle is registered in the request data structure.
  *
- * Return: allocated request handle in case of success; IS_ERR() is true in case
- *        of an error, PTR_ERR() returns the error code.
+ * Return: allocated request handle in case of success, or NULL if out of memory
  */
 static inline struct ablkcipher_request *ablkcipher_request_alloc(
        struct crypto_ablkcipher *tfm, gfp_t gfp)
index 554522934c442ae15c01b1b1266e8e3e9515bfbd..0bd8a611eb83c99aad01fcee01143bbaad490845 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
+#include <linux/module.h>
 #include <linux/asn1_decoder.h>
 #include <linux/asn1_ber_bytecode.h>
 
@@ -506,3 +507,5 @@ error:
        return -EBADMSG;
 }
 EXPORT_SYMBOL_GPL(asn1_ber_decoder);
+
+MODULE_LICENSE("GPL");
index eb15e7dc7b6522dacd786e15f73eefb879a97614..747606f9e4a355adaaa93950577a7697e8107207 100644 (file)
@@ -20,6 +20,8 @@
 
 #include <linux/bitops.h>
 #include <linux/count_zeros.h>
+#include <linux/byteorder/generic.h>
+#include <linux/string.h>
 #include "mpi-internal.h"
 
 #define MAX_EXTERN_MPI_BITS 16384
@@ -163,7 +165,13 @@ int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes,
                    int *sign)
 {
        uint8_t *p;
-       mpi_limb_t alimb;
+#if BYTES_PER_MPI_LIMB == 4
+       __be32 alimb;
+#elif BYTES_PER_MPI_LIMB == 8
+       __be64 alimb;
+#else
+#error please implement for this limb size.
+#endif
        unsigned int n = mpi_get_size(a);
        int i, lzeros;
 
@@ -183,38 +191,19 @@ int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes,
        p = buf;
        *nbytes = n - lzeros;
 
-       for (i = a->nlimbs - 1; i >= 0; i--) {
-               alimb = a->d[i];
+       for (i = a->nlimbs - 1 - lzeros / BYTES_PER_MPI_LIMB,
+                       lzeros %= BYTES_PER_MPI_LIMB;
+               i >= 0; i--) {
 #if BYTES_PER_MPI_LIMB == 4
-               *p++ = alimb >> 24;
-               *p++ = alimb >> 16;
-               *p++ = alimb >> 8;
-               *p++ = alimb;
+               alimb = cpu_to_be32(a->d[i]);
 #elif BYTES_PER_MPI_LIMB == 8
-               *p++ = alimb >> 56;
-               *p++ = alimb >> 48;
-               *p++ = alimb >> 40;
-               *p++ = alimb >> 32;
-               *p++ = alimb >> 24;
-               *p++ = alimb >> 16;
-               *p++ = alimb >> 8;
-               *p++ = alimb;
+               alimb = cpu_to_be64(a->d[i]);
 #else
 #error please implement for this limb size.
 #endif
-
-               if (lzeros > 0) {
-                       if (lzeros >= sizeof(alimb)) {
-                               p -= sizeof(alimb);
-                       } else {
-                               mpi_limb_t *limb1 = (void *)p - sizeof(alimb);
-                               mpi_limb_t *limb2 = (void *)p - sizeof(alimb)
-                                                       + lzeros;
-                               *limb1 = *limb2;
-                               p -= lzeros;
-                       }
-                       lzeros -= sizeof(alimb);
-               }
+               memcpy(p, (u8 *)&alimb + lzeros, BYTES_PER_MPI_LIMB - lzeros);
+               p += BYTES_PER_MPI_LIMB - lzeros;
+               lzeros = 0;
        }
        return 0;
 }
@@ -359,7 +348,13 @@ int mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned *nbytes,
                     int *sign)
 {
        u8 *p, *p2;
-       mpi_limb_t alimb, alimb2;
+#if BYTES_PER_MPI_LIMB == 4
+       __be32 alimb;
+#elif BYTES_PER_MPI_LIMB == 8
+       __be64 alimb;
+#else
+#error please implement for this limb size.
+#endif
        unsigned int n = mpi_get_size(a);
        int i, x, y = 0, lzeros, buf_len;
 
@@ -380,42 +375,22 @@ int mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned *nbytes,
        buf_len = sgl->length;
        p2 = sg_virt(sgl);
 
-       for (i = a->nlimbs - 1; i >= 0; i--) {
-               alimb = a->d[i];
-               p = (u8 *)&alimb2;
+       for (i = a->nlimbs - 1 - lzeros / BYTES_PER_MPI_LIMB,
+                       lzeros %= BYTES_PER_MPI_LIMB;
+               i >= 0; i--) {
 #if BYTES_PER_MPI_LIMB == 4
-               *p++ = alimb >> 24;
-               *p++ = alimb >> 16;
-               *p++ = alimb >> 8;
-               *p++ = alimb;
+               alimb = cpu_to_be32(a->d[i]);
 #elif BYTES_PER_MPI_LIMB == 8
-               *p++ = alimb >> 56;
-               *p++ = alimb >> 48;
-               *p++ = alimb >> 40;
-               *p++ = alimb >> 32;
-               *p++ = alimb >> 24;
-               *p++ = alimb >> 16;
-               *p++ = alimb >> 8;
-               *p++ = alimb;
+               alimb = cpu_to_be64(a->d[i]);
 #else
 #error please implement for this limb size.
 #endif
-               if (lzeros > 0) {
-                       if (lzeros >= sizeof(alimb)) {
-                               p -= sizeof(alimb);
-                               continue;
-                       } else {
-                               mpi_limb_t *limb1 = (void *)p - sizeof(alimb);
-                               mpi_limb_t *limb2 = (void *)p - sizeof(alimb)
-                                                       + lzeros;
-                               *limb1 = *limb2;
-                               p -= lzeros;
-                               y = lzeros;
-                       }
-                       lzeros -= sizeof(alimb);
+               if (lzeros) {
+                       y = lzeros;
+                       lzeros = 0;
                }
 
-               p = p - (sizeof(alimb) - y);
+               p = (u8 *)&alimb + y;
 
                for (x = 0; x < sizeof(alimb) - y; x++) {
                        if (!buf_len) {
@@ -443,15 +418,15 @@ EXPORT_SYMBOL_GPL(mpi_write_to_sgl);
  * a new MPI and reads the content of the sgl to the MPI.
  *
  * @sgl:       scatterlist to read from
- * @len:       number of bytes to read
+ * @nbytes:    number of bytes to read
  *
  * Return:     Pointer to a new MPI or NULL on error
  */
-MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int len)
+MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int nbytes)
 {
        struct scatterlist *sg;
        int x, i, j, z, lzeros, ents;
-       unsigned int nbits, nlimbs, nbytes;
+       unsigned int nbits, nlimbs;
        mpi_limb_t a;
        MPI val = NULL;
 
@@ -472,16 +447,12 @@ MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int len)
                        break;
 
                ents--;
+               nbytes -= lzeros;
                lzeros = 0;
        }
 
        sgl = sg;
-
-       if (!ents)
-               nbytes = 0;
-       else
-               nbytes = len - lzeros;
-
+       nbytes -= lzeros;
        nbits = nbytes * 8;
        if (nbits > MAX_EXTERN_MPI_BITS) {
                pr_info("MPI: mpi too large (%u bits)\n", nbits);
@@ -489,9 +460,8 @@ MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int len)
        }
 
        if (nbytes > 0)
-               nbits -= count_leading_zeros(*(u8 *)(sg_virt(sgl) + lzeros));
-       else
-               nbits = 0;
+               nbits -= count_leading_zeros(*(u8 *)(sg_virt(sgl) + lzeros)) -
+                       (BITS_PER_LONG - 8);
 
        nlimbs = DIV_ROUND_UP(nbytes, BYTES_PER_MPI_LIMB);
        val = mpi_alloc(nlimbs);
@@ -507,19 +477,14 @@ MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int len)
 
        j = nlimbs - 1;
        a = 0;
-       z = 0;
-       x = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
-       x %= BYTES_PER_MPI_LIMB;
+       z = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
+       z %= BYTES_PER_MPI_LIMB;
 
        for_each_sg(sgl, sg, ents, i) {
                const u8 *buffer = sg_virt(sg) + lzeros;
                int len = sg->length - lzeros;
-               int buf_shift = x;
-
-               if  (sg_is_last(sg) && (len % BYTES_PER_MPI_LIMB))
-                       len += BYTES_PER_MPI_LIMB - (len % BYTES_PER_MPI_LIMB);
 
-               for (; x < len + buf_shift; x++) {
+               for (x = 0; x < len; x++) {
                        a <<= 8;
                        a |= *buffer++;
                        if (((z + x + 1) % BYTES_PER_MPI_LIMB) == 0) {
@@ -528,7 +493,6 @@ MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int len)
                        }
                }
                z += x;
-               x = 0;
                lzeros = 0;
        }
        return val;