pci_virtio_net.c (268953) | pci_virtio_net.c (271685) |
---|---|
1/*- 2 * Copyright (c) 2011 NetApp, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 9 unchanged lines hidden (view full) --- 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * | 1/*- 2 * Copyright (c) 2011 NetApp, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 9 unchanged lines hidden (view full) --- 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * |
26 * $FreeBSD: stable/10/usr.sbin/bhyve/pci_virtio_net.c 268953 2014-07-21 19:08:02Z jhb $ | 26 * $FreeBSD: stable/10/usr.sbin/bhyve/pci_virtio_net.c 271685 2014-09-16 19:08:54Z grehan $ |
27 */ 28 29#include <sys/cdefs.h> | 27 */ 28 29#include <sys/cdefs.h> |
30__FBSDID("$FreeBSD: stable/10/usr.sbin/bhyve/pci_virtio_net.c 268953 2014-07-21 19:08:02Z jhb $"); | 30__FBSDID("$FreeBSD: stable/10/usr.sbin/bhyve/pci_virtio_net.c 271685 2014-09-16 19:08:54Z grehan $"); |
31 32#include <sys/param.h> 33#include <sys/linker_set.h> 34#include <sys/select.h> 35#include <sys/uio.h> 36#include <sys/ioctl.h> 37#include <net/ethernet.h> 38 --- 91 unchanged lines hidden (view full) --- 130 struct vqueue_info vsc_queues[VTNET_MAXQ - 1]; 131 pthread_mutex_t vsc_mtx; 132 struct mevent *vsc_mevp; 133 134 int vsc_tapfd; 135 int vsc_rx_ready; 136 volatile int resetting; /* set and checked outside lock */ 137 | 31 32#include <sys/param.h> 33#include <sys/linker_set.h> 34#include <sys/select.h> 35#include <sys/uio.h> 36#include <sys/ioctl.h> 37#include <net/ethernet.h> 38 --- 91 unchanged lines hidden (view full) --- 130 struct vqueue_info vsc_queues[VTNET_MAXQ - 1]; 131 pthread_mutex_t vsc_mtx; 132 struct mevent *vsc_mevp; 133 134 int vsc_tapfd; 135 int vsc_rx_ready; 136 volatile int resetting; /* set and checked outside lock */ 137 |
138 uint32_t vsc_features; | 138 uint64_t vsc_features; /* negotiated features */ 139 |
139 struct virtio_net_config vsc_config; 140 141 pthread_mutex_t rx_mtx; 142 int rx_in_progress; | 140 struct virtio_net_config vsc_config; 141 142 pthread_mutex_t rx_mtx; 143 int rx_in_progress; |
144 int rx_vhdrlen; 145 int rx_merge; /* merged rx bufs in use */ |
|
143 144 pthread_t tx_tid; 145 pthread_mutex_t tx_mtx; 146 pthread_cond_t tx_cond; 147 int tx_in_progress; 148}; 149 150static void pci_vtnet_reset(void *); 151/* static void pci_vtnet_notify(void *, struct vqueue_info *); */ 152static int pci_vtnet_cfgread(void *, int, int, uint32_t *); 153static int pci_vtnet_cfgwrite(void *, int, int, uint32_t); | 146 147 pthread_t tx_tid; 148 pthread_mutex_t tx_mtx; 149 pthread_cond_t tx_cond; 150 int tx_in_progress; 151}; 152 153static void pci_vtnet_reset(void *); 154/* static void pci_vtnet_notify(void *, struct vqueue_info *); */ 155static int pci_vtnet_cfgread(void *, int, int, uint32_t *); 156static int pci_vtnet_cfgwrite(void *, int, int, uint32_t); |
157static void pci_vtnet_neg_features(void *, uint64_t); |
|
154 155static struct virtio_consts vtnet_vi_consts = { 156 "vtnet", /* our name */ 157 VTNET_MAXQ - 1, /* we currently support 2 virtqueues */ 158 sizeof(struct virtio_net_config), /* config reg size */ 159 pci_vtnet_reset, /* reset */ 160 NULL, /* device-wide qnotify -- not used */ 161 pci_vtnet_cfgread, /* read PCI config */ 162 pci_vtnet_cfgwrite, /* write PCI config */ | 158 159static struct virtio_consts vtnet_vi_consts = { 160 "vtnet", /* our name */ 161 VTNET_MAXQ - 1, /* we currently support 2 virtqueues */ 162 sizeof(struct virtio_net_config), /* config reg size */ 163 pci_vtnet_reset, /* reset */ 164 NULL, /* device-wide qnotify -- not used */ 165 pci_vtnet_cfgread, /* read PCI config */ 166 pci_vtnet_cfgwrite, /* write PCI config */ |
167 pci_vtnet_neg_features, /* apply negotiated features */ |
|
163 VTNET_S_HOSTCAPS, /* our capabilities */ 164}; 165 166/* 167 * If the transmit thread is active then stall until it is done. 168 */ 169static void 170pci_vtnet_txwait(struct pci_vtnet_softc *sc) --- 36 unchanged lines hidden (view full) --- 207 /* 208 * Wait for the transmit and receive threads to finish their 209 * processing. 210 */ 211 pci_vtnet_txwait(sc); 212 pci_vtnet_rxwait(sc); 213 214 sc->vsc_rx_ready = 0; | 168 VTNET_S_HOSTCAPS, /* our capabilities */ 169}; 170 171/* 172 * If the transmit thread is active then stall until it is done. 173 */ 174static void 175pci_vtnet_txwait(struct pci_vtnet_softc *sc) --- 36 unchanged lines hidden (view full) --- 212 /* 213 * Wait for the transmit and receive threads to finish their 214 * processing. 215 */ 216 pci_vtnet_txwait(sc); 217 pci_vtnet_rxwait(sc); 218 219 sc->vsc_rx_ready = 0; |
220 sc->rx_merge = 1; 221 sc->rx_vhdrlen = sizeof(struct virtio_net_rxhdr); |
|
215 216 /* now reset rings, MSI-X vectors, and negotiated capabilities */ 217 vi_reset_dev(&sc->vsc_vs); 218 219 sc->resetting = 0; 220} 221 222/* --- 25 unchanged lines hidden (view full) --- 248 * Called when there is read activity on the tap file descriptor. 249 * Each buffer posted by the guest is assumed to be able to contain 250 * an entire ethernet frame + rx header. 251 * MP note: the dummybuf is only used for discarding frames, so there 252 * is no need for it to be per-vtnet or locked. 253 */ 254static uint8_t dummybuf[2048]; 255 | 222 223 /* now reset rings, MSI-X vectors, and negotiated capabilities */ 224 vi_reset_dev(&sc->vsc_vs); 225 226 sc->resetting = 0; 227} 228 229/* --- 25 unchanged lines hidden (view full) --- 255 * Called when there is read activity on the tap file descriptor. 256 * Each buffer posted by the guest is assumed to be able to contain 257 * an entire ethernet frame + rx header. 258 * MP note: the dummybuf is only used for discarding frames, so there 259 * is no need for it to be per-vtnet or locked. 260 */ 261static uint8_t dummybuf[2048]; 262 |
263static __inline struct iovec * 264rx_iov_trim(struct iovec *iov, int *niov, int tlen) 265{ 266 struct iovec *riov; 267 268 /* XXX short-cut: assume first segment is >= tlen */ 269 assert(iov[0].iov_len >= tlen); 270 271 iov[0].iov_len -= tlen; 272 if (iov[0].iov_len == 0) { 273 assert(*niov > 1); 274 *niov -= 1; 275 riov = &iov[1]; 276 } else { 277 iov[0].iov_base = (void *)((uintptr_t)iov[0].iov_base + tlen); 278 riov = &iov[0]; 279 } 280 281 return (riov); 282} 283 |
|
256static void 257pci_vtnet_tap_rx(struct pci_vtnet_softc *sc) 258{ | 284static void 285pci_vtnet_tap_rx(struct pci_vtnet_softc *sc) 286{ |
287 struct iovec iov[VTNET_MAXSEGS], *riov; |
|
259 struct vqueue_info *vq; | 288 struct vqueue_info *vq; |
260 struct virtio_net_rxhdr *vrx; 261 uint8_t *buf; 262 int len; 263 struct iovec iov; | 289 void *vrx; 290 int len, n; |
264 265 /* 266 * Should never be called without a valid tap fd 267 */ 268 assert(sc->vsc_tapfd != -1); 269 270 /* 271 * But, will be called when the rx ring hasn't yet --- 19 unchanged lines hidden (view full) --- 291 */ 292 (void) read(sc->vsc_tapfd, dummybuf, sizeof(dummybuf)); 293 vq_endchains(vq, 1); 294 return; 295 } 296 297 do { 298 /* | 291 292 /* 293 * Should never be called without a valid tap fd 294 */ 295 assert(sc->vsc_tapfd != -1); 296 297 /* 298 * But, will be called when the rx ring hasn't yet --- 19 unchanged lines hidden (view full) --- 318 */ 319 (void) read(sc->vsc_tapfd, dummybuf, sizeof(dummybuf)); 320 vq_endchains(vq, 1); 321 return; 322 } 323 324 do { 325 /* |
299 * Get descriptor chain, which should have just 300 * one descriptor in it. 301 * ??? allow guests to use multiple descs? | 326 * Get descriptor chain. |
302 */ | 327 */ |
303 assert(vq_getchain(vq, &iov, 1, NULL) == 1); | 328 n = vq_getchain(vq, iov, VTNET_MAXSEGS, NULL); 329 assert(n >= 1 && n <= VTNET_MAXSEGS); |
304 305 /* 306 * Get a pointer to the rx header, and use the 307 * data immediately following it for the packet buffer. 308 */ | 330 331 /* 332 * Get a pointer to the rx header, and use the 333 * data immediately following it for the packet buffer. 334 */ |
309 vrx = iov.iov_base; 310 buf = (uint8_t *)(vrx + 1); | 335 vrx = iov[0].iov_base; 336 riov = rx_iov_trim(iov, &n, sc->rx_vhdrlen); |
311 | 337 |
312 len = read(sc->vsc_tapfd, buf, 313 iov.iov_len - sizeof(struct virtio_net_rxhdr)); | 338 len = readv(sc->vsc_tapfd, riov, n); |
314 315 if (len < 0 && errno == EWOULDBLOCK) { 316 /* 317 * No more packets, but still some avail ring 318 * entries. Interrupt if needed/appropriate. 319 */ 320 vq_endchains(vq, 0); 321 return; 322 } 323 324 /* 325 * The only valid field in the rx packet header is the | 339 340 if (len < 0 && errno == EWOULDBLOCK) { 341 /* 342 * No more packets, but still some avail ring 343 * entries. Interrupt if needed/appropriate. 344 */ 345 vq_endchains(vq, 0); 346 return; 347 } 348 349 /* 350 * The only valid field in the rx packet header is the |
326 * number of buffers, which is always 1 without TSO 327 * support. | 351 * number of buffers if merged rx bufs were negotiated. |
328 */ | 352 */ |
329 memset(vrx, 0, sizeof(struct virtio_net_rxhdr)); 330 vrx->vrh_bufs = 1; | 353 memset(vrx, 0, sc->rx_vhdrlen); |
331 | 354 |
355 if (sc->rx_merge) { 356 struct virtio_net_rxhdr *vrxh; 357 358 vrxh = vrx; 359 vrxh->vrh_bufs = 1; 360 } 361 |
|
332 /* 333 * Release this chain and handle more chains. 334 */ | 362 /* 363 * Release this chain and handle more chains. 364 */ |
335 vq_relchain(vq, len + sizeof(struct virtio_net_rxhdr)); | 365 vq_relchain(vq, len + sc->rx_vhdrlen); |
336 } while (vq_has_descs(vq)); 337 338 /* Interrupt if needed, including for NOTIFY_ON_EMPTY. */ 339 vq_endchains(vq, 1); 340} 341 342static void 343pci_vtnet_tap_callback(int fd, enum ev_type type, void *param) --- 274 unchanged lines hidden (view full) --- 618 if (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix())) 619 return (1); 620 621 /* use BAR 0 to map config regs in IO space */ 622 vi_set_io_bar(&sc->vsc_vs, 0); 623 624 sc->resetting = 0; 625 | 366 } while (vq_has_descs(vq)); 367 368 /* Interrupt if needed, including for NOTIFY_ON_EMPTY. */ 369 vq_endchains(vq, 1); 370} 371 372static void 373pci_vtnet_tap_callback(int fd, enum ev_type type, void *param) --- 274 unchanged lines hidden (view full) --- 648 if (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix())) 649 return (1); 650 651 /* use BAR 0 to map config regs in IO space */ 652 vi_set_io_bar(&sc->vsc_vs, 0); 653 654 sc->resetting = 0; 655 |
656 sc->rx_merge = 1; 657 sc->rx_vhdrlen = sizeof(struct virtio_net_rxhdr); |
|
626 sc->rx_in_progress = 0; 627 pthread_mutex_init(&sc->rx_mtx, NULL); 628 629 /* 630 * Initialize tx semaphore & spawn TX processing thread. 631 * As of now, only one thread for TX desc processing is 632 * spawned. 633 */ --- 17 unchanged lines hidden (view full) --- 651 if (offset < 6) { 652 assert(offset + size <= 6); 653 /* 654 * The driver is allowed to change the MAC address 655 */ 656 ptr = &sc->vsc_config.mac[offset]; 657 memcpy(ptr, &value, size); 658 } else { | 658 sc->rx_in_progress = 0; 659 pthread_mutex_init(&sc->rx_mtx, NULL); 660 661 /* 662 * Initialize tx semaphore & spawn TX processing thread. 663 * As of now, only one thread for TX desc processing is 664 * spawned. 665 */ --- 17 unchanged lines hidden (view full) --- 683 if (offset < 6) { 684 assert(offset + size <= 6); 685 /* 686 * The driver is allowed to change the MAC address 687 */ 688 ptr = &sc->vsc_config.mac[offset]; 689 memcpy(ptr, &value, size); 690 } else { |
691 /* silently ignore other writes */ |
|
659 DPRINTF(("vtnet: write to readonly reg %d\n\r", offset)); | 692 DPRINTF(("vtnet: write to readonly reg %d\n\r", offset)); |
660 return (1); | |
661 } | 693 } |
694 |
|
662 return (0); 663} 664 665static int 666pci_vtnet_cfgread(void *vsc, int offset, int size, uint32_t *retval) 667{ 668 struct pci_vtnet_softc *sc = vsc; 669 void *ptr; 670 671 ptr = (uint8_t *)&sc->vsc_config + offset; 672 memcpy(retval, ptr, size); 673 return (0); 674} 675 | 695 return (0); 696} 697 698static int 699pci_vtnet_cfgread(void *vsc, int offset, int size, uint32_t *retval) 700{ 701 struct pci_vtnet_softc *sc = vsc; 702 void *ptr; 703 704 ptr = (uint8_t *)&sc->vsc_config + offset; 705 memcpy(retval, ptr, size); 706 return (0); 707} 708 |
709static void 710pci_vtnet_neg_features(void *vsc, uint64_t negotiated_features) 711{ 712 struct pci_vtnet_softc *sc = vsc; 713 714 sc->vsc_features = negotiated_features; 715 716 if (!(sc->vsc_features & VIRTIO_NET_F_MRG_RXBUF)) { 717 sc->rx_merge = 0; 718 /* non-merge rx header is 2 bytes shorter */ 719 sc->rx_vhdrlen -= 2; 720 } 721} 722 |
|
676struct pci_devemu pci_de_vnet = { 677 .pe_emu = "virtio-net", 678 .pe_init = pci_vtnet_init, 679 .pe_barwrite = vi_pci_write, 680 .pe_barread = vi_pci_read 681}; 682PCI_EMUL_SET(pci_de_vnet); | 723struct pci_devemu pci_de_vnet = { 724 .pe_emu = "virtio-net", 725 .pe_init = pci_vtnet_init, 726 .pe_barwrite = vi_pci_write, 727 .pe_barread = vi_pci_read 728}; 729PCI_EMUL_SET(pci_de_vnet); |