[PATCH v9 2/5] crypto: loongson - add Loongson RNG driver support

Qunqin Zhao posted 5 patches 7 months, 2 weeks ago
Only 4 patches received!
There is a newer version of this series
[PATCH v9 2/5] crypto: loongson - add Loongson RNG driver support
Posted by Qunqin Zhao 7 months, 2 weeks ago
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>
---
v8: Added reseed callbak. "lsrng" --> "loongson_rng".
v7: Change the lsrng_ prefix to loongson_rng_
v6: Replace all "ls6000se" with "loongson"
v2-v5: None

 drivers/crypto/Kconfig                 |   1 +
 drivers/crypto/Makefile                |   1 +
 drivers/crypto/loongson/Kconfig        |   5 +
 drivers/crypto/loongson/Makefile       |   1 +
 drivers/crypto/loongson/loongson-rng.c | 197 +++++++++++++++++++++++++
 5 files changed, 205 insertions(+)
 create mode 100644 drivers/crypto/loongson/Kconfig
 create mode 100644 drivers/crypto/loongson/Makefile
 create mode 100644 drivers/crypto/loongson/loongson-rng.c

diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 470827820..371a2bd58 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -833,6 +833,7 @@ config CRYPTO_DEV_CCREE
 	  If unsure say Y.
 
 source "drivers/crypto/hisilicon/Kconfig"
+source "drivers/crypto/loongson/Kconfig"
 
 source "drivers/crypto/amlogic/Kconfig"
 
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index c97f0ebc5..fbd039058 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -47,6 +47,7 @@ obj-y += inside-secure/
 obj-$(CONFIG_CRYPTO_DEV_ARTPEC6) += axis/
 obj-y += xilinx/
 obj-y += hisilicon/
+obj-y += loongson/
 obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/
 obj-y += intel/
 obj-y += starfive/
diff --git a/drivers/crypto/loongson/Kconfig b/drivers/crypto/loongson/Kconfig
new file mode 100644
index 000000000..15475da8f
--- /dev/null
+++ b/drivers/crypto/loongson/Kconfig
@@ -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.
diff --git a/drivers/crypto/loongson/Makefile b/drivers/crypto/loongson/Makefile
new file mode 100644
index 000000000..1ce5ec32b
--- /dev/null
+++ b/drivers/crypto/loongson/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_CRYPTO_DEV_LOONGSON_RNG)  += loongson-rng.o
diff --git a/drivers/crypto/loongson/loongson-rng.c b/drivers/crypto/loongson/loongson-rng.c
new file mode 100644
index 000000000..bc0a4404b
--- /dev/null
+++ b/drivers/crypto/loongson/loongson-rng.c
@@ -0,0 +1,197 @@
+// 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 is_init;
+};
+
+struct loongson_rng {
+	bool is_used;
+	struct loongson_se_engine *engine;
+	struct list_head list;
+};
+
+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 atomic_t rng_active_devs;
+static struct loongson_rng_list rng_devices;
+
+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;
+
+	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)
+			return err;
+
+		cmd = rng->engine->command_ret;
+		if (cmd->u.ret)
+			return -EFAULT;
+
+		memcpy(dstn, rng->engine->data_buffer, len);
+		dlen -= len;
+		dstn += len;
+	} while (dlen > 0);
+
+	return 0;
+}
+
+static int loongson_rng_init(struct crypto_tfm *tfm)
+{
+	struct loongson_rng_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct loongson_rng *rng;
+	int ret = -EBUSY;
+
+	mutex_lock(&rng_devices.lock);
+	list_for_each_entry(rng, &rng_devices.list, list) {
+		if (!rng->is_used) {
+			rng->is_used = true;
+			ctx->rng = rng;
+			ret = 0;
+			break;
+		}
+	}
+	mutex_unlock(&rng_devices.lock);
+
+	return ret;
+}
+
+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->is_used = false;
+	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;
+
+	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);
+	cmd = rng->engine->command_ret;
+	if (err || cmd->u.ret)
+		return -EFAULT;
+
+	return 0;
+}
+
+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 void loongson_rng_add_to_list(struct loongson_rng *rng)
+{
+	mutex_lock(&rng_devices.lock);
+	list_add_tail(&rng->list, &rng_devices.list);
+	mutex_unlock(&rng_devices.lock);
+}
+
+static int loongson_rng_probe(struct platform_device *pdev)
+{
+	struct loongson_rng_cmd *cmd;
+	struct loongson_rng *rng;
+	int ret;
+
+	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;
+
+	if (!rng_devices.is_init) {
+		ret = crypto_register_rng(&loongson_rng_alg);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to register crypto(%d)\n", ret);
+			return ret;
+		}
+		INIT_LIST_HEAD(&rng_devices.list);
+		mutex_init(&rng_devices.lock);
+		rng_devices.is_init = true;
+	}
+
+	loongson_rng_add_to_list(rng);
+	atomic_inc(&rng_active_devs);
+
+	return 0;
+}
+
+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");
-- 
2.45.2
Re: [PATCH v9 2/5] crypto: loongson - add Loongson RNG driver support
Posted by Herbert Xu 7 months ago
On Tue, May 06, 2025 at 11:19:44AM +0800, Qunqin Zhao wrote:
>
> +static int loongson_rng_init(struct crypto_tfm *tfm)
> +{
> +	struct loongson_rng_ctx *ctx = crypto_tfm_ctx(tfm);
> +	struct loongson_rng *rng;
> +	int ret = -EBUSY;
> +
> +	mutex_lock(&rng_devices.lock);
> +	list_for_each_entry(rng, &rng_devices.list, list) {
> +		if (!rng->is_used) {
> +			rng->is_used = true;
> +			ctx->rng = rng;
> +			ret = 0;
> +			break;
> +		}
> +	}
> +	mutex_unlock(&rng_devices.lock);
> +
> +	return ret;
> +}

