From owner-svn-src-user@FreeBSD.ORG Wed Apr 10 06:21:40 2013 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 1818CA8B; Wed, 10 Apr 2013 06:21:40 +0000 (UTC) (envelope-from bryanv@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id 09A286C8; Wed, 10 Apr 2013 06:21:40 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.6/8.14.6) with ESMTP id r3A6LeNb012144; Wed, 10 Apr 2013 06:21:40 GMT (envelope-from bryanv@svn.freebsd.org) Received: (from bryanv@localhost) by svn.freebsd.org (8.14.6/8.14.5/Submit) id r3A6LdbS012136; Wed, 10 Apr 2013 06:21:39 GMT (envelope-from bryanv@svn.freebsd.org) Message-Id: <201304100621.r3A6LdbS012136@svn.freebsd.org> From: Bryan Venteicher Date: Wed, 10 Apr 2013 06:21:39 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r249325 - user/bryanv/vtnetmq/sys/dev/virtio/network X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 10 Apr 2013 06:21:40 -0000 Author: bryanv Date: Wed Apr 10 06:21:39 2013 New Revision: 249325 URL: http://svnweb.freebsd.org/changeset/base/249325 Log: Commit development snapshot of the multiqueue driver This commit includes various (mostly minor) changes: - Support for instance specific and global tunables - Fix a swap argument bug that broke TSO - Initial support for the VIRTIO_NET_F_CTRL_MAC_ADDR feature - Shuffle some structure around to be more cache line friendly Modified: user/bryanv/vtnetmq/sys/dev/virtio/network/if_vtnet.c user/bryanv/vtnetmq/sys/dev/virtio/network/if_vtnetvar.h user/bryanv/vtnetmq/sys/dev/virtio/network/virtio_net.h Modified: user/bryanv/vtnetmq/sys/dev/virtio/network/if_vtnet.c ============================================================================== --- user/bryanv/vtnetmq/sys/dev/virtio/network/if_vtnet.c Wed Apr 10 05:59:07 2013 (r249324) +++ user/bryanv/vtnetmq/sys/dev/virtio/network/if_vtnet.c Wed Apr 10 06:21:39 2013 (r249325) @@ -175,6 +175,7 @@ static void vtnet_init(void *); static void vtnet_free_ctrl_vq(struct vtnet_softc *); static void vtnet_exec_ctrl_cmd(struct vtnet_softc *, void *, struct sglist *, int, int); +static int vtnet_ctrl_mac_cmd(struct vtnet_softc *, uint8_t *); static int vtnet_ctrl_mq_cmd(struct vtnet_softc *, uint16_t); static int vtnet_ctrl_rx_cmd(struct vtnet_softc *, int, int); static int vtnet_set_promisc(struct vtnet_softc *, int); @@ -214,6 +215,8 @@ static void vtnet_disable_rx_interrupts( static void vtnet_disable_tx_interrupts(struct vtnet_softc *); static void vtnet_disable_interrupts(struct vtnet_softc *); +static int vtnet_tunable_int(struct vtnet_softc *, const char *, int); + /* Tunables. */ static int vtnet_csum_disable = 0; TUNABLE_INT("hw.vtnet.csum_disable", &vtnet_csum_disable); @@ -222,10 +225,10 @@ TUNABLE_INT("hw.vtnet.tso_disable", &vtn static int vtnet_lro_disable = 0; TUNABLE_INT("hw.vtnet.lro_disable", &vtnet_lro_disable); static int vtnet_mq_disable = 0; -TUNABLE_INT("hw.vtnet.mq_dislabe", &vtnet_mq_disable); -static int vtnet_mq_max_queues = 0; -TUNABLE_INT("hw.vtnet.mq_max_queues", &vtnet_mq_max_queues); -static int vtnet_rx_process_limit = 256; +TUNABLE_INT("hw.vtnet.mq_disable", &vtnet_mq_disable); +static int vtnet_mq_max_pairs = 0; +TUNABLE_INT("hw.vtnet.mq_max_pairs", &vtnet_mq_max_pairs); +static int vtnet_rx_process_limit = 512; TUNABLE_INT("hw.vtnet.rx_process_limit", &vtnet_rx_process_limit); /* @@ -519,13 +522,15 @@ vtnet_negotiate_features(struct vtnet_so * TSO and LRO are only available when their corresponding checksum * offload feature is also negotiated. */ - if (vtnet_csum_disable) + if (vtnet_tunable_int(sc, "csum_disable", vtnet_csum_disable)) { mask |= VIRTIO_NET_F_CSUM | VIRTIO_NET_F_GUEST_CSUM; - if (vtnet_csum_disable || vtnet_tso_disable) + mask |= VTNET_TSO_FEATURES | VTNET_LRO_FEATURES; + } + if (vtnet_tunable_int(sc, "tso_disable", vtnet_tso_disable)) mask |= VTNET_TSO_FEATURES; - if (vtnet_csum_disable || vtnet_lro_disable) + if (vtnet_tunable_int(sc, "lro_disable", vtnet_lro_disable)) mask |= VTNET_LRO_FEATURES; - if (vtnet_mq_disable) + if (vtnet_tunable_int(sc, "mq_disable", vtnet_mq_disable)) mask |= VIRTIO_NET_F_MQ; features = VTNET_FEATURES & ~mask; @@ -559,12 +564,17 @@ static void vtnet_setup_features(struct vtnet_softc *sc) { device_t dev; - int max_pairs; + int max_pairs, max; dev = sc->vtnet_dev; vtnet_negotiate_features(sc); + if (virtio_with_feature(dev, VIRTIO_NET_F_MAC)) { + /* This feature should always be negotiated. */ + sc->vtnet_flags |= VTNET_FLAG_MAC; + } + if (virtio_with_feature(dev, VIRTIO_NET_F_MRG_RXBUF)) { sc->vtnet_flags |= VTNET_FLAG_MRG_RXBUFS; sc->vtnet_hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf); @@ -578,6 +588,8 @@ vtnet_setup_features(struct vtnet_softc sc->vtnet_flags |= VTNET_FLAG_CTRL_RX; if (virtio_with_feature(dev, VIRTIO_NET_F_CTRL_VLAN)) sc->vtnet_flags |= VTNET_FLAG_VLAN_FILTER; + if (virtio_with_feature(dev, VIRTIO_NET_F_CTRL_MAC_ADDR)) + sc->vtnet_flags |= VTNET_FLAG_CTRL_MAC; } if (virtio_with_feature(dev, VIRTIO_NET_F_MQ) && @@ -592,16 +604,17 @@ vtnet_setup_features(struct vtnet_softc if (max_pairs > 1) { /* - * Limit the maximum number of queue pairs to the number - * of CPUs or the configured maximum. The actual number - * of queues that get used may be less. + * Limit the maximum number of queue pairs to the number of + * CPUs or the configured maximum. The actual number of + * queues that get used may be less. */ + max = vtnet_tunable_int(sc, "mq_max_pairs", vtnet_mq_max_pairs); + if (max > 0 && max_pairs > max) + max_pairs = max; if (max_pairs > mp_ncpus) max_pairs = mp_ncpus; if (max_pairs > VTNET_MAX_QUEUE_PAIRS) max_pairs = VTNET_MAX_QUEUE_PAIRS; - if (vtnet_mq_max_queues != 0) - max_pairs = vtnet_mq_max_queues; if (max_pairs > 1) sc->vtnet_flags |= VTNET_FLAG_MULTIQ; } @@ -622,7 +635,6 @@ vtnet_init_rxq(struct vtnet_softc *sc, i rxq->vtnrx_sc = sc; rxq->vtnrx_id = id; - rxq->vtnrx_process_limit = vtnet_rx_process_limit; TASK_INIT(&rxq->vtnrx_intrtask, 0, vtnet_rxq_tq_intr, rxq); rxq->vtnrx_tq = taskqueue_create(rxq->vtnrx_name, M_NOWAIT, @@ -708,10 +720,12 @@ vtnet_destroy_txq(struct vtnet_txq *txq) txq->vtntx_sc = NULL; txq->vtntx_id = -1; +#ifndef VTNET_LEGACY_TX if (txq->vtntx_br != NULL) { buf_ring_free(txq->vtntx_br, M_DEVBUF); txq->vtntx_br = NULL; } +#endif if (mtx_initialized(&txq->vtntx_mtx) != 0) mtx_destroy(&txq->vtntx_mtx); @@ -1035,35 +1049,15 @@ vtnet_ioctl(struct ifnet *ifp, u_long cm VTNET_CORE_LOCK(sc); mask = ifr->ifr_reqcap ^ ifp->if_capenable; - if (mask & IFCAP_TXCSUM) { + if (mask & IFCAP_TXCSUM) ifp->if_capenable ^= IFCAP_TXCSUM; - if (ifp->if_capenable & IFCAP_TXCSUM) - ifp->if_hwassist |= VTNET_CSUM_OFFLOAD; - else - ifp->if_hwassist &= ~VTNET_CSUM_OFFLOAD; - } - - if (mask & IFCAP_TXCSUM_IPV6) { + if (mask & IFCAP_TXCSUM_IPV6) ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; - if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) - ifp->if_hwassist |= VTNET_CSUM_OFFLOAD_IPV6; - else - ifp->if_hwassist &= ~VTNET_CSUM_OFFLOAD_IPV6; - } - if (mask & IFCAP_TSO) { if (mask & IFCAP_TSO4) ifp->if_capenable ^= IFCAP_TSO4; if (mask & IFCAP_TSO6) ifp->if_capenable ^= IFCAP_TSO6; - /* - * Set if either is enabled. The CSUM_TSO_IPV6 flag is - * currently commented out. - */ - if (ifp->if_capenable & IFCAP_TSO) - ifp->if_hwassist |= CSUM_TSO; - else - ifp->if_hwassist &= ~CSUM_TSO; } if (mask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6 | IFCAP_LRO | @@ -1423,10 +1417,10 @@ vtnet_rxq_csum_by_offset(struct vtnet_rx } /* - * Use the offset to determine the appropriate CSUM_* flags. This - * is a bit dirty, but we can get by with it since the checksum - * offsets happen to be different. We assume the host host does - * not do IPv4 header checksum offloading. + * Use the offset to determine the appropriate CSUM_* flags. This is + * a bit dirty, but we can get by with it since the checksum offsets + * happen to be different. We assume the host host does not do IPv4 + * header checksum offloading. */ switch (hdr->csum_offset) { case offsetof(struct udphdr, uh_sum): @@ -1648,7 +1642,7 @@ vtnet_rxq_input(struct vtnet_rxq *rxq, s m->m_flags |= M_FLOWID; /* - * BVM: FreeBSD does not have the UNNECESSARY and PARTIAL checksum + * BMV: FreeBSD does not have the UNNECESSARY and PARTIAL checksum * distinction that Linux does. Need to reevaluate if performing * offloading for the NEEDS_CSUM case is really appropriate. */ @@ -1686,7 +1680,7 @@ vtnet_rxq_eof(struct vtnet_rxq *rxq) hdr = &lhdr; deq = 0; - count = rxq->vtnrx_process_limit; + count = sc->vtnet_rx_process_limit; VTNET_RXQ_LOCK_ASSERT(rxq); @@ -1962,7 +1956,7 @@ vtnet_txq_offload(struct vtnet_txq *txq, sc = txq->vtntx_sc; flags = m->m_pkthdr.csum_flags; - error = vtnet_txq_offload_ctx(txq, m, &etype, &csum_start, &proto); + error = vtnet_txq_offload_ctx(txq, m, &etype, &proto, &csum_start); if (error) goto drop; @@ -2695,7 +2689,7 @@ vtnet_virtio_reinit(struct vtnet_softc * if (ifp->if_capabilities & _RXCSUM_IPV46) { /* * We require both IPv4 and IPv6 offloading to be enabled - * inorder to negotiated it: VirtIO does not distinguish + * in order to negotiated it: VirtIO does not distinguish * between the two. * * BMV: What about when INET and/or INET6 is not defined? @@ -2736,7 +2730,6 @@ vtnet_init_rx_filters(struct vtnet_softc vtnet_rx_filter_mac(sc); } - /* Restore filtered VLANs. */ if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) vtnet_rx_filter_vlan(sc); } @@ -2746,11 +2739,21 @@ vtnet_init_rx_queues(struct vtnet_softc { device_t dev; struct vtnet_rxq *rxq; - int i, clsize, error; + int i, limit, clsize, error; dev = sc->vtnet_dev; /* + * Assume the same limit is appropriate for all the Rx queues. + * We may later want to scale this by each virtqueue's size. + */ + limit = vtnet_tunable_int(sc, "rx_process_limit", + vtnet_rx_process_limit); + if (limit < 0) + limit = INT_MAX; + sc->vtnet_rx_process_limit = limit; + + /* * Use the new cluster size if one has been set (via a MTU * change). Otherwise, use the standard 2K clusters. * @@ -2974,6 +2977,32 @@ vtnet_exec_ctrl_cmd(struct vtnet_softc * } static int +vtnet_ctrl_mac_cmd(struct vtnet_softc *sc, uint8_t *hwaddr) +{ + struct virtio_net_ctrl_hdr hdr; + struct sglist_seg segs[3]; + struct sglist sg; + uint8_t ack; + int error; + + hdr.class = VIRTIO_NET_CTRL_MAC; + hdr.cmd = VIRTIO_NET_CTRL_MAC_ADDR_SET; + ack = VIRTIO_NET_ERR; + + sglist_init(&sg, 3, segs); + error = 0; + error |= sglist_append(&sg, &hdr, sizeof(struct virtio_net_ctrl_hdr)); + error |= sglist_append(&sg, hwaddr, ETHER_ADDR_LEN); + error |= sglist_append(&sg, &ack, sizeof(uint8_t)); + KASSERT(error == 0 && sg.sg_nseg == 3, + ("%s: error %d adding set MAC msg to sglist", __func__, error)); + + vtnet_exec_ctrl_cmd(sc, &ack, &sg, sg.sg_nseg - 1, 1); + + return (ack == VIRTIO_NET_OK ? 0 : EIO); +} + +static int vtnet_ctrl_mq_cmd(struct vtnet_softc *sc, uint16_t npairs) { struct sglist_seg segs[3]; @@ -2987,9 +3016,6 @@ vtnet_ctrl_mq_cmd(struct vtnet_softc *sc } s; int error; - if ((sc->vtnet_flags & VTNET_FLAG_CTRL_VQ) == 0) - return (ENOTSUP); - s.hdr.class = VIRTIO_NET_CTRL_MQ; s.hdr.cmd = VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET; s.mq.virtqueue_pairs = npairs; @@ -3204,12 +3230,10 @@ vtnet_rx_filter_mac(struct vtnet_softc * if_printf(ifp, "error setting host MAC filter table\n"); out: - if (promisc) - if (vtnet_set_promisc(sc, 1) != 0) - if_printf(ifp, "cannot enable promiscuous mode\n"); - if (allmulti) - if (vtnet_set_allmulti(sc, 1) != 0) - if_printf(ifp, "cannot enable all-multicast mode\n"); + if (promisc && vtnet_set_promisc(sc, 1) != 0) + if_printf(ifp, "cannot enable promiscuous mode\n"); + if (allmulti && vtnet_set_allmulti(sc, 1) != 0) + if_printf(ifp, "cannot enable all-multicast mode\n"); } static int @@ -3286,11 +3310,6 @@ vtnet_update_vlan_filter(struct vtnet_so VTNET_CORE_LOCK(sc); - /* - * Update the in-memory table. We must keep the table current with - * configured VLANs even if HW filtering is disabled, since it could - * be enabled later. - */ if (add) sc->vtnet_vlan_filter[idx] |= (1 << bit); else @@ -3407,8 +3426,14 @@ vtnet_set_hwaddr(struct vtnet_softc *sc) dev = sc->vtnet_dev; - virtio_write_device_config(dev, offsetof(struct virtio_net_config, mac), - sc->vtnet_hwaddr, ETHER_ADDR_LEN); + if (sc->vtnet_flags & VTNET_FLAG_CTRL_MAC) { + if (vtnet_ctrl_mac_cmd(sc, sc->vtnet_hwaddr) != 0) + device_printf(dev, "unable to set MAC address\n"); + } else if (sc->vtnet_flags & VTNET_FLAG_MAC) { + virtio_write_device_config(dev, + offsetof(struct virtio_net_config, mac), + sc->vtnet_hwaddr, ETHER_ADDR_LEN); + } } static void @@ -3418,7 +3443,7 @@ vtnet_get_hwaddr(struct vtnet_softc *sc) dev = sc->vtnet_dev; - if (virtio_with_feature(dev, VIRTIO_NET_F_MAC) == 0) { + if ((sc->vtnet_flags & VTNET_FLAG_MAC) == 0) { /* * Generate a random locally administered unicast address. * @@ -3707,3 +3732,15 @@ vtnet_disable_interrupts(struct vtnet_so vtnet_disable_rx_interrupts(sc); vtnet_disable_tx_interrupts(sc); } + +static int +vtnet_tunable_int(struct vtnet_softc *sc, const char *knob, int def) +{ + char path[64]; + + snprintf(path, sizeof(path), + "hw.vtnet.%d.%s", device_get_unit(sc->vtnet_dev), knob); + TUNABLE_INT_FETCH(path, &def); + + return (def); +} Modified: user/bryanv/vtnetmq/sys/dev/virtio/network/if_vtnetvar.h ============================================================================== --- user/bryanv/vtnetmq/sys/dev/virtio/network/if_vtnetvar.h Wed Apr 10 05:59:07 2013 (r249324) +++ user/bryanv/vtnetmq/sys/dev/virtio/network/if_vtnetvar.h Wed Apr 10 06:21:39 2013 (r249325) @@ -100,7 +100,9 @@ struct vtnet_txq { struct mtx vtntx_mtx; struct vtnet_softc *vtntx_sc; struct virtqueue *vtntx_vq; +#ifndef VTNET_LEGACY_TX struct buf_ring *vtntx_br; +#endif int vtntx_id; int vtntx_watchdog; struct vtnet_txq_stats vtntx_stats; @@ -123,43 +125,45 @@ struct vtnet_txq { struct vtnet_softc { device_t vtnet_dev; struct ifnet *vtnet_ifp; - struct mtx vtnet_mtx; + struct vtnet_rxq *vtnet_rxqs; + struct vtnet_txq *vtnet_txqs; uint32_t vtnet_flags; #define VTNET_FLAG_SUSPENDED 0x0001 -#define VTNET_FLAG_CTRL_VQ 0x0002 -#define VTNET_FLAG_CTRL_RX 0x0004 -#define VTNET_FLAG_VLAN_FILTER 0x0008 -#define VTNET_FLAG_TSO_ECN 0x0010 -#define VTNET_FLAG_MRG_RXBUFS 0x0020 -#define VTNET_FLAG_LRO_NOMRG 0x0040 -#define VTNET_FLAG_MULTIQ 0x0080 - - struct vtnet_rxq *vtnet_rxqs; - struct vtnet_txq *vtnet_txqs; - struct virtqueue *vtnet_ctrl_vq; +#define VTNET_FLAG_MAC 0x0002 +#define VTNET_FLAG_CTRL_VQ 0x0004 +#define VTNET_FLAG_CTRL_RX 0x0008 +#define VTNET_FLAG_CTRL_MAC 0x0010 +#define VTNET_FLAG_VLAN_FILTER 0x0020 +#define VTNET_FLAG_TSO_ECN 0x0040 +#define VTNET_FLAG_MRG_RXBUFS 0x0080 +#define VTNET_FLAG_LRO_NOMRG 0x0100 +#define VTNET_FLAG_MULTIQ 0x0200 - int vtnet_hdr_size; int vtnet_link_active; + int vtnet_hdr_size; + int vtnet_rx_process_limit; int vtnet_rx_nmbufs; int vtnet_rx_clsize; int vtnet_rx_new_clsize; int vtnet_if_flags; int vtnet_act_vq_pairs; int vtnet_max_vq_pairs; - uint64_t vtnet_features; - - struct vtnet_statistics vtnet_stats; - struct callout vtnet_tick_ch; + struct virtqueue *vtnet_ctrl_vq; struct vtnet_mac_filter *vtnet_mac_filter; uint32_t *vtnet_vlan_filter; + + uint64_t vtnet_features; + struct vtnet_statistics vtnet_stats; + struct callout vtnet_tick_ch; struct ifmedia vtnet_media; eventhandler_tag vtnet_vlan_attach; eventhandler_tag vtnet_vlan_detach; - char vtnet_hwaddr[ETHER_ADDR_LEN]; + struct mtx vtnet_mtx; char vtnet_mtx_name[16]; + char vtnet_hwaddr[ETHER_ADDR_LEN]; }; /* @@ -181,8 +185,8 @@ struct vtnet_softc { #define VTNET_MEDIATYPE (IFM_ETHER | IFM_10G_T | IFM_FDX) /* - * Number of words to allocate for the VLAN shadow table. Each possible - * VLAN gets one bit. + * Number of words to allocate for the VLAN shadow table. There is one + * bit for each VLAN. */ #define VTNET_VLAN_FILTER_NWORDS (4096 / 32) @@ -263,7 +267,6 @@ CTASSERT(sizeof(struct vtnet_mac_filter) VIRTIO_NET_F_GUEST_TSO6 | \ VIRTIO_NET_F_GUEST_ECN | \ VIRTIO_NET_F_MRG_RXBUF | \ - VIRTIO_NET_F_MQ | \ VIRTIO_RING_F_INDIRECT_DESC) /* Modified: user/bryanv/vtnetmq/sys/dev/virtio/network/virtio_net.h ============================================================================== --- user/bryanv/vtnetmq/sys/dev/virtio/network/virtio_net.h Wed Apr 10 05:59:07 2013 (r249324) +++ user/bryanv/vtnetmq/sys/dev/virtio/network/virtio_net.h Wed Apr 10 06:21:39 2013 (r249325) @@ -51,7 +51,8 @@ #define VIRTIO_NET_F_CTRL_VLAN 0x80000 /* Control channel VLAN filtering */ #define VIRTIO_NET_F_CTRL_RX_EXTRA 0x100000 /* Extra RX mode control support */ #define VIRTIO_NET_F_GUEST_ANNOUNCE 0x200000 /* Announce device on network */ -#define VIRTIO_NET_F_MQ 0x400000 +#define VIRTIO_NET_F_MQ 0x400000 /* Device supports RFS */ +#define VIRTIO_NET_F_CTRL_MAC_ADDR 0x800000 /* Set MAC address */ #define VIRTIO_NET_S_LINK_UP 1 /* Link is up */ @@ -142,6 +143,10 @@ typedef uint8_t virtio_net_ctrl_ack; * first sg list contains unicast addresses, the second is for multicast. * This functionality is present if the VIRTIO_NET_F_CTRL_RX feature * is available. + * + * The ADDR_SET command requests one out scatterlist, it contains a + * 6 bytes MAC address. This functionality is present if the + * VIRTIO_NET_F_CTRL_MAC_ADDR feature is available. */ struct virtio_net_ctrl_mac { uint32_t entries; @@ -150,6 +155,7 @@ struct virtio_net_ctrl_mac { #define VIRTIO_NET_CTRL_MAC 1 #define VIRTIO_NET_CTRL_MAC_TABLE_SET 0 +#define VIRTIO_NET_CTRL_MAC_ADDR_SET 1 /* * Control VLAN filtering