virtio_mmio.c revision 1.12 1 1.12 thorpej /* $NetBSD: virtio_mmio.c,v 1.12 2024/01/02 07:24:50 thorpej Exp $ */
2 1.1 jakllsch /* $OpenBSD: virtio_mmio.c,v 1.2 2017/02/24 17:12:31 patrick Exp $ */
3 1.1 jakllsch
4 1.12 thorpej /*-
5 1.12 thorpej * Copyright (c) 2024 The NetBSD Foundation, Inc.
6 1.12 thorpej * All rights reserved.
7 1.12 thorpej *
8 1.12 thorpej * This code is derived from software contributed to The NetBSD Foundation
9 1.12 thorpej * by Jason R. Thorpe.
10 1.12 thorpej *
11 1.12 thorpej * Redistribution and use in source and binary forms, with or without
12 1.12 thorpej * modification, are permitted provided that the following conditions
13 1.12 thorpej * are met:
14 1.12 thorpej * 1. Redistributions of source code must retain the above copyright
15 1.12 thorpej * notice, this list of conditions and the following disclaimer.
16 1.12 thorpej * 2. Redistributions in binary form must reproduce the above copyright
17 1.12 thorpej * notice, this list of conditions and the following disclaimer in the
18 1.12 thorpej * documentation and/or other materials provided with the distribution.
19 1.12 thorpej *
20 1.12 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 1.12 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 1.12 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 1.12 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 1.12 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 1.12 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 1.12 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 1.12 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 1.12 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 1.12 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 1.12 thorpej * POSSIBILITY OF SUCH DAMAGE.
31 1.12 thorpej */
32 1.12 thorpej
33 1.1 jakllsch /*
34 1.1 jakllsch * Copyright (c) 2014 Patrick Wildt <patrick (at) blueri.se>
35 1.1 jakllsch * Copyright (c) 2012 Stefan Fritsch.
36 1.1 jakllsch * Copyright (c) 2010 Minoura Makoto.
37 1.1 jakllsch * All rights reserved.
38 1.1 jakllsch *
39 1.1 jakllsch * Redistribution and use in source and binary forms, with or without
40 1.1 jakllsch * modification, are permitted provided that the following conditions
41 1.1 jakllsch * are met:
42 1.1 jakllsch * 1. Redistributions of source code must retain the above copyright
43 1.1 jakllsch * notice, this list of conditions and the following disclaimer.
44 1.1 jakllsch * 2. Redistributions in binary form must reproduce the above copyright
45 1.1 jakllsch * notice, this list of conditions and the following disclaimer in the
46 1.1 jakllsch * documentation and/or other materials provided with the distribution.
47 1.1 jakllsch *
48 1.1 jakllsch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
49 1.1 jakllsch * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
50 1.1 jakllsch * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
51 1.1 jakllsch * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
52 1.1 jakllsch * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
53 1.1 jakllsch * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
54 1.1 jakllsch * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
55 1.1 jakllsch * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
56 1.1 jakllsch * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
57 1.1 jakllsch * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58 1.1 jakllsch */
59 1.1 jakllsch
60 1.1 jakllsch #include <sys/cdefs.h>
61 1.12 thorpej __KERNEL_RCSID(0, "$NetBSD: virtio_mmio.c,v 1.12 2024/01/02 07:24:50 thorpej Exp $");
62 1.1 jakllsch
63 1.1 jakllsch #include <sys/param.h>
64 1.1 jakllsch #include <sys/systm.h>
65 1.1 jakllsch #include <sys/kernel.h>
66 1.1 jakllsch #include <sys/device.h>
67 1.1 jakllsch #include <sys/mutex.h>
68 1.1 jakllsch
69 1.1 jakllsch #define VIRTIO_PRIVATE
70 1.1 jakllsch #include <dev/virtio/virtio_mmiovar.h>
71 1.1 jakllsch
72 1.1 jakllsch #define VIRTIO_MMIO_MAGIC ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)
73 1.1 jakllsch
74 1.1 jakllsch #define VIRTIO_MMIO_MAGIC_VALUE 0x000
75 1.1 jakllsch #define VIRTIO_MMIO_VERSION 0x004
76 1.1 jakllsch #define VIRTIO_MMIO_DEVICE_ID 0x008
77 1.1 jakllsch #define VIRTIO_MMIO_VENDOR_ID 0x00c
78 1.12 thorpej #define VIRTIO_MMIO_DEVICE_FEATURES 0x010 /* "HostFeatures" in v1 */
79 1.12 thorpej #define VIRTIO_MMIO_DEVICE_FEATURES_SEL 0x014 /* "HostFeaturesSel" in v1 */
80 1.12 thorpej #define VIRTIO_MMIO_DRIVER_FEATURES 0x020 /* "GuestFeatures" in v1 */
81 1.12 thorpej #define VIRTIO_MMIO_DRIVER_FEATURES_SEL 0x024 /* "GuestFeaturesSel" in v1 */
82 1.12 thorpej #define VIRTIO_MMIO_V1_GUEST_PAGE_SIZE 0x028
83 1.1 jakllsch #define VIRTIO_MMIO_QUEUE_SEL 0x030
84 1.1 jakllsch #define VIRTIO_MMIO_QUEUE_NUM_MAX 0x034
85 1.1 jakllsch #define VIRTIO_MMIO_QUEUE_NUM 0x038
86 1.12 thorpej #define VIRTIO_MMIO_V1_QUEUE_ALIGN 0x03c
87 1.12 thorpej #define VIRTIO_MMIO_V1_QUEUE_PFN 0x040
88 1.12 thorpej #define VIRTIO_MMIO_QUEUE_READY 0x044
89 1.1 jakllsch #define VIRTIO_MMIO_QUEUE_NOTIFY 0x050
90 1.1 jakllsch #define VIRTIO_MMIO_INTERRUPT_STATUS 0x060
91 1.1 jakllsch #define VIRTIO_MMIO_INTERRUPT_ACK 0x064
92 1.1 jakllsch #define VIRTIO_MMIO_STATUS 0x070
93 1.12 thorpej #define VIRTIO_MMIO_V2_QUEUE_DESC_LOW 0x080
94 1.12 thorpej #define VIRTIO_MMIO_V2_QUEUE_DESC_HIGH 0x084
95 1.12 thorpej #define VIRTIO_MMIO_V2_QUEUE_AVAIL_LOW 0x090
96 1.12 thorpej #define VIRTIO_MMIO_V2_QUEUE_AVAIL_HIGH 0x094
97 1.12 thorpej #define VIRTIO_MMIO_V2_QUEUE_USED_LOW 0x0a0
98 1.12 thorpej #define VIRTIO_MMIO_V2_QUEUE_USED_HIGH 0x0a4
99 1.12 thorpej #define VIRTIO_MMIO_V2_CONFIG_GEN 0x0fc
100 1.1 jakllsch #define VIRTIO_MMIO_CONFIG 0x100
101 1.1 jakllsch
102 1.1 jakllsch #define VIRTIO_MMIO_INT_VRING (1 << 0)
103 1.1 jakllsch #define VIRTIO_MMIO_INT_CONFIG (1 << 1)
104 1.1 jakllsch
105 1.1 jakllsch /*
106 1.4 reinoud * MMIO configuration space for virtio-mmio v1 is in guest byte order.
107 1.4 reinoud *
108 1.11 rin * XXX For big-endian aarch64 and arm, see note in virtio_pci.c.
109 1.3 jmcneill */
110 1.4 reinoud
111 1.11 rin #if (defined(__aarch64__) || defined(__arm__)) && BYTE_ORDER == BIG_ENDIAN
112 1.5 reinoud # define READ_ENDIAN LITTLE_ENDIAN
113 1.5 reinoud # define STRUCT_ENDIAN BIG_ENDIAN
114 1.5 reinoud #elif BYTE_ORDER == BIG_ENDIAN
115 1.5 reinoud # define READ_ENDIAN BIG_ENDIAN
116 1.5 reinoud # define STRUCT_ENDIAN BIG_ENDIAN
117 1.3 jmcneill #else
118 1.5 reinoud # define READ_ENDIAN LITTLE_ENDIAN
119 1.5 reinoud # define STRUCT_ENDIAN LITTLE_ENDIAN
120 1.3 jmcneill #endif
121 1.3 jmcneill
122 1.1 jakllsch
123 1.1 jakllsch static void virtio_mmio_kick(struct virtio_softc *, uint16_t);
124 1.1 jakllsch static uint16_t virtio_mmio_read_queue_size(struct virtio_softc *, uint16_t);
125 1.12 thorpej static void virtio_mmio_v1_setup_queue(struct virtio_softc *, uint16_t, uint64_t);
126 1.12 thorpej static void virtio_mmio_v2_setup_queue(struct virtio_softc *, uint16_t, uint64_t);
127 1.1 jakllsch static void virtio_mmio_set_status(struct virtio_softc *, int);
128 1.4 reinoud static void virtio_mmio_negotiate_features(struct virtio_softc *, uint64_t);
129 1.7 yamaguch static int virtio_mmio_alloc_interrupts(struct virtio_softc *);
130 1.1 jakllsch static void virtio_mmio_free_interrupts(struct virtio_softc *);
131 1.7 yamaguch static int virtio_mmio_setup_interrupts(struct virtio_softc *, int);
132 1.1 jakllsch
133 1.12 thorpej static uint32_t
134 1.12 thorpej virtio_mmio_reg_read(struct virtio_mmio_softc *sc, bus_addr_t reg)
135 1.12 thorpej {
136 1.12 thorpej uint32_t val;
137 1.12 thorpej
138 1.12 thorpej val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg);
139 1.12 thorpej if (sc->sc_le_regs) {
140 1.12 thorpej val = le32toh(val);
141 1.12 thorpej }
142 1.12 thorpej return val;
143 1.12 thorpej }
144 1.12 thorpej
145 1.12 thorpej static void
146 1.12 thorpej virtio_mmio_reg_write(struct virtio_mmio_softc *sc, bus_addr_t reg,
147 1.12 thorpej uint32_t val)
148 1.12 thorpej {
149 1.12 thorpej if (sc->sc_le_regs) {
150 1.12 thorpej val = htole32(val);
151 1.12 thorpej }
152 1.12 thorpej bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, val);
153 1.12 thorpej }
154 1.12 thorpej
155 1.12 thorpej static void
156 1.12 thorpej virtio_mmio_v2_set_addr(struct virtio_mmio_softc *sc, bus_addr_t reg,
157 1.12 thorpej uint64_t addr)
158 1.12 thorpej {
159 1.12 thorpej virtio_mmio_reg_write(sc, reg, BUS_ADDR_LO32(addr));
160 1.12 thorpej virtio_mmio_reg_write(sc, reg + 4, BUS_ADDR_HI32(addr));
161 1.12 thorpej }
162 1.12 thorpej
163 1.12 thorpej static const struct virtio_ops virtio_mmio_v1_ops = {
164 1.1 jakllsch .kick = virtio_mmio_kick,
165 1.1 jakllsch .read_queue_size = virtio_mmio_read_queue_size,
166 1.12 thorpej .setup_queue = virtio_mmio_v1_setup_queue,
167 1.12 thorpej .set_status = virtio_mmio_set_status,
168 1.12 thorpej .neg_features = virtio_mmio_negotiate_features,
169 1.12 thorpej .alloc_interrupts = virtio_mmio_alloc_interrupts,
170 1.12 thorpej .free_interrupts = virtio_mmio_free_interrupts,
171 1.12 thorpej .setup_interrupts = virtio_mmio_setup_interrupts,
172 1.12 thorpej };
173 1.12 thorpej
174 1.12 thorpej static const struct virtio_ops virtio_mmio_v2_ops = {
175 1.12 thorpej .kick = virtio_mmio_kick,
176 1.12 thorpej .read_queue_size = virtio_mmio_read_queue_size,
177 1.12 thorpej .setup_queue = virtio_mmio_v2_setup_queue,
178 1.1 jakllsch .set_status = virtio_mmio_set_status,
179 1.1 jakllsch .neg_features = virtio_mmio_negotiate_features,
180 1.7 yamaguch .alloc_interrupts = virtio_mmio_alloc_interrupts,
181 1.7 yamaguch .free_interrupts = virtio_mmio_free_interrupts,
182 1.1 jakllsch .setup_interrupts = virtio_mmio_setup_interrupts,
183 1.1 jakllsch };
184 1.1 jakllsch
185 1.1 jakllsch static uint16_t
186 1.1 jakllsch virtio_mmio_read_queue_size(struct virtio_softc *vsc, uint16_t idx)
187 1.1 jakllsch {
188 1.1 jakllsch struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
189 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_QUEUE_SEL, idx);
190 1.12 thorpej return virtio_mmio_reg_read(sc, VIRTIO_MMIO_QUEUE_NUM_MAX);
191 1.1 jakllsch }
192 1.1 jakllsch
193 1.1 jakllsch static void
194 1.12 thorpej virtio_mmio_v1_setup_queue(struct virtio_softc *vsc, uint16_t idx,
195 1.12 thorpej uint64_t addr)
196 1.1 jakllsch {
197 1.1 jakllsch struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
198 1.1 jakllsch
199 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_QUEUE_SEL, idx);
200 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_QUEUE_NUM,
201 1.12 thorpej virtio_mmio_reg_read(sc, VIRTIO_MMIO_QUEUE_NUM_MAX));
202 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_V1_QUEUE_ALIGN,
203 1.1 jakllsch VIRTIO_PAGE_SIZE);
204 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_V1_QUEUE_PFN,
205 1.4 reinoud addr / VIRTIO_PAGE_SIZE);
206 1.1 jakllsch }
207 1.1 jakllsch
208 1.1 jakllsch static void
209 1.12 thorpej virtio_mmio_v2_setup_queue(struct virtio_softc *vsc, uint16_t idx,
210 1.12 thorpej uint64_t addr)
211 1.12 thorpej {
212 1.12 thorpej struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
213 1.12 thorpej struct virtqueue *vq = &vsc->sc_vqs[idx];
214 1.12 thorpej KASSERT(vq->vq_index == idx);
215 1.12 thorpej
216 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_QUEUE_SEL, idx);
217 1.12 thorpej if (addr == 0) {
218 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_QUEUE_READY, 0);
219 1.12 thorpej virtio_mmio_v2_set_addr(sc, VIRTIO_MMIO_V2_QUEUE_DESC_LOW, 0);
220 1.12 thorpej virtio_mmio_v2_set_addr(sc, VIRTIO_MMIO_V2_QUEUE_AVAIL_LOW, 0);
221 1.12 thorpej virtio_mmio_v2_set_addr(sc, VIRTIO_MMIO_V2_QUEUE_USED_LOW, 0);
222 1.12 thorpej } else {
223 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_QUEUE_NUM,
224 1.12 thorpej virtio_mmio_reg_read(sc, VIRTIO_MMIO_QUEUE_NUM_MAX));
225 1.12 thorpej virtio_mmio_v2_set_addr(sc, VIRTIO_MMIO_V2_QUEUE_DESC_LOW,
226 1.12 thorpej addr);
227 1.12 thorpej virtio_mmio_v2_set_addr(sc, VIRTIO_MMIO_V2_QUEUE_AVAIL_LOW,
228 1.12 thorpej addr + vq->vq_availoffset);
229 1.12 thorpej virtio_mmio_v2_set_addr(sc, VIRTIO_MMIO_V2_QUEUE_USED_LOW,
230 1.12 thorpej addr + vq->vq_usedoffset);
231 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_QUEUE_READY, 1);
232 1.12 thorpej }
233 1.12 thorpej }
234 1.12 thorpej
235 1.12 thorpej static void
236 1.1 jakllsch virtio_mmio_set_status(struct virtio_softc *vsc, int status)
237 1.1 jakllsch {
238 1.1 jakllsch struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
239 1.1 jakllsch int old = 0;
240 1.1 jakllsch
241 1.1 jakllsch if (status != 0)
242 1.12 thorpej old = virtio_mmio_reg_read(sc, VIRTIO_MMIO_STATUS);
243 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_STATUS, status|old);
244 1.1 jakllsch }
245 1.1 jakllsch
246 1.6 reinoud bool
247 1.6 reinoud virtio_mmio_common_probe_present(struct virtio_mmio_softc *sc)
248 1.6 reinoud {
249 1.6 reinoud uint32_t magic;
250 1.6 reinoud
251 1.12 thorpej /* XXX */
252 1.6 reinoud magic = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
253 1.6 reinoud VIRTIO_MMIO_MAGIC_VALUE);
254 1.6 reinoud return (magic == VIRTIO_MMIO_MAGIC);
255 1.6 reinoud }
256 1.6 reinoud
257 1.12 thorpej
258 1.1 jakllsch void
259 1.1 jakllsch virtio_mmio_common_attach(struct virtio_mmio_softc *sc)
260 1.1 jakllsch {
261 1.1 jakllsch struct virtio_softc *vsc = &sc->sc_sc;
262 1.4 reinoud device_t self = vsc->sc_dev;
263 1.1 jakllsch uint32_t id, magic, ver;
264 1.1 jakllsch
265 1.1 jakllsch magic = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
266 1.1 jakllsch VIRTIO_MMIO_MAGIC_VALUE);
267 1.1 jakllsch if (magic != VIRTIO_MMIO_MAGIC) {
268 1.12 thorpej if (magic == le32toh(VIRTIO_MMIO_MAGIC)) {
269 1.12 thorpej sc->sc_le_regs = true;
270 1.12 thorpej } else {
271 1.12 thorpej aprint_error_dev(vsc->sc_dev,
272 1.12 thorpej "wrong magic value 0x%08x; giving up\n", magic);
273 1.12 thorpej return;
274 1.12 thorpej }
275 1.1 jakllsch }
276 1.12 thorpej vsc->sc_bus_endian = READ_ENDIAN;
277 1.12 thorpej vsc->sc_struct_endian = STRUCT_ENDIAN;
278 1.1 jakllsch
279 1.12 thorpej ver = virtio_mmio_reg_read(sc, VIRTIO_MMIO_VERSION);
280 1.12 thorpej switch (ver) {
281 1.12 thorpej case 1:
282 1.12 thorpej /* we could use PAGE_SIZE, but virtio(4) assumes 4KiB for now */
283 1.12 thorpej virtio_mmio_reg_write(sc,
284 1.12 thorpej VIRTIO_MMIO_V1_GUEST_PAGE_SIZE, VIRTIO_PAGE_SIZE);
285 1.12 thorpej vsc->sc_ops = &virtio_mmio_v1_ops;
286 1.12 thorpej break;
287 1.12 thorpej
288 1.12 thorpej case 2:
289 1.12 thorpej vsc->sc_ops = &virtio_mmio_v2_ops;
290 1.12 thorpej break;
291 1.12 thorpej
292 1.12 thorpej default:
293 1.1 jakllsch aprint_error_dev(vsc->sc_dev,
294 1.12 thorpej "unknown version 0x%08x; giving up\n", ver);
295 1.1 jakllsch return;
296 1.1 jakllsch }
297 1.12 thorpej aprint_normal_dev(self, "VirtIO-MMIO v%d\n", ver);
298 1.1 jakllsch
299 1.12 thorpej id = virtio_mmio_reg_read(sc, VIRTIO_MMIO_DEVICE_ID);
300 1.12 thorpej if (id == 0) {
301 1.12 thorpej /* no device connected. */
302 1.1 jakllsch return;
303 1.12 thorpej }
304 1.1 jakllsch
305 1.4 reinoud virtio_print_device_type(self, id, ver);
306 1.4 reinoud
307 1.4 reinoud /* set up our device config tag */
308 1.4 reinoud vsc->sc_devcfg_iosize = sc->sc_iosize - VIRTIO_MMIO_CONFIG;
309 1.4 reinoud vsc->sc_devcfg_iot = sc->sc_iot;
310 1.4 reinoud if (bus_space_subregion(sc->sc_iot, sc->sc_ioh,
311 1.4 reinoud VIRTIO_MMIO_CONFIG, vsc->sc_devcfg_iosize,
312 1.4 reinoud &vsc->sc_devcfg_ioh)) {
313 1.4 reinoud aprint_error_dev(self, "can't map config i/o space\n");
314 1.4 reinoud return;
315 1.4 reinoud }
316 1.1 jakllsch
317 1.1 jakllsch virtio_device_reset(vsc);
318 1.1 jakllsch virtio_mmio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_ACK);
319 1.1 jakllsch virtio_mmio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER);
320 1.1 jakllsch
321 1.1 jakllsch /* XXX: use softc as aux... */
322 1.1 jakllsch vsc->sc_childdevid = id;
323 1.1 jakllsch vsc->sc_child = NULL;
324 1.1 jakllsch }
325 1.1 jakllsch
326 1.1 jakllsch int
327 1.1 jakllsch virtio_mmio_common_detach(struct virtio_mmio_softc *sc, int flags)
328 1.1 jakllsch {
329 1.1 jakllsch struct virtio_softc *vsc = &sc->sc_sc;
330 1.1 jakllsch int r;
331 1.1 jakllsch
332 1.9 yamaguch r = config_detach_children(vsc->sc_dev, flags);
333 1.8 yamaguch if (r != 0)
334 1.8 yamaguch return r;
335 1.8 yamaguch
336 1.10 yamaguch KASSERT(vsc->sc_child == NULL);
337 1.1 jakllsch KASSERT(vsc->sc_vqs == NULL);
338 1.1 jakllsch KASSERT(sc->sc_ih == NULL);
339 1.1 jakllsch
340 1.1 jakllsch if (sc->sc_iosize) {
341 1.1 jakllsch bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize);
342 1.1 jakllsch sc->sc_iosize = 0;
343 1.1 jakllsch }
344 1.1 jakllsch
345 1.1 jakllsch return 0;
346 1.1 jakllsch }
347 1.1 jakllsch
348 1.1 jakllsch /*
349 1.1 jakllsch * Feature negotiation.
350 1.1 jakllsch */
351 1.4 reinoud static void
352 1.4 reinoud virtio_mmio_negotiate_features(struct virtio_softc *vsc, uint64_t
353 1.12 thorpej driver_features)
354 1.1 jakllsch {
355 1.1 jakllsch struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
356 1.1 jakllsch uint32_t r;
357 1.1 jakllsch
358 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_DEVICE_FEATURES_SEL, 0);
359 1.12 thorpej r = virtio_mmio_reg_read(sc, VIRTIO_MMIO_DEVICE_FEATURES);
360 1.12 thorpej r &= driver_features;
361 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_DRIVER_FEATURES_SEL, 0);
362 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_DRIVER_FEATURES, r);
363 1.4 reinoud
364 1.4 reinoud vsc->sc_active_features = r;
365 1.1 jakllsch }
366 1.1 jakllsch
367 1.1 jakllsch /*
368 1.1 jakllsch * Interrupt handler.
369 1.1 jakllsch */
370 1.1 jakllsch int
371 1.1 jakllsch virtio_mmio_intr(void *arg)
372 1.1 jakllsch {
373 1.1 jakllsch struct virtio_mmio_softc *sc = arg;
374 1.1 jakllsch struct virtio_softc *vsc = &sc->sc_sc;
375 1.1 jakllsch int isr, r = 0;
376 1.1 jakllsch
377 1.1 jakllsch /* check and ack the interrupt */
378 1.12 thorpej isr = virtio_mmio_reg_read(sc, VIRTIO_MMIO_INTERRUPT_STATUS);
379 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_INTERRUPT_ACK, isr);
380 1.1 jakllsch if ((isr & VIRTIO_MMIO_INT_CONFIG) &&
381 1.1 jakllsch (vsc->sc_config_change != NULL))
382 1.1 jakllsch r = (vsc->sc_config_change)(vsc);
383 1.1 jakllsch if ((isr & VIRTIO_MMIO_INT_VRING) &&
384 1.1 jakllsch (vsc->sc_intrhand != NULL)) {
385 1.1 jakllsch if (vsc->sc_soft_ih != NULL)
386 1.1 jakllsch softint_schedule(vsc->sc_soft_ih);
387 1.1 jakllsch else
388 1.1 jakllsch r |= (vsc->sc_intrhand)(vsc);
389 1.1 jakllsch }
390 1.1 jakllsch
391 1.1 jakllsch return r;
392 1.1 jakllsch }
393 1.1 jakllsch
394 1.1 jakllsch static void
395 1.1 jakllsch virtio_mmio_kick(struct virtio_softc *vsc, uint16_t idx)
396 1.1 jakllsch {
397 1.1 jakllsch struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
398 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_QUEUE_NOTIFY, idx);
399 1.1 jakllsch }
400 1.1 jakllsch
401 1.1 jakllsch static int
402 1.7 yamaguch virtio_mmio_alloc_interrupts(struct virtio_softc *vsc)
403 1.1 jakllsch {
404 1.1 jakllsch struct virtio_mmio_softc * const sc = (struct virtio_mmio_softc *)vsc;
405 1.1 jakllsch
406 1.7 yamaguch return sc->sc_alloc_interrupts(sc);
407 1.1 jakllsch }
408 1.1 jakllsch
409 1.1 jakllsch static void
410 1.1 jakllsch virtio_mmio_free_interrupts(struct virtio_softc *vsc)
411 1.1 jakllsch {
412 1.1 jakllsch struct virtio_mmio_softc * const sc = (struct virtio_mmio_softc *)vsc;
413 1.1 jakllsch
414 1.1 jakllsch sc->sc_free_interrupts(sc);
415 1.1 jakllsch }
416 1.7 yamaguch
417 1.7 yamaguch static int
418 1.7 yamaguch virtio_mmio_setup_interrupts(struct virtio_softc *vsc __unused,
419 1.7 yamaguch int reinit __unused)
420 1.7 yamaguch {
421 1.7 yamaguch
422 1.7 yamaguch return 0;
423 1.7 yamaguch }
424