Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6

Pull crypto updates from Herbert Xu:
 "API:
   - Add library interfaces of certain crypto algorithms for WireGuard
   - Remove the obsolete ablkcipher and blkcipher interfaces
   - Move add_early_randomness() out of rng_mutex

  Algorithms:
   - Add blake2b shash algorithm
   - Add blake2s shash algorithm
   - Add curve25519 kpp algorithm
   - Implement 4 way interleave in arm64/gcm-ce
   - Implement ciphertext stealing in powerpc/spe-xts
   - Add Eric Biggers's scalar accelerated ChaCha code for ARM
   - Add accelerated 32r2 code from Zinc for MIPS
   - Add OpenSSL/CRYPTOGRAMS poly1305 implementation for ARM and MIPS

  Drivers:
   - Fix entropy reading failures in ks-sa
   - Add support for sam9x60 in atmel
   - Add crypto accelerator for amlogic GXL
   - Add sun8i-ce Crypto Engine
   - Add sun8i-ss cryptographic offloader
   - Add a host of algorithms to inside-secure
   - Add NPCM RNG driver
   - add HiSilicon HPRE accelerator
   - Add HiSilicon TRNG driver"

* git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6: (285 commits)
  crypto: vmx - Avoid weird build failures
  crypto: lib/chacha20poly1305 - use chacha20_crypt()
  crypto: x86/chacha - only unregister algorithms if registered
  crypto: chacha_generic - remove unnecessary setkey() functions
  crypto: amlogic - enable working on big endian kernel
  crypto: sun8i-ce - enable working on big endian
  crypto: mips/chacha - select CRYPTO_SKCIPHER, not CRYPTO_BLKCIPHER
  hwrng: ks-sa - Enable COMPILE_TEST
  crypto: essiv - remove redundant null pointer check before kfree
  crypto: atmel-aes - Change data type for "lastc" buffer
  crypto: atmel-tdes - Set the IV after {en,de}crypt
  crypto: sun4i-ss - fix big endian issues
  crypto: sun4i-ss - hide the Invalid keylen message
  crypto: sun4i-ss - use crypto_ahash_digestsize
  crypto: sun4i-ss - remove dependency on not 64BIT
  crypto: sun4i-ss - Fix 64-bit size_t warnings on sun4i-ss-hash.c
  MAINTAINERS: Add maintainer for HiSilicon SEC V2 driver
  crypto: hisilicon - add DebugFS for HiSilicon SEC
  Documentation: add DebugFS doc for HiSilicon SEC
  crypto: hisilicon - add SRIOV for HiSilicon SEC
  ...
Esse commit está contido em:
Linus Torvalds
2019-11-25 19:49:58 -08:00
291 arquivos alterados com 46877 adições e 11162 exclusões

Ver arquivo

@@ -308,6 +308,19 @@ config HW_RANDOM_HISI
If unsure, say Y.
config HW_RANDOM_HISI_V2
tristate "HiSilicon True Random Number Generator V2 support"
depends on HW_RANDOM && ARM64 && ACPI
default HW_RANDOM
help
This driver provides kernel-side support for the True Random Number
Generator V2 hardware found on HiSilicon Hi1620 SoC.
To compile this driver as a module, choose M here: the
module will be called hisi-trng-v2.
If unsure, say Y.
config HW_RANDOM_ST
tristate "ST Microelectronics HW Random Number Generator support"
depends on HW_RANDOM && ARCH_STI
@@ -440,6 +453,19 @@ config HW_RANDOM_OPTEE
If unsure, say Y.
config HW_RANDOM_NPCM
tristate "NPCM Random Number Generator support"
depends on ARCH_NPCM || COMPILE_TEST
default HW_RANDOM
help
This driver provides support for the Random Number
Generator hardware available in Nuvoton NPCM SoCs.
To compile this driver as a module, choose M here: the
module will be called npcm-rng.
If unsure, say Y.
endif # HW_RANDOM
config UML_RANDOM
@@ -458,7 +484,7 @@ config UML_RANDOM
/dev/hwrng and injects the entropy into /dev/random.
config HW_RANDOM_KEYSTONE
depends on ARCH_KEYSTONE
depends on ARCH_KEYSTONE || COMPILE_TEST
default HW_RANDOM
tristate "TI Keystone NETCP SA Hardware random number generator"
help

Ver arquivo

