Convert VirtIO to use ithreads instead of taskqueues

Contains projects/virtio commits:

r245709:
    Each VirtIO device was scheduling its own taskqueue(9) to do the
    off-level interrupt handling. ithreads(9) is the more nature way
    to do this. The primary motivation for this work to better support
    network multiqueue.
r245710:
    virtio: Change virtqueue intr handlers to return void
r245711:
    virtio_blk: Remove interrupt taskqueue
r245721:
    vtnet: Remove interrupt taskqueue
r245722:
    virtio_scsi: Remove interrupt taskqueue
r245747:
    vtnet: Remove taskqueue fields missed in r245721

MFC after:	1 month
This commit is contained in:
Bryan Venteicher 2013-07-04 17:50:11 +00:00
parent 61762e7dbc
commit 6632efe40d
10 changed files with 113 additions and 278 deletions

View File

@ -90,7 +90,7 @@ static int vtballoon_config_change(device_t);
static void vtballoon_negotiate_features(struct vtballoon_softc *); static void vtballoon_negotiate_features(struct vtballoon_softc *);
static int vtballoon_alloc_virtqueues(struct vtballoon_softc *); static int vtballoon_alloc_virtqueues(struct vtballoon_softc *);
static int vtballoon_vq_intr(void *); static void vtballoon_vq_intr(void *);
static void vtballoon_inflate(struct vtballoon_softc *, int); static void vtballoon_inflate(struct vtballoon_softc *, int);
static void vtballoon_deflate(struct vtballoon_softc *, int); static void vtballoon_deflate(struct vtballoon_softc *, int);
@ -300,7 +300,7 @@ vtballoon_alloc_virtqueues(struct vtballoon_softc *sc)
return (virtio_alloc_virtqueues(dev, 0, nvqs, vq_info)); return (virtio_alloc_virtqueues(dev, 0, nvqs, vq_info));
} }
static int static void
vtballoon_vq_intr(void *xsc) vtballoon_vq_intr(void *xsc)
{ {
struct vtballoon_softc *sc; struct vtballoon_softc *sc;
@ -310,8 +310,6 @@ vtballoon_vq_intr(void *xsc)
VTBALLOON_LOCK(sc); VTBALLOON_LOCK(sc);
wakeup_one(sc); wakeup_one(sc);
VTBALLOON_UNLOCK(sc); VTBALLOON_UNLOCK(sc);
return (1);
} }
static void static void

View File

