summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2023-07-07 10:23:40 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2023-07-07 10:23:40 +0000
commitca891b6d8eac884b8be8b5dcf4f0fc4e72480a5e (patch)
tree55c52c3d33d8d462c52458c1545c4fc53fbece24 /sys
parent8888312e624ecc9bdb18bb3b6833e7687fc08b77 (diff)
The per-VQ MSI-X interrupt handler needs to sync DMA mappings in the
same way that the shared interrupt handler does. This is one of the requirements of virtio_dequeue(), as specified in its comment above. Without the DMA sync, it will not see a new entry on the ring and return. Since the interrupt is edge-triggered there won't be another one and we'll get stuck. ok dv@
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/virtio_pci.c14
-rw-r--r--sys/dev/pv/virtio.c33
-rw-r--r--sys/dev/pv/virtiovar.h3
3 files changed, 31 insertions, 19 deletions
diff --git a/sys/dev/pci/virtio_pci.c b/sys/dev/pci/virtio_pci.c
index 28087f1ac9d..398dc960f6d 100644
--- a/sys/dev/pci/virtio_pci.c
+++ b/sys/dev/pci/virtio_pci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: virtio_pci.c,v 1.34 2023/07/05 18:11:08 patrick Exp $ */
+/* $OpenBSD: virtio_pci.c,v 1.35 2023/07/07 10:23:39 patrick Exp $ */
/* $NetBSD: virtio.c,v 1.3 2011/11/02 23:05:52 njoly Exp $ */
/*
@@ -961,6 +961,13 @@ virtio_pci_setup_msix(struct virtio_pci_softc *sc, struct pci_attach_args *pa,
struct virtio_softc *vsc = &sc->sc_sc;
int i;
+ /* Shared needs config + queue */
+ if (shared && pci_intr_msix_count(pa) < 1 + 1)
+ return 1;
+ /* Per VQ needs config + N * queue */
+ if (!shared && pci_intr_msix_count(pa) < 1 + vsc->sc_nvqs)
+ return 1;
+
if (virtio_pci_msix_establish(sc, pa, 0, virtio_pci_config_intr, vsc))
return 1;
sc->sc_devcfg_offset = VIRTIO_CONFIG_DEVICE_CONFIG_MSI;
@@ -1059,10 +1066,9 @@ int
virtio_pci_queue_intr(void *arg)
{
struct virtqueue *vq = arg;
+ struct virtio_softc *vsc = vq->vq_owner;
- if (vq->vq_done)
- return (vq->vq_done)(vq);
- return 0;
+ return virtio_check_vq(vsc, vq);
}
int
diff --git a/sys/dev/pv/virtio.c b/sys/dev/pv/virtio.c
index d085376d054..e9be61c0bbe 100644
--- a/sys/dev/pv/virtio.c
+++ b/sys/dev/pv/virtio.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: virtio.c,v 1.22 2023/04/20 19:28:31 jcs Exp $ */
+/* $OpenBSD: virtio.c,v 1.23 2023/07/07 10:23:39 patrick Exp $ */
/* $NetBSD: virtio.c,v 1.3 2011/11/02 23:05:52 njoly Exp $ */
/*
@@ -218,26 +218,31 @@ vq_sync_indirect(struct virtio_softc *sc, struct virtqueue *vq, int slot,
int
virtio_check_vqs(struct virtio_softc *sc)
{
- struct virtqueue *vq;
int i, r = 0;
/* going backwards is better for if_vio */
- for (i = sc->sc_nvqs - 1; i >= 0; i--) {
- vq = &sc->sc_vqs[i];
- if (vq->vq_queued) {
- vq->vq_queued = 0;
- vq_sync_aring(sc, vq, BUS_DMASYNC_POSTWRITE);
- }
- vq_sync_uring(sc, vq, BUS_DMASYNC_POSTREAD);
- if (vq->vq_used_idx != vq->vq_used->idx) {
- if (vq->vq_done)
- r |= (vq->vq_done)(vq);
- }
- }
+ for (i = sc->sc_nvqs - 1; i >= 0; i--)
+ r |= virtio_check_vq(sc, &sc->sc_vqs[i]);
return r;
}
+int
+virtio_check_vq(struct virtio_softc *sc, struct virtqueue *vq)
+{
+ if (vq->vq_queued) {
+ vq->vq_queued = 0;
+ vq_sync_aring(sc, vq, BUS_DMASYNC_POSTWRITE);
+ }
+ vq_sync_uring(sc, vq, BUS_DMASYNC_POSTREAD);
+ if (vq->vq_used_idx != vq->vq_used->idx) {
+ if (vq->vq_done)
+ return (vq->vq_done)(vq);
+ }
+
+ return 0;
+}
+
/*
* Initialize vq structure.
*/
diff --git a/sys/dev/pv/virtiovar.h b/sys/dev/pv/virtiovar.h
index 9e3e9c9a27b..7f2aea701cd 100644
--- a/sys/dev/pv/virtiovar.h
+++ b/sys/dev/pv/virtiovar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: virtiovar.h,v 1.14 2019/05/26 15:22:31 sf Exp $ */
+/* $OpenBSD: virtiovar.h,v 1.15 2023/07/07 10:23:39 patrick Exp $ */
/* $NetBSD: virtiovar.h,v 1.1 2011/10/30 12:12:21 hannken Exp $ */
/*
@@ -233,6 +233,7 @@ int virtio_dequeue_commit(struct virtqueue*, int);
int virtio_intr(void *arg);
int virtio_check_vqs(struct virtio_softc *);
+int virtio_check_vq(struct virtio_softc *, struct virtqueue *);
void virtio_stop_vq_intr(struct virtio_softc *, struct virtqueue *);
int virtio_start_vq_intr(struct virtio_softc *, struct virtqueue *);