Deleted Added
full compact
virtio_pci.c (234270) virtio_pci.c (238360)
1/*-
2 * Copyright (c) 2011, Bryan Venteicher <bryanv@daemoninthecloset.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 13 unchanged lines hidden (view full) ---

22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27/* Driver for the VirtIO PCI interface. */
28
29#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2011, Bryan Venteicher <bryanv@daemoninthecloset.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 13 unchanged lines hidden (view full) ---

22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27/* Driver for the VirtIO PCI interface. */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: head/sys/dev/virtio/pci/virtio_pci.c 234270 2012-04-14 05:48:04Z grehan $");
30__FBSDID("$FreeBSD: head/sys/dev/virtio/pci/virtio_pci.c 238360 2012-07-11 02:57:19Z grehan $");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/bus.h>
35#include <sys/kernel.h>
36#include <sys/module.h>
37#include <sys/malloc.h>
38

--- 13 unchanged lines hidden (view full) ---

52#include "virtio_if.h"
53
54struct vtpci_softc {
55 device_t vtpci_dev;
56 struct resource *vtpci_res;
57 struct resource *vtpci_msix_res;
58 uint64_t vtpci_features;
59 uint32_t vtpci_flags;
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/bus.h>
35#include <sys/kernel.h>
36#include <sys/module.h>
37#include <sys/malloc.h>
38

--- 13 unchanged lines hidden (view full) ---

52#include "virtio_if.h"
53
54struct vtpci_softc {
55 device_t vtpci_dev;
56 struct resource *vtpci_res;
57 struct resource *vtpci_msix_res;
58 uint64_t vtpci_features;
59 uint32_t vtpci_flags;
60#define VIRTIO_PCI_FLAG_NO_MSI 0x0001
61#define VIRTIO_PCI_FLAG_MSI 0x0002
62#define VIRTIO_PCI_FLAG_NO_MSIX 0x0010
63#define VIRTIO_PCI_FLAG_MSIX 0x0020
64#define VIRTIO_PCI_FLAG_SHARED_MSIX 0x0040
60#define VTPCI_FLAG_NO_MSI 0x0001
61#define VTPCI_FLAG_NO_MSIX 0x0002
62#define VTPCI_FLAG_LEGACY 0x1000
63#define VTPCI_FLAG_MSI 0x2000
64#define VTPCI_FLAG_MSIX 0x4000
65#define VTPCI_FLAG_SHARED_MSIX 0x8000
66#define VTPCI_FLAG_ITYPE_MASK 0xF000
65
67
68 /* This "bus" will only ever have one child. */
66 device_t vtpci_child_dev;
67 struct virtio_feature_desc *vtpci_child_feat_desc;
68
69 /*
70 * Ideally, each virtqueue that the driver provides a callback for
71 * will receive its own MSIX vector. If there are not sufficient
72 * vectors available, we will then attempt to have all the VQs
73 * share one vector. Note that when using MSIX, the configuration
74 * changed notifications must be on their own vector.
75 *
76 * If MSIX is not available, we will attempt to have the whole
77 * device share one MSI vector, and then, finally, one legacy
78 * interrupt.
79 */
80 int vtpci_nvqs;
81 struct vtpci_virtqueue {
82 struct virtqueue *vq;
69 device_t vtpci_child_dev;
70 struct virtio_feature_desc *vtpci_child_feat_desc;
71
72 /*
73 * Ideally, each virtqueue that the driver provides a callback for
74 * will receive its own MSIX vector. If there are not sufficient
75 * vectors available, we will then attempt to have all the VQs
76 * share one vector. Note that when using MSIX, the configuration
77 * changed notifications must be on their own vector.
78 *
79 * If MSIX is not available, we will attempt to have the whole
80 * device share one MSI vector, and then, finally, one legacy
81 * interrupt.
82 */
83 int vtpci_nvqs;
84 struct vtpci_virtqueue {
85 struct virtqueue *vq;
83
86 /* Device did not provide a callback for this virtqueue. */
87 int no_intr;
84 /* Index into vtpci_intr_res[] below. Unused, then -1. */
85 int ires_idx;
86 } vtpci_vqx[VIRTIO_MAX_VIRTQUEUES];
87
88 /*
89 * When using MSIX interrupts, the first element of vtpci_intr_res[]
90 * is always the configuration changed notifications. The remaining
91 * element(s) are used for the virtqueues.

--- 33 unchanged lines hidden (view full) ---

125static void vtpci_set_status(device_t, uint8_t);
126static void vtpci_read_dev_config(device_t, bus_size_t, void *, int);
127static void vtpci_write_dev_config(device_t, bus_size_t, void *, int);
128
129static void vtpci_describe_features(struct vtpci_softc *, const char *,
130 uint64_t);
131static void vtpci_probe_and_attach_child(struct vtpci_softc *);
132
88 /* Index into vtpci_intr_res[] below. Unused, then -1. */
89 int ires_idx;
90 } vtpci_vqx[VIRTIO_MAX_VIRTQUEUES];
91
92 /*
93 * When using MSIX interrupts, the first element of vtpci_intr_res[]
94 * is always the configuration changed notifications. The remaining
95 * element(s) are used for the virtqueues.

--- 33 unchanged lines hidden (view full) ---

129static void vtpci_set_status(device_t, uint8_t);
130static void vtpci_read_dev_config(device_t, bus_size_t, void *, int);
131static void vtpci_write_dev_config(device_t, bus_size_t, void *, int);
132
133static void vtpci_describe_features(struct vtpci_softc *, const char *,
134 uint64_t);
135static void vtpci_probe_and_attach_child(struct vtpci_softc *);
136
133static int vtpci_alloc_interrupts(struct vtpci_softc *, int, int,
134 struct vq_alloc_info *);
135static int vtpci_alloc_intr_resources(struct vtpci_softc *, int,
136 struct vq_alloc_info *);
137static int vtpci_alloc_msi(struct vtpci_softc *);
138static int vtpci_alloc_msix(struct vtpci_softc *, int);
137static int vtpci_alloc_msix(struct vtpci_softc *, int);
138static int vtpci_alloc_msi(struct vtpci_softc *);
139static int vtpci_alloc_intr_msix_pervq(struct vtpci_softc *);
140static int vtpci_alloc_intr_msix_shared(struct vtpci_softc *);
141static int vtpci_alloc_intr_msi(struct vtpci_softc *);
142static int vtpci_alloc_intr_legacy(struct vtpci_softc *);
143static int vtpci_alloc_intr_resources(struct vtpci_softc *);
144
145static int vtpci_setup_legacy_interrupt(struct vtpci_softc *,
146 enum intr_type);
147static int vtpci_setup_msix_interrupts(struct vtpci_softc *,
148 enum intr_type);
149static int vtpci_setup_interrupts(struct vtpci_softc *, enum intr_type);
150
139static int vtpci_register_msix_vector(struct vtpci_softc *, int, int);
151static int vtpci_register_msix_vector(struct vtpci_softc *, int, int);
152static int vtpci_set_host_msix_vectors(struct vtpci_softc *);
153static int vtpci_reinit_virtqueue(struct vtpci_softc *, int);
140
141static void vtpci_free_interrupts(struct vtpci_softc *);
142static void vtpci_free_virtqueues(struct vtpci_softc *);
154
155static void vtpci_free_interrupts(struct vtpci_softc *);
156static void vtpci_free_virtqueues(struct vtpci_softc *);
157static void vtpci_cleanup_setup_intr_attempt(struct vtpci_softc *);
143static void vtpci_release_child_resources(struct vtpci_softc *);
144static void vtpci_reset(struct vtpci_softc *);
145
158static void vtpci_release_child_resources(struct vtpci_softc *);
159static void vtpci_reset(struct vtpci_softc *);
160
161static void vtpci_select_virtqueue(struct vtpci_softc *, int);
162
146static int vtpci_legacy_intr(void *);
147static int vtpci_vq_shared_intr(void *);
148static int vtpci_vq_intr(void *);
149static int vtpci_config_intr(void *);
150
163static int vtpci_legacy_intr(void *);
164static int vtpci_vq_shared_intr(void *);
165static int vtpci_vq_intr(void *);
166static int vtpci_config_intr(void *);
167
168#define vtpci_setup_msi_interrupt vtpci_setup_legacy_interrupt
169
151/*
152 * I/O port read/write wrappers.
153 */
154#define vtpci_read_config_1(sc, o) bus_read_1((sc)->vtpci_res, (o))
155#define vtpci_read_config_2(sc, o) bus_read_2((sc)->vtpci_res, (o))
156#define vtpci_read_config_4(sc, o) bus_read_4((sc)->vtpci_res, (o))
157#define vtpci_write_config_1(sc, o, v) bus_write_1((sc)->vtpci_res, (o), (v))
158#define vtpci_write_config_2(sc, o, v) bus_write_2((sc)->vtpci_res, (o), (v))

--- 88 unchanged lines hidden (view full) ---

247 sc->vtpci_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
248 RF_ACTIVE);
249 if (sc->vtpci_res == NULL) {
250 device_printf(dev, "cannot map I/O space\n");
251 return (ENXIO);
252 }
253
254 if (pci_find_cap(dev, PCIY_MSI, NULL) != 0)
170/*
171 * I/O port read/write wrappers.
172 */
173#define vtpci_read_config_1(sc, o) bus_read_1((sc)->vtpci_res, (o))
174#define vtpci_read_config_2(sc, o) bus_read_2((sc)->vtpci_res, (o))
175#define vtpci_read_config_4(sc, o) bus_read_4((sc)->vtpci_res, (o))
176#define vtpci_write_config_1(sc, o, v) bus_write_1((sc)->vtpci_res, (o), (v))
177#define vtpci_write_config_2(sc, o, v) bus_write_2((sc)->vtpci_res, (o), (v))

--- 88 unchanged lines hidden (view full) ---

266 sc->vtpci_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
267 RF_ACTIVE);
268 if (sc->vtpci_res == NULL) {
269 device_printf(dev, "cannot map I/O space\n");
270 return (ENXIO);
271 }
272
273 if (pci_find_cap(dev, PCIY_MSI, NULL) != 0)
255 sc->vtpci_flags |= VIRTIO_PCI_FLAG_NO_MSI;
274 sc->vtpci_flags |= VTPCI_FLAG_NO_MSI;
256
257 if (pci_find_cap(dev, PCIY_MSIX, NULL) == 0) {
258 rid = PCIR_BAR(1);
259 sc->vtpci_msix_res = bus_alloc_resource_any(dev,
260 SYS_RES_MEMORY, &rid, RF_ACTIVE);
261 }
262
263 if (sc->vtpci_msix_res == NULL)
275
276 if (pci_find_cap(dev, PCIY_MSIX, NULL) == 0) {
277 rid = PCIR_BAR(1);
278 sc->vtpci_msix_res = bus_alloc_resource_any(dev,
279 SYS_RES_MEMORY, &rid, RF_ACTIVE);
280 }
281
282 if (sc->vtpci_msix_res == NULL)
264 sc->vtpci_flags |= VIRTIO_PCI_FLAG_NO_MSIX;
283 sc->vtpci_flags |= VTPCI_FLAG_NO_MSIX;
265
266 vtpci_reset(sc);
267
268 /* Tell the host we've noticed this device. */
269 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_ACK);
270
271 if ((child = device_add_child(dev, NULL, -1)) == NULL) {
272 device_printf(dev, "cannot create child device\n");

--- 94 unchanged lines hidden (view full) ---

367
368 sc = device_get_softc(dev);
369
370 if (sc->vtpci_child_dev != child)
371 return (ENOENT);
372
373 switch (index) {
374 case VIRTIO_IVAR_DEVTYPE:
284
285 vtpci_reset(sc);
286
287 /* Tell the host we've noticed this device. */
288 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_ACK);
289
290 if ((child = device_add_child(dev, NULL, -1)) == NULL) {
291 device_printf(dev, "cannot create child device\n");

--- 94 unchanged lines hidden (view full) ---

386
387 sc = device_get_softc(dev);
388
389 if (sc->vtpci_child_dev != child)
390 return (ENOENT);
391
392 switch (index) {
393 case VIRTIO_IVAR_DEVTYPE:
394 case VIRTIO_IVAR_SUBDEVICE:
375 *result = pci_get_subdevice(dev);
376 break;
395 *result = pci_get_subdevice(dev);
396 break;
397 case VIRTIO_IVAR_VENDOR:
398 *result = pci_get_vendor(dev);
399 break;
400 case VIRTIO_IVAR_DEVICE:
401 *result = pci_get_device(dev);
402 break;
403 case VIRTIO_IVAR_SUBVENDOR:
404 *result = pci_get_subdevice(dev);
405 break;
377 default:
378 return (ENOENT);
379 }
380
381 return (0);
382}
383
384static int

--- 52 unchanged lines hidden (view full) ---

437 return ((sc->vtpci_features & feature) != 0);
438}
439
440static int
441vtpci_alloc_virtqueues(device_t dev, int flags, int nvqs,
442 struct vq_alloc_info *vq_info)
443{
444 struct vtpci_softc *sc;
406 default:
407 return (ENOENT);
408 }
409
410 return (0);
411}
412
413static int

