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(-) (limited to 'drivers') diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 477fffdb4f49..41f194b92d34 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c index ada081232528..d1fd21e99368 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c index d1fd21e99368..38b80f82ddd2 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c index 38b80f82ddd2..71b45b153cf2 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.2.3 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(+) (limited to 'drivers') diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c index 71b45b153cf2..ed78f25e4ec6 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 67ee8b08ab53..3c5be60befce 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 41f194b92d34..8c141f01f29c 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index b85a7a7dbf63..c5aac25a5738 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/marvell/hash.c b/drivers/crypto/marvell/hash.c index 7ca2e0f9dc2e..7a5058da9151 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index 5f161a9777e3..60f835455a41 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index 60f835455a41..3730fb0af4d8 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index 3730fb0af4d8..4f6d5b3ec418 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/adf_admin.c b/drivers/crypto/qat/qat_common/adf_admin.c index eb557f69e367..ce7c4626c983 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/adf_cfg_strings.h b/drivers/crypto/qat/qat_common/adf_cfg_strings.h index 13575111382c..7632ed0f25c5 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/qat_asym_algs.c b/drivers/crypto/qat/qat_common/qat_asym_algs.c index e5c0727d4876..8dbbf0849436 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/qat_asym_algs.c b/drivers/crypto/qat/qat_common/qat_asym_algs.c index 8dbbf0849436..05f49d4f94b2 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c b/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c index 7be3fbcd8d78..3830d7c4e138 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/qat/qat_common/adf_ctl_drv.c index 5c897e6e7994..740335630c57 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_c3xxx/adf_drv.c b/drivers/crypto/qat/qat_c3xxx/adf_drv.c index e13bd08ddd1e..640c3fc870fd 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 1ac4ae90e072..a998981e9610 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 512c56509718..bc5cbc193aae 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 d2e4b928f3be..ccfb25e8a4a1 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 0e82ce3c383e..c9e4d469e930 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 740335630c57..48a1248381b3 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 ef5575e4a215..a29470bc8539 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 1117a8b58280..4479b0b63296 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 a8c4b92a7cbd..4d2de2838451 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 f8cc4bf0a50c..1bf753244230 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c index ed78f25e4ec6..ed44561ea647 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c index 4dbc18727235..87b9f2bfa623 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h index c9e4d469e930..fd096eda880f 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 48a1248381b3..116ddda75e27 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 09427b3d4d55..c3d501681466 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.2.3 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 (limited to 'drivers') diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 8c141f01f29c..0a22ac7db360 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 713de9d11148..3c6432dd09d9 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 000000000000..38b01bf141d3 --- /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.2.3 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 (limited to 'drivers') diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 3c5be60befce..c76a88da8d04 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 f5a6fa7690e7..e09305bb89e1 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 000000000000..40d96572c591 --- /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.2.3 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 (limited to 'drivers') 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 1af321c2ce1a..d2d0ae445fd8 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 baf4b509c892..38e4bc04f407 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 29c7c53d2845..5873d22fc6cd 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 fd096eda880f..a8100a37ee0c 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 000000000000..5f1d863ae802 --- /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 dc04ab68d24d..a3b4dd8099a7 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c b/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c index a998981e9610..949d77b79fbe 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 ccfb25e8a4a1..7540ce13b0d0 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 a8100a37ee0c..557ea361d385 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 5f1d863ae802..cd5f37dffe8a 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 c3d501681466..5d45796576ee 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 1bf753244230..60df98632fa2 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/adf_init.c b/drivers/crypto/qat/qat_common/adf_init.c index a29470bc8539..888c6675e7e5 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/adf_vf_isr.c b/drivers/crypto/qat/qat_common/adf_vf_isr.c index 5d45796576ee..aa689cabedb4 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.2.3 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 (limited to 'drivers') diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index c76a88da8d04..ac51149e9777 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 e09305bb89e1..63022b49f160 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 c0db4387d2e2..000000000000 --- 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 0a22ac7db360..12fd49950f47 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 5c0c62b65d69..b95539928fdf 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 62134c8a2260..dae1e39139e9 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 bac0bdeb4b5f..ecfdcfe3698d 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 5f5fbc0716ff..46fe57c8f6eb 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 000000000000..677ca17fd223 --- /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 000000000000..931d22531f51 --- /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.2.3 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 (limited to 'drivers') diff --git a/drivers/crypto/ccp/Kconfig b/drivers/crypto/ccp/Kconfig index 6e37845abf8f..79cabfba2a2a 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 b750592cc936..ee4d2741b3ab 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 7d5eab49179e..597fc50bdaa6 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 7745d0be491d..5d986c9d72eb 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; @@ -260,6 +296,14 @@ struct ccp_device { struct hwrng hwrng; unsigned int hwrng_retries; + /* + * Support for the CCP DMA capabilities + */ + struct dma_device dma_dev; + struct ccp_dma_chan *ccp_dma_chan; + struct kmem_cache *dma_cmd_cache; + struct kmem_cache *dma_desc_cache; + /* * A counter used to generate job-ids for cmds submitted to the CCP */ @@ -418,4 +462,7 @@ int ccp_cmd_queue_thread(void *data); int ccp_run_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd); +int ccp_dmaengine_register(struct ccp_device *ccp); +void ccp_dmaengine_unregister(struct ccp_device *ccp); + #endif diff --git a/drivers/crypto/ccp/ccp-dmaengine.c b/drivers/crypto/ccp/ccp-dmaengine.c new file mode 100644 index 000000000000..94f77b0f9ae7 --- /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 eefdf595f758..ffa2891035ac 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 915af3095b39..7c2bb27c067c 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index 4f6d5b3ec418..b0484d4d68d9 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.2.3 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(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/crypto/samsung-sss.txt b/Documentation/devicetree/bindings/crypto/samsung-sss.txt index a6dafa83c6df..7a5ca56683cc 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 b0484d4d68d9..71ca6a5d636d 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/marvell/cesa.c b/drivers/crypto/marvell/cesa.c index 80239ae69527..e8ef9fd24a16 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.2.3 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(+) (limited to 'drivers') diff --git a/drivers/crypto/ccp/Kconfig b/drivers/crypto/ccp/Kconfig index 79cabfba2a2a..2238f77aa248 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.2.3 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(+) (limited to 'drivers') diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index a0d4a08313ae..f3b540153d0f 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/mxc-scc.c b/drivers/crypto/mxc-scc.c index 38b01bf141d3..9b348a78dd23 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/mxc-scc.c b/drivers/crypto/mxc-scc.c index 9b348a78dd23..ff383ef83871 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index 71ca6a5d636d..b96532078d0c 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index b96532078d0c..ac6d62b3be07 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index ac6d62b3be07..2b3a0cfe3331 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 12fd49950f47..d77ba2f12242 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 dd7b93f2f94c..b9a465fc2300 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index d420ec751c7c..ce174d3b842c 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c index b9a465fc2300..3eedb03111ba 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index 48adb2a0903e..6eefaa2fe58f 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/adf_isr.c b/drivers/crypto/qat/qat_common/adf_isr.c index b81f79acc4ea..06d49017a52b 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/Makefile b/drivers/crypto/qat/qat_common/Makefile index 5873d22fc6cd..6d74b91f2152 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 35ffa940989b..75faa39bc8d0 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/marvell/tdma.c b/drivers/crypto/marvell/tdma.c index 76427981275b..0ad8f1ecf175 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/ccp/ccp-dev-v3.c b/drivers/crypto/ccp/ccp-dev-v3.c index 597fc50bdaa6..d7a710347967 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 5d986c9d72eb..bd41ffceff82 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.2.3 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(+) (limited to 'drivers') diff --git a/drivers/crypto/vmx/ppc-xlate.pl b/drivers/crypto/vmx/ppc-xlate.pl index b9997335f193..9f4994cabcc7 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c index 6fd63a600614..5ef4be22eb80 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.2.3 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(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/qat/qat_common/adf_ctl_drv.c index db21b499cc1d..abc7a7f64d64 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.2.3