1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2019 HiSilicon Limited. */
4 #include <crypto/internal/rng.h>
5 #include <linux/acpi.h>
6 #include <linux/crypto.h>
8 #include <linux/hw_random.h>
10 #include <linux/iopoll.h>
11 #include <linux/kernel.h>
12 #include <linux/list.h>
13 #include <linux/module.h>
14 #include <linux/mutex.h>
15 #include <linux/platform_device.h>
16 #include <linux/random.h>
18 #define HISI_TRNG_REG 0x00F0
19 #define HISI_TRNG_BYTES 4
20 #define HISI_TRNG_QUALITY 512
21 #define HISI_TRNG_VERSION 0x01B8
22 #define HISI_TRNG_VER_V1 GENMASK(31, 0)
24 #define TIMEOUT_US 10000
25 #define SW_DRBG_NUM_SHIFT 2
26 #define SW_DRBG_KEY_BASE 0x082C
27 #define SW_DRBG_SEED(n) (SW_DRBG_KEY_BASE - ((n) << SW_DRBG_NUM_SHIFT))
28 #define SW_DRBG_SEED_REGS_NUM 12
29 #define SW_DRBG_SEED_SIZE 48
30 #define SW_DRBG_BLOCKS 0x0830
31 #define SW_DRBG_INIT 0x0834
32 #define SW_DRBG_GEN 0x083c
33 #define SW_DRBG_STATUS 0x0840
34 #define SW_DRBG_BLOCKS_NUM 4095
35 #define SW_DRBG_DATA_BASE 0x0850
36 #define SW_DRBG_DATA_NUM 4
37 #define SW_DRBG_DATA(n) (SW_DRBG_DATA_BASE - ((n) << SW_DRBG_NUM_SHIFT))
38 #define SW_DRBG_BYTES 16
39 #define SW_DRBG_ENABLE_SHIFT 12
40 #define SEED_SHIFT_24 24
41 #define SEED_SHIFT_16 16
42 #define SEED_SHIFT_8 8
44 struct hisi_trng_list
{
46 struct list_head list
;
52 struct hisi_trng_list
*trng_list
;
53 struct list_head list
;
60 struct hisi_trng_ctx
{
61 struct hisi_trng
*trng
;
64 static atomic_t trng_active_devs
;
65 static struct hisi_trng_list trng_devices
;
67 static void hisi_trng_set_seed(struct hisi_trng
*trng
, const u8
*seed
)
71 for (i
= 0; i
< SW_DRBG_SEED_SIZE
;
72 i
+= SW_DRBG_SEED_SIZE
/ SW_DRBG_SEED_REGS_NUM
) {
73 val
= seed
[i
] << SEED_SHIFT_24
;
74 val
|= seed
[i
+ 1UL] << SEED_SHIFT_16
;
75 val
|= seed
[i
+ 2UL] << SEED_SHIFT_8
;
78 seed_reg
= (i
>> SW_DRBG_NUM_SHIFT
) % SW_DRBG_SEED_REGS_NUM
;
79 writel(val
, trng
->base
+ SW_DRBG_SEED(seed_reg
));
83 static int hisi_trng_seed(struct crypto_rng
*tfm
, const u8
*seed
,
86 struct hisi_trng_ctx
*ctx
= crypto_rng_ctx(tfm
);
87 struct hisi_trng
*trng
= ctx
->trng
;
91 if (slen
< SW_DRBG_SEED_SIZE
) {
92 pr_err("slen(%u) is not matched with trng(%d)\n", slen
,
97 writel(0x0, trng
->base
+ SW_DRBG_BLOCKS
);
98 hisi_trng_set_seed(trng
, seed
);
100 writel(SW_DRBG_BLOCKS_NUM
| (0x1 << SW_DRBG_ENABLE_SHIFT
),
101 trng
->base
+ SW_DRBG_BLOCKS
);
102 writel(0x1, trng
->base
+ SW_DRBG_INIT
);
104 ret
= readl_relaxed_poll_timeout(trng
->base
+ SW_DRBG_STATUS
,
105 val
, val
& BIT(0), SLEEP_US
, TIMEOUT_US
);
107 pr_err("fail to init trng(%d)\n", ret
);
112 static int hisi_trng_generate(struct crypto_rng
*tfm
, const u8
*src
,
113 unsigned int slen
, u8
*dstn
, unsigned int dlen
)
115 struct hisi_trng_ctx
*ctx
= crypto_rng_ctx(tfm
);
116 struct hisi_trng
*trng
= ctx
->trng
;
117 u32 data
[SW_DRBG_DATA_NUM
];
123 if (dlen
> SW_DRBG_BLOCKS_NUM
* SW_DRBG_BYTES
|| dlen
== 0) {
124 pr_err("dlen(%u) exceeds limit(%d)!\n", dlen
,
125 SW_DRBG_BLOCKS_NUM
* SW_DRBG_BYTES
);
130 ret
= readl_relaxed_poll_timeout(trng
->base
+ SW_DRBG_STATUS
,
131 val
, val
& BIT(1), SLEEP_US
, TIMEOUT_US
);
133 pr_err("fail to generate random number(%d)!\n", ret
);
137 for (i
= 0; i
< SW_DRBG_DATA_NUM
; i
++)
138 data
[i
] = readl(trng
->base
+ SW_DRBG_DATA(i
));
140 if (dlen
- currsize
>= SW_DRBG_BYTES
) {
141 memcpy(dstn
+ currsize
, data
, SW_DRBG_BYTES
);
142 currsize
+= SW_DRBG_BYTES
;
144 memcpy(dstn
+ currsize
, data
, dlen
- currsize
);
148 writel(0x1, trng
->base
+ SW_DRBG_GEN
);
149 } while (currsize
< dlen
);
154 static int hisi_trng_init(struct crypto_tfm
*tfm
)
156 struct hisi_trng_ctx
*ctx
= crypto_tfm_ctx(tfm
);
157 struct hisi_trng
*trng
;
160 mutex_lock(&trng_devices
.lock
);
161 list_for_each_entry(trng
, &trng_devices
.list
, list
) {
162 if (!trng
->is_used
) {
163 trng
->is_used
= true;
169 mutex_unlock(&trng_devices
.lock
);
174 static void hisi_trng_exit(struct crypto_tfm
*tfm
)
176 struct hisi_trng_ctx
*ctx
= crypto_tfm_ctx(tfm
);
178 mutex_lock(&trng_devices
.lock
);
179 ctx
->trng
->is_used
= false;
180 mutex_unlock(&trng_devices
.lock
);
183 static int hisi_trng_read(struct hwrng
*rng
, void *buf
, size_t max
, bool wait
)
185 struct hisi_trng
*trng
;
190 trng
= container_of(rng
, struct hisi_trng
, rng
);
193 ret
= readl_poll_timeout(trng
->base
+ HISI_TRNG_REG
, val
,
194 val
, SLEEP_US
, TIMEOUT_US
);
198 if (max
- currsize
>= HISI_TRNG_BYTES
) {
199 memcpy(buf
+ currsize
, &val
, HISI_TRNG_BYTES
);
200 currsize
+= HISI_TRNG_BYTES
;
206 /* copy remaining bytes */
207 memcpy(buf
+ currsize
, &val
, max
- currsize
);
209 } while (currsize
< max
);
214 static struct rng_alg hisi_trng_alg
= {
215 .generate
= hisi_trng_generate
,
216 .seed
= hisi_trng_seed
,
217 .seedsize
= SW_DRBG_SEED_SIZE
,
219 .cra_name
= "stdrng",
220 .cra_driver_name
= "hisi_stdrng",
222 .cra_ctxsize
= sizeof(struct hisi_trng_ctx
),
223 .cra_module
= THIS_MODULE
,
224 .cra_init
= hisi_trng_init
,
225 .cra_exit
= hisi_trng_exit
,
229 static void hisi_trng_add_to_list(struct hisi_trng
*trng
)
231 mutex_lock(&trng_devices
.lock
);
232 list_add_tail(&trng
->list
, &trng_devices
.list
);
233 mutex_unlock(&trng_devices
.lock
);
236 static int hisi_trng_del_from_list(struct hisi_trng
*trng
)
240 mutex_lock(&trng_devices
.lock
);
241 if (!trng
->is_used
) {
242 list_del(&trng
->list
);
245 mutex_unlock(&trng_devices
.lock
);
250 static int hisi_trng_probe(struct platform_device
*pdev
)
252 struct hisi_trng
*trng
;
255 trng
= devm_kzalloc(&pdev
->dev
, sizeof(*trng
), GFP_KERNEL
);
259 platform_set_drvdata(pdev
, trng
);
261 trng
->base
= devm_platform_ioremap_resource(pdev
, 0);
262 if (IS_ERR(trng
->base
))
263 return PTR_ERR(trng
->base
);
265 trng
->is_used
= false;
266 trng
->ver
= readl(trng
->base
+ HISI_TRNG_VERSION
);
267 if (!trng_devices
.is_init
) {
268 INIT_LIST_HEAD(&trng_devices
.list
);
269 mutex_init(&trng_devices
.lock
);
270 trng_devices
.is_init
= true;
273 hisi_trng_add_to_list(trng
);
274 if (trng
->ver
!= HISI_TRNG_VER_V1
&&
275 atomic_inc_return(&trng_active_devs
) == 1) {
276 ret
= crypto_register_rng(&hisi_trng_alg
);
279 "failed to register crypto(%d)\n", ret
);
280 atomic_dec_return(&trng_active_devs
);
281 goto err_remove_from_list
;
285 trng
->rng
.name
= pdev
->name
;
286 trng
->rng
.read
= hisi_trng_read
;
287 trng
->rng
.quality
= HISI_TRNG_QUALITY
;
288 ret
= devm_hwrng_register(&pdev
->dev
, &trng
->rng
);
290 dev_err(&pdev
->dev
, "failed to register hwrng: %d!\n", ret
);
291 goto err_crypto_unregister
;
296 err_crypto_unregister
:
297 if (trng
->ver
!= HISI_TRNG_VER_V1
&&
298 atomic_dec_return(&trng_active_devs
) == 0)
299 crypto_unregister_rng(&hisi_trng_alg
);
301 err_remove_from_list
:
302 hisi_trng_del_from_list(trng
);
306 static void hisi_trng_remove(struct platform_device
*pdev
)
308 struct hisi_trng
*trng
= platform_get_drvdata(pdev
);
310 /* Wait until the task is finished */
311 while (hisi_trng_del_from_list(trng
))
314 if (trng
->ver
!= HISI_TRNG_VER_V1
&&
315 atomic_dec_return(&trng_active_devs
) == 0)
316 crypto_unregister_rng(&hisi_trng_alg
);
319 static const struct acpi_device_id hisi_trng_acpi_match
[] = {
323 MODULE_DEVICE_TABLE(acpi
, hisi_trng_acpi_match
);
325 static struct platform_driver hisi_trng_driver
= {
326 .probe
= hisi_trng_probe
,
327 .remove
= hisi_trng_remove
,
329 .name
= "hisi-trng-v2",
330 .acpi_match_table
= ACPI_PTR(hisi_trng_acpi_match
),
334 module_platform_driver(hisi_trng_driver
);
336 MODULE_LICENSE("GPL v2");
337 MODULE_AUTHOR("Weili Qian <qianweili@huawei.com>");
338 MODULE_AUTHOR("Zaibo Xu <xuzaibo@huawei.com>");
339 MODULE_DESCRIPTION("HiSilicon true random number generator V2 driver");