FreeBSD/Linux Kernel Cross Reference
sys/riscv/htif/htif.c
1 /*-
2 * Copyright (c) 2015-2016 Ruslan Bukin <br@bsdpad.com>
3 * All rights reserved.
4 *
5 * Portions of this software were developed by SRI International and the
6 * University of Cambridge Computer Laboratory under DARPA/AFRL contract
7 * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
8 *
9 * Portions of this software were developed by the University of Cambridge
10 * Computer Laboratory as part of the CTSRD Project, with support from the
11 * UK Higher Education Innovation Fund (HEIF).
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD: releng/11.0/sys/riscv/htif/htif.c 295972 2016-02-24 16:50:34Z br $");
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/bus.h>
41 #include <sys/kernel.h>
42 #include <sys/module.h>
43 #include <sys/rman.h>
44 #include <sys/pcpu.h>
45 #include <sys/proc.h>
46
47 #include <vm/vm.h>
48 #include <vm/pmap.h>
49
50 #include <dev/fdt/fdt_common.h>
51 #include <dev/ofw/openfirm.h>
52 #include <dev/ofw/ofw_bus.h>
53 #include <dev/ofw/ofw_bus_subr.h>
54
55 #include <machine/bus.h>
56 #include <machine/cpu.h>
57 #include <machine/intr.h>
58 #include <machine/asm.h>
59 #include <machine/trap.h>
60 #include <machine/vmparam.h>
61
62 #include "htif.h"
63
64 static struct resource_spec htif_spec[] = {
65 { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE},
66 { -1, 0 }
67 };
68
69 struct intr_entry {
70 void (*func) (void *, uint64_t);
71 void *arg;
72 };
73
74 struct intr_entry intrs[HTIF_NDEV];
75
76 uint64_t
77 htif_command(uint64_t arg)
78 {
79
80 return (machine_command(ECALL_HTIF_CMD, arg));
81 }
82
83 int
84 htif_setup_intr(int id, void *func, void *arg)
85 {
86
87 if (id >= HTIF_NDEV)
88 return (-1);
89
90 intrs[id].func = func;
91 intrs[id].arg = arg;
92
93 return (0);
94 }
95
96 static void
97 htif_handle_entry(struct htif_softc *sc)
98 {
99 uint64_t entry;
100 uint8_t devcmd;
101 uint8_t devid;
102
103 entry = machine_command(ECALL_HTIF_GET_ENTRY, 0);
104 while (entry) {
105 devid = HTIF_DEV_ID(entry);
106 devcmd = HTIF_DEV_CMD(entry);
107
108 if (devcmd == HTIF_CMD_IDENTIFY) {
109 /* Enumeration interrupt */
110 if (devid == sc->identify_id)
111 sc->identify_done = 1;
112 } else {
113 /* Device interrupt */
114 if (intrs[devid].func != NULL)
115 intrs[devid].func(intrs[devid].arg, entry);
116 }
117
118 entry = machine_command(ECALL_HTIF_GET_ENTRY, 0);
119 }
120 }
121
122 static int
123 htif_intr(void *arg)
124 {
125 struct htif_softc *sc;
126
127 sc = arg;
128
129 csr_clear(sip, SIP_SSIP);
130
131 htif_handle_entry(sc);
132
133 return (FILTER_HANDLED);
134 }
135
136 static int
137 htif_add_device(struct htif_softc *sc, int i, char *id, char *name)
138 {
139 struct htif_dev_ivars *di;
140
141 di = malloc(sizeof(struct htif_dev_ivars), M_DEVBUF, M_WAITOK | M_ZERO);
142 di->sc = sc;
143 di->index = i;
144 di->id = malloc(HTIF_ID_LEN, M_DEVBUF, M_WAITOK | M_ZERO);
145 memcpy(di->id, id, HTIF_ID_LEN);
146
147 di->dev = device_add_child(sc->dev, name, -1);
148 device_set_ivars(di->dev, di);
149
150 return (0);
151 }
152
153 static int
154 htif_enumerate(struct htif_softc *sc)
155 {
156 char id[HTIF_ID_LEN] __aligned(HTIF_ALIGN);
157 uint64_t paddr;
158 uint64_t data;
159 uint64_t cmd;
160 int len;
161 int i;
162
163 device_printf(sc->dev, "Enumerating devices\n");
164
165 for (i = 0; i < HTIF_NDEV; i++) {
166 paddr = pmap_kextract((vm_offset_t)&id);
167 data = (paddr << IDENTIFY_PADDR_SHIFT);
168 data |= IDENTIFY_IDENT;
169
170 sc->identify_id = i;
171 sc->identify_done = 0;
172
173 cmd = i;
174 cmd <<= HTIF_DEV_ID_SHIFT;
175 cmd |= (HTIF_CMD_IDENTIFY << HTIF_CMD_SHIFT);
176 cmd |= data;
177
178 htif_command(cmd);
179
180 /* Do poll as interrupts are disabled yet */
181 while (sc->identify_done == 0) {
182 htif_handle_entry(sc);
183 }
184
185 len = strnlen(id, sizeof(id));
186 if (len <= 0)
187 break;
188
189 if (bootverbose)
190 printf(" %d %s\n", i, id);
191
192 if (strncmp(id, "disk", 4) == 0)
193 htif_add_device(sc, i, id, "htif_blk");
194 else if (strncmp(id, "bcd", 3) == 0)
195 htif_add_device(sc, i, id, "htif_console");
196 else if (strncmp(id, "syscall_proxy", 13) == 0)
197 htif_add_device(sc, i, id, "htif_syscall_proxy");
198 }
199
200 return (bus_generic_attach(sc->dev));
201 }
202
203 int
204 htif_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
205 {
206 struct htif_dev_ivars *ivars;
207
208 ivars = device_get_ivars(child);
209
210 switch (which) {
211 case HTIF_IVAR_INDEX:
212 *result = ivars->index;
213 break;
214 case HTIF_IVAR_ID:
215 *result = (uintptr_t)ivars->id;
216 default:
217 return (EINVAL);
218 }
219
220 return (0);
221 }
222
223 static int
224 htif_probe(device_t dev)
225 {
226
227 if (!ofw_bus_status_okay(dev))
228 return (ENXIO);
229
230 if (!ofw_bus_is_compatible(dev, "riscv,htif"))
231 return (ENXIO);
232
233 device_set_desc(dev, "HTIF bus device");
234 return (BUS_PROBE_DEFAULT);
235 }
236
237 static int
238 htif_attach(device_t dev)
239 {
240 struct htif_softc *sc;
241 int error;
242
243 sc = device_get_softc(dev);
244 sc->dev = dev;
245
246 if (bus_alloc_resources(dev, htif_spec, sc->res)) {
247 device_printf(dev, "could not allocate resources\n");
248 return (ENXIO);
249 }
250
251 /* Setup IRQs handler */
252 error = bus_setup_intr(dev, sc->res[0], INTR_TYPE_CLK,
253 htif_intr, NULL, sc, &sc->ihl[0]);
254 if (error) {
255 device_printf(dev, "Unable to alloc int resource.\n");
256 return (ENXIO);
257 }
258
259 csr_set(sie, SIE_SSIE);
260
261 return (htif_enumerate(sc));
262 }
263
264 static device_method_t htif_methods[] = {
265 DEVMETHOD(device_probe, htif_probe),
266 DEVMETHOD(device_attach, htif_attach),
267
268 /* Bus interface */
269 DEVMETHOD(bus_read_ivar, htif_read_ivar),
270
271 DEVMETHOD_END
272 };
273
274 static driver_t htif_driver = {
275 "htif",
276 htif_methods,
277 sizeof(struct htif_softc)
278 };
279
280 static devclass_t htif_devclass;
281
282 DRIVER_MODULE(htif, simplebus, htif_driver,
283 htif_devclass, 0, 0);
Cache object: 506e376f2b10359a1994fdbd0abe369c
|