1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright 2013 Michael Ellerman, Guo Chao, IBM Corp. |
4 | */ |
5 | |
6 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
7 | |
8 | #include <linux/module.h> |
9 | #include <linux/mod_devicetable.h> |
10 | #include <linux/kernel.h> |
11 | #include <linux/platform_device.h> |
12 | #include <linux/random.h> |
13 | #include <linux/hw_random.h> |
14 | #include <asm/archrandom.h> |
15 | |
16 | static int powernv_rng_read(struct hwrng *rng, void *data, size_t max, bool wait) |
17 | { |
18 | unsigned long *buf; |
19 | int i, len; |
20 | |
21 | /* We rely on rng_buffer_size() being >= sizeof(unsigned long) */ |
22 | len = max / sizeof(unsigned long); |
23 | |
24 | buf = (unsigned long *)data; |
25 | |
26 | for (i = 0; i < len; i++) |
27 | pnv_get_random_long(buf++); |
28 | |
29 | return len * sizeof(unsigned long); |
30 | } |
31 | |
32 | static struct hwrng powernv_hwrng = { |
33 | .name = "powernv-rng" , |
34 | .read = powernv_rng_read, |
35 | }; |
36 | |
37 | static int powernv_rng_probe(struct platform_device *pdev) |
38 | { |
39 | int rc; |
40 | |
41 | rc = devm_hwrng_register(dev: &pdev->dev, rng: &powernv_hwrng); |
42 | if (rc) { |
43 | /* We only register one device, ignore any others */ |
44 | if (rc == -EEXIST) |
45 | rc = -ENODEV; |
46 | |
47 | return rc; |
48 | } |
49 | |
50 | pr_info("Registered powernv hwrng.\n" ); |
51 | |
52 | return 0; |
53 | } |
54 | |
55 | static const struct of_device_id powernv_rng_match[] = { |
56 | { .compatible = "ibm,power-rng" ,}, |
57 | {}, |
58 | }; |
59 | MODULE_DEVICE_TABLE(of, powernv_rng_match); |
60 | |
61 | static struct platform_driver powernv_rng_driver = { |
62 | .driver = { |
63 | .name = "powernv_rng" , |
64 | .of_match_table = powernv_rng_match, |
65 | }, |
66 | .probe = powernv_rng_probe, |
67 | }; |
68 | module_platform_driver(powernv_rng_driver); |
69 | |
70 | MODULE_LICENSE("GPL" ); |
71 | MODULE_DESCRIPTION("Bare metal HWRNG driver for POWER7+ and above" ); |
72 | |