From 83094e5e9e49f893403d6fad20c9c06c980c2d1b Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Fri, 11 Mar 2016 11:50:33 -0800 Subject: crypto: af_alg - add async support to algif_aead Following the async change for algif_skcipher this patch adds similar async read to algif_aead. changes in v3: - add call to aead_reset_ctx directly from aead_put_sgl instead of calling them separatelly one after the other - remove wait from aead_sock_destruct function as it is not needed when sock_hold is used changes in v2: - change internal data structures from fixed size arrays, limited to RSGL_MAX_ENTRIES, to linked list model with no artificial limitation. - use sock_kmalloc instead of kmalloc for memory allocation - use sock_hold instead of separate atomic ctr to wait for outstanding request Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- crypto/algif_aead.c | 268 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 237 insertions(+), 31 deletions(-) diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c index 147069c..80a0f1a 100644 --- a/crypto/algif_aead.c +++ b/crypto/algif_aead.c @@ -13,7 +13,7 @@ * any later version. */ -#include +#include #include #include #include @@ -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; -- cgit v1.1 From 97ee7ed394f9f277f492026b9a0708cd92e6ef7d Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Sun, 13 Mar 2016 16:15:37 +0100 Subject: crypto: omap-des - Improve wording for CRYPTO_DEV_OMAP_DES in Kconfig Signed-off-by: Peter Meerwald Signed-off-by: Herbert Xu --- drivers/crypto/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 477fffd..41f194b 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -302,15 +302,15 @@ 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 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" -- cgit v1.1 From f0d947ac01632fa6c75cb07262922a93736385c1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 14 Mar 2016 09:07:12 +0900 Subject: hwrng: exynos - Runtime suspend device after init The driver uses pm_runtime_put_noidle() after initialization so the device might remain in active state if the core does not read from it (the read callback contains regular runtime put). The put_noidle() was chosen probably to avoid unneeded suspend and resume cycle after the initialization. However for this purpose autosuspend is enabled so it is safe to runtime put just after the initialization. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- drivers/char/hw_random/exynos-rng.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c index ada0812..d1fd21e 100644 --- a/drivers/char/hw_random/exynos-rng.c +++ b/drivers/char/hw_random/exynos-rng.c @@ -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; } -- cgit v1.1 From f1925d78d7b710a1179828d53e918295f5f5d222 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 14 Mar 2016 09:07:13 +0900 Subject: hwrng: exynos - Fix unbalanced PM runtime put on timeout error path In case of timeout during read operation, the exit path lacked PM runtime put. This could lead to unbalanced runtime PM usage counter thus leaving the device in an active state. Fixes: d7fd6075a205 ("hwrng: exynos - Add timeout for waiting on init done") Cc: # v4.4+ Signed-off-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- drivers/char/hw_random/exynos-rng.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c index d1fd21e..38b80f8 100644 --- a/drivers/char/hw_random/exynos-rng.c +++ b/drivers/char/hw_random/exynos-rng.c @@ -90,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); @@ -98,17 +99,20 @@ 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) -- cgit v1.1 From 48a61e1e2af8020f11a2b8f8dc878144477623c6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 14 Mar 2016 09:07:14 +0900 Subject: hwrng: exynos - Disable runtime PM on probe failure Add proper error path (for disabling runtime PM) when registering of hwrng fails. Fixes: b329669ea0b5 ("hwrng: exynos - Add support for Exynos random number generator") Signed-off-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- drivers/char/hw_random/exynos-rng.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c index 38b80f8..71b45b1 100644 --- a/drivers/char/hw_random/exynos-rng.c +++ b/drivers/char/hw_random/exynos-rng.c @@ -119,6 +119,7 @@ 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); @@ -146,7 +147,13 @@ 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 __maybe_unused exynos_rng_runtime_suspend(struct device *dev) -- cgit v1.1 From 27d80fa8bccf8d28bef4f89709638efc624fef9a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 14 Mar 2016 09:07:15 +0900 Subject: hwrng: exynos - Disable runtime PM on driver unbind Driver enabled runtime PM but did not revert this on removal. Re-binding of a device triggered warning: exynos-rng 10830400.rng: Unbalanced pm_runtime_enable! Fixes: b329669ea0b5 ("hwrng: exynos - Add support for Exynos random number generator") Signed-off-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- drivers/char/hw_random/exynos-rng.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c index 71b45b1..ed78f25 100644 --- a/drivers/char/hw_random/exynos-rng.c +++ b/drivers/char/hw_random/exynos-rng.c @@ -156,6 +156,14 @@ static int exynos_rng_probe(struct platform_device *pdev) 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) { struct platform_device *pdev = to_platform_device(dev); @@ -213,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); -- cgit v1.1 From 4dd6e9ea7ae824ebfd054b92e4f97ad75454b4c2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 14 Mar 2016 13:19:55 +0900 Subject: hwrng: exynos - Enable COMPILE_TEST Get some build coverage of Exynos H/W random number generator driver. Driver uses devm_ioremap_resource() so add IOMEM dependency for the compile testing. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- drivers/char/hw_random/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 67ee8b0..3c5be60 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -309,7 +309,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 -- cgit v1.1 From dc1d9dee3042d4c507bd7eb557a06918a1f09ae0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 14 Mar 2016 13:20:18 +0900 Subject: crypto: s5p-sss - Enable COMPILE_TEST Get some build coverage of S5P/Exynos AES H/W acceleration driver. Driver uses DMA and devm_ioremap_resource() so add DMA and IOMEM dependencies for the compile testing. Signed-off-by: Krzysztof Kozlowski Acked-by: Vladimir Zapolskiy Signed-off-by: Herbert Xu --- drivers/crypto/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 41f194b..8c141f0 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -342,7 +342,8 @@ config CRYPTO_DEV_SAHARA 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 -- cgit v1.1 From 150f6d457cfcb37646b026251d8a584978618726 Mon Sep 17 00:00:00 2001 From: Amitoj Kaur Chawla Date: Fri, 18 Mar 2016 19:08:48 +0530 Subject: crypto: n2 - Remove return statement from void function Return statement at the end of a void function is useless. The Coccinelle semantic patch used to make this change is as follows: // @@ identifier f; expression e; @@ void f(...) { <... - return e; ...> } // Signed-off-by: Amitoj Kaur Chawla Signed-off-by: Herbert Xu --- drivers/crypto/n2_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index b85a7a7..c5aac25 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -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) -- cgit v1.1 From 06af9b0f4949b85b20107e6d75f5eba15111d220 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 18 Mar 2016 15:51:31 +0000 Subject: PKCS#7: fix missing break on OID_sha224 case The OID_sha224 case is missing a break and it falls through to the -ENOPKG error default. Since HASH_ALGO_SHA224 seems to be supported, this looks like an unintentional missing break. Fixes: 07f081fb5057 ("PKCS#7: Add OIDs for sha224, sha284 and sha512 hash algos and use them") Cc: # 4.2+ Signed-off-by: Colin Ian King Signed-off-by: Herbert Xu --- crypto/asymmetric_keys/pkcs7_parser.c | 1 + 1 file changed, 1 insertion(+) diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c index 40de03f..bdd0d753 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.c +++ b/crypto/asymmetric_keys/pkcs7_parser.c @@ -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; -- cgit v1.1 From 063327f54e864874de3f4d6715ff284e8d135e12 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 21 Mar 2016 12:03:43 +0300 Subject: crypto: marvell/cesa - remove unneeded condition creq->cache[] is an array inside the struct, it's not a pointer and it can't be NULL. Signed-off-by: Dan Carpenter Acked-by: Boris Brezillon Signed-off-by: Herbert Xu --- drivers/crypto/marvell/hash.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/crypto/marvell/hash.c b/drivers/crypto/marvell/hash.c index 7ca2e0f..7a5058d 100644 --- a/drivers/crypto/marvell/hash.c +++ b/drivers/crypto/marvell/hash.c @@ -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; } -- cgit v1.1 From 29e9330f2ba8cbca7c9dd8a03db1e6e453aea2f2 Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Mon, 21 Mar 2016 11:43:22 -0500 Subject: MAINTAINERS: Add a new maintainer for the CCP driver Gary will be taking over future development of the CCP driver, so add him as a co-maintainer of the driver. Signed-off-by: Tom Lendacky Acked-by: Gary Hook Signed-off-by: Herbert Xu --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 1c32f8a..c5048fa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -627,6 +627,7 @@ F: include/linux/altera_jtaguart.h AMD CRYPTOGRAPHIC COPROCESSOR (CCP) DRIVER M: Tom Lendacky +M: Gary Hook L: linux-crypto@vger.kernel.org S: Supported F: drivers/crypto/ccp/ -- cgit v1.1 From 119c3ab4ed33c04782f02040a4bc686216788c53 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 22 Mar 2016 10:58:23 +0900 Subject: crypto: s5p-sss - Minor coding cleanups Remove unneeded inclusion of delay.h and get rid of indentation from labels. Signed-off-by: Krzysztof Kozlowski Acked-by: Vladimir Zapolskiy Signed-off-by: Herbert Xu --- drivers/crypto/s5p-sss.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index 5f161a9..60f8354 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -11,7 +11,6 @@ * */ -#include #include #include #include @@ -284,7 +283,7 @@ static int s5p_set_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg) dev->sg_dst = sg; err = 0; - exit: +exit: return err; } @@ -310,7 +309,7 @@ static int s5p_set_indata(struct s5p_aes_dev *dev, struct scatterlist *sg) dev->sg_src = sg; err = 0; - exit: +exit: return err; } @@ -452,10 +451,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 +505,7 @@ static int s5p_aes_handle_req(struct s5p_aes_dev *dev, tasklet_schedule(&dev->tasklet); - exit: +exit: return err; } @@ -705,7 +704,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 +712,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; -- cgit v1.1 From 9e4a1100a445671dd55ff74dce859221cc1464fa Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 22 Mar 2016 10:58:24 +0900 Subject: crypto: s5p-sss - Handle unaligned buffers During crypto selftests on Odroid XU3 (Exynos5422) some of the algorithms failed because of passing AES-block unaligned source and destination buffers: alg: skcipher: encryption failed on chunk test 1 for ecb-aes-s5p: ret=22 Handle such case by copying the buffers to a new aligned and contiguous space. Signed-off-by: Krzysztof Kozlowski Acked-by: Vladimir Zapolskiy Signed-off-by: Herbert Xu --- drivers/crypto/s5p-sss.c | 150 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 138 insertions(+), 12 deletions(-) diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index 60f8354..3730fb0 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -28,6 +28,7 @@ #include #include #include +#include #define _SBF(s, v) ((v) << (s)) #define _BIT(b) _SBF(b, 1) @@ -185,6 +186,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; @@ -244,8 +249,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; @@ -261,14 +303,36 @@ 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)) { err = -EINVAL; goto exit; @@ -291,10 +355,6 @@ 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)) { err = -EINVAL; goto exit; @@ -394,6 +454,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_dma_len(sg), 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; @@ -430,19 +555,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,6 +577,7 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode) return; outdata_error: + s5p_free_sg_cpy(dev, &dev->sg_src_cpy); s5p_unset_indata(dev); indata_error: -- cgit v1.1 From 3cf9d84eb84abb4c186cd793d8720437a2ee2b1a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 22 Mar 2016 10:58:25 +0900 Subject: crypto: s5p-sss - Sort the headers to improve readability Sort the headers alphabetically to improve readability and to spot duplications easier. Suggested-by: Vladimir Zapolskiy Signed-off-by: Krzysztof Kozlowski Acked-by: Vladimir Zapolskiy Signed-off-by: Herbert Xu --- drivers/crypto/s5p-sss.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index 3730fb0..4f6d5b3 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -11,23 +11,23 @@ * */ +#include +#include +#include #include -#include -#include #include +#include +#include +#include #include -#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include #include #define _SBF(s, v) ((v) << (s)) -- cgit v1.1 From f2d1362ff7d266b3d2b1c764d6c2ef4a3b457f23 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 22 Mar 2016 13:12:35 +0100 Subject: lib/mpi: mpi_write_sgl(): fix skipping of leading zero limbs Currently, if the number of leading zeros is greater than fits into a complete limb, mpi_write_sgl() skips them by iterating over them limb-wise. However, it fails to adjust its internal leading zeros tracking variable, lzeros, accordingly: it does a p -= sizeof(alimb); continue; which should really have been a lzeros -= sizeof(alimb); continue; Since lzeros never decreases if its initial value >= sizeof(alimb), nothing gets copied by mpi_write_sgl() in that case. Instead of skipping the high order zero limbs within the loop as shown above, fix the issue by adjusting the copying loop's bounds. Fixes: 2d4d1eea540b ("lib/mpi: Add mpi sgl helpers") Signed-off-by: Nicolai Stange Signed-off-by: Herbert Xu --- lib/mpi/mpicoder.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c index eb15e7d..6bb52be 100644 --- a/lib/mpi/mpicoder.c +++ b/lib/mpi/mpicoder.c @@ -380,7 +380,9 @@ 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--) { + for (i = a->nlimbs - 1 - lzeros / BYTES_PER_MPI_LIMB, + lzeros %= BYTES_PER_MPI_LIMB; + i >= 0; i--) { alimb = a->d[i]; p = (u8 *)&alimb2; #if BYTES_PER_MPI_LIMB == 4 @@ -401,17 +403,12 @@ int mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned *nbytes, #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; - } + 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); } -- cgit v1.1 From 654842ef53d7820129a751f5cc620e5a69c694a9 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 22 Mar 2016 13:12:36 +0100 Subject: lib/mpi: mpi_write_sgl(): fix style issue with lzero decrement Within the copying loop in mpi_write_sgl(), we have if (lzeros > 0) { ... lzeros -= sizeof(alimb); } However, at this point, lzeros < sizeof(alimb) holds. Make this fact explicit by rewriting the above to if (lzeros) { ... lzeros = 0; } Signed-off-by: Nicolai Stange Signed-off-by: Herbert Xu --- lib/mpi/mpicoder.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c index 6bb52be..d8b372b 100644 --- a/lib/mpi/mpicoder.c +++ b/lib/mpi/mpicoder.c @@ -402,14 +402,14 @@ int mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned *nbytes, #else #error please implement for this limb size. #endif - if (lzeros > 0) { + if (lzeros) { 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); + lzeros = 0; } p = p - (sizeof(alimb) - y); -- cgit v1.1 From ea122be0b8f788b30e71ed5536fddc05f5ddff86 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 22 Mar 2016 13:12:37 +0100 Subject: lib/mpi: mpi_write_sgl(): purge redundant pointer arithmetic Within the copying loop in mpi_write_sgl(), we have if (lzeros) { ... p -= lzeros; y = lzeros; } p = p - (sizeof(alimb) - y); If lzeros == 0, then y == 0, too. Thus, lzeros gets subtracted and added back again to p. Purge this redundancy. Signed-off-by: Nicolai Stange Signed-off-by: Herbert Xu --- lib/mpi/mpicoder.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c index d8b372b..78ec4e1 100644 --- a/lib/mpi/mpicoder.c +++ b/lib/mpi/mpicoder.c @@ -407,12 +407,11 @@ int mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned *nbytes, mpi_limb_t *limb2 = (void *)p - sizeof(alimb) + lzeros; *limb1 = *limb2; - p -= lzeros; y = lzeros; lzeros = 0; } - p = p - (sizeof(alimb) - y); + p = p - sizeof(alimb); for (x = 0; x < sizeof(alimb) - y; x++) { if (!buf_len) { -- cgit v1.1 From cece762f6f3cb1c1687f467e98faef21b0096600 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 22 Mar 2016 13:12:38 +0100 Subject: lib/mpi: mpi_write_sgl(): fix out-of-bounds stack access Within the copying loop in mpi_write_sgl(), we have if (lzeros) { mpi_limb_t *limb1 = (void *)p - sizeof(alimb); mpi_limb_t *limb2 = (void *)p - sizeof(alimb) + lzeros; *limb1 = *limb2; ... } where p points past the end of alimb2 which lives on the stack and contains the current limb in BE order. The purpose of the above is to shift the non-zero bytes of alimb2 to its beginning in memory, i.e. to skip its leading zero bytes. However, limb2 points somewhere into the middle of alimb2 and thus, reading *limb2 pulls in lzero bytes from somewhere. Indeed, KASAN splats: BUG: KASAN: stack-out-of-bounds in mpi_write_to_sgl+0x4e3/0x6f0 at addr ffff8800cb04f601 Read of size 8 by task systemd-udevd/391 page:ffffea00032c13c0 count:0 mapcount:0 mapping: (null) index:0x0 flags: 0x3fff8000000000() page dumped because: kasan: bad access detected CPU: 3 PID: 391 Comm: systemd-udevd Tainted: G B L 4.5.0-next-20160316+ #12 [...] Call Trace: [] dump_stack+0xdc/0x15e [] ? _atomic_dec_and_lock+0xa2/0xa2 [] ? __dump_page+0x185/0x330 [] kasan_report_error+0x5e6/0x8b0 [] ? kzfree+0x2d/0x40 [] ? mpi_free_limb_space+0xe/0x20 [] ? mpi_powm+0x37e/0x16f0 [] kasan_report+0x71/0xa0 [] ? mpi_write_to_sgl+0x4e3/0x6f0 [] __asan_load8+0x64/0x70 [] mpi_write_to_sgl+0x4e3/0x6f0 [] ? mpi_set_buffer+0x620/0x620 [] ? mpi_cmp+0xbf/0x180 [] rsa_verify+0x202/0x260 What's more, since lzeros can be anything from 1 to sizeof(mpi_limb_t)-1, the above will cause unaligned accesses which is bad on non-x86 archs. Fix the issue, by preparing the starting point p for the upcoming copy operation instead of shifting the source memory, i.e. alimb2. Fixes: 2d4d1eea540b ("lib/mpi: Add mpi sgl helpers") Signed-off-by: Nicolai Stange Signed-off-by: Herbert Xu --- lib/mpi/mpicoder.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c index 78ec4e1..b05d390 100644 --- a/lib/mpi/mpicoder.c +++ b/lib/mpi/mpicoder.c @@ -403,15 +403,11 @@ int mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned *nbytes, #error please implement for this limb size. #endif if (lzeros) { - mpi_limb_t *limb1 = (void *)p - sizeof(alimb); - mpi_limb_t *limb2 = (void *)p - sizeof(alimb) - + lzeros; - *limb1 = *limb2; y = lzeros; lzeros = 0; } - p = p - sizeof(alimb); + p = p - sizeof(alimb) + y; for (x = 0; x < sizeof(alimb) - y; x++) { if (!buf_len) { -- cgit v1.1 From d755290689646fa66cc4830ca55569f2c9863666 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 22 Mar 2016 13:12:39 +0100 Subject: lib/mpi: mpi_write_sgl(): replace open coded endian conversion Currently, the endian conversion from CPU order to BE is open coded in mpi_write_sgl(). Replace this by the centrally provided cpu_to_be*() macros. Signed-off-by: Nicolai Stange Signed-off-by: Herbert Xu --- lib/mpi/mpicoder.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c index b05d390..623439e 100644 --- a/lib/mpi/mpicoder.c +++ b/lib/mpi/mpicoder.c @@ -20,6 +20,7 @@ #include #include +#include #include "mpi-internal.h" #define MAX_EXTERN_MPI_BITS 16384 @@ -359,7 +360,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; @@ -383,22 +390,10 @@ int mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned *nbytes, for (i = a->nlimbs - 1 - lzeros / BYTES_PER_MPI_LIMB, lzeros %= BYTES_PER_MPI_LIMB; i >= 0; i--) { - alimb = a->d[i]; - p = (u8 *)&alimb2; #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 @@ -407,7 +402,7 @@ int mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned *nbytes, lzeros = 0; } - p = p - sizeof(alimb) + y; + p = (u8 *)&alimb + y; for (x = 0; x < sizeof(alimb) - y; x++) { if (!buf_len) { -- cgit v1.1 From f00fa2417b3e1252b1a761f88731af03afff4407 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 22 Mar 2016 13:12:40 +0100 Subject: lib/mpi: mpi_read_buffer(): optimize skipping of leading zero limbs Currently, if the number of leading zeros is greater than fits into a complete limb, mpi_read_buffer() skips them by iterating over them limb-wise. Instead of skipping the high order zero limbs within the loop as shown above, adjust the copying loop's bounds. Signed-off-by: Nicolai Stange Signed-off-by: Herbert Xu --- lib/mpi/mpicoder.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c index 623439e..2fd8d41 100644 --- a/lib/mpi/mpicoder.c +++ b/lib/mpi/mpicoder.c @@ -184,7 +184,9 @@ 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--) { + for (i = a->nlimbs - 1 - lzeros / BYTES_PER_MPI_LIMB, + lzeros %= BYTES_PER_MPI_LIMB; + i >= 0; i--) { alimb = a->d[i]; #if BYTES_PER_MPI_LIMB == 4 *p++ = alimb >> 24; @@ -205,15 +207,11 @@ int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes, #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; - } + mpi_limb_t *limb1 = (void *)p - sizeof(alimb); + mpi_limb_t *limb2 = (void *)p - sizeof(alimb) + + lzeros; + *limb1 = *limb2; + p -= lzeros; lzeros -= sizeof(alimb); } } -- cgit v1.1 From 90f864e20029600a8dc33e27b1192af4636100d4 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 22 Mar 2016 13:12:41 +0100 Subject: lib/mpi: mpi_read_buffer(): replace open coded endian conversion Currently, the endian conversion from CPU order to BE is open coded in mpi_read_buffer(). Replace this by the centrally provided cpu_to_be*() macros. Copy from the temporary storage on stack to the destination buffer by means of memcpy(). Signed-off-by: Nicolai Stange Signed-off-by: Herbert Xu --- lib/mpi/mpicoder.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c index 2fd8d41..a999ee1 100644 --- a/lib/mpi/mpicoder.c +++ b/lib/mpi/mpicoder.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "mpi-internal.h" #define MAX_EXTERN_MPI_BITS 16384 @@ -164,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; @@ -187,25 +194,15 @@ int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes, for (i = a->nlimbs - 1 - lzeros / BYTES_PER_MPI_LIMB, lzeros %= BYTES_PER_MPI_LIMB; i >= 0; i--) { - alimb = a->d[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 - + memcpy(p, &alimb, BYTES_PER_MPI_LIMB); + p += BYTES_PER_MPI_LIMB; if (lzeros > 0) { mpi_limb_t *limb1 = (void *)p - sizeof(alimb); mpi_limb_t *limb2 = (void *)p - sizeof(alimb) -- cgit v1.1 From 462696fd0fd2aae2fd38d22d19b2d08a55606014 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 22 Mar 2016 13:12:42 +0100 Subject: lib/mpi: mpi_read_buffer(): fix buffer overflow Currently, mpi_read_buffer() writes full limbs to the output buffer and moves memory around to purge leading zero limbs afterwards. However, with commit 9cbe21d8f89d ("lib/mpi: only require buffers as big as needed for the integer") the caller is only required to provide a buffer large enough to hold the result without the leading zeros. This might result in a buffer overflow for small MP numbers with leading zeros. Fix this by coping the result to its final destination within the output buffer and not copying the leading zeros at all. Fixes: 9cbe21d8f89d ("lib/mpi: only require buffers as big as needed for the integer") Signed-off-by: Nicolai Stange Signed-off-by: Herbert Xu --- lib/mpi/mpicoder.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c index a999ee1..d995a4c 100644 --- a/lib/mpi/mpicoder.c +++ b/lib/mpi/mpicoder.c @@ -201,16 +201,9 @@ int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes, #else #error please implement for this limb size. #endif - memcpy(p, &alimb, BYTES_PER_MPI_LIMB); - p += BYTES_PER_MPI_LIMB; - if (lzeros > 0) { - 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; } -- cgit v1.1 From b698538951a45dd853d9e40f51e143fdd46a60c6 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 22 Mar 2016 13:12:43 +0100 Subject: lib/mpi: mpi_read_raw_from_sgl(): replace len argument by nbytes Currently, the nbytes local variable is calculated from the len argument as follows: ... mpi_read_raw_from_sgl(..., unsigned int len) { unsigned nbytes; ... if (!ents) nbytes = 0; else nbytes = len - lzeros; ... } Given that nbytes is derived from len in a trivial way and that the len argument is shadowed by a local len variable in several loops, this is just confusing. Rename the len argument to nbytes and get rid of the nbytes local variable. Do the nbytes calculation in place. Signed-off-by: Nicolai Stange Signed-off-by: Herbert Xu --- lib/mpi/mpicoder.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c index d995a4c..048f0aa 100644 --- a/lib/mpi/mpicoder.c +++ b/lib/mpi/mpicoder.c @@ -418,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; @@ -455,7 +455,7 @@ MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int len) if (!ents) nbytes = 0; else - nbytes = len - lzeros; + nbytes -= lzeros; nbits = nbytes * 8; if (nbits > MAX_EXTERN_MPI_BITS) { -- cgit v1.1 From ab1e912ec1021e7532148398a01eb1283437fe62 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 22 Mar 2016 13:12:44 +0100 Subject: lib/mpi: mpi_read_raw_from_sgl(): don't include leading zero SGEs in nbytes At the very beginning of mpi_read_raw_from_sgl(), the leading zeros of the input scatterlist are counted: lzeros = 0; for_each_sg(sgl, sg, ents, i) { ... if (/* sg contains nonzero bytes */) break; /* sg contains nothing but zeros here */ ents--; lzeros = 0; } Later on, the total number of trailing nonzero bytes is calculated by subtracting the number of leading zero bytes from the total number of input bytes: nbytes -= lzeros; However, since lzeros gets reset to zero for each completely zero leading sg in the loop above, it doesn't include those. Besides wasting resources by allocating a too large output buffer, this mistake propagates into the calculation of x, the number of leading zeros within the most significant output limb: x = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; What's more, the low order bytes of the output, equal in number to the extra bytes in nbytes, are left uninitialized. Fix this by adjusting nbytes for each completely zero leading scatterlist entry. Fixes: 2d4d1eea540b ("lib/mpi: Add mpi sgl helpers") Signed-off-by: Nicolai Stange Signed-off-by: Herbert Xu --- lib/mpi/mpicoder.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c index 048f0aa..4ba0f23 100644 --- a/lib/mpi/mpicoder.c +++ b/lib/mpi/mpicoder.c @@ -447,16 +447,12 @@ MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int nbytes) break; ents--; + nbytes -= lzeros; lzeros = 0; } sgl = sg; - - if (!ents) - nbytes = 0; - else - nbytes -= lzeros; - + nbytes -= lzeros; nbits = nbytes * 8; if (nbits > MAX_EXTERN_MPI_BITS) { pr_info("MPI: mpi too large (%u bits)\n", nbits); -- cgit v1.1 From 60e1b74c224e9eda14e5b479413c5d990373c2cb Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 22 Mar 2016 13:12:45 +0100 Subject: lib/mpi: mpi_read_raw_from_sgl(): purge redundant clearing of nbits In mpi_read_raw_from_sgl(), unsigned nbits is calculated as follows: nbits = nbytes * 8; and redundantly cleared later on if nbytes == 0: if (nbytes > 0) ... else nbits = 0; Purge this redundant clearing for the sake of clarity. Signed-off-by: Nicolai Stange Signed-off-by: Herbert Xu --- lib/mpi/mpicoder.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c index 4ba0f23..27703aa 100644 --- a/lib/mpi/mpicoder.c +++ b/lib/mpi/mpicoder.c @@ -461,8 +461,6 @@ MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int nbytes) if (nbytes > 0) nbits -= count_leading_zeros(*(u8 *)(sg_virt(sgl) + lzeros)); - else - nbits = 0; nlimbs = DIV_ROUND_UP(nbytes, BYTES_PER_MPI_LIMB); val = mpi_alloc(nlimbs); -- cgit v1.1 From 64c09b0b59b92ad231dd526f57f24139b728044b Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 22 Mar 2016 13:17:27 +0100 Subject: lib/mpi: mpi_read_raw_from_sgl(): fix nbits calculation The number of bits, nbits, is calculated in mpi_read_raw_from_sgl() as follows: nbits = nbytes * 8; Afterwards, the number of leading zero bits of the first byte get subtracted: nbits -= count_leading_zeros(*(u8 *)(sg_virt(sgl) + lzeros)); However, count_leading_zeros() takes an unsigned long and thus, the u8 gets promoted to an unsigned long. Thus, the above doesn't subtract the number of leading zeros in the most significant nonzero input byte from nbits, but the number of leading zeros of the most significant nonzero input byte promoted to unsigned long, i.e. BITS_PER_LONG - 8 too many. Fix this by subtracting count_leading_zeros(...) - (BITS_PER_LONG - 8) from nbits only. Fixes: 2d4d1eea540b ("lib/mpi: Add mpi sgl helpers") Signed-off-by: Nicolai Stange Signed-off-by: Herbert Xu --- lib/mpi/mpicoder.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c index 27703aa..24a0155 100644 --- a/lib/mpi/mpicoder.c +++ b/lib/mpi/mpicoder.c @@ -460,7 +460,8 @@ MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int nbytes) } if (nbytes > 0) - nbits -= count_leading_zeros(*(u8 *)(sg_virt(sgl) + lzeros)); + 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); -- cgit v1.1 From 85d541a3d14ab7a4e08c280740d9a7e097b04835 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 22 Mar 2016 13:18:07 +0100 Subject: lib/mpi: mpi_read_raw_from_sgl(): sanitize meaning of indices Within the byte reading loop in mpi_read_raw_sgl(), there are two housekeeping indices used, z and x. At all times, the index z represents the number of output bytes covered by the input SGEs for which processing has completed so far. This includes any leading zero bytes within the most significant limb. The index x changes its meaning after the first outer loop's iteration though: while processing the first input SGE, it represents "number of leading zero bytes in most significant output limb" + "current position within current SGE" For the remaining SGEs OTOH, x corresponds just to "current position within current SGE" After all, it is only the sum of z and x that has any meaning for the output buffer and thus, the "number of leading zero bytes in most significant output limb" part can be moved away from x into z from the beginning, opening up the opportunity for cleaner code. Before the outer loop iterating over the SGEs, don't initialize z with zero, but with the number of leading zero bytes in the most significant output limb. For the inner loop iterating over a single SGE's bytes, get rid of the buf_shift offset to x' bounds and let x run from zero to sg->length - 1. Signed-off-by: Nicolai Stange Signed-off-by: Herbert Xu --- lib/mpi/mpicoder.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c index 24a0155..a9f1097 100644 --- a/lib/mpi/mpicoder.c +++ b/lib/mpi/mpicoder.c @@ -477,19 +477,17 @@ MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int nbytes) 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) { @@ -498,7 +496,6 @@ MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int nbytes) } } z += x; - x = 0; lzeros = 0; } return val; -- cgit v1.1 From 0bb5c9ead62f4e1eaf226744076e0b4e8348f68f Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 22 Mar 2016 13:18:16 +0100 Subject: lib/mpi: mpi_read_raw_from_sgl(): fix out-of-bounds buffer access Within the copying loop in mpi_read_raw_from_sgl(), the last input SGE's byte count gets artificially extended as follows: if (sg_is_last(sg) && (len % BYTES_PER_MPI_LIMB)) len += BYTES_PER_MPI_LIMB - (len % BYTES_PER_MPI_LIMB); Within the following byte copying loop, this causes reads beyond that SGE's allocated buffer: BUG: KASAN: slab-out-of-bounds in mpi_read_raw_from_sgl+0x331/0x650 at addr ffff8801e168d4d8 Read of size 1 by task systemd-udevd/721 [...] Call Trace: [] dump_stack+0xbc/0x117 [] ? _atomic_dec_and_lock+0x169/0x169 [] ? print_section+0x61/0xb0 [] print_trailer+0x179/0x2c0 [] object_err+0x34/0x40 [] kasan_report_error+0x307/0x8c0 [] ? kasan_unpoison_shadow+0x35/0x50 [] ? kasan_kmalloc+0x5e/0x70 [] kasan_report+0x71/0xa0 [] ? mpi_read_raw_from_sgl+0x331/0x650 [] __asan_load1+0x46/0x50 [] mpi_read_raw_from_sgl+0x331/0x650 [] rsa_verify+0x106/0x260 [] ? rsa_set_pub_key+0xf0/0xf0 [] ? sg_init_table+0x29/0x50 [] ? pkcs1pad_sg_set_buf+0xb2/0x2e0 [] pkcs1pad_verify+0x1f4/0x2b0 [] public_key_verify_signature+0x3a7/0x5e0 [] ? public_key_describe+0x80/0x80 [] ? keyring_search_aux+0x150/0x150 [] ? x509_request_asymmetric_key+0x114/0x370 [] ? kfree+0x220/0x370 [] public_key_verify_signature_2+0x32/0x50 [] verify_signature+0x7c/0xb0 [] pkcs7_validate_trust+0x42c/0x5f0 [] system_verify_data+0xca/0x170 [] ? top_trace_array+0x9b/0x9b [] ? __vfs_read+0x279/0x3d0 [] mod_verify_sig+0x1ff/0x290 [...] The exact purpose of the len extension isn't clear to me, but due to its form, I suspect that it's a leftover somehow accounting for leading zero bytes within the most significant output limb. Note however that without that len adjustement, the total number of bytes ever processed by the inner loop equals nbytes and thus, the last output limb gets written at this point. Thus the net effect of the len adjustement cited above is just to keep the inner loop running for some more iterations, namely < BYTES_PER_MPI_LIMB ones, reading some extra bytes from beyond the last SGE's buffer and discarding them afterwards. Fix this issue by purging the extension of len beyond the last input SGE's buffer length. Fixes: 2d4d1eea540b ("lib/mpi: Add mpi sgl helpers") Signed-off-by: Nicolai Stange Signed-off-by: Herbert Xu --- lib/mpi/mpicoder.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c index a9f1097..747606f 100644 --- a/lib/mpi/mpicoder.c +++ b/lib/mpi/mpicoder.c @@ -484,9 +484,6 @@ MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int nbytes) const u8 *buffer = sg_virt(sg) + lzeros; int len = sg->length - lzeros; - if (sg_is_last(sg) && (len % BYTES_PER_MPI_LIMB)) - len += BYTES_PER_MPI_LIMB - (len % BYTES_PER_MPI_LIMB); - for (x = 0; x < len; x++) { a <<= 8; a |= *buffer++; -- cgit v1.1 From 082ebe92ca7f09845f0550e85837a878d6cedb34 Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Tue, 22 Mar 2016 10:45:25 -0700 Subject: crypto: qat - make sure const_tab is 1024 bytes aligned FW requires the const_tab to be 1024 bytes aligned. Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_admin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/qat/qat_common/adf_admin.c b/drivers/crypto/qat/qat_common/adf_admin.c index eb557f6..ce7c462 100644 --- a/drivers/crypto/qat/qat_common/adf_admin.c +++ b/drivers/crypto/qat/qat_common/adf_admin.c @@ -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, -- cgit v1.1 From 0c4935b31df0e5ffa6da0f8a2fdfc690d1118ba7 Mon Sep 17 00:00:00 2001 From: Ahsan Atta Date: Tue, 22 Mar 2016 11:25:21 -0700 Subject: crypto: qat - Remove redundant nrbg rings Remove redundant nrbg rings. Signed-off-by: Ahsan Atta Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_cfg_strings.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_cfg_strings.h b/drivers/crypto/qat/qat_common/adf_cfg_strings.h index 1357511..7632ed0 100644 --- a/drivers/crypto/qat/qat_common/adf_cfg_strings.h +++ b/drivers/crypto/qat/qat_common/adf_cfg_strings.h @@ -57,10 +57,8 @@ #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" -- cgit v1.1 From aa8b6dd4b06bab62ec7f8972f9e66782dbc23d60 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Wed, 23 Mar 2016 17:06:39 +0200 Subject: crypto: qat - avoid memory corruption or undefined behaviour memcopying to a (null pointer + offset) will result in memory corruption or undefined behaviour. Signed-off-by: Tudor Ambarus Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/qat_asym_algs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/qat/qat_common/qat_asym_algs.c b/drivers/crypto/qat/qat_common/qat_asym_algs.c index e5c0727..8dbbf084 100644 --- a/drivers/crypto/qat/qat_common/qat_asym_algs.c +++ b/drivers/crypto/qat/qat_common/qat_asym_algs.c @@ -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); -- cgit v1.1 From 738f98233b94db55607f97a76f9699efc4217276 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Wed, 23 Mar 2016 17:06:40 +0200 Subject: crypto: qat - fix address leaking of RSA public exponent Signed-off-by: Tudor Ambarus Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/qat_asym_algs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/qat/qat_common/qat_asym_algs.c b/drivers/crypto/qat/qat_common/qat_asym_algs.c index 8dbbf084..05f49d4 100644 --- a/drivers/crypto/qat/qat_common/qat_asym_algs.c +++ b/drivers/crypto/qat/qat_common/qat_asym_algs.c @@ -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; } -- cgit v1.1 From bdb6cf9f6fe6d9af905ea34b7c4bb78ea601329e Mon Sep 17 00:00:00 2001 From: Corentin LABBE Date: Wed, 23 Mar 2016 16:11:24 +0100 Subject: crypto: sun4i-ss - Replace spinlock_bh by spin_lock_irq{save|restore} The current sun4i-ss driver could generate data corruption when ciphering/deciphering. It occurs randomly on end of handled data. No root cause have been found and the only way to remove it is to replace all spin_lock_bh by their irq counterparts. Fixes: 6298e948215f ("crypto: sunxi-ss - Add Allwinner Security System crypto accelerator") Signed-off-by: LABBE Corentin Cc: stable Signed-off-by: Herbert Xu --- drivers/crypto/sunxi-ss/sun4i-ss-cipher.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c b/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c index 7be3fbc..3830d7c 100644 --- a/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c +++ b/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c @@ -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; } -- cgit v1.1 From 4218ebe8cab421c72f134cca1374e0985303f34a Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Mon, 28 Mar 2016 16:47:55 +0200 Subject: crypto: drbg - set HMAC key only when altered The HMAC implementation allows setting the HMAC key independently from the hashing operation. Therefore, the key only needs to be set when a new key is generated. This patch increases the speed of the HMAC DRBG by at least 35% depending on the use case. The patch is fully CAVS tested. Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- crypto/drbg.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index 1b86310..0a3538f 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -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); -- cgit v1.1 From cb00bca42f8b819498b2647f24b6148d65ec9aa4 Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Tue, 29 Mar 2016 10:20:52 -0700 Subject: crypto: qat - explicitly stop all VFs first When stopping devices it is not enought to loop backwards. We need to explicitly stop all VFs first. Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_ctl_drv.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/qat/qat_common/adf_ctl_drv.c index 5c897e6..7403356 100644 --- a/drivers/crypto/qat/qat_common/adf_ctl_drv.c +++ b/drivers/crypto/qat/qat_common/adf_ctl_drv.c @@ -275,7 +275,26 @@ static int 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; + + /* First stop all VFs */ + if (!accel_dev->is_vf) + 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); + } + } + } + + 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; -- cgit v1.1 From f1420ceef3011547323733e3bb4fcb4aca3fe840 Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Tue, 29 Mar 2016 10:21:07 -0700 Subject: crypto: qat - changed adf_dev_stop to void It returns always zero anyway. Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_c3xxx/adf_drv.c | 4 +--- drivers/crypto/qat/qat_c3xxxvf/adf_drv.c | 4 +--- drivers/crypto/qat/qat_c62x/adf_drv.c | 4 +--- drivers/crypto/qat/qat_c62xvf/adf_drv.c | 4 +--- drivers/crypto/qat/qat_common/adf_common_drv.h | 2 +- drivers/crypto/qat/qat_common/adf_ctl_drv.c | 18 ++++-------------- drivers/crypto/qat/qat_common/adf_init.c | 12 +++++------- drivers/crypto/qat/qat_common/adf_sriov.c | 8 +------- drivers/crypto/qat/qat_dh895xcc/adf_drv.c | 4 +--- drivers/crypto/qat/qat_dh895xccvf/adf_drv.c | 4 +--- 10 files changed, 17 insertions(+), 47 deletions(-) diff --git a/drivers/crypto/qat/qat_c3xxx/adf_drv.c b/drivers/crypto/qat/qat_c3xxx/adf_drv.c index e13bd08..640c3fc 100644 --- a/drivers/crypto/qat/qat_c3xxx/adf_drv.c +++ b/drivers/crypto/qat/qat_c3xxx/adf_drv.c @@ -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); diff --git a/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c b/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c index 1ac4ae9..a998981 100644 --- a/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c +++ b/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c @@ -270,9 +270,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); diff --git a/drivers/crypto/qat/qat_c62x/adf_drv.c b/drivers/crypto/qat/qat_c62x/adf_drv.c index 512c565..bc5cbc1 100644 --- a/drivers/crypto/qat/qat_c62x/adf_drv.c +++ b/drivers/crypto/qat/qat_c62x/adf_drv.c @@ -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); diff --git a/drivers/crypto/qat/qat_c62xvf/adf_drv.c b/drivers/crypto/qat/qat_c62xvf/adf_drv.c index d2e4b92..ccfb25e 100644 --- a/drivers/crypto/qat/qat_c62xvf/adf_drv.c +++ b/drivers/crypto/qat/qat_c62xvf/adf_drv.c @@ -270,9 +270,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); diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h index 0e82ce3..c9e4d46 100644 --- a/drivers/crypto/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/qat/qat_common/adf_common_drv.h @@ -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); diff --git a/drivers/crypto/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/qat/qat_common/adf_ctl_drv.c index 7403356..48a1248 100644 --- a/drivers/crypto/qat/qat_common/adf_ctl_drv.c +++ b/drivers/crypto/qat/qat_common/adf_ctl_drv.c @@ -284,13 +284,8 @@ static int adf_ctl_stop_devices(uint32_t id) if (!accel_dev->is_vf) 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); - } + adf_dev_stop(accel_dev); + adf_dev_shutdown(accel_dev); } } @@ -299,13 +294,8 @@ static int adf_ctl_stop_devices(uint32_t id) 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); - } + adf_dev_stop(accel_dev); + adf_dev_shutdown(accel_dev); } } return ret; diff --git a/drivers/crypto/qat/qat_common/adf_init.c b/drivers/crypto/qat/qat_common/adf_init.c index ef5575e..a29470b 100644 --- a/drivers/crypto/qat/qat_common/adf_init.c +++ b/drivers/crypto/qat/qat_common/adf_init.c @@ -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); diff --git a/drivers/crypto/qat/qat_common/adf_sriov.c b/drivers/crypto/qat/qat_common/adf_sriov.c index 1117a8b..4479b0b 100644 --- a/drivers/crypto/qat/qat_common/adf_sriov.c +++ b/drivers/crypto/qat/qat_common/adf_sriov.c @@ -259,13 +259,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_dh895xcc/adf_drv.c b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c index a8c4b92..4d2de28 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c +++ b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c @@ -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); diff --git a/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c b/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c index f8cc4bf..1bf75324 100644 --- a/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c +++ b/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c @@ -270,9 +270,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); -- cgit v1.1 From 043809d8d25eac8307c8c7b74bca7266070cb007 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 5 Apr 2016 11:04:28 +0900 Subject: hwrng: exynos - Fix misspelled Samsung address Correct smasung.com into samsung.com. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- drivers/char/hw_random/exynos-rng.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c index ed78f25..ed44561 100644 --- a/drivers/char/hw_random/exynos-rng.c +++ b/drivers/char/hw_random/exynos-rng.c @@ -2,7 +2,7 @@ * exynos-rng.c - Random Number Generator driver for the exynos * * Copyright (C) 2012 Samsung Electronics - * Jonghwa Lee + * Jonghwa Lee * * 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 -- cgit v1.1 From 6eae29e7e7144d01a6d6af111d232b36cdd30f51 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 2 Apr 2016 10:54:56 -0500 Subject: crypto: doc - document correct return value for request allocation Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- Documentation/DocBook/crypto-API.tmpl | 6 +++--- include/crypto/aead.h | 3 +-- include/crypto/hash.h | 3 +-- include/crypto/skcipher.h | 3 +-- include/linux/crypto.h | 3 +-- 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/Documentation/DocBook/crypto-API.tmpl b/Documentation/DocBook/crypto-API.tmpl index 348619f..d55dc5a 100644 --- a/Documentation/DocBook/crypto-API.tmpl +++ b/Documentation/DocBook/crypto-API.tmpl @@ -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/include/crypto/aead.h b/include/crypto/aead.h index 957bb87..75174f8 100644 --- a/include/crypto/aead.h +++ b/include/crypto/aead.h @@ -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) diff --git a/include/crypto/hash.h b/include/crypto/hash.h index 1969f14..2660588 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -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) diff --git a/include/crypto/skcipher.h b/include/crypto/skcipher.h index 905490c..0f987f5 100644 --- a/include/crypto/skcipher.h +++ b/include/crypto/skcipher.h @@ -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) diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 99c9489..6e28c89 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -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) -- cgit v1.1 From 7587c407540006e4e8fd5ed33f66ffe6158e830a Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Tue, 5 Apr 2016 15:03:21 +0200 Subject: crypto: ccp - Fix RT breaking #include Direct include of rwlock_types.h breaks RT, use spinlock_types.h instead. Fixes: 553d2374db0b crypto: ccp - Support for multiple CCPs Signed-off-by: Mike Galbraith Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c index 4dbc187..87b9f2b 100644 --- a/drivers/crypto/ccp/ccp-dev.c +++ b/drivers/crypto/ccp/ccp-dev.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.1 From d6064165ba4449ea085a389724d728258a3180ec Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Wed, 6 Apr 2016 11:01:54 -0700 Subject: crypto: qat - adf_dev_stop should not be called in atomic context VFs call adf_dev_stop() from a PF to VF interrupt bottom half. This causes an oops "scheduling while atomic", because it tries to acquire a mutex to un-register crypto algorithms. This patch fixes the issue by calling adf_dev_stop() asynchronously. Changes in v2: - change kthread to a work queue. Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_common_drv.h | 2 + drivers/crypto/qat/qat_common/adf_ctl_drv.c | 6 +++ drivers/crypto/qat/qat_common/adf_vf_isr.c | 59 ++++++++++++++++++++++++-- 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h index c9e4d46..fd096ed 100644 --- a/drivers/crypto/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/qat/qat_common/adf_common_drv.h @@ -144,6 +144,8 @@ void adf_disable_aer(struct adf_accel_dev *accel_dev); void adf_dev_restore(struct adf_accel_dev *accel_dev); int adf_init_aer(void); void adf_exit_aer(void); +int adf_init_vf_wq(void); +void adf_exit_vf_wq(void); int adf_init_admin_comms(struct adf_accel_dev *accel_dev); void adf_exit_admin_comms(struct adf_accel_dev *accel_dev); int adf_send_admin_init(struct adf_accel_dev *accel_dev); diff --git a/drivers/crypto/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/qat/qat_common/adf_ctl_drv.c index 48a1248..116ddda 100644 --- a/drivers/crypto/qat/qat_common/adf_ctl_drv.c +++ b/drivers/crypto/qat/qat_common/adf_ctl_drv.c @@ -471,12 +471,17 @@ static int __init adf_register_ctl_device_driver(void) if (adf_init_aer()) goto err_aer; + 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_aer(); err_aer: adf_chr_drv_destroy(); @@ -489,6 +494,7 @@ static void __exit adf_unregister_ctl_device_driver(void) { adf_chr_drv_destroy(); adf_exit_aer(); + adf_exit_vf_wq(); qat_crypto_unregister(); adf_clean_vf_map(false); mutex_destroy(&adf_ctl_lock); diff --git a/drivers/crypto/qat/qat_common/adf_vf_isr.c b/drivers/crypto/qat/qat_common/adf_vf_isr.c index 09427b3..c3d5016 100644 --- a/drivers/crypto/qat/qat_common/adf_vf_isr.c +++ b/drivers/crypto/qat/qat_common/adf_vf_isr.c @@ -51,6 +51,7 @@ #include #include #include +#include #include "adf_accel_devices.h" #include "adf_common_drv.h" #include "adf_cfg.h" @@ -64,6 +65,13 @@ #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,27 @@ 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; + + 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 +316,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 __exit adf_exit_vf_wq(void) +{ + if (adf_vf_stop_wq) + destroy_workqueue(adf_vf_stop_wq); + + adf_vf_stop_wq = NULL; +} -- cgit v1.1 From ff0078f0b047520405db14ef0deecde5898b50a4 Mon Sep 17 00:00:00 2001 From: Steffen Trumtrar Date: Tue, 12 Apr 2016 11:04:24 +0200 Subject: Documentation: devicetree: add Freescale SCC bindings Add documentation for the Freescale Security Controller (SCC) found on i.MX25 SoCs. Signed-off-by: Steffen Trumtrar Acked-by: Rob Herring Signed-off-by: Herbert Xu --- .../devicetree/bindings/crypto/fsl-imx-scc.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Documentation/devicetree/bindings/crypto/fsl-imx-scc.txt diff --git a/Documentation/devicetree/bindings/crypto/fsl-imx-scc.txt b/Documentation/devicetree/bindings/crypto/fsl-imx-scc.txt new file mode 100644 index 0000000..7aad448 --- /dev/null +++ b/Documentation/devicetree/bindings/crypto/fsl-imx-scc.txt @@ -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"; + }; -- cgit v1.1 From ba97eed2b62e97ab6a96d27ea6a049f3a815237c Mon Sep 17 00:00:00 2001 From: Steffen Trumtrar Date: Tue, 12 Apr 2016 11:04:25 +0200 Subject: ARM: i.MX25: add scc module to dtsi Add the Security Controller (SCC) module to the dtsi. Signed-off-by: Steffen Trumtrar Signed-off-by: Herbert Xu --- arch/arm/boot/dts/imx25.dtsi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm/boot/dts/imx25.dtsi b/arch/arm/boot/dts/imx25.dtsi index 6b1f4bb..af6af87 100644 --- a/arch/arm/boot/dts/imx25.dtsi +++ b/arch/arm/boot/dts/imx25.dtsi @@ -420,6 +420,15 @@ 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>; -- cgit v1.1 From d293b640ebd532eb9d65bc42d48fb9d2c06e71c9 Mon Sep 17 00:00:00 2001 From: Steffen Trumtrar Date: Tue, 12 Apr 2016 11:04:26 +0200 Subject: crypto: mxc-scc - add basic driver for the MXC SCC According to the Freescale GPL driver code, there are two different Security Controller (SCC) versions: SCC and SCC2. The SCC is found on older i.MX SoCs, e.g. the i.MX25. This is the version implemented and tested here. As there is no publicly available documentation for this IP core, all information about this unit is gathered from the GPL'ed driver from Freescale. Signed-off-by: Steffen Trumtrar Signed-off-by: Herbert Xu --- drivers/crypto/Kconfig | 9 + drivers/crypto/Makefile | 1 + drivers/crypto/mxc-scc.c | 762 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 772 insertions(+) create mode 100644 drivers/crypto/mxc-scc.c diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 8c141f0..0a22ac7 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -340,6 +340,15 @@ 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 || COMPILE_TEST diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 713de9d..3c6432dd 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -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/ diff --git a/drivers/crypto/mxc-scc.c b/drivers/crypto/mxc-scc.c new file mode 100644 index 0000000..38b01bf --- /dev/null +++ b/drivers/crypto/mxc-scc.c @@ -0,0 +1,762 @@ +/* + * Copyright (C) 2016 Pengutronix, Steffen Trumtrar + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* 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; + + ctx->src_nents = sg_nents_for_len(req->src, req->nbytes); + if (ctx->src_nents < 0) { + dev_err(scc->dev, "Invalid number of src SC"); + return ctx->src_nents; + } + + ctx->dst_nents = sg_nents_for_len(req->dst, req->nbytes); + if (ctx->dst_nents < 0) { + dev_err(scc->dev, "Invalid number of dst SC"); + return ctx->dst_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) +{ + unsigned 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: + for (; i > 0; i--) + 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 "); +MODULE_DESCRIPTION("Freescale i.MX25 SCC Crypto driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.1 From c7995ee7ff60c1973a3a63e35b41c2393f47f760 Mon Sep 17 00:00:00 2001 From: Kefeng Wang Date: Wed, 13 Apr 2016 18:11:27 +0800 Subject: dt/bindings: Add bindings for hisilicon random number generator Document the devicetree bindings for the random number generator found on Hisilicon Hip04 and Hip05 soc. Signed-off-by: Kefeng Wang Acked-by: Rob Herring Signed-off-by: Herbert Xu --- Documentation/devicetree/bindings/rng/hisi-rng.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 Documentation/devicetree/bindings/rng/hisi-rng.txt diff --git a/Documentation/devicetree/bindings/rng/hisi-rng.txt b/Documentation/devicetree/bindings/rng/hisi-rng.txt new file mode 100644 index 0000000..d04d55a --- /dev/null +++ b/Documentation/devicetree/bindings/rng/hisi-rng.txt @@ -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>; +}; -- cgit v1.1 From afc39d6e89b4f410f511f03dc6de8dc1d4952d42 Mon Sep 17 00:00:00 2001 From: Kefeng Wang Date: Wed, 13 Apr 2016 18:11:28 +0800 Subject: hwrng: hisi - Add support for Hisilicon SoC RNG This adds the Hisilicon Random Number Generator(RNG) support, which is found in Hip04 and Hip05 soc. Reviewed-by: Mathieu Poirier Signed-off-by: Kefeng Wang Signed-off-by: Herbert Xu --- drivers/char/hw_random/Kconfig | 13 ++++ drivers/char/hw_random/Makefile | 1 + drivers/char/hw_random/hisi-rng.c | 126 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+) create mode 100644 drivers/char/hw_random/hisi-rng.c diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 3c5be60..c76a88d 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -334,6 +334,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 diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index f5a6fa7..e09305b 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -26,6 +26,7 @@ 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 diff --git a/drivers/char/hw_random/hisi-rng.c b/drivers/char/hw_random/hisi-rng.c new file mode 100644 index 0000000..40d9657 --- /dev/null +++ b/drivers/char/hw_random/hisi-rng.c @@ -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 +#include +#include +#include +#include +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("Hisilicon random number generator driver"); -- cgit v1.1 From 5f575efea79caae69b81f922d99b221302a2c003 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Thu, 14 Apr 2016 10:51:42 +0200 Subject: crypto: lzo - get rid of superfluous __GFP_REPEAT __GFP_REPEAT has a rather weak semantic but since it has been introduced around 2.6.12 it has been ignored for low order allocations. lzo_init uses __GFP_REPEAT to allocate LZO1X_MEM_COMPRESS 16K. This is order 3 allocation request and __GFP_REPEAT is ignored for this size as well as all <= PAGE_ALLOC_COSTLY requests. Cc: Herbert Xu Cc: "David S. Miller" Cc: linux-crypto@vger.kernel.org Signed-off-by: Michal Hocko Signed-off-by: Herbert Xu --- crypto/lzo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/lzo.c b/crypto/lzo.c index 4b3e925..c3f3dd9 100644 --- a/crypto/lzo.c +++ b/crypto/lzo.c @@ -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) -- cgit v1.1 From 02dc8d634b4f175d92aa8b0b217eb0e4db1a0c3b Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Fri, 15 Apr 2016 10:37:58 -0700 Subject: crypto: qat - move vf2pf_init and vf2pf_exit to common The vf2pf_init and vf2pf_exit are exactly the same for all VFs so move them to common and reuse. Tested-by: Suman Bangalore Sathyanarayana Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- .../crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c | 23 ------ drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c | 23 ------ drivers/crypto/qat/qat_common/Makefile | 2 +- drivers/crypto/qat/qat_common/adf_common_drv.h | 12 +++ drivers/crypto/qat/qat_common/adf_vf2pf_msg.c | 90 ++++++++++++++++++++++ .../qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c | 23 ------ 6 files changed, 103 insertions(+), 70 deletions(-) create mode 100644 drivers/crypto/qat/qat_common/adf_vf2pf_msg.c diff --git a/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c b/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c index 1af321c..d2d0ae4 100644 --- a/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c +++ b/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c @@ -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; diff --git a/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c b/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c index baf4b509..38e4bc0 100644 --- a/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c +++ b/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c @@ -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; diff --git a/drivers/crypto/qat/qat_common/Makefile b/drivers/crypto/qat/qat_common/Makefile index 29c7c53..5873d22 100644 --- a/drivers/crypto/qat/qat_common/Makefile +++ b/drivers/crypto/qat/qat_common/Makefile @@ -27,4 +27,4 @@ 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 diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h index fd096ed..a8100a3 100644 --- a/drivers/crypto/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/qat/qat_common/adf_common_drv.h @@ -238,6 +238,9 @@ 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); #else static inline int adf_sriov_configure(struct pci_dev *pdev, int numvfs) { @@ -255,5 +258,14 @@ static inline void adf_enable_pf2vf_interrupts(struct adf_accel_dev *accel_dev) 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) +{ +} #endif #endif 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 index 0000000..5f1d863 --- /dev/null +++ b/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c @@ -0,0 +1,90 @@ +/* + 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; + } + 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 (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); diff --git a/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c b/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c index dc04ab6..a3b4dd8 100644 --- a/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c +++ b/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c @@ -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; -- cgit v1.1 From 25c6ffb249f612c56a48ce48a3887adf57b8f4bd Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Fri, 15 Apr 2016 10:37:59 -0700 Subject: crypto: qat - check if PF is running Before VF sends a signal to PF it should check if PF is still running. Tested-by: Suman Bangalore Sathyanarayana Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_c3xxxvf/adf_drv.c | 2 ++ drivers/crypto/qat/qat_c62xvf/adf_drv.c | 2 ++ drivers/crypto/qat/qat_common/adf_common_drv.h | 2 +- drivers/crypto/qat/qat_common/adf_vf2pf_msg.c | 8 +++++--- drivers/crypto/qat/qat_common/adf_vf_isr.c | 2 ++ drivers/crypto/qat/qat_dh895xccvf/adf_drv.c | 2 ++ 6 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c b/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c index a998981..949d77b 100644 --- a/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c +++ b/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c @@ -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; diff --git a/drivers/crypto/qat/qat_c62xvf/adf_drv.c b/drivers/crypto/qat/qat_c62xvf/adf_drv.c index ccfb25e..7540ce1 100644 --- a/drivers/crypto/qat/qat_c62xvf/adf_drv.c +++ b/drivers/crypto/qat/qat_c62xvf/adf_drv.c @@ -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; diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h index a8100a3..557ea36 100644 --- a/drivers/crypto/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/qat/qat_common/adf_common_drv.h @@ -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 { diff --git a/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c b/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c index 5f1d863..cd5f37d 100644 --- a/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c @@ -66,6 +66,7 @@ int adf_vf2pf_init(struct adf_accel_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); @@ -83,8 +84,9 @@ 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"); + 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); diff --git a/drivers/crypto/qat/qat_common/adf_vf_isr.c b/drivers/crypto/qat/qat_common/adf_vf_isr.c index c3d5016..5d45796 100644 --- a/drivers/crypto/qat/qat_common/adf_vf_isr.c +++ b/drivers/crypto/qat/qat_common/adf_vf_isr.c @@ -135,6 +135,8 @@ static void adf_pf2vf_bh_handler(void *data) dev_dbg(&GET_DEV(accel_dev), "Restarting msg received from PF 0x%x\n", msg); + 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), diff --git a/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c b/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c index 1bf75324..60df986 100644 --- a/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c +++ b/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c @@ -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; -- cgit v1.1 From 87ba569a398826733b14e77668c8d2630119b0ca Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Fri, 15 Apr 2016 10:38:00 -0700 Subject: crypto: qat - interrupts need to be enabled when VFs are disabled IRQs need to be enabled when VFs go down in case some VF to PF comms happens. Tested-by: Suman Bangalore Sathyanarayana Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/qat/qat_common/adf_init.c b/drivers/crypto/qat/qat_common/adf_init.c index a29470b..888c667 100644 --- a/drivers/crypto/qat/qat_common/adf_init.c +++ b/drivers/crypto/qat/qat_common/adf_init.c @@ -327,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); @@ -342,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); } -- cgit v1.1 From b3ab30a7cbdaf7ba20dddeac252cc0238312fff0 Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Fri, 15 Apr 2016 10:54:07 -0700 Subject: crypto: qat - fix section mismatch warning Fix Section mismatch warinig in adf_exit_vf_wq() Reported-by: kbuild test robot Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_vf_isr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/qat/qat_common/adf_vf_isr.c b/drivers/crypto/qat/qat_common/adf_vf_isr.c index 5d45796..aa689ca 100644 --- a/drivers/crypto/qat/qat_common/adf_vf_isr.c +++ b/drivers/crypto/qat/qat_common/adf_vf_isr.c @@ -326,7 +326,7 @@ int __init adf_init_vf_wq(void) return !adf_vf_stop_wq ? -EFAULT : 0; } -void __exit adf_exit_vf_wq(void) +void adf_exit_vf_wq(void) { if (adf_vf_stop_wq) destroy_workqueue(adf_vf_stop_wq); -- cgit v1.1 From e81f3340bba2bdcdf021aff511830e718e6e2112 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 16 Apr 2016 15:01:09 +0800 Subject: eCryptfs: Do not allocate hash tfm in NORECLAIM context You cannot allocate crypto tfm objects in NORECLAIM or NOFS contexts. The ecryptfs code currently does exactly that for the MD5 tfm. This patch fixes it by preallocating the MD5 tfm in a safe context. The MD5 tfm is also reentrant so this patch removes the superfluous cs_hash_tfm_mutex. Reported-by: Nicolas Boichat Signed-off-by: Herbert Xu --- fs/ecryptfs/crypto.c | 32 ++++++++++++++++---------------- fs/ecryptfs/ecryptfs_kernel.h | 3 +-- fs/ecryptfs/inode.c | 7 +++++-- fs/ecryptfs/super.c | 5 ++++- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index 64026e5..5600496 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -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; } /** diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index d123fba..c7761a9 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -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); diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 121114e..0caec70 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -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); diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c index 77a486d..85411ce 100644 --- a/fs/ecryptfs/super.c +++ b/fs/ecryptfs/super.c @@ -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; -- cgit v1.1 From 5343e674f32fb82b7a80a24b5a84eee62d3fe624 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 18 Apr 2016 12:57:41 +0200 Subject: crypto4xx: integrate ppc4xx-rng into crypto4xx This patch integrates the ppc4xx-rng driver into the existing crypto4xx. This is because the true random number generator is controlled and part of the security core. Signed-off-by: Christian Lamparter Signed-off-by: Herbert Xu --- drivers/char/hw_random/Kconfig | 13 --- drivers/char/hw_random/Makefile | 1 - drivers/char/hw_random/ppc4xx-rng.c | 147 -------------------------------- drivers/crypto/Kconfig | 8 ++ drivers/crypto/amcc/Makefile | 1 + drivers/crypto/amcc/crypto4xx_core.c | 7 +- drivers/crypto/amcc/crypto4xx_core.h | 4 + drivers/crypto/amcc/crypto4xx_reg_def.h | 1 + drivers/crypto/amcc/crypto4xx_trng.c | 131 ++++++++++++++++++++++++++++ drivers/crypto/amcc/crypto4xx_trng.h | 34 ++++++++ 10 files changed, 184 insertions(+), 163 deletions(-) delete mode 100644 drivers/char/hw_random/ppc4xx-rng.c create mode 100644 drivers/crypto/amcc/crypto4xx_trng.c create mode 100644 drivers/crypto/amcc/crypto4xx_trng.h diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index c76a88d..ac51149 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -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 diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index e09305b..63022b4 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -22,7 +22,6 @@ 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 diff --git a/drivers/char/hw_random/ppc4xx-rng.c b/drivers/char/hw_random/ppc4xx-rng.c deleted file mode 100644 index c0db438..0000000 --- a/drivers/char/hw_random/ppc4xx-rng.c +++ /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 -#include -#include -#include -#include -#include -#include -#include - -#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 "); -MODULE_DESCRIPTION("HW RNG driver for PPC 4xx processors"); diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 0a22ac7..12fd499 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -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 diff --git a/drivers/crypto/amcc/Makefile b/drivers/crypto/amcc/Makefile index 5c0c62b..b955399 100644 --- a/drivers/crypto/amcc/Makefile +++ b/drivers/crypto/amcc/Makefile @@ -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 diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 62134c8..dae1e39 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -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 "); MODULE_DESCRIPTION("Driver for AMCC PPC4xx crypto accelerator"); - diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h index bac0bde..ecfdcfe 100644 --- a/drivers/crypto/amcc/crypto4xx_core.h +++ b/drivers/crypto/amcc/crypto4xx_core.h @@ -24,6 +24,8 @@ #include +#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; diff --git a/drivers/crypto/amcc/crypto4xx_reg_def.h b/drivers/crypto/amcc/crypto4xx_reg_def.h index 5f5fbc0..46fe57c 100644 --- a/drivers/crypto/amcc/crypto4xx_reg_def.h +++ b/drivers/crypto/amcc/crypto4xx_reg_def.h @@ -125,6 +125,7 @@ #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 index 0000000..677ca17 --- /dev/null +++ b/drivers/crypto/amcc/crypto4xx_trng.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 0000000..931d225 --- /dev/null +++ b/drivers/crypto/amcc/crypto4xx_trng.h @@ -0,0 +1,34 @@ +/** + * AMCC SoC PPC4xx Crypto Driver + * + * Copyright (c) 2008 Applied Micro Circuits Corporation. + * All rights reserved. James Hsiao + * + * 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 -- cgit v1.1 From 58ea8abf490415c390e0cc671e875510c9b66318 Mon Sep 17 00:00:00 2001 From: Gary R Hook Date: Mon, 18 Apr 2016 09:21:44 -0500 Subject: crypto: ccp - Register the CCP as a DMA resource The CCP has the ability to provide DMA services to the kernel using pass-through mode of the device. Register these services as general purpose DMA channels. Changes since v2: - Add a Signed-off-by Changes since v1: - Allocate memory for a string in ccp_dmaengine_register - Ensure register/unregister calls are properly ordered - Verified all changed files are listed in the diffstat - Undo some superfluous changes - Added a cc: Signed-off-by: Gary R Hook Signed-off-by: Herbert Xu --- drivers/crypto/ccp/Kconfig | 1 + drivers/crypto/ccp/Makefile | 6 +- drivers/crypto/ccp/ccp-dev-v3.c | 11 + drivers/crypto/ccp/ccp-dev.h | 47 +++ drivers/crypto/ccp/ccp-dmaengine.c | 727 +++++++++++++++++++++++++++++++++++++ drivers/crypto/ccp/ccp-ops.c | 69 +++- include/linux/ccp.h | 36 +- 7 files changed, 893 insertions(+), 4 deletions(-) create mode 100644 drivers/crypto/ccp/ccp-dmaengine.c diff --git a/drivers/crypto/ccp/Kconfig b/drivers/crypto/ccp/Kconfig index 6e37845..79cabfb 100644 --- a/drivers/crypto/ccp/Kconfig +++ b/drivers/crypto/ccp/Kconfig @@ -3,6 +3,7 @@ config CRYPTO_DEV_CCP_DD depends on CRYPTO_DEV_CCP default m select HW_RANDOM + select DMA_ENGINE select CRYPTO_SHA1 select CRYPTO_SHA256 help diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile index b750592..ee4d274 100644 --- a/drivers/crypto/ccp/Makefile +++ b/drivers/crypto/ccp/Makefile @@ -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 diff --git a/drivers/crypto/ccp/ccp-dev-v3.c b/drivers/crypto/ccp/ccp-dev-v3.c index 7d5eab4..597fc50 100644 --- a/drivers/crypto/ccp/ccp-dev-v3.c +++ b/drivers/crypto/ccp/ccp-dev-v3.c @@ -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); diff --git a/drivers/crypto/ccp/ccp-dev.h b/drivers/crypto/ccp/ccp-dev.h index 7745d0b..5d986c9 100644 --- a/drivers/crypto/ccp/ccp-dev.h +++ b/drivers/crypto/ccp/ccp-dev.h @@ -22,6 +22,9 @@ #include #include #include +#include +#include +#include #define MAX_CCP_NAME_LEN 16 #define MAX_DMAPOOL_NAME_LEN 32 @@ -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; @@ -261,6 +297,14 @@ struct ccp_device { 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 */ atomic_t current_id ____cacheline_aligned; @@ -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 index 0000000..94f77b0 --- /dev/null +++ b/drivers/crypto/ccp/ccp-dmaengine.c @@ -0,0 +1,727 @@ +/* + * AMD Cryptographic Coprocessor (CCP) driver + * + * Copyright (C) 2016 Advanced Micro Devices, Inc. + * + * Author: Gary R Hook + * + * 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 +#include +#include +#include +#include + +#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); +} diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c index eefdf59..ffa2891 100644 --- a/drivers/crypto/ccp/ccp-ops.c +++ b/drivers/crypto/ccp/ccp-ops.c @@ -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); diff --git a/include/linux/ccp.h b/include/linux/ccp.h index 915af30..7c2bb27 100644 --- a/include/linux/ccp.h +++ b/include/linux/ccp.h @@ -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 + * Author: Gary R Hook * * 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; -- cgit v1.1 From 07c8fccbf7fd6adf896db380c5a32c66a5b32aca Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 19 Apr 2016 15:44:11 +0200 Subject: crypto: s5p-sss - Fix use after free of copied input buffer in error path The driver makes copies of memory (input or output scatterlists) if they are not aligned. In s5p_aes_crypt_start() error path (on unsuccessful initialization of output scatterlist), if input scatterlist was not aligned, the driver first freed copied input memory and then unmapped it from the device, instead of doing otherwise (unmap and then free). This was wrong in two ways: 1. Freed pages were still mapped to the device. 2. The dma_unmap_sg() iterated over freed scatterlist structure. The call to s5p_free_sg_cpy() in this error path is not needed because the copied scatterlists will be freed by s5p_aes_complete(). Fixes: 9e4a1100a445 ("crypto: s5p-sss - Handle unaligned buffers") Signed-off-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- drivers/crypto/s5p-sss.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index 4f6d5b3..b0484d4 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -577,7 +577,6 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode) return; outdata_error: - s5p_free_sg_cpy(dev, &dev->sg_src_cpy); s5p_unset_indata(dev); indata_error: -- cgit v1.1 From 5512442553bbe8d4fcdba3e17b30f187706384a7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 19 Apr 2016 15:44:12 +0200 Subject: crypto: s5p-sss - Remove useless hash interrupt handler Beside regular feed control interrupt, the driver requires also hash interrupt for older SoCs (samsung,s5pv210-secss). However after requesting it, the interrupt handler isn't doing anything with it, not even clearing the hash interrupt bit. Driver does not provide hash functions so it is safe to remove the hash interrupt related code and to not require the interrupt in Device Tree. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- .../devicetree/bindings/crypto/samsung-sss.txt | 6 ++-- drivers/crypto/s5p-sss.c | 34 ++++------------------ 2 files changed, 8 insertions(+), 32 deletions(-) diff --git a/Documentation/devicetree/bindings/crypto/samsung-sss.txt b/Documentation/devicetree/bindings/crypto/samsung-sss.txt index a6dafa8..7a5ca56 100644 --- a/Documentation/devicetree/bindings/crypto/samsung-sss.txt +++ b/Documentation/devicetree/bindings/crypto/samsung-sss.txt @@ -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/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index b0484d4..71ca6a5 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -149,7 +149,6 @@ /** * 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. @@ -157,7 +156,6 @@ * expansion of its usage. */ struct samsung_aes_variant { - bool has_hash_irq; unsigned int aes_offset; }; @@ -178,7 +176,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; @@ -201,12 +198,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, }; @@ -421,15 +416,13 @@ static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id) 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); + 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); - } + SSS_WRITE(dev, FCINTPEND, status); spin_unlock_irqrestore(&dev->lock, flags); @@ -795,21 +788,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; -- cgit v1.1 From 21ec757d2dd8650f978d27ad53cb1fcca8bb5e2b Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Tue, 19 Apr 2016 17:09:20 +0200 Subject: crypto: marvell/cesa - Improving code readability When looking for available engines, the variable "engine" is assigned to "&cesa->engines[i]" at the beginning of the for loop. Replacing next occurences of "&cesa->engines[i]" by "engine" and in order to improve readability. Signed-off-by: Romain Perier Acked-by: Boris Brezillon Signed-off-by: Herbert Xu --- drivers/crypto/marvell/cesa.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/crypto/marvell/cesa.c b/drivers/crypto/marvell/cesa.c index 80239ae..e8ef9fd 100644 --- a/drivers/crypto/marvell/cesa.c +++ b/drivers/crypto/marvell/cesa.c @@ -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; } -- cgit v1.1 From b3c2fee5d66b0d1e977de1a56243002e532da6a5 Mon Sep 17 00:00:00 2001 From: Gary R Hook Date: Wed, 20 Apr 2016 09:55:12 -0500 Subject: crypto: ccp - Ensure all dependencies are specified A DMA_ENGINE requires DMADEVICES in Kconfig Signed-off-by: Gary R Hook Signed-off-by: Herbert Xu --- drivers/crypto/ccp/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/crypto/ccp/Kconfig b/drivers/crypto/ccp/Kconfig index 79cabfb..2238f77 100644 --- a/drivers/crypto/ccp/Kconfig +++ b/drivers/crypto/ccp/Kconfig @@ -4,6 +4,7 @@ config CRYPTO_DEV_CCP_DD default m select HW_RANDOM select DMA_ENGINE + select DMADEVICES select CRYPTO_SHA1 select CRYPTO_SHA256 help -- cgit v1.1 From 3639ca840df953f9af6f15fc8a6bf77f19075ab1 Mon Sep 17 00:00:00 2001 From: Horia Geant? Date: Thu, 21 Apr 2016 19:24:55 +0300 Subject: crypto: talitos - fix ahash algorithms registration Provide hardware state import/export functionality, as mandated by commit 8996eafdcbad ("crypto: ahash - ensure statesize is non-zero") Cc: # 4.3+ Reported-by: Jonas Eymann Signed-off-by: Horia Geant? Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index a0d4a08..f3b5401 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -827,6 +827,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) { @@ -1967,6 +1977,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; @@ -2444,6 +2494,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", @@ -2459,6 +2510,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", @@ -2474,6 +2526,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", @@ -2489,6 +2542,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", @@ -2504,6 +2558,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", @@ -2519,6 +2574,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", @@ -2534,6 +2590,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", @@ -2549,6 +2606,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", @@ -2564,6 +2622,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", @@ -2579,6 +2638,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", @@ -2594,6 +2654,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", @@ -2609,6 +2670,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", @@ -2787,6 +2849,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)) { -- cgit v1.1 From b908bd3d4c4110a8a2ed84e2b6ab56fa7201db25 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 22 Apr 2016 12:56:31 +0300 Subject: crypto: mxc-scc - signedness bugs in mxc_scc_ablkcipher_req_init() ->src_nents and ->dst_nents are unsigned so they can't be less than zero. I fixed this by introducing a temporary "nents" variable. Fixes: d293b640ebd5 ('crypto: mxc-scc - add basic driver for the MXC SCC') Signed-off-by: Dan Carpenter Signed-off-by: Herbert Xu --- drivers/crypto/mxc-scc.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/crypto/mxc-scc.c b/drivers/crypto/mxc-scc.c index 38b01bf..9b348a7 100644 --- a/drivers/crypto/mxc-scc.c +++ b/drivers/crypto/mxc-scc.c @@ -210,18 +210,21 @@ static int mxc_scc_ablkcipher_req_init(struct ablkcipher_request *req, struct mxc_scc_ctx *ctx) { struct mxc_scc *scc = ctx->scc; + int nents; - ctx->src_nents = sg_nents_for_len(req->src, req->nbytes); - if (ctx->src_nents < 0) { + nents = sg_nents_for_len(req->src, req->nbytes); + if (nents < 0) { dev_err(scc->dev, "Invalid number of src SC"); - return ctx->src_nents; + return nents; } + ctx->src_nents = nents; - ctx->dst_nents = sg_nents_for_len(req->dst, req->nbytes); - if (ctx->dst_nents < 0) { + nents = sg_nents_for_len(req->dst, req->nbytes); + if (nents < 0) { dev_err(scc->dev, "Invalid number of dst SC"); - return ctx->dst_nents; + return nents; } + ctx->dst_nents = nents; ctx->size = 0; ctx->offset = 0; -- cgit v1.1 From 4c048af708a8d562d02c5a2c8f46e01de6d81e34 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 22 Apr 2016 13:01:39 +0300 Subject: crypto: mxc-scc - fix unwinding in mxc_scc_crypto_register() There are two issues here: 1) We need to decrement "i" otherwise we unregister something that was not successfully registered. 2) The original code did not unregister the first element in the array where i is zero. Fixes: d293b640ebd5 ('crypto: mxc-scc - add basic driver for the MXC SCC') Signed-off-by: Dan Carpenter Signed-off-by: Herbert Xu --- drivers/crypto/mxc-scc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/mxc-scc.c b/drivers/crypto/mxc-scc.c index 9b348a7..ff383ef 100644 --- a/drivers/crypto/mxc-scc.c +++ b/drivers/crypto/mxc-scc.c @@ -616,7 +616,7 @@ static struct mxc_scc_crypto_tmpl *scc_crypto_algs[] = { static int mxc_scc_crypto_register(struct mxc_scc *scc) { - unsigned int i; + int i; int err = 0; for (i = 0; i < ARRAY_SIZE(scc_crypto_algs); i++) { @@ -629,7 +629,7 @@ static int mxc_scc_crypto_register(struct mxc_scc *scc) return 0; err_out: - for (; i > 0; i--) + while (--i >= 0) crypto_unregister_alg(&scc_crypto_algs[i]->alg); return err; -- cgit v1.1 From 5e00c6040dfd367e35bdc7b8ef28861ff8b1dd64 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 22 Apr 2016 14:15:22 +0200 Subject: crypto: s5p-sss - Use common BIT macro The BIT() macro is obvious and well known, so prefer to use it instead of crafted own macro. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Herbert Xu --- drivers/crypto/s5p-sss.c | 95 ++++++++++++++++++++++++------------------------ 1 file changed, 47 insertions(+), 48 deletions(-) diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index 71ca6a5..b965320 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -31,45 +31,44 @@ #include #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) @@ -77,52 +76,52 @@ #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)) @@ -139,7 +138,7 @@ 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) -- cgit v1.1 From 79152e8d085fd64484afd473ef6830b45518acba Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 22 Apr 2016 14:15:23 +0200 Subject: crypto: s5p-sss - Fix missed interrupts when working with 8 kB blocks The tcrypt testing module on Exynos5422-based Odroid XU3/4 board failed on testing 8 kB size blocks: $ sudo modprobe tcrypt sec=1 mode=500 testing speed of async ecb(aes) (ecb-aes-s5p) encryption test 0 (128 bit key, 16 byte blocks): 21971 operations in 1 seconds (351536 bytes) test 1 (128 bit key, 64 byte blocks): 21731 operations in 1 seconds (1390784 bytes) test 2 (128 bit key, 256 byte blocks): 21932 operations in 1 seconds (5614592 bytes) test 3 (128 bit key, 1024 byte blocks): 21685 operations in 1 seconds (22205440 bytes) test 4 (128 bit key, 8192 byte blocks): This was caused by a race issue of missed BRDMA_DONE ("Block cipher Receiving DMA") interrupt. Device starts processing the data in DMA mode immediately after setting length of DMA block: receiving (FCBRDMAL) or transmitting (FCBTDMAL). The driver sets these lengths from interrupt handler through s5p_set_dma_indata() function (or xxx_setdata()). However the interrupt handler was first dealing with receive buffer (dma-unmap old, dma-map new, set receive block length which starts the operation), then with transmit buffer and finally was clearing pending interrupts (FCINTPEND). Because of the time window between setting receive buffer length and clearing pending interrupts, the operation on receive buffer could end already and driver would miss new interrupt. User manual for Exynos5422 confirms in example code that setting DMA block lengths should be the last operation. The tcrypt hang could be also observed in following blocked-task dmesg: INFO: task modprobe:258 blocked for more than 120 seconds. Not tainted 4.6.0-rc4-next-20160419-00005-g9eac8b7b7753-dirty #42 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. modprobe D c06b09d8 0 258 256 0x00000000 [] (__schedule) from [] (schedule+0x40/0xac) [] (schedule) from [] (schedule_timeout+0x124/0x178) [] (schedule_timeout) from [] (wait_for_common+0xb8/0x144) [] (wait_for_common) from [] (test_acipher_speed+0x49c/0x740 [tcrypt]) [] (test_acipher_speed [tcrypt]) from [] (do_test+0x2240/0x30ec [tcrypt]) [] (do_test [tcrypt]) from [] (tcrypt_mod_init+0x48/0xa4 [tcrypt]) [] (tcrypt_mod_init [tcrypt]) from [] (do_one_initcall+0x3c/0x16c) [] (do_one_initcall) from [] (do_init_module+0x5c/0x1ac) [] (do_init_module) from [] (load_module+0x1a30/0x1d08) [] (load_module) from [] (SyS_finit_module+0x8c/0x98) [] (SyS_finit_module) from [] (ret_fast_syscall+0x0/0x3c) Fixes: a49e490c7a8a ("crypto: s5p-sss - add S5PV210 advanced crypto engine support") Cc: Signed-off-by: Krzysztof Kozlowski Tested-by: Marek Szyprowski Signed-off-by: Herbert Xu --- drivers/crypto/s5p-sss.c | 53 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index b965320..ac6d62b 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -367,43 +367,55 @@ 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) @@ -412,17 +424,30 @@ 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); status = SSS_READ(dev, FCINTSTAT); if (status & SSS_FCINTSTAT_BRDMAINT) - s5p_aes_rx(dev); + set_dma_rx = s5p_aes_rx(dev); if (status & SSS_FCINTSTAT_BTDMAINT) - s5p_aes_tx(dev); + 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); return IRQ_HANDLED; -- cgit v1.1 From d1497977fecb9acce05988d6322ad415ef93bb39 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 26 Apr 2016 09:29:26 +0200 Subject: crypto: s5p-sss - fix incorrect usage of scatterlists api sg_dma_len() macro can be used only on scattelists which are mapped, so all calls to it before dma_map_sg() are invalid. Replace them by proper check for direct sg segment length read. Fixes: a49e490c7a8a ("crypto: s5p-sss - add S5PV210 advanced crypto engine support") Fixes: 9e4a1100a445 ("crypto: s5p-sss - Handle unaligned buffers") Signed-off-by: Marek Szyprowski Reviewed-by: Krzysztof Kozlowski Acked-by: Vladimir Zapolskiy Signed-off-by: Herbert Xu --- drivers/crypto/s5p-sss.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index ac6d62b..2b3a0cf 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -327,7 +327,7 @@ static int s5p_set_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg) { int err; - if (!sg_dma_len(sg)) { + if (!sg->length) { err = -EINVAL; goto exit; } @@ -349,7 +349,7 @@ static int s5p_set_indata(struct s5p_aes_dev *dev, struct scatterlist *sg) { int err; - if (!sg_dma_len(sg)) { + if (!sg->length) { err = -EINVAL; goto exit; } @@ -474,7 +474,7 @@ static void s5p_set_aes(struct s5p_aes_dev *dev, static bool s5p_is_sg_aligned(struct scatterlist *sg) { while (sg) { - if (!IS_ALIGNED(sg_dma_len(sg), AES_BLOCK_SIZE)) + if (!IS_ALIGNED(sg->length, AES_BLOCK_SIZE)) return false; sg = sg_next(sg); } -- cgit v1.1 From f1b77aaca85a610948f02d11288845f4cfe7d3eb Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Thu, 28 Apr 2016 14:11:51 +0800 Subject: crypto: omap-des - Integrate with the crypto engine framework Since the crypto engine framework had been merged, thus this patch integrates with the newly added crypto engine framework to make the crypto hardware engine under utilized as each block needs to be processed before the crypto hardware can start working on the next block. The crypto engine framework can manage and process the requests automatically, so remove the 'queue' and 'queue_task' things in omap des driver. Signed-off-by: Baolin Signed-off-by: Herbert Xu --- drivers/crypto/Kconfig | 1 + drivers/crypto/omap-des.c | 97 +++++++++++++++++++++-------------------------- 2 files changed, 44 insertions(+), 54 deletions(-) diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 12fd499..d77ba2f 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -314,6 +314,7 @@ config CRYPTO_DEV_OMAP_DES 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 diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c index dd7b93f..b9a465f 100644 --- a/drivers/crypto/omap-des.c +++ b/drivers/crypto/omap-des.c @@ -39,6 +39,7 @@ #include #include #include +#include #define DST_MAXBURST 2 @@ -132,14 +133,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 @@ -520,9 +517,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 +580,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 +627,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); +} - return ret; /* return ret, which is enqueue return value */ +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 omap_des_crypt_dma_start(dd); } static void omap_des_done_task(unsigned long data) @@ -683,18 +672,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( @@ -1062,9 +1043,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,7 +1081,6 @@ 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)) { @@ -1144,7 +1121,21 @@ 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--) @@ -1154,7 +1145,6 @@ err_algs: 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 +1172,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; -- cgit v1.1 From da8b29a6c1894874b681f42186c61c58c09e0b56 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 29 Apr 2016 16:02:18 +0300 Subject: crypto: omap-aes - Use dma_request_chan() for requesting DMA channel With the new dma_request_chan() the client driver does not need to look for the DMA resource and it does not need to pass filter_fn anymore. By switching to the new API the driver can now support deferred probing against DMA. Signed-off-by: Peter Ujfalusi CC: Herbert Xu CC: David S. Miller CC: Lokesh Vutla Signed-off-by: Herbert Xu --- drivers/crypto/omap-aes.c | 62 ++++++++++++----------------------------------- 1 file changed, 16 insertions(+), 46 deletions(-) diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index d420ec7..ce174d3 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -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); -- cgit v1.1 From 2f6f0680c78e2bc35f576ea956b284aa45cef0d1 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 29 Apr 2016 16:02:56 +0300 Subject: crypto: omap-des - Use dma_request_chan() for requesting DMA channel With the new dma_request_chan() the client driver does not need to look for the DMA resource and it does not need to pass filter_fn anymore. By switching to the new API the driver can now support deferred probing against DMA. Signed-off-by: Peter Ujfalusi CC: Herbert Xu CC: David S. Miller CC: Lokesh Vutla Signed-off-by: Herbert Xu --- drivers/crypto/omap-des.c | 68 ++++++++++++----------------------------------- 1 file changed, 17 insertions(+), 51 deletions(-) diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c index b9a465f..3eedb03 100644 --- a/drivers/crypto/omap-des.c +++ b/drivers/crypto/omap-des.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -155,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; @@ -337,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; } @@ -368,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); } @@ -980,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; @@ -997,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) @@ -1083,7 +1047,9 @@ static int omap_des_probe(struct platform_device *pdev) tasklet_init(&dd->done_task, omap_des_done_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); @@ -1141,8 +1107,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_des_dma_cleanup(dd); + + omap_des_dma_cleanup(dd); err_irq: tasklet_kill(&dd->done_task); err_get: -- cgit v1.1 From dbe246209bc1a2a870250499b8f584251838d5b4 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 29 Apr 2016 16:03:41 +0300 Subject: crypto: omap-sham - Use dma_request_chan() for requesting DMA channel With the new dma_request_chan() the client driver does not need to look for the DMA resource and it does not need to pass filter_fn anymore. By switching to the new API the driver can now support deferred probing against DMA. Signed-off-by: Peter Ujfalusi CC: Herbert Xu CC: David S. Miller CC: Lokesh Vutla Signed-off-by: Herbert Xu --- drivers/crypto/omap-sham.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index 48adb2a..6eefaa2 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -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; -- cgit v1.1 From ccab6058daa4933def4194b8ff6a4bb33c7f2a97 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 29 Apr 2016 17:48:08 +0300 Subject: lib: asn1_decoder - add MODULE_LICENSE("GPL") A kernel taint results when loading the rsa_generic module: root@(none):~# modprobe rsa_generic asn1_decoder: module license 'unspecified' taints kernel. Disabling lock debugging due to kernel taint "Tainting" of the kernel is (usually) a way of indicating that a proprietary module has been inserted, which is not the case here. Signed-off-by: Tudor Ambarus Signed-off-by: Herbert Xu --- lib/asn1_decoder.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/asn1_decoder.c b/lib/asn1_decoder.c index 2b3f46c..b1ffcab 100644 --- a/lib/asn1_decoder.c +++ b/lib/asn1_decoder.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -504,3 +505,5 @@ error: return -EBADMSG; } EXPORT_SYMBOL_GPL(asn1_ber_decoder); + +MODULE_LICENSE("GPL"); -- cgit v1.1 From cca0a7b0ac7fd905a9db6c724dab87e6e6bbee00 Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Fri, 29 Apr 2016 10:59:59 -0700 Subject: crypto: qat - Fix typo in comments Fix copy and paste typo adf_isr.c Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_isr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_isr.c b/drivers/crypto/qat/qat_common/adf_isr.c index b81f79a..06d4901 100644 --- a/drivers/crypto/qat/qat_common/adf_isr.c +++ b/drivers/crypto/qat/qat_common/adf_isr.c @@ -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. -- cgit v1.1 From d0c15bd5067ec75d8738f4d4ba1e5e3ab0ea6f2d Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Fri, 29 Apr 2016 11:00:00 -0700 Subject: crypto: qat - make adf_vf_isr.c dependant on IOV config The adf_vf_isr.c should only be build if CONFIG_PCI_IOV is enabled Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/Makefile | 4 ++-- drivers/crypto/qat/qat_common/adf_common_drv.h | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/qat/qat_common/Makefile b/drivers/crypto/qat/qat_common/Makefile index 5873d22..6d74b91 100644 --- a/drivers/crypto/qat/qat_common/Makefile +++ b/drivers/crypto/qat/qat_common/Makefile @@ -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 adf_vf2pf_msg.o +intel_qat-$(CONFIG_PCI_IOV) += adf_sriov.o adf_pf2vf_msg.o \ + adf_vf2pf_msg.o adf_vf_isr.o diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h index 35ffa940..75faa39 100644 --- a/drivers/crypto/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/qat/qat_common/adf_common_drv.h @@ -144,8 +144,6 @@ void adf_disable_aer(struct adf_accel_dev *accel_dev); void adf_dev_restore(struct adf_accel_dev *accel_dev); int adf_init_aer(void); void adf_exit_aer(void); -int adf_init_vf_wq(void); -void adf_exit_vf_wq(void); int adf_init_admin_comms(struct adf_accel_dev *accel_dev); void adf_exit_admin_comms(struct adf_accel_dev *accel_dev); int adf_send_admin_init(struct adf_accel_dev *accel_dev); @@ -243,6 +241,8 @@ 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) { @@ -278,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 -- cgit v1.1 From 472d640bd0fe5b28332b277316cff1dadf40d083 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 29 Apr 2016 22:09:11 +0200 Subject: crypto: marvell/cesa - Use dma_pool_zalloc Dma_pool_zalloc combines dma_pool_alloc and memset 0. The semantic patch that makes this transformation is as follows: (http://coccinelle.lip6.fr/) // @@ expression d,e; statement S; @@ d = - dma_pool_alloc + dma_pool_zalloc (...); if (!d) S - memset(d, 0, sizeof(*d)); // Signed-off-by: Julia Lawall Acked-by: Boris Brezillon Signed-off-by: Herbert Xu --- drivers/crypto/marvell/tdma.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/marvell/tdma.c b/drivers/crypto/marvell/tdma.c index 7642798..0ad8f1e 100644 --- a/drivers/crypto/marvell/tdma.c +++ b/drivers/crypto/marvell/tdma.c @@ -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); -- cgit v1.1 From bc197b2a9c7e0129fa0ec1961881e2a0b3bef967 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 1 May 2016 13:52:55 +0200 Subject: crypto: ccp - constify ccp_actions structure The ccp_actions structure is never modified, so declare it as const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Acked-by: Gary Hook Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-dev-v3.c | 2 +- drivers/crypto/ccp/ccp-dev.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/ccp/ccp-dev-v3.c b/drivers/crypto/ccp/ccp-dev-v3.c index 597fc50..d7a7103 100644 --- a/drivers/crypto/ccp/ccp-dev-v3.c +++ b/drivers/crypto/ccp/ccp-dev-v3.c @@ -526,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, diff --git a/drivers/crypto/ccp/ccp-dev.h b/drivers/crypto/ccp/ccp-dev.h index 5d986c9..bd41ffce 100644 --- a/drivers/crypto/ccp/ccp-dev.h +++ b/drivers/crypto/ccp/ccp-dev.h @@ -162,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; -- cgit v1.1 From 9e5c9fe4cbb89b9af1fcf317f7b39d993bb47a71 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 3 May 2016 10:00:17 +0100 Subject: crypto: testmgr - Add a flag allowing the self-tests to be disabled at runtime. Running self-tests for a short-lived KVM VM takes 28ms on my laptop. This commit adds a flag 'cryptomgr.notests' which allows them to be disabled. However if fips=1 as well, we ignore this flag as FIPS mode mandates that the self-tests are run. Signed-off-by: Richard W.M. Jones Signed-off-by: Herbert Xu --- Documentation/kernel-parameters.txt | 3 +++ crypto/testmgr.c | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index ecc74fa..c799c04 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -826,6 +826,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: diff --git a/crypto/testmgr.c b/crypto/testmgr.c index b86883a..fcd89fe 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -35,6 +35,10 @@ #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 */ @@ -3868,6 +3872,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) { -- cgit v1.1 From 5ca55738201c7ae1b556ad87bbb22c139ecc01dd Mon Sep 17 00:00:00 2001 From: Paulo Flabiano Smorigo Date: Thu, 5 May 2016 11:09:27 -0300 Subject: crypto: vmx - comply with ABIs that specify vrsave as reserved. It gives significant improvements ( ~+15%) on some modes. These code has been adopted from OpenSSL project in collaboration with the original author (Andy Polyakov ). Signed-off-by: Paulo Flabiano Smorigo Signed-off-by: Herbert Xu --- drivers/crypto/vmx/ppc-xlate.pl | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/crypto/vmx/ppc-xlate.pl b/drivers/crypto/vmx/ppc-xlate.pl index b999733..9f4994c 100644 --- a/drivers/crypto/vmx/ppc-xlate.pl +++ b/drivers/crypto/vmx/ppc-xlate.pl @@ -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) = @_; -- cgit v1.1 From e930c765ca5c6b039cd22ebfb4504ea7b5dab43d Mon Sep 17 00:00:00 2001 From: Catalin Vasile Date: Fri, 6 May 2016 16:18:53 +0300 Subject: crypto: caam - fix caam_jr_alloc() ret code caam_jr_alloc() used to return NULL if a JR device could not be allocated for a session. In turn, every user of this function used IS_ERR() function to verify if anything went wrong, which does NOT look for NULL values. This made the kernel crash if the sanity check failed, because the driver continued to think it had allocated a valid JR dev instance to the session and at some point it tries to do a caam_jr_free() on a NULL JR dev pointer. This patch is a fix for this issue. Cc: Signed-off-by: Catalin Vasile Signed-off-by: Herbert Xu --- drivers/crypto/caam/jr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c index 6fd63a6..5ef4be2 100644 --- a/drivers/crypto/caam/jr.c +++ b/drivers/crypto/caam/jr.c @@ -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; -- cgit v1.1 From 256b1cfb9a346bb4808cd27b7b8f9b120f96491e Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Wed, 11 May 2016 13:21:29 -0700 Subject: crypto: qat - change the adf_ctl_stop_devices to void Change the adf_ctl_stop_devices to a void function. Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_ctl_drv.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/qat/qat_common/adf_ctl_drv.c index db21b49..abc7a7f 100644 --- a/drivers/crypto/qat/qat_common/adf_ctl_drv.c +++ b/drivers/crypto/qat/qat_common/adf_ctl_drv.c @@ -270,10 +270,9 @@ 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(accel_dev, adf_devmgr_get_head(), list) { if (id == accel_dev->accel_id || id == ADF_CFG_ALL_DEVICES) { @@ -298,7 +297,6 @@ static int adf_ctl_stop_devices(uint32_t id) adf_dev_shutdown(accel_dev); } } - return ret; } static int adf_ctl_ioctl_dev_stop(struct file *fp, unsigned int cmd, @@ -327,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; -- cgit v1.1