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