The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arm/broadcom/bcm2835/bcm2835_rng.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 BCM2835_RNG_STATUS      0x04            /* BCM2835 RNG status register */
   73 #define BCM2838_RNG_STATUS      0x18            /* BCM2838 RNG status register */
   74 
   75 #define BCM2838_RNG_COUNT       0x24            /* How many values available */
   76 #define BCM2838_COUNT_VAL_MASK  0x000000ff
   77 
   78 #define BCM2835_RND_VAL_SHIFT   24              /*  Shift for valid words */
   79 #define BCM2835_RND_VAL_MASK    0x000000ff      /*  Number valid words mask */
   80 #define BCM2835_RND_VAL_WARM_CNT        0x40000         /*  RNG Warm Up count */
   81 #define BCM2835_RND_WARM_CNT    0xfffff         /*  RNG Warm Up Count mask */
   82 
   83 #define BCM2835_RNG_DATA        0x08            /* RNG Data Register */
   84 #define BCM2838_RNG_DATA        0x20
   85 #define RNG_FF_THRES            0x0c
   86 #define RNG_FF_THRES_MASK       0x0000001f
   87 
   88 #define BCM2835_RNG_INT_MASK            0x10
   89 #define BCM2835_RNG_INT_OFF_BIT         0x00000001
   90 
   91 #define RNG_FF_DEFAULT          0x10            /* FIFO threshold default */
   92 #define RNG_FIFO_WORDS          (RNG_FF_DEFAULT / sizeof(uint32_t))
   93 
   94 #define RNG_NUM_OSCILLATORS     6
   95 #define RNG_STALL_COUNT_DEFAULT 10
   96 
   97 #define RNG_CALLOUT_TICKS       (hz * 4)
   98 
   99 struct bcm_rng_conf {
  100         bus_size_t              control_reg;
  101         bus_size_t              status_reg;
  102         bus_size_t              count_reg;
  103         bus_size_t              data_reg;
  104         bus_size_t              intr_mask_reg;
  105         uint32_t                intr_disable_bit;
  106         uint32_t                count_value_shift;
  107         uint32_t                count_value_mask;
  108         uint32_t                warmup_count;
  109         bool                    allow_2x_mode;
  110         bool                    can_diagnose;
  111         /* XXX diag regs */
  112 };
  113 
  114 static const struct bcm_rng_conf bcm2835_rng_conf = {
  115         .control_reg            = RNG_CTRL,
  116         .status_reg             = BCM2835_RNG_STATUS,
  117         .count_reg              = BCM2835_RNG_STATUS,   /* Same register */
  118         .data_reg               = BCM2835_RNG_DATA,
  119         .intr_mask_reg          = BCM2835_RNG_INT_MASK,
  120         .intr_disable_bit       = BCM2835_RNG_INT_OFF_BIT,
  121         .count_value_shift      = BCM2835_RND_VAL_SHIFT,
  122         .count_value_mask       = BCM2835_RND_VAL_MASK,
  123         .warmup_count           = BCM2835_RND_VAL_WARM_CNT,
  124         .allow_2x_mode          = true,
  125         .can_diagnose           = true
  126 };
  127 
  128 static const struct bcm_rng_conf bcm2838_rng_conf = {
  129         .control_reg            = RNG_CTRL,
  130         .status_reg             = BCM2838_RNG_STATUS,
  131         .count_reg              = BCM2838_RNG_COUNT,
  132         .data_reg               = BCM2838_RNG_DATA,
  133         .intr_mask_reg          = 0,
  134         .intr_disable_bit       = 0,
  135         .count_value_shift      = 0,
  136         .count_value_mask       = BCM2838_COUNT_VAL_MASK,
  137         .warmup_count           = 0,
  138         .allow_2x_mode          = false,
  139         .can_diagnose           = false
  140 };
  141 
  142 struct bcm2835_rng_softc {
  143         device_t                sc_dev;
  144         struct resource *       sc_mem_res;
  145         struct resource *       sc_irq_res;
  146         void *                  sc_intr_hdl;
  147         struct bcm_rng_conf const*      conf;
  148         uint32_t                sc_buf[RNG_FIFO_WORDS];
  149         struct callout          sc_rngto;
  150         int                     sc_stall_count;
  151         int                     sc_rbg2x;
  152         long                    sc_underrun;
  153 };
  154 
  155 static struct ofw_compat_data compat_data[] = {
  156         {"broadcom,bcm2835-rng",        (uintptr_t)&bcm2835_rng_conf},
  157         {"brcm,bcm2835-rng",            (uintptr_t)&bcm2835_rng_conf},
  158 
  159         {"brcm,bcm2711-rng200",         (uintptr_t)&bcm2838_rng_conf},
  160         {"brcm,bcm2838-rng",            (uintptr_t)&bcm2838_rng_conf},
  161         {"brcm,bcm2838-rng200",         (uintptr_t)&bcm2838_rng_conf},
  162         {"brcm,bcm7211-rng",            (uintptr_t)&bcm2838_rng_conf},
  163         {"brcm,bcm7278-rng",            (uintptr_t)&bcm2838_rng_conf},
  164         {"brcm,iproc-rng200",           (uintptr_t)&bcm2838_rng_conf},
  165         {NULL,                          0}
  166 };
  167 
  168 static __inline void
  169 bcm2835_rng_stat_inc_underrun(struct bcm2835_rng_softc *sc)
  170 {
  171 
  172         atomic_add_long(&sc->sc_underrun, 1);
  173 }
  174 
  175 static __inline uint32_t
  176 bcm2835_rng_read4(struct bcm2835_rng_softc *sc, bus_size_t off)
  177 {
  178 
  179         return bus_read_4(sc->sc_mem_res, off);
  180 }
  181 
  182 static __inline void
  183 bcm2835_rng_read_multi4(struct bcm2835_rng_softc *sc, bus_size_t off,
  184     uint32_t *datap, bus_size_t count)
  185 {
  186 
  187         bus_read_multi_4(sc->sc_mem_res, off, datap, count);
  188 }
  189 
  190 static __inline void
  191 bcm2835_rng_write4(struct bcm2835_rng_softc *sc, bus_size_t off, uint32_t val)
  192 {
  193 
  194         bus_write_4(sc->sc_mem_res, off, val);
  195 }
  196 
  197 static void
  198 bcm2835_rng_dump_registers(struct bcm2835_rng_softc *sc, struct sbuf *sbp)
  199 {
  200         uint32_t comblk2_osc, comblk1_osc, jclk_byp_div, val;
  201         int i;
  202 
  203         if (!sc->conf->can_diagnose)
  204             /* Not implemented. */
  205             return;
  206 
  207         /* Display RNG control register contents */
  208         val = bcm2835_rng_read4(sc, sc->conf->control_reg);
  209         sbuf_printf(sbp, "RNG_CTRL (%08x)\n", val);
  210 
  211         comblk2_osc = (val & RNG_COMBLK2_OSC) >> RNG_COMBLK2_OSC_SHIFT;
  212         sbuf_printf(sbp, "  RNG_COMBLK2_OSC (%02x)\n", comblk2_osc);
  213         for (i = 0; i < RNG_NUM_OSCILLATORS; i++)
  214                 if ((comblk2_osc & (1 << i)) == 0)
  215                         sbuf_printf(sbp, "    Oscillator %d enabled\n", i + 1);
  216 
  217         comblk1_osc = (val & RNG_COMBLK1_OSC) >> RNG_COMBLK1_OSC_SHIFT;
  218         sbuf_printf(sbp, "  RNG_COMBLK1_OSC (%02x)\n", comblk1_osc);
  219         for (i = 0; i < RNG_NUM_OSCILLATORS; i++)
  220                 if ((comblk1_osc & (1 << i)) == 0)
  221                         sbuf_printf(sbp, "    Oscillator %d enabled\n", i + 1);
  222 
  223         jclk_byp_div = (val & RNG_JCLK_BYP_DIV_CNT) >>
  224             RNG_JCLK_BYP_DIV_CNT_SHIFT;
  225         sbuf_printf(sbp,
  226             "  RNG_JCLK_BYP_DIV_CNT (%02x)\n    APB clock frequency / %d\n",
  227             jclk_byp_div, 2 * (jclk_byp_div + 1));
  228 
  229         sbuf_printf(sbp, "  RNG_JCLK_BYP_SRC:\n    %s\n",
  230             (val & RNG_JCLK_BYP_SRC) ? "Use divided down APB clock" :
  231             "Use RNG clock (APB clock)");
  232 
  233         sbuf_printf(sbp, "  RNG_JCLK_BYP_SEL:\n    %s\n",
  234             (val & RNG_JCLK_BYP_SEL) ? "Bypass internal jitter clock" :
  235             "Use internal jitter clock");
  236 
  237         if ((val & RNG_RBG2X) != 0)
  238                 sbuf_cat(sbp, "  RNG_RBG2X: RNG 2X SPEED enabled\n");
  239 
  240         if ((val & RNG_RBGEN_BIT) != 0)
  241                 sbuf_cat(sbp, "  RNG_RBGEN_BIT: RBG enabled\n");
  242 
  243         /* Display RNG status register contents */
  244         val = bcm2835_rng_read4(sc, sc->conf->status_reg);
  245         sbuf_printf(sbp, "RNG_CTRL (%08x)\n", val);
  246         sbuf_printf(sbp, "  RND_VAL: %02x\n",
  247             (val >> sc->conf->count_value_shift) & sc->conf->count_value_mask);
  248         sbuf_printf(sbp, "  RND_WARM_CNT: %05x\n", val & sc->conf->warmup_count);
  249 
  250         /* Display FIFO threshold register contents */
  251         val = bcm2835_rng_read4(sc, RNG_FF_THRES);
  252         sbuf_printf(sbp, "RNG_FF_THRES: %05x\n", val & RNG_FF_THRES_MASK);
  253 
  254         /* Display interrupt mask register contents */
  255         val = bcm2835_rng_read4(sc, sc->conf->intr_mask_reg);
  256         sbuf_printf(sbp, "RNG_INT_MASK: interrupt %s\n",
  257              ((val & sc->conf->intr_disable_bit) != 0) ? "disabled" : "enabled");
  258 }
  259 
  260 static void
  261 bcm2835_rng_disable_intr(struct bcm2835_rng_softc *sc)
  262 {
  263         uint32_t mask;
  264 
  265         /* Set the interrupt off bit in the interrupt mask register */
  266         mask = bcm2835_rng_read4(sc, sc->conf->intr_mask_reg);
  267         mask |= sc->conf->intr_disable_bit;
  268         bcm2835_rng_write4(sc, sc->conf->intr_mask_reg, mask);
  269 }
  270 
  271 static void
  272 bcm2835_rng_start(struct bcm2835_rng_softc *sc)
  273 {
  274         uint32_t ctrl;
  275 
  276         /* Disable the interrupt */
  277         if (sc->conf->intr_mask_reg)
  278             bcm2835_rng_disable_intr(sc);
  279 
  280         /* Set the warmup count */
  281         if (sc->conf->warmup_count > 0)
  282             bcm2835_rng_write4(sc, sc->conf->status_reg,
  283                     sc->conf->warmup_count);
  284 
  285         /* Enable the RNG */
  286         ctrl = bcm2835_rng_read4(sc, sc->conf->control_reg);
  287         ctrl |= RNG_RBGEN_BIT;
  288         if (sc->sc_rbg2x && sc->conf->allow_2x_mode)
  289                 ctrl |= RNG_RBG2X;
  290         bcm2835_rng_write4(sc, sc->conf->control_reg, ctrl);
  291 }
  292 
  293 static void
  294 bcm2835_rng_stop(struct bcm2835_rng_softc *sc)
  295 {
  296         uint32_t ctrl;
  297 
  298         /* Disable the RNG */
  299         ctrl = bcm2835_rng_read4(sc, sc->conf->control_reg);
  300         ctrl &= ~RNG_RBGEN_BIT;
  301         bcm2835_rng_write4(sc, sc->conf->control_reg, ctrl);
  302 }
  303 
  304 static void
  305 bcm2835_rng_enqueue_harvest(struct bcm2835_rng_softc *sc, uint32_t nread)
  306 {
  307         char *sc_buf_chunk;
  308         uint32_t chunk_size;
  309         uint32_t cnt;
  310 
  311         chunk_size = sizeof(((struct harvest_event *)0)->he_entropy);
  312         cnt = nread * sizeof(uint32_t);
  313         sc_buf_chunk = (void*)sc->sc_buf;
  314 
  315         while (cnt > 0) {
  316                 uint32_t size;
  317 
  318                 size = MIN(cnt, chunk_size);
  319 
  320                 random_harvest_queue(sc_buf_chunk, size, RANDOM_PURE_BROADCOM);
  321 
  322                 sc_buf_chunk += size;
  323                 cnt -= size;
  324         }
  325 }
  326 
  327 static void
  328 bcm2835_rng_harvest(void *arg)
  329 {
  330         uint32_t *dest;
  331         uint32_t hwcount;
  332         u_int cnt, nread, num_avail, num_words;
  333         int seen_underrun, num_stalls;
  334         struct bcm2835_rng_softc *sc = arg;
  335 
  336         dest = sc->sc_buf;
  337         nread = num_words = 0;
  338         seen_underrun = num_stalls = 0;
  339 
  340         for (cnt = sizeof(sc->sc_buf) / sizeof(uint32_t); cnt > 0;
  341             cnt -= num_words) {
  342                 /* Read count register to find out how many words available */
  343                 hwcount = bcm2835_rng_read4(sc, sc->conf->count_reg);
  344                 num_avail = (hwcount >> sc->conf->count_value_shift) &
  345                     sc->conf->count_value_mask;
  346 
  347                 /* If we have none... */
  348                 if (num_avail == 0) {
  349                         bcm2835_rng_stat_inc_underrun(sc);
  350                         if (++seen_underrun >= sc->sc_stall_count) {
  351                                 if (num_stalls++ > 0) {
  352                                         device_printf(sc->sc_dev,
  353                                             "RNG stalled, disabling device\n");
  354                                         bcm2835_rng_stop(sc);
  355                                         break;
  356                                 } else {
  357                                         device_printf(sc->sc_dev,
  358                                             "Too many underruns, resetting\n");
  359                                         bcm2835_rng_stop(sc);
  360                                         bcm2835_rng_start(sc);
  361                                         seen_underrun = 0;
  362                                 }
  363                         }
  364                         /* Try again */
  365                         continue;
  366                 }
  367 
  368                 CTR2(KTR_DEV, "%s: %d words available in RNG FIFO",
  369                     device_get_nameunit(sc->sc_dev), num_avail);
  370 
  371                 /* Pull MIN(num_avail, cnt) words from the FIFO */
  372                 num_words = (num_avail > cnt) ? cnt : num_avail;
  373                 bcm2835_rng_read_multi4(sc, sc->conf->data_reg, dest,
  374                     num_words);
  375                 dest += num_words;
  376                 nread += num_words;
  377         }
  378 
  379         bcm2835_rng_enqueue_harvest(sc, nread);
  380 
  381         callout_reset(&sc->sc_rngto, RNG_CALLOUT_TICKS, bcm2835_rng_harvest, sc);
  382 }
  383 
  384 static int
  385 sysctl_bcm2835_rng_2xspeed(SYSCTL_HANDLER_ARGS)
  386 {
  387         struct bcm2835_rng_softc *sc = arg1;
  388         int error, rbg2x;
  389 
  390         rbg2x = sc->sc_rbg2x;
  391         error = sysctl_handle_int(oidp, &rbg2x, 0, req);
  392         if (error)
  393                 return (error);
  394         if (req->newptr == NULL)
  395                 return (error);
  396         if (rbg2x == sc->sc_rbg2x)
  397                 return (0);
  398 
  399         /* Reset the RNG */
  400         bcm2835_rng_stop(sc);
  401         sc->sc_rbg2x = rbg2x;
  402         bcm2835_rng_start(sc);
  403 
  404         return (0);
  405 }
  406 
  407 #ifdef BCM2835_RNG_DEBUG_REGISTERS
  408 static int
  409 sysctl_bcm2835_rng_dump(SYSCTL_HANDLER_ARGS)
  410 {
  411         struct sbuf sb;
  412         struct bcm2835_rng_softc *sc = arg1;
  413         int error;
  414 
  415         error = sysctl_wire_old_buffer(req, 0);
  416         if (error != 0)
  417                 return (error);
  418         sbuf_new_for_sysctl(&sb, NULL, 128, req);
  419         bcm2835_rng_dump_registers(sc, &sb);
  420         error = sbuf_finish(&sb);
  421         sbuf_delete(&sb);
  422         return (error);
  423 }
  424 #endif
  425 
  426 static int
  427 bcm2835_rng_probe(device_t dev)
  428 {
  429 
  430         if (!ofw_bus_status_okay(dev))
  431                 return (ENXIO);
  432 
  433         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
  434                 return (ENXIO);
  435 
  436         device_set_desc(dev, "Broadcom BCM2835/BCM2838 RNG");
  437 
  438         return (BUS_PROBE_DEFAULT);
  439 }
  440 
  441 static int
  442 bcm2835_rng_attach(device_t dev)
  443 {
  444         struct bcm2835_rng_softc *sc;
  445         struct sysctl_ctx_list *sysctl_ctx;
  446         struct sysctl_oid *sysctl_tree;
  447         int error, rid;
  448 
  449         error = 0;
  450         sc = device_get_softc(dev);
  451         sc->sc_dev = dev;
  452 
  453         sc->conf = (void const*)ofw_bus_search_compatible(dev, compat_data)->ocd_data;
  454         KASSERT(sc->conf != NULL, ("bcm2835_rng_attach: sc->conf == NULL"));
  455 
  456         sc->sc_stall_count = RNG_STALL_COUNT_DEFAULT;
  457 
  458         /* Initialize callout */
  459         callout_init(&sc->sc_rngto, CALLOUT_MPSAFE);
  460 
  461         TUNABLE_INT_FETCH("bcmrng.stall_count", &sc->sc_stall_count);
  462         if (sc->conf->allow_2x_mode)
  463             TUNABLE_INT_FETCH("bcmrng.2xspeed", &sc->sc_rbg2x);
  464 
  465         /* Allocate memory resources */
  466         rid = 0;
  467         sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  468             RF_ACTIVE);
  469         if (sc->sc_mem_res == NULL) {
  470                 bcm2835_rng_detach(dev);
  471                 return (ENXIO);
  472         }
  473 
  474         /* Start the RNG */
  475         bcm2835_rng_start(sc);
  476 
  477         /* Dump the registers if booting verbose */
  478         if (bootverbose) {
  479                 struct sbuf sb;
  480 
  481                 (void) sbuf_new(&sb, NULL, 256,
  482                     SBUF_AUTOEXTEND | SBUF_INCLUDENUL);
  483                 bcm2835_rng_dump_registers(sc, &sb);
  484                 sbuf_trim(&sb);
  485                 error = sbuf_finish(&sb);
  486                 if (error == 0)
  487                         device_printf(dev, "%s", sbuf_data(&sb));
  488                 sbuf_delete(&sb);
  489         }
  490 
  491         sysctl_ctx = device_get_sysctl_ctx(dev);
  492         sysctl_tree = device_get_sysctl_tree(dev);
  493         SYSCTL_ADD_LONG(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
  494             "underrun", CTLFLAG_RD, &sc->sc_underrun,
  495             "Number of FIFO underruns");
  496         if (sc->conf->allow_2x_mode)
  497                 SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
  498                         "2xspeed", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0,
  499                         sysctl_bcm2835_rng_2xspeed, "I", "Enable RBG 2X SPEED");
  500         SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
  501             "stall_count", CTLFLAG_RW, &sc->sc_stall_count,
  502             RNG_STALL_COUNT_DEFAULT, "Number of underruns to assume RNG stall");
  503 #ifdef BCM2835_RNG_DEBUG_REGISTERS
  504         SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
  505             "dumpregs", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, 0,
  506             sysctl_bcm2835_rng_dump, "S", "Dump RNG registers");
  507 #endif
  508 
  509         /*
  510          * Schedule the initial harvesting one second from now, which should give the
  511          * hardware RNG plenty of time to generate the first random bytes.
  512          */
  513         callout_reset(&sc->sc_rngto, hz, bcm2835_rng_harvest, sc);
  514 
  515         return (0);
  516 }
  517 
  518 static int
  519 bcm2835_rng_detach(device_t dev)
  520 {
  521         struct bcm2835_rng_softc *sc;
  522 
  523         sc = device_get_softc(dev);
  524 
  525         /* Stop the RNG */
  526         bcm2835_rng_stop(sc);
  527 
  528         /* Drain the callout it */
  529         callout_drain(&sc->sc_rngto);
  530 
  531         /* Release memory resource */
  532         if (sc->sc_mem_res != NULL)
  533                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  534 
  535         return (0);
  536 }
  537 
  538 static device_method_t bcm2835_rng_methods[] = {
  539         /* Device interface */
  540         DEVMETHOD(device_probe,         bcm2835_rng_probe),
  541         DEVMETHOD(device_attach,        bcm2835_rng_attach),
  542         DEVMETHOD(device_detach,        bcm2835_rng_detach),
  543 
  544         DEVMETHOD_END
  545 };
  546 
  547 static driver_t bcm2835_rng_driver = {
  548         "bcmrng",
  549         bcm2835_rng_methods,
  550         sizeof(struct bcm2835_rng_softc)
  551 };
  552 
  553 DRIVER_MODULE(bcm2835_rng, simplebus, bcm2835_rng_driver, 0, 0);
  554 DRIVER_MODULE(bcm2835_rng, ofwbus, bcm2835_rng_driver, 0, 0);
  555 MODULE_VERSION(bcm2835_rng, 1);
  556 MODULE_DEPEND(bcm2835_rng, randomdev, 1, 1, 1);

Cache object: 14781a0e6a1b601e3dc9c11b61e3574d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.