1210311Sjmallett/*-
2210311Sjmallett * Copyright (c) 2010 Juli Mallett <jmallett@FreeBSD.org>
3210311Sjmallett * All rights reserved.
4210311Sjmallett *
5210311Sjmallett * Redistribution and use in source and binary forms, with or without
6210311Sjmallett * modification, are permitted provided that the following conditions
7210311Sjmallett * are met:
8210311Sjmallett * 1. Redistributions of source code must retain the above copyright
9210311Sjmallett *    notice, this list of conditions and the following disclaimer.
10210311Sjmallett * 2. Redistributions in binary form must reproduce the above copyright
11210311Sjmallett *    notice, this list of conditions and the following disclaimer in the
12210311Sjmallett *    documentation and/or other materials provided with the distribution.
13210311Sjmallett *
14210311Sjmallett * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15210311Sjmallett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16210311Sjmallett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17210311Sjmallett * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18210311Sjmallett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19210311Sjmallett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20210311Sjmallett * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21210311Sjmallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22210311Sjmallett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23210311Sjmallett * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24210311Sjmallett * SUCH DAMAGE.
25210311Sjmallett *
26210311Sjmallett * $FreeBSD: releng/10.2/sys/mips/cavium/octeon_rnd.c 265999 2014-05-14 01:35:43Z ian $
27210311Sjmallett */
28210311Sjmallett
29210311Sjmallett#include <sys/cdefs.h>
30210311Sjmallett__FBSDID("$FreeBSD: releng/10.2/sys/mips/cavium/octeon_rnd.c 265999 2014-05-14 01:35:43Z ian $");
31210311Sjmallett
32210311Sjmallett#include <sys/param.h>
33210311Sjmallett#include <sys/systm.h>
34210311Sjmallett#include <sys/bus.h>
35210311Sjmallett#include <sys/clock.h>
36210311Sjmallett#include <sys/kernel.h>
37210311Sjmallett#include <sys/lock.h>
38210311Sjmallett#include <sys/module.h>
39210311Sjmallett#include <sys/random.h>
40210311Sjmallett
41210311Sjmallett#include <contrib/octeon-sdk/cvmx.h>
42210311Sjmallett#include <contrib/octeon-sdk/cvmx-rng.h>
43210311Sjmallett
44210311Sjmallett#define	OCTEON_RND_WORDS	2
45210311Sjmallett
46210311Sjmallettstruct octeon_rnd_softc {
47210311Sjmallett	uint64_t sc_entropy[OCTEON_RND_WORDS];
48210311Sjmallett	struct callout sc_callout;
49210311Sjmallett};
50210311Sjmallett
51210311Sjmallettstatic void	octeon_rnd_identify(driver_t *drv, device_t parent);
52210311Sjmallettstatic int	octeon_rnd_attach(device_t dev);
53210311Sjmallettstatic int	octeon_rnd_probe(device_t dev);
54210311Sjmallettstatic int	octeon_rnd_detach(device_t dev);
55210311Sjmallett
56210311Sjmallettstatic void	octeon_rnd_harvest(void *);
57210311Sjmallett
58210311Sjmallettstatic device_method_t octeon_rnd_methods[] = {
59210311Sjmallett	/* Device interface */
60210311Sjmallett	DEVMETHOD(device_identify,	octeon_rnd_identify),
61210311Sjmallett	DEVMETHOD(device_probe,		octeon_rnd_probe),
62210311Sjmallett	DEVMETHOD(device_attach,	octeon_rnd_attach),
63210311Sjmallett	DEVMETHOD(device_detach,	octeon_rnd_detach),
64210311Sjmallett
65210311Sjmallett	{ 0, 0 }
66210311Sjmallett};
67210311Sjmallett
68210311Sjmallettstatic driver_t octeon_rnd_driver = {
69210311Sjmallett	"rnd",
70210311Sjmallett	octeon_rnd_methods,
71210311Sjmallett	sizeof (struct octeon_rnd_softc)
72210311Sjmallett};
73210311Sjmallettstatic devclass_t octeon_rnd_devclass;
74210311SjmallettDRIVER_MODULE(rnd, nexus, octeon_rnd_driver, octeon_rnd_devclass, 0, 0);
75210311Sjmallett
76210311Sjmallettstatic void
77210311Sjmallettocteon_rnd_identify(driver_t *drv, device_t parent)
78210311Sjmallett{
79210311Sjmallett	BUS_ADD_CHILD(parent, 0, "rnd", 0);
80210311Sjmallett}
81210311Sjmallett
82210311Sjmallettstatic int
83210311Sjmallettocteon_rnd_probe(device_t dev)
84210311Sjmallett{
85210311Sjmallett	if (device_get_unit(dev) != 0)
86210311Sjmallett		return (ENXIO);
87210311Sjmallett
88210311Sjmallett	device_set_desc(dev, "Cavium Octeon Random Number Generator");
89265999Sian	return (BUS_PROBE_NOWILDCARD);
90210311Sjmallett}
91210311Sjmallett
92210311Sjmallettstatic int
93210311Sjmallettocteon_rnd_attach(device_t dev)
94210311Sjmallett{
95210311Sjmallett	struct octeon_rnd_softc *sc;
96210311Sjmallett
97210311Sjmallett	sc = device_get_softc(dev);
98210311Sjmallett	callout_init(&sc->sc_callout, CALLOUT_MPSAFE);
99210311Sjmallett	callout_reset(&sc->sc_callout, hz * 5, octeon_rnd_harvest, sc);
100210311Sjmallett
101210311Sjmallett	cvmx_rng_enable();
102210311Sjmallett
103210311Sjmallett	return (0);
104210311Sjmallett}
105210311Sjmallett
106210311Sjmallettstatic int
107210311Sjmallettocteon_rnd_detach(device_t dev)
108210311Sjmallett{
109210311Sjmallett	struct octeon_rnd_softc *sc;
110210311Sjmallett
111210311Sjmallett	sc = device_get_softc(dev);
112210311Sjmallett
113210311Sjmallett	callout_stop(&sc->sc_callout);
114210311Sjmallett
115210311Sjmallett	return (0);
116210311Sjmallett}
117210311Sjmallett
118210311Sjmallettstatic void
119210311Sjmallettocteon_rnd_harvest(void *arg)
120210311Sjmallett{
121210311Sjmallett	struct octeon_rnd_softc *sc;
122210311Sjmallett	unsigned i;
123210311Sjmallett
124210311Sjmallett	sc = arg;
125210311Sjmallett
126210311Sjmallett	for (i = 0; i < OCTEON_RND_WORDS; i++)
127210311Sjmallett		sc->sc_entropy[i] = cvmx_rng_get_random64();
128210311Sjmallett	random_harvest(sc->sc_entropy, sizeof sc->sc_entropy,
129256381Smarkm		       (sizeof(sc->sc_entropy)*8)/2, RANDOM_PURE_OCTEON);
130210311Sjmallett
131210311Sjmallett	callout_reset(&sc->sc_callout, hz * 5, octeon_rnd_harvest, sc);
132210311Sjmallett}
133