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
This commit is contained in:
Bryan Venteicher 2013-07-04 17:59:09 +00:00
parent abd6790ce8
commit 62a69c4153
3 changed files with 243 additions and 202 deletions

View File

@ -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(struct vtpci_softc *, const char *,
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_msix_interrupts(struct vtpci_softc *,
static int vtpci_setup_pervq_msix_interrupts(struct vtpci_softc *,
enum intr_type);
static int vtpci_setup_interrupts(struct vtpci_softc *, enum intr_type);
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_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 flags, int nvqs,
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 flags, int nvqs,
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, int nvectors)
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_softc *sc)
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,7 +873,22 @@ vtpci_alloc_intr_legacy(struct vtpci_softc *sc)
{
sc->vtpci_flags |= VTPCI_FLAG_LEGACY;
sc->vtpci_nintr_res = 1;
return (0);
}
static int
vtpci_alloc_interrupt(struct vtpci_softc *sc, int rid, int flags,
struct vtpci_interrupt *intr)
{
struct resource *irq;
irq = bus_alloc_resource_any(sc->vtpci_dev, SYS_RES_IRQ, &rid, flags);
if (irq == NULL)
return (ENXIO);
intr->vti_irq = irq;
intr->vti_rid = rid;
return (0);
}
@ -876,46 +896,39 @@ vtpci_alloc_intr_legacy(struct vtpci_softc *sc)
static int
vtpci_alloc_intr_resources(struct vtpci_softc *sc)
{
device_t dev;
struct resource *irq;
struct vtpci_virtqueue *vqx;
int i, rid, flags, res_idx;
struct vtpci_interrupt *intr;
int i, rid, flags, nvq_intrs, error;
dev = sc->vtpci_dev;
rid = 0;
flags = RF_ACTIVE;
if (sc->vtpci_flags & VTPCI_FLAG_LEGACY) {
rid = 0;
flags = RF_ACTIVE | RF_SHAREABLE;
} else {
if (sc->vtpci_flags & VTPCI_FLAG_LEGACY)
flags |= RF_SHAREABLE;
else
rid = 1;
flags = RF_ACTIVE;
}
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);
sc->vtpci_intr_res[i].irq = irq;
sc->vtpci_intr_res[i].rid = rid++;
}
/*
* 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);
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;
/* 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);
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_softc *sc)
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_pervq_msix_interrupts(struct vtpci_softc *sc, enum intr_type type)
{
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_intr_resource *ires;
struct vtpci_virtqueue *vqx;
int i, error;
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;
&intr->vti_handler);
} else
error = vtpci_setup_pervq_msix_interrupts(sc, type);
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);
return (error);
return (error ? error : vtpci_set_host_msix_vectors(sc));
}
static int
@ -990,7 +1007,7 @@ vtpci_setup_interrupts(struct vtpci_softc *sc, enum intr_type type)
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_softc *sc, enum intr_type type)
}
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_softc *sc, int offset, int res_idx)
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_softc *sc, int idx)
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_softc *sc, int idx)
}
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;
}
}
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);
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 (ires->irq != NULL) {
bus_release_resource(dev, SYS_RES_IRQ, ires->rid,
ires->irq);
ires->irq = NULL;
}
ires->rid = -1;
}
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,18 +1167,31 @@ 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];
virtqueue_free(vqx->vq);
vqx->vq = NULL;
vtpci_select_virtqueue(sc, idx);
vtpci_write_config_4(sc, VIRTIO_PCI_QUEUE_PFN, 0);
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)
{
@ -1160,14 +1211,6 @@ vtpci_cleanup_setup_intr_attempt(struct vtpci_softc *sc)
vtpci_free_interrupts(sc);
}
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

View File

@ -70,11 +70,6 @@ struct vq_alloc_info;
#define VIRTIO_TRANSPORT_F_START 28
#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

View File

@ -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