Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/pci_virtio_net.c
Show First 20 Lines • Show All 103 Lines • ▼ Show 20 Lines | struct pci_vtnet_softc { | ||||
net_backend_t *vsc_be; | net_backend_t *vsc_be; | ||||
int resetting; /* protected by tx_mtx */ | int resetting; /* protected by tx_mtx */ | ||||
uint64_t vsc_features; /* negotiated features */ | uint64_t vsc_features; /* negotiated features */ | ||||
pthread_mutex_t rx_mtx; | pthread_mutex_t rx_mtx; | ||||
unsigned int rx_vhdrlen; | |||||
int rx_merge; /* merged rx bufs in use */ | int rx_merge; /* merged rx bufs in use */ | ||||
pthread_t tx_tid; | pthread_t tx_tid; | ||||
pthread_mutex_t tx_mtx; | pthread_mutex_t tx_mtx; | ||||
pthread_cond_t tx_cond; | pthread_cond_t tx_cond; | ||||
int tx_in_progress; | int tx_in_progress; | ||||
struct virtio_net_config vsc_config; | struct virtio_net_config vsc_config; | ||||
Show All 23 Lines | |||||
{ | { | ||||
struct pci_vtnet_softc *sc = vsc; | struct pci_vtnet_softc *sc = vsc; | ||||
DPRINTF(("vtnet: device reset requested !\n")); | DPRINTF(("vtnet: device reset requested !\n")); | ||||
/* Acquire the RX lock to block RX processing. */ | /* Acquire the RX lock to block RX processing. */ | ||||
pthread_mutex_lock(&sc->rx_mtx); | pthread_mutex_lock(&sc->rx_mtx); | ||||
/* | |||||
* Make sure receive operation is disabled at least until we | |||||
* re-negotiate the features, since receive operation depends | |||||
* on the value of sc->rx_merge and the header length, which | |||||
* are both set in pci_vtnet_neg_features(). | |||||
* Receive operation will be enabled again once the guest adds | |||||
* the first receive buffers and kicks us. | |||||
*/ | |||||
netbe_rx_disable(sc->vsc_be); | |||||
/* Set sc->resetting and give a chance to the TX thread to stop. */ | /* Set sc->resetting and give a chance to the TX thread to stop. */ | ||||
pthread_mutex_lock(&sc->tx_mtx); | pthread_mutex_lock(&sc->tx_mtx); | ||||
sc->resetting = 1; | sc->resetting = 1; | ||||
while (sc->tx_in_progress) { | while (sc->tx_in_progress) { | ||||
pthread_mutex_unlock(&sc->tx_mtx); | pthread_mutex_unlock(&sc->tx_mtx); | ||||
usleep(10000); | usleep(10000); | ||||
pthread_mutex_lock(&sc->tx_mtx); | pthread_mutex_lock(&sc->tx_mtx); | ||||
} | } | ||||
sc->rx_merge = 1; | |||||
sc->rx_vhdrlen = sizeof(struct virtio_net_rxhdr); | |||||
/* | /* | ||||
* Now reset rings, MSI-X vectors, and negotiated capabilities. | * Now reset rings, MSI-X vectors, and negotiated capabilities. | ||||
* Do that with the TX lock held, since we need to reset | * Do that with the TX lock held, since we need to reset | ||||
* sc->resetting. | * sc->resetting. | ||||
*/ | */ | ||||
vi_reset_dev(&sc->vsc_vs); | vi_reset_dev(&sc->vsc_vs); | ||||
sc->resetting = 0; | sc->resetting = 0; | ||||
▲ Show 20 Lines • Show All 335 Lines • ▼ Show 20 Lines | if (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix())) { | ||||
return (1); | return (1); | ||||
} | } | ||||
/* use BAR 0 to map config regs in IO space */ | /* use BAR 0 to map config regs in IO space */ | ||||
vi_set_io_bar(&sc->vsc_vs, 0); | vi_set_io_bar(&sc->vsc_vs, 0); | ||||
sc->resetting = 0; | sc->resetting = 0; | ||||
sc->rx_merge = 1; | sc->rx_merge = 1; | ||||
jhb: My only thought is perhaps we should assume rx_merge is not supported until we negotiate that… | |||||
Done Inline ActionsAgreed. vmaffione: Agreed. | |||||
sc->rx_vhdrlen = sizeof(struct virtio_net_rxhdr); | |||||
pthread_mutex_init(&sc->rx_mtx, NULL); | pthread_mutex_init(&sc->rx_mtx, NULL); | ||||
/* | /* | ||||
* Initialize tx semaphore & spawn TX processing thread. | * Initialize tx semaphore & spawn TX processing thread. | ||||
* As of now, only one thread for TX desc processing is | * As of now, only one thread for TX desc processing is | ||||
* spawned. | * spawned. | ||||
*/ | */ | ||||
sc->tx_in_progress = 0; | sc->tx_in_progress = 0; | ||||
Show All 38 Lines | pci_vtnet_cfgread(void *vsc, int offset, int size, uint32_t *retval) | ||||
memcpy(retval, ptr, size); | memcpy(retval, ptr, size); | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
pci_vtnet_neg_features(void *vsc, uint64_t negotiated_features) | pci_vtnet_neg_features(void *vsc, uint64_t negotiated_features) | ||||
{ | { | ||||
struct pci_vtnet_softc *sc = vsc; | struct pci_vtnet_softc *sc = vsc; | ||||
unsigned int rx_vhdrlen = 0; | |||||
markjUnsubmitted Done Inline ActionsThe initialization is not needed. markj: The initialization is not needed. | |||||
sc->vsc_features = negotiated_features; | sc->vsc_features = negotiated_features; | ||||
if (!(negotiated_features & VIRTIO_NET_F_MRG_RXBUF)) { | if (negotiated_features & VIRTIO_NET_F_MRG_RXBUF) { | ||||
sc->rx_merge = 0; | rx_vhdrlen = sizeof(struct virtio_net_rxhdr); | ||||
sc->rx_merge = 1; | |||||
} else { | |||||
/* Without mergeable rx buffers, virtio-net header is 2 | /* Without mergeable rx buffers, virtio-net header is 2 | ||||
* bytes shorter than sizeof(struct virtio_net_rxhdr). */ | * bytes shorter than sizeof(struct virtio_net_rxhdr). */ | ||||
markjUnsubmitted Done Inline ActionsFix comment style while you're here? markj: Fix comment style while you're here? | |||||
sc->rx_vhdrlen = sizeof(struct virtio_net_rxhdr) - 2; | rx_vhdrlen = sizeof(struct virtio_net_rxhdr) - 2; | ||||
sc->rx_merge = 0; | |||||
} | } | ||||
/* 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->rx_vhdrlen); | netbe_set_cap(sc->vsc_be, negotiated_features, rx_vhdrlen); | ||||
} | } | ||||
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 | ||||
}; | }; | ||||
PCI_EMUL_SET(pci_de_vnet); | PCI_EMUL_SET(pci_de_vnet); |
My only thought is perhaps we should assume rx_merge is not supported until we negotiate that it is. The race would not have been fatal (but is still good to fix) if the default been the more compatible behavior. That is, maybe 'rx_merge' should be 0 by default instead of 1.