@@ -27,6 +27,7 @@ obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
obj-$(CONFIG_HW_RANDOM_HISI) += hisi-rng.o
obj-$(CONFIG_HW_RANDOM_HISI_V2) += hisi-trng-v2.o
obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
obj-$(CONFIG_HW_RANDOM_ST) += st-rng.o
@@ -39,3 +40,4 @@ obj-$(CONFIG_HW_RANDOM_MTK) += mtk-rng.o
obj-$(CONFIG_HW_RANDOM_S390) += s390-trng.o
obj-$(CONFIG_HW_RANDOM_KEYSTONE) += ks-sa-rng.o
obj-$(CONFIG_HW_RANDOM_OPTEE) += optee-rng.o
obj-$(CONFIG_HW_RANDOM_NPCM) += npcm-rng.o

Ver arquivo

@@ -14,14 +14,22 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/hw_random.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#define TRNG_CR 0x00
#define TRNG_MR 0x04
#define TRNG_ISR 0x1c
#define TRNG_ODATA 0x50
#define TRNG_KEY 0x524e4700 /* RNG */
#define TRNG_HALFR BIT(0) /* generate RN every 168 cycles */
struct atmel_trng_data {
bool has_half_rate;
};
struct atmel_trng {
struct clk *clk;
void __iomem *base;
@@ -62,21 +70,31 @@ static void atmel_trng_disable(struct atmel_trng *trng)
static int atmel_trng_probe(struct platform_device *pdev)
{
struct atmel_trng *trng;
struct resource *res;
const struct atmel_trng_data *data;
int ret;
trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
if (!trng)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
trng->base = devm_ioremap_resource(&pdev->dev, res);
trng->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(trng->base))
return PTR_ERR(trng->base);
trng->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(trng->clk))
return PTR_ERR(trng->clk);
data = of_device_get_match_data(&pdev->dev);
if (!data)
return -ENODEV;
if (data->has_half_rate) {
unsigned long rate = clk_get_rate(trng->clk);
/* if peripheral clk is above 100MHz, set HALFR */
if (rate > 100000000)
writel(TRNG_HALFR, trng->base + TRNG_MR);
}
ret = clk_prepare_enable(trng->clk);
if (ret)
@@ -141,9 +159,24 @@ static const struct dev_pm_ops atmel_trng_pm_ops = {
};
#endif /* CONFIG_PM */
static const struct atmel_trng_data at91sam9g45_config = {
.has_half_rate = false,
};
static const struct atmel_trng_data sam9x60_config = {
.has_half_rate = true,
};
static const struct of_device_id atmel_trng_dt_ids[] = {
{ .compatible = "atmel,at91sam9g45-trng" },
{ /* sentinel */ }
{
.compatible = "atmel,at91sam9g45-trng",
.data = &at91sam9g45_config,
}, {
.compatible = "microchip,sam9x60-trng",
.data = &sam9x60_config,
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(of, atmel_trng_dt_ids);

Ver arquivo

@@ -142,7 +142,6 @@ static int bcm2835_rng_probe(struct platform_device *pdev)
struct device_node *np = dev->of_node;
const struct of_device_id *rng_id;
struct bcm2835_rng_priv *priv;
struct resource *r;
int err;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -151,10 +150,8 @@ static int bcm2835_rng_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
/* map peripheral */
priv->base = devm_ioremap_resource(dev, r);
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);

Ver arquivo

@@ -111,6 +111,14 @@ static void drop_current_rng(void)
}
/* Returns ERR_PTR(), NULL or refcounted hwrng */
static struct hwrng *get_current_rng_nolock(void)
{
if (current_rng)
kref_get(&current_rng->ref);
return current_rng;
}
static struct hwrng *get_current_rng(void)
{
struct hwrng *rng;
@@ -118,9 +126,7 @@ static struct hwrng *get_current_rng(void)
if (mutex_lock_interruptible(&rng_mutex))
return ERR_PTR(-ERESTARTSYS);
rng = current_rng;
if (rng)
kref_get(&rng->ref);
rng = get_current_rng_nolock();
mutex_unlock(&rng_mutex);
return rng;
@@ -155,8 +161,6 @@ static int hwrng_init(struct hwrng *rng)
reinit_completion(&rng->cleanup_done);
skip_init:
add_early_randomness(rng);
current_quality = rng->quality ? : default_quality;
if (current_quality > 1024)
current_quality = 1024;
@@ -320,12 +324,13 @@ static ssize_t hwrng_attr_current_store(struct device *dev,
const char *buf, size_t len)
{
int err = -ENODEV;
struct hwrng *rng;
struct hwrng *rng, *old_rng, *new_rng;
err = mutex_lock_interruptible(&rng_mutex);
if (err)
return -ERESTARTSYS;
old_rng = current_rng;
if (sysfs_streq(buf, "")) {
err = enable_best_rng();
} else {
@@ -337,9 +342,15 @@ static ssize_t hwrng_attr_current_store(struct device *dev,
}
}
}
new_rng = get_current_rng_nolock();
mutex_unlock(&rng_mutex);
if (new_rng) {
if (new_rng != old_rng)
add_early_randomness(new_rng);
put_rng(new_rng);
}
return err ? : len;
}
@@ -457,13 +468,15 @@ static void start_khwrngd(void)
int hwrng_register(struct hwrng *rng)
{
int err = -EINVAL;
struct hwrng *old_rng, *tmp;
struct hwrng *tmp;
struct list_head *rng_list_ptr;
bool is_new_current = false;
if (!rng->name || (!rng->data_read && !rng->read))
goto out;
mutex_lock(&rng_mutex);
/* Must not register two RNGs with the same name. */
err = -EEXIST;
list_for_each_entry(tmp, &rng_list, list) {
@@ -482,10 +495,8 @@ int hwrng_register(struct hwrng *rng)
}
list_add_tail(&rng->list, rng_list_ptr);
old_rng = current_rng;
err = 0;
if (!old_rng ||
(!cur_rng_set_by_user && rng->quality > old_rng->quality)) {
if (!current_rng ||
(!cur_rng_set_by_user && rng->quality > current_rng->quality)) {
/*
* Set new rng as current as the new rng source
* provides better entropy quality and was not
@@ -494,19 +505,26 @@ int hwrng_register(struct hwrng *rng)
err = set_current_rng(rng);
if (err)
goto out_unlock;
/* to use current_rng in add_early_randomness() we need
* to take a ref
*/
is_new_current = true;
kref_get(&rng->ref);
}
if (old_rng && !rng->init) {
mutex_unlock(&rng_mutex);
if (is_new_current || !rng->init) {
/*
* Use a new device's input to add some randomness to
* the system. If this rng device isn't going to be
* used right away, its init function hasn't been
* called yet; so only use the randomness from devices
* that don't need an init callback.
* called yet by set_current_rng(); so only use the
* randomness from devices that don't need an init callback
*/
add_early_randomness(rng);
}
if (is_new_current)
put_rng(rng);
return 0;
out_unlock:
mutex_unlock(&rng_mutex);
out:
@@ -516,10 +534,12 @@ EXPORT_SYMBOL_GPL(hwrng_register);
void hwrng_unregister(struct hwrng *rng)
{
struct hwrng *old_rng, *new_rng;
int err;
mutex_lock(&rng_mutex);
old_rng = current_rng;
list_del(&rng->list);
if (current_rng == rng) {
err = enable_best_rng();
@@ -529,6 +549,7 @@ void hwrng_unregister(struct hwrng *rng)
}
}
new_rng = get_current_rng_nolock();
if (list_empty(&rng_list)) {
mutex_unlock(&rng_mutex);
if (hwrng_fill)
@@ -536,6 +557,12 @@ void hwrng_unregister(struct hwrng *rng)
} else
mutex_unlock(&rng_mutex);
if (new_rng) {
if (old_rng != new_rng)
add_early_randomness(new_rng);
put_rng(new_rng);
}
wait_for_completion(&rng->cleanup_done);
}
EXPORT_SYMBOL_GPL(hwrng_unregister);

Ver arquivo

@@ -109,7 +109,6 @@ static int exynos_trng_init(struct hwrng *rng)
static int exynos_trng_probe(struct platform_device *pdev)
{
struct exynos_trng_dev *trng;
struct resource *res;
int ret = -ENOMEM;
trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
@@ -128,8 +127,7 @@ static int exynos_trng_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, trng);
trng->dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
trng->mem = devm_ioremap_resource(&pdev->dev, res);
trng->mem = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(trng->mem))
return PTR_ERR(trng->mem);

Ver arquivo

@@ -73,7 +73,6 @@ static int hisi_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
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);
@@ -82,8 +81,7 @@ static int hisi_rng_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, rng);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
rng->base = devm_ioremap_resource(&pdev->dev, res);
rng->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(rng->base))
return PTR_ERR(rng->base);

