diff options
| -rw-r--r-- | drivers/char/hw_random/Kconfig | 13 | ||||
| -rw-r--r-- | drivers/char/hw_random/Makefile | 2 | ||||
| -rw-r--r-- | drivers/char/hw_random/n2-asm.S | 79 | ||||
| -rw-r--r-- | drivers/char/hw_random/n2-drv.c | 771 | ||||
| -rw-r--r-- | drivers/char/hw_random/n2rng.h | 118 |
5 files changed, 983 insertions, 0 deletions
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index efd0b4db7c8e..8822eca58ffa 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig | |||
| @@ -59,6 +59,19 @@ config HW_RANDOM_GEODE | |||
| 59 | 59 | ||
| 60 | If unsure, say Y. | 60 | If unsure, say Y. |
| 61 | 61 | ||
| 62 | config HW_RANDOM_N2RNG | ||
| 63 | tristate "Niagara2 Random Number Generator support" | ||
| 64 | depends on HW_RANDOM && SPARC64 | ||
| 65 | default HW_RANDOM | ||
| 66 | ---help--- | ||
| 67 | This driver provides kernel-side support for the Random Number | ||
| 68 | Generator hardware found on Niagara2 cpus. | ||
| 69 | |||
| 70 | To compile this driver as a module, choose M here: the | ||
| 71 | module will be called n2-rng. | ||
| 72 | |||
| 73 | If unsure, say Y. | ||
| 74 | |||
| 62 | config HW_RANDOM_VIA | 75 | config HW_RANDOM_VIA |
| 63 | tristate "VIA HW Random Number Generator support" | 76 | tristate "VIA HW Random Number Generator support" |
| 64 | depends on HW_RANDOM && X86_32 | 77 | depends on HW_RANDOM && X86_32 |
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index b4940ddbb35f..b6effb7522c2 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile | |||
| @@ -7,6 +7,8 @@ rng-core-y := core.o | |||
| 7 | obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o | 7 | obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o |
| 8 | obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o | 8 | obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o |
| 9 | obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o | 9 | obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o |
| 10 | obj-$(CONFIG_HW_RANDOM_N2RNG) += n2-rng.o | ||
| 11 | n2-rng-y := n2-drv.o n2-asm.o | ||
| 10 | obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o | 12 | obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o |
| 11 | obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o | 13 | obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o |
| 12 | obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o | 14 | obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o |
diff --git a/drivers/char/hw_random/n2-asm.S b/drivers/char/hw_random/n2-asm.S new file mode 100644 index 000000000000..9b6eb5cd59f6 --- /dev/null +++ b/drivers/char/hw_random/n2-asm.S | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | /* n2-asm.S: Niagara2 RNG hypervisor call assembler. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2008 David S. Miller <davem@davemloft.net> | ||
| 4 | */ | ||
| 5 | #include <linux/linkage.h> | ||
| 6 | #include <asm/hypervisor.h> | ||
| 7 | #include "n2rng.h" | ||
| 8 | |||
| 9 | .text | ||
| 10 | |||
| 11 | ENTRY(sun4v_rng_get_diag_ctl) | ||
| 12 | mov HV_FAST_RNG_GET_DIAG_CTL, %o5 | ||
| 13 | ta HV_FAST_TRAP | ||
| 14 | retl | ||
| 15 | nop | ||
| 16 | ENDPROC(sun4v_rng_get_diag_ctl) | ||
| 17 | |||
| 18 | ENTRY(sun4v_rng_ctl_read_v1) | ||
| 19 | mov %o1, %o3 | ||
| 20 | mov %o2, %o4 | ||
| 21 | mov HV_FAST_RNG_CTL_READ, %o5 | ||
| 22 | ta HV_FAST_TRAP | ||
| 23 | stx %o1, [%o3] | ||
| 24 | retl | ||
| 25 | stx %o2, [%o4] | ||
| 26 | ENDPROC(sun4v_rng_ctl_read_v1) | ||
| 27 | |||
| 28 | ENTRY(sun4v_rng_ctl_read_v2) | ||
| 29 | save %sp, -192, %sp | ||
| 30 | mov %i0, %o0 | ||
| 31 | mov %i1, %o1 | ||
| 32 | mov HV_FAST_RNG_CTL_READ, %o5 | ||
| 33 | ta HV_FAST_TRAP | ||
| 34 | stx %o1, [%i2] | ||
| 35 | stx %o2, [%i3] | ||
| 36 | stx %o3, [%i4] | ||
| 37 | stx %o4, [%i5] | ||
| 38 | ret | ||
| 39 | restore %g0, %o0, %o0 | ||
| 40 | ENDPROC(sun4v_rng_ctl_read_v2) | ||
| 41 | |||
| 42 | ENTRY(sun4v_rng_ctl_write_v1) | ||
| 43 | mov %o3, %o4 | ||
| 44 | mov HV_FAST_RNG_CTL_WRITE, %o5 | ||
| 45 | ta HV_FAST_TRAP | ||
| 46 | retl | ||
| 47 | stx %o1, [%o4] | ||
| 48 | ENDPROC(sun4v_rng_ctl_write_v1) | ||
| 49 | |||
| 50 | ENTRY(sun4v_rng_ctl_write_v2) | ||
| 51 | mov HV_FAST_RNG_CTL_WRITE, %o5 | ||
| 52 | ta HV_FAST_TRAP | ||
| 53 | retl | ||
| 54 | nop | ||
| 55 | ENDPROC(sun4v_rng_ctl_write_v2) | ||
| 56 | |||
| 57 | ENTRY(sun4v_rng_data_read_diag_v1) | ||
| 58 | mov %o2, %o4 | ||
| 59 | mov HV_FAST_RNG_DATA_READ_DIAG, %o5 | ||
| 60 | ta HV_FAST_TRAP | ||
| 61 | retl | ||
| 62 | stx %o1, [%o4] | ||
| 63 | ENDPROC(sun4v_rng_data_read_diag_v1) | ||
| 64 | |||
| 65 | ENTRY(sun4v_rng_data_read_diag_v2) | ||
| 66 | mov %o3, %o4 | ||
| 67 | mov HV_FAST_RNG_DATA_READ_DIAG, %o5 | ||
| 68 | ta HV_FAST_TRAP | ||
| 69 | retl | ||
| 70 | stx %o1, [%o4] | ||
| 71 | ENDPROC(sun4v_rng_data_read_diag_v2) | ||
| 72 | |||
| 73 | ENTRY(sun4v_rng_data_read) | ||
| 74 | mov %o1, %o4 | ||
| 75 | mov HV_FAST_RNG_DATA_READ, %o5 | ||
| 76 | ta HV_FAST_TRAP | ||
| 77 | retl | ||
| 78 | stx %o1, [%o4] | ||
| 79 | ENDPROC(sun4v_rng_data_read) | ||
diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c new file mode 100644 index 000000000000..5220f541df25 --- /dev/null +++ b/drivers/char/hw_random/n2-drv.c | |||
| @@ -0,0 +1,771 @@ | |||
| 1 | /* n2-drv.c: Niagara-2 RNG driver. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2008 David S. Miller <davem@davemloft.net> | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/kernel.h> | ||
| 7 | #include <linux/module.h> | ||
| 8 | #include <linux/types.h> | ||
| 9 | #include <linux/delay.h> | ||
| 10 | #include <linux/init.h> | ||
| 11 | #include <linux/slab.h> | ||
| 12 | #include <linux/workqueue.h> | ||
| 13 | #include <linux/preempt.h> | ||
| 14 | #include <linux/hw_random.h> | ||
| 15 | |||
| 16 | #include <linux/of.h> | ||
| 17 | #include <linux/of_device.h> | ||
| 18 | |||
| 19 | #include <asm/hypervisor.h> | ||
| 20 | |||
| 21 | #include "n2rng.h" | ||
| 22 | |||
| 23 | #define DRV_MODULE_NAME "n2rng" | ||
| 24 | #define PFX DRV_MODULE_NAME ": " | ||
| 25 | #define DRV_MODULE_VERSION "0.1" | ||
| 26 | #define DRV_MODULE_RELDATE "May 15, 2008" | ||
| 27 | |||
| 28 | static char version[] __devinitdata = | ||
| 29 | DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; | ||
| 30 | |||
| 31 | MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); | ||
| 32 | MODULE_DESCRIPTION("Niagara2 RNG driver"); | ||
| 33 | MODULE_LICENSE("GPL"); | ||
| 34 | MODULE_VERSION(DRV_MODULE_VERSION); | ||
| 35 | |||
| 36 | /* The Niagara2 RNG provides a 64-bit read-only random number | ||
| 37 | * register, plus a control register. Access to the RNG is | ||
| 38 | * virtualized through the hypervisor so that both guests and control | ||
| 39 | * nodes can access the device. | ||
| 40 | * | ||
| 41 | * The entropy source consists of raw entropy sources, each | ||
| 42 | * constructed from a voltage controlled oscillator whose phase is | ||
| 43 | * jittered by thermal noise sources. | ||
| 44 | * | ||
| 45 | * The oscillator in each of the three raw entropy sources run at | ||
| 46 | * different frequencies. Normally, all three generator outputs are | ||
| 47 | * gathered, xored together, and fed into a CRC circuit, the output of | ||
| 48 | * which is the 64-bit read-only register. | ||
| 49 | * | ||
| 50 | * Some time is necessary for all the necessary entropy to build up | ||
| 51 | * such that a full 64-bits of entropy are available in the register. | ||
| 52 | * In normal operating mode (RNG_CTL_LFSR is set), the chip implements | ||
| 53 | * an interlock which blocks register reads until sufficient entropy | ||
| 54 | * is available. | ||
| 55 | * | ||
| 56 | * A control register is provided for adjusting various aspects of RNG | ||
| 57 | * operation, and to enable diagnostic modes. Each of the three raw | ||
| 58 | * entropy sources has an enable bit (RNG_CTL_ES{1,2,3}). Also | ||
| 59 | * provided are fields for controlling the minimum time in cycles | ||
| 60 | * between read accesses to the register (RNG_CTL_WAIT, this controls | ||
| 61 | * the interlock described in the previous paragraph). | ||
| 62 | * | ||
| 63 | * The standard setting is to have the mode bit (RNG_CTL_LFSR) set, | ||
| 64 | * all three entropy sources enabled, and the interlock time set | ||
| 65 | * appropriately. | ||
| 66 | * | ||
| 67 | * The CRC polynomial used by the chip is: | ||
| 68 | * | ||
| 69 | * P(X) = x64 + x61 + x57 + x56 + x52 + x51 + x50 + x48 + x47 + x46 + | ||
| 70 | * x43 + x42 + x41 + x39 + x38 + x37 + x35 + x32 + x28 + x25 + | ||
| 71 | * x22 + x21 + x17 + x15 + x13 + x12 + x11 + x7 + x5 + x + 1 | ||
| 72 | * | ||
| 73 | * The RNG_CTL_VCO value of each noise cell must be programmed | ||
| 74 | * seperately. This is why 4 control register values must be provided | ||
| 75 | * to the hypervisor. During a write, the hypervisor writes them all, | ||
| 76 | * one at a time, to the actual RNG_CTL register. The first three | ||
| 77 | * values are used to setup the desired RNG_CTL_VCO for each entropy | ||
| 78 | * source, for example: | ||
| 79 | * | ||
| 80 | * control 0: (1 << RNG_CTL_VCO_SHIFT) | RNG_CTL_ES1 | ||
| 81 | * control 1: (2 << RNG_CTL_VCO_SHIFT) | RNG_CTL_ES2 | ||
| 82 | * control 2: (3 << RNG_CTL_VCO_SHIFT) | RNG_CTL_ES3 | ||
| 83 | * | ||
| 84 | * And then the fourth value sets the final chip state and enables | ||
| 85 | * desired. | ||
| 86 | */ | ||
| 87 | |||
| 88 | static int n2rng_hv_err_trans(unsigned long hv_err) | ||
| 89 | { | ||
| 90 | switch (hv_err) { | ||
| 91 | case HV_EOK: | ||
| 92 | return 0; | ||
| 93 | case HV_EWOULDBLOCK: | ||
| 94 | return -EAGAIN; | ||
| 95 | case HV_ENOACCESS: | ||
| 96 | return -EPERM; | ||
| 97 | case HV_EIO: | ||
| 98 | return -EIO; | ||
| 99 | case HV_EBUSY: | ||
| 100 | return -EBUSY; | ||
| 101 | case HV_EBADALIGN: | ||
| 102 | case HV_ENORADDR: | ||
| 103 | return -EFAULT; | ||
| 104 | default: | ||
| 105 | return -EINVAL; | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | static unsigned long n2rng_generic_read_control_v2(unsigned long ra, | ||
| 110 | unsigned long unit) | ||
| 111 | { | ||
| 112 | unsigned long hv_err, state, ticks, watchdog_delta, watchdog_status; | ||
| 113 | int block = 0, busy = 0; | ||
| 114 | |||
| 115 | while (1) { | ||
| 116 | hv_err = sun4v_rng_ctl_read_v2(ra, unit, &state, | ||
| 117 | &ticks, | ||
| 118 | &watchdog_delta, | ||
| 119 | &watchdog_status); | ||
| 120 | if (hv_err == HV_EOK) | ||
| 121 | break; | ||
| 122 | |||
| 123 | if (hv_err == HV_EBUSY) { | ||
| 124 | if (++busy >= N2RNG_BUSY_LIMIT) | ||
| 125 | break; | ||
| 126 | |||
| 127 | udelay(1); | ||
| 128 | } else if (hv_err == HV_EWOULDBLOCK) { | ||
| 129 | if (++block >= N2RNG_BLOCK_LIMIT) | ||
| 130 | break; | ||
| 131 | |||
| 132 | __delay(ticks); | ||
| 133 | } else | ||
| 134 | break; | ||
| 135 | } | ||
| 136 | |||
| 137 | return hv_err; | ||
| 138 | } | ||
| 139 | |||
| 140 | /* In multi-socket situations, the hypervisor might need to | ||
| 141 | * queue up the RNG control register write if it's for a unit | ||
| 142 | * that is on a cpu socket other than the one we are executing on. | ||
| 143 | * | ||
| 144 | * We poll here waiting for a successful read of that control | ||
| 145 | * register to make sure the write has been actually performed. | ||
| 146 | */ | ||
| 147 | static unsigned long n2rng_control_settle_v2(struct n2rng *np, int unit) | ||
| 148 | { | ||
| 149 | unsigned long ra = __pa(&np->scratch_control[0]); | ||
| 150 | |||
| 151 | return n2rng_generic_read_control_v2(ra, unit); | ||
| 152 | } | ||
| 153 | |||
| 154 | static unsigned long n2rng_write_ctl_one(struct n2rng *np, int unit, | ||
| 155 | unsigned long state, | ||
| 156 | unsigned long control_ra, | ||
| 157 | unsigned long watchdog_timeout, | ||
| 158 | unsigned long *ticks) | ||
| 159 | { | ||
| 160 | unsigned long hv_err; | ||
| 161 | |||
| 162 | if (np->hvapi_major == 1) { | ||
| 163 | hv_err = sun4v_rng_ctl_write_v1(control_ra, state, | ||
| 164 | watchdog_timeout, ticks); | ||
| 165 | } else { | ||
| 166 | hv_err = sun4v_rng_ctl_write_v2(control_ra, state, | ||
| 167 | watchdog_timeout, unit); | ||
| 168 | if (hv_err == HV_EOK) | ||
| 169 | hv_err = n2rng_control_settle_v2(np, unit); | ||
| 170 | *ticks = N2RNG_ACCUM_CYCLES_DEFAULT; | ||
| 171 | } | ||
| 172 | |||
| 173 | return hv_err; | ||
| 174 | } | ||
| 175 | |||
| 176 | static int n2rng_generic_read_data(unsigned long data_ra) | ||
| 177 | { | ||
| 178 | unsigned long ticks, hv_err; | ||
| 179 | int block = 0, hcheck = 0; | ||
| 180 | |||
| 181 | while (1) { | ||
| 182 | hv_err = sun4v_rng_data_read(data_ra, &ticks); | ||
| 183 | if (hv_err == HV_EOK) | ||
| 184 | return 0; | ||
| 185 | |||
| 186 | if (hv_err == HV_EWOULDBLOCK) { | ||
| 187 | if (++block >= N2RNG_BLOCK_LIMIT) | ||
| 188 | return -EWOULDBLOCK; | ||
| 189 | __delay(ticks); | ||
| 190 | } else if (hv_err == HV_ENOACCESS) { | ||
| 191 | return -EPERM; | ||
| 192 | } else if (hv_err == HV_EIO) { | ||
| 193 | if (++hcheck >= N2RNG_HCHECK_LIMIT) | ||
| 194 | return -EIO; | ||
| 195 | udelay(10000); | ||
| 196 | } else | ||
| 197 | return -ENODEV; | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | static unsigned long n2rng_read_diag_data_one(struct n2rng *np, | ||
| 202 | unsigned long unit, | ||
| 203 | unsigned long data_ra, | ||
| 204 | unsigned long data_len, | ||
| 205 | unsigned long *ticks) | ||
| 206 | { | ||
| 207 | unsigned long hv_err; | ||
| 208 | |||
| 209 | if (np->hvapi_major == 1) { | ||
| 210 | hv_err = sun4v_rng_data_read_diag_v1(data_ra, data_len, ticks); | ||
| 211 | } else { | ||
| 212 | hv_err = sun4v_rng_data_read_diag_v2(data_ra, data_len, | ||
| 213 | unit, ticks); | ||
| 214 | if (!*ticks) | ||
| 215 | *ticks = N2RNG_ACCUM_CYCLES_DEFAULT; | ||
| 216 | } | ||
| 217 | return hv_err; | ||
| 218 | } | ||
| 219 | |||
| 220 | static int n2rng_generic_read_diag_data(struct n2rng *np, | ||
| 221 | unsigned long unit, | ||
| 222 | unsigned long data_ra, | ||
| 223 | unsigned long data_len) | ||
| 224 | { | ||
| 225 | unsigned long ticks, hv_err; | ||
| 226 | int block = 0; | ||
| 227 | |||
| 228 | while (1) { | ||
| 229 | hv_err = n2rng_read_diag_data_one(np, unit, | ||
| 230 | data_ra, data_len, | ||
| 231 | &ticks); | ||
| 232 | if (hv_err == HV_EOK) | ||
| 233 | return 0; | ||
| 234 | |||
| 235 | if (hv_err == HV_EWOULDBLOCK) { | ||
| 236 | if (++block >= N2RNG_BLOCK_LIMIT) | ||
| 237 | return -EWOULDBLOCK; | ||
| 238 | __delay(ticks); | ||
| 239 | } else if (hv_err == HV_ENOACCESS) { | ||
| 240 | return -EPERM; | ||
| 241 | } else if (hv_err == HV_EIO) { | ||
| 242 | return -EIO; | ||
| 243 | } else | ||
| 244 | return -ENODEV; | ||
| 245 | } | ||
| 246 | } | ||
| 247 | |||
| 248 | |||
| 249 | static int n2rng_generic_write_control(struct n2rng *np, | ||
| 250 | unsigned long control_ra, | ||
| 251 | unsigned long unit, | ||
| 252 | unsigned long state) | ||
| 253 | { | ||
| 254 | unsigned long hv_err, ticks; | ||
| 255 | int block = 0, busy = 0; | ||
| 256 | |||
| 257 | while (1) { | ||
| 258 | hv_err = n2rng_write_ctl_one(np, unit, state, control_ra, | ||
| 259 | np->wd_timeo, &ticks); | ||
| 260 | if (hv_err == HV_EOK) | ||
| 261 | return 0; | ||
| 262 | |||
| 263 | if (hv_err == HV_EWOULDBLOCK) { | ||
| 264 | if (++block >= N2RNG_BLOCK_LIMIT) | ||
| 265 | return -EWOULDBLOCK; | ||
| 266 | __delay(ticks); | ||
| 267 | } else if (hv_err == HV_EBUSY) { | ||
| 268 | if (++busy >= N2RNG_BUSY_LIMIT) | ||
| 269 | return -EBUSY; | ||
| 270 | udelay(1); | ||
| 271 | } else | ||
| 272 | return -ENODEV; | ||
| 273 | } | ||
| 274 | } | ||
| 275 | |||
| 276 | /* Just try to see if we can successfully access the control register | ||
| 277 | * of the RNG on the domain on which we are currently executing. | ||
| 278 | */ | ||
| 279 | static int n2rng_try_read_ctl(struct n2rng *np) | ||
| 280 | { | ||
| 281 | unsigned long hv_err; | ||
| 282 | unsigned long x; | ||
| 283 | |||
| 284 | if (np->hvapi_major == 1) { | ||
| 285 | hv_err = sun4v_rng_get_diag_ctl(); | ||
| 286 | } else { | ||
| 287 | /* We purposefully give invalid arguments, HV_NOACCESS | ||
| 288 | * is higher priority than the errors we'd get from | ||
| 289 | * these other cases, and that's the error we are | ||
| 290 | * truly interested in. | ||
| 291 | */ | ||
| 292 | hv_err = sun4v_rng_ctl_read_v2(0UL, ~0UL, &x, &x, &x, &x); | ||
| 293 | switch (hv_err) { | ||
| 294 | case HV_EWOULDBLOCK: | ||
| 295 | case HV_ENOACCESS: | ||
| 296 | break; | ||
| 297 | default: | ||
| 298 | hv_err = HV_EOK; | ||
| 299 | break; | ||
| 300 | } | ||
| 301 | } | ||
| 302 | |||
| 303 | return n2rng_hv_err_trans(hv_err); | ||
| 304 | } | ||
| 305 | |||
| 306 | #define CONTROL_DEFAULT_BASE \ | ||
| 307 | ((2 << RNG_CTL_ASEL_SHIFT) | \ | ||
| 308 | (N2RNG_ACCUM_CYCLES_DEFAULT << RNG_CTL_WAIT_SHIFT) | \ | ||
| 309 | RNG_CTL_LFSR) | ||
| 310 | |||
| 311 | #define CONTROL_DEFAULT_0 \ | ||
| 312 | (CONTROL_DEFAULT_BASE | \ | ||
| 313 | (1 << RNG_CTL_VCO_SHIFT) | \ | ||
| 314 | RNG_CTL_ES1) | ||
| 315 | #define CONTROL_DEFAULT_1 \ | ||
| 316 | (CONTROL_DEFAULT_BASE | \ | ||
| 317 | (2 << RNG_CTL_VCO_SHIFT) | \ | ||
| 318 | RNG_CTL_ES2) | ||
| 319 | #define CONTROL_DEFAULT_2 \ | ||
| 320 | (CONTROL_DEFAULT_BASE | \ | ||
| 321 | (3 << RNG_CTL_VCO_SHIFT) | \ | ||
| 322 | RNG_CTL_ES3) | ||
| 323 | #define CONTROL_DEFAULT_3 \ | ||
| 324 | (CONTROL_DEFAULT_BASE | \ | ||
| 325 | RNG_CTL_ES1 | RNG_CTL_ES2 | RNG_CTL_ES3) | ||
| 326 | |||
| 327 | static void n2rng_control_swstate_init(struct n2rng *np) | ||
| 328 | { | ||
| 329 | int i; | ||
| 330 | |||
| 331 | np->flags |= N2RNG_FLAG_CONTROL; | ||
| 332 | |||
| 333 | np->health_check_sec = N2RNG_HEALTH_CHECK_SEC_DEFAULT; | ||
| 334 | np->accum_cycles = N2RNG_ACCUM_CYCLES_DEFAULT; | ||
| 335 | np->wd_timeo = N2RNG_WD_TIMEO_DEFAULT; | ||
| 336 | |||
| 337 | for (i = 0; i < np->num_units; i++) { | ||
| 338 | struct n2rng_unit *up = &np->units[i]; | ||
| 339 | |||
| 340 | up->control[0] = CONTROL_DEFAULT_0; | ||
| 341 | up->control[1] = CONTROL_DEFAULT_1; | ||
| 342 | up->control[2] = CONTROL_DEFAULT_2; | ||
| 343 | up->control[3] = CONTROL_DEFAULT_3; | ||
| 344 | } | ||
| 345 | |||
| 346 | np->hv_state = HV_RNG_STATE_UNCONFIGURED; | ||
| 347 | } | ||
| 348 | |||
| 349 | static int n2rng_grab_diag_control(struct n2rng *np) | ||
| 350 | { | ||
| 351 | int i, busy_count, err = -ENODEV; | ||
| 352 | |||
| 353 | busy_count = 0; | ||
| 354 | for (i = 0; i < 100; i++) { | ||
| 355 | err = n2rng_try_read_ctl(np); | ||
| 356 | if (err != -EAGAIN) | ||
| 357 | break; | ||
| 358 | |||
| 359 | if (++busy_count > 100) { | ||
| 360 | dev_err(&np->op->dev, | ||
| 361 | "Grab diag control timeout.\n"); | ||
| 362 | return -ENODEV; | ||
| 363 | } | ||
| 364 | |||
| 365 | udelay(1); | ||
| 366 | } | ||
| 367 | |||
| 368 | return err; | ||
| 369 | } | ||
| 370 | |||
| 371 | static int n2rng_init_control(struct n2rng *np) | ||
| 372 | { | ||
| 373 | int err = n2rng_grab_diag_control(np); | ||
| 374 | |||
| 375 | /* Not in the control domain, that's OK we are only a consumer | ||
| 376 | * of the RNG data, we don't setup and program it. | ||
| 377 | */ | ||
| 378 | if (err == -EPERM) | ||
| 379 | return 0; | ||
| 380 | if (err) | ||
| 381 | return err; | ||
| 382 | |||
| 383 | n2rng_control_swstate_init(np); | ||
| 384 | |||
| 385 | return 0; | ||
| 386 | } | ||
| 387 | |||
| 388 | static int n2rng_data_read(struct hwrng *rng, u32 *data) | ||
| 389 | { | ||
| 390 | struct n2rng *np = (struct n2rng *) rng->priv; | ||
| 391 | unsigned long ra = __pa(&np->test_data); | ||
| 392 | int len; | ||
| 393 | |||
| 394 | if (!(np->flags & N2RNG_FLAG_READY)) { | ||
| 395 | len = 0; | ||
| 396 | } else if (np->flags & N2RNG_FLAG_BUFFER_VALID) { | ||
| 397 | np->flags &= ~N2RNG_FLAG_BUFFER_VALID; | ||
| 398 | *data = np->buffer; | ||
| 399 | len = 4; | ||
| 400 | } else { | ||
| 401 | int err = n2rng_generic_read_data(ra); | ||
| 402 | if (!err) { | ||
| 403 | np->buffer = np->test_data >> 32; | ||
| 404 | *data = np->test_data & 0xffffffff; | ||
| 405 | len = 4; | ||
| 406 | } else { | ||
| 407 | dev_err(&np->op->dev, "RNG error, restesting\n"); | ||
| 408 | np->flags &= ~N2RNG_FLAG_READY; | ||
| 409 | if (!(np->flags & N2RNG_FLAG_SHUTDOWN)) | ||
| 410 | schedule_delayed_work(&np->work, 0); | ||
| 411 | len = 0; | ||
| 412 | } | ||
| 413 | } | ||
| 414 | |||
| 415 | return len; | ||
| 416 | } | ||
| 417 | |||
| 418 | /* On a guest node, just make sure we can read random data properly. | ||
| 419 | * If a control node reboots or reloads it's n2rng driver, this won't | ||
| 420 | * work during that time. So we have to keep probing until the device | ||
| 421 | * becomes usable. | ||
| 422 | */ | ||
| 423 | static int n2rng_guest_check(struct n2rng *np) | ||
| 424 | { | ||
| 425 | unsigned long ra = __pa(&np->test_data); | ||
| 426 | |||
| 427 | return n2rng_generic_read_data(ra); | ||
| 428 | } | ||
| 429 | |||
| 430 | static int n2rng_entropy_diag_read(struct n2rng *np, unsigned long unit, | ||
| 431 | u64 *pre_control, u64 pre_state, | ||
| 432 | u64 *buffer, unsigned long buf_len, | ||
| 433 | u64 *post_control, u64 post_state) | ||
| 434 | { | ||
| 435 | unsigned long post_ctl_ra = __pa(post_control); | ||
| 436 | unsigned long pre_ctl_ra = __pa(pre_control); | ||
| 437 | unsigned long buffer_ra = __pa(buffer); | ||
| 438 | int err; | ||
| 439 | |||
| 440 | err = n2rng_generic_write_control(np, pre_ctl_ra, unit, pre_state); | ||
| 441 | if (err) | ||
| 442 | return err; | ||
| 443 | |||
| 444 | err = n2rng_generic_read_diag_data(np, unit, | ||
| 445 | buffer_ra, buf_len); | ||
| 446 | |||
| 447 | (void) n2rng_generic_write_control(np, post_ctl_ra, unit, | ||
| 448 | post_state); | ||
| 449 | |||
| 450 | return err; | ||
| 451 | } | ||
| 452 | |||
| 453 | static u64 advance_polynomial(u64 poly, u64 val, int count) | ||
| 454 | { | ||
| 455 | int i; | ||
| 456 | |||
| 457 | for (i = 0; i < count; i++) { | ||
| 458 | int highbit_set = ((s64)val < 0); | ||
| 459 | |||
| 460 | val <<= 1; | ||
| 461 | if (highbit_set) | ||
| 462 | val ^= poly; | ||
| 463 | } | ||
| 464 | |||
| 465 | return val; | ||
| 466 | } | ||
| 467 | |||
| 468 | static int n2rng_test_buffer_find(struct n2rng *np, u64 val) | ||
| 469 | { | ||
| 470 | int i, count = 0; | ||
| 471 | |||
| 472 | /* Purposefully skip over the first word. */ | ||
| 473 | for (i = 1; i < SELFTEST_BUFFER_WORDS; i++) { | ||
| 474 | if (np->test_buffer[i] == val) | ||
| 475 | count++; | ||
| 476 | } | ||
| 477 | return count; | ||
| 478 | } | ||
| 479 | |||
| 480 | static void n2rng_dump_test_buffer(struct n2rng *np) | ||
| 481 | { | ||
| 482 | int i; | ||
| 483 | |||
| 484 | for (i = 0; i < SELFTEST_BUFFER_WORDS; i++) | ||
| 485 | dev_err(&np->op->dev, "Test buffer slot %d [0x%016lx]\n", | ||
| 486 | i, np->test_buffer[i]); | ||
| 487 | } | ||
| 488 | |||
| 489 | static int n2rng_check_selftest_buffer(struct n2rng *np, unsigned long unit) | ||
| 490 | { | ||
| 491 | u64 val = SELFTEST_VAL; | ||
| 492 | int err, matches, limit; | ||
| 493 | |||
| 494 | matches = 0; | ||
| 495 | for (limit = 0; limit < SELFTEST_LOOPS_MAX; limit++) { | ||
| 496 | matches += n2rng_test_buffer_find(np, val); | ||
| 497 | if (matches >= SELFTEST_MATCH_GOAL) | ||
| 498 | break; | ||
| 499 | val = advance_polynomial(SELFTEST_POLY, val, 1); | ||
| 500 | } | ||
| 501 | |||
| 502 | err = 0; | ||
| 503 | if (limit >= SELFTEST_LOOPS_MAX) { | ||
| 504 | err = -ENODEV; | ||
| 505 | dev_err(&np->op->dev, "Selftest failed on unit %lu\n", unit); | ||
| 506 | n2rng_dump_test_buffer(np); | ||
| 507 | } else | ||
| 508 | dev_info(&np->op->dev, "Selftest passed on unit %lu\n", unit); | ||
| 509 | |||
| 510 | return err; | ||
| 511 | } | ||
| 512 | |||
| 513 | static int n2rng_control_selftest(struct n2rng *np, unsigned long unit) | ||
| 514 | { | ||
| 515 | int err; | ||
| 516 | |||
| 517 | np->test_control[0] = (0x2 << RNG_CTL_ASEL_SHIFT); | ||
| 518 | np->test_control[1] = (0x2 << RNG_CTL_ASEL_SHIFT); | ||
| 519 | np->test_control[2] = (0x2 << RNG_CTL_ASEL_SHIFT); | ||
| 520 | np->test_control[3] = ((0x2 << RNG_CTL_ASEL_SHIFT) | | ||
| 521 | RNG_CTL_LFSR | | ||
| 522 | ((SELFTEST_TICKS - 2) << RNG_CTL_WAIT_SHIFT)); | ||
| 523 | |||
| 524 | |||
| 525 | err = n2rng_entropy_diag_read(np, unit, np->test_control, | ||
| 526 | HV_RNG_STATE_HEALTHCHECK, | ||
| 527 | np->test_buffer, | ||
| 528 | sizeof(np->test_buffer), | ||
| 529 | &np->units[unit].control[0], | ||
| 530 | np->hv_state); | ||
| 531 | if (err) | ||
| 532 | return err; | ||
| 533 | |||
| 534 | return n2rng_check_selftest_buffer(np, unit); | ||
| 535 | } | ||
| 536 | |||
| 537 | static int n2rng_control_check(struct n2rng *np) | ||
| 538 | { | ||
| 539 | int i; | ||
| 540 | |||
| 541 | for (i = 0; i < np->num_units; i++) { | ||
| 542 | int err = n2rng_control_selftest(np, i); | ||
| 543 | if (err) | ||
| 544 | return err; | ||
| 545 | } | ||
| 546 | return 0; | ||
| 547 | } | ||
| 548 | |||
| 549 | /* The sanity checks passed, install the final configuration into the | ||
| 550 | * chip, it's ready to use. | ||
| 551 | */ | ||
| 552 | static int n2rng_control_configure_units(struct n2rng *np) | ||
| 553 | { | ||
| 554 | int unit, err; | ||
| 555 | |||
| 556 | err = 0; | ||
| 557 | for (unit = 0; unit < np->num_units; unit++) { | ||
| 558 | struct n2rng_unit *up = &np->units[unit]; | ||
| 559 | unsigned long ctl_ra = __pa(&up->control[0]); | ||
| 560 | int esrc; | ||
| 561 | u64 base; | ||
| 562 | |||
| 563 | base = ((np->accum_cycles << RNG_CTL_WAIT_SHIFT) | | ||
| 564 | (2 << RNG_CTL_ASEL_SHIFT) | | ||
| 565 | RNG_CTL_LFSR); | ||
| 566 | |||
| 567 | /* XXX This isn't the best. We should fetch a bunch | ||
| 568 | * XXX of words using each entropy source combined XXX | ||
| 569 | * with each VCO setting, and see which combinations | ||
| 570 | * XXX give the best random data. | ||
| 571 | */ | ||
| 572 | for (esrc = 0; esrc < 3; esrc++) | ||
| 573 | up->control[esrc] = base | | ||
| 574 | (esrc << RNG_CTL_VCO_SHIFT) | | ||
| 575 | (RNG_CTL_ES1 << esrc); | ||
| 576 | |||
| 577 | up->control[3] = base | | ||
| 578 | (RNG_CTL_ES1 | RNG_CTL_ES2 | RNG_CTL_ES3); | ||
| 579 | |||
| 580 | err = n2rng_generic_write_control(np, ctl_ra, unit, | ||
| 581 | HV_RNG_STATE_CONFIGURED); | ||
| 582 | if (err) | ||
| 583 | break; | ||
| 584 | } | ||
| 585 | |||
| 586 | return err; | ||
| 587 | } | ||
| 588 | |||
| 589 | static void n2rng_work(struct work_struct *work) | ||
| 590 | { | ||
| 591 | struct n2rng *np = container_of(work, struct n2rng, work.work); | ||
| 592 | int err = 0; | ||
| 593 | |||
| 594 | if (!(np->flags & N2RNG_FLAG_CONTROL)) { | ||
| 595 | err = n2rng_guest_check(np); | ||
| 596 | } else { | ||
| 597 | preempt_disable(); | ||
| 598 | err = n2rng_control_check(np); | ||
| 599 | preempt_enable(); | ||
| 600 | |||
| 601 | if (!err) | ||
| 602 | err = n2rng_control_configure_units(np); | ||
| 603 | } | ||
| 604 | |||
| 605 | if (!err) { | ||
| 606 | np->flags |= N2RNG_FLAG_READY; | ||
| 607 | dev_info(&np->op->dev, "RNG ready\n"); | ||
| 608 | } | ||
| 609 | |||
| 610 | if (err && !(np->flags & N2RNG_FLAG_SHUTDOWN)) | ||
| 611 | schedule_delayed_work(&np->work, HZ * 2); | ||
| 612 | } | ||
| 613 | |||
| 614 | static void __devinit n2rng_driver_version(void) | ||
| 615 | { | ||
| 616 | static int n2rng_version_printed; | ||
| 617 | |||
| 618 | if (n2rng_version_printed++ == 0) | ||
| 619 | pr_info("%s", version); | ||
| 620 | } | ||
| 621 | |||
| 622 | static int __devinit n2rng_probe(struct of_device *op, | ||
| 623 | const struct of_device_id *match) | ||
| 624 | { | ||
| 625 | int victoria_falls = (match->data != NULL); | ||
| 626 | int err = -ENOMEM; | ||
| 627 | struct n2rng *np; | ||
| 628 | |||
| 629 | n2rng_driver_version(); | ||
| 630 | |||
| 631 | np = kzalloc(sizeof(*np), GFP_KERNEL); | ||
| 632 | if (!np) | ||
| 633 | goto out; | ||
| 634 | np->op = op; | ||
| 635 | |||
| 636 | INIT_DELAYED_WORK(&np->work, n2rng_work); | ||
| 637 | |||
| 638 | if (victoria_falls) | ||
| 639 | np->flags |= N2RNG_FLAG_VF; | ||
| 640 | |||
| 641 | err = -ENODEV; | ||
| 642 | np->hvapi_major = 2; | ||
| 643 | if (sun4v_hvapi_register(HV_GRP_RNG, | ||
| 644 | np->hvapi_major, | ||
| 645 | &np->hvapi_minor)) { | ||
| 646 | np->hvapi_major = 1; | ||
| 647 | if (sun4v_hvapi_register(HV_GRP_RNG, | ||
| 648 | np->hvapi_major, | ||
| 649 | &np->hvapi_minor)) { | ||
| 650 | dev_err(&op->dev, "Cannot register suitable " | ||
| 651 | "HVAPI version.\n"); | ||
| 652 | goto out_free; | ||
| 653 | } | ||
| 654 | } | ||
| 655 | |||
| 656 | if (np->flags & N2RNG_FLAG_VF) { | ||
| 657 | if (np->hvapi_major < 2) { | ||
| 658 | dev_err(&op->dev, "VF RNG requires HVAPI major " | ||
| 659 | "version 2 or later, got %lu\n", | ||
| 660 | np->hvapi_major); | ||
| 661 | goto out_hvapi_unregister; | ||
| 662 | } | ||
| 663 | np->num_units = of_getintprop_default(op->node, | ||
| 664 | "rng-#units", 0); | ||
| 665 | if (!np->num_units) { | ||
| 666 | dev_err(&op->dev, "VF RNG lacks rng-#units property\n"); | ||
| 667 | goto out_hvapi_unregister; | ||
| 668 | } | ||
| 669 | } else | ||
| 670 | np->num_units = 1; | ||
| 671 | |||
| 672 | dev_info(&op->dev, "Registered RNG HVAPI major %lu minor %lu\n", | ||
| 673 | np->hvapi_major, np->hvapi_minor); | ||
| 674 | |||
| 675 | np->units = kzalloc(sizeof(struct n2rng_unit) * np->num_units, | ||
| 676 | GFP_KERNEL); | ||
| 677 | err = -ENOMEM; | ||
| 678 | if (!np->units) | ||
| 679 | goto out_hvapi_unregister; | ||
| 680 | |||
| 681 | err = n2rng_init_control(np); | ||
| 682 | if (err) | ||
| 683 | goto out_free_units; | ||
| 684 | |||
| 685 | dev_info(&op->dev, "Found %s RNG, units: %d\n", | ||
| 686 | ((np->flags & N2RNG_FLAG_VF) ? | ||
| 687 | "Victoria Falls" : "Niagara2"), | ||
| 688 | np->num_units); | ||
| 689 | |||
| 690 | np->hwrng.name = "n2rng"; | ||
| 691 | np->hwrng.data_read = n2rng_data_read; | ||
| 692 | np->hwrng.priv = (unsigned long) np; | ||
| 693 | |||
| 694 | err = hwrng_register(&np->hwrng); | ||
| 695 | if (err) | ||
| 696 | goto out_free_units; | ||
| 697 | |||
| 698 | dev_set_drvdata(&op->dev, np); | ||
| 699 | |||
| 700 | schedule_delayed_work(&np->work, 0); | ||
| 701 | |||
| 702 | return 0; | ||
| 703 | |||
| 704 | out_free_units: | ||
| 705 | kfree(np->units); | ||
| 706 | np->units = NULL; | ||
| 707 | |||
| 708 | out_hvapi_unregister: | ||
| 709 | sun4v_hvapi_unregister(HV_GRP_RNG); | ||
| 710 | |||
| 711 | out_free: | ||
| 712 | kfree(np); | ||
| 713 | out: | ||
| 714 | return err; | ||
| 715 | } | ||
| 716 | |||
| 717 | static int __devexit n2rng_remove(struct of_device *op) | ||
| 718 | { | ||
| 719 | struct n2rng *np = dev_get_drvdata(&op->dev); | ||
| 720 | |||
| 721 | np->flags |= N2RNG_FLAG_SHUTDOWN; | ||
| 722 | |||
| 723 | cancel_delayed_work_sync(&np->work); | ||
| 724 | |||
| 725 | hwrng_unregister(&np->hwrng); | ||
| 726 | |||
| 727 | sun4v_hvapi_unregister(HV_GRP_RNG); | ||
| 728 | |||
| 729 | kfree(np->units); | ||
| 730 | np->units = NULL; | ||
| 731 | |||
| 732 | kfree(np); | ||
| 733 | |||
| 734 | dev_set_drvdata(&op->dev, NULL); | ||
| 735 | |||
| 736 | return 0; | ||
| 737 | } | ||
| 738 | |||
| 739 | static struct of_device_id n2rng_match[] = { | ||
| 740 | { | ||
| 741 | .name = "random-number-generator", | ||
| 742 | .compatible = "SUNW,n2-rng", | ||
| 743 | }, | ||
| 744 | { | ||
| 745 | .name = "random-number-generator", | ||
| 746 | .compatible = "SUNW,vf-rng", | ||
| 747 | .data = (void *) 1, | ||
| 748 | }, | ||
| 749 | {}, | ||
| 750 | }; | ||
| 751 | MODULE_DEVICE_TABLE(of, n2rng_match); | ||
| 752 | |||
| 753 | static struct of_platform_driver n2rng_driver = { | ||
| 754 | .name = "n2rng", | ||
| 755 | .match_table = n2rng_match, | ||
| 756 | .probe = n2rng_probe, | ||
| 757 | .remove = __devexit_p(n2rng_remove), | ||
| 758 | }; | ||
| 759 | |||
| 760 | static int __init n2rng_init(void) | ||
| 761 | { | ||
| 762 | return of_register_driver(&n2rng_driver, &of_bus_type); | ||
| 763 | } | ||
| 764 | |||
| 765 | static void __exit n2rng_exit(void) | ||
| 766 | { | ||
| 767 | of_unregister_driver(&n2rng_driver); | ||
| 768 | } | ||
| 769 | |||
| 770 | module_init(n2rng_init); | ||
| 771 | module_exit(n2rng_exit); | ||
diff --git a/drivers/char/hw_random/n2rng.h b/drivers/char/hw_random/n2rng.h new file mode 100644 index 000000000000..a2b81e7bfc18 --- /dev/null +++ b/drivers/char/hw_random/n2rng.h | |||
| @@ -0,0 +1,118 @@ | |||
| 1 | /* n2rng.h: Niagara2 RNG defines. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2008 David S. Miller <davem@davemloft.net> | ||
| 4 | */ | ||
| 5 | |||
| 6 | #ifndef _N2RNG_H | ||
| 7 | #define _N2RNG_H | ||
| 8 | |||
| 9 | #define RNG_CTL_WAIT 0x0000000001fffe00ULL /* Minimum wait time */ | ||
| 10 | #define RNG_CTL_WAIT_SHIFT 9 | ||
| 11 | #define RNG_CTL_BYPASS 0x0000000000000100ULL /* VCO voltage source */ | ||
| 12 | #define RNG_CTL_VCO 0x00000000000000c0ULL /* VCO rate control */ | ||
| 13 | #define RNG_CTL_VCO_SHIFT 6 | ||
| 14 | #define RNG_CTL_ASEL 0x0000000000000030ULL /* Analog MUX select */ | ||
| 15 | #define RNG_CTL_ASEL_SHIFT 4 | ||
| 16 | #define RNG_CTL_LFSR 0x0000000000000008ULL /* Use LFSR or plain shift */ | ||
| 17 | #define RNG_CTL_ES3 0x0000000000000004ULL /* Enable entropy source 3 */ | ||
| 18 | #define RNG_CTL_ES2 0x0000000000000002ULL /* Enable entropy source 2 */ | ||
| 19 | #define RNG_CTL_ES1 0x0000000000000001ULL /* Enable entropy source 1 */ | ||
| 20 | |||
| 21 | #define HV_FAST_RNG_GET_DIAG_CTL 0x130 | ||
| 22 | #define HV_FAST_RNG_CTL_READ 0x131 | ||
| 23 | #define HV_FAST_RNG_CTL_WRITE 0x132 | ||
| 24 | #define HV_FAST_RNG_DATA_READ_DIAG 0x133 | ||
| 25 | #define HV_FAST_RNG_DATA_READ 0x134 | ||
| 26 | |||
| 27 | #define HV_RNG_STATE_UNCONFIGURED 0 | ||
| 28 | #define HV_RNG_STATE_CONFIGURED 1 | ||
| 29 | #define HV_RNG_STATE_HEALTHCHECK 2 | ||
| 30 | #define HV_RNG_STATE_ERROR 3 | ||
| 31 | |||
| 32 | #define HV_RNG_NUM_CONTROL 4 | ||
| 33 | |||
| 34 | #ifndef __ASSEMBLY__ | ||
| 35 | extern unsigned long sun4v_rng_get_diag_ctl(void); | ||
| 36 | extern unsigned long sun4v_rng_ctl_read_v1(unsigned long ctl_regs_ra, | ||
| 37 | unsigned long *state, | ||
| 38 | unsigned long *tick_delta); | ||
| 39 | extern unsigned long sun4v_rng_ctl_read_v2(unsigned long ctl_regs_ra, | ||
| 40 | unsigned long unit, | ||
| 41 | unsigned long *state, | ||
| 42 | unsigned long *tick_delta, | ||
| 43 | unsigned long *watchdog, | ||
| 44 | unsigned long *write_status); | ||
| 45 | extern unsigned long sun4v_rng_ctl_write_v1(unsigned long ctl_regs_ra, | ||
| 46 | unsigned long state, | ||
| 47 | unsigned long write_timeout, | ||
| 48 | unsigned long *tick_delta); | ||
| 49 | extern unsigned long sun4v_rng_ctl_write_v2(unsigned long ctl_regs_ra, | ||
| 50 | unsigned long state, | ||
| 51 | unsigned long write_timeout, | ||
| 52 | unsigned long unit); | ||
| 53 | extern unsigned long sun4v_rng_data_read_diag_v1(unsigned long data_ra, | ||
| 54 | unsigned long len, | ||
| 55 | unsigned long *tick_delta); | ||
| 56 | extern unsigned long sun4v_rng_data_read_diag_v2(unsigned long data_ra, | ||
| 57 | unsigned long len, | ||
| 58 | unsigned long unit, | ||
| 59 | unsigned long *tick_delta); | ||
| 60 | extern unsigned long sun4v_rng_data_read(unsigned long data_ra, | ||
| 61 | unsigned long *tick_delta); | ||
| 62 | |||
| 63 | struct n2rng_unit { | ||
| 64 | u64 control[HV_RNG_NUM_CONTROL]; | ||
| 65 | }; | ||
| 66 | |||
| 67 | struct n2rng { | ||
| 68 | struct of_device *op; | ||
| 69 | |||
| 70 | unsigned long flags; | ||
| 71 | #define N2RNG_FLAG_VF 0x00000001 /* Victoria Falls RNG, else N2 */ | ||
| 72 | #define N2RNG_FLAG_CONTROL 0x00000002 /* Operating in control domain */ | ||
| 73 | #define N2RNG_FLAG_READY 0x00000008 /* Ready for hw-rng layer */ | ||
| 74 | #define N2RNG_FLAG_SHUTDOWN 0x00000010 /* Driver unregistering */ | ||
| 75 | #define N2RNG_FLAG_BUFFER_VALID 0x00000020 /* u32 buffer holds valid data */ | ||
| 76 | |||
| 77 | int num_units; | ||
| 78 | struct n2rng_unit *units; | ||
| 79 | |||
| 80 | struct hwrng hwrng; | ||
| 81 | u32 buffer; | ||
| 82 | |||
| 83 | /* Registered hypervisor group API major and minor version. */ | ||
| 84 | unsigned long hvapi_major; | ||
| 85 | unsigned long hvapi_minor; | ||
| 86 | |||
| 87 | struct delayed_work work; | ||
| 88 | |||
| 89 | unsigned long hv_state; /* HV_RNG_STATE_foo */ | ||
| 90 | |||
| 91 | unsigned long health_check_sec; | ||
| 92 | unsigned long accum_cycles; | ||
| 93 | unsigned long wd_timeo; | ||
| 94 | #define N2RNG_HEALTH_CHECK_SEC_DEFAULT 0 | ||
| 95 | #define N2RNG_ACCUM_CYCLES_DEFAULT 2048 | ||
| 96 | #define N2RNG_WD_TIMEO_DEFAULT 0 | ||
| 97 | |||
| 98 | u64 scratch_control[HV_RNG_NUM_CONTROL]; | ||
| 99 | |||
| 100 | #define SELFTEST_TICKS 38859 | ||
| 101 | #define SELFTEST_VAL ((u64)0xB8820C7BD387E32C) | ||
| 102 | #define SELFTEST_POLY ((u64)0x231DCEE91262B8A3) | ||
| 103 | #define SELFTEST_MATCH_GOAL 6 | ||
| 104 | #define SELFTEST_LOOPS_MAX 40000 | ||
| 105 | #define SELFTEST_BUFFER_WORDS 8 | ||
| 106 | |||
| 107 | u64 test_data; | ||
| 108 | u64 test_control[HV_RNG_NUM_CONTROL]; | ||
| 109 | u64 test_buffer[SELFTEST_BUFFER_WORDS]; | ||
| 110 | }; | ||
| 111 | |||
| 112 | #define N2RNG_BLOCK_LIMIT 60000 | ||
| 113 | #define N2RNG_BUSY_LIMIT 100 | ||
| 114 | #define N2RNG_HCHECK_LIMIT 100 | ||
| 115 | |||
| 116 | #endif /* !(__ASSEMBLY__) */ | ||
| 117 | |||
| 118 | #endif /* _N2RNG_H */ | ||