@ -39,7 +39,6 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h> #include <sys/lock.h>
#include <sys/mutex.h> #include <sys/mutex.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <sys/taskqueue.h>
#include <geom/geom_disk.h> #include <geom/geom_disk.h>
@ -85,9 +84,6 @@ struct vtblk_softc {
vtblk_req_ready; vtblk_req_ready;
struct vtblk_request *vtblk_req_ordered; struct vtblk_request *vtblk_req_ordered;
struct taskqueue *vtblk_tq;
struct task vtblk_intr_task;
int vtblk_max_nsegs; int vtblk_max_nsegs;
int vtblk_request_count; int vtblk_request_count;
@ -138,8 +134,7 @@ static struct vtblk_request * vtblk_bio_request(struct vtblk_softc *);
static int vtblk_execute_request(struct vtblk_softc *, static int vtblk_execute_request(struct vtblk_softc *,
struct vtblk_request *); struct vtblk_request *);
static int vtblk_vq_intr(void *); static void vtblk_vq_intr(void *);
static void vtblk_intr_task(void *, int);
static void vtblk_stop(struct vtblk_softc *); static void vtblk_stop(struct vtblk_softc *);
@ -333,24 +328,12 @@ vtblk_attach(device_t dev)
vtblk_alloc_disk(sc, &blkcfg); vtblk_alloc_disk(sc, &blkcfg);
TASK_INIT(&sc->vtblk_intr_task, 0, vtblk_intr_task, sc);
sc->vtblk_tq = taskqueue_create_fast("vtblk_taskq", M_NOWAIT,
taskqueue_thread_enqueue, &sc->vtblk_tq);
if (sc->vtblk_tq == NULL) {
error = ENOMEM;
device_printf(dev, "cannot allocate taskqueue\n");
goto fail;
}
error = virtio_setup_intr(dev, INTR_TYPE_BIO | INTR_ENTROPY); error = virtio_setup_intr(dev, INTR_TYPE_BIO | INTR_ENTROPY);
if (error) { if (error) {
device_printf(dev, "cannot setup virtqueue interrupt\n"); device_printf(dev, "cannot setup virtqueue interrupt\n");
goto fail; goto fail;
} }
taskqueue_start_threads(&sc->vtblk_tq, 1, PI_DISK, "%s taskq",
device_get_nameunit(dev));
vtblk_create_disk(sc); vtblk_create_disk(sc);
virtqueue_enable_intr(sc->vtblk_vq); virtqueue_enable_intr(sc->vtblk_vq);
@ -375,12 +358,6 @@ vtblk_detach(device_t dev)
vtblk_stop(sc); vtblk_stop(sc);
VTBLK_UNLOCK(sc); VTBLK_UNLOCK(sc);
if (sc->vtblk_tq != NULL) {
taskqueue_drain(sc->vtblk_tq, &sc->vtblk_intr_task);
taskqueue_free(sc->vtblk_tq);
sc->vtblk_tq = NULL;
}
vtblk_drain(sc); vtblk_drain(sc);
if (sc->vtblk_disk != NULL) { if (sc->vtblk_disk != NULL) {
@ -834,28 +811,16 @@ vtblk_execute_request(struct vtblk_softc *sc, struct vtblk_request *req)
return (error); return (error);
} }
static int
vtblk_vq_intr(void *xsc)
{
struct vtblk_softc *sc;
sc = xsc;
virtqueue_disable_intr(sc->vtblk_vq);
taskqueue_enqueue_fast(sc->vtblk_tq, &sc->vtblk_intr_task);
return (1);
}
static void static void
vtblk_intr_task(void *arg, int pending) vtblk_vq_intr(void *xsc)
{ {
struct vtblk_softc *sc; struct vtblk_softc *sc;
struct virtqueue *vq; struct virtqueue *vq;
sc = arg; sc = xsc;
vq = sc->vtblk_vq; vq = sc->vtblk_vq;
again:
VTBLK_LOCK(sc); VTBLK_LOCK(sc);
if (sc->vtblk_flags & VTBLK_FLAG_DETACH) { if (sc->vtblk_flags & VTBLK_FLAG_DETACH) {
VTBLK_UNLOCK(sc); VTBLK_UNLOCK(sc);
@ -872,9 +837,7 @@ vtblk_intr_task(void *arg, int pending)
if (virtqueue_enable_intr(vq) != 0) { if (virtqueue_enable_intr(vq) != 0) {
virtqueue_disable_intr(vq); virtqueue_disable_intr(vq);
VTBLK_UNLOCK(sc); VTBLK_UNLOCK(sc);
taskqueue_enqueue_fast(sc->vtblk_tq, goto again;
&sc->vtblk_intr_task);
return;
} }
VTBLK_UNLOCK(sc); VTBLK_UNLOCK(sc);

View File

@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$");
#include <sys/module.h> #include <sys/module.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/sysctl.h> #include <sys/sysctl.h>
#include <sys/taskqueue.h>
#include <sys/random.h> #include <sys/random.h>
#include <sys/sglist.h> #include <sys/sglist.h>
#include <sys/lock.h> #include <sys/lock.h>
@ -97,7 +96,6 @@ static void vtnet_set_hwaddr(struct vtnet_softc *);
static int vtnet_is_link_up(struct vtnet_softc *); static int vtnet_is_link_up(struct vtnet_softc *);
static void vtnet_update_link_status(struct vtnet_softc *); static void vtnet_update_link_status(struct vtnet_softc *);
static void vtnet_watchdog(struct vtnet_softc *); static void vtnet_watchdog(struct vtnet_softc *);
static void vtnet_config_change_task(void *, int);
static int vtnet_change_mtu(struct vtnet_softc *, int); static int vtnet_change_mtu(struct vtnet_softc *, int);
static int vtnet_ioctl(struct ifnet *, u_long, caddr_t); static int vtnet_ioctl(struct ifnet *, u_long, caddr_t);
@ -123,8 +121,7 @@ static int vtnet_rx_csum(struct vtnet_softc *, struct mbuf *,
struct virtio_net_hdr *); struct virtio_net_hdr *);
static int vtnet_rxeof_merged(struct vtnet_softc *, struct mbuf *, int); static int vtnet_rxeof_merged(struct vtnet_softc *, struct mbuf *, int);
static int vtnet_rxeof(struct vtnet_softc *, int, int *); static int vtnet_rxeof(struct vtnet_softc *, int, int *);
static void vtnet_rx_intr_task(void *, int); static void vtnet_rx_vq_intr(void *);
static int vtnet_rx_vq_intr(void *);
static void vtnet_txeof(struct vtnet_softc *); static void vtnet_txeof(struct vtnet_softc *);
static struct mbuf * vtnet_tx_offload(struct vtnet_softc *, struct mbuf *, static struct mbuf * vtnet_tx_offload(struct vtnet_softc *, struct mbuf *,
@ -135,8 +132,7 @@ static int vtnet_encap(struct vtnet_softc *, struct mbuf **);
static void vtnet_start_locked(struct ifnet *); static void vtnet_start_locked(struct ifnet *);
static void vtnet_start(struct ifnet *); static void vtnet_start(struct ifnet *);
static void vtnet_tick(void *); static void vtnet_tick(void *);
static void vtnet_tx_intr_task(void *, int); static void vtnet_tx_vq_intr(void *);
static int vtnet_tx_vq_intr(void *);
static void vtnet_stop(struct vtnet_softc *); static void vtnet_stop(struct vtnet_softc *);
static int vtnet_reinit(struct vtnet_softc *); static int vtnet_reinit(struct vtnet_softc *);
@ -427,19 +423,6 @@ vtnet_attach(device_t dev)
ifp->if_capabilities |= IFCAP_POLLING; ifp->if_capabilities |= IFCAP_POLLING;
#endif #endif
TASK_INIT(&sc->vtnet_rx_intr_task, 0, vtnet_rx_intr_task, sc);
TASK_INIT(&sc->vtnet_tx_intr_task, 0, vtnet_tx_intr_task, sc);
TASK_INIT(&sc->vtnet_cfgchg_task, 0, vtnet_config_change_task, sc);
sc->vtnet_tq = taskqueue_create_fast("vtnet_taskq", M_NOWAIT,
taskqueue_thread_enqueue, &sc->vtnet_tq);
if (sc->vtnet_tq == NULL) {
error = ENOMEM;
device_printf(dev, "cannot allocate taskqueue\n");
ether_ifdetach(ifp);
goto fail;
}
error = virtio_setup_intr(dev, INTR_TYPE_NET); error = virtio_setup_intr(dev, INTR_TYPE_NET);
if (error) { if (error) {
device_printf(dev, "cannot setup virtqueue interrupts\n"); device_printf(dev, "cannot setup virtqueue interrupts\n");
@ -447,9 +430,6 @@ vtnet_attach(device_t dev)
goto fail; goto fail;
} }
taskqueue_start_threads(&sc->vtnet_tq, 1, PI_NET, "%s taskq",
device_get_nameunit(dev));
/* /*
* Device defaults to promiscuous mode for backwards * Device defaults to promiscuous mode for backwards
* compatibility. Turn it off if possible. * compatibility. Turn it off if possible.
@ -495,18 +475,10 @@ vtnet_detach(device_t dev)
VTNET_UNLOCK(sc); VTNET_UNLOCK(sc);
callout_drain(&sc->vtnet_tick_ch); callout_drain(&sc->vtnet_tick_ch);
taskqueue_drain(taskqueue_fast, &sc->vtnet_cfgchg_task);
ether_ifdetach(ifp); ether_ifdetach(ifp);
} }
if (sc->vtnet_tq != NULL) {
taskqueue_drain(sc->vtnet_tq, &sc->vtnet_rx_intr_task);
taskqueue_drain(sc->vtnet_tq, &sc->vtnet_tx_intr_task);
taskqueue_free(sc->vtnet_tq);
sc->vtnet_tq = NULL;
}
if (sc->vtnet_vlan_attach != NULL) { if (sc->vtnet_vlan_attach != NULL) {
EVENTHANDLER_DEREGISTER(vlan_config, sc->vtnet_vlan_attach); EVENTHANDLER_DEREGISTER(vlan_config, sc->vtnet_vlan_attach);
sc->vtnet_vlan_attach = NULL; sc->vtnet_vlan_attach = NULL;
@ -590,9 +562,11 @@ vtnet_config_change(device_t dev)
sc = device_get_softc(dev); sc = device_get_softc(dev);
taskqueue_enqueue_fast(taskqueue_fast, &sc->vtnet_cfgchg_task); VTNET_LOCK(sc);
vtnet_update_link_status(sc);
VTNET_UNLOCK(sc);
return (1); return (0);
} }
static void static void
@ -788,18 +762,6 @@ vtnet_watchdog(struct vtnet_softc *sc)
vtnet_init_locked(sc); vtnet_init_locked(sc);
} }
static void
vtnet_config_change_task(void *arg, int pending)
{
struct vtnet_softc *sc;
sc = arg;
VTNET_LOCK(sc);
vtnet_update_link_status(sc);
VTNET_UNLOCK(sc);
}
static int static int
vtnet_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) vtnet_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{ {
@ -1705,15 +1667,16 @@ vtnet_rxeof(struct vtnet_softc *sc, int count, int *rx_npktsp)
} }
static void static void
vtnet_rx_intr_task(void *arg, int pending) vtnet_rx_vq_intr(void *xsc)
{ {
struct vtnet_softc *sc; struct vtnet_softc *sc;
struct ifnet *ifp; struct ifnet *ifp;
int more; int more;
sc = arg; sc = xsc;
ifp = sc->vtnet_ifp; ifp = sc->vtnet_ifp;
again:
VTNET_LOCK(sc); VTNET_LOCK(sc);
#ifdef DEVICE_POLLING #ifdef DEVICE_POLLING
@ -1730,31 +1693,15 @@ vtnet_rx_intr_task(void *arg, int pending)
} }
more = vtnet_rxeof(sc, sc->vtnet_rx_process_limit, NULL); more = vtnet_rxeof(sc, sc->vtnet_rx_process_limit, NULL);
if (!more && vtnet_enable_rx_intr(sc) != 0) { if (more || vtnet_enable_rx_intr(sc) != 0) {
vtnet_disable_rx_intr(sc); if (!more)
more = 1; vtnet_disable_rx_intr(sc);
sc->vtnet_stats.rx_task_rescheduled++;
VTNET_UNLOCK(sc);
goto again;
} }
VTNET_UNLOCK(sc); VTNET_UNLOCK(sc);
if (more) {
sc->vtnet_stats.rx_task_rescheduled++;
taskqueue_enqueue_fast(sc->vtnet_tq,
&sc->vtnet_rx_intr_task);
}
}
static int
vtnet_rx_vq_intr(void *xsc)
{
struct vtnet_softc *sc;
sc = xsc;
vtnet_disable_rx_intr(sc);
taskqueue_enqueue_fast(sc->vtnet_tq, &sc->vtnet_rx_intr_task);
return (1);
} }
static void static void
@ -2077,14 +2024,15 @@ vtnet_tick(void *xsc)
} }
static void static void
vtnet_tx_intr_task(void *arg, int pending) vtnet_tx_vq_intr(void *xsc)
{ {
struct vtnet_softc *sc; struct vtnet_softc *sc;
struct ifnet *ifp; struct ifnet *ifp;
sc = arg; sc = xsc;
ifp = sc->vtnet_ifp; ifp = sc->vtnet_ifp;
again:
VTNET_LOCK(sc); VTNET_LOCK(sc);
#ifdef DEVICE_POLLING #ifdef DEVICE_POLLING
@ -2109,26 +2057,12 @@ vtnet_tx_intr_task(void *arg, int pending)
vtnet_disable_tx_intr(sc); vtnet_disable_tx_intr(sc);
sc->vtnet_stats.tx_task_rescheduled++; sc->vtnet_stats.tx_task_rescheduled++;
VTNET_UNLOCK(sc); VTNET_UNLOCK(sc);
taskqueue_enqueue_fast(sc->vtnet_tq, &sc->vtnet_tx_intr_task); goto again;
return;
} }
VTNET_UNLOCK(sc); VTNET_UNLOCK(sc);
} }
static int
vtnet_tx_vq_intr(void *xsc)
{
struct vtnet_softc *sc;
sc = xsc;
vtnet_disable_tx_intr(sc);
taskqueue_enqueue_fast(sc->vtnet_tq, &sc->vtnet_tx_intr_task);
return (1);
}
static void static void
vtnet_stop(struct vtnet_softc *sc) vtnet_stop(struct vtnet_softc *sc)
{ {

View File

@ -79,11 +79,6 @@ struct vtnet_softc {
int vtnet_watchdog_timer; int vtnet_watchdog_timer;
uint64_t vtnet_features; uint64_t vtnet_features;
struct taskqueue *vtnet_tq;
struct task vtnet_rx_intr_task;
struct task vtnet_tx_intr_task;
struct task vtnet_cfgchg_task;
struct vtnet_statistics vtnet_stats; struct vtnet_statistics vtnet_stats;
struct callout vtnet_tick_ch; struct callout vtnet_tick_ch;

View File

@ -160,10 +160,12 @@ static void vtpci_reset(struct vtpci_softc *);
static void vtpci_select_virtqueue(struct vtpci_softc *, int); static void vtpci_select_virtqueue(struct vtpci_softc *, int);
static int vtpci_legacy_intr(void *); static void vtpci_legacy_intr(void *);
static int vtpci_vq_shared_intr(void *); static int vtpci_vq_shared_intr_filter(void *);
static int vtpci_vq_intr(void *); static void vtpci_vq_shared_intr(void *);
static int vtpci_config_intr(void *); static int vtpci_vq_intr_filter(void *);
static void vtpci_vq_intr(void *);
static void vtpci_config_intr(void *);
#define vtpci_setup_msi_interrupt vtpci_setup_legacy_interrupt #define vtpci_setup_msi_interrupt vtpci_setup_legacy_interrupt
@ -932,7 +934,7 @@ vtpci_setup_legacy_interrupt(struct vtpci_softc *sc, enum intr_type type)
dev = sc->vtpci_dev; dev = sc->vtpci_dev;
ires = &sc->vtpci_intr_res[0]; ires = &sc->vtpci_intr_res[0];
error = bus_setup_intr(dev, ires->irq, type, vtpci_legacy_intr, NULL, error = bus_setup_intr(dev, ires->irq, type, NULL, vtpci_legacy_intr,
sc, &ires->intrhand); sc, &ires->intrhand);
return (error); return (error);
@ -949,11 +951,11 @@ vtpci_setup_msix_interrupts(struct vtpci_softc *sc, enum intr_type type)
dev = sc->vtpci_dev; dev = sc->vtpci_dev;
/* /*
* The first resource is used for configuration changed interrupts. * The first MSIX vector is used for configuration changed interrupts.
*/ */
ires = &sc->vtpci_intr_res[0]; ires = &sc->vtpci_intr_res[0];
error = bus_setup_intr(dev, ires->irq, type, vtpci_config_intr, error = bus_setup_intr(dev, ires->irq, type, NULL, vtpci_config_intr,
NULL, sc, &ires->intrhand); sc, &ires->intrhand);
if (error) if (error)
return (error); return (error);
@ -961,13 +963,9 @@ vtpci_setup_msix_interrupts(struct vtpci_softc *sc, enum intr_type type)
ires = &sc->vtpci_intr_res[1]; ires = &sc->vtpci_intr_res[1];
error = bus_setup_intr(dev, ires->irq, type, error = bus_setup_intr(dev, ires->irq, type,
vtpci_vq_shared_intr, NULL, sc, &ires->intrhand); vtpci_vq_shared_intr_filter, vtpci_vq_shared_intr, sc,
if (error) &ires->intrhand);
return (error);
} else { } else {
/*
* Each remaining resource is assigned to a specific virtqueue.
*/
for (i = 0; i < sc->vtpci_nvqs; i++) { for (i = 0; i < sc->vtpci_nvqs; i++) {
vqx = &sc->vtpci_vqx[i]; vqx = &sc->vtpci_vqx[i];
if (vqx->ires_idx < 1) if (vqx->ires_idx < 1)
@ -975,17 +973,17 @@ vtpci_setup_msix_interrupts(struct vtpci_softc *sc, enum intr_type type)
ires = &sc->vtpci_intr_res[vqx->ires_idx]; ires = &sc->vtpci_intr_res[vqx->ires_idx];
error = bus_setup_intr(dev, ires->irq, type, error = bus_setup_intr(dev, ires->irq, type,
vtpci_vq_intr, NULL, vqx->vq, &ires->intrhand); vtpci_vq_intr_filter, vtpci_vq_intr, vqx->vq,
&ires->intrhand);
if (error) if (error)
return (error); break;
} }
} }
error = vtpci_set_host_msix_vectors(sc); if (error == 0)
if (error) error = vtpci_set_host_msix_vectors(sc);
return (error);
return (0); return (error);
} }
static int static int
@ -1191,7 +1189,7 @@ vtpci_select_virtqueue(struct vtpci_softc *sc, int idx)
vtpci_write_config_2(sc, VIRTIO_PCI_QUEUE_SEL, idx); vtpci_write_config_2(sc, VIRTIO_PCI_QUEUE_SEL, idx);
} }
static int static void
vtpci_legacy_intr(void *xsc) vtpci_legacy_intr(void *xsc)
{ {
struct vtpci_softc *sc; struct vtpci_softc *sc;
@ -1208,15 +1206,14 @@ vtpci_legacy_intr(void *xsc)
if (isr & VIRTIO_PCI_ISR_CONFIG) if (isr & VIRTIO_PCI_ISR_CONFIG)
vtpci_config_intr(sc); vtpci_config_intr(sc);
if (isr & VIRTIO_PCI_ISR_INTR) if (isr & VIRTIO_PCI_ISR_INTR) {
for (i = 0; i < sc->vtpci_nvqs; i++, vqx++) for (i = 0; i < sc->vtpci_nvqs; i++, vqx++)
virtqueue_intr(vqx->vq); virtqueue_intr(vqx->vq);
}
return (isr ? FILTER_HANDLED : FILTER_STRAY);
} }
static int static int
vtpci_vq_shared_intr(void *xsc) vtpci_vq_shared_intr_filter(void *xsc)
{ {
struct vtpci_softc *sc; struct vtpci_softc *sc;
struct vtpci_virtqueue *vqx; struct vtpci_virtqueue *vqx;
@ -1227,36 +1224,55 @@ vtpci_vq_shared_intr(void *xsc)
vqx = &sc->vtpci_vqx[0]; vqx = &sc->vtpci_vqx[0];
for (i = 0; i < sc->vtpci_nvqs; i++, vqx++) for (i = 0; i < sc->vtpci_nvqs; i++, vqx++)
rc |= virtqueue_intr(vqx->vq); rc |= virtqueue_intr_filter(vqx->vq);
return (rc ? FILTER_HANDLED : FILTER_STRAY); return (rc ? FILTER_SCHEDULE_THREAD : FILTER_STRAY);
}
static void
vtpci_vq_shared_intr(void *xsc)
{
struct vtpci_softc *sc;
struct vtpci_virtqueue *vqx;
int i;
sc = xsc;
vqx = &sc->vtpci_vqx[0];
for (i = 0; i < sc->vtpci_nvqs; i++, vqx++)
virtqueue_intr(vqx->vq);
} }
static int static int
vtpci_vq_intr(void *xvq) vtpci_vq_intr_filter(void *xvq)
{ {
struct virtqueue *vq; struct virtqueue *vq;
int rc; int rc;
vq = xvq; vq = xvq;
rc = virtqueue_intr(vq); rc = virtqueue_intr_filter(vq);
return (rc ? FILTER_HANDLED : FILTER_STRAY); return (rc ? FILTER_SCHEDULE_THREAD : FILTER_STRAY);
} }
static int static void
vtpci_vq_intr(void *xvq)
{
struct virtqueue *vq;
vq = xvq;
virtqueue_intr(vq);
}
static void
vtpci_config_intr(void *xsc) vtpci_config_intr(void *xsc)
{ {
struct vtpci_softc *sc; struct vtpci_softc *sc;
device_t child; device_t child;
int rc;
rc = 0;
sc = xsc; sc = xsc;
child = sc->vtpci_child_dev; child = sc->vtpci_child_dev;
if (child != NULL) if (child != NULL)
rc = VIRTIO_CONFIG_CHANGE(child); VIRTIO_CONFIG_CHANGE(child);
return (rc ? FILTER_HANDLED : FILTER_STRAY);
} }

