xref: /netbsd-src/sys/dev/virtio/virtio_mmio.c (revision 2cd310f610b7cfa27083b8fb09464f39df3a0163)
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