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