Ver arquivo

@@ -0,0 +1,99 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2019 HiSilicon Limited. */
#include <linux/acpi.h>
#include <linux/err.h>
#include <linux/hw_random.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/random.h>
#define HISI_TRNG_REG 0x00F0
#define HISI_TRNG_BYTES 4
#define HISI_TRNG_QUALITY 512
#define SLEEP_US 10
#define TIMEOUT_US 10000
struct hisi_trng {
void __iomem *base;
struct hwrng rng;
};
static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
{
struct hisi_trng *trng;
int currsize = 0;
u32 val = 0;
u32 ret;
trng = container_of(rng, struct hisi_trng, rng);
do {
ret = readl_poll_timeout(trng->base + HISI_TRNG_REG, val,
val, SLEEP_US, TIMEOUT_US);
if (ret)
return currsize;
if (max - currsize >= HISI_TRNG_BYTES) {
memcpy(buf + currsize, &val, HISI_TRNG_BYTES);
currsize += HISI_TRNG_BYTES;
if (currsize == max)
return currsize;
continue;
}
/* copy remaining bytes */
memcpy(buf + currsize, &val, max - currsize);
currsize = max;
} while (currsize < max);
return currsize;
}
static int hisi_trng_probe(struct platform_device *pdev)
{
struct hisi_trng *trng;
int ret;
trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
if (!trng)
return -ENOMEM;
trng->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(trng->base))
return PTR_ERR(trng->base);
trng->rng.name = pdev->name;
trng->rng.read = hisi_trng_read;
trng->rng.quality = HISI_TRNG_QUALITY;
ret = devm_hwrng_register(&pdev->dev, &trng->rng);
if (ret)
dev_err(&pdev->dev, "failed to register hwrng!\n");
return ret;
}
static const struct acpi_device_id hisi_trng_acpi_match[] = {
{ "HISI02B3", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, hisi_trng_acpi_match);
static struct platform_driver hisi_trng_driver = {
.probe = hisi_trng_probe,
.driver = {
.name = "hisi-trng-v2",
.acpi_match_table = ACPI_PTR(hisi_trng_acpi_match),
},
};
module_platform_driver(hisi_trng_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Weili Qian <qianweili@huawei.com>");
MODULE_AUTHOR("Zaibo Xu <xuzaibo@huawei.com>");
MODULE_DESCRIPTION("HiSilicon true random number generator V2 driver");

Ver arquivo

@@ -181,7 +181,6 @@ static void iproc_rng200_cleanup(struct hwrng *rng)
static int iproc_rng200_probe(struct platform_device *pdev)
{
struct iproc_rng200_dev *priv;
struct resource *res;
struct device *dev = &pdev->dev;
int ret;
@@ -190,13 +189,7 @@ static int iproc_rng200_probe(struct platform_device *pdev)
return -ENOMEM;
/* Map peripheral */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "failed to get rng resources\n");
return -EINVAL;
}
priv->base = devm_ioremap_resource(dev, res);
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base)) {
dev_err(dev, "failed to remap rng regs\n");
return PTR_ERR(priv->base);

Ver arquivo

@@ -21,6 +21,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/delay.h>
#include <linux/timekeeping.h>
#define SA_CMD_STATUS_OFS 0x8
@@ -84,14 +85,37 @@ struct ks_sa_rng {
struct hwrng rng;
struct clk *clk;
struct regmap *regmap_cfg;
struct trng_regs *reg_rng;
struct trng_regs __iomem *reg_rng;
u64 ready_ts;
unsigned int refill_delay_ns;
};
static unsigned int cycles_to_ns(unsigned long clk_rate, unsigned int cycles)
{
return DIV_ROUND_UP_ULL((TRNG_DEF_CLK_DIV_CYCLES + 1) * 1000000000ull *
cycles, clk_rate);
}
static unsigned int startup_delay_ns(unsigned long clk_rate)
{
if (!TRNG_DEF_STARTUP_CYCLES)
return cycles_to_ns(clk_rate, BIT(24));
return cycles_to_ns(clk_rate, 256 * TRNG_DEF_STARTUP_CYCLES);
}
static unsigned int refill_delay_ns(unsigned long clk_rate)
{
if (!TRNG_DEF_MAX_REFILL_CYCLES)
return cycles_to_ns(clk_rate, BIT(24));
return cycles_to_ns(clk_rate, 256 * TRNG_DEF_MAX_REFILL_CYCLES);
}
static int ks_sa_rng_init(struct hwrng *rng)
{
u32 value;
struct device *dev = (struct device *)rng->priv;
struct ks_sa_rng *ks_sa_rng = dev_get_drvdata(dev);
unsigned long clk_rate = clk_get_rate(ks_sa_rng->clk);
/* Enable RNG module */
regmap_write_bits(ks_sa_rng->regmap_cfg, SA_CMD_STATUS_OFS,
@@ -120,6 +144,10 @@ static int ks_sa_rng_init(struct hwrng *rng)
value |= TRNG_CNTL_REG_TRNG_ENABLE;
writel(value, &ks_sa_rng->reg_rng->control);
ks_sa_rng->refill_delay_ns = refill_delay_ns(clk_rate);
ks_sa_rng->ready_ts = ktime_get_ns() +
startup_delay_ns(clk_rate);
return 0;
}
@@ -144,6 +172,7 @@ static int ks_sa_rng_data_read(struct hwrng *rng, u32 *data)
data[1] = readl(&ks_sa_rng->reg_rng->output_h);
writel(TRNG_INTACK_REG_READY, &ks_sa_rng->reg_rng->intack);
ks_sa_rng->ready_ts = ktime_get_ns() + ks_sa_rng->refill_delay_ns;
return sizeof(u32) * 2;
}
@@ -152,10 +181,19 @@ static int ks_sa_rng_data_present(struct hwrng *rng, int wait)
{
struct device *dev = (struct device *)rng->priv;
struct ks_sa_rng *ks_sa_rng = dev_get_drvdata(dev);
u64 now = ktime_get_ns();
u32 ready;
int j;
if (wait && now < ks_sa_rng->ready_ts) {
/* Max delay expected here is 81920000 ns */
unsigned long min_delay =
DIV_ROUND_UP((u32)(ks_sa_rng->ready_ts - now), 1000);
usleep_range(min_delay, min_delay + SA_RNG_DATA_RETRY_DELAY);
}
for (j = 0; j < SA_MAX_RNG_DATA_RETRIES; j++) {
ready = readl(&ks_sa_rng->reg_rng->status);
ready &= TRNG_STATUS_REG_READY;
@@ -174,7 +212,6 @@ static int ks_sa_rng_probe(struct platform_device *pdev)
struct ks_sa_rng *ks_sa_rng;
struct device *dev = &pdev->dev;
int ret;
struct resource *mem;
ks_sa_rng = devm_kzalloc(dev, sizeof(*ks_sa_rng), GFP_KERNEL);
if (!ks_sa_rng)
@@ -190,8 +227,7 @@ static int ks_sa_rng_probe(struct platform_device *pdev)
};
ks_sa_rng->rng.priv = (unsigned long)dev;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ks_sa_rng->reg_rng = devm_ioremap_resource(dev, mem);
ks_sa_rng->reg_rng = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(ks_sa_rng->reg_rng))
return PTR_ERR(ks_sa_rng->reg_rng);

Ver arquivo

@@ -42,7 +42,6 @@ static int meson_rng_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct meson_rng_data *data;
struct resource *res;
int ret;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
@@ -51,8 +50,7 @@ static int meson_rng_probe(struct platform_device *pdev)
data->pdev = pdev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
data->base = devm_ioremap_resource(dev, res);
data->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(data->base))
return PTR_ERR(data->base);

