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