View File

@ -40,7 +40,6 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h> #include <sys/lock.h>
#include <sys/mutex.h> #include <sys/mutex.h>
#include <sys/callout.h> #include <sys/callout.h>
#include <sys/taskqueue.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <sys/sbuf.h> #include <sys/sbuf.h>
@ -172,13 +171,10 @@ static struct vtscsi_request * vtscsi_dequeue_request(struct vtscsi_softc *);
static void vtscsi_complete_request(struct vtscsi_request *); static void vtscsi_complete_request(struct vtscsi_request *);
static void vtscsi_complete_vq(struct vtscsi_softc *, struct virtqueue *); static void vtscsi_complete_vq(struct vtscsi_softc *, struct virtqueue *);
static void vtscsi_control_vq_task(void *, int);
static void vtscsi_event_vq_task(void *, int);
static void vtscsi_request_vq_task(void *, int);
static int vtscsi_control_vq_intr(void *); static void vtscsi_control_vq_intr(void *);
static int vtscsi_event_vq_intr(void *); static void vtscsi_event_vq_intr(void *);
static int vtscsi_request_vq_intr(void *); static void vtscsi_request_vq_intr(void *);
static void vtscsi_disable_vqs_intr(struct vtscsi_softc *); static void vtscsi_disable_vqs_intr(struct vtscsi_softc *);
static void vtscsi_enable_vqs_intr(struct vtscsi_softc *); static void vtscsi_enable_vqs_intr(struct vtscsi_softc *);
@ -333,30 +329,12 @@ vtscsi_attach(device_t dev)
goto fail; goto fail;
} }
TASK_INIT(&sc->vtscsi_control_intr_task, 0,
vtscsi_control_vq_task, sc);
TASK_INIT(&sc->vtscsi_event_intr_task, 0,
vtscsi_event_vq_task, sc);
TASK_INIT(&sc->vtscsi_request_intr_task, 0,
vtscsi_request_vq_task, sc);
sc->vtscsi_tq = taskqueue_create_fast("vtscsi_taskq", M_NOWAIT,
taskqueue_thread_enqueue, &sc->vtscsi_tq);
if (sc->vtscsi_tq == NULL) {
error = ENOMEM;
device_printf(dev, "cannot allocate taskqueue\n");
goto fail;
}
error = virtio_setup_intr(dev, INTR_TYPE_CAM); error = virtio_setup_intr(dev, INTR_TYPE_CAM);
if (error) { if (error) {
device_printf(dev, "cannot setup virtqueue interrupts\n"); device_printf(dev, "cannot setup virtqueue interrupts\n");
goto fail; goto fail;
} }
taskqueue_start_threads(&sc->vtscsi_tq, 1, PI_DISK, "%s taskq",
device_get_nameunit(dev));
vtscsi_enable_vqs_intr(sc); vtscsi_enable_vqs_intr(sc);
/* /*
@ -389,14 +367,6 @@ vtscsi_detach(device_t dev)
vtscsi_stop(sc); vtscsi_stop(sc);
VTSCSI_UNLOCK(sc); VTSCSI_UNLOCK(sc);
if (sc->vtscsi_tq != NULL) {
taskqueue_drain(sc->vtscsi_tq, &sc->vtscsi_control_intr_task);
taskqueue_drain(sc->vtscsi_tq, &sc->vtscsi_event_intr_task);
taskqueue_drain(sc->vtscsi_tq, &sc->vtscsi_request_intr_task);
taskqueue_free(sc->vtscsi_tq);
sc->vtscsi_tq = NULL;
}
vtscsi_complete_vqs(sc); vtscsi_complete_vqs(sc);
vtscsi_drain_vqs(sc); vtscsi_drain_vqs(sc);
@ -2152,14 +2122,15 @@ vtscsi_complete_vq(struct vtscsi_softc *sc, struct virtqueue *vq)
} }
static void static void
vtscsi_control_vq_task(void *arg, int pending) vtscsi_control_vq_intr(void *xsc)
{ {
struct vtscsi_softc *sc; struct vtscsi_softc *sc;
struct virtqueue *vq; struct virtqueue *vq;
sc = arg; sc = xsc;
vq = sc->vtscsi_control_vq; vq = sc->vtscsi_control_vq;
again:
VTSCSI_LOCK(sc); VTSCSI_LOCK(sc);
vtscsi_complete_vq(sc, sc->vtscsi_control_vq); vtscsi_complete_vq(sc, sc->vtscsi_control_vq);
@ -2167,24 +2138,23 @@ vtscsi_control_vq_task(void *arg, int pending)
if (virtqueue_enable_intr(vq) != 0) { if (virtqueue_enable_intr(vq) != 0) {
virtqueue_disable_intr(vq); virtqueue_disable_intr(vq);
VTSCSI_UNLOCK(sc); VTSCSI_UNLOCK(sc);
taskqueue_enqueue_fast(sc->vtscsi_tq, goto again;
&sc->vtscsi_control_intr_task);
return;
} }
VTSCSI_UNLOCK(sc); VTSCSI_UNLOCK(sc);
} }
static void static void
vtscsi_event_vq_task(void *arg, int pending) vtscsi_event_vq_intr(void *xsc)
{ {
struct vtscsi_softc *sc; struct vtscsi_softc *sc;
struct virtqueue *vq; struct virtqueue *vq;
struct virtio_scsi_event *event; struct virtio_scsi_event *event;
sc = arg; sc = xsc;
vq = sc->vtscsi_event_vq; vq = sc->vtscsi_event_vq;
again:
VTSCSI_LOCK(sc); VTSCSI_LOCK(sc);
while ((event = virtqueue_dequeue(vq, NULL)) != NULL) while ((event = virtqueue_dequeue(vq, NULL)) != NULL)
@ -2193,23 +2163,22 @@ vtscsi_event_vq_task(void *arg, int pending)
if (virtqueue_enable_intr(vq) != 0) { if (virtqueue_enable_intr(vq) != 0) {
virtqueue_disable_intr(vq); virtqueue_disable_intr(vq);
VTSCSI_UNLOCK(sc); VTSCSI_UNLOCK(sc);
taskqueue_enqueue_fast(sc->vtscsi_tq, goto again;
&sc->vtscsi_control_intr_task);
return;
} }
VTSCSI_UNLOCK(sc); VTSCSI_UNLOCK(sc);
} }
static void static void
vtscsi_request_vq_task(void *arg, int pending) vtscsi_request_vq_intr(void *xsc)
{ {
struct vtscsi_softc *sc; struct vtscsi_softc *sc;
struct virtqueue *vq; struct virtqueue *vq;
sc = arg; sc = xsc;
vq = sc->vtscsi_request_vq; vq = sc->vtscsi_request_vq;
again:
VTSCSI_LOCK(sc); VTSCSI_LOCK(sc);
vtscsi_complete_vq(sc, sc->vtscsi_request_vq); vtscsi_complete_vq(sc, sc->vtscsi_request_vq);
@ -2217,56 +2186,12 @@ vtscsi_request_vq_task(void *arg, int pending)
if (virtqueue_enable_intr(vq) != 0) { if (virtqueue_enable_intr(vq) != 0) {
virtqueue_disable_intr(vq); virtqueue_disable_intr(vq);
VTSCSI_UNLOCK(sc); VTSCSI_UNLOCK(sc);
taskqueue_enqueue_fast(sc->vtscsi_tq, goto again;
&sc->vtscsi_request_intr_task);
return;
} }
VTSCSI_UNLOCK(sc); VTSCSI_UNLOCK(sc);
} }
static int
vtscsi_control_vq_intr(void *xsc)
{
struct vtscsi_softc *sc;
sc = xsc;
virtqueue_disable_intr(sc->vtscsi_control_vq);
taskqueue_enqueue_fast(sc->vtscsi_tq,
&sc->vtscsi_control_intr_task);
return (1);
}
static int
vtscsi_event_vq_intr(void *xsc)
{
struct vtscsi_softc *sc;
sc = xsc;
virtqueue_disable_intr(sc->vtscsi_event_vq);
taskqueue_enqueue_fast(sc->vtscsi_tq,
&sc->vtscsi_event_intr_task);
return (1);
}
static int
vtscsi_request_vq_intr(void *xsc)
{
struct vtscsi_softc *sc;
sc = xsc;
virtqueue_disable_intr(sc->vtscsi_request_vq);
taskqueue_enqueue_fast(sc->vtscsi_tq,
&sc->vtscsi_request_intr_task);
return (1);
}
static void static void
vtscsi_disable_vqs_intr(struct vtscsi_softc *sc) vtscsi_disable_vqs_intr(struct vtscsi_softc *sc)
{ {

View File

@ -62,11 +62,6 @@ struct vtscsi_softc {
struct virtqueue *vtscsi_event_vq; struct virtqueue *vtscsi_event_vq;
struct virtqueue *vtscsi_request_vq; struct virtqueue *vtscsi_request_vq;
struct taskqueue *vtscsi_tq;
struct task vtscsi_control_intr_task;
struct task vtscsi_event_intr_task;
struct task vtscsi_request_intr_task;
struct cam_sim *vtscsi_sim; struct cam_sim *vtscsi_sim;
struct cam_path *vtscsi_path; struct cam_path *vtscsi_path;

View File

@ -33,8 +33,7 @@ CODE {
static int static int
virtio_default_config_change(device_t dev) virtio_default_config_change(device_t dev)
{ {
/* Return that we've handled the change. */ return (0);
return (1);
} }
}; };

