From 5343e674f32fb82b7a80a24b5a84eee62d3fe624 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 18 Apr 2016 12:57:41 +0200 Subject: [PATCH] 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 --- 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 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -22,7 +22,6 @@ obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939 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 --- 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"); --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -277,6 +277,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 --- 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 --- 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" @@ -1230,6 +1231,7 @@ static int crypto4xx_probe(struct platfo if (rc) goto err_start_dev; + ppc4xx_trng_probe(core_dev); return 0; err_start_dev: @@ -1256,6 +1258,8 @@ static int crypto4xx_remove(struct platf 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); @@ -1276,7 +1280,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, @@ -1288,4 +1292,3 @@ module_platform_driver(crypto4xx_driver) MODULE_LICENSE("GPL"); MODULE_AUTHOR("James Hsiao "); MODULE_DESCRIPTION("Driver for AMCC PPC4xx crypto accelerator"); - --- 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; --- 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 --- /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"); --- /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