--- 52 unchanged lines hidden (view full) ---

466 return ((sc->vtpci_features & feature) != 0);
467}
468
469static int
470vtpci_alloc_virtqueues(device_t dev, int flags, int nvqs,
471 struct vq_alloc_info *vq_info)
472{
473 struct vtpci_softc *sc;
474 struct virtqueue *vq;
445 struct vtpci_virtqueue *vqx;
446 struct vq_alloc_info *info;
475 struct vtpci_virtqueue *vqx;
476 struct vq_alloc_info *info;
447 int queue, error;
448 uint16_t vq_size;
477 int idx, error;
478 uint16_t size;
449
450 sc = device_get_softc(dev);
479
480 sc = device_get_softc(dev);
481 error = 0;
451
482
452 if (sc->vtpci_nvqs != 0 || nvqs <= 0 ||
453 nvqs > VIRTIO_MAX_VIRTQUEUES)
483 if (sc->vtpci_nvqs != 0)
484 return (EALREADY);
485 if (nvqs <= 0 || nvqs > VIRTIO_MAX_VIRTQUEUES)
454 return (EINVAL);
455
486 return (EINVAL);
487
456 error = vtpci_alloc_interrupts(sc, flags, nvqs, vq_info);
457 if (error) {
458 device_printf(dev, "cannot allocate interrupts\n");
459 return (error);
460 }
488 if (flags & VIRTIO_ALLOC_VQS_DISABLE_MSIX)
489 sc->vtpci_flags |= VTPCI_FLAG_NO_MSIX;
461
490
462 if (sc->vtpci_flags & VIRTIO_PCI_FLAG_MSIX) {
463 error = vtpci_register_msix_vector(sc,
464 VIRTIO_MSI_CONFIG_VECTOR, 0);
465 if (error)
466 return (error);
467 }
491 for (idx = 0; idx < nvqs; idx++) {
492 vqx = &sc->vtpci_vqx[idx];
493 info = &vq_info[idx];
468
494
469 for (queue = 0; queue < nvqs; queue++) {
470 vqx = &sc->vtpci_vqx[queue];
471 info = &vq_info[queue];
495 vtpci_select_virtqueue(sc, idx);
496 size = vtpci_read_config_2(sc, VIRTIO_PCI_QUEUE_NUM);
472
497
473 vtpci_write_config_2(sc, VIRTIO_PCI_QUEUE_SEL, queue);
474
475 vq_size = vtpci_read_config_2(sc, VIRTIO_PCI_QUEUE_NUM);
476 error = virtqueue_alloc(dev, queue, vq_size,
477 VIRTIO_PCI_VRING_ALIGN, 0xFFFFFFFFUL, info, &vqx->vq);
478 if (error)
479 return (error);
480
481 if (sc->vtpci_flags & VIRTIO_PCI_FLAG_MSIX) {
482 error = vtpci_register_msix_vector(sc,
483 VIRTIO_MSI_QUEUE_VECTOR, vqx->ires_idx);
484 if (error)
485 return (error);
498 error = virtqueue_alloc(dev, idx, size, VIRTIO_PCI_VRING_ALIGN,
499 0xFFFFFFFFUL, info, &vq);
500 if (error) {
501 device_printf(dev,
502 "cannot allocate virtqueue %d: %d\n", idx, error);
503 break;
486 }
487
488 vtpci_write_config_4(sc, VIRTIO_PCI_QUEUE_PFN,
504 }
505
506 vtpci_write_config_4(sc, VIRTIO_PCI_QUEUE_PFN,
489 virtqueue_paddr(vqx->vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
507 virtqueue_paddr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
490
508
491 *info->vqai_vq = vqx->vq;
509 vqx->vq = *info->vqai_vq = vq;
510 vqx->no_intr = info->vqai_intr == NULL;
511
492 sc->vtpci_nvqs++;
493 }
494
512 sc->vtpci_nvqs++;
513 }
514
495 return (0);
515 return (error);
496}
497
498static int
499vtpci_setup_intr(device_t dev, enum intr_type type)
500{
501 struct vtpci_softc *sc;
516}
517
518static int
519vtpci_setup_intr(device_t dev, enum intr_type type)
520{
521 struct vtpci_softc *sc;
502 struct vtpci_intr_resource *ires;
503 struct vtpci_virtqueue *vqx;
504 int i, flags, error;
522 int attempt, error;
505
506 sc = device_get_softc(dev);
523
524 sc = device_get_softc(dev);
507 flags = type | INTR_MPSAFE;
508 ires = &sc->vtpci_intr_res[0];
509
525
510 if ((sc->vtpci_flags & VIRTIO_PCI_FLAG_MSIX) == 0) {
511 error = bus_setup_intr(dev, ires->irq, flags,
512 vtpci_legacy_intr, NULL, sc, &ires->intrhand);
526 for (attempt = 0; attempt < 5; attempt++) {
527 /*
528 * Start with the most desirable interrupt configuration and
529 * fallback towards less desirable ones.
530 */
531 switch (attempt) {
532 case 0:
533 error = vtpci_alloc_intr_msix_pervq(sc);
534 break;
535 case 1:
536 error = vtpci_alloc_intr_msix_shared(sc);
537 break;
538 case 2:
539 error = vtpci_alloc_intr_msi(sc);
540 break;
541 case 3:
542 error = vtpci_alloc_intr_legacy(sc);
543 break;
544 default:
545 device_printf(dev,
546 "exhausted all interrupt allocation attempts\n");
547 return (ENXIO);
548 }
513
549
514 return (error);
515 }
550 if (error == 0 && vtpci_setup_interrupts(sc, type) == 0)
551 break;
516
552
517 error = bus_setup_intr(dev, ires->irq, flags, vtpci_config_intr,
518 NULL, sc, &ires->intrhand);
519 if (error)
520 return (error);
521
522 if (sc->vtpci_flags & VIRTIO_PCI_FLAG_SHARED_MSIX) {
523 ires = &sc->vtpci_intr_res[1];
524 error = bus_setup_intr(dev, ires->irq, flags,
525 vtpci_vq_shared_intr, NULL, sc, &ires->intrhand);
526
527 return (error);
553 vtpci_cleanup_setup_intr_attempt(sc);
528 }
529
554 }
555
530 /* Setup an interrupt handler for each virtqueue. */
531 for (i = 0; i < sc->vtpci_nvqs; i++) {
532 vqx = &sc->vtpci_vqx[i];
533 if (vqx->ires_idx < 1)
534 continue;
535
536 ires = &sc->vtpci_intr_res[vqx->ires_idx];
537 error = bus_setup_intr(dev, ires->irq, flags,
538 vtpci_vq_intr, NULL, vqx->vq, &ires->intrhand);
539 if (error)
540 return (error);
556 if (bootverbose) {
557 if (sc->vtpci_flags & VTPCI_FLAG_LEGACY)
558 device_printf(dev, "using legacy interrupt\n");
559 else if (sc->vtpci_flags & VTPCI_FLAG_MSI)
560 device_printf(dev, "using MSI interrupt\n");
561 else if (sc->vtpci_flags & VTPCI_FLAG_SHARED_MSIX)
562 device_printf(dev, "using shared MSIX interrupts\n");
563 else
564 device_printf(dev, "using per VQ MSIX interrupts\n");
541 }
542
543 return (0);
544}
545
546static void
547vtpci_stop(device_t dev)
548{
549
550 vtpci_reset(device_get_softc(dev));
551}
552
553static int
554vtpci_reinit(device_t dev, uint64_t features)
555{
556 struct vtpci_softc *sc;
565 }
566
567 return (0);
568}
569
570static void
571vtpci_stop(device_t dev)
572{
573
574 vtpci_reset(device_get_softc(dev));
575}
576
577static int
578vtpci_reinit(device_t dev, uint64_t features)
579{
580 struct vtpci_softc *sc;
557 struct vtpci_virtqueue *vqx;
558 struct virtqueue *vq;
559 int queue, error;
560 uint16_t vq_size;
581 int idx, error;
561
562 sc = device_get_softc(dev);
563
564 /*
582
583 sc = device_get_softc(dev);
584
585 /*
565 * Redrive the device initialization. This is a bit of an abuse
566 * of the specification, but both VirtualBox and QEMU/KVM seem
567 * to play nice. We do not allow the host device to change from
568 * what was originally negotiated beyond what the guest driver
569 * changed (MSIX state should not change, number of virtqueues
570 * and their size remain the same, etc).
586 * Redrive the device initialization. This is a bit of an abuse of
587 * the specification, but VirtualBox, QEMU/KVM, and BHyVe seem to
588 * play nice.
589 *
590 * We do not allow the host device to change from what was originally
591 * negotiated beyond what the guest driver changed. MSIX state should
592 * not change, number of virtqueues and their size remain the same, etc.
593 * This will need to be rethought when we want to support migration.
571 */
572
573 if (vtpci_get_status(dev) != VIRTIO_CONFIG_STATUS_RESET)
574 vtpci_stop(dev);
575
576 /*
577 * Quickly drive the status through ACK and DRIVER. The device
578 * does not become usable again until vtpci_reinit_complete().
579 */
580 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_ACK);
581 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER);
582
583 vtpci_negotiate_features(dev, features);
584
594 */
595
596 if (vtpci_get_status(dev) != VIRTIO_CONFIG_STATUS_RESET)
597 vtpci_stop(dev);
598
599 /*
600 * Quickly drive the status through ACK and DRIVER. The device
601 * does not become usable again until vtpci_reinit_complete().
602 */
603 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_ACK);
604 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER);
605
606 vtpci_negotiate_features(dev, features);
607
585 if (sc->vtpci_flags & VIRTIO_PCI_FLAG_MSIX) {
586 error = vtpci_register_msix_vector(sc,
587 VIRTIO_MSI_CONFIG_VECTOR, 0);
608 for (idx = 0; idx < sc->vtpci_nvqs; idx++) {
609 error = vtpci_reinit_virtqueue(sc, idx);
588 if (error)
589 return (error);
590 }
591
610 if (error)
611 return (error);
612 }
613
592 for (queue = 0; queue < sc->vtpci_nvqs; queue++) {
593 vqx = &sc->vtpci_vqx[queue];
594 vq = vqx->vq;
595
596 KASSERT(vq != NULL, ("vq %d not allocated", queue));
597 vtpci_write_config_2(sc, VIRTIO_PCI_QUEUE_SEL, queue);
598
599 vq_size = vtpci_read_config_2(sc, VIRTIO_PCI_QUEUE_NUM);
600 error = virtqueue_reinit(vq, vq_size);
614 if (sc->vtpci_flags & VTPCI_FLAG_MSIX) {
615 error = vtpci_set_host_msix_vectors(sc);
601 if (error)
602 return (error);
616 if (error)
617 return (error);
603
604 if (sc->vtpci_flags & VIRTIO_PCI_FLAG_MSIX) {
605 error = vtpci_register_msix_vector(sc,
606 VIRTIO_MSI_QUEUE_VECTOR, vqx->ires_idx);
607 if (error)
608 return (error);
609 }
610
611 vtpci_write_config_4(sc, VIRTIO_PCI_QUEUE_PFN,
612 virtqueue_paddr(vqx->vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
613 }
614
615 return (0);
616}
617
618static void
619vtpci_reinit_complete(device_t dev)
620{

--- 118 unchanged lines hidden (view full) ---

739 if (device_probe(child) != 0)
740 return;
741
742 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER);
743 if (device_attach(child) != 0) {
744 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_FAILED);
745 vtpci_reset(sc);
746 vtpci_release_child_resources(sc);
618 }
619
620 return (0);
621}
622
623static void
624vtpci_reinit_complete(device_t dev)
625{

--- 118 unchanged lines hidden (view full) ---

744 if (device_probe(child) != 0)
745 return;
746
747 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER);
748 if (device_attach(child) != 0) {
749 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_FAILED);
750 vtpci_reset(sc);
751 vtpci_release_child_resources(sc);
747
748 /* Reset status for future attempt. */
749 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_ACK);
750 } else
751 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER_OK);
752}
753
754static int
752 /* Reset status for future attempt. */
753 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_ACK);
754 } else
755 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER_OK);
756}
757
758static int
755vtpci_alloc_interrupts(struct vtpci_softc *sc, int flags, int nvqs,
756 struct vq_alloc_info *vq_info)
759vtpci_alloc_msix(struct vtpci_softc *sc, int nvectors)
757{
760{
761 device_t dev;
762 int nmsix, cnt, required;
763
764 dev = sc->vtpci_dev;
765
766 /* Allocate an additional vector for the config changes. */
767 required = nvectors + 1;
768
769 nmsix = pci_msix_count(dev);
770 if (nmsix < required)
771 return (1);
772
773 cnt = required;
774 if (pci_alloc_msix(dev, &cnt) == 0 && cnt >= required) {
775 sc->vtpci_nintr_res = required;
776 return (0);
777 }
778
779 pci_release_msi(dev);
780
781 return (1);
782}
783
784static int
785vtpci_alloc_msi(struct vtpci_softc *sc)
786{
787 device_t dev;
788 int nmsi, cnt, required;
789
790 dev = sc->vtpci_dev;
791 required = 1;
792
793 nmsi = pci_msi_count(dev);
794 if (nmsi < required)
795 return (1);
796
797 cnt = required;
798 if (pci_alloc_msi(dev, &cnt) == 0 && cnt >= required) {
799 sc->vtpci_nintr_res = required;
800 return (0);
801 }
802
803 pci_release_msi(dev);
804
805 return (1);
806}
807
808static int
809vtpci_alloc_intr_msix_pervq(struct vtpci_softc *sc)
810{
758 int i, nvectors, error;
759
811 int i, nvectors, error;
812
760 /*
761 * Only allocate a vector for virtqueues that are actually
762 * expecting an interrupt.
763 */
764 for (nvectors = 0, i = 0; i < nvqs; i++)
765 if (vq_info[i].vqai_intr != NULL)
813 if (vtpci_disable_msix != 0 ||
814 sc->vtpci_flags & VTPCI_FLAG_NO_MSIX)
815 return (ENOTSUP);
816
817 for (nvectors = 0, i = 0; i < sc->vtpci_nvqs; i++) {
818 if (sc->vtpci_vqx[i].no_intr == 0)
766 nvectors++;
819 nvectors++;
820 }
767
821
822 error = vtpci_alloc_msix(sc, nvectors);
823 if (error)
824 return (error);
825
826 sc->vtpci_flags |= VTPCI_FLAG_MSIX;
827
828 return (0);
829}
830
831static int
832vtpci_alloc_intr_msix_shared(struct vtpci_softc *sc)
833{
834 int error;
835
768 if (vtpci_disable_msix != 0 ||
836 if (vtpci_disable_msix != 0 ||
769 sc->vtpci_flags & VIRTIO_PCI_FLAG_NO_MSIX ||
770 flags & VIRTIO_ALLOC_VQS_DISABLE_MSIX ||
771 vtpci_alloc_msix(sc, nvectors) != 0) {
772 /*
773 * Use MSI interrupts if available. Otherwise, we fallback
774 * to legacy interrupts.
775 */
776 if ((sc->vtpci_flags & VIRTIO_PCI_FLAG_NO_MSI) == 0 &&
777 vtpci_alloc_msi(sc) == 0)
778 sc->vtpci_flags |= VIRTIO_PCI_FLAG_MSI;
837 sc->vtpci_flags & VTPCI_FLAG_NO_MSIX)
838 return (ENOTSUP);
779
839
780 sc->vtpci_nintr_res = 1;
781 }
840 error = vtpci_alloc_msix(sc, 1);
841 if (error)
842 return (error);
782
843
783 error = vtpci_alloc_intr_resources(sc, nvqs, vq_info);
844 sc->vtpci_flags |= VTPCI_FLAG_MSIX | VTPCI_FLAG_SHARED_MSIX;
784
845
785 return (error);
846 return (0);
786}
787
788static int
847}
848
849static int
789vtpci_alloc_intr_resources(struct vtpci_softc *sc, int nvqs,
790 struct vq_alloc_info *vq_info)
850vtpci_alloc_intr_msi(struct vtpci_softc *sc)
791{
851{
852 int error;
853
854 /* Only BHyVe supports MSI. */
855 if (sc->vtpci_flags & VTPCI_FLAG_NO_MSI)
856 return (ENOTSUP);
857
858 error = vtpci_alloc_msi(sc);
859 if (error)
860 return (error);
861
862 sc->vtpci_flags |= VTPCI_FLAG_MSI;
863
864 return (0);
865}
866
867static int
868vtpci_alloc_intr_legacy(struct vtpci_softc *sc)
869{
870
871 sc->vtpci_flags |= VTPCI_FLAG_LEGACY;
872 sc->vtpci_nintr_res = 1;
873
874 return (0);
875}
876
877static int
878vtpci_alloc_intr_resources(struct vtpci_softc *sc)
879{
792 device_t dev;
793 struct resource *irq;
794 struct vtpci_virtqueue *vqx;
795 int i, rid, flags, res_idx;
796
797 dev = sc->vtpci_dev;
880 device_t dev;
881 struct resource *irq;
882 struct vtpci_virtqueue *vqx;
883 int i, rid, flags, res_idx;
884
885 dev = sc->vtpci_dev;
798 flags = RF_ACTIVE;
799
886
800 if ((sc->vtpci_flags &
801 (VIRTIO_PCI_FLAG_MSI | VIRTIO_PCI_FLAG_MSIX)) == 0) {
887 if (sc->vtpci_flags & VTPCI_FLAG_LEGACY) {
802 rid = 0;
888 rid = 0;
803 flags |= RF_SHAREABLE;
804 } else
889 flags = RF_ACTIVE | RF_SHAREABLE;
890 } else {
805 rid = 1;
891 rid = 1;
892 flags = RF_ACTIVE;
893 }
806
807 for (i = 0; i < sc->vtpci_nintr_res; i++) {
808 irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, flags);
809 if (irq == NULL)
810 return (ENXIO);
811
812 sc->vtpci_intr_res[i].irq = irq;
813 sc->vtpci_intr_res[i].rid = rid++;
814 }
815
816 /*
894
895 for (i = 0; i < sc->vtpci_nintr_res; i++) {
896 irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, flags);
897 if (irq == NULL)
898 return (ENXIO);
899
900 sc->vtpci_intr_res[i].irq = irq;
901 sc->vtpci_intr_res[i].rid = rid++;
902 }
903
904 /*
817 * Map the virtqueue into the correct index in vq_intr_res[]. Note the
818 * first index is reserved for configuration changes notifications.
905 * Map the virtqueue into the correct index in vq_intr_res[]. The
906 * first index is reserved for configuration changed notifications.
819 */
907 */
820 for (i = 0, res_idx = 1; i < nvqs; i++) {
908 for (i = 0, res_idx = 1; i < sc->vtpci_nvqs; i++) {
821 vqx = &sc->vtpci_vqx[i];
822
909 vqx = &sc->vtpci_vqx[i];
910
823 if (sc->vtpci_flags & VIRTIO_PCI_FLAG_MSIX) {
824 if (vq_info[i].vqai_intr == NULL)
911 if (sc->vtpci_flags & VTPCI_FLAG_MSIX) {
912 if (vqx->no_intr != 0)
825 vqx->ires_idx = -1;
913 vqx->ires_idx = -1;
826 else if (sc->vtpci_flags & VIRTIO_PCI_FLAG_SHARED_MSIX)
914 else if (sc->vtpci_flags & VTPCI_FLAG_SHARED_MSIX)
827 vqx->ires_idx = res_idx;
828 else
829 vqx->ires_idx = res_idx++;
830 } else
831 vqx->ires_idx = -1;
832 }
833
834 return (0);
835}
836
837static int
915 vqx->ires_idx = res_idx;
916 else
917 vqx->ires_idx = res_idx++;
918 } else
919 vqx->ires_idx = -1;
920 }
921
922 return (0);
923}
924
925static int
838vtpci_alloc_msi(struct vtpci_softc *sc)
926vtpci_setup_legacy_interrupt(struct vtpci_softc *sc, enum intr_type type)
839{
840 device_t dev;
927{
928 device_t dev;
841 int nmsi, cnt;
929 struct vtpci_intr_resource *ires;
930 int error;
842
843 dev = sc->vtpci_dev;
931
932 dev = sc->vtpci_dev;
844 nmsi = pci_msi_count(dev);
845
933
846 if (nmsi < 1)
847 return (1);
934 ires = &sc->vtpci_intr_res[0];
935 error = bus_setup_intr(dev, ires->irq, type, vtpci_legacy_intr, NULL,
936 sc, &ires->intrhand);
848
937
849 cnt = 1;
850 if (pci_alloc_msi(dev, &cnt) == 0 && cnt == 1)
851 return (0);
852
853 return (1);
938 return (error);
854}
855
856static int
939}
940
941static int
857vtpci_alloc_msix(struct vtpci_softc *sc, int nvectors)
942vtpci_setup_msix_interrupts(struct vtpci_softc *sc, enum intr_type type)
858{
859 device_t dev;
943{
944 device_t dev;
860 int nmsix, cnt, required;
945 struct vtpci_intr_resource *ires;
946 struct vtpci_virtqueue *vqx;
947 int i, error;
861
862 dev = sc->vtpci_dev;
863
948
949 dev = sc->vtpci_dev;
950
864 nmsix = pci_msix_count(dev);
865 if (nmsix < 1)
866 return (1);
951 /*
952 * The first resource is used for configuration changed interrupts.
953 */
954 ires = &sc->vtpci_intr_res[0];
955 error = bus_setup_intr(dev, ires->irq, type, vtpci_config_intr,
956 NULL, sc, &ires->intrhand);
957 if (error)
958 return (error);
867
959
868 /* An additional vector is needed for the config changes. */
869 required = nvectors + 1;
870 if (nmsix >= required) {
871 cnt = required;
872 if (pci_alloc_msix(dev, &cnt) == 0 && cnt >= required)
873 goto out;
960 if (sc->vtpci_flags & VTPCI_FLAG_SHARED_MSIX) {
961 ires = &sc->vtpci_intr_res[1];
874
962
875 pci_release_msi(dev);
876 }
963 error = bus_setup_intr(dev, ires->irq, type,
964 vtpci_vq_shared_intr, NULL, sc, &ires->intrhand);
965 if (error)
966 return (error);
967 } else {
968 /*
969 * Each remaining resource is assigned to a specific virtqueue.
970 */
971 for (i = 0; i < sc->vtpci_nvqs; i++) {
972 vqx = &sc->vtpci_vqx[i];
973 if (vqx->ires_idx < 1)
974 continue;
877
975
878 /* Attempt shared MSIX configuration. */
879 required = 2;
880 if (nmsix >= required) {
881 cnt = required;
882 if (pci_alloc_msix(dev, &cnt) == 0 && cnt >= required) {
883 sc->vtpci_flags |= VIRTIO_PCI_FLAG_SHARED_MSIX;
884 goto out;
976 ires = &sc->vtpci_intr_res[vqx->ires_idx];
977 error = bus_setup_intr(dev, ires->irq, type,
978 vtpci_vq_intr, NULL, vqx->vq, &ires->intrhand);
979 if (error)
980 return (error);
885 }
981 }
886
887 pci_release_msi(dev);
888 }
889
982 }
983
890 return (1);
984 error = vtpci_set_host_msix_vectors(sc);
985 if (error)
986 return (error);
891
987
892out:
893 sc->vtpci_nintr_res = required;
894 sc->vtpci_flags |= VIRTIO_PCI_FLAG_MSIX;
988 return (0);
989}
895
990
896 if (bootverbose) {
897 if (sc->vtpci_flags & VIRTIO_PCI_FLAG_SHARED_MSIX)
898 device_printf(dev, "using shared virtqueue MSIX\n");
899 else
900 device_printf(dev, "using per virtqueue MSIX\n");
901 }
991static int
992vtpci_setup_interrupts(struct vtpci_softc *sc, enum intr_type type)
993{
994 int error;
902
995
903 return (0);
996 type |= INTR_MPSAFE;
997 KASSERT(sc->vtpci_flags & VTPCI_FLAG_ITYPE_MASK,
998 ("no interrupt type selected: %#x", sc->vtpci_flags));
999
1000 error = vtpci_alloc_intr_resources(sc);
1001 if (error)
1002 return (error);
1003
1004 if (sc->vtpci_flags & VTPCI_FLAG_LEGACY)
1005 error = vtpci_setup_legacy_interrupt(sc, type);
1006 else if (sc->vtpci_flags & VTPCI_FLAG_MSI)
1007 error = vtpci_setup_msi_interrupt(sc, type);
1008 else
1009 error = vtpci_setup_msix_interrupts(sc, type);
1010
1011 return (error);
904}
905
906static int
907vtpci_register_msix_vector(struct vtpci_softc *sc, int offset, int res_idx)
908{
909 device_t dev;
1012}
1013
1014static int
1015vtpci_register_msix_vector(struct vtpci_softc *sc, int offset, int res_idx)
1016{
1017 device_t dev;
910 uint16_t vector;
1018 uint16_t vector, rdvector;
911
912 dev = sc->vtpci_dev;
913
1019
1020 dev = sc->vtpci_dev;
1021
914 if (offset != VIRTIO_MSI_CONFIG_VECTOR &&
915 offset != VIRTIO_MSI_QUEUE_VECTOR)
916 return (EINVAL);
917
918 if (res_idx != -1) {
1022 if (res_idx != -1) {
919 /* Map from rid to host vector. */
1023 /* Map from guest rid to host vector. */
920 vector = sc->vtpci_intr_res[res_idx].rid - 1;
921 } else
922 vector = VIRTIO_MSI_NO_VECTOR;
923
1024 vector = sc->vtpci_intr_res[res_idx].rid - 1;
1025 } else
1026 vector = VIRTIO_MSI_NO_VECTOR;
1027
924 /* The first resource is special; make sure it is used correctly. */
1028 /*
1029 * Assert the first resource is always used for the configuration
1030 * changed interrupts.
1031 */
925 if (res_idx == 0) {
1032 if (res_idx == 0) {
926 KASSERT(vector == 0, ("unexpected config vector"));
927 KASSERT(offset == VIRTIO_MSI_CONFIG_VECTOR,
928 ("unexpected config offset"));
929 }
1033 KASSERT(vector == 0 && offset == VIRTIO_MSI_CONFIG_VECTOR,
1034 ("bad first res use vector:%d offset:%d", vector, offset));
1035 } else
1036 KASSERT(offset == VIRTIO_MSI_QUEUE_VECTOR, ("bad offset"));
930
931 vtpci_write_config_2(sc, offset, vector);
932
1037
1038 vtpci_write_config_2(sc, offset, vector);
1039
933 if (vtpci_read_config_2(sc, offset) != vector) {
934 device_printf(dev, "insufficient host resources for "
935 "MSIX interrupts\n");
1040 /* Read vector to determine if the host had sufficient resources. */
1041 rdvector = vtpci_read_config_2(sc, offset);
1042 if (rdvector != vector) {
1043 device_printf(dev,
1044 "insufficient host resources for MSIX interrupts\n");
936 return (ENODEV);
937 }
938
939 return (0);
940}
941
1045 return (ENODEV);
1046 }
1047
1048 return (0);
1049}
1050
1051static int
1052vtpci_set_host_msix_vectors(struct vtpci_softc *sc)
1053{
1054 struct vtpci_virtqueue *vqx;
1055 int idx, error;
1056
1057 error = vtpci_register_msix_vector(sc, VIRTIO_MSI_CONFIG_VECTOR, 0);
1058 if (error)
1059 return (error);
1060
1061 for (idx = 0; idx < sc->vtpci_nvqs; idx++) {
1062 vqx = &sc->vtpci_vqx[idx];
1063
1064 vtpci_select_virtqueue(sc, idx);
1065 error = vtpci_register_msix_vector(sc, VIRTIO_MSI_QUEUE_VECTOR,
1066 vqx->ires_idx);
1067 if (error)
1068 return (error);
1069 }
1070
1071 return (0);
1072}
1073
1074static int
1075vtpci_reinit_virtqueue(struct vtpci_softc *sc, int idx)
1076{
1077 struct vtpci_virtqueue *vqx;
1078 struct virtqueue *vq;
1079 int error;
1080 uint16_t size;
1081
1082 vqx = &sc->vtpci_vqx[idx];
1083 vq = vqx->vq;
1084
1085 KASSERT(vq != NULL, ("vq %d not allocated", idx));
1086
1087 vtpci_select_virtqueue(sc, idx);
1088 size = vtpci_read_config_2(sc, VIRTIO_PCI_QUEUE_NUM);
1089
1090 error = virtqueue_reinit(vq, size);
1091 if (error)
1092 return (error);
1093
1094 vtpci_write_config_4(sc, VIRTIO_PCI_QUEUE_PFN,
1095 virtqueue_paddr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
1096
1097 return (0);
1098}
1099
942static void
943vtpci_free_interrupts(struct vtpci_softc *sc)
944{
945 device_t dev;
946 struct vtpci_intr_resource *ires;
947 int i;
948
949 dev = sc->vtpci_dev;
1100static void
1101vtpci_free_interrupts(struct vtpci_softc *sc)
1102{
1103 device_t dev;
1104 struct vtpci_intr_resource *ires;
1105 int i;
1106
1107 dev = sc->vtpci_dev;
950 sc->vtpci_nintr_res = 0;
951
1108
952 if (sc->vtpci_flags & (VIRTIO_PCI_FLAG_MSI | VIRTIO_PCI_FLAG_MSIX)) {
953 pci_release_msi(dev);
954 sc->vtpci_flags &= ~(VIRTIO_PCI_FLAG_MSI |
955 VIRTIO_PCI_FLAG_MSIX | VIRTIO_PCI_FLAG_SHARED_MSIX);
956 }
957
958 for (i = 0; i < 1 + VIRTIO_MAX_VIRTQUEUES; i++) {
1109 for (i = 0; i < sc->vtpci_nintr_res; i++) {
959 ires = &sc->vtpci_intr_res[i];
960
961 if (ires->intrhand != NULL) {
962 bus_teardown_intr(dev, ires->irq, ires->intrhand);
963 ires->intrhand = NULL;
964 }
965
966 if (ires->irq != NULL) {
967 bus_release_resource(dev, SYS_RES_IRQ, ires->rid,
968 ires->irq);
969 ires->irq = NULL;
970 }
971
972 ires->rid = -1;
973 }
1110 ires = &sc->vtpci_intr_res[i];
1111
1112 if (ires->intrhand != NULL) {
1113 bus_teardown_intr(dev, ires->irq, ires->intrhand);
1114 ires->intrhand = NULL;
1115 }
1116
1117 if (ires->irq != NULL) {
1118 bus_release_resource(dev, SYS_RES_IRQ, ires->rid,
1119 ires->irq);
1120 ires->irq = NULL;
1121 }
1122
1123 ires->rid = -1;
1124 }
1125
1126 if (sc->vtpci_flags & (VTPCI_FLAG_MSI | VTPCI_FLAG_MSIX))
1127 pci_release_msi(dev);
1128
1129 sc->vtpci_nintr_res = 0;
1130 sc->vtpci_flags &= ~VTPCI_FLAG_ITYPE_MASK;
974}
975
976static void
977vtpci_free_virtqueues(struct vtpci_softc *sc)
978{
979 struct vtpci_virtqueue *vqx;
980 int i;
981
1131}
1132
1133static void
1134vtpci_free_virtqueues(struct vtpci_softc *sc)
1135{
1136 struct vtpci_virtqueue *vqx;
1137 int i;
1138
1139 for (i = 0; i < sc->vtpci_nvqs; i++) {
1140 vqx = &sc->vtpci_vqx[i];
1141
1142 virtqueue_free(vqx->vq);
1143 vqx->vq = NULL;
1144 }
1145
982 sc->vtpci_nvqs = 0;
1146 sc->vtpci_nvqs = 0;
1147}
983
1148
984 for (i = 0; i < VIRTIO_MAX_VIRTQUEUES; i++) {
985 vqx = &sc->vtpci_vqx[i];
1149static void
1150vtpci_cleanup_setup_intr_attempt(struct vtpci_softc *sc)
1151{
1152 int idx;
986
1153
987 if (vqx->vq != NULL) {
988 virtqueue_free(vqx->vq);
989 vqx->vq = NULL;
1154 if (sc->vtpci_flags & VTPCI_FLAG_MSIX) {
1155 vtpci_write_config_2(sc, VIRTIO_MSI_CONFIG_VECTOR,
1156 VIRTIO_MSI_NO_VECTOR);
1157
1158 for (idx = 0; idx < sc->vtpci_nvqs; idx++) {
1159 vtpci_select_virtqueue(sc, idx);
1160 vtpci_write_config_2(sc, VIRTIO_MSI_QUEUE_VECTOR,
1161 VIRTIO_MSI_NO_VECTOR);
990 }
991 }
1162 }
1163 }
1164
1165 vtpci_free_interrupts(sc);
992}
993
994static void
995vtpci_release_child_resources(struct vtpci_softc *sc)
996{
997
998 vtpci_free_interrupts(sc);
999 vtpci_free_virtqueues(sc);

--- 5 unchanged lines hidden (view full) ---

1005
1006 /*
1007 * Setting the status to RESET sets the host device to
1008 * the original, uninitialized state.
1009 */
1010 vtpci_set_status(sc->vtpci_dev, VIRTIO_CONFIG_STATUS_RESET);
1011}
1012
1166}
1167
1168static void
1169vtpci_release_child_resources(struct vtpci_softc *sc)
1170{
1171
1172 vtpci_free_interrupts(sc);
1173 vtpci_free_virtqueues(sc);

--- 5 unchanged lines hidden (view full) ---

1179
1180 /*
1181 * Setting the status to RESET sets the host device to
1182 * the original, uninitialized state.
1183 */
1184 vtpci_set_status(sc->vtpci_dev, VIRTIO_CONFIG_STATUS_RESET);
1185}
1186
1187static void
1188vtpci_select_virtqueue(struct vtpci_softc *sc, int idx)
1189{
1190
1191 vtpci_write_config_2(sc, VIRTIO_PCI_QUEUE_SEL, idx);
1192}
1193
1013static int
1014vtpci_legacy_intr(void *xsc)
1015{
1016 struct vtpci_softc *sc;
1017 struct vtpci_virtqueue *vqx;
1018 int i;
1019 uint8_t isr;
1020

--- 61 unchanged lines hidden ---
1194static int
1195vtpci_legacy_intr(void *xsc)
1196{
1197 struct vtpci_softc *sc;
1198 struct vtpci_virtqueue *vqx;
1199 int i;
1200 uint8_t isr;
1201

--- 61 unchanged lines hidden ---