Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Qunqin Zhao and committed by
Lee Jones
766b2d72 e551fa31

+217
+1
drivers/crypto/Kconfig
··· 840 840 If unsure say Y. 841 841 842 842 source "drivers/crypto/hisilicon/Kconfig" 843 + source "drivers/crypto/loongson/Kconfig" 843 844 844 845 source "drivers/crypto/amlogic/Kconfig" 845 846
+1
drivers/crypto/Makefile
··· 44 44 obj-$(CONFIG_CRYPTO_DEV_ARTPEC6) += axis/ 45 45 obj-y += xilinx/ 46 46 obj-y += hisilicon/ 47 + obj-y += loongson/ 47 48 obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/ 48 49 obj-y += intel/ 49 50 obj-y += starfive/
+5
drivers/crypto/loongson/Kconfig
··· 1 + config CRYPTO_DEV_LOONGSON_RNG 2 + tristate "Support for Loongson RNG Driver" 3 + depends on MFD_LOONGSON_SE 4 + help 5 + Support for Loongson RNG Driver.
+1
drivers/crypto/loongson/Makefile
··· 1 + obj-$(CONFIG_CRYPTO_DEV_LOONGSON_RNG) += loongson-rng.o
+209
drivers/crypto/loongson/loongson-rng.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2019 HiSilicon Limited. */ 3 + /* Copyright (c) 2025 Loongson Technology Corporation Limited. */ 4 + 5 + #include <linux/crypto.h> 6 + #include <linux/err.h> 7 + #include <linux/hw_random.h> 8 + #include <linux/io.h> 9 + #include <linux/iopoll.h> 10 + #include <linux/kernel.h> 11 + #include <linux/list.h> 12 + #include <linux/mfd/loongson-se.h> 13 + #include <linux/module.h> 14 + #include <linux/mutex.h> 15 + #include <linux/platform_device.h> 16 + #include <linux/random.h> 17 + #include <crypto/internal/rng.h> 18 + 19 + #define SE_SEED_SIZE 32 20 + 21 + struct loongson_rng_list { 22 + struct mutex lock; 23 + struct list_head list; 24 + int registered; 25 + }; 26 + 27 + struct loongson_rng { 28 + u32 used; 29 + struct loongson_se_engine *engine; 30 + struct list_head list; 31 + struct mutex lock; 32 + }; 33 + 34 + struct loongson_rng_ctx { 35 + struct loongson_rng *rng; 36 + }; 37 + 38 + struct loongson_rng_cmd { 39 + u32 cmd_id; 40 + union { 41 + u32 len; 42 + u32 ret; 43 + } u; 44 + u32 seed_off; 45 + u32 out_off; 46 + u32 pad[4]; 47 + }; 48 + 49 + static struct loongson_rng_list rng_devices = { 50 + .lock = __MUTEX_INITIALIZER(rng_devices.lock), 51 + .list = LIST_HEAD_INIT(rng_devices.list), 52 + }; 53 + 54 + static int loongson_rng_generate(struct crypto_rng *tfm, const u8 *src, 55 + unsigned int slen, u8 *dstn, unsigned int dlen) 56 + { 57 + struct loongson_rng_ctx *ctx = crypto_rng_ctx(tfm); 58 + struct loongson_rng *rng = ctx->rng; 59 + struct loongson_rng_cmd *cmd = rng->engine->command; 60 + int err, len; 61 + 62 + mutex_lock(&rng->lock); 63 + cmd->seed_off = 0; 64 + do { 65 + len = min(dlen, rng->engine->buffer_size); 66 + cmd = rng->engine->command; 67 + cmd->u.len = len; 68 + err = loongson_se_send_engine_cmd(rng->engine); 69 + if (err) 70 + break; 71 + 72 + cmd = rng->engine->command_ret; 73 + if (cmd->u.ret) { 74 + err = -EIO; 75 + break; 76 + } 77 + 78 + memcpy(dstn, rng->engine->data_buffer, len); 79 + dlen -= len; 80 + dstn += len; 81 + } while (dlen > 0); 82 + mutex_unlock(&rng->lock); 83 + 84 + return err; 85 + } 86 + 87 + static int loongson_rng_init(struct crypto_tfm *tfm) 88 + { 89 + struct loongson_rng_ctx *ctx = crypto_tfm_ctx(tfm); 90 + struct loongson_rng *rng; 91 + u32 min_used = U32_MAX; 92 + 93 + mutex_lock(&rng_devices.lock); 94 + list_for_each_entry(rng, &rng_devices.list, list) { 95 + if (rng->used < min_used) { 96 + ctx->rng = rng; 97 + min_used = rng->used; 98 + } 99 + } 100 + ctx->rng->used++; 101 + mutex_unlock(&rng_devices.lock); 102 + 103 + return 0; 104 + } 105 + 106 + static void loongson_rng_exit(struct crypto_tfm *tfm) 107 + { 108 + struct loongson_rng_ctx *ctx = crypto_tfm_ctx(tfm); 109 + 110 + mutex_lock(&rng_devices.lock); 111 + ctx->rng->used--; 112 + mutex_unlock(&rng_devices.lock); 113 + } 114 + 115 + static int loongson_rng_seed(struct crypto_rng *tfm, const u8 *seed, 116 + unsigned int slen) 117 + { 118 + struct loongson_rng_ctx *ctx = crypto_rng_ctx(tfm); 119 + struct loongson_rng *rng = ctx->rng; 120 + struct loongson_rng_cmd *cmd; 121 + int err; 122 + 123 + if (slen < SE_SEED_SIZE) 124 + return -EINVAL; 125 + 126 + slen = min(slen, rng->engine->buffer_size); 127 + 128 + mutex_lock(&rng->lock); 129 + cmd = rng->engine->command; 130 + cmd->u.len = slen; 131 + cmd->seed_off = rng->engine->buffer_off; 132 + memcpy(rng->engine->data_buffer, seed, slen); 133 + err = loongson_se_send_engine_cmd(rng->engine); 134 + if (err) 135 + goto out; 136 + 137 + cmd = rng->engine->command_ret; 138 + if (cmd->u.ret) 139 + err = -EIO; 140 + out: 141 + mutex_unlock(&rng->lock); 142 + 143 + return err; 144 + } 145 + 146 + static struct rng_alg loongson_rng_alg = { 147 + .generate = loongson_rng_generate, 148 + .seed = loongson_rng_seed, 149 + .seedsize = SE_SEED_SIZE, 150 + .base = { 151 + .cra_name = "stdrng", 152 + .cra_driver_name = "loongson_stdrng", 153 + .cra_priority = 300, 154 + .cra_ctxsize = sizeof(struct loongson_rng_ctx), 155 + .cra_module = THIS_MODULE, 156 + .cra_init = loongson_rng_init, 157 + .cra_exit = loongson_rng_exit, 158 + }, 159 + }; 160 + 161 + static int loongson_rng_probe(struct platform_device *pdev) 162 + { 163 + struct loongson_rng_cmd *cmd; 164 + struct loongson_rng *rng; 165 + int ret = 0; 166 + 167 + rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL); 168 + if (!rng) 169 + return -ENOMEM; 170 + 171 + rng->engine = loongson_se_init_engine(pdev->dev.parent, SE_ENGINE_RNG); 172 + if (!rng->engine) 173 + return -ENODEV; 174 + cmd = rng->engine->command; 175 + cmd->cmd_id = SE_CMD_RNG; 176 + cmd->out_off = rng->engine->buffer_off; 177 + mutex_init(&rng->lock); 178 + 179 + mutex_lock(&rng_devices.lock); 180 + 181 + if (!rng_devices.registered) { 182 + ret = crypto_register_rng(&loongson_rng_alg); 183 + if (ret) { 184 + dev_err(&pdev->dev, "failed to register crypto(%d)\n", ret); 185 + goto out; 186 + } 187 + rng_devices.registered = 1; 188 + } 189 + 190 + list_add_tail(&rng->list, &rng_devices.list); 191 + out: 192 + mutex_unlock(&rng_devices.lock); 193 + 194 + return ret; 195 + } 196 + 197 + static struct platform_driver loongson_rng_driver = { 198 + .probe = loongson_rng_probe, 199 + .driver = { 200 + .name = "loongson-rng", 201 + }, 202 + }; 203 + module_platform_driver(loongson_rng_driver); 204 + 205 + MODULE_ALIAS("platform:loongson-rng"); 206 + MODULE_LICENSE("GPL"); 207 + MODULE_AUTHOR("Yinggang Gu <guyinggang@loongson.cn>"); 208 + MODULE_AUTHOR("Qunqin Zhao <zhaoqunqin@loongson.cn>"); 209 + MODULE_DESCRIPTION("Loongson Random Number Generator driver");