This isn't right.  The number of TFMs in the system is unlimited.
You should not pair each tfm with an individual hardwre device.

If you want to do load-balancing you could certainly pick a device
per tfm, but each device must be able to support an unlimited number
of tfms.

Cheers,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
Re: [PATCH v9 2/5] crypto: loongson - add Loongson RNG driver support
Posted by Qunqin Zhao 7 months ago
在 2025/5/19 下午1:57, Herbert Xu 写道:
> On Tue, May 06, 2025 at 11:19:44AM +0800, Qunqin Zhao wrote:
>> +static int loongson_rng_init(struct crypto_tfm *tfm)
>> +{
>> +	struct loongson_rng_ctx *ctx = crypto_tfm_ctx(tfm);
>> +	struct loongson_rng *rng;
>> +	int ret = -EBUSY;
>> +
>> +	mutex_lock(&rng_devices.lock);
>> +	list_for_each_entry(rng, &rng_devices.list, list) {
>> +		if (!rng->is_used) {
>> +			rng->is_used = true;
>> +			ctx->rng = rng;
>> +			ret = 0;
>> +			break;
>> +		}
>> +	}
>> +	mutex_unlock(&rng_devices.lock);
>> +
>> +	return ret;
>> +}
> This isn't right.  The number of TFMs in the system is unlimited.
> You should not pair each tfm with an individual hardwre device.
Then the HISI TRNG driver isn't a right demo?
>
> If you want to do load-balancing you could certainly pick a device
> per tfm, but each device must be able to support an unlimited number
> of tfms.

This can also avoid concurrent access to a device, otherwise i need to

add mutex_lock/unlock in generate and seed callback.

Thanks,

Qunqin.

>
> Cheers,

Re: [PATCH v9 2/5] crypto: loongson - add Loongson RNG driver support
Posted by Herbert Xu 7 months ago
On Mon, May 19, 2025 at 04:13:14PM +0800, Qunqin Zhao wrote:
>
> Then the HISI TRNG driver isn't a right demo?

Yes the hisi trng looks wrong too.

> This can also avoid concurrent access to a device, otherwise i need to
> 
> add mutex_lock/unlock in generate and seed callback.

Randomly failing the tfm allocation is not a solution to resource
control :)

Cheers,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
Re: [PATCH v9 2/5] crypto: loongson - add Loongson RNG driver support
Posted by liulongfang 7 months ago
On 2025/5/19 16:22, Herbert Xu wrote:
> On Mon, May 19, 2025 at 04:13:14PM +0800, Qunqin Zhao wrote:
>>
>> Then the HISI TRNG driver isn't a right demo?
> 
> Yes the hisi trng looks wrong too.
>

We are currently updating and plan to create software TFM for users when
they unable to apply for hardware device queues, ensuring that users' tasks
can continue to be completed.

Thanks,
Longfang.

>> This can also avoid concurrent access to a device, otherwise i need to
>>
>> add mutex_lock/unlock in generate and seed callback.
> 
> Randomly failing the tfm allocation is not a solution to resource
> control :)
> 
> Cheers,
>
Re: [PATCH v9 2/5] crypto: loongson - add Loongson RNG driver support
Posted by Qunqin Zhao 7 months ago
在 2025/5/19 下午4:22, Herbert Xu 写道:
> On Mon, May 19, 2025 at 04:13:14PM +0800, Qunqin Zhao wrote:
>> Then the HISI TRNG driver isn't a right demo?
> Yes the hisi trng looks wrong too.
>
>> This can also avoid concurrent access to a device, otherwise i need to
>>
>> add mutex_lock/unlock in generate and seed callback.
> Randomly failing the tfm allocation is not a solution to resource
> control :)

Is it fine waiting in init-callback until someone calls exit-callback?

Thanks,

Qunqin.

>
> Cheers,

Re: [PATCH v9 2/5] crypto: loongson - add Loongson RNG driver support
Posted by Herbert Xu 7 months ago
On Mon, May 19, 2025 at 04:49:45PM +0800, Qunqin Zhao wrote:
>
> Is it fine waiting in init-callback until someone calls exit-callback?

No that's just as bad as failing.  Remember this is exposed to
user-space through af_alg.  If you make it wait it'll just appear
to hang for the user invoking this.

Cheers,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt