From owner-svn-src-head@FreeBSD.ORG Tue Sep 9 22:35:02 2014 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id BAE86887; Tue, 9 Sep 2014 22:35:02 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 9AD9D226; Tue, 9 Sep 2014 22:35:02 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s89MZ2nB033994; Tue, 9 Sep 2014 22:35:02 GMT (envelope-from grehan@FreeBSD.org) Received: (from grehan@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id s89MZ2Cc033993; Tue, 9 Sep 2014 22:35:02 GMT (envelope-from grehan@FreeBSD.org) Message-Id: <201409092235.s89MZ2Cc033993@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: grehan set sender to grehan@FreeBSD.org using -f From: Peter Grehan Date: Tue, 9 Sep 2014 22:35:02 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r271338 - head/usr.sbin/bhyve X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Sep 2014 22:35:02 -0000 Author: grehan Date: Tue Sep 9 22:35:02 2014 New Revision: 271338 URL: http://svnweb.freebsd.org/changeset/base/271338 Log: Allow vtnet operation without merged rx buffers. NetBSD's virtio-net implementation doesn't negotiate the merged rx-buffers feature. To support this, check to see if the feature was negotiated, and then adjust the operation of the receive path accordingly by using a larger iovec, and a smaller rx header. In addition, ignore writes to the (read-only) status byte. Tested with NetBSD/amd64 5.2.2, 6.1.4 and 7-beta. Reviewed by: neel, tychon Phabric: D745 MFC after: 3 days Modified: head/usr.sbin/bhyve/pci_virtio_net.c Modified: head/usr.sbin/bhyve/pci_virtio_net.c ============================================================================== --- head/usr.sbin/bhyve/pci_virtio_net.c Tue Sep 9 22:24:01 2014 (r271337) +++ head/usr.sbin/bhyve/pci_virtio_net.c Tue Sep 9 22:35:02 2014 (r271338) @@ -135,11 +135,14 @@ struct pci_vtnet_softc { int vsc_rx_ready; volatile int resetting; /* set and checked outside lock */ - uint32_t vsc_features; + uint64_t vsc_features; /* negotiated features */ + struct virtio_net_config vsc_config; pthread_mutex_t rx_mtx; int rx_in_progress; + int rx_vhdrlen; + int rx_merge; /* merged rx bufs in use */ pthread_t tx_tid; pthread_mutex_t tx_mtx; @@ -151,6 +154,7 @@ static void pci_vtnet_reset(void *); /* static void pci_vtnet_notify(void *, struct vqueue_info *); */ static int pci_vtnet_cfgread(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 struct virtio_consts vtnet_vi_consts = { "vtnet", /* our name */ @@ -160,7 +164,7 @@ static struct virtio_consts vtnet_vi_con NULL, /* device-wide qnotify -- not used */ pci_vtnet_cfgread, /* read PCI config */ pci_vtnet_cfgwrite, /* write PCI config */ - NULL, /* apply negotiated features */ + pci_vtnet_neg_features, /* apply negotiated features */ VTNET_S_HOSTCAPS, /* our capabilities */ }; @@ -213,6 +217,8 @@ pci_vtnet_reset(void *vsc) pci_vtnet_rxwait(sc); sc->vsc_rx_ready = 0; + sc->rx_merge = 1; + sc->rx_vhdrlen = sizeof(struct virtio_net_rxhdr); /* now reset rings, MSI-X vectors, and negotiated capabilities */ vi_reset_dev(&sc->vsc_vs); @@ -254,14 +260,34 @@ pci_vtnet_tap_tx(struct pci_vtnet_softc */ static uint8_t dummybuf[2048]; +static __inline struct iovec * +rx_iov_trim(struct iovec *iov, int *niov, int tlen) +{ + struct iovec *riov; + + /* XXX short-cut: assume first segment is >= tlen */ + assert(iov[0].iov_len >= tlen); + + iov[0].iov_len -= tlen; + if (iov[0].iov_len == 0) { + assert(*niov > 1); + *niov -= 1; + riov = &iov[1]; + } else { + iov[0].iov_base = (void *)((uintptr_t)iov[0].iov_base + tlen); + riov = &iov[0]; + } + + return (riov); +} + static void pci_vtnet_tap_rx(struct pci_vtnet_softc *sc) { + struct iovec iov[VTNET_MAXSEGS], *riov; struct vqueue_info *vq; - struct virtio_net_rxhdr *vrx; - uint8_t *buf; - int len; - struct iovec iov; + void *vrx; + int len, n; /* * Should never be called without a valid tap fd @@ -297,21 +323,19 @@ pci_vtnet_tap_rx(struct pci_vtnet_softc do { /* - * Get descriptor chain, which should have just - * one descriptor in it. - * ??? allow guests to use multiple descs? + * Get descriptor chain. */ - assert(vq_getchain(vq, &iov, 1, NULL) == 1); + n = vq_getchain(vq, iov, VTNET_MAXSEGS, NULL); + assert(n >= 1 && n <= VTNET_MAXSEGS); /* * Get a pointer to the rx header, and use the * data immediately following it for the packet buffer. */ - vrx = iov.iov_base; - buf = (uint8_t *)(vrx + 1); + vrx = iov[0].iov_base; + riov = rx_iov_trim(iov, &n, sc->rx_vhdrlen); - len = read(sc->vsc_tapfd, buf, - iov.iov_len - sizeof(struct virtio_net_rxhdr)); + len = readv(sc->vsc_tapfd, riov, n); if (len < 0 && errno == EWOULDBLOCK) { /* @@ -324,16 +348,21 @@ pci_vtnet_tap_rx(struct pci_vtnet_softc /* * The only valid field in the rx packet header is the - * number of buffers, which is always 1 without TSO - * support. + * number of buffers if merged rx bufs were negotiated. */ - memset(vrx, 0, sizeof(struct virtio_net_rxhdr)); - vrx->vrh_bufs = 1; + memset(vrx, 0, sc->rx_vhdrlen); + + if (sc->rx_merge) { + struct virtio_net_rxhdr *vrxh; + + vrxh = vrx; + vrxh->vrh_bufs = 1; + } /* * Release this chain and handle more chains. */ - vq_relchain(vq, len + sizeof(struct virtio_net_rxhdr)); + vq_relchain(vq, len + sc->rx_vhdrlen); } while (vq_has_descs(vq)); /* Interrupt if needed, including for NOTIFY_ON_EMPTY. */ @@ -624,6 +653,8 @@ pci_vtnet_init(struct vmctx *ctx, struct sc->resetting = 0; + sc->rx_merge = 1; + sc->rx_vhdrlen = sizeof(struct virtio_net_rxhdr); sc->rx_in_progress = 0; pthread_mutex_init(&sc->rx_mtx, NULL); @@ -657,9 +688,10 @@ pci_vtnet_cfgwrite(void *vsc, int offset ptr = &sc->vsc_config.mac[offset]; memcpy(ptr, &value, size); } else { + /* silently ignore other writes */ DPRINTF(("vtnet: write to readonly reg %d\n\r", offset)); - return (1); } + return (0); } @@ -674,6 +706,20 @@ pci_vtnet_cfgread(void *vsc, int offset, return (0); } +static void +pci_vtnet_neg_features(void *vsc, uint64_t negotiated_features) +{ + struct pci_vtnet_softc *sc = vsc; + + sc->vsc_features = negotiated_features; + + if (!(sc->vsc_features & VIRTIO_NET_F_MRG_RXBUF)) { + sc->rx_merge = 0; + /* non-merge rx header is 2 bytes shorter */ + sc->rx_vhdrlen -= 2; + } +} + struct pci_devemu pci_de_vnet = { .pe_emu = "virtio-net", .pe_init = pci_vtnet_init,