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:
parent
61762e7dbc
commit
6632efe40d
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user