View File

@ -414,16 +414,25 @@ virtqueue_nused(struct virtqueue *vq)
} }
int 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);
virtqueue_disable_intr(vq);
return (1);
}
void
virtqueue_intr(struct virtqueue *vq) virtqueue_intr(struct virtqueue *vq)
{ {
if (vq->vq_intrhand == NULL || if (__predict_true(vq->vq_intrhand != NULL))
vq->vq_used_cons_idx == vq->vq_ring.used->idx) vq->vq_intrhand(vq->vq_intrhand_arg);
return (0);
vq->vq_intrhand(vq->vq_intrhand_arg);
return (1);
} }
int int

View File

@ -39,7 +39,7 @@ struct sglist;
#define VIRTIO_RING_F_EVENT_IDX (1 << 29) #define VIRTIO_RING_F_EVENT_IDX (1 << 29)
/* Device callback for a virtqueue interrupt. */ /* Device callback for a virtqueue interrupt. */
typedef int virtqueue_intr_t(void *); typedef void virtqueue_intr_t(void *);
#define VIRTQUEUE_MAX_NAME_SZ 32 #define VIRTQUEUE_MAX_NAME_SZ 32
@ -70,7 +70,8 @@ void *virtqueue_drain(struct virtqueue *vq, int *last);
void virtqueue_free(struct virtqueue *vq); void virtqueue_free(struct virtqueue *vq);
int virtqueue_reinit(struct virtqueue *vq, uint16_t size); int virtqueue_reinit(struct virtqueue *vq, uint16_t size);
int virtqueue_intr(struct virtqueue *vq); int virtqueue_intr_filter(struct virtqueue *vq);
void virtqueue_intr(struct virtqueue *vq);
int virtqueue_enable_intr(struct virtqueue *vq); int virtqueue_enable_intr(struct virtqueue *vq);
int virtqueue_postpone_intr(struct virtqueue *vq); int virtqueue_postpone_intr(struct virtqueue *vq);
void virtqueue_disable_intr(struct virtqueue *vq); void virtqueue_disable_intr(struct virtqueue *vq);