diff options
Diffstat (limited to 'drivers/char/hw_random/powernv-rng.c')
-rw-r--r-- | drivers/char/hw_random/powernv-rng.c | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/drivers/char/hw_random/powernv-rng.c b/drivers/char/hw_random/powernv-rng.c new file mode 100644 index 000000000000..3f4f63204560 --- /dev/null +++ b/drivers/char/hw_random/powernv-rng.c | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Michael Ellerman, Guo Chao, IBM Corp. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | */ | ||
9 | |||
10 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/random.h> | ||
16 | #include <linux/hw_random.h> | ||
17 | |||
18 | static int powernv_rng_read(struct hwrng *rng, void *data, size_t max, bool wait) | ||
19 | { | ||
20 | unsigned long *buf; | ||
21 | int i, len; | ||
22 | |||
23 | /* We rely on rng_buffer_size() being >= sizeof(unsigned long) */ | ||
24 | len = max / sizeof(unsigned long); | ||
25 | |||
26 | buf = (unsigned long *)data; | ||
27 | |||
28 | for (i = 0; i < len; i++) | ||
29 | powernv_get_random_long(buf++); | ||
30 | |||
31 | return len * sizeof(unsigned long); | ||
32 | } | ||
33 | |||
34 | static struct hwrng powernv_hwrng = { | ||
35 | .name = "powernv-rng", | ||
36 | .read = powernv_rng_read, | ||
37 | }; | ||
38 | |||
39 | static int powernv_rng_remove(struct platform_device *pdev) | ||
40 | { | ||
41 | hwrng_unregister(&powernv_hwrng); | ||
42 | |||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static int powernv_rng_probe(struct platform_device *pdev) | ||
47 | { | ||
48 | int rc; | ||
49 | |||
50 | rc = hwrng_register(&powernv_hwrng); | ||
51 | if (rc) { | ||
52 | /* We only register one device, ignore any others */ | ||
53 | if (rc == -EEXIST) | ||
54 | rc = -ENODEV; | ||
55 | |||
56 | return rc; | ||
57 | } | ||
58 | |||
59 | pr_info("Registered powernv hwrng.\n"); | ||
60 | |||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | static struct of_device_id powernv_rng_match[] = { | ||
65 | { .compatible = "ibm,power-rng",}, | ||
66 | {}, | ||
67 | }; | ||
68 | MODULE_DEVICE_TABLE(of, powernv_rng_match); | ||
69 | |||
70 | static struct platform_driver powernv_rng_driver = { | ||
71 | .driver = { | ||
72 | .name = "powernv_rng", | ||
73 | .of_match_table = powernv_rng_match, | ||
74 | }, | ||
75 | .probe = powernv_rng_probe, | ||
76 | .remove = powernv_rng_remove, | ||
77 | }; | ||
78 | module_platform_driver(powernv_rng_driver); | ||
79 | |||
80 | MODULE_LICENSE("GPL"); | ||
81 | MODULE_DESCRIPTION("Bare metal HWRNG driver for POWER7+ and above"); | ||