Author: bryanv
Date: Thu Jul  4 17:59:09 2013
New Revision: 252708
URL: http://svnweb.freebsd.org/changeset/base/252708

Log:
  Merge virtio_pci changes from projects/virtio
  
  This commit is primarily a significant cleanup to the interrupt
  allocation code that had gotten a bit jumbled from having to
  support per-vq MSIX, shared MSIX, MSI, and legacy style interrupts.
  
  Contains projects/virtio commits:
  
  r246064:
      virtio_pci: Rewrite allocation of interrupts
  r246065:
      virtio_pci: Remove spaces before a tab
  r246066:
      virtio_pci: Dynamically allocate the virtqueue array
  r246304:
      virtio_pci: Clean up after failed virtqueue alloc attempt
  r246305:
      virtio_pci: Move no interrupt check into the PCI interrupt handlers
  r246308:
      virtio_pci: Remove unused variable
  
  MFC after:    1 month

Modified:
  head/sys/dev/virtio/pci/virtio_pci.c
  head/sys/dev/virtio/virtio.h
  head/sys/dev/virtio/virtqueue.c

Modified: head/sys/dev/virtio/pci/virtio_pci.c
==============================================================================
--- head/sys/dev/virtio/pci/virtio_pci.c        Thu Jul  4 17:57:26 2013        
(r252707)
+++ head/sys/dev/virtio/pci/virtio_pci.c        Thu Jul  4 17:59:09 2013        
(r252708)
@@ -51,6 +51,17 @@ __FBSDID("$FreeBSD$");
 #include "virtio_bus_if.h"
 #include "virtio_if.h"
 
