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 18static 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 34static struct hwrng powernv_hwrng = { 35 .name = "powernv-rng", 36 .read = powernv_rng_read, 37}; 38 39static int powernv_rng_remove(struct platform_device *pdev) 40{ 41 hwrng_unregister(&powernv_hwrng); 42 43 return 0; 44} 45 46static 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 64static const struct of_device_id powernv_rng_match[] = { 65 { .compatible = "ibm,power-rng",}, 66 {}, 67}; 68MODULE_DEVICE_TABLE(of, powernv_rng_match); 69 70static 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}; 78module_platform_driver(powernv_rng_driver); 79 80MODULE_LICENSE("GPL"); 81MODULE_DESCRIPTION("Bare metal HWRNG driver for POWER7+ and above"); 82