162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* n2-drv.c: Niagara-2 RNG driver. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2008, 2011 David S. Miller <davem@davemloft.net> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/types.h> 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/workqueue.h> 1362306a36Sopenharmony_ci#include <linux/preempt.h> 1462306a36Sopenharmony_ci#include <linux/hw_random.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/of.h> 1762306a36Sopenharmony_ci#include <linux/of_device.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <asm/hypervisor.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include "n2rng.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define DRV_MODULE_NAME "n2rng" 2462306a36Sopenharmony_ci#define PFX DRV_MODULE_NAME ": " 2562306a36Sopenharmony_ci#define DRV_MODULE_VERSION "0.3" 2662306a36Sopenharmony_ci#define DRV_MODULE_RELDATE "Jan 7, 2017" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic char version[] = 2962306a36Sopenharmony_ci DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ciMODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); 3262306a36Sopenharmony_ciMODULE_DESCRIPTION("Niagara2 RNG driver"); 3362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 3462306a36Sopenharmony_ciMODULE_VERSION(DRV_MODULE_VERSION); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* The Niagara2 RNG provides a 64-bit read-only random number 3762306a36Sopenharmony_ci * register, plus a control register. Access to the RNG is 3862306a36Sopenharmony_ci * virtualized through the hypervisor so that both guests and control 3962306a36Sopenharmony_ci * nodes can access the device. 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * The entropy source consists of raw entropy sources, each 4262306a36Sopenharmony_ci * constructed from a voltage controlled oscillator whose phase is 4362306a36Sopenharmony_ci * jittered by thermal noise sources. 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * The oscillator in each of the three raw entropy sources run at 4662306a36Sopenharmony_ci * different frequencies. Normally, all three generator outputs are 4762306a36Sopenharmony_ci * gathered, xored together, and fed into a CRC circuit, the output of 4862306a36Sopenharmony_ci * which is the 64-bit read-only register. 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * Some time is necessary for all the necessary entropy to build up 5162306a36Sopenharmony_ci * such that a full 64-bits of entropy are available in the register. 5262306a36Sopenharmony_ci * In normal operating mode (RNG_CTL_LFSR is set), the chip implements 5362306a36Sopenharmony_ci * an interlock which blocks register reads until sufficient entropy 5462306a36Sopenharmony_ci * is available. 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci * A control register is provided for adjusting various aspects of RNG 5762306a36Sopenharmony_ci * operation, and to enable diagnostic modes. Each of the three raw 5862306a36Sopenharmony_ci * entropy sources has an enable bit (RNG_CTL_ES{1,2,3}). Also 5962306a36Sopenharmony_ci * provided are fields for controlling the minimum time in cycles 6062306a36Sopenharmony_ci * between read accesses to the register (RNG_CTL_WAIT, this controls 6162306a36Sopenharmony_ci * the interlock described in the previous paragraph). 6262306a36Sopenharmony_ci * 6362306a36Sopenharmony_ci * The standard setting is to have the mode bit (RNG_CTL_LFSR) set, 6462306a36Sopenharmony_ci * all three entropy sources enabled, and the interlock time set 6562306a36Sopenharmony_ci * appropriately. 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci * The CRC polynomial used by the chip is: 6862306a36Sopenharmony_ci * 6962306a36Sopenharmony_ci * P(X) = x64 + x61 + x57 + x56 + x52 + x51 + x50 + x48 + x47 + x46 + 7062306a36Sopenharmony_ci * x43 + x42 + x41 + x39 + x38 + x37 + x35 + x32 + x28 + x25 + 7162306a36Sopenharmony_ci * x22 + x21 + x17 + x15 + x13 + x12 + x11 + x7 + x5 + x + 1 7262306a36Sopenharmony_ci * 7362306a36Sopenharmony_ci * The RNG_CTL_VCO value of each noise cell must be programmed 7462306a36Sopenharmony_ci * separately. This is why 4 control register values must be provided 7562306a36Sopenharmony_ci * to the hypervisor. During a write, the hypervisor writes them all, 7662306a36Sopenharmony_ci * one at a time, to the actual RNG_CTL register. The first three 7762306a36Sopenharmony_ci * values are used to setup the desired RNG_CTL_VCO for each entropy 7862306a36Sopenharmony_ci * source, for example: 7962306a36Sopenharmony_ci * 8062306a36Sopenharmony_ci * control 0: (1 << RNG_CTL_VCO_SHIFT) | RNG_CTL_ES1 8162306a36Sopenharmony_ci * control 1: (2 << RNG_CTL_VCO_SHIFT) | RNG_CTL_ES2 8262306a36Sopenharmony_ci * control 2: (3 << RNG_CTL_VCO_SHIFT) | RNG_CTL_ES3 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * And then the fourth value sets the final chip state and enables 8562306a36Sopenharmony_ci * desired. 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic int n2rng_hv_err_trans(unsigned long hv_err) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci switch (hv_err) { 9162306a36Sopenharmony_ci case HV_EOK: 9262306a36Sopenharmony_ci return 0; 9362306a36Sopenharmony_ci case HV_EWOULDBLOCK: 9462306a36Sopenharmony_ci return -EAGAIN; 9562306a36Sopenharmony_ci case HV_ENOACCESS: 9662306a36Sopenharmony_ci return -EPERM; 9762306a36Sopenharmony_ci case HV_EIO: 9862306a36Sopenharmony_ci return -EIO; 9962306a36Sopenharmony_ci case HV_EBUSY: 10062306a36Sopenharmony_ci return -EBUSY; 10162306a36Sopenharmony_ci case HV_EBADALIGN: 10262306a36Sopenharmony_ci case HV_ENORADDR: 10362306a36Sopenharmony_ci return -EFAULT; 10462306a36Sopenharmony_ci default: 10562306a36Sopenharmony_ci return -EINVAL; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic unsigned long n2rng_generic_read_control_v2(unsigned long ra, 11062306a36Sopenharmony_ci unsigned long unit) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci unsigned long hv_err, state, ticks, watchdog_delta, watchdog_status; 11362306a36Sopenharmony_ci int block = 0, busy = 0; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci while (1) { 11662306a36Sopenharmony_ci hv_err = sun4v_rng_ctl_read_v2(ra, unit, &state, 11762306a36Sopenharmony_ci &ticks, 11862306a36Sopenharmony_ci &watchdog_delta, 11962306a36Sopenharmony_ci &watchdog_status); 12062306a36Sopenharmony_ci if (hv_err == HV_EOK) 12162306a36Sopenharmony_ci break; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (hv_err == HV_EBUSY) { 12462306a36Sopenharmony_ci if (++busy >= N2RNG_BUSY_LIMIT) 12562306a36Sopenharmony_ci break; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci udelay(1); 12862306a36Sopenharmony_ci } else if (hv_err == HV_EWOULDBLOCK) { 12962306a36Sopenharmony_ci if (++block >= N2RNG_BLOCK_LIMIT) 13062306a36Sopenharmony_ci break; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci __delay(ticks); 13362306a36Sopenharmony_ci } else 13462306a36Sopenharmony_ci break; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci return hv_err; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci/* In multi-socket situations, the hypervisor might need to 14162306a36Sopenharmony_ci * queue up the RNG control register write if it's for a unit 14262306a36Sopenharmony_ci * that is on a cpu socket other than the one we are executing on. 14362306a36Sopenharmony_ci * 14462306a36Sopenharmony_ci * We poll here waiting for a successful read of that control 14562306a36Sopenharmony_ci * register to make sure the write has been actually performed. 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_cistatic unsigned long n2rng_control_settle_v2(struct n2rng *np, int unit) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci unsigned long ra = __pa(&np->scratch_control[0]); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci return n2rng_generic_read_control_v2(ra, unit); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic unsigned long n2rng_write_ctl_one(struct n2rng *np, int unit, 15562306a36Sopenharmony_ci unsigned long state, 15662306a36Sopenharmony_ci unsigned long control_ra, 15762306a36Sopenharmony_ci unsigned long watchdog_timeout, 15862306a36Sopenharmony_ci unsigned long *ticks) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci unsigned long hv_err; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (np->hvapi_major == 1) { 16362306a36Sopenharmony_ci hv_err = sun4v_rng_ctl_write_v1(control_ra, state, 16462306a36Sopenharmony_ci watchdog_timeout, ticks); 16562306a36Sopenharmony_ci } else { 16662306a36Sopenharmony_ci hv_err = sun4v_rng_ctl_write_v2(control_ra, state, 16762306a36Sopenharmony_ci watchdog_timeout, unit); 16862306a36Sopenharmony_ci if (hv_err == HV_EOK) 16962306a36Sopenharmony_ci hv_err = n2rng_control_settle_v2(np, unit); 17062306a36Sopenharmony_ci *ticks = N2RNG_ACCUM_CYCLES_DEFAULT; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci return hv_err; 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic int n2rng_generic_read_data(unsigned long data_ra) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci unsigned long ticks, hv_err; 17962306a36Sopenharmony_ci int block = 0, hcheck = 0; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci while (1) { 18262306a36Sopenharmony_ci hv_err = sun4v_rng_data_read(data_ra, &ticks); 18362306a36Sopenharmony_ci if (hv_err == HV_EOK) 18462306a36Sopenharmony_ci return 0; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (hv_err == HV_EWOULDBLOCK) { 18762306a36Sopenharmony_ci if (++block >= N2RNG_BLOCK_LIMIT) 18862306a36Sopenharmony_ci return -EWOULDBLOCK; 18962306a36Sopenharmony_ci __delay(ticks); 19062306a36Sopenharmony_ci } else if (hv_err == HV_ENOACCESS) { 19162306a36Sopenharmony_ci return -EPERM; 19262306a36Sopenharmony_ci } else if (hv_err == HV_EIO) { 19362306a36Sopenharmony_ci if (++hcheck >= N2RNG_HCHECK_LIMIT) 19462306a36Sopenharmony_ci return -EIO; 19562306a36Sopenharmony_ci udelay(10000); 19662306a36Sopenharmony_ci } else 19762306a36Sopenharmony_ci return -ENODEV; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic unsigned long n2rng_read_diag_data_one(struct n2rng *np, 20262306a36Sopenharmony_ci unsigned long unit, 20362306a36Sopenharmony_ci unsigned long data_ra, 20462306a36Sopenharmony_ci unsigned long data_len, 20562306a36Sopenharmony_ci unsigned long *ticks) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci unsigned long hv_err; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (np->hvapi_major == 1) { 21062306a36Sopenharmony_ci hv_err = sun4v_rng_data_read_diag_v1(data_ra, data_len, ticks); 21162306a36Sopenharmony_ci } else { 21262306a36Sopenharmony_ci hv_err = sun4v_rng_data_read_diag_v2(data_ra, data_len, 21362306a36Sopenharmony_ci unit, ticks); 21462306a36Sopenharmony_ci if (!*ticks) 21562306a36Sopenharmony_ci *ticks = N2RNG_ACCUM_CYCLES_DEFAULT; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci return hv_err; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic int n2rng_generic_read_diag_data(struct n2rng *np, 22162306a36Sopenharmony_ci unsigned long unit, 22262306a36Sopenharmony_ci unsigned long data_ra, 22362306a36Sopenharmony_ci unsigned long data_len) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci unsigned long ticks, hv_err; 22662306a36Sopenharmony_ci int block = 0; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci while (1) { 22962306a36Sopenharmony_ci hv_err = n2rng_read_diag_data_one(np, unit, 23062306a36Sopenharmony_ci data_ra, data_len, 23162306a36Sopenharmony_ci &ticks); 23262306a36Sopenharmony_ci if (hv_err == HV_EOK) 23362306a36Sopenharmony_ci return 0; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci if (hv_err == HV_EWOULDBLOCK) { 23662306a36Sopenharmony_ci if (++block >= N2RNG_BLOCK_LIMIT) 23762306a36Sopenharmony_ci return -EWOULDBLOCK; 23862306a36Sopenharmony_ci __delay(ticks); 23962306a36Sopenharmony_ci } else if (hv_err == HV_ENOACCESS) { 24062306a36Sopenharmony_ci return -EPERM; 24162306a36Sopenharmony_ci } else if (hv_err == HV_EIO) { 24262306a36Sopenharmony_ci return -EIO; 24362306a36Sopenharmony_ci } else 24462306a36Sopenharmony_ci return -ENODEV; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic int n2rng_generic_write_control(struct n2rng *np, 25062306a36Sopenharmony_ci unsigned long control_ra, 25162306a36Sopenharmony_ci unsigned long unit, 25262306a36Sopenharmony_ci unsigned long state) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci unsigned long hv_err, ticks; 25562306a36Sopenharmony_ci int block = 0, busy = 0; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci while (1) { 25862306a36Sopenharmony_ci hv_err = n2rng_write_ctl_one(np, unit, state, control_ra, 25962306a36Sopenharmony_ci np->wd_timeo, &ticks); 26062306a36Sopenharmony_ci if (hv_err == HV_EOK) 26162306a36Sopenharmony_ci return 0; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (hv_err == HV_EWOULDBLOCK) { 26462306a36Sopenharmony_ci if (++block >= N2RNG_BLOCK_LIMIT) 26562306a36Sopenharmony_ci return -EWOULDBLOCK; 26662306a36Sopenharmony_ci __delay(ticks); 26762306a36Sopenharmony_ci } else if (hv_err == HV_EBUSY) { 26862306a36Sopenharmony_ci if (++busy >= N2RNG_BUSY_LIMIT) 26962306a36Sopenharmony_ci return -EBUSY; 27062306a36Sopenharmony_ci udelay(1); 27162306a36Sopenharmony_ci } else 27262306a36Sopenharmony_ci return -ENODEV; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci/* Just try to see if we can successfully access the control register 27762306a36Sopenharmony_ci * of the RNG on the domain on which we are currently executing. 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_cistatic int n2rng_try_read_ctl(struct n2rng *np) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci unsigned long hv_err; 28262306a36Sopenharmony_ci unsigned long x; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (np->hvapi_major == 1) { 28562306a36Sopenharmony_ci hv_err = sun4v_rng_get_diag_ctl(); 28662306a36Sopenharmony_ci } else { 28762306a36Sopenharmony_ci /* We purposefully give invalid arguments, HV_NOACCESS 28862306a36Sopenharmony_ci * is higher priority than the errors we'd get from 28962306a36Sopenharmony_ci * these other cases, and that's the error we are 29062306a36Sopenharmony_ci * truly interested in. 29162306a36Sopenharmony_ci */ 29262306a36Sopenharmony_ci hv_err = sun4v_rng_ctl_read_v2(0UL, ~0UL, &x, &x, &x, &x); 29362306a36Sopenharmony_ci switch (hv_err) { 29462306a36Sopenharmony_ci case HV_EWOULDBLOCK: 29562306a36Sopenharmony_ci case HV_ENOACCESS: 29662306a36Sopenharmony_ci break; 29762306a36Sopenharmony_ci default: 29862306a36Sopenharmony_ci hv_err = HV_EOK; 29962306a36Sopenharmony_ci break; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci return n2rng_hv_err_trans(hv_err); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic u64 n2rng_control_default(struct n2rng *np, int ctl) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci u64 val = 0; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (np->data->chip_version == 1) { 31162306a36Sopenharmony_ci val = ((2 << RNG_v1_CTL_ASEL_SHIFT) | 31262306a36Sopenharmony_ci (N2RNG_ACCUM_CYCLES_DEFAULT << RNG_v1_CTL_WAIT_SHIFT) | 31362306a36Sopenharmony_ci RNG_CTL_LFSR); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci switch (ctl) { 31662306a36Sopenharmony_ci case 0: 31762306a36Sopenharmony_ci val |= (1 << RNG_v1_CTL_VCO_SHIFT) | RNG_CTL_ES1; 31862306a36Sopenharmony_ci break; 31962306a36Sopenharmony_ci case 1: 32062306a36Sopenharmony_ci val |= (2 << RNG_v1_CTL_VCO_SHIFT) | RNG_CTL_ES2; 32162306a36Sopenharmony_ci break; 32262306a36Sopenharmony_ci case 2: 32362306a36Sopenharmony_ci val |= (3 << RNG_v1_CTL_VCO_SHIFT) | RNG_CTL_ES3; 32462306a36Sopenharmony_ci break; 32562306a36Sopenharmony_ci case 3: 32662306a36Sopenharmony_ci val |= RNG_CTL_ES1 | RNG_CTL_ES2 | RNG_CTL_ES3; 32762306a36Sopenharmony_ci break; 32862306a36Sopenharmony_ci default: 32962306a36Sopenharmony_ci break; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci } else { 33362306a36Sopenharmony_ci val = ((2 << RNG_v2_CTL_ASEL_SHIFT) | 33462306a36Sopenharmony_ci (N2RNG_ACCUM_CYCLES_DEFAULT << RNG_v2_CTL_WAIT_SHIFT) | 33562306a36Sopenharmony_ci RNG_CTL_LFSR); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci switch (ctl) { 33862306a36Sopenharmony_ci case 0: 33962306a36Sopenharmony_ci val |= (1 << RNG_v2_CTL_VCO_SHIFT) | RNG_CTL_ES1; 34062306a36Sopenharmony_ci break; 34162306a36Sopenharmony_ci case 1: 34262306a36Sopenharmony_ci val |= (2 << RNG_v2_CTL_VCO_SHIFT) | RNG_CTL_ES2; 34362306a36Sopenharmony_ci break; 34462306a36Sopenharmony_ci case 2: 34562306a36Sopenharmony_ci val |= (3 << RNG_v2_CTL_VCO_SHIFT) | RNG_CTL_ES3; 34662306a36Sopenharmony_ci break; 34762306a36Sopenharmony_ci case 3: 34862306a36Sopenharmony_ci val |= RNG_CTL_ES1 | RNG_CTL_ES2 | RNG_CTL_ES3; 34962306a36Sopenharmony_ci break; 35062306a36Sopenharmony_ci default: 35162306a36Sopenharmony_ci break; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return val; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic void n2rng_control_swstate_init(struct n2rng *np) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci int i; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci np->flags |= N2RNG_FLAG_CONTROL; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci np->health_check_sec = N2RNG_HEALTH_CHECK_SEC_DEFAULT; 36562306a36Sopenharmony_ci np->accum_cycles = N2RNG_ACCUM_CYCLES_DEFAULT; 36662306a36Sopenharmony_ci np->wd_timeo = N2RNG_WD_TIMEO_DEFAULT; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci for (i = 0; i < np->num_units; i++) { 36962306a36Sopenharmony_ci struct n2rng_unit *up = &np->units[i]; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci up->control[0] = n2rng_control_default(np, 0); 37262306a36Sopenharmony_ci up->control[1] = n2rng_control_default(np, 1); 37362306a36Sopenharmony_ci up->control[2] = n2rng_control_default(np, 2); 37462306a36Sopenharmony_ci up->control[3] = n2rng_control_default(np, 3); 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci np->hv_state = HV_RNG_STATE_UNCONFIGURED; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic int n2rng_grab_diag_control(struct n2rng *np) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci int i, busy_count, err = -ENODEV; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci busy_count = 0; 38562306a36Sopenharmony_ci for (i = 0; i < 100; i++) { 38662306a36Sopenharmony_ci err = n2rng_try_read_ctl(np); 38762306a36Sopenharmony_ci if (err != -EAGAIN) 38862306a36Sopenharmony_ci break; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (++busy_count > 100) { 39162306a36Sopenharmony_ci dev_err(&np->op->dev, 39262306a36Sopenharmony_ci "Grab diag control timeout.\n"); 39362306a36Sopenharmony_ci return -ENODEV; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci udelay(1); 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci return err; 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic int n2rng_init_control(struct n2rng *np) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci int err = n2rng_grab_diag_control(np); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* Not in the control domain, that's OK we are only a consumer 40762306a36Sopenharmony_ci * of the RNG data, we don't setup and program it. 40862306a36Sopenharmony_ci */ 40962306a36Sopenharmony_ci if (err == -EPERM) 41062306a36Sopenharmony_ci return 0; 41162306a36Sopenharmony_ci if (err) 41262306a36Sopenharmony_ci return err; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci n2rng_control_swstate_init(np); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci return 0; 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic int n2rng_data_read(struct hwrng *rng, u32 *data) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct n2rng *np = (struct n2rng *) rng->priv; 42262306a36Sopenharmony_ci unsigned long ra = __pa(&np->test_data); 42362306a36Sopenharmony_ci int len; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (!(np->flags & N2RNG_FLAG_READY)) { 42662306a36Sopenharmony_ci len = 0; 42762306a36Sopenharmony_ci } else if (np->flags & N2RNG_FLAG_BUFFER_VALID) { 42862306a36Sopenharmony_ci np->flags &= ~N2RNG_FLAG_BUFFER_VALID; 42962306a36Sopenharmony_ci *data = np->buffer; 43062306a36Sopenharmony_ci len = 4; 43162306a36Sopenharmony_ci } else { 43262306a36Sopenharmony_ci int err = n2rng_generic_read_data(ra); 43362306a36Sopenharmony_ci if (!err) { 43462306a36Sopenharmony_ci np->flags |= N2RNG_FLAG_BUFFER_VALID; 43562306a36Sopenharmony_ci np->buffer = np->test_data >> 32; 43662306a36Sopenharmony_ci *data = np->test_data & 0xffffffff; 43762306a36Sopenharmony_ci len = 4; 43862306a36Sopenharmony_ci } else { 43962306a36Sopenharmony_ci dev_err(&np->op->dev, "RNG error, retesting\n"); 44062306a36Sopenharmony_ci np->flags &= ~N2RNG_FLAG_READY; 44162306a36Sopenharmony_ci if (!(np->flags & N2RNG_FLAG_SHUTDOWN)) 44262306a36Sopenharmony_ci schedule_delayed_work(&np->work, 0); 44362306a36Sopenharmony_ci len = 0; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci return len; 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci/* On a guest node, just make sure we can read random data properly. 45162306a36Sopenharmony_ci * If a control node reboots or reloads it's n2rng driver, this won't 45262306a36Sopenharmony_ci * work during that time. So we have to keep probing until the device 45362306a36Sopenharmony_ci * becomes usable. 45462306a36Sopenharmony_ci */ 45562306a36Sopenharmony_cistatic int n2rng_guest_check(struct n2rng *np) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci unsigned long ra = __pa(&np->test_data); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci return n2rng_generic_read_data(ra); 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic int n2rng_entropy_diag_read(struct n2rng *np, unsigned long unit, 46362306a36Sopenharmony_ci u64 *pre_control, u64 pre_state, 46462306a36Sopenharmony_ci u64 *buffer, unsigned long buf_len, 46562306a36Sopenharmony_ci u64 *post_control, u64 post_state) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci unsigned long post_ctl_ra = __pa(post_control); 46862306a36Sopenharmony_ci unsigned long pre_ctl_ra = __pa(pre_control); 46962306a36Sopenharmony_ci unsigned long buffer_ra = __pa(buffer); 47062306a36Sopenharmony_ci int err; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci err = n2rng_generic_write_control(np, pre_ctl_ra, unit, pre_state); 47362306a36Sopenharmony_ci if (err) 47462306a36Sopenharmony_ci return err; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci err = n2rng_generic_read_diag_data(np, unit, 47762306a36Sopenharmony_ci buffer_ra, buf_len); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci (void) n2rng_generic_write_control(np, post_ctl_ra, unit, 48062306a36Sopenharmony_ci post_state); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci return err; 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic u64 advance_polynomial(u64 poly, u64 val, int count) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci int i; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci for (i = 0; i < count; i++) { 49062306a36Sopenharmony_ci int highbit_set = ((s64)val < 0); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci val <<= 1; 49362306a36Sopenharmony_ci if (highbit_set) 49462306a36Sopenharmony_ci val ^= poly; 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci return val; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic int n2rng_test_buffer_find(struct n2rng *np, u64 val) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci int i, count = 0; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci /* Purposefully skip over the first word. */ 50562306a36Sopenharmony_ci for (i = 1; i < SELFTEST_BUFFER_WORDS; i++) { 50662306a36Sopenharmony_ci if (np->test_buffer[i] == val) 50762306a36Sopenharmony_ci count++; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci return count; 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic void n2rng_dump_test_buffer(struct n2rng *np) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci int i; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci for (i = 0; i < SELFTEST_BUFFER_WORDS; i++) 51762306a36Sopenharmony_ci dev_err(&np->op->dev, "Test buffer slot %d [0x%016llx]\n", 51862306a36Sopenharmony_ci i, np->test_buffer[i]); 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic int n2rng_check_selftest_buffer(struct n2rng *np, unsigned long unit) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci u64 val; 52462306a36Sopenharmony_ci int err, matches, limit; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci switch (np->data->id) { 52762306a36Sopenharmony_ci case N2_n2_rng: 52862306a36Sopenharmony_ci case N2_vf_rng: 52962306a36Sopenharmony_ci case N2_kt_rng: 53062306a36Sopenharmony_ci case N2_m4_rng: /* yes, m4 uses the old value */ 53162306a36Sopenharmony_ci val = RNG_v1_SELFTEST_VAL; 53262306a36Sopenharmony_ci break; 53362306a36Sopenharmony_ci default: 53462306a36Sopenharmony_ci val = RNG_v2_SELFTEST_VAL; 53562306a36Sopenharmony_ci break; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci matches = 0; 53962306a36Sopenharmony_ci for (limit = 0; limit < SELFTEST_LOOPS_MAX; limit++) { 54062306a36Sopenharmony_ci matches += n2rng_test_buffer_find(np, val); 54162306a36Sopenharmony_ci if (matches >= SELFTEST_MATCH_GOAL) 54262306a36Sopenharmony_ci break; 54362306a36Sopenharmony_ci val = advance_polynomial(SELFTEST_POLY, val, 1); 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci err = 0; 54762306a36Sopenharmony_ci if (limit >= SELFTEST_LOOPS_MAX) { 54862306a36Sopenharmony_ci err = -ENODEV; 54962306a36Sopenharmony_ci dev_err(&np->op->dev, "Selftest failed on unit %lu\n", unit); 55062306a36Sopenharmony_ci n2rng_dump_test_buffer(np); 55162306a36Sopenharmony_ci } else 55262306a36Sopenharmony_ci dev_info(&np->op->dev, "Selftest passed on unit %lu\n", unit); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci return err; 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistatic int n2rng_control_selftest(struct n2rng *np, unsigned long unit) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci int err; 56062306a36Sopenharmony_ci u64 base, base3; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci switch (np->data->id) { 56362306a36Sopenharmony_ci case N2_n2_rng: 56462306a36Sopenharmony_ci case N2_vf_rng: 56562306a36Sopenharmony_ci case N2_kt_rng: 56662306a36Sopenharmony_ci base = RNG_v1_CTL_ASEL_NOOUT << RNG_v1_CTL_ASEL_SHIFT; 56762306a36Sopenharmony_ci base3 = base | RNG_CTL_LFSR | 56862306a36Sopenharmony_ci ((RNG_v1_SELFTEST_TICKS - 2) << RNG_v1_CTL_WAIT_SHIFT); 56962306a36Sopenharmony_ci break; 57062306a36Sopenharmony_ci case N2_m4_rng: 57162306a36Sopenharmony_ci base = RNG_v2_CTL_ASEL_NOOUT << RNG_v2_CTL_ASEL_SHIFT; 57262306a36Sopenharmony_ci base3 = base | RNG_CTL_LFSR | 57362306a36Sopenharmony_ci ((RNG_v1_SELFTEST_TICKS - 2) << RNG_v2_CTL_WAIT_SHIFT); 57462306a36Sopenharmony_ci break; 57562306a36Sopenharmony_ci default: 57662306a36Sopenharmony_ci base = RNG_v2_CTL_ASEL_NOOUT << RNG_v2_CTL_ASEL_SHIFT; 57762306a36Sopenharmony_ci base3 = base | RNG_CTL_LFSR | 57862306a36Sopenharmony_ci (RNG_v2_SELFTEST_TICKS << RNG_v2_CTL_WAIT_SHIFT); 57962306a36Sopenharmony_ci break; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci np->test_control[0] = base; 58362306a36Sopenharmony_ci np->test_control[1] = base; 58462306a36Sopenharmony_ci np->test_control[2] = base; 58562306a36Sopenharmony_ci np->test_control[3] = base3; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci err = n2rng_entropy_diag_read(np, unit, np->test_control, 58862306a36Sopenharmony_ci HV_RNG_STATE_HEALTHCHECK, 58962306a36Sopenharmony_ci np->test_buffer, 59062306a36Sopenharmony_ci sizeof(np->test_buffer), 59162306a36Sopenharmony_ci &np->units[unit].control[0], 59262306a36Sopenharmony_ci np->hv_state); 59362306a36Sopenharmony_ci if (err) 59462306a36Sopenharmony_ci return err; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci return n2rng_check_selftest_buffer(np, unit); 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic int n2rng_control_check(struct n2rng *np) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci int i; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci for (i = 0; i < np->num_units; i++) { 60462306a36Sopenharmony_ci int err = n2rng_control_selftest(np, i); 60562306a36Sopenharmony_ci if (err) 60662306a36Sopenharmony_ci return err; 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci return 0; 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci/* The sanity checks passed, install the final configuration into the 61262306a36Sopenharmony_ci * chip, it's ready to use. 61362306a36Sopenharmony_ci */ 61462306a36Sopenharmony_cistatic int n2rng_control_configure_units(struct n2rng *np) 61562306a36Sopenharmony_ci{ 61662306a36Sopenharmony_ci int unit, err; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci err = 0; 61962306a36Sopenharmony_ci for (unit = 0; unit < np->num_units; unit++) { 62062306a36Sopenharmony_ci struct n2rng_unit *up = &np->units[unit]; 62162306a36Sopenharmony_ci unsigned long ctl_ra = __pa(&up->control[0]); 62262306a36Sopenharmony_ci int esrc; 62362306a36Sopenharmony_ci u64 base, shift; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (np->data->chip_version == 1) { 62662306a36Sopenharmony_ci base = ((np->accum_cycles << RNG_v1_CTL_WAIT_SHIFT) | 62762306a36Sopenharmony_ci (RNG_v1_CTL_ASEL_NOOUT << RNG_v1_CTL_ASEL_SHIFT) | 62862306a36Sopenharmony_ci RNG_CTL_LFSR); 62962306a36Sopenharmony_ci shift = RNG_v1_CTL_VCO_SHIFT; 63062306a36Sopenharmony_ci } else { 63162306a36Sopenharmony_ci base = ((np->accum_cycles << RNG_v2_CTL_WAIT_SHIFT) | 63262306a36Sopenharmony_ci (RNG_v2_CTL_ASEL_NOOUT << RNG_v2_CTL_ASEL_SHIFT) | 63362306a36Sopenharmony_ci RNG_CTL_LFSR); 63462306a36Sopenharmony_ci shift = RNG_v2_CTL_VCO_SHIFT; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci /* XXX This isn't the best. We should fetch a bunch 63862306a36Sopenharmony_ci * XXX of words using each entropy source combined XXX 63962306a36Sopenharmony_ci * with each VCO setting, and see which combinations 64062306a36Sopenharmony_ci * XXX give the best random data. 64162306a36Sopenharmony_ci */ 64262306a36Sopenharmony_ci for (esrc = 0; esrc < 3; esrc++) 64362306a36Sopenharmony_ci up->control[esrc] = base | 64462306a36Sopenharmony_ci (esrc << shift) | 64562306a36Sopenharmony_ci (RNG_CTL_ES1 << esrc); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci up->control[3] = base | 64862306a36Sopenharmony_ci (RNG_CTL_ES1 | RNG_CTL_ES2 | RNG_CTL_ES3); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci err = n2rng_generic_write_control(np, ctl_ra, unit, 65162306a36Sopenharmony_ci HV_RNG_STATE_CONFIGURED); 65262306a36Sopenharmony_ci if (err) 65362306a36Sopenharmony_ci break; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci return err; 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_cistatic void n2rng_work(struct work_struct *work) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci struct n2rng *np = container_of(work, struct n2rng, work.work); 66262306a36Sopenharmony_ci int err = 0; 66362306a36Sopenharmony_ci static int retries = 4; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci if (!(np->flags & N2RNG_FLAG_CONTROL)) { 66662306a36Sopenharmony_ci err = n2rng_guest_check(np); 66762306a36Sopenharmony_ci } else { 66862306a36Sopenharmony_ci preempt_disable(); 66962306a36Sopenharmony_ci err = n2rng_control_check(np); 67062306a36Sopenharmony_ci preempt_enable(); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (!err) 67362306a36Sopenharmony_ci err = n2rng_control_configure_units(np); 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci if (!err) { 67762306a36Sopenharmony_ci np->flags |= N2RNG_FLAG_READY; 67862306a36Sopenharmony_ci dev_info(&np->op->dev, "RNG ready\n"); 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (--retries == 0) 68262306a36Sopenharmony_ci dev_err(&np->op->dev, "Self-test retries failed, RNG not ready\n"); 68362306a36Sopenharmony_ci else if (err && !(np->flags & N2RNG_FLAG_SHUTDOWN)) 68462306a36Sopenharmony_ci schedule_delayed_work(&np->work, HZ * 2); 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_cistatic void n2rng_driver_version(void) 68862306a36Sopenharmony_ci{ 68962306a36Sopenharmony_ci static int n2rng_version_printed; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci if (n2rng_version_printed++ == 0) 69262306a36Sopenharmony_ci pr_info("%s", version); 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cistatic const struct of_device_id n2rng_match[]; 69662306a36Sopenharmony_cistatic int n2rng_probe(struct platform_device *op) 69762306a36Sopenharmony_ci{ 69862306a36Sopenharmony_ci const struct of_device_id *match; 69962306a36Sopenharmony_ci int err = -ENOMEM; 70062306a36Sopenharmony_ci struct n2rng *np; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci match = of_match_device(n2rng_match, &op->dev); 70362306a36Sopenharmony_ci if (!match) 70462306a36Sopenharmony_ci return -EINVAL; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci n2rng_driver_version(); 70762306a36Sopenharmony_ci np = devm_kzalloc(&op->dev, sizeof(*np), GFP_KERNEL); 70862306a36Sopenharmony_ci if (!np) 70962306a36Sopenharmony_ci goto out; 71062306a36Sopenharmony_ci np->op = op; 71162306a36Sopenharmony_ci np->data = (struct n2rng_template *)match->data; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci INIT_DELAYED_WORK(&np->work, n2rng_work); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci if (np->data->multi_capable) 71662306a36Sopenharmony_ci np->flags |= N2RNG_FLAG_MULTI; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci err = -ENODEV; 71962306a36Sopenharmony_ci np->hvapi_major = 2; 72062306a36Sopenharmony_ci if (sun4v_hvapi_register(HV_GRP_RNG, 72162306a36Sopenharmony_ci np->hvapi_major, 72262306a36Sopenharmony_ci &np->hvapi_minor)) { 72362306a36Sopenharmony_ci np->hvapi_major = 1; 72462306a36Sopenharmony_ci if (sun4v_hvapi_register(HV_GRP_RNG, 72562306a36Sopenharmony_ci np->hvapi_major, 72662306a36Sopenharmony_ci &np->hvapi_minor)) { 72762306a36Sopenharmony_ci dev_err(&op->dev, "Cannot register suitable " 72862306a36Sopenharmony_ci "HVAPI version.\n"); 72962306a36Sopenharmony_ci goto out; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci if (np->flags & N2RNG_FLAG_MULTI) { 73462306a36Sopenharmony_ci if (np->hvapi_major < 2) { 73562306a36Sopenharmony_ci dev_err(&op->dev, "multi-unit-capable RNG requires " 73662306a36Sopenharmony_ci "HVAPI major version 2 or later, got %lu\n", 73762306a36Sopenharmony_ci np->hvapi_major); 73862306a36Sopenharmony_ci goto out_hvapi_unregister; 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci np->num_units = of_getintprop_default(op->dev.of_node, 74162306a36Sopenharmony_ci "rng-#units", 0); 74262306a36Sopenharmony_ci if (!np->num_units) { 74362306a36Sopenharmony_ci dev_err(&op->dev, "VF RNG lacks rng-#units property\n"); 74462306a36Sopenharmony_ci goto out_hvapi_unregister; 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci } else { 74762306a36Sopenharmony_ci np->num_units = 1; 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci dev_info(&op->dev, "Registered RNG HVAPI major %lu minor %lu\n", 75162306a36Sopenharmony_ci np->hvapi_major, np->hvapi_minor); 75262306a36Sopenharmony_ci np->units = devm_kcalloc(&op->dev, np->num_units, sizeof(*np->units), 75362306a36Sopenharmony_ci GFP_KERNEL); 75462306a36Sopenharmony_ci err = -ENOMEM; 75562306a36Sopenharmony_ci if (!np->units) 75662306a36Sopenharmony_ci goto out_hvapi_unregister; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci err = n2rng_init_control(np); 75962306a36Sopenharmony_ci if (err) 76062306a36Sopenharmony_ci goto out_hvapi_unregister; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci dev_info(&op->dev, "Found %s RNG, units: %d\n", 76362306a36Sopenharmony_ci ((np->flags & N2RNG_FLAG_MULTI) ? 76462306a36Sopenharmony_ci "multi-unit-capable" : "single-unit"), 76562306a36Sopenharmony_ci np->num_units); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci np->hwrng.name = DRV_MODULE_NAME; 76862306a36Sopenharmony_ci np->hwrng.data_read = n2rng_data_read; 76962306a36Sopenharmony_ci np->hwrng.priv = (unsigned long) np; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci err = devm_hwrng_register(&op->dev, &np->hwrng); 77262306a36Sopenharmony_ci if (err) 77362306a36Sopenharmony_ci goto out_hvapi_unregister; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci platform_set_drvdata(op, np); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci schedule_delayed_work(&np->work, 0); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci return 0; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ciout_hvapi_unregister: 78262306a36Sopenharmony_ci sun4v_hvapi_unregister(HV_GRP_RNG); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ciout: 78562306a36Sopenharmony_ci return err; 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic int n2rng_remove(struct platform_device *op) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci struct n2rng *np = platform_get_drvdata(op); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci np->flags |= N2RNG_FLAG_SHUTDOWN; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci cancel_delayed_work_sync(&np->work); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci sun4v_hvapi_unregister(HV_GRP_RNG); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci return 0; 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_cistatic struct n2rng_template n2_template = { 80262306a36Sopenharmony_ci .id = N2_n2_rng, 80362306a36Sopenharmony_ci .multi_capable = 0, 80462306a36Sopenharmony_ci .chip_version = 1, 80562306a36Sopenharmony_ci}; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_cistatic struct n2rng_template vf_template = { 80862306a36Sopenharmony_ci .id = N2_vf_rng, 80962306a36Sopenharmony_ci .multi_capable = 1, 81062306a36Sopenharmony_ci .chip_version = 1, 81162306a36Sopenharmony_ci}; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_cistatic struct n2rng_template kt_template = { 81462306a36Sopenharmony_ci .id = N2_kt_rng, 81562306a36Sopenharmony_ci .multi_capable = 1, 81662306a36Sopenharmony_ci .chip_version = 1, 81762306a36Sopenharmony_ci}; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_cistatic struct n2rng_template m4_template = { 82062306a36Sopenharmony_ci .id = N2_m4_rng, 82162306a36Sopenharmony_ci .multi_capable = 1, 82262306a36Sopenharmony_ci .chip_version = 2, 82362306a36Sopenharmony_ci}; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cistatic struct n2rng_template m7_template = { 82662306a36Sopenharmony_ci .id = N2_m7_rng, 82762306a36Sopenharmony_ci .multi_capable = 1, 82862306a36Sopenharmony_ci .chip_version = 2, 82962306a36Sopenharmony_ci}; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_cistatic const struct of_device_id n2rng_match[] = { 83262306a36Sopenharmony_ci { 83362306a36Sopenharmony_ci .name = "random-number-generator", 83462306a36Sopenharmony_ci .compatible = "SUNW,n2-rng", 83562306a36Sopenharmony_ci .data = &n2_template, 83662306a36Sopenharmony_ci }, 83762306a36Sopenharmony_ci { 83862306a36Sopenharmony_ci .name = "random-number-generator", 83962306a36Sopenharmony_ci .compatible = "SUNW,vf-rng", 84062306a36Sopenharmony_ci .data = &vf_template, 84162306a36Sopenharmony_ci }, 84262306a36Sopenharmony_ci { 84362306a36Sopenharmony_ci .name = "random-number-generator", 84462306a36Sopenharmony_ci .compatible = "SUNW,kt-rng", 84562306a36Sopenharmony_ci .data = &kt_template, 84662306a36Sopenharmony_ci }, 84762306a36Sopenharmony_ci { 84862306a36Sopenharmony_ci .name = "random-number-generator", 84962306a36Sopenharmony_ci .compatible = "ORCL,m4-rng", 85062306a36Sopenharmony_ci .data = &m4_template, 85162306a36Sopenharmony_ci }, 85262306a36Sopenharmony_ci { 85362306a36Sopenharmony_ci .name = "random-number-generator", 85462306a36Sopenharmony_ci .compatible = "ORCL,m7-rng", 85562306a36Sopenharmony_ci .data = &m7_template, 85662306a36Sopenharmony_ci }, 85762306a36Sopenharmony_ci {}, 85862306a36Sopenharmony_ci}; 85962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, n2rng_match); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_cistatic struct platform_driver n2rng_driver = { 86262306a36Sopenharmony_ci .driver = { 86362306a36Sopenharmony_ci .name = "n2rng", 86462306a36Sopenharmony_ci .of_match_table = n2rng_match, 86562306a36Sopenharmony_ci }, 86662306a36Sopenharmony_ci .probe = n2rng_probe, 86762306a36Sopenharmony_ci .remove = n2rng_remove, 86862306a36Sopenharmony_ci}; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_cimodule_platform_driver(n2rng_driver); 871