diff options
author | David S. Miller <davem@davemloft.net> | 2008-06-03 18:56:11 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-07-18 03:46:09 -0400 |
commit | ce087150211412afd901a3fa16b1aab5b54d1bcb (patch) | |
tree | 0d0a725558c797193d3c40256d26a69c279668e6 /drivers/char/hw_random | |
parent | 432e8765f0206de5bbddcbd4eb1d9611c79b1eaa (diff) |
sparc64: Add Niagara2 RNG driver.
With feedback and suggestions from Sam Ravnborg.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/char/hw_random')
-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 */ | ||