Module Name:    src
Committed By:   ozaki-r
Date:           Mon Oct 26 01:44:48 UTC 2015

Modified Files:
        src/sys/dev/pci: if_vioif.c virtio.c virtioreg.h virtiovar.h

Log Message:
Support MSI-X in virtio

Currently only vioif(4) uses the feature.

knakahara@ helped to migrate to pci_intr_alloc(9). Thanks!


To generate a diff of this commit:
cvs rdiff -u -r1.16 -r1.17 src/sys/dev/pci/if_vioif.c
cvs rdiff -u -r1.10 -r1.11 src/sys/dev/pci/virtio.c
cvs rdiff -u -r1.3 -r1.4 src/sys/dev/pci/virtioreg.h
cvs rdiff -u -r1.4 -r1.5 src/sys/dev/pci/virtiovar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/if_vioif.c
diff -u src/sys/dev/pci/if_vioif.c:1.16 src/sys/dev/pci/if_vioif.c:1.17
--- src/sys/dev/pci/if_vioif.c:1.16	Tue May  5 10:56:13 2015
+++ src/sys/dev/pci/if_vioif.c	Mon Oct 26 01:44:48 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_vioif.c,v 1.16 2015/05/05 10:56:13 ozaki-r Exp $	*/
+/*	$NetBSD: if_vioif.c,v 1.17 2015/10/26 01:44:48 ozaki-r Exp $	*/
 
 /*
  * Copyright (c) 2010 Minoura Makoto.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_vioif.c,v 1.16 2015/05/05 10:56:13 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_vioif.c,v 1.17 2015/10/26 01:44:48 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -487,6 +487,7 @@ vioif_attach(device_t parent, device_t s
 	uint32_t features;
 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
 	u_int flags;
+	int r;
 
 	if (vsc->sc_child != NULL) {
 		aprint_normal(": child already attached for %s; "
@@ -511,6 +512,7 @@ vioif_attach(device_t parent, device_t s
 #ifdef VIOIF_SOFTINT_INTR
 	vsc->sc_flags |= VIRTIO_F_PCI_INTR_SOFTINT;
 #endif
+	vsc->sc_flags |= VIRTIO_F_PCI_INTR_MSIX;
 
 	features = virtio_negotiate_features(vsc,
 					     (VIRTIO_NET_F_MAC |
@@ -560,21 +562,6 @@ vioif_attach(device_t parent, device_t s
 	aprint_normal(": Ethernet address %s\n", ether_sprintf(sc->sc_mac));
 	aprint_naive("\n");
 
-	if (virtio_alloc_vq(vsc, &sc->sc_vq[0], 0,
-			    MCLBYTES+sizeof(struct virtio_net_hdr), 2,
-			    "rx") != 0) {
-		goto err;
-	}
-	vsc->sc_nvqs = 1;
-	sc->sc_vq[0].vq_done = vioif_rx_vq_done;
-	if (virtio_alloc_vq(vsc, &sc->sc_vq[1], 1,
-			    (sizeof(struct virtio_net_hdr)
-			     + (ETHER_MAX_LEN - ETHER_HDR_LEN)),
-			    VIRTIO_NET_TX_MAXNSEGS + 1,
-			    "tx") != 0) {
-		goto err;
-	}
-
 #ifdef VIOIF_MPSAFE
 	sc->sc_tx_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET);
 	sc->sc_rx_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET);
@@ -584,23 +571,51 @@ vioif_attach(device_t parent, device_t s
 #endif
 	sc->sc_stopping = false;
 
+	/*
+	 * Allocating a virtqueue for Rx
+	 */
+	r = virtio_alloc_vq(vsc, &sc->sc_vq[0], 0,
+	    MCLBYTES+sizeof(struct virtio_net_hdr), 2, "rx");
+	if (r != 0)
+		goto err;
+	vsc->sc_nvqs = 1;
+	sc->sc_vq[0].vq_done = vioif_rx_vq_done;
+
+	/*
+	 * Allocating a virtqueue for Tx
+	 */
+	r = virtio_alloc_vq(vsc, &sc->sc_vq[1], 1,
+	    (sizeof(struct virtio_net_hdr) + (ETHER_MAX_LEN - ETHER_HDR_LEN)),
+	    VIRTIO_NET_TX_MAXNSEGS + 1, "tx");
+	if (r != 0)
+		goto err;
 	vsc->sc_nvqs = 2;
 	sc->sc_vq[1].vq_done = vioif_tx_vq_done;