+struct vtpci_interrupt {
+       struct resource         *vti_irq;
+       int                      vti_rid;
+       void                    *vti_handler;
+};
+
+struct vtpci_virtqueue {
+       struct virtqueue        *vtv_vq;
+       int                      vtv_no_intr;
+};
+
 struct vtpci_softc {
        device_t                         vtpci_dev;
        struct resource                 *vtpci_res;
@@ -69,40 +80,22 @@ struct vtpci_softc {
        device_t                         vtpci_child_dev;
        struct virtio_feature_desc      *vtpci_child_feat_desc;
 
-       /*
-        * Ideally, each virtqueue that the driver provides a callback for
-        * will receive its own MSIX vector. If there are not sufficient
-        * vectors available, we will then attempt to have all the VQs
-        * share one vector. Note that when using MSIX, the configuration
-        * changed notifications must be on their own vector.
-        *
-        * If MSIX is not available, we will attempt to have the whole
-        * device share one MSI vector, and then, finally, one legacy
-        * interrupt.
-        */
        int                              vtpci_nvqs;
-       struct vtpci_virtqueue {
-               struct virtqueue *vq;
-               /* Device did not provide a callback for this virtqueue. */
-               int               no_intr;
-               /* Index into vtpci_intr_res[] below. Unused, then -1. */
-               int               ires_idx;
-       } vtpci_vqx[VIRTIO_MAX_VIRTQUEUES];
+       struct vtpci_virtqueue          *vtpci_vqs;
 
        /*
-        * When using MSIX interrupts, the first element of vtpci_intr_res[]
-        * is always the configuration changed notifications. The remaining
-        * element(s) are used for the virtqueues.
+        * Ideally, each virtqueue that the driver provides a callback for will
+        * receive its own MSIX vector. If there are not sufficient vectors
+        * available, then attempt to have all the VQs share one vector. For
+        * MSIX, the configuration changed notifications must be on their own
+        * vector.
         *
-        * With MSI and legacy interrupts, only the first element of
-        * vtpci_intr_res[] is used.
+        * If MSIX is not available, we will attempt to have the whole device
+        * share one MSI vector, and then, finally, one legacy interrupt.
         */
-       int                              vtpci_nintr_res;
-       struct vtpci_intr_resource {
-               struct resource *irq;
-               int              rid;
-               void            *intrhand;
-       } vtpci_intr_res[1 + VIRTIO_MAX_VIRTQUEUES];
+       struct vtpci_interrupt           vtpci_device_interrupt;
+       struct vtpci_interrupt          *vtpci_msix_vq_interrupts;
+       int                              vtpci_nmsix_resources;
 };
 
 static int     vtpci_probe(device_t);
@@ -134,28 +127,35 @@ static void       vtpci_describe_features(stru
                    uint64_t);
 static void    vtpci_probe_and_attach_child(struct vtpci_softc *);
 
-static int     vtpci_alloc_msix(struct vtpci_softc *, int);
-static int     vtpci_alloc_msi(struct vtpci_softc *);
-static int     vtpci_alloc_intr_msix_pervq(struct vtpci_softc *);
-static int     vtpci_alloc_intr_msix_shared(struct vtpci_softc *);
-static int     vtpci_alloc_intr_msi(struct vtpci_softc *);
-static int     vtpci_alloc_intr_legacy(struct vtpci_softc *);
+static int     vtpci_alloc_msix(struct vtpci_softc *, int);
+static int     vtpci_alloc_msi(struct vtpci_softc *);
+static int     vtpci_alloc_intr_msix_pervq(struct vtpci_softc *);
+static int     vtpci_alloc_intr_msix_shared(struct vtpci_softc *);
+static int     vtpci_alloc_intr_msi(struct vtpci_softc *);
+static int     vtpci_alloc_intr_legacy(struct vtpci_softc *);
+static int     vtpci_alloc_interrupt(struct vtpci_softc *, int, int,
+                   struct vtpci_interrupt *);
 static int     vtpci_alloc_intr_resources(struct vtpci_softc *);
 
-static int     vtpci_setup_legacy_interrupt(struct vtpci_softc *,
+static int     vtpci_setup_legacy_interrupt(struct vtpci_softc *,
+                   enum intr_type);
+static int     vtpci_setup_pervq_msix_interrupts(struct vtpci_softc *,
                    enum intr_type);
-static int     vtpci_setup_msix_interrupts(struct vtpci_softc *,
+static int     vtpci_setup_msix_interrupts(struct vtpci_softc *,
                    enum intr_type);
-static int     vtpci_setup_interrupts(struct vtpci_softc *, enum intr_type);
+static int     vtpci_setup_interrupts(struct vtpci_softc *, enum intr_type);
 
-static int     vtpci_register_msix_vector(struct vtpci_softc *, int, int);
-static int     vtpci_set_host_msix_vectors(struct vtpci_softc *);
-static int     vtpci_reinit_virtqueue(struct vtpci_softc *, int);
+static int     vtpci_register_msix_vector(struct vtpci_softc *, int,
+                   struct vtpci_interrupt *);
+static int     vtpci_set_host_msix_vectors(struct vtpci_softc *);
+static int     vtpci_reinit_virtqueue(struct vtpci_softc *, int);
 
+static void    vtpci_free_interrupt(struct vtpci_softc *,
+                   struct vtpci_interrupt *);
 static void    vtpci_free_interrupts(struct vtpci_softc *);
 static void    vtpci_free_virtqueues(struct vtpci_softc *);
-static void    vtpci_cleanup_setup_intr_attempt(struct vtpci_softc *);
 static void    vtpci_release_child_resources(struct vtpci_softc *);
+static void    vtpci_cleanup_setup_intr_attempt(struct vtpci_softc *);
 static void    vtpci_reset(struct vtpci_softc *);
 
 static void    vtpci_select_virtqueue(struct vtpci_softc *, int);
@@ -480,15 +480,19 @@ vtpci_alloc_virtqueues(device_t dev, int
        uint16_t size;
 
        sc = device_get_softc(dev);
-       error = 0;
 
        if (sc->vtpci_nvqs != 0)
                return (EALREADY);
-       if (nvqs <= 0 || nvqs > VIRTIO_MAX_VIRTQUEUES)
+       if (nvqs <= 0)
                return (EINVAL);
 
+       sc->vtpci_vqs = malloc(nvqs * sizeof(struct vtpci_virtqueue),
+           M_DEVBUF, M_NOWAIT | M_ZERO);
+       if (sc->vtpci_vqs == NULL)
+               return (ENOMEM);
+
        for (idx = 0; idx < nvqs; idx++) {
-               vqx = &sc->vtpci_vqx[idx];
+               vqx = &sc->vtpci_vqs[idx];
                info = &vq_info[idx];
 
                vtpci_select_virtqueue(sc, idx);
@@ -505,12 +509,15 @@ vtpci_alloc_virtqueues(device_t dev, int
                vtpci_write_config_4(sc, VIRTIO_PCI_QUEUE_PFN,
                    virtqueue_paddr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
 
-               vqx->vq = *info->vqai_vq = vq;
-               vqx->no_intr = info->vqai_intr == NULL;
+               vqx->vtv_vq = *info->vqai_vq = vq;
+               vqx->vtv_no_intr = info->vqai_intr == NULL;
 
                sc->vtpci_nvqs++;
        }
 
+       if (error)
+               vtpci_free_virtqueues(sc);
+
        return (error);
 }
 
@@ -771,7 +778,7 @@ vtpci_alloc_msix(struct vtpci_softc *sc,
 
        cnt = required;
        if (pci_alloc_msix(dev, &cnt) == 0 && cnt >= required) {
-               sc->vtpci_nintr_res = required;
+               sc->vtpci_nmsix_resources = required;
                return (0);
        }
 
@@ -794,10 +801,8 @@ vtpci_alloc_msi(struct vtpci_softc *sc)
                return (1);
 
        cnt = required;
-       if (pci_alloc_msi(dev, &cnt) == 0 && cnt >= required) {
-               sc->vtpci_nintr_res = required;
+       if (pci_alloc_msi(dev, &cnt) == 0 && cnt >= required)
                return (0);
-       }
 
        pci_release_msi(dev);
 
@@ -814,7 +819,7 @@ vtpci_alloc_intr_msix_pervq(struct vtpci
                return (ENOTSUP);
 
        for (nvectors = 0, i = 0; i < sc->vtpci_nvqs; i++) {
-               if (sc->vtpci_vqx[i].no_intr == 0)
+               if (sc->vtpci_vqs[i].vtv_no_intr == 0)
                        nvectors++;
        }
 
@@ -868,54 +873,62 @@ vtpci_alloc_intr_legacy(struct vtpci_sof
 {
 
        sc->vtpci_flags |= VTPCI_FLAG_LEGACY;
-       sc->vtpci_nintr_res = 1;
 
        return (0);
 }
 
 static int
-vtpci_alloc_intr_resources(struct vtpci_softc *sc)
+vtpci_alloc_interrupt(struct vtpci_softc *sc, int rid, int flags,
+    struct vtpci_interrupt *intr)
 {
-       device_t dev;
        struct resource *irq;
-       struct vtpci_virtqueue *vqx;
-       int i, rid, flags, res_idx;
 
-       dev = sc->vtpci_dev;
+       irq = bus_alloc_resource_any(sc->vtpci_dev, SYS_RES_IRQ, &rid, flags);
+       if (irq == NULL)
+               return (ENXIO);
 
-       if (sc->vtpci_flags & VTPCI_FLAG_LEGACY) {
-               rid = 0;
-               flags = RF_ACTIVE | RF_SHAREABLE;
-       } else {
-               rid = 1;
-               flags = RF_ACTIVE;
-       }
+       intr->vti_irq = irq;
+       intr->vti_rid = rid;
 
-       for (i = 0; i < sc->vtpci_nintr_res; i++) {
-               irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, flags);
-               if (irq == NULL)
-                       return (ENXIO);
+       return (0);
+}
 
-               sc->vtpci_intr_res[i].irq = irq;
-               sc->vtpci_intr_res[i].rid = rid++;
-       }
+static int
+vtpci_alloc_intr_resources(struct vtpci_softc *sc)
+{
+       struct vtpci_interrupt *intr;
+       int i, rid, flags, nvq_intrs, error;
+
+       rid = 0;
+       flags = RF_ACTIVE;
+
+       if (sc->vtpci_flags & VTPCI_FLAG_LEGACY)
+               flags |= RF_SHAREABLE;
+       else
+               rid = 1;
 
        /*
-        * Map the virtqueue into the correct index in vq_intr_res[]. The
-        * first index is reserved for configuration changed notifications.
+        * For legacy and MSI interrupts, this single resource handles all
+        * interrupts. For MSIX, this resource is used for the configuration
+        * changed interrupt.
         */
-       for (i = 0, res_idx = 1; i < sc->vtpci_nvqs; i++) {
-               vqx = &sc->vtpci_vqx[i];
+       intr = &sc->vtpci_device_interrupt;
+       error = vtpci_alloc_interrupt(sc, rid, flags, intr);
+       if (error || sc->vtpci_flags & (VTPCI_FLAG_LEGACY | VTPCI_FLAG_MSI))
+               return (error);
+
+       /* Subtract one for the configuration changed interrupt. */
+       nvq_intrs = sc->vtpci_nmsix_resources - 1;
+
+       intr = sc->vtpci_msix_vq_interrupts = malloc(nvq_intrs *
+           sizeof(struct vtpci_interrupt), M_DEVBUF, M_NOWAIT | M_ZERO);
+       if (sc->vtpci_msix_vq_interrupts == NULL)
+               return (ENOMEM);
 
-               if (sc->vtpci_flags & VTPCI_FLAG_MSIX) {
-                       if (vqx->no_intr != 0)
-                               vqx->ires_idx = -1;
-                       else if (sc->vtpci_flags & VTPCI_FLAG_SHARED_MSIX)
-                               vqx->ires_idx = res_idx;
-                       else
-                               vqx->ires_idx = res_idx++;
-               } else
-                       vqx->ires_idx = -1;
+       for (i = 0, rid++; i < nvq_intrs; i++, rid++, intr++) {
+               error = vtpci_alloc_interrupt(sc, rid, flags, intr);
+               if (error)
+                       return (error);
        }
 
        return (0);
@@ -924,63 +937,67 @@ vtpci_alloc_intr_resources(struct vtpci_
 static int
 vtpci_setup_legacy_interrupt(struct vtpci_softc *sc, enum intr_type type)
 {
-       device_t dev;
-       struct vtpci_intr_resource *ires;
+       struct vtpci_interrupt *intr;
        int error;
 
-       dev = sc->vtpci_dev;
-
-       ires = &sc->vtpci_intr_res[0];
-       error = bus_setup_intr(dev, ires->irq, type, NULL, vtpci_legacy_intr,
-           sc, &ires->intrhand);
+       intr = &sc->vtpci_device_interrupt;
+       error = bus_setup_intr(sc->vtpci_dev, intr->vti_irq, type, NULL,
+           vtpci_legacy_intr, sc, &intr->vti_handler);
 
        return (error);
 }
 
 static int
-vtpci_setup_msix_interrupts(struct vtpci_softc *sc, enum intr_type type)
+vtpci_setup_pervq_msix_interrupts(struct vtpci_softc *sc, enum intr_type type)
 {
-       device_t dev;
-       struct vtpci_intr_resource *ires;
        struct vtpci_virtqueue *vqx;
+       struct vtpci_interrupt *intr;
        int i, error;
 
+       intr = sc->vtpci_msix_vq_interrupts;
+
+       for (i = 0; i < sc->vtpci_nvqs; i++) {
+               vqx = &sc->vtpci_vqs[i];
+
+               if (vqx->vtv_no_intr)
+                       continue;
+
+               error = bus_setup_intr(sc->vtpci_dev, intr->vti_irq, type,
+                   vtpci_vq_intr_filter, vtpci_vq_intr, vqx->vtv_vq,
+                   &intr->vti_handler);
+               if (error)
+                       return (error);
+
+               intr++;
+       }
+
+       return (0);
+}
+
+static int
+vtpci_setup_msix_interrupts(struct vtpci_softc *sc, enum intr_type type)
+{
+       device_t dev;
+       struct vtpci_interrupt *intr;
+       int error;
+
        dev = sc->vtpci_dev;
+       intr = &sc->vtpci_device_interrupt;
 
-       /*
-        * The first MSIX vector is used for configuration changed interrupts.
-        */
-       ires = &sc->vtpci_intr_res[0];
-       error = bus_setup_intr(dev, ires->irq, type, NULL, vtpci_config_intr,
-           sc, &ires->intrhand);
+       error = bus_setup_intr(dev, intr->vti_irq, type, NULL,
+           vtpci_config_intr, sc, &intr->vti_handler);
        if (error)
                return (error);
 
        if (sc->vtpci_flags & VTPCI_FLAG_SHARED_MSIX) {
-               ires = &sc->vtpci_intr_res[1];
-
-               error = bus_setup_intr(dev, ires->irq, type,
+               intr = sc->vtpci_msix_vq_interrupts;
+               error = bus_setup_intr(dev, intr->vti_irq, type,
                    vtpci_vq_shared_intr_filter, vtpci_vq_shared_intr, sc,
-                   &ires->intrhand);
-       } else {
-               for (i = 0; i < sc->vtpci_nvqs; i++) {
-                       vqx = &sc->vtpci_vqx[i];
-                       if (vqx->ires_idx < 1)
-                               continue;
-
-                       ires = &sc->vtpci_intr_res[vqx->ires_idx];
-                       error = bus_setup_intr(dev, ires->irq, type,
-                           vtpci_vq_intr_filter, vtpci_vq_intr, vqx->vq,
-                           &ires->intrhand);
-                       if (error)
-                               break;
-               }
-       }
-
-       if (error == 0)
-               error = vtpci_set_host_msix_vectors(sc);
+                   &intr->vti_handler);
+       } else
+               error = vtpci_setup_pervq_msix_interrupts(sc, type);
 
-       return (error);
+       return (error ? error : vtpci_set_host_msix_vectors(sc));
 }
 
 static int
@@ -990,7 +1007,7 @@ vtpci_setup_interrupts(struct vtpci_soft
 
        type |= INTR_MPSAFE;
        KASSERT(sc->vtpci_flags & VTPCI_FLAG_ITYPE_MASK,
-           ("no interrupt type selected: %#x", sc->vtpci_flags));
+           ("%s: no interrupt type selected %#x", __func__, sc->vtpci_flags));
 
        error = vtpci_alloc_intr_resources(sc);
        if (error)
@@ -1007,34 +1024,24 @@ vtpci_setup_interrupts(struct vtpci_soft
 }
 
 static int
-vtpci_register_msix_vector(struct vtpci_softc *sc, int offset, int res_idx)
+vtpci_register_msix_vector(struct vtpci_softc *sc, int offset,
+    struct vtpci_interrupt *intr)
 {
        device_t dev;
-       uint16_t vector, rdvector;
+       uint16_t vector;
 
        dev = sc->vtpci_dev;
 
-       if (res_idx != -1) {
+       if (intr != NULL) {
                /* Map from guest rid to host vector. */
-               vector = sc->vtpci_intr_res[res_idx].rid - 1;
+               vector = intr->vti_rid - 1;
        } else
                vector = VIRTIO_MSI_NO_VECTOR;
 
-       /*
-        * Assert the first resource is always used for the configuration
-        * changed interrupts.
-        */
-       if (res_idx == 0) {
-               KASSERT(vector == 0 && offset == VIRTIO_MSI_CONFIG_VECTOR,
-                   ("bad first res use vector:%d offset:%d", vector, offset));
-       } else
-               KASSERT(offset == VIRTIO_MSI_QUEUE_VECTOR, ("bad offset"));
-
        vtpci_write_config_2(sc, offset, vector);
 
        /* Read vector to determine if the host had sufficient resources. */
-       rdvector = vtpci_read_config_2(sc, offset);
-       if (rdvector != vector) {
+       if (vtpci_read_config_2(sc, offset) != vector) {
                device_printf(dev,
                    "insufficient host resources for MSIX interrupts\n");
                return (ENODEV);
@@ -1046,24 +1053,40 @@ vtpci_register_msix_vector(struct vtpci_
 static int
 vtpci_set_host_msix_vectors(struct vtpci_softc *sc)
 {
-       struct vtpci_virtqueue *vqx;
-       int idx, error;
+       struct vtpci_interrupt *intr, *tintr;
+       int idx, offset, error;
 
-       error = vtpci_register_msix_vector(sc, VIRTIO_MSI_CONFIG_VECTOR, 0);
+       intr = &sc->vtpci_device_interrupt;
+       offset = VIRTIO_MSI_CONFIG_VECTOR;
+
+       error = vtpci_register_msix_vector(sc, offset, intr);
        if (error)
                return (error);
 
-       for (idx = 0; idx < sc->vtpci_nvqs; idx++) {
-               vqx = &sc->vtpci_vqx[idx];
+       intr = sc->vtpci_msix_vq_interrupts;
+       offset = VIRTIO_MSI_QUEUE_VECTOR;
 
+       for (idx = 0; idx < sc->vtpci_nvqs; idx++) {
                vtpci_select_virtqueue(sc, idx);
-               error = vtpci_register_msix_vector(sc, VIRTIO_MSI_QUEUE_VECTOR,
-                   vqx->ires_idx);
+
+               if (sc->vtpci_vqs[idx].vtv_no_intr)
+                       tintr = NULL;
+               else
+                       tintr = intr;
+
+               error = vtpci_register_msix_vector(sc, offset, tintr);
                if (error)
-                       return (error);
+                       break;
+
+               /*
+                * For shared MSIX, all the virtqueues share the first
+                * interrupt.
+                */
+               if ((sc->vtpci_flags & VTPCI_FLAG_SHARED_MSIX) == 0)
+                       intr++;
        }
 
-       return (0);
+       return (error);
 }
 
 static int
@@ -1074,10 +1097,10 @@ vtpci_reinit_virtqueue(struct vtpci_soft
        int error;
        uint16_t size;
 
-       vqx = &sc->vtpci_vqx[idx];
-       vq = vqx->vq;
+       vqx = &sc->vtpci_vqs[idx];
+       vq = vqx->vtv_vq;
 
-       KASSERT(vq != NULL, ("vq %d not allocated", idx));
+       KASSERT(vq != NULL, ("%s: vq %d not allocated", __func__, idx));
 
        vtpci_select_virtqueue(sc, idx);
        size = vtpci_read_config_2(sc, VIRTIO_PCI_QUEUE_NUM);
@@ -1093,35 +1116,50 @@ vtpci_reinit_virtqueue(struct vtpci_soft
 }
 
 static void
-vtpci_free_interrupts(struct vtpci_softc *sc)
+vtpci_free_interrupt(struct vtpci_softc *sc, struct vtpci_interrupt *intr)
 {
        device_t dev;
-       struct vtpci_intr_resource *ires;
-       int i;
 
        dev = sc->vtpci_dev;
 
-       for (i = 0; i < sc->vtpci_nintr_res; i++) {
-               ires = &sc->vtpci_intr_res[i];
+       if (intr->vti_handler != NULL) {
+               bus_teardown_intr(dev, intr->vti_irq, intr->vti_handler);
+               intr->vti_handler = NULL;
+       }
 
-               if (ires->intrhand != NULL) {
-                       bus_teardown_intr(dev, ires->irq, ires->intrhand);
-                       ires->intrhand = NULL;
-               }
+       if (intr->vti_irq != NULL) {
+               bus_release_resource(dev, SYS_RES_IRQ, intr->vti_rid,
+                   intr->vti_irq);
+               intr->vti_irq = NULL;
+               intr->vti_rid = -1;
+       }
+}
 
-               if (ires->irq != NULL) {
-                       bus_release_resource(dev, SYS_RES_IRQ, ires->rid,
-                           ires->irq);
-                       ires->irq = NULL;
-               }
+static void
+vtpci_free_interrupts(struct vtpci_softc *sc)
+{
+       struct vtpci_interrupt *intr;
+       int i, nvq_intrs;
+
+       vtpci_free_interrupt(sc, &sc->vtpci_device_interrupt);
 
-               ires->rid = -1;
+       if (sc->vtpci_nmsix_resources != 0) {
+               nvq_intrs = sc->vtpci_nmsix_resources - 1;
+               sc->vtpci_nmsix_resources = 0;
+
+               intr = sc->vtpci_msix_vq_interrupts;
+               if (intr != NULL) {
+                       for (i = 0; i < nvq_intrs; i++, intr++)
+                               vtpci_free_interrupt(sc, intr);
+
+                       free(sc->vtpci_msix_vq_interrupts, M_DEVBUF);
+                       sc->vtpci_msix_vq_interrupts = NULL;
+               }
        }
 
        if (sc->vtpci_flags & (VTPCI_FLAG_MSI | VTPCI_FLAG_MSIX))
-               pci_release_msi(dev);
+               pci_release_msi(sc->vtpci_dev);
 
-       sc->vtpci_nintr_res = 0;
        sc->vtpci_flags &= ~VTPCI_FLAG_ITYPE_MASK;
 }
 
@@ -1129,19 +1167,32 @@ static void
 vtpci_free_virtqueues(struct vtpci_softc *sc)
 {
        struct vtpci_virtqueue *vqx;
-       int i;
+       int idx;
 
-       for (i = 0; i < sc->vtpci_nvqs; i++) {
-               vqx = &sc->vtpci_vqx[i];
+       for (idx = 0; idx < sc->vtpci_nvqs; idx++) {
+               vqx = &sc->vtpci_vqs[idx];
+
+               vtpci_select_virtqueue(sc, idx);
+               vtpci_write_config_4(sc, VIRTIO_PCI_QUEUE_PFN, 0);
 
-               virtqueue_free(vqx->vq);
-               vqx->vq = NULL;
+               virtqueue_free(vqx->vtv_vq);
+               vqx->vtv_vq = NULL;
        }
 
+       free(sc->vtpci_vqs, M_DEVBUF);
+       sc->vtpci_vqs = NULL;
        sc->vtpci_nvqs = 0;
 }
 
 static void
+vtpci_release_child_resources(struct vtpci_softc *sc)
+{
+
+       vtpci_free_interrupts(sc);
+       vtpci_free_virtqueues(sc);
+}
+
+static void
 vtpci_cleanup_setup_intr_attempt(struct vtpci_softc *sc)
 {
        int idx;
@@ -1161,14 +1212,6 @@ vtpci_cleanup_setup_intr_attempt(struct 
 }
 
 static void
-vtpci_release_child_resources(struct vtpci_softc *sc)
-{
-
-       vtpci_free_interrupts(sc);
-       vtpci_free_virtqueues(sc);
-}
-
-static void
 vtpci_reset(struct vtpci_softc *sc)
 {
 
@@ -1195,7 +1238,7 @@ vtpci_legacy_intr(void *xsc)
        uint8_t isr;
 
        sc = xsc;
-       vqx = &sc->vtpci_vqx[0];
+       vqx = &sc->vtpci_vqs[0];
 
        /* Reading the ISR also clears it. */
        isr = vtpci_read_config_1(sc, VIRTIO_PCI_ISR);
@@ -1204,8 +1247,10 @@ vtpci_legacy_intr(void *xsc)
                vtpci_config_intr(sc);
 
        if (isr & VIRTIO_PCI_ISR_INTR) {
-               for (i = 0; i < sc->vtpci_nvqs; i++, vqx++)
-                       virtqueue_intr(vqx->vq);
+               for (i = 0; i < sc->vtpci_nvqs; i++, vqx++) {
+                       if (vqx->vtv_no_intr == 0)
+                               virtqueue_intr(vqx->vtv_vq);
+               }
        }
 }
 
@@ -1218,10 +1263,12 @@ vtpci_vq_shared_intr_filter(void *xsc)
 
        rc = 0;
        sc = xsc;
-       vqx = &sc->vtpci_vqx[0];
+       vqx = &sc->vtpci_vqs[0];
 
-       for (i = 0; i < sc->vtpci_nvqs; i++, vqx++)
-               rc |= virtqueue_intr_filter(vqx->vq);
+       for (i = 0; i < sc->vtpci_nvqs; i++, vqx++) {
+               if (vqx->vtv_no_intr == 0)
+                       rc |= virtqueue_intr_filter(vqx->vtv_vq);
+       }
 
        return (rc ? FILTER_SCHEDULE_THREAD : FILTER_STRAY);
 }
@@ -1234,10 +1281,12 @@ vtpci_vq_shared_intr(void *xsc)
        int i;
 
        sc = xsc;
-       vqx = &sc->vtpci_vqx[0];
+       vqx = &sc->vtpci_vqs[0];
 
-       for (i = 0; i < sc->vtpci_nvqs; i++, vqx++)
-               virtqueue_intr(vqx->vq);
+       for (i = 0; i < sc->vtpci_nvqs; i++, vqx++) {
+               if (vqx->vtv_no_intr == 0)
+                       virtqueue_intr(vqx->vtv_vq);
+       }
 }
 
 static int

Modified: head/sys/dev/virtio/virtio.h
==============================================================================
--- head/sys/dev/virtio/virtio.h        Thu Jul  4 17:57:26 2013        
(r252707)
+++ head/sys/dev/virtio/virtio.h        Thu Jul  4 17:59:09 2013        
(r252708)
@@ -71,11 +71,6 @@ struct vq_alloc_info;
 #define VIRTIO_TRANSPORT_F_END         32
 
 /*
- * Maximum number of virtqueues per device.
- */
-#define VIRTIO_MAX_VIRTQUEUES 8
-
-/*
  * Each virtqueue indirect descriptor list must be physically contiguous.
  * To allow us to malloc(9) each list individually, limit the number
  * supported to what will fit in one page. With 4KB pages, this is a limit

Modified: head/sys/dev/virtio/virtqueue.c
==============================================================================
--- head/sys/dev/virtio/virtqueue.c     Thu Jul  4 17:57:26 2013        
(r252707)
+++ head/sys/dev/virtio/virtqueue.c     Thu Jul  4 17:59:09 2013        
(r252708)
@@ -417,8 +417,6 @@ int
 virtqueue_intr_filter(struct virtqueue *vq)
 {
 
-       if (__predict_false(vq->vq_intrhand == NULL))
-               return (0);
        if (vq->vq_used_cons_idx == vq->vq_ring.used->idx)
                return (0);
 
@@ -431,8 +429,7 @@ void
 virtqueue_intr(struct virtqueue *vq)
 {
 
-       if (__predict_true(vq->vq_intrhand != NULL))
-               vq->vq_intrhand(vq->vq_intrhand_arg);
+       vq->vq_intrhand(vq->vq_intrhand_arg);
 }
 
 int
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to