Ver arquivo

@@ -105,16 +105,9 @@ static int mtk_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
static int mtk_rng_probe(struct platform_device *pdev)
{
struct resource *res;
int ret;
struct mtk_rng *priv;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "no iomem resource\n");
return -ENXIO;
}
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -135,7 +128,7 @@ static int mtk_rng_probe(struct platform_device *pdev)
return ret;
}
priv->base = devm_ioremap_resource(&pdev->dev, res);
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);

Ver arquivo

@@ -0,0 +1,184 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Nuvoton Technology corporation.
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/init.h>
#include <linux/random.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/hw_random.h>
#include <linux/delay.h>
#include <linux/of_irq.h>
#include <linux/pm_runtime.h>
#define NPCM_RNGCS_REG 0x00 /* Control and status register */
#define NPCM_RNGD_REG 0x04 /* Data register */
#define NPCM_RNGMODE_REG 0x08 /* Mode register */
#define NPCM_RNG_CLK_SET_25MHZ GENMASK(4, 3) /* 20-25 MHz */
#define NPCM_RNG_DATA_VALID BIT(1)
#define NPCM_RNG_ENABLE BIT(0)
#define NPCM_RNG_M1ROSEL BIT(1)
#define NPCM_RNG_TIMEOUT_USEC 20000
#define NPCM_RNG_POLL_USEC 1000
#define to_npcm_rng(p) container_of(p, struct npcm_rng, rng)
struct npcm_rng {
void __iomem *base;
struct hwrng rng;
};
static int npcm_rng_init(struct hwrng *rng)
{
struct npcm_rng *priv = to_npcm_rng(rng);
writel(NPCM_RNG_CLK_SET_25MHZ | NPCM_RNG_ENABLE,
priv->base + NPCM_RNGCS_REG);
return 0;
}
static void npcm_rng_cleanup(struct hwrng *rng)
{
struct npcm_rng *priv = to_npcm_rng(rng);
writel(NPCM_RNG_CLK_SET_25MHZ, priv->base + NPCM_RNGCS_REG);
}
static int npcm_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
{
struct npcm_rng *priv = to_npcm_rng(rng);
int retval = 0;
int ready;
pm_runtime_get_sync((struct device *)priv->rng.priv);
while (max >= sizeof(u32)) {
if (wait) {
if (readl_poll_timeout(priv->base + NPCM_RNGCS_REG,
ready,
ready & NPCM_RNG_DATA_VALID,
NPCM_RNG_POLL_USEC,
NPCM_RNG_TIMEOUT_USEC))
break;
} else {
if ((readl(priv->base + NPCM_RNGCS_REG) &
NPCM_RNG_DATA_VALID) == 0)
break;
}
*(u32 *)buf = readl(priv->base + NPCM_RNGD_REG);
retval += sizeof(u32);
buf += sizeof(u32);
max -= sizeof(u32);
}
pm_runtime_mark_last_busy((struct device *)priv->rng.priv);
pm_runtime_put_sync_autosuspend((struct device *)priv->rng.priv);
return retval || !wait ? retval : -EIO;
}
static int npcm_rng_probe(struct platform_device *pdev)
{
struct npcm_rng *priv;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
dev_set_drvdata(&pdev->dev, priv);
pm_runtime_set_autosuspend_delay(&pdev->dev, 100);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_enable(&pdev->dev);
#ifndef CONFIG_PM
priv->rng.init = npcm_rng_init;
priv->rng.cleanup = npcm_rng_cleanup;
#endif
priv->rng.name = pdev->name;
priv->rng.read = npcm_rng_read;
priv->rng.priv = (unsigned long)&pdev->dev;
priv->rng.quality = 1000;
writel(NPCM_RNG_M1ROSEL, priv->base + NPCM_RNGMODE_REG);
ret = devm_hwrng_register(&pdev->dev, &priv->rng);
if (ret) {
dev_err(&pdev->dev, "Failed to register rng device: %d\n",
ret);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
return ret;
}
return 0;
}
static int npcm_rng_remove(struct platform_device *pdev)
{
struct npcm_rng *priv = platform_get_drvdata(pdev);
devm_hwrng_unregister(&pdev->dev, &priv->rng);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
return 0;
}
#ifdef CONFIG_PM
static int npcm_rng_runtime_suspend(struct device *dev)
{
struct npcm_rng *priv = dev_get_drvdata(dev);
npcm_rng_cleanup(&priv->rng);
return 0;
}
static int npcm_rng_runtime_resume(struct device *dev)
{
struct npcm_rng *priv = dev_get_drvdata(dev);
return npcm_rng_init(&priv->rng);
}
#endif
static const struct dev_pm_ops npcm_rng_pm_ops = {
SET_RUNTIME_PM_OPS(npcm_rng_runtime_suspend,
npcm_rng_runtime_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
};
static const struct of_device_id rng_dt_id[] = {
{ .compatible = "nuvoton,npcm750-rng", },
{},
};
MODULE_DEVICE_TABLE(of, rng_dt_id);
static struct platform_driver npcm_rng_driver = {
.driver = {
.name = "npcm-rng",
.pm = &npcm_rng_pm_ops,
.of_match_table = of_match_ptr(rng_dt_id),
},
.probe = npcm_rng_probe,
.remove = npcm_rng_remove,
};
module_platform_driver(npcm_rng_driver);
MODULE_DESCRIPTION("Nuvoton NPCM Random Number Generator Driver");
MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
MODULE_LICENSE("GPL v2");

Ver arquivo

@@ -66,6 +66,13 @@
#define OMAP4_RNG_OUTPUT_SIZE 0x8
#define EIP76_RNG_OUTPUT_SIZE 0x10
/*
* EIP76 RNG takes approx. 700us to produce 16 bytes of output data
* as per testing results. And to account for the lack of udelay()'s
* reliability, we keep the timeout as 1000us.
*/
#define RNG_DATA_FILL_TIMEOUT 100
enum {
RNG_OUTPUT_0_REG = 0,
RNG_OUTPUT_1_REG,
@@ -176,7 +183,7 @@ static int omap_rng_do_read(struct hwrng *rng, void *data, size_t max,
if (max < priv->pdata->data_size)
return 0;
for (i = 0; i < 20; i++) {
for (i = 0; i < RNG_DATA_FILL_TIMEOUT; i++) {
present = priv->pdata->data_present(priv);
if (present || !wait)
break;
@@ -432,7 +439,6 @@ static int get_omap_rng_device_details(struct omap_rng_dev *omap_rng)
static int omap_rng_probe(struct platform_device *pdev)
{
struct omap_rng_dev *priv;
struct resource *res;
struct device *dev = &pdev->dev;
int ret;
@@ -449,8 +455,7 @@ static int omap_rng_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv);
priv->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->base = devm_ioremap_resource(dev, res);
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base)) {
ret = PTR_ERR(priv->base);
goto err_ioremap;

Ver arquivo

@@ -11,8 +11,6 @@
* warranty of any kind, whether express or implied.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/init.h>
#include <linux/random.h>
@@ -20,117 +18,159 @@
#include <linux/workqueue.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#define RNG_RESET 0x01
#define RNG_GEN_PRNG_HW_INIT 0x02
#define RNG_GEN_HW 0x08
/* param1: ptr, param2: count, param3: flag */
static u32 (*omap3_rom_rng_call)(u32, u32, u32);
static struct delayed_work idle_work;
static int rng_idle;
static struct clk *rng_clk;
static void omap3_rom_rng_idle(struct work_struct *work)
{
int r;
r = omap3_rom_rng_call(0, 0, RNG_RESET);
if (r != 0) {
pr_err("reset failed: %d\n", r);
return;
}
clk_disable_unprepare(rng_clk);
rng_idle = 1;
}
static int omap3_rom_rng_get_random(void *buf, unsigned int count)
{
u32 r;
u32 ptr;
cancel_delayed_work_sync(&idle_work);
if (rng_idle) {
r = clk_prepare_enable(rng_clk);
if (r)
return r;
r = omap3_rom_rng_call(0, 0, RNG_GEN_PRNG_HW_INIT);
if (r != 0) {
clk_disable_unprepare(rng_clk);
pr_err("HW init failed: %d\n", r);
return -EIO;
}
rng_idle = 0;
}
ptr = virt_to_phys(buf);
r = omap3_rom_rng_call(ptr, count, RNG_GEN_HW);
schedule_delayed_work(&idle_work, msecs_to_jiffies(500));
if (r != 0)
return -EINVAL;
return 0;
}
struct omap_rom_rng {
struct clk *clk;
struct device *dev;
struct hwrng ops;
u32 (*rom_rng_call)(u32 ptr, u32 count, u32 flag);
};
static int omap3_rom_rng_read(struct hwrng *rng, void *data, size_t max, bool w)
{
struct omap_rom_rng *ddata;
u32 ptr;
int r;
r = omap3_rom_rng_get_random(data, 4);
if (r < 0)
ddata = (struct omap_rom_rng *)rng->priv;
r = pm_runtime_get_sync(ddata->dev);
if (r < 0) {
pm_runtime_put_noidle(ddata->dev);
return r;
return 4;
}
ptr = virt_to_phys(data);
r = ddata->rom_rng_call(ptr, 4, RNG_GEN_HW);
if (r != 0)
r = -EINVAL;
else
r = 4;
pm_runtime_mark_last_busy(ddata->dev);
pm_runtime_put_autosuspend(ddata->dev);
return r;
}
static struct hwrng omap3_rom_rng_ops = {
.name = "omap3-rom",
.read = omap3_rom_rng_read,
};
static int __maybe_unused omap_rom_rng_runtime_suspend(struct device *dev)
{
struct omap_rom_rng *ddata;
int r;
ddata = dev_get_drvdata(dev);
r = ddata->rom_rng_call(0, 0, RNG_RESET);
if (r != 0)
dev_err(dev, "reset failed: %d\n", r);
clk_disable_unprepare(ddata->clk);
return 0;
}
static int __maybe_unused omap_rom_rng_runtime_resume(struct device *dev)
{
struct omap_rom_rng *ddata;
int r;
ddata = dev_get_drvdata(dev);
r = clk_prepare_enable(ddata->clk);
if (r < 0)
return r;
r = ddata->rom_rng_call(0, 0, RNG_GEN_PRNG_HW_INIT);
if (r != 0) {
clk_disable(ddata->clk);
dev_err(dev, "HW init failed: %d\n", r);
return -EIO;
}
return 0;
}
static void omap_rom_rng_finish(void *data)
{
struct omap_rom_rng *ddata = data;
pm_runtime_dont_use_autosuspend(ddata->dev);
pm_runtime_disable(ddata->dev);
}
static int omap3_rom_rng_probe(struct platform_device *pdev)
{
struct omap_rom_rng *ddata;
int ret = 0;
pr_info("initializing\n");
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
omap3_rom_rng_call = pdev->dev.platform_data;
if (!omap3_rom_rng_call) {
pr_err("omap3_rom_rng_call is NULL\n");
ddata->dev = &pdev->dev;
ddata->ops.priv = (unsigned long)ddata;
ddata->ops.name = "omap3-rom";
ddata->ops.read = of_device_get_match_data(&pdev->dev);
ddata->ops.quality = 900;
if (!ddata->ops.read) {
dev_err(&pdev->dev, "missing rom code handler\n");
return -ENODEV;
}
dev_set_drvdata(ddata->dev, ddata);
ddata->rom_rng_call = pdev->dev.platform_data;
if (!ddata->rom_rng_call) {
dev_err(ddata->dev, "rom_rng_call is NULL\n");
return -EINVAL;
}
INIT_DELAYED_WORK(&idle_work, omap3_rom_rng_idle);
rng_clk = devm_clk_get(&pdev->dev, "ick");
if (IS_ERR(rng_clk)) {
pr_err("unable to get RNG clock\n");
return PTR_ERR(rng_clk);
ddata->clk = devm_clk_get(ddata->dev, "ick");
if (IS_ERR(ddata->clk)) {
dev_err(ddata->dev, "unable to get RNG clock\n");
return PTR_ERR(ddata->clk);
}
/* Leave the RNG in reset state. */
ret = clk_prepare_enable(rng_clk);
pm_runtime_enable(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
pm_runtime_use_autosuspend(&pdev->dev);
ret = devm_add_action_or_reset(ddata->dev, omap_rom_rng_finish,
ddata);
if (ret)
return ret;
omap3_rom_rng_idle(0);
return hwrng_register(&omap3_rom_rng_ops);
return devm_hwrng_register(ddata->dev, &ddata->ops);
}
static int omap3_rom_rng_remove(struct platform_device *pdev)
{
cancel_delayed_work_sync(&idle_work);
hwrng_unregister(&omap3_rom_rng_ops);
clk_disable_unprepare(rng_clk);
return 0;
}
static const struct of_device_id omap_rom_rng_match[] = {
{ .compatible = "nokia,n900-rom-rng", .data = omap3_rom_rng_read, },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, omap_rom_rng_match);
static const struct dev_pm_ops omap_rom_rng_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(omap_rom_rng_runtime_suspend,
omap_rom_rng_runtime_resume)
};
static struct platform_driver omap3_rom_rng_driver = {
.driver = {
.name = "omap3-rom-rng",
.of_match_table = omap_rom_rng_match,
.pm = &omap_rom_rng_pm_ops,
},
.probe = omap3_rom_rng_probe,
.remove = omap3_rom_rng_remove,
};
module_platform_driver(omap3_rom_rng_driver);

Ver arquivo

@@ -86,10 +86,8 @@ static struct hwrng pasemi_rng = {
static int rng_probe(struct platform_device *pdev)
{
void __iomem *rng_regs;
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
rng_regs = devm_ioremap_resource(&pdev->dev, res);
rng_regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(rng_regs))
return PTR_ERR(rng_regs);

Ver arquivo

@@ -70,7 +70,6 @@ static int pic32_rng_read(struct hwrng *rng, void *buf, size_t max,
static int pic32_rng_probe(struct platform_device *pdev)
{
struct pic32_rng *priv;
struct resource *res;
u32 v;
int ret;
@@ -78,8 +77,7 @@ static int pic32_rng_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->base = devm_ioremap_resource(&pdev->dev, res);
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);

Ver arquivo

@@ -72,7 +72,6 @@ static int st_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
static int st_rng_probe(struct platform_device *pdev)
{
struct st_rng_data *ddata;
struct resource *res;
struct clk *clk;
void __iomem *base;
int ret;
@@ -81,8 +80,7 @@ static int st_rng_probe(struct platform_device *pdev)
if (!ddata)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);

Ver arquivo

@@ -107,14 +107,12 @@ static int tx4939_rng_data_read(struct hwrng *rng, u32 *buffer)
static int __init tx4939_rng_probe(struct platform_device *dev)
{
struct tx4939_rng *rngdev;
struct resource *r;
int i;
rngdev = devm_kzalloc(&dev->dev, sizeof(*rngdev), GFP_KERNEL);
if (!rngdev)
return -ENOMEM;
r = platform_get_resource(dev, IORESOURCE_MEM, 0);
rngdev->base = devm_ioremap_resource(&dev->dev, r);
rngdev->base = devm_platform_ioremap_resource(dev, 0);
if (IS_ERR(rngdev->base))
return PTR_ERR(rngdev->base);

Ver arquivo

@@ -313,7 +313,6 @@ static struct hwrng xgene_rng_func = {
static int xgene_rng_probe(struct platform_device *pdev)
{
struct resource *res;
struct xgene_rng_dev *ctx;
int rc = 0;
@@ -324,8 +323,7 @@ static int xgene_rng_probe(struct platform_device *pdev)
ctx->dev = &pdev->dev;
platform_set_drvdata(pdev, ctx);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ctx->csr_base = devm_ioremap_resource(&pdev->dev, res);
ctx->csr_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(ctx->csr_base))
return PTR_ERR(ctx->csr_base);