mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
crypto: loongson - add Loongson RNG driver support
Loongson's Random Number Generator is found inside Loongson Security Engine chip. Co-developed-by: Yinggang Gu <guyinggang@loongson.cn> Signed-off-by: Yinggang Gu <guyinggang@loongson.cn> Signed-off-by: Qunqin Zhao <zhaoqunqin@loongson.cn> Reviewed-by: Huacai Chen <chenhuacai@loongson.cn> Acked-by: Herbert Xu <herbert@gondor.apana.org.au> Link: https://lore.kernel.org/r/20250705072045.1067-3-zhaoqunqin@loongson.cn Signed-off-by: Lee Jones <lee@kernel.org>
This commit is contained in:
parent
e551fa3159
commit
766b2d724c
|
|
@ -840,6 +840,7 @@ config CRYPTO_DEV_CCREE
|
||||||
If unsure say Y.
|
If unsure say Y.
|
||||||
|
|
||||||
source "drivers/crypto/hisilicon/Kconfig"
|
source "drivers/crypto/hisilicon/Kconfig"
|
||||||
|
source "drivers/crypto/loongson/Kconfig"
|
||||||
|
|
||||||
source "drivers/crypto/amlogic/Kconfig"
|
source "drivers/crypto/amlogic/Kconfig"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ obj-y += inside-secure/
|
||||||
obj-$(CONFIG_CRYPTO_DEV_ARTPEC6) += axis/
|
obj-$(CONFIG_CRYPTO_DEV_ARTPEC6) += axis/
|
||||||
obj-y += xilinx/
|
obj-y += xilinx/
|
||||||
obj-y += hisilicon/
|
obj-y += hisilicon/
|
||||||
|
obj-y += loongson/
|
||||||
obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/
|
obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/
|
||||||
obj-y += intel/
|
obj-y += intel/
|
||||||
obj-y += starfive/
|
obj-y += starfive/
|
||||||
|
|
|
||||||
5
drivers/crypto/loongson/Kconfig
Normal file
5
drivers/crypto/loongson/Kconfig
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
config CRYPTO_DEV_LOONGSON_RNG
|
||||||
|
tristate "Support for Loongson RNG Driver"
|
||||||
|
depends on MFD_LOONGSON_SE
|
||||||
|
help
|
||||||
|
Support for Loongson RNG Driver.
|
||||||
1
drivers/crypto/loongson/Makefile
Normal file
1
drivers/crypto/loongson/Makefile
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
obj-$(CONFIG_CRYPTO_DEV_LOONGSON_RNG) += loongson-rng.o
|
||||||
209
drivers/crypto/loongson/loongson-rng.c
Normal file
209
drivers/crypto/loongson/loongson-rng.c
Normal file
|
|
@ -0,0 +1,209 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/* Copyright (c) 2019 HiSilicon Limited. */
|
||||||
|
/* Copyright (c) 2025 Loongson Technology Corporation Limited. */
|
||||||
|
|
||||||
|
#include <linux/crypto.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/hw_random.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/iopoll.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/mfd/loongson-se.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/random.h>
|
||||||
|
#include <crypto/internal/rng.h>
|
||||||
|
|
||||||
|
#define SE_SEED_SIZE 32
|
||||||
|
|
||||||
|
struct loongson_rng_list {
|
||||||
|
struct mutex lock;
|
||||||
|
struct list_head list;
|
||||||
|
int registered;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct loongson_rng {
|
||||||
|
u32 used;
|
||||||
|
struct loongson_se_engine *engine;
|
||||||
|
struct list_head list;
|
||||||
|
struct mutex lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct loongson_rng_ctx {
|
||||||
|
struct loongson_rng *rng;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct loongson_rng_cmd {
|
||||||
|
u32 cmd_id;
|
||||||
|
union {
|
||||||
|
u32 len;
|
||||||
|
u32 ret;
|
||||||
|
} u;
|
||||||
|
u32 seed_off;
|
||||||
|
u32 out_off;
|
||||||
|
u32 pad[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct loongson_rng_list rng_devices = {
|
||||||
|
.lock = __MUTEX_INITIALIZER(rng_devices.lock),
|
||||||
|
.list = LIST_HEAD_INIT(rng_devices.list),
|
||||||
|
};
|
||||||
|
|
||||||
|
static int loongson_rng_generate(struct crypto_rng *tfm, const u8 *src,
|
||||||
|
unsigned int slen, u8 *dstn, unsigned int dlen)
|
||||||
|
{
|
||||||
|
struct loongson_rng_ctx *ctx = crypto_rng_ctx(tfm);
|
||||||
|
struct loongson_rng *rng = ctx->rng;
|
||||||
|
struct loongson_rng_cmd *cmd = rng->engine->command;
|
||||||
|
int err, len;
|
||||||
|
|
||||||
|
mutex_lock(&rng->lock);
|
||||||
|
cmd->seed_off = 0;
|
||||||
|
do {
|
||||||
|
len = min(dlen, rng->engine->buffer_size);
|
||||||
|
cmd = rng->engine->command;
|
||||||
|
cmd->u.len = len;
|
||||||
|
err = loongson_se_send_engine_cmd(rng->engine);
|
||||||
|
if (err)
|
||||||
|
break;
|
||||||
|
|
||||||
|
cmd = rng->engine->command_ret;
|
||||||
|
if (cmd->u.ret) {
|
||||||
|
err = -EIO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(dstn, rng->engine->data_buffer, len);
|
||||||
|
dlen -= len;
|
||||||
|
dstn += len;
|
||||||
|
} while (dlen > 0);
|
||||||
|
mutex_unlock(&rng->lock);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int loongson_rng_init(struct crypto_tfm *tfm)
|
||||||
|
{
|
||||||
|
struct loongson_rng_ctx *ctx = crypto_tfm_ctx(tfm);
|
||||||
|
struct loongson_rng *rng;
|
||||||
|
u32 min_used = U32_MAX;
|
||||||
|
|
||||||
|
mutex_lock(&rng_devices.lock);
|
||||||
|
list_for_each_entry(rng, &rng_devices.list, list) {
|
||||||
|
if (rng->used < min_used) {
|
||||||
|
ctx->rng = rng;
|
||||||
|
min_used = rng->used;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx->rng->used++;
|
||||||
|
mutex_unlock(&rng_devices.lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loongson_rng_exit(struct crypto_tfm *tfm)
|
||||||
|
{
|
||||||
|
struct loongson_rng_ctx *ctx = crypto_tfm_ctx(tfm);
|
||||||
|
|
||||||
|
mutex_lock(&rng_devices.lock);
|
||||||
|
ctx->rng->used--;
|
||||||
|
mutex_unlock(&rng_devices.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int loongson_rng_seed(struct crypto_rng *tfm, const u8 *seed,
|
||||||
|
unsigned int slen)
|
||||||
|
{
|
||||||
|
struct loongson_rng_ctx *ctx = crypto_rng_ctx(tfm);
|
||||||
|
struct loongson_rng *rng = ctx->rng;
|
||||||
|
struct loongson_rng_cmd *cmd;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (slen < SE_SEED_SIZE)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
slen = min(slen, rng->engine->buffer_size);
|
||||||
|
|
||||||
|
mutex_lock(&rng->lock);
|
||||||
|
cmd = rng->engine->command;
|
||||||
|
cmd->u.len = slen;
|
||||||
|
cmd->seed_off = rng->engine->buffer_off;
|
||||||
|
memcpy(rng->engine->data_buffer, seed, slen);
|
||||||
|
err = loongson_se_send_engine_cmd(rng->engine);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
cmd = rng->engine->command_ret;
|
||||||
|
if (cmd->u.ret)
|
||||||
|
err = -EIO;
|
||||||
|
out:
|
||||||
|
mutex_unlock(&rng->lock);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct rng_alg loongson_rng_alg = {
|
||||||
|
.generate = loongson_rng_generate,
|
||||||
|
.seed = loongson_rng_seed,
|
||||||
|
.seedsize = SE_SEED_SIZE,
|
||||||
|
.base = {
|
||||||
|
.cra_name = "stdrng",
|
||||||
|
.cra_driver_name = "loongson_stdrng",
|
||||||
|
.cra_priority = 300,
|
||||||
|
.cra_ctxsize = sizeof(struct loongson_rng_ctx),
|
||||||
|
.cra_module = THIS_MODULE,
|
||||||
|
.cra_init = loongson_rng_init,
|
||||||
|
.cra_exit = loongson_rng_exit,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int loongson_rng_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct loongson_rng_cmd *cmd;
|
||||||
|
struct loongson_rng *rng;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
|
||||||
|
if (!rng)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
rng->engine = loongson_se_init_engine(pdev->dev.parent, SE_ENGINE_RNG);
|
||||||
|
if (!rng->engine)
|
||||||
|
return -ENODEV;
|
||||||
|
cmd = rng->engine->command;
|
||||||
|
cmd->cmd_id = SE_CMD_RNG;
|
||||||
|
cmd->out_off = rng->engine->buffer_off;
|
||||||
|
mutex_init(&rng->lock);
|
||||||
|
|
||||||
|
mutex_lock(&rng_devices.lock);
|
||||||
|
|
||||||
|
if (!rng_devices.registered) {
|
||||||
|
ret = crypto_register_rng(&loongson_rng_alg);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "failed to register crypto(%d)\n", ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
rng_devices.registered = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_add_tail(&rng->list, &rng_devices.list);
|
||||||
|
out:
|
||||||
|
mutex_unlock(&rng_devices.lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver loongson_rng_driver = {
|
||||||
|
.probe = loongson_rng_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "loongson-rng",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(loongson_rng_driver);
|
||||||
|
|
||||||
|
MODULE_ALIAS("platform:loongson-rng");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Yinggang Gu <guyinggang@loongson.cn>");
|
||||||
|
MODULE_AUTHOR("Qunqin Zhao <zhaoqunqin@loongson.cn>");
|
||||||
|
MODULE_DESCRIPTION("Loongson Random Number Generator driver");
|
||||||
Loading…
Reference in New Issue
Block a user