+
 	virtio_start_vq_intr(vsc, &sc->sc_vq[0]);
 	virtio_stop_vq_intr(vsc, &sc->sc_vq[1]); /* not urgent; do it later */
-	if ((features & VIRTIO_NET_F_CTRL_VQ)
-	    && (features & VIRTIO_NET_F_CTRL_RX)) {
-		if (virtio_alloc_vq(vsc, &sc->sc_vq[2], 2,
-				    NBPG, 1, "control") == 0) {
-			sc->sc_vq[2].vq_done = vioif_ctrl_vq_done;
-			cv_init(&sc->sc_ctrl_wait, "ctrl_vq");
-			mutex_init(&sc->sc_ctrl_wait_lock,
-				   MUTEX_DEFAULT, IPL_NET);
-			sc->sc_ctrl_inuse = FREE;
-			virtio_start_vq_intr(vsc, &sc->sc_vq[2]);
-			vsc->sc_nvqs = 3;
+
+	if ((features & VIRTIO_NET_F_CTRL_VQ) &&
+	    (features & VIRTIO_NET_F_CTRL_RX)) {
+		/*
+		 * Allocating a virtqueue for control channel
+		 */
+		r = virtio_alloc_vq(vsc, &sc->sc_vq[2], 2,
+		    NBPG, 1, "control");
+		if (r != 0) {
+			aprint_error_dev(self, "failed to allocate "
+			    "a virtqueue for control channel\n");
+			goto skip;
 		}
+
+		sc->sc_vq[2].vq_done = vioif_ctrl_vq_done;
+		cv_init(&sc->sc_ctrl_wait, "ctrl_vq");
+		mutex_init(&sc->sc_ctrl_wait_lock, MUTEX_DEFAULT, IPL_NET);
+		sc->sc_ctrl_inuse = FREE;
+		virtio_start_vq_intr(vsc, &sc->sc_vq[2]);
+		vsc->sc_nvqs = 3;
 	}
+skip:
 
 #ifdef VIOIF_MPSAFE
 	flags = SOFTINT_NET | SOFTINT_MPSAFE;

Index: src/sys/dev/pci/virtio.c
diff -u src/sys/dev/pci/virtio.c:1.10 src/sys/dev/pci/virtio.c:1.11
--- src/sys/dev/pci/virtio.c:1.10	Thu Oct 15 02:40:38 2015
+++ src/sys/dev/pci/virtio.c	Mon Oct 26 01:44:48 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: virtio.c,v 1.10 2015/10/15 02:40:38 ozaki-r Exp $	*/
+/*	$NetBSD: virtio.c,v 1.11 2015/10/26 01:44:48 ozaki-r Exp $	*/
 
 /*
  * Copyright (c) 2010 Minoura Makoto.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: virtio.c,v 1.10 2015/10/15 02:40:38 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: virtio.c,v 1.11 2015/10/26 01:44:48 ozaki-r Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -49,6 +49,15 @@ static int	virtio_match(device_t, cfdata
 static void	virtio_attach(device_t, device_t, void *);
 static int	virtio_detach(device_t, int);
 static int	virtio_intr(void *arg);
+static int	virtio_msix_queue_intr(void *);
+static int	virtio_msix_config_intr(void *);
+static int	virtio_setup_msix_vectors(struct virtio_softc *);
+static int	virtio_setup_msix_interrupts(struct virtio_softc *,
+		    struct pci_attach_args *);
+static int	virtio_setup_intx_interrupt(struct virtio_softc *,
+		    struct pci_attach_args *);
+static int	virtio_setup_interrupts(struct virtio_softc *,
+		    struct pci_attach_args *);
 static void	virtio_soft_intr(void *arg);
 static void	virtio_init_vq(struct virtio_softc *,
 		    struct virtqueue *, const bool);
@@ -104,6 +113,203 @@ static const char *virtio_device_name[] 
 };
 #define NDEVNAMES	(sizeof(virtio_device_name)/sizeof(char*))
 
+#define VIRTIO_MSIX_CONFIG_VECTOR_INDEX	0
+#define VIRTIO_MSIX_QUEUE_VECTOR_INDEX	1
+
+static int
+virtio_setup_msix_vectors(struct virtio_softc *sc)
+{
+	int offset, vector, ret, qid;
+
+	offset = VIRTIO_CONFIG_MSI_CONFIG_VECTOR;
+	vector = VIRTIO_MSIX_CONFIG_VECTOR_INDEX;
+
+	bus_space_write_2(sc->sc_iot, sc->sc_ioh, offset, vector);
+	ret = bus_space_read_2(sc->sc_iot, sc->sc_ioh, offset);
+	aprint_debug_dev(sc->sc_dev, "expected=%d, actual=%d\n",
+	    vector, ret);
+	if (ret != vector)
+		return -1;
+
+	for (qid = 0; qid < sc->sc_nvqs; qid++) {
+		offset = VIRTIO_CONFIG_QUEUE_SELECT;
+		bus_space_write_2(sc->sc_iot, sc->sc_ioh, offset, qid);
+
+		offset = VIRTIO_CONFIG_MSI_QUEUE_VECTOR;
+		vector = VIRTIO_MSIX_QUEUE_VECTOR_INDEX;
+
+		bus_space_write_2(sc->sc_iot, sc->sc_ioh, offset, vector);
+		ret = bus_space_read_2(sc->sc_iot, sc->sc_ioh, offset);
+		aprint_debug_dev(sc->sc_dev, "expected=%d, actual=%d\n",
+		    vector, ret);
+		if (ret != vector)
+			return -1;
+	}
+
+	return 0;
+}
+
+static int
+virtio_setup_msix_interrupts(struct virtio_softc *sc,
+    struct pci_attach_args *pa)
+{
+	device_t self = sc->sc_dev;
+	pci_chipset_tag_t pc = pa->pa_pc;
+	char intrbuf[PCI_INTRSTR_LEN];
+	char const *intrstr;
+	int idx;
+
+	idx = VIRTIO_MSIX_CONFIG_VECTOR_INDEX;
+	if (sc->sc_flags & VIRTIO_F_PCI_INTR_MPSAFE)
+		pci_intr_setattr(pc, &sc->sc_ihp[idx], PCI_INTR_MPSAFE, true);
+
+	sc->sc_ihs[idx] = pci_intr_establish_xname(pc, sc->sc_ihp[idx], IPL_NET,
+	    virtio_msix_config_intr, sc, device_xname(sc->sc_dev));
+	if (sc->sc_ihs[idx] == NULL) {
+		aprint_error_dev(self, "couldn't establish MSI-X for config\n");
+		goto error;
+	}
+
+	idx = VIRTIO_MSIX_QUEUE_VECTOR_INDEX;
+	if (sc->sc_flags & VIRTIO_F_PCI_INTR_MPSAFE)
+		pci_intr_setattr(pc, &sc->sc_ihp[idx], PCI_INTR_MPSAFE, true);
+
+	sc->sc_ihs[idx] = pci_intr_establish_xname(pc, sc->sc_ihp[idx], IPL_NET,
+	    virtio_msix_queue_intr, sc, device_xname(sc->sc_dev));
+	if (sc->sc_ihs[idx] == NULL) {
+		aprint_error_dev(self, "couldn't establish MSI-X for queues\n");
+		goto error;
+	}
+
+	if (virtio_setup_msix_vectors(sc) != 0) {
+		aprint_error_dev(self, "couldn't setup MSI-X vectors\n");
+		goto error;
+	}
+
+	idx = VIRTIO_MSIX_CONFIG_VECTOR_INDEX;
+	intrstr = pci_intr_string(pc, sc->sc_ihp[idx], intrbuf, sizeof(intrbuf));
+	aprint_normal_dev(self, "config interrupting at %s\n", intrstr);
+	idx = VIRTIO_MSIX_QUEUE_VECTOR_INDEX;
+	intrstr = pci_intr_string(pc, sc->sc_ihp[idx], intrbuf, sizeof(intrbuf));
+	aprint_normal_dev(self, "queues interrupting at %s\n", intrstr);
+
+	return 0;
+
+error:
+	idx = VIRTIO_MSIX_CONFIG_VECTOR_INDEX;
+	if (sc->sc_ihs[idx] != NULL)
+		pci_intr_disestablish(sc->sc_pc, sc->sc_ihs[idx]);
+	idx = VIRTIO_MSIX_QUEUE_VECTOR_INDEX;
+	if (sc->sc_ihs[idx] != NULL)
+		pci_intr_disestablish(sc->sc_pc, sc->sc_ihs[idx]);
+
+	return -1;
+}
+
+static int
+virtio_setup_intx_interrupt(struct virtio_softc *sc, struct pci_attach_args *pa)
+{
+	device_t self = sc->sc_dev;
+	pci_chipset_tag_t pc = pa->pa_pc;
+	char intrbuf[PCI_INTRSTR_LEN];
+	char const *intrstr;
+
+	if (sc->sc_flags & VIRTIO_F_PCI_INTR_MPSAFE)
+		pci_intr_setattr(pc, &sc->sc_ihp[0], PCI_INTR_MPSAFE, true);
+
+	sc->sc_ihs[0] = pci_intr_establish_xname(pc, sc->sc_ihp[0],
+	    IPL_NET, virtio_intr, sc, device_xname(sc->sc_dev));
+	if (sc->sc_ihs[0] == NULL) {
+		aprint_error_dev(self, "couldn't establish INTx\n");
+		return -1;
+	}
+
+	intrstr = pci_intr_string(pc, sc->sc_ihp[0], intrbuf, sizeof(intrbuf));
+	aprint_normal_dev(self, "interrupting at %s\n", intrstr);
+
+	return 0;
+}
+
+static int
+virtio_setup_interrupts(struct virtio_softc *sc, struct pci_attach_args *pa)
+{
+	device_t self = sc->sc_dev;
+	pci_chipset_tag_t pc = pa->pa_pc;
+	int error;
+	int nmsix;
+	int counts[PCI_INTR_TYPE_SIZE];
+	pci_intr_type_t max_type;
+
+	nmsix = pci_msix_count(pa->pa_pc, pa->pa_tag);
+	aprint_debug_dev(self, "pci_msix_count=%d\n", nmsix);
+
+	/* We need at least two: one for config and the other for queues */
+	if ((sc->sc_flags & VIRTIO_F_PCI_INTR_MSIX) == 0 || nmsix < 2) {
+		/* Try INTx only */
+		max_type = PCI_INTR_TYPE_INTX;
+		counts[PCI_INTR_TYPE_INTX] = 1;
+	} else {
+		/* Try MSI-X first and INTx second */
+		max_type = PCI_INTR_TYPE_MSIX;
+		counts[PCI_INTR_TYPE_MSIX] = 2;
+		counts[PCI_INTR_TYPE_MSI] = 0;
+		counts[PCI_INTR_TYPE_INTX] = 1;
+	}
+
+ retry:
+	error = pci_intr_alloc(pa, &sc->sc_ihp, counts, max_type);
+	if (error != 0) {
+		aprint_error_dev(self, "couldn't map interrupt\n");
+		return -1;
+	}
+
+	if (pci_intr_type(sc->sc_ihp[0]) == PCI_INTR_TYPE_MSIX) {
+		sc->sc_ihs = kmem_alloc(sizeof(*sc->sc_ihs) * 2,
+		    KM_SLEEP);
+		if (sc->sc_ihs == NULL) {
+			pci_intr_release(pc, sc->sc_ihp, 2);
+
+			/* Retry INTx */
+			max_type = PCI_INTR_TYPE_INTX;
+			counts[PCI_INTR_TYPE_INTX] = 1;
+			goto retry;
+		}
+
+		error = virtio_setup_msix_interrupts(sc, pa);
+		if (error != 0) {
+			kmem_free(sc->sc_ihs, sizeof(*sc->sc_ihs) * 2);
+			pci_intr_release(pc, sc->sc_ihp, 2);
+
+			/* Retry INTx */
+			max_type = PCI_INTR_TYPE_INTX;
+			counts[PCI_INTR_TYPE_INTX] = 1;
+			goto retry;
+		}
+
+		sc->sc_ihs_num = 2;
+		sc->sc_config_offset = VIRTIO_CONFIG_DEVICE_CONFIG_MSI;
+	} else if (pci_intr_type(sc->sc_ihp[0]) == PCI_INTR_TYPE_INTX) {
+		sc->sc_ihs = kmem_alloc(sizeof(*sc->sc_ihs) * 1,
+		    KM_SLEEP);
+		if (sc->sc_ihs == NULL) {
+			pci_intr_release(pc, sc->sc_ihp, 1);
+			return -1;
+		}
+
+		error = virtio_setup_intx_interrupt(sc, pa);
+		if (error != 0) {
+			kmem_free(sc->sc_ihs, sizeof(*sc->sc_ihs) * 1);
+			pci_intr_release(pc, sc->sc_ihp, 1);
+			return -1;
+		}
+
+		sc->sc_ihs_num = 1;
+		sc->sc_config_offset = VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI;
+	}
+
+	return 0;
+}
+
 static void
 virtio_attach(device_t parent, device_t self, void *aux)
 {
@@ -113,9 +319,7 @@ virtio_attach(device_t parent, device_t 
 	pcitag_t tag = pa->pa_tag;
 	int revision;
 	pcireg_t id;
-	char const *intrstr;
-	pci_intr_handle_t ih;
-	char intrbuf[PCI_INTRSTR_LEN];
+	int r;
 
 	revision = PCI_REVISION(pa->pa_class);
 	if (revision != 0) {
@@ -166,29 +370,12 @@ virtio_attach(device_t parent, device_t 
 		return;
 	}
 
-	if (pci_intr_map(pa, &ih)) {
-		aprint_error_dev(self, "couldn't map interrupt\n");
-		virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_FAILED);
-		return;
-	}
-
-	intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf));
-
-	if (sc->sc_flags & VIRTIO_F_PCI_INTR_MPSAFE)
-		pci_intr_setattr(pc, &ih, PCI_INTR_MPSAFE, true);
-
-	sc->sc_ih = pci_intr_establish_xname(pc, ih, sc->sc_ipl, virtio_intr, sc,
-	    device_xname(sc->sc_dev));
-
-	if (sc->sc_ih == NULL) {
-		aprint_error_dev(self, "couldn't establish interrupt");
-		if (intrstr != NULL)
-			aprint_error(" at %s", intrstr);
-		aprint_error("\n");
+	r = virtio_setup_interrupts(sc, pa);
+	if (r != 0) {
+		aprint_error_dev(self, "failed to setup interrupts\n");
 		virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_FAILED);
 		return;
 	}
-	aprint_normal_dev(self, "interrupting at %s\n", intrstr);
 
 	sc->sc_soft_ih = NULL;
 	if (sc->sc_flags & VIRTIO_F_PCI_INTR_SOFTINT) {
@@ -211,6 +398,7 @@ virtio_detach(device_t self, int flags)
 {
 	struct virtio_softc *sc = device_private(self);
 	int r;
+	int i;
 
 	if (sc->sc_child != 0 && sc->sc_child != (void*)1) {
 		r = config_detach(sc->sc_child, flags);
@@ -219,10 +407,14 @@ virtio_detach(device_t self, int flags)
 	}
 	KASSERT(sc->sc_child == 0 || sc->sc_child == (void*)1);
 	KASSERT(sc->sc_vqs == 0);
-	if (sc->sc_ih != NULL) {
-		pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
-		sc->sc_ih = NULL;
+	for (i = 0; i < sc->sc_ihs_num; i++) {
+		if (sc->sc_ihs[i] == NULL)
+			continue;
+		pci_intr_disestablish(sc->sc_pc, sc->sc_ihs[i]);
 	}
+	pci_intr_release(sc->sc_pc, sc->sc_ihp, sc->sc_ihs_num);
+	kmem_free(sc->sc_ihs, sizeof(*sc->sc_ihs) * sc->sc_ihs_num);
+	sc->sc_ihs_num = 0;
 	if (sc->sc_iosize)
 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize);
 	sc->sc_iosize = 0;
@@ -278,6 +470,14 @@ virtio_reinit_start(struct virtio_softc 
 				  (vq->vq_dmamap->dm_segs[0].ds_addr
 				   / VIRTIO_PAGE_SIZE));
 	}
+
+	/* MSI-X should have more than one handles where INTx has just one */
+	if (sc->sc_ihs_num > 1) {
+		if (virtio_setup_msix_vectors(sc) != 0) {
+			aprint_error_dev(sc->sc_dev, "couldn't setup MSI-X vectors\n");
+			return;
+		}
+	}
 }
 
 void
@@ -411,6 +611,32 @@ virtio_intr(void *arg)
 	return r;
 }
 
