From patchwork Thu Jun 28 03:19:37 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "John Daley (johndale)" X-Patchwork-Id: 41781 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id D4B5F5B36; Thu, 28 Jun 2018 05:25:41 +0200 (CEST) Received: from alln-iport-1.cisco.com (alln-iport-1.cisco.com [173.37.142.88]) by dpdk.org (Postfix) with ESMTP id 49D5A5B20 for ; Thu, 28 Jun 2018 05:25:40 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=cisco.com; i=@cisco.com; l=10092; q=dns/txt; s=iport; t=1530156340; x=1531365940; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=hiFzwqa5BKQioiup/I88pZkDvulO3/JtevHVhI6cc8s=; b=Vy2Ba9SFW6V0xv78qMEVywHnaqJXDJctflXdqI5Zz8vGyiEjIRKTv3TU ZFxs+68U5HTa985NzQWG18xdDklaO4aZ9TNRg4q2ZigHIFxZC7H4Q4Y1n 6ouxFP+ehsm40lVjvQjUiwVv3vbylRbCTpjBpxqYfYiWyGKVLKxYLwZ8T c=; X-IronPort-AV: E=Sophos;i="5.51,281,1526342400"; d="scan'208";a="135726619" Received: from rcdn-core-10.cisco.com ([173.37.93.146]) by alln-iport-1.cisco.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 28 Jun 2018 03:25:39 +0000 Received: from cisco.com (savbu-usnic-a.cisco.com [10.193.184.48]) by rcdn-core-10.cisco.com (8.14.5/8.14.5) with ESMTP id w5S3PdFP022450; Thu, 28 Jun 2018 03:25:39 GMT Received: by cisco.com (Postfix, from userid 392789) id 4576820F2001; Wed, 27 Jun 2018 20:25:39 -0700 (PDT) From: John Daley To: ferruh.yigit@intel.com Cc: dev@dpdk.org, Hyong Youb Kim Date: Wed, 27 Jun 2018 20:19:37 -0700 Message-Id: <20180628031940.17397-11-johndale@cisco.com> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180628031940.17397-1-johndale@cisco.com> References: <20180628031940.17397-1-johndale@cisco.com> Subject: [dpdk-dev] [PATCH 11/14] net/enic: add the simple version of Tx handler X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Hyong Youb Kim Add a much-simplified handler that works when all offloads are disabled, except mbuf fast free. When compared against the default handler, under ideal conditions, cycles per packet drop by 60+%. By default, the driver tries to use the simple handler. Add a new devarg (disable-simple-tx) to allow the user to force-disable this new handler. The idea of using specialized/simplified handlers is from the Intel and Mellanox drivers. Signed-off-by: Hyong Youb Kim Reviewed-by: John Daley --- drivers/net/enic/enic.h | 3 ++ drivers/net/enic/enic_compat.h | 5 +++ drivers/net/enic/enic_ethdev.c | 31 ++++++++++------- drivers/net/enic/enic_main.c | 37 ++++++++++++++++++++ drivers/net/enic/enic_rxtx.c | 77 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 141 insertions(+), 12 deletions(-) diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index af790fc2e..e1d0ea552 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -126,6 +126,7 @@ struct enic { u8 filter_actions; /* HW supported actions */ bool vxlan; bool disable_overlay; /* devargs disable_overlay=1 */ + bool disable_simple_tx; /* devargs disable-simple-tx=1 */ bool nic_cfg_chk; /* NIC_CFG_CHK available */ bool udp_rss_weak; /* Bodega style UDP RSS */ uint8_t ig_vlan_rewrite_mode; /* devargs ig-vlan-rewrite */ @@ -318,6 +319,8 @@ uint16_t enic_dummy_recv_pkts(void *rx_queue, uint16_t nb_pkts); uint16_t enic_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts); +uint16_t enic_simple_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, + uint16_t nb_pkts); uint16_t enic_prep_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts); int enic_set_mtu(struct enic *enic, uint16_t new_mtu); diff --git a/drivers/net/enic/enic_compat.h b/drivers/net/enic/enic_compat.h index c0af1ed29..ceb1b0962 100644 --- a/drivers/net/enic/enic_compat.h +++ b/drivers/net/enic/enic_compat.h @@ -56,6 +56,11 @@ #define dev_debug(x, args...) dev_printk(DEBUG, args) extern int enicpmd_logtype_flow; +extern int enicpmd_logtype_init; + +#define PMD_INIT_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, enicpmd_logtype_init, \ + "%s" fmt "\n", __func__, ##args) #define __le16 u16 #define __le32 u32 diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c index ef18f8802..d013333f9 100644 --- a/drivers/net/enic/enic_ethdev.c +++ b/drivers/net/enic/enic_ethdev.c @@ -24,10 +24,6 @@ int enicpmd_logtype_init; int enicpmd_logtype_flow; -#define PMD_INIT_LOG(level, fmt, args...) \ - rte_log(RTE_LOG_ ## level, enicpmd_logtype_init, \ - "%s" fmt "\n", __func__, ##args) - #define ENICPMD_FUNC_TRACE() PMD_INIT_LOG(DEBUG, " >>") /* @@ -42,6 +38,7 @@ static const struct rte_pci_id pci_id_enic_map[] = { #define ENIC_DEVARG_DISABLE_OVERLAY "disable-overlay" #define ENIC_DEVARG_IG_VLAN_REWRITE "ig-vlan-rewrite" +#define ENIC_DEVARG_DISABLE_SIMPLE_TX "disable-simple-tx" RTE_INIT(enicpmd_init_log); static void @@ -920,22 +917,27 @@ static const struct eth_dev_ops enicpmd_eth_dev_ops = { .udp_tunnel_port_del = enicpmd_dev_udp_tunnel_port_del, }; -static int enic_parse_disable_overlay(__rte_unused const char *key, - const char *value, - void *opaque) +static int enic_parse_zero_one(const char *key, + const char *value, + void *opaque) { struct enic *enic; + bool b; enic = (struct enic *)opaque; if (strcmp(value, "0") == 0) { - enic->disable_overlay = false; + b = false; } else if (strcmp(value, "1") == 0) { - enic->disable_overlay = true; + b = true; } else { - dev_err(enic, "Invalid value for " ENIC_DEVARG_DISABLE_OVERLAY - ": expected=0|1 given=%s\n", value); + dev_err(enic, "Invalid value for %s" + ": expected=0|1 given=%s\n", key, value); return -EINVAL; } + if (strcmp(key, ENIC_DEVARG_DISABLE_OVERLAY) == 0) + enic->disable_overlay = b; + if (strcmp(key, ENIC_DEVARG_DISABLE_SIMPLE_TX) == 0) + enic->disable_simple_tx = b; return 0; } @@ -976,6 +978,7 @@ static int enic_check_devargs(struct rte_eth_dev *dev) { static const char *const valid_keys[] = { ENIC_DEVARG_DISABLE_OVERLAY, + ENIC_DEVARG_DISABLE_SIMPLE_TX, ENIC_DEVARG_IG_VLAN_REWRITE, NULL}; struct enic *enic = pmd_priv(dev); @@ -984,6 +987,7 @@ static int enic_check_devargs(struct rte_eth_dev *dev) ENICPMD_FUNC_TRACE(); enic->disable_overlay = false; + enic->disable_simple_tx = false; enic->ig_vlan_rewrite_mode = IG_VLAN_REWRITE_MODE_PASS_THRU; if (!dev->device->devargs) return 0; @@ -991,7 +995,9 @@ static int enic_check_devargs(struct rte_eth_dev *dev) if (!kvlist) return -EINVAL; if (rte_kvargs_process(kvlist, ENIC_DEVARG_DISABLE_OVERLAY, - enic_parse_disable_overlay, enic) < 0 || + enic_parse_zero_one, enic) < 0 || + rte_kvargs_process(kvlist, ENIC_DEVARG_DISABLE_SIMPLE_TX, + enic_parse_zero_one, enic) < 0 || rte_kvargs_process(kvlist, ENIC_DEVARG_IG_VLAN_REWRITE, enic_parse_ig_vlan_rewrite, enic) < 0) { rte_kvargs_free(kvlist); @@ -1059,4 +1065,5 @@ RTE_PMD_REGISTER_PCI_TABLE(net_enic, pci_id_enic_map); RTE_PMD_REGISTER_KMOD_DEP(net_enic, "* igb_uio | uio_pci_generic | vfio-pci"); RTE_PMD_REGISTER_PARAM_STRING(net_enic, ENIC_DEVARG_DISABLE_OVERLAY "=0|1 " + ENIC_DEVARG_DISABLE_SIMPLE_TX "=0|1 " ENIC_DEVARG_IG_VLAN_REWRITE "=trunk|untag|priority|pass"); diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index c03ec247a..66706448c 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -493,6 +493,27 @@ static void enic_rxq_intr_deinit(struct enic *enic) } } +static void enic_prep_wq_for_simple_tx(struct enic *enic, uint16_t queue_idx) +{ + struct wq_enet_desc *desc; + struct vnic_wq *wq; + unsigned int i; + + /* + * Fill WQ descriptor fields that never change. Every descriptor is + * one packet, so set EOP. Also set CQ_ENTRY every ENIC_WQ_CQ_THRESH + * descriptors (i.e. request one completion update every 32 packets). + */ + wq = &enic->wq[queue_idx]; + desc = (struct wq_enet_desc *)wq->ring.descs; + for (i = 0; i < wq->ring.desc_count; i++, desc++) { + desc->header_length_flags = 1 << WQ_ENET_FLAGS_EOP_SHIFT; + if (i % ENIC_WQ_CQ_THRESH == ENIC_WQ_CQ_THRESH - 1) + desc->header_length_flags |= + (1 << WQ_ENET_FLAGS_CQ_ENTRY_SHIFT); + } +} + int enic_enable(struct enic *enic) { unsigned int index; @@ -535,6 +556,22 @@ int enic_enable(struct enic *enic) } } + /* + * Use the simple TX handler if possible. All offloads must be disabled + * except mbuf fast free. + */ + if (!enic->disable_simple_tx && + (eth_dev->data->dev_conf.txmode.offloads & + ~DEV_TX_OFFLOAD_MBUF_FAST_FREE) == 0) { + PMD_INIT_LOG(DEBUG, " use the simple tx handler"); + eth_dev->tx_pkt_burst = &enic_simple_xmit_pkts; + for (index = 0; index < enic->wq_count; index++) + enic_prep_wq_for_simple_tx(enic, index); + } else { + PMD_INIT_LOG(DEBUG, " use the default tx handler"); + eth_dev->tx_pkt_burst = &enic_xmit_pkts; + } + for (index = 0; index < enic->wq_count; index++) enic_start_wq(enic, index); for (index = 0; index < enic->rq_count; index++) diff --git a/drivers/net/enic/enic_rxtx.c b/drivers/net/enic/enic_rxtx.c index 7cddb53d9..7dec486fe 100644 --- a/drivers/net/enic/enic_rxtx.c +++ b/drivers/net/enic/enic_rxtx.c @@ -741,4 +741,81 @@ uint16_t enic_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, return index; } +static void enqueue_simple_pkts(struct rte_mbuf **pkts, + struct wq_enet_desc *desc, + uint16_t n, + struct enic *enic) +{ + struct rte_mbuf *p; + + while (n) { + n--; + p = *pkts++; + desc->address = p->buf_iova + p->data_off; + desc->length = p->pkt_len; + /* + * The app should not send oversized + * packets. tx_pkt_prepare includes a check as + * well. But some apps ignore the device max size and + * tx_pkt_prepare. Oversized packets cause WQ errrors + * and the NIC ends up disabling the whole WQ. So + * truncate packets.. + */ + if (unlikely(p->pkt_len > ENIC_TX_MAX_PKT_SIZE)) { + desc->length = ENIC_TX_MAX_PKT_SIZE; + rte_atomic64_inc(&enic->soft_stats.tx_oversized); + } + desc++; + } +} + +uint16_t enic_simple_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, + uint16_t nb_pkts) +{ + unsigned int head_idx, desc_count; + struct wq_enet_desc *desc; + struct vnic_wq *wq; + struct enic *enic; + uint16_t rem, n; + + wq = (struct vnic_wq *)tx_queue; + enic = vnic_dev_priv(wq->vdev); + enic_cleanup_wq(enic, wq); + /* Will enqueue this many packets in this call */ + nb_pkts = RTE_MIN(nb_pkts, wq->ring.desc_avail); + if (nb_pkts == 0) + return 0; + + head_idx = wq->head_idx; + desc_count = wq->ring.desc_count; + + /* Descriptors until the end of the ring */ + n = desc_count - head_idx; + n = RTE_MIN(nb_pkts, n); + /* Save mbuf pointers to free later */ + memcpy(wq->bufs + head_idx, tx_pkts, sizeof(struct rte_mbuf *) * n); + + /* Enqueue until the ring end */ + rem = nb_pkts - n; + desc = ((struct wq_enet_desc *)wq->ring.descs) + head_idx; + enqueue_simple_pkts(tx_pkts, desc, n, enic); + + /* Wrap to the start of the ring */ + if (rem) { + tx_pkts += n; + memcpy(wq->bufs, tx_pkts, sizeof(struct rte_mbuf *) * rem); + desc = (struct wq_enet_desc *)wq->ring.descs; + enqueue_simple_pkts(tx_pkts, desc, rem, enic); + } + rte_wmb(); + + /* Update head_idx and desc_avail */ + wq->ring.desc_avail -= nb_pkts; + head_idx += nb_pkts; + if (head_idx >= desc_count) + head_idx -= desc_count; + wq->head_idx = head_idx; + iowrite32_relaxed(head_idx, &wq->ctrl->posted_index); + return nb_pkts; +}