18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2010 Michael Neuling IBM Corporation 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Driver for the pseries hardware RNG for POWER7+ and above 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/hw_random.h> 138c2ecf20Sopenharmony_ci#include <asm/vio.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic int pseries_rng_read(struct hwrng *rng, void *data, size_t max, bool wait) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci u64 buffer[PLPAR_HCALL_BUFSIZE]; 198c2ecf20Sopenharmony_ci int rc; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci rc = plpar_hcall(H_RANDOM, (unsigned long *)buffer); 228c2ecf20Sopenharmony_ci if (rc != H_SUCCESS) { 238c2ecf20Sopenharmony_ci pr_err_ratelimited("H_RANDOM call failed %d\n", rc); 248c2ecf20Sopenharmony_ci return -EIO; 258c2ecf20Sopenharmony_ci } 268c2ecf20Sopenharmony_ci memcpy(data, buffer, 8); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci /* The hypervisor interface returns 64 bits */ 298c2ecf20Sopenharmony_ci return 8; 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/** 338c2ecf20Sopenharmony_ci * pseries_rng_get_desired_dma - Return desired DMA allocate for CMO operations 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * This is a required function for a driver to operate in a CMO environment 368c2ecf20Sopenharmony_ci * but this device does not make use of DMA allocations, return 0. 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * Return value: 398c2ecf20Sopenharmony_ci * Number of bytes of IO data the driver will need to perform well -> 0 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_cistatic unsigned long pseries_rng_get_desired_dma(struct vio_dev *vdev) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci return 0; 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic struct hwrng pseries_rng = { 478c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 488c2ecf20Sopenharmony_ci .read = pseries_rng_read, 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic int pseries_rng_probe(struct vio_dev *dev, 528c2ecf20Sopenharmony_ci const struct vio_device_id *id) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci return hwrng_register(&pseries_rng); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic int pseries_rng_remove(struct vio_dev *dev) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci hwrng_unregister(&pseries_rng); 608c2ecf20Sopenharmony_ci return 0; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic const struct vio_device_id pseries_rng_driver_ids[] = { 648c2ecf20Sopenharmony_ci { "ibm,random-v1", "ibm,random"}, 658c2ecf20Sopenharmony_ci { "", "" } 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(vio, pseries_rng_driver_ids); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic struct vio_driver pseries_rng_driver = { 708c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 718c2ecf20Sopenharmony_ci .probe = pseries_rng_probe, 728c2ecf20Sopenharmony_ci .remove = pseries_rng_remove, 738c2ecf20Sopenharmony_ci .get_desired_dma = pseries_rng_get_desired_dma, 748c2ecf20Sopenharmony_ci .id_table = pseries_rng_driver_ids 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic int __init rng_init(void) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci pr_info("Registering IBM pSeries RNG driver\n"); 808c2ecf20Sopenharmony_ci return vio_register_driver(&pseries_rng_driver); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cimodule_init(rng_init); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic void __exit rng_exit(void) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci vio_unregister_driver(&pseries_rng_driver); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_cimodule_exit(rng_exit); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 928c2ecf20Sopenharmony_ciMODULE_AUTHOR("Michael Neuling <mikey@neuling.org>"); 938c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("H/W RNG driver for IBM pSeries processors"); 94