+static int
+virtio_msix_queue_intr(void *arg)
+{
+	struct virtio_softc *sc = arg;
+	int r = 0;
+
+	if (sc->sc_intrhand != NULL) {
+		if (sc->sc_soft_ih != NULL)
+			softint_schedule(sc->sc_soft_ih);
+		else
+			r |= (sc->sc_intrhand)(sc);
+	}
+
+	return r;
+}
+
+static int
+virtio_msix_config_intr(void *arg)
+{
+	struct virtio_softc *sc = arg;
+
+	/* TODO: handle events */
+	aprint_debug_dev(sc->sc_dev, "%s\n", __func__);
+	return 1;
+}
+
 static void
 virtio_soft_intr(void *arg)
 {

Index: src/sys/dev/pci/virtioreg.h
diff -u src/sys/dev/pci/virtioreg.h:1.3 src/sys/dev/pci/virtioreg.h:1.4
--- src/sys/dev/pci/virtioreg.h:1.3	Mon May  4 14:08:57 2015
+++ src/sys/dev/pci/virtioreg.h	Mon Oct 26 01:44:48 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: virtioreg.h,v 1.3 2015/05/04 14:08:57 ozaki-r Exp $	*/
+/*	$NetBSD: virtioreg.h,v 1.4 2015/10/26 01:44:48 ozaki-r Exp $	*/
 
 /*
  * Copyright (c) 2010 Minoura Makoto.
@@ -96,6 +96,9 @@
 #define VIRTIO_CONFIG_CONFIG_VECTOR	20 /* 16bit, optional */
 #define VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI	20
 #define VIRTIO_CONFIG_DEVICE_CONFIG_MSI		24
+/* MSI/MSI-X */
+#define VIRTIO_CONFIG_MSI_CONFIG_VECTOR		20
+#define VIRTIO_CONFIG_MSI_QUEUE_VECTOR		22
 
 /* Virtqueue */
 /* This marks a buffer as continuing via the next field. */

Index: src/sys/dev/pci/virtiovar.h
diff -u src/sys/dev/pci/virtiovar.h:1.4 src/sys/dev/pci/virtiovar.h:1.5
--- src/sys/dev/pci/virtiovar.h:1.4	Fri Dec 19 06:54:40 2014
+++ src/sys/dev/pci/virtiovar.h	Mon Oct 26 01:44:48 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: virtiovar.h,v 1.4 2014/12/19 06:54:40 ozaki-r Exp $	*/
+/*	$NetBSD: virtiovar.h,v 1.5 2015/10/26 01:44:48 ozaki-r Exp $	*/
 
 /*
  * Copyright (c) 2010 Minoura Makoto.
@@ -125,7 +125,9 @@ struct virtio_softc {
 	bus_dma_tag_t		sc_dmat;
 
 	int			sc_ipl; /* set by child */
-	void			*sc_ih;
+	pci_intr_handle_t	*sc_ihp;
+	void			**sc_ihs;
+	int			sc_ihs_num;
 	void			*sc_soft_ih;
 
 	int			sc_flags; /* set by child */
@@ -151,6 +153,7 @@ struct virtio_softc {
 
 #define VIRTIO_F_PCI_INTR_MPSAFE	(1 << 0)
 #define VIRTIO_F_PCI_INTR_SOFTINT	(1 << 1)
+#define VIRTIO_F_PCI_INTR_MSIX		(1 << 2)
 
 /* public interface */
 uint32_t virtio_negotiate_features(struct virtio_softc*, uint32_t);

Reply via email to