]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/broadcom/bcm2835/bcm2835_rng.c
Merge ^/head r358269 through r358399.
[FreeBSD/FreeBSD.git] / sys / arm / broadcom / bcm2835 / bcm2835_rng.c
1 /*
2  * Copyright (c) 2015, 2016, Stephen J. Kiernan
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/ktr.h>
34 #include <sys/lock.h>
35 #include <sys/malloc.h>
36 #include <sys/module.h>
37 #include <sys/random.h>
38 #include <sys/sbuf.h>
39 #include <sys/sysctl.h>
40 #include <sys/selinfo.h>
41 #include <sys/systm.h>
42 #include <sys/bus.h>
43 #include <sys/rman.h>
44
45 #include <machine/bus.h>
46 #include <machine/resource.h>
47
48 #include <dev/ofw/openfirm.h>
49 #include <dev/ofw/ofw_bus.h>
50 #include <dev/ofw/ofw_bus_subr.h>
51
52 #include <dev/random/randomdev.h>
53 #include <dev/random/random_harvestq.h>
54
55 static device_attach_t bcm2835_rng_attach;
56 static device_detach_t bcm2835_rng_detach;
57 static device_probe_t bcm2835_rng_probe;
58
59 #define RNG_CTRL                0x00            /* RNG Control Register */
60 #define RNG_COMBLK1_OSC         0x003f0000      /*  Combiner Blk 1 Oscillator */
61 #define RNG_COMBLK1_OSC_SHIFT   16
62 #define RNG_COMBLK2_OSC         0x0fc00000      /*  Combiner Blk 2 Oscillator */
63 #define RNG_COMBLK2_OSC_SHIFT   22
64 #define RNG_JCLK_BYP_DIV_CNT    0x0000ff00      /*  Jitter clk bypass divider
65                                                     count */
66 #define RNG_JCLK_BYP_DIV_CNT_SHIFT 8
67 #define RNG_JCLK_BYP_SRC        0x00000020      /*  Jitter clk bypass source */
68 #define RNG_JCLK_BYP_SEL        0x00000010      /*  Jitter clk bypass select */
69 #define RNG_RBG2X               0x00000002      /*  RBG 2X SPEED */
70 #define RNG_RBGEN_BIT           0x00000001      /*  Enable RNG bit */
71
72 #define RNG_STATUS              0x04            /* RNG status register */
73 #define RND_VAL_SHIFT           24              /*  Shift for valid words */
74 #define RND_VAL_MASK            0x000000ff      /*  Number valid words mask */
75 #define RND_VAL_WARM_CNT        0x40000         /*  RNG Warm Up count */
76 #define RND_WARM_CNT            0xfffff         /*  RNG Warm Up Count mask */
77
78 #define RNG_DATA                0x08            /* RNG Data Register */
79 #define RNG_FF_THRES            0x0c
80 #define RNG_FF_THRES_MASK       0x0000001f
81
82 #define RNG_INT_MASK            0x10
83 #define RNG_INT_OFF_BIT         0x00000001
84
85 #define RNG_FF_DEFAULT          0x10            /* FIFO threshold default */
86
87 #define RNG_FIFO_WORDS          (RNG_FF_DEFAULT / sizeof(uint32_t))
88
89 #define RNG_NUM_OSCILLATORS     6
90 #define RNG_STALL_COUNT_DEFAULT 10
91
92 #define RNG_CALLOUT_TICKS       (hz * 4)
93
94 struct bcm2835_rng_softc {
95         device_t                sc_dev;
96         struct resource *       sc_mem_res;
97         struct resource *       sc_irq_res;
98         void *                  sc_intr_hdl;
99         uint32_t                sc_buf[RNG_FIFO_WORDS];
100         struct callout          sc_rngto;
101         int                     sc_stall_count;
102         int                     sc_rbg2x;
103         long                    sc_underrun;
104 };
105
106 static struct ofw_compat_data compat_data[] = {
107         {"broadcom,bcm2835-rng",        1},
108         {"brcm,bcm2835-rng",            1},
109         {NULL,                          0}
110 };
111
112 static __inline void
113 bcm2835_rng_stat_inc_underrun(struct bcm2835_rng_softc *sc)
114 {
115
116         atomic_add_long(&sc->sc_underrun, 1);
117 }
118
119 static __inline uint32_t
120 bcm2835_rng_read4(struct bcm2835_rng_softc *sc, bus_size_t off)
121 {
122
123         return bus_read_4(sc->sc_mem_res, off);
124 }
125
126 static __inline void
127 bcm2835_rng_read_multi4(struct bcm2835_rng_softc *sc, bus_size_t off,
128     uint32_t *datap, bus_size_t count)
129 {
130
131         bus_read_multi_4(sc->sc_mem_res, off, datap, count);
132 }
133
134 static __inline void
135 bcm2835_rng_write4(struct bcm2835_rng_softc *sc, bus_size_t off, uint32_t val)
136 {
137
138         bus_write_4(sc->sc_mem_res, off, val);
139 }
140
141 static void
142 bcm2835_rng_dump_registers(struct bcm2835_rng_softc *sc, struct sbuf *sbp)
143 {
144         uint32_t comblk2_osc, comblk1_osc, jclk_byp_div, val;
145         int i;
146
147         /* Display RNG control register contents */
148         val = bcm2835_rng_read4(sc, RNG_CTRL);
149         sbuf_printf(sbp, "RNG_CTRL (%08x)\n", val);
150
151         comblk2_osc = (val & RNG_COMBLK2_OSC) >> RNG_COMBLK2_OSC_SHIFT;
152         sbuf_printf(sbp, "  RNG_COMBLK2_OSC (%02x)\n", comblk2_osc);
153         for (i = 0; i < RNG_NUM_OSCILLATORS; i++)
154                 if ((comblk2_osc & (1 << i)) == 0)
155                         sbuf_printf(sbp, "    Oscillator %d enabled\n", i + 1);
156
157         comblk1_osc = (val & RNG_COMBLK1_OSC) >> RNG_COMBLK1_OSC_SHIFT;
158         sbuf_printf(sbp, "  RNG_COMBLK1_OSC (%02x)\n", comblk1_osc);
159         for (i = 0; i < RNG_NUM_OSCILLATORS; i++)
160                 if ((comblk1_osc & (1 << i)) == 0)
161                         sbuf_printf(sbp, "    Oscillator %d enabled\n", i + 1);
162
163         jclk_byp_div = (val & RNG_JCLK_BYP_DIV_CNT) >>
164             RNG_JCLK_BYP_DIV_CNT_SHIFT;
165         sbuf_printf(sbp,
166             "  RNG_JCLK_BYP_DIV_CNT (%02x)\n    APB clock frequency / %d\n",
167             jclk_byp_div, 2 * (jclk_byp_div + 1));
168
169         sbuf_printf(sbp, "  RNG_JCLK_BYP_SRC:\n    %s\n",
170             (val & RNG_JCLK_BYP_SRC) ? "Use divided down APB clock" :
171             "Use RNG clock (APB clock)");
172
173         sbuf_printf(sbp, "  RNG_JCLK_BYP_SEL:\n    %s\n",
174             (val & RNG_JCLK_BYP_SEL) ? "Bypass internal jitter clock" :
175             "Use internal jitter clock");
176
177         if ((val & RNG_RBG2X) != 0)
178                 sbuf_cat(sbp, "  RNG_RBG2X: RNG 2X SPEED enabled\n");
179
180         if ((val & RNG_RBGEN_BIT) != 0)
181                 sbuf_cat(sbp, "  RNG_RBGEN_BIT: RBG enabled\n");
182
183         /* Display RNG status register contents */
184         val = bcm2835_rng_read4(sc, RNG_STATUS);
185         sbuf_printf(sbp, "RNG_CTRL (%08x)\n", val);
186         sbuf_printf(sbp, "  RND_VAL: %02x\n",
187             (val >> RND_VAL_SHIFT) & RND_VAL_MASK);
188         sbuf_printf(sbp, "  RND_WARM_CNT: %05x\n", val & RND_WARM_CNT);
189
190         /* Display FIFO threshold register contents */
191         val = bcm2835_rng_read4(sc, RNG_FF_THRES);
192         sbuf_printf(sbp, "RNG_FF_THRES: %05x\n", val & RNG_FF_THRES_MASK);
193
194         /* Display interrupt mask register contents */
195         val = bcm2835_rng_read4(sc, RNG_INT_MASK);
196         sbuf_printf(sbp, "RNG_INT_MASK: interrupt %s\n",
197              ((val & RNG_INT_OFF_BIT) != 0) ? "disabled" : "enabled");
198 }
199
200 static void
201 bcm2835_rng_disable_intr(struct bcm2835_rng_softc *sc)
202 {
203         uint32_t mask;
204
205         /* Set the interrupt off bit in the interrupt mask register */
206         mask = bcm2835_rng_read4(sc, RNG_INT_MASK);
207         mask |= RNG_INT_OFF_BIT;
208         bcm2835_rng_write4(sc, RNG_INT_MASK, mask);
209 }
210
211 static void
212 bcm2835_rng_start(struct bcm2835_rng_softc *sc)
213 {
214         uint32_t ctrl;
215
216         /* Disable the interrupt */
217         bcm2835_rng_disable_intr(sc);
218
219         /* Set the warmup count */
220         bcm2835_rng_write4(sc, RNG_STATUS, RND_VAL_WARM_CNT);
221
222         /* Enable the RNG */
223         ctrl = bcm2835_rng_read4(sc, RNG_CTRL);
224         ctrl |= RNG_RBGEN_BIT;
225         if (sc->sc_rbg2x)
226                 ctrl |= RNG_RBG2X;
227         bcm2835_rng_write4(sc, RNG_CTRL, ctrl);
228 }
229
230 static void
231 bcm2835_rng_stop(struct bcm2835_rng_softc *sc)
232 {
233         uint32_t ctrl;
234
235         /* Disable the RNG */
236         ctrl = bcm2835_rng_read4(sc, RNG_CTRL);
237         ctrl &= ~RNG_RBGEN_BIT;
238         bcm2835_rng_write4(sc, RNG_CTRL, ctrl);
239 }
240
241 static void
242 bcm2835_rng_harvest(void *arg)
243 {
244         uint32_t *dest;
245         uint32_t status;
246         u_int cnt, nread, num_avail, num_words;
247         int seen_underrun, num_stalls;
248         struct bcm2835_rng_softc *sc = arg;
249
250         dest = sc->sc_buf;
251         nread = num_words = 0;
252         seen_underrun = num_stalls = 0;
253         for (cnt = sizeof(sc->sc_buf) / sizeof(uint32_t); cnt > 0;
254             cnt -= num_words) {
255                 /* Read status register to find out how many words available */
256                 status = bcm2835_rng_read4(sc, RNG_STATUS);
257                 num_avail = (status >> RND_VAL_SHIFT) & RND_VAL_MASK;
258
259                 /* If we have none... */
260                 if (num_avail == 0) {
261                         bcm2835_rng_stat_inc_underrun(sc);
262                         if (++seen_underrun >= sc->sc_stall_count) {
263                                 if (num_stalls++ > 0) {
264                                         device_printf(sc->sc_dev,
265                                             "RNG stalled, disabling device\n");
266                                         bcm2835_rng_stop(sc);
267                                         break;
268                                 } else {
269                                         device_printf(sc->sc_dev,
270                                             "Too many underruns, resetting\n");
271                                         bcm2835_rng_stop(sc);
272                                         bcm2835_rng_start(sc);
273                                         seen_underrun = 0;
274                                 }
275                         }
276                         /* Try again */
277                         continue;
278                 }
279
280                 CTR2(KTR_DEV, "%s: %d words available in RNG FIFO",
281                     device_get_nameunit(sc->sc_dev), num_avail);
282
283                 /* Pull MIN(num_avail, cnt) words from the FIFO */
284                 num_words = (num_avail > cnt) ? cnt : num_avail;
285                 bcm2835_rng_read_multi4(sc, RNG_DATA, dest,
286                     num_words);
287                 dest += num_words;
288                 nread += num_words;
289         }
290
291         cnt = nread * sizeof(uint32_t);
292         if (cnt > 0)
293                 random_harvest_queue(sc->sc_buf, cnt, RANDOM_PURE_BROADCOM);
294
295         callout_reset(&sc->sc_rngto, RNG_CALLOUT_TICKS, bcm2835_rng_harvest, sc);
296 }
297
298 static int
299 sysctl_bcm2835_rng_2xspeed(SYSCTL_HANDLER_ARGS)
300 {
301         struct bcm2835_rng_softc *sc = arg1;
302         int error, rbg2x;
303
304         rbg2x = sc->sc_rbg2x;
305         error = sysctl_handle_int(oidp, &rbg2x, 0, req);
306         if (error)
307                 return (error);
308         if (req->newptr == NULL)
309                 return (error);
310         if (rbg2x == sc->sc_rbg2x)
311                 return (0);
312
313         /* Reset the RNG */
314         bcm2835_rng_stop(sc);
315         sc->sc_rbg2x = rbg2x;
316         bcm2835_rng_start(sc);
317
318         return (0);
319 }
320
321 #ifdef BCM2835_RNG_DEBUG_REGISTERS
322 static int
323 sysctl_bcm2835_rng_dump(SYSCTL_HANDLER_ARGS)
324 {
325         struct sbuf sb;
326         struct bcm2835_rng_softc *sc = arg1;
327         int error;
328
329         error = sysctl_wire_old_buffer(req, 0);
330         if (error != 0)
331                 return (error);
332         sbuf_new_for_sysctl(&sb, NULL, 128, req);
333         bcm2835_rng_dump_registers(sc, &sb);
334         error = sbuf_finish(&sb);
335         sbuf_delete(&sb);
336         return (error);
337 }
338 #endif
339
340 static int
341 bcm2835_rng_probe(device_t dev)
342 {
343
344         if (!ofw_bus_status_okay(dev))
345                 return (ENXIO);
346
347         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
348                 return (ENXIO);
349
350         device_set_desc(dev, "Broadcom BCM2835 RNG");
351
352         return (BUS_PROBE_DEFAULT);
353 }
354
355 static int
356 bcm2835_rng_attach(device_t dev)
357 {
358         struct bcm2835_rng_softc *sc;
359         struct sysctl_ctx_list *sysctl_ctx;
360         struct sysctl_oid *sysctl_tree;
361         int error, rid;
362
363         error = 0;
364         sc = device_get_softc(dev);
365         sc->sc_dev = dev;
366         sc->sc_stall_count = RNG_STALL_COUNT_DEFAULT;
367
368         /* Initialize callout */
369         callout_init(&sc->sc_rngto, CALLOUT_MPSAFE);
370
371         TUNABLE_INT_FETCH("bcmrng.2xspeed", &sc->sc_rbg2x);
372         TUNABLE_INT_FETCH("bcmrng.stall_count", &sc->sc_stall_count);
373
374         /* Allocate memory resources */
375         rid = 0;
376         sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
377             RF_ACTIVE);
378         if (sc->sc_mem_res == NULL) {
379                 bcm2835_rng_detach(dev);
380                 return (ENXIO);
381         }
382
383         /* Start the RNG */
384         bcm2835_rng_start(sc);
385
386         /* Dump the registers if booting verbose */
387         if (bootverbose) {
388                 struct sbuf sb;
389
390                 (void) sbuf_new(&sb, NULL, 256,
391                     SBUF_AUTOEXTEND | SBUF_INCLUDENUL);
392                 bcm2835_rng_dump_registers(sc, &sb);
393                 sbuf_trim(&sb);
394                 error = sbuf_finish(&sb);
395                 if (error == 0)
396                         device_printf(dev, "%s", sbuf_data(&sb));
397                 sbuf_delete(&sb);
398         }
399
400         sysctl_ctx = device_get_sysctl_ctx(dev);
401         sysctl_tree = device_get_sysctl_tree(dev);
402         SYSCTL_ADD_LONG(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
403             "underrun", CTLFLAG_RD, &sc->sc_underrun,
404             "Number of FIFO underruns");
405         SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
406             "2xspeed", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0,
407             sysctl_bcm2835_rng_2xspeed, "I", "Enable RBG 2X SPEED");
408         SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
409             "stall_count", CTLFLAG_RW, &sc->sc_stall_count,
410             RNG_STALL_COUNT_DEFAULT, "Number of underruns to assume RNG stall");
411 #ifdef BCM2835_RNG_DEBUG_REGISTERS
412         SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
413             "dumpregs", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, 0,
414             sysctl_bcm2835_rng_dump, "S", "Dump RNG registers");
415 #endif
416
417         /* 
418          * Schedule the initial harvesting one second from now, which should give the
419          * hardware RNG plenty of time to generate the first random bytes.
420          */
421         callout_reset(&sc->sc_rngto, hz, bcm2835_rng_harvest, sc);
422
423         return (0);
424 }
425
426 static int
427 bcm2835_rng_detach(device_t dev)
428 {
429         struct bcm2835_rng_softc *sc;
430
431         sc = device_get_softc(dev);
432
433         /* Stop the RNG */
434         bcm2835_rng_stop(sc);
435
436         /* Drain the callout it */
437         callout_drain(&sc->sc_rngto);
438
439         /* Release memory resource */
440         if (sc->sc_mem_res != NULL)
441                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
442
443         return (0);
444 }
445
446 static device_method_t bcm2835_rng_methods[] = {
447         /* Device interface */
448         DEVMETHOD(device_probe,         bcm2835_rng_probe),
449         DEVMETHOD(device_attach,        bcm2835_rng_attach),
450         DEVMETHOD(device_detach,        bcm2835_rng_detach),
451
452         DEVMETHOD_END
453 };
454
455 static driver_t bcm2835_rng_driver = {
456         "bcmrng",
457         bcm2835_rng_methods,
458         sizeof(struct bcm2835_rng_softc)
459 };
460 static devclass_t bcm2835_rng_devclass;
461
462 DRIVER_MODULE(bcm2835_rng, simplebus, bcm2835_rng_driver,
463     bcm2835_rng_devclass, 0, 0);
464 DRIVER_MODULE(bcm2835_rng, ofwbus, bcm2835_rng_driver, bcm2835_rng_devclass, 0,
465     0);
466 MODULE_VERSION(bcm2835_rng, 1);
467 MODULE_DEPEND(bcm2835_rng, randomdev, 1, 1, 1);