octeon_rnm.c revision 1.4 1 /* $NetBSD: octeon_rnm.c,v 1.4 2020/05/12 14:04:50 simonb Exp $ */
2
3 /*
4 * Copyright (c) 2007 Internet Initiative Japan, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: octeon_rnm.c,v 1.4 2020/05/12 14:04:50 simonb Exp $");
31
32 #include <sys/param.h>
33 #include <sys/device.h>
34 #include <sys/kernel.h>
35 #include <sys/rndsource.h>
36 #include <sys/systm.h>
37
38 #include <mips/locore.h>
39 #include <mips/cavium/include/iobusvar.h>
40 #include <mips/cavium/dev/octeon_rnmreg.h>
41 #include <mips/cavium/dev/octeon_corereg.h>
42 #include <mips/cavium/octeonvar.h>
43
44 #include <sys/bus.h>
45
46 #define RNG_DELAY_CLOCK 91
47
48 struct octeon_rnm_softc {
49 bus_space_tag_t sc_bust;
50 bus_space_handle_t sc_regh;
51 kmutex_t sc_lock;
52 krndsource_t sc_rndsrc; /* /dev/random source */
53 };
54
55 static int octeon_rnm_match(device_t, struct cfdata *, void *);
56 static void octeon_rnm_attach(device_t, device_t, void *);
57 static void octeon_rnm_rng(size_t, void *);
58 static uint64_t octeon_rnm_load(struct octeon_rnm_softc *);
59
60 CFATTACH_DECL_NEW(octeon_rnm, sizeof(struct octeon_rnm_softc),
61 octeon_rnm_match, octeon_rnm_attach, NULL, NULL);
62
63 static int
64 octeon_rnm_match(device_t parent, struct cfdata *cf, void *aux)
65 {
66 struct iobus_attach_args *aa = aux;
67 int result = 0;
68
69 if (strcmp(cf->cf_name, aa->aa_name) != 0)
70 goto out;
71 if (cf->cf_unit != aa->aa_unitno)
72 goto out;
73 result = 1;
74
75 out:
76 return result;
77 }
78
79 static void
80 octeon_rnm_attach(device_t parent, device_t self, void *aux)
81 {
82 struct octeon_rnm_softc *sc = device_private(self);
83 struct iobus_attach_args *aa = aux;
84 uint64_t bist_status;
85
86 aprint_normal("\n");
87
88 sc->sc_bust = aa->aa_bust;
89 if (bus_space_map(aa->aa_bust, aa->aa_unit->addr, RNM_SIZE,
90 0, &sc->sc_regh) != 0) {
91 aprint_error_dev(self, "unable to map device\n");
92 return;
93 }
94
95 bist_status = bus_space_read_8(sc->sc_bust, sc->sc_regh,
96 RNM_BIST_STATUS_OFFSET);
97 if (bist_status) {
98 aprint_error_dev(self, "RNG built in self test failed: %#lx\n",
99 bist_status);
100 return;
101 }
102
103 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
104
105 #ifdef notyet
106 /*
107 * Enable the internal ring oscillator entropy source (ENT),
108 * but disable the LFSR/SHA-1 engine (RNG) so we get the raw RO
109 * samples.
110 *
111 * XXX simonb
112 * To access the raw entropy, it looks like this needs to be
113 * done through the IOBDMA. Put this in the "Too Hard For Now"
114 * basket and just use the RNG.
115 */
116 bus_space_write_8(sc->sc_bust, sc->sc_regh, RNM_CTL_STATUS_OFFSET,
117 RNM_CTL_STATUS_EXP_ENT | RNM_CTL_STATUS_ENT_EN);
118
119 /*
120 * Once entropy is enabled, 64 bits of raw entropy is available
121 * every 8 clock cycles. Wait a microsecond now before the
122 * random callback is called to much sure random data is
123 * available.
124 */
125 delay(1);
126 #else
127 /* Enable the LFSR/SHA-1 engine (RNG). */
128 bus_space_write_8(sc->sc_bust, sc->sc_regh, RNM_CTL_STATUS_OFFSET,
129 RNM_CTL_STATUS_RNG_EN | RNM_CTL_STATUS_ENT_EN);
130
131 /*
132 * Once entropy is enabled, a 64-bit random number is available
133 * every 81 clock cycles. Wait a microsecond now before the
134 * random callback is called to much sure random data is
135 * available.
136 */
137 delay(1);
138 #endif
139
140 rndsource_setcb(&sc->sc_rndsrc, octeon_rnm_rng, sc);
141 rnd_attach_source(&sc->sc_rndsrc, device_xname(self), RND_TYPE_RNG,
142 RND_FLAG_DEFAULT | RND_FLAG_HASCB);
143 }
144
145 static void
146 octeon_rnm_rng(size_t nbytes, void *vsc)
147 {
148 struct octeon_rnm_softc *sc = vsc;
149 uint64_t rn;
150 int i;
151
152 /* Prevent concurrent access from emptying the FIFO. */
153 mutex_enter(&sc->sc_lock);
154 for (i = 0; i < howmany(nbytes, sizeof(rn)); i++) {
155 rn = octeon_rnm_load(sc);
156 rnd_add_data(&sc->sc_rndsrc,
157 &rn, sizeof(rn), sizeof(rn) * NBBY);
158 /*
159 * XXX
160 *
161 * If accessing RNG data, the 512 byte FIFO that gets
162 * 8 bytes of RNG data added every 81 clock cycles.
163 *
164 * If accessing raw oscillator entropy, the 512 byte
165 * FIFO gets 8 bytes of raw entropy added every 8 clock
166 * cycles.
167 *
168 * We should in theory rate limit calls to
169 * octeon_rnm_load() to observe this limit. In practice
170 * we don't appear to call octeon_rnm_load() anywhere
171 * near that often.
172 */
173 }
174 mutex_exit(&sc->sc_lock);
175 }
176
177 static uint64_t
178 octeon_rnm_load(struct octeon_rnm_softc *sc)
179 {
180 uint64_t addr =
181 RNM_OPERATION_BASE_IO_BIT |
182 __BITS64_SET(RNM_OPERATION_BASE_MAJOR_DID, 0x08) |
183 __BITS64_SET(RNM_OPERATION_BASE_SUB_DID, 0x00);
184
185 return octeon_xkphys_read_8(addr);
186 }
187