1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2011, Bryan Venteicher <bryanv@FreeBSD.org>
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 unmodified, this list of conditions, and the following
12 *    disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/* Driver for the legacy VirtIO PCI interface. */
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/bus.h>
34#include <sys/lock.h>
35#include <sys/kernel.h>
36#include <sys/module.h>
37#include <sys/endian.h>
38
39#include <machine/bus.h>
40#include <machine/resource.h>
41#include <sys/bus.h>
42#include <sys/rman.h>
43
44#include <dev/pci/pcivar.h>
45#include <dev/pci/pcireg.h>
46
47#include <dev/virtio/virtio.h>
48#include <dev/virtio/virtqueue.h>
49#include <dev/virtio/pci/virtio_pci.h>
50#include <dev/virtio/pci/virtio_pci_legacy_var.h>
51
52#include "virtio_bus_if.h"
53#include "virtio_pci_if.h"
54#include "virtio_if.h"
55
56struct vtpci_legacy_softc {
57	device_t			 vtpci_dev;
58	struct vtpci_common		 vtpci_common;
59	int				 vtpci_res_type;
60	struct resource			*vtpci_res;
61	struct resource			*vtpci_msix_table_res;
62	struct resource			*vtpci_msix_pba_res;
63};
64
65static int	vtpci_legacy_probe(device_t);
66static int	vtpci_legacy_attach(device_t);
67static int	vtpci_legacy_detach(device_t);
68static int	vtpci_legacy_suspend(device_t);
69static int	vtpci_legacy_resume(device_t);
70static int	vtpci_legacy_shutdown(device_t);
71
72static void	vtpci_legacy_driver_added(device_t, driver_t *);
73static void	vtpci_legacy_child_detached(device_t, device_t);
74static int	vtpci_legacy_read_ivar(device_t, device_t, int, uintptr_t *);
75static int	vtpci_legacy_write_ivar(device_t, device_t, int, uintptr_t);
76
77static uint8_t	vtpci_legacy_read_isr(device_t);
78static uint16_t	vtpci_legacy_get_vq_size(device_t, int);
79static bus_size_t vtpci_legacy_get_vq_notify_off(device_t, int);
80static void	vtpci_legacy_set_vq(device_t, struct virtqueue *);
81static void	vtpci_legacy_disable_vq(device_t, int);
82static int	vtpci_legacy_register_cfg_msix(device_t,
83		    struct vtpci_interrupt *);
84static int	vtpci_legacy_register_vq_msix(device_t, int idx,
85		    struct vtpci_interrupt *);
86
87static uint64_t	vtpci_legacy_negotiate_features(device_t, uint64_t);
88static bool	vtpci_legacy_with_feature(device_t, uint64_t);
89static int	vtpci_legacy_alloc_virtqueues(device_t, int,
90		    struct vq_alloc_info *);
91static int	vtpci_legacy_setup_interrupts(device_t, enum intr_type);
92static void	vtpci_legacy_stop(device_t);
93static int	vtpci_legacy_reinit(device_t, uint64_t);
94static void	vtpci_legacy_reinit_complete(device_t);
95static void	vtpci_legacy_notify_vq(device_t, uint16_t, bus_size_t);
96static void	vtpci_legacy_read_dev_config(device_t, bus_size_t, void *, int);
97static void	vtpci_legacy_write_dev_config(device_t, bus_size_t, const void *, int);
98
99static bool	vtpci_legacy_setup_msix(struct vtpci_legacy_softc *sc);
100static void	vtpci_legacy_teardown_msix(struct vtpci_legacy_softc *sc);
101static int	vtpci_legacy_alloc_resources(struct vtpci_legacy_softc *);
102static void	vtpci_legacy_free_resources(struct vtpci_legacy_softc *);
103
104static void	vtpci_legacy_probe_and_attach_child(struct vtpci_legacy_softc *);
105
106static uint8_t	vtpci_legacy_get_status(struct vtpci_legacy_softc *);
107static void	vtpci_legacy_set_status(struct vtpci_legacy_softc *, uint8_t);
108static void	vtpci_legacy_select_virtqueue(struct vtpci_legacy_softc *, int);
109static void	vtpci_legacy_reset(struct vtpci_legacy_softc *);
110
111#define VIRTIO_PCI_LEGACY_CONFIG(_sc) \
112    VIRTIO_PCI_CONFIG_OFF(vtpci_is_msix_enabled(&(_sc)->vtpci_common))
113
114#define vtpci_legacy_read_config_1(sc, o) \
115    bus_read_1((sc)->vtpci_res, (o))
116#define vtpci_legacy_write_config_1(sc, o, v) \
117    bus_write_1((sc)->vtpci_res, (o), (v))
118/*
119 * VirtIO specifies that PCI Configuration area is guest endian. However,
120 * since PCI devices are inherently little-endian, on big-endian systems
121 * the bus layer transparently converts it to BE. For virtio-legacy, this
122 * conversion is undesired, so an extra byte swap is required to fix it.
123 */
124#define vtpci_legacy_read_config_2(sc, o) \
125    le16toh(bus_read_2((sc)->vtpci_res, (o)))
126#define vtpci_legacy_read_config_4(sc, o) \
127    le32toh(bus_read_4((sc)->vtpci_res, (o)))
128#define vtpci_legacy_write_config_2(sc, o, v) \
129    bus_write_2((sc)->vtpci_res, (o), (htole16(v)))
130#define vtpci_legacy_write_config_4(sc, o, v) \
131    bus_write_4((sc)->vtpci_res, (o), (htole32(v)))
132/* PCI Header LE. On BE systems the bus layer takes care of byte swapping. */
133#define vtpci_legacy_read_header_2(sc, o) \
134    bus_read_2((sc)->vtpci_res, (o))
135#define vtpci_legacy_read_header_4(sc, o) \
136    bus_read_4((sc)->vtpci_res, (o))
137#define vtpci_legacy_write_header_2(sc, o, v) \
138    bus_write_2((sc)->vtpci_res, (o), (v))
139#define vtpci_legacy_write_header_4(sc, o, v) \
140    bus_write_4((sc)->vtpci_res, (o), (v))
141
142static device_method_t vtpci_legacy_methods[] = {
143	/* Device interface. */
144	DEVMETHOD(device_probe,			  vtpci_legacy_probe),
145	DEVMETHOD(device_attach,		  vtpci_legacy_attach),
146	DEVMETHOD(device_detach,		  vtpci_legacy_detach),
147	DEVMETHOD(device_suspend,		  vtpci_legacy_suspend),
148	DEVMETHOD(device_resume,		  vtpci_legacy_resume),
149	DEVMETHOD(device_shutdown,		  vtpci_legacy_shutdown),
150
151	/* Bus interface. */
152	DEVMETHOD(bus_driver_added,		  vtpci_legacy_driver_added),
153	DEVMETHOD(bus_child_detached,		  vtpci_legacy_child_detached),
154	DEVMETHOD(bus_child_pnpinfo,		  virtio_child_pnpinfo),
155	DEVMETHOD(bus_read_ivar,		  vtpci_legacy_read_ivar),
156	DEVMETHOD(bus_write_ivar,		  vtpci_legacy_write_ivar),
157
158	/* VirtIO PCI interface. */
159	DEVMETHOD(virtio_pci_read_isr,		 vtpci_legacy_read_isr),
160	DEVMETHOD(virtio_pci_get_vq_size,	 vtpci_legacy_get_vq_size),
161	DEVMETHOD(virtio_pci_get_vq_notify_off,	 vtpci_legacy_get_vq_notify_off),
162	DEVMETHOD(virtio_pci_set_vq,		 vtpci_legacy_set_vq),
163	DEVMETHOD(virtio_pci_disable_vq,	 vtpci_legacy_disable_vq),
164	DEVMETHOD(virtio_pci_register_cfg_msix,  vtpci_legacy_register_cfg_msix),
165	DEVMETHOD(virtio_pci_register_vq_msix,	 vtpci_legacy_register_vq_msix),
166
167	/* VirtIO bus interface. */
168	DEVMETHOD(virtio_bus_negotiate_features,  vtpci_legacy_negotiate_features),
169	DEVMETHOD(virtio_bus_with_feature,	  vtpci_legacy_with_feature),
170	DEVMETHOD(virtio_bus_alloc_virtqueues,	  vtpci_legacy_alloc_virtqueues),
171	DEVMETHOD(virtio_bus_setup_intr,	  vtpci_legacy_setup_interrupts),
172	DEVMETHOD(virtio_bus_stop,		  vtpci_legacy_stop),
173	DEVMETHOD(virtio_bus_reinit,		  vtpci_legacy_reinit),
174	DEVMETHOD(virtio_bus_reinit_complete,	  vtpci_legacy_reinit_complete),
175	DEVMETHOD(virtio_bus_notify_vq,		  vtpci_legacy_notify_vq),
176	DEVMETHOD(virtio_bus_read_device_config,  vtpci_legacy_read_dev_config),
177	DEVMETHOD(virtio_bus_write_device_config, vtpci_legacy_write_dev_config),
178
179	DEVMETHOD_END
180};
181
182static driver_t vtpci_legacy_driver = {
183	.name = "virtio_pci",
184	.methods = vtpci_legacy_methods,
185	.size = sizeof(struct vtpci_legacy_softc)
186};
187
188DRIVER_MODULE(virtio_pci_legacy, pci, vtpci_legacy_driver, 0, 0);
189
190static int
191vtpci_legacy_probe(device_t dev)
192{
193	const char *name;
194
195	if (pci_get_vendor(dev) != VIRTIO_PCI_VENDORID)
196		return (ENXIO);
197
198	if (pci_get_device(dev) < VIRTIO_PCI_DEVICEID_MIN ||
199	    pci_get_device(dev) > VIRTIO_PCI_DEVICEID_LEGACY_MAX)
200		return (ENXIO);
201
202	if (pci_get_revid(dev) != VIRTIO_PCI_ABI_VERSION)
203		return (ENXIO);
204
205	name = virtio_device_name(pci_get_subdevice(dev));
206	if (name == NULL)
207		name = "Unknown";
208
209	device_set_descf(dev, "VirtIO PCI (legacy) %s adapter", name);
210
211	/* Prefer transitional modern VirtIO PCI. */
212	return (BUS_PROBE_LOW_PRIORITY);
213}
214
215static int
216vtpci_legacy_attach(device_t dev)
217{
218	struct vtpci_legacy_softc *sc;
219	int error;
220
221	sc = device_get_softc(dev);
222	sc->vtpci_dev = dev;
223	vtpci_init(&sc->vtpci_common, dev, false);
224
225	error = vtpci_legacy_alloc_resources(sc);
226	if (error) {
227		device_printf(dev, "cannot map I/O space nor memory space\n");
228		return (error);
229	}
230
231	if (vtpci_is_msix_available(&sc->vtpci_common) &&
232	    !vtpci_legacy_setup_msix(sc)) {
233		device_printf(dev, "cannot setup MSI-x resources\n");
234		error = ENXIO;
235		goto fail;
236	}
237
238	vtpci_legacy_reset(sc);
239
240	/* Tell the host we've noticed this device. */
241	vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_ACK);
242
243	error = vtpci_add_child(&sc->vtpci_common);
244	if (error)
245		goto fail;
246
247	vtpci_legacy_probe_and_attach_child(sc);
248
249	return (0);
250
251fail:
252	vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_FAILED);
253	vtpci_legacy_detach(dev);
254
255	return (error);
256}
257
258static int
259vtpci_legacy_detach(device_t dev)
260{
261	struct vtpci_legacy_softc *sc;
262	int error;
263
264	sc = device_get_softc(dev);
265
266	error = vtpci_delete_child(&sc->vtpci_common);
267	if (error)
268		return (error);
269
270	vtpci_legacy_reset(sc);
271	vtpci_legacy_teardown_msix(sc);
272	vtpci_legacy_free_resources(sc);
273
274	return (0);
275}
276
277static int
278vtpci_legacy_suspend(device_t dev)
279{
280	return (bus_generic_suspend(dev));
281}
282
283static int
284vtpci_legacy_resume(device_t dev)
285{
286	return (bus_generic_resume(dev));
287}
288
289static int
290vtpci_legacy_shutdown(device_t dev)
291{
292	(void) bus_generic_shutdown(dev);
293	/* Forcibly stop the host device. */
294	vtpci_legacy_stop(dev);
295
296	return (0);
297}
298
299static void
300vtpci_legacy_driver_added(device_t dev, driver_t *driver)
301{
302	vtpci_legacy_probe_and_attach_child(device_get_softc(dev));
303}
304
305static void
306vtpci_legacy_child_detached(device_t dev, device_t child)
307{
308	struct vtpci_legacy_softc *sc;
309
310	sc = device_get_softc(dev);
311
312	vtpci_legacy_reset(sc);
313	vtpci_child_detached(&sc->vtpci_common);
314
315	/* After the reset, retell the host we've noticed this device. */
316	vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_ACK);
317}
318
319static int
320vtpci_legacy_read_ivar(device_t dev, device_t child, int index,
321    uintptr_t *result)
322{
323	struct vtpci_legacy_softc *sc;
324	struct vtpci_common *cn;
325
326	sc = device_get_softc(dev);
327	cn = &sc->vtpci_common;
328
329	if (vtpci_child_device(cn) != child)
330		return (ENOENT);
331
332	switch (index) {
333	case VIRTIO_IVAR_DEVTYPE:
334		*result = pci_get_subdevice(dev);
335		break;
336	default:
337		return (vtpci_read_ivar(cn, index, result));
338	}
339
340	return (0);
341}
342
343static int
344vtpci_legacy_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
345{
346	struct vtpci_legacy_softc *sc;
347	struct vtpci_common *cn;
348
349	sc = device_get_softc(dev);
350	cn = &sc->vtpci_common;
351
352	if (vtpci_child_device(cn) != child)
353		return (ENOENT);
354
355	switch (index) {
356	default:
357		return (vtpci_write_ivar(cn, index, value));
358	}
359
360	return (0);
361}
362
363static uint64_t
364vtpci_legacy_negotiate_features(device_t dev, uint64_t child_features)
365{
366	struct vtpci_legacy_softc *sc;
367	uint64_t host_features, features;
368
369	sc = device_get_softc(dev);
370	host_features = vtpci_legacy_read_header_4(sc, VIRTIO_PCI_HOST_FEATURES);
371
372	features = vtpci_negotiate_features(&sc->vtpci_common,
373	    child_features, host_features);
374	vtpci_legacy_write_header_4(sc, VIRTIO_PCI_GUEST_FEATURES, features);
375
376	return (features);
377}
378
379static bool
380vtpci_legacy_with_feature(device_t dev, uint64_t feature)
381{
382	struct vtpci_legacy_softc *sc;
383
384	sc = device_get_softc(dev);
385
386	return (vtpci_with_feature(&sc->vtpci_common, feature));
387}
388
389static int
390vtpci_legacy_alloc_virtqueues(device_t dev, int nvqs,
391    struct vq_alloc_info *vq_info)
392{
393	struct vtpci_legacy_softc *sc;
394	struct vtpci_common *cn;
395
396	sc = device_get_softc(dev);
397	cn = &sc->vtpci_common;
398
399	return (vtpci_alloc_virtqueues(cn, nvqs, vq_info));
400}
401
402static int
403vtpci_legacy_setup_interrupts(device_t dev, enum intr_type type)
404{
405	struct vtpci_legacy_softc *sc;
406
407	sc = device_get_softc(dev);
408
409	return (vtpci_setup_interrupts(&sc->vtpci_common, type));
410}
411
412static void
413vtpci_legacy_stop(device_t dev)
414{
415	vtpci_legacy_reset(device_get_softc(dev));
416}
417
418static int
419vtpci_legacy_reinit(device_t dev, uint64_t features)
420{
421	struct vtpci_legacy_softc *sc;
422	struct vtpci_common *cn;
423	int error;
424
425	sc = device_get_softc(dev);
426	cn = &sc->vtpci_common;
427
428	/*
429	 * Redrive the device initialization. This is a bit of an abuse of
430	 * the specification, but VirtualBox, QEMU/KVM, and BHyVe seem to
431	 * play nice.
432	 *
433	 * We do not allow the host device to change from what was originally
434	 * negotiated beyond what the guest driver changed. MSIX state should
435	 * not change, number of virtqueues and their size remain the same, etc.
436	 * This will need to be rethought when we want to support migration.
437	 */
438
439	if (vtpci_legacy_get_status(sc) != VIRTIO_CONFIG_STATUS_RESET)
440		vtpci_legacy_stop(dev);
441
442	/*
443	 * Quickly drive the status through ACK and DRIVER. The device does
444	 * not become usable again until DRIVER_OK in reinit complete.
445	 */
446	vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_ACK);
447	vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_DRIVER);
448
449	vtpci_legacy_negotiate_features(dev, features);
450
451	error = vtpci_reinit(cn);
452	if (error)
453		return (error);
454
455	return (0);
456}
457
458static void
459vtpci_legacy_reinit_complete(device_t dev)
460{
461	struct vtpci_legacy_softc *sc;
462
463	sc = device_get_softc(dev);
464
465	vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_DRIVER_OK);
466}
467
468static void
469vtpci_legacy_notify_vq(device_t dev, uint16_t queue, bus_size_t offset)
470{
471	struct vtpci_legacy_softc *sc;
472
473	sc = device_get_softc(dev);
474	MPASS(offset == VIRTIO_PCI_QUEUE_NOTIFY);
475
476	vtpci_legacy_write_header_2(sc, offset, queue);
477}
478
479static uint8_t
480vtpci_legacy_get_status(struct vtpci_legacy_softc *sc)
481{
482	return (vtpci_legacy_read_config_1(sc, VIRTIO_PCI_STATUS));
483}
484
485static void
486vtpci_legacy_set_status(struct vtpci_legacy_softc *sc, uint8_t status)
487{
488	if (status != VIRTIO_CONFIG_STATUS_RESET)
489		status |= vtpci_legacy_get_status(sc);
490
491	vtpci_legacy_write_config_1(sc, VIRTIO_PCI_STATUS, status);
492}
493
494static void
495vtpci_legacy_read_dev_config(device_t dev, bus_size_t offset,
496    void *dst, int length)
497{
498	struct vtpci_legacy_softc *sc;
499	bus_size_t off;
500	uint8_t *d;
501	int i;
502
503	sc = device_get_softc(dev);
504	off = VIRTIO_PCI_LEGACY_CONFIG(sc) + offset;
505
506	d = dst;
507	for (i = 0; i < length; i++) {
508		d[i] = vtpci_legacy_read_config_1(sc, off + i);
509	}
510}
511
512static void
513vtpci_legacy_write_dev_config(device_t dev, bus_size_t offset,
514    const void *src, int length)
515{
516	struct vtpci_legacy_softc *sc;
517	bus_size_t off;
518	const uint8_t *s;
519	int i;
520
521	sc = device_get_softc(dev);
522	off = VIRTIO_PCI_LEGACY_CONFIG(sc) + offset;
523
524	s = src;
525	for (i = 0; i < length; i++) {
526		vtpci_legacy_write_config_1(sc, off + i, s[i]);
527	}
528}
529
530static bool
531vtpci_legacy_setup_msix(struct vtpci_legacy_softc *sc)
532{
533	device_t dev;
534	int rid, table_rid;
535
536	dev = sc->vtpci_dev;
537
538	rid = table_rid = pci_msix_table_bar(dev);
539	if (rid != PCIR_BAR(0)) {
540		sc->vtpci_msix_table_res = bus_alloc_resource_any(
541		    dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
542		if (sc->vtpci_msix_table_res == NULL)
543			return (false);
544	}
545
546	rid = pci_msix_pba_bar(dev);
547	if (rid != table_rid && rid != PCIR_BAR(0)) {
548		sc->vtpci_msix_pba_res = bus_alloc_resource_any(
549		    dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
550		if (sc->vtpci_msix_pba_res == NULL)
551			return (false);
552	}
553
554	return (true);
555}
556
557static void
558vtpci_legacy_teardown_msix(struct vtpci_legacy_softc *sc)
559{
560	device_t dev;
561
562	dev = sc->vtpci_dev;
563
564	if (sc->vtpci_msix_pba_res != NULL) {
565		bus_release_resource(dev, SYS_RES_MEMORY,
566		    rman_get_rid(sc->vtpci_msix_pba_res),
567		    sc->vtpci_msix_pba_res);
568		sc->vtpci_msix_pba_res = NULL;
569	}
570	if (sc->vtpci_msix_table_res != NULL) {
571		bus_release_resource(dev, SYS_RES_MEMORY,
572		    rman_get_rid(sc->vtpci_msix_table_res),
573		    sc->vtpci_msix_table_res);
574		sc->vtpci_msix_table_res = NULL;
575	}
576}
577
578static int
579vtpci_legacy_alloc_resources(struct vtpci_legacy_softc *sc)
580{
581	const int res_types[] = { SYS_RES_IOPORT, SYS_RES_MEMORY };
582	device_t dev;
583	int rid, i;
584
585	dev = sc->vtpci_dev;
586
587	/*
588	 * Most hypervisors export the common configuration structure in IO
589	 * space, but some use memory space; try both.
590	 */
591	for (i = 0; nitems(res_types); i++) {
592		rid = PCIR_BAR(0);
593		sc->vtpci_res_type = res_types[i];
594		sc->vtpci_res = bus_alloc_resource_any(dev, res_types[i], &rid,
595		    RF_ACTIVE);
596		if (sc->vtpci_res != NULL)
597			break;
598	}
599	if (sc->vtpci_res == NULL)
600		return (ENXIO);
601
602	return (0);
603}
604
605static void
606vtpci_legacy_free_resources(struct vtpci_legacy_softc *sc)
607{
608	device_t dev;
609
610	dev = sc->vtpci_dev;
611
612	if (sc->vtpci_res != NULL) {
613		bus_release_resource(dev, sc->vtpci_res_type, PCIR_BAR(0),
614		    sc->vtpci_res);
615		sc->vtpci_res = NULL;
616	}
617}
618
619static void
620vtpci_legacy_probe_and_attach_child(struct vtpci_legacy_softc *sc)
621{
622	device_t dev, child;
623
624	dev = sc->vtpci_dev;
625	child = vtpci_child_device(&sc->vtpci_common);
626
627	if (child == NULL || device_get_state(child) != DS_NOTPRESENT)
628		return;
629
630	if (device_probe(child) != 0)
631		return;
632
633	vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_DRIVER);
634
635	if (device_attach(child) != 0) {
636		vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_FAILED);
637		/* Reset status for future attempt. */
638		vtpci_legacy_child_detached(dev, child);
639	} else {
640		vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_DRIVER_OK);
641		VIRTIO_ATTACH_COMPLETED(child);
642	}
643}
644
645static int
646vtpci_legacy_register_msix(struct vtpci_legacy_softc *sc, int offset,
647    struct vtpci_interrupt *intr)
648{
649	uint16_t vector;
650
651	if (intr != NULL) {
652		/* Map from guest rid to host vector. */
653		vector = intr->vti_rid - 1;
654	} else
655		vector = VIRTIO_MSI_NO_VECTOR;
656
657	vtpci_legacy_write_header_2(sc, offset, vector);
658	return (vtpci_legacy_read_header_2(sc, offset) == vector ? 0 : ENODEV);
659}
660
661static int
662vtpci_legacy_register_cfg_msix(device_t dev, struct vtpci_interrupt *intr)
663{
664	struct vtpci_legacy_softc *sc;
665	int error;
666
667	sc = device_get_softc(dev);
668
669	error = vtpci_legacy_register_msix(sc, VIRTIO_MSI_CONFIG_VECTOR, intr);
670	if (error) {
671		device_printf(dev,
672		    "unable to register config MSIX interrupt\n");
673		return (error);
674	}
675
676	return (0);
677}
678
679static int
680vtpci_legacy_register_vq_msix(device_t dev, int idx,
681    struct vtpci_interrupt *intr)
682{
683	struct vtpci_legacy_softc *sc;
684	int error;
685
686	sc = device_get_softc(dev);
687
688	vtpci_legacy_select_virtqueue(sc, idx);
689	error = vtpci_legacy_register_msix(sc, VIRTIO_MSI_QUEUE_VECTOR, intr);
690	if (error) {
691		device_printf(dev,
692		    "unable to register virtqueue MSIX interrupt\n");
693		return (error);
694	}
695
696	return (0);
697}
698
699static void
700vtpci_legacy_reset(struct vtpci_legacy_softc *sc)
701{
702	/*
703	 * Setting the status to RESET sets the host device to the
704	 * original, uninitialized state.
705	 */
706	vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_RESET);
707	(void) vtpci_legacy_get_status(sc);
708}
709
710static void
711vtpci_legacy_select_virtqueue(struct vtpci_legacy_softc *sc, int idx)
712{
713	vtpci_legacy_write_header_2(sc, VIRTIO_PCI_QUEUE_SEL, idx);
714}
715
716static uint8_t
717vtpci_legacy_read_isr(device_t dev)
718{
719	struct vtpci_legacy_softc *sc;
720
721	sc = device_get_softc(dev);
722
723	return (vtpci_legacy_read_config_1(sc, VIRTIO_PCI_ISR));
724}
725
726static uint16_t
727vtpci_legacy_get_vq_size(device_t dev, int idx)
728{
729	struct vtpci_legacy_softc *sc;
730
731	sc = device_get_softc(dev);
732
733	vtpci_legacy_select_virtqueue(sc, idx);
734	return (vtpci_legacy_read_header_2(sc, VIRTIO_PCI_QUEUE_NUM));
735}
736
737static bus_size_t
738vtpci_legacy_get_vq_notify_off(device_t dev, int idx)
739{
740	return (VIRTIO_PCI_QUEUE_NOTIFY);
741}
742
743static void
744vtpci_legacy_set_vq(device_t dev, struct virtqueue *vq)
745{
746	struct vtpci_legacy_softc *sc;
747
748	sc = device_get_softc(dev);
749
750	vtpci_legacy_select_virtqueue(sc, virtqueue_index(vq));
751	vtpci_legacy_write_header_4(sc, VIRTIO_PCI_QUEUE_PFN,
752	    virtqueue_paddr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
753}
754
755static void
756vtpci_legacy_disable_vq(device_t dev, int idx)
757{
758	struct vtpci_legacy_softc *sc;
759
760	sc = device_get_softc(dev);
761
762	vtpci_legacy_select_virtqueue(sc, idx);
763	vtpci_legacy_write_header_4(sc, VIRTIO_PCI_QUEUE_PFN, 0);
764}
765