Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/pci Support MSI-X in virtio
details: https://anonhg.NetBSD.org/src/rev/6e3d7a301c41
branches: trunk
changeset: 341204:6e3d7a301c41
user: ozaki-r <ozaki-r%NetBSD.org@localhost>
date: Mon Oct 26 01:44:48 2015 +0000
description:
Support MSI-X in virtio
Currently only vioif(4) uses the feature.
knakahara@ helped to migrate to pci_intr_alloc(9). Thanks!
diffstat:
sys/dev/pci/if_vioif.c | 71 +++++++----
sys/dev/pci/virtio.c | 282 +++++++++++++++++++++++++++++++++++++++++++----
sys/dev/pci/virtioreg.h | 5 +-
sys/dev/pci/virtiovar.h | 7 +-
4 files changed, 306 insertions(+), 59 deletions(-)
diffs (truncated from 523 to 300 lines):
diff -r f7cc68cd173d -r 6e3d7a301c41 sys/dev/pci/if_vioif.c
--- a/sys/dev/pci/if_vioif.c Sun Oct 25 23:00:00 2015 +0000
+++ b/sys/dev/pci/if_vioif.c Mon Oct 26 01:44:48 2015 +0000
@@ -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 @@
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 @@
#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 @@
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 @@
#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;
diff -r f7cc68cd173d -r 6e3d7a301c41 sys/dev/pci/virtio.c
--- a/sys/dev/pci/virtio.c Sun Oct 25 23:00:00 2015 +0000
+++ b/sys/dev/pci/virtio.c Mon Oct 26 01:44:48 2015 +0000
@@ -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 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 @@
};
#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;
+ }
+
Home |
Main Index |
Thread Index |
Old Index