Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/pci_virtio_net.c
Show All 30 Lines | |||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/linker_set.h> | #include <sys/linker_set.h> | ||||
#include <sys/select.h> | #include <sys/select.h> | ||||
#include <sys/uio.h> | #include <sys/uio.h> | ||||
#include <sys/ioctl.h> | #include <sys/ioctl.h> | ||||
#include <machine/vmm_snapshot.h> | |||||
#include <net/ethernet.h> | #include <net/ethernet.h> | ||||
#include <net/if.h> /* IFNAMSIZ */ | #include <net/if.h> /* IFNAMSIZ */ | ||||
#include <err.h> | #include <err.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <fcntl.h> | #include <fcntl.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | struct pci_vtnet_softc { | ||||
struct virtio_consts vsc_consts; | struct virtio_consts vsc_consts; | ||||
}; | }; | ||||
static void pci_vtnet_reset(void *); | static void pci_vtnet_reset(void *); | ||||
/* static void pci_vtnet_notify(void *, struct vqueue_info *); */ | /* static void pci_vtnet_notify(void *, struct vqueue_info *); */ | ||||
static int pci_vtnet_cfgread(void *, int, int, uint32_t *); | static int pci_vtnet_cfgread(void *, int, int, uint32_t *); | ||||
static int pci_vtnet_cfgwrite(void *, int, int, uint32_t); | static int pci_vtnet_cfgwrite(void *, int, int, uint32_t); | ||||
static void pci_vtnet_neg_features(void *, uint64_t); | static void pci_vtnet_neg_features(void *, uint64_t); | ||||
#ifdef BHYVE_SNAPSHOT | |||||
static void pci_vtnet_pause(void *); | |||||
static void pci_vtnet_resume(void *); | |||||
static int pci_vtnet_snapshot(void *, struct vm_snapshot_meta *); | |||||
#endif | |||||
static struct virtio_consts vtnet_vi_consts = { | static struct virtio_consts vtnet_vi_consts = { | ||||
"vtnet", /* our name */ | "vtnet", /* our name */ | ||||
VTNET_MAXQ - 1, /* we currently support 2 virtqueues */ | VTNET_MAXQ - 1, /* we currently support 2 virtqueues */ | ||||
sizeof(struct virtio_net_config), /* config reg size */ | sizeof(struct virtio_net_config), /* config reg size */ | ||||
pci_vtnet_reset, /* reset */ | pci_vtnet_reset, /* reset */ | ||||
NULL, /* device-wide qnotify -- not used */ | NULL, /* device-wide qnotify -- not used */ | ||||
pci_vtnet_cfgread, /* read PCI config */ | pci_vtnet_cfgread, /* read PCI config */ | ||||
pci_vtnet_cfgwrite, /* write PCI config */ | pci_vtnet_cfgwrite, /* write PCI config */ | ||||
pci_vtnet_neg_features, /* apply negotiated features */ | pci_vtnet_neg_features, /* apply negotiated features */ | ||||
VTNET_S_HOSTCAPS, /* our capabilities */ | VTNET_S_HOSTCAPS, /* our capabilities */ | ||||
#ifdef BHYVE_SNAPSHOT | |||||
pci_vtnet_pause, /* pause rx/tx threads */ | |||||
pci_vtnet_resume, /* resume rx/tx threads */ | |||||
pci_vtnet_snapshot, /* save / restore device state */ | |||||
#endif | |||||
}; | }; | ||||
static void | static void | ||||
pci_vtnet_reset(void *vsc) | pci_vtnet_reset(void *vsc) | ||||
{ | { | ||||
struct pci_vtnet_softc *sc = vsc; | struct pci_vtnet_softc *sc = vsc; | ||||
DPRINTF(("vtnet: device reset requested !")); | DPRINTF(("vtnet: device reset requested !")); | ||||
▲ Show 20 Lines • Show All 554 Lines • ▼ Show 20 Lines | pci_vtnet_neg_features(void *vsc, uint64_t negotiated_features) | ||||
} | } | ||||
/* Tell the backend to enable some capabilities it has advertised. */ | /* Tell the backend to enable some capabilities it has advertised. */ | ||||
netbe_set_cap(sc->vsc_be, negotiated_features, sc->vhdrlen); | netbe_set_cap(sc->vsc_be, negotiated_features, sc->vhdrlen); | ||||
sc->be_vhdrlen = netbe_get_vnet_hdr_len(sc->vsc_be); | sc->be_vhdrlen = netbe_get_vnet_hdr_len(sc->vsc_be); | ||||
assert(sc->be_vhdrlen == 0 || sc->be_vhdrlen == sc->vhdrlen); | assert(sc->be_vhdrlen == 0 || sc->be_vhdrlen == sc->vhdrlen); | ||||
} | } | ||||
#ifdef BHYVE_SNAPSHOT | |||||
static void | |||||
pci_vtnet_pause(void *vsc) | |||||
{ | |||||
struct pci_vtnet_softc *sc = vsc; | |||||
DPRINTF(("vtnet: device pause requested !\n")); | |||||
/* Acquire the RX lock to block RX processing. */ | |||||
pthread_mutex_lock(&sc->rx_mtx); | |||||
/* Wait for the transmit thread to finish its processing. */ | |||||
pthread_mutex_lock(&sc->tx_mtx); | |||||
while (sc->tx_in_progress) { | |||||
pthread_mutex_unlock(&sc->tx_mtx); | |||||
usleep(10000); | |||||
pthread_mutex_lock(&sc->tx_mtx); | |||||
} | |||||
} | |||||
static void | |||||
pci_vtnet_resume(void *vsc) | |||||
{ | |||||
struct pci_vtnet_softc *sc = vsc; | |||||
DPRINTF(("vtnet: device resume requested !\n")); | |||||
pthread_mutex_unlock(&sc->tx_mtx); | |||||
/* The RX lock should have been acquired in vtnet_pause. */ | |||||
pthread_mutex_unlock(&sc->rx_mtx); | |||||
} | |||||
static int | |||||
pci_vtnet_snapshot(void *vsc, struct vm_snapshot_meta *meta) | |||||
{ | |||||
int ret; | |||||
struct pci_vtnet_softc *sc = vsc; | |||||
DPRINTF(("vtnet: device snapshot requested !\n")); | |||||
/* | |||||
* Queues and consts should have been saved by the more generic | |||||
* vi_pci_snapshot function. We need to save only our features and | |||||
* config. | |||||
*/ | |||||
SNAPSHOT_VAR_OR_LEAVE(sc->vsc_features, meta, ret, done); | |||||
/* Force reapply negociated features at restore time */ | |||||
if (meta->op == VM_SNAPSHOT_RESTORE) { | |||||
pci_vtnet_neg_features(sc, sc->vsc_features); | |||||
netbe_rx_enable(sc->vsc_be); | |||||
} | |||||
SNAPSHOT_VAR_OR_LEAVE(sc->vsc_config, meta, ret, done); | |||||
SNAPSHOT_VAR_OR_LEAVE(sc->rx_merge, meta, ret, done); | |||||
SNAPSHOT_VAR_OR_LEAVE(sc->vhdrlen, meta, ret, done); | |||||
SNAPSHOT_VAR_OR_LEAVE(sc->be_vhdrlen, meta, ret, done); | |||||
done: | |||||
return (ret); | |||||
} | |||||
#endif | |||||
static struct pci_devemu pci_de_vnet = { | static struct pci_devemu pci_de_vnet = { | ||||
.pe_emu = "virtio-net", | .pe_emu = "virtio-net", | ||||
.pe_init = pci_vtnet_init, | .pe_init = pci_vtnet_init, | ||||
.pe_barwrite = vi_pci_write, | .pe_barwrite = vi_pci_write, | ||||
.pe_barread = vi_pci_read | .pe_barread = vi_pci_read, | ||||
#ifdef BHYVE_SNAPSHOT | |||||
.pe_snapshot = vi_pci_snapshot, | |||||
.pe_pause = vi_pci_pause, | |||||
.pe_resume = vi_pci_resume, | |||||
#endif | |||||
}; | }; | ||||
PCI_EMUL_SET(pci_de_vnet); | PCI_EMUL_SET(pci_de_vnet); |