All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] net/enic: remove 'extern' in .h file function declarations
@ 2018-02-24 19:17 John Daley
  2018-02-24 19:17 ` [PATCH] net/enic: allow the user to change RSS settings John Daley
                   ` (8 more replies)
  0 siblings, 9 replies; 44+ messages in thread
From: John Daley @ 2018-02-24 19:17 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, John Daley

Signed-off-by: John Daley <johndale@cisco.com>
---
 drivers/net/enic/enic.h | 80 ++++++++++++++++++++++++-------------------------
 1 file changed, 40 insertions(+), 40 deletions(-)

diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index c083985ee..e88af6bc9 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -220,54 +220,54 @@ enic_ring_incr(uint32_t n_descriptors, uint32_t idx)
 	return idx;
 }
 
-extern void enic_fdir_stats_get(struct enic *enic,
-	struct rte_eth_fdir_stats *stats);
-extern int enic_fdir_add_fltr(struct enic *enic,
-	struct rte_eth_fdir_filter *params);
-extern int enic_fdir_del_fltr(struct enic *enic,
-	struct rte_eth_fdir_filter *params);
-extern void enic_free_wq(void *txq);
-extern int enic_alloc_intr_resources(struct enic *enic);
-extern int enic_setup_finish(struct enic *enic);
-extern int enic_alloc_wq(struct enic *enic, uint16_t queue_idx,
-	unsigned int socket_id, uint16_t nb_desc);
-extern void enic_start_wq(struct enic *enic, uint16_t queue_idx);
-extern int enic_stop_wq(struct enic *enic, uint16_t queue_idx);
-extern void enic_start_rq(struct enic *enic, uint16_t queue_idx);
-extern int enic_stop_rq(struct enic *enic, uint16_t queue_idx);
-extern void enic_free_rq(void *rxq);
-extern int enic_alloc_rq(struct enic *enic, uint16_t queue_idx,
-	unsigned int socket_id, struct rte_mempool *mp,
-	uint16_t nb_desc, uint16_t free_thresh);
-extern int enic_set_rss_nic_cfg(struct enic *enic);
-extern int enic_set_vnic_res(struct enic *enic);
-extern int enic_enable(struct enic *enic);
-extern int enic_disable(struct enic *enic);
-extern void enic_remove(struct enic *enic);
-extern int enic_get_link_status(struct enic *enic);
-extern int enic_dev_stats_get(struct enic *enic,
-	struct rte_eth_stats *r_stats);
-extern void enic_dev_stats_clear(struct enic *enic);
-extern void enic_add_packet_filter(struct enic *enic);
+void enic_fdir_stats_get(struct enic *enic,
+			 struct rte_eth_fdir_stats *stats);
+int enic_fdir_add_fltr(struct enic *enic,
+		       struct rte_eth_fdir_filter *params);
+int enic_fdir_del_fltr(struct enic *enic,
+		       struct rte_eth_fdir_filter *params);
+void enic_free_wq(void *txq);
+int enic_alloc_intr_resources(struct enic *enic);
+int enic_setup_finish(struct enic *enic);
+int enic_alloc_wq(struct enic *enic, uint16_t queue_idx,
+		  unsigned int socket_id, uint16_t nb_desc);
+void enic_start_wq(struct enic *enic, uint16_t queue_idx);
+int enic_stop_wq(struct enic *enic, uint16_t queue_idx);
+void enic_start_rq(struct enic *enic, uint16_t queue_idx);
+int enic_stop_rq(struct enic *enic, uint16_t queue_idx);
+void enic_free_rq(void *rxq);
+int enic_alloc_rq(struct enic *enic, uint16_t queue_idx,
+		  unsigned int socket_id, struct rte_mempool *mp,
+		  uint16_t nb_desc, uint16_t free_thresh);
+int enic_set_rss_nic_cfg(struct enic *enic);
+int enic_set_vnic_res(struct enic *enic);
+int enic_enable(struct enic *enic);
+int enic_disable(struct enic *enic);
+void enic_remove(struct enic *enic);
+int enic_get_link_status(struct enic *enic);
+int enic_dev_stats_get(struct enic *enic,
+		       struct rte_eth_stats *r_stats);
+void enic_dev_stats_clear(struct enic *enic);
+void enic_add_packet_filter(struct enic *enic);
 int enic_set_mac_address(struct enic *enic, uint8_t *mac_addr);
 void enic_del_mac_address(struct enic *enic, int mac_index);
-extern unsigned int enic_cleanup_wq(struct enic *enic, struct vnic_wq *wq);
-extern void enic_send_pkt(struct enic *enic, struct vnic_wq *wq,
-			  struct rte_mbuf *tx_pkt, unsigned short len,
-			  uint8_t sop, uint8_t eop, uint8_t cq_entry,
-			  uint16_t ol_flags, uint16_t vlan_tag);
-
-extern void enic_post_wq_index(struct vnic_wq *wq);
-extern int enic_probe(struct enic *enic);
-extern int enic_clsf_init(struct enic *enic);
-extern void enic_clsf_destroy(struct enic *enic);
+unsigned int enic_cleanup_wq(struct enic *enic, struct vnic_wq *wq);
+void enic_send_pkt(struct enic *enic, struct vnic_wq *wq,
+		   struct rte_mbuf *tx_pkt, unsigned short len,
+		   uint8_t sop, uint8_t eop, uint8_t cq_entry,
+		   uint16_t ol_flags, uint16_t vlan_tag);
+
+void enic_post_wq_index(struct vnic_wq *wq);
+int enic_probe(struct enic *enic);
+int enic_clsf_init(struct enic *enic);
+void enic_clsf_destroy(struct enic *enic);
 uint16_t enic_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
 			uint16_t nb_pkts);
 uint16_t enic_dummy_recv_pkts(void *rx_queue,
 			      struct rte_mbuf **rx_pkts,
 			      uint16_t nb_pkts);
 uint16_t enic_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
-			       uint16_t nb_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);
-- 
2.12.0

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH] net/enic: allow the user to change RSS settings
  2018-02-24 19:17 [PATCH] net/enic: remove 'extern' in .h file function declarations John Daley
@ 2018-02-24 19:17 ` John Daley
  2018-02-24 19:17 ` [PATCH] net/enic: heed the requested max Rx packet size John Daley
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-02-24 19:17 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

Currently, when more than 1 receive queues are configured, the driver
always enables RSS with the driver's own default hash type, key, and
RETA. The user is unable to change any of the RSS settings. Address
this by implementing the ethdev RSS API as follows.

Correctly report the RETA size, key size, and supported hash types
through rte_eth_dev_info.

During dev_configure(), initialize RSS according to the device's
mq_mode and rss_conf. Start with the default RETA, and use the default
key unless a custom key is provided.

Add the RETA and rss_conf query/set handlers to let the user change
RSS settings after the initial configuration. The hardware is able to
change hash type, key, and RETA individually. So, the handlers change
only the affected settings.

Refactor/rename several functions in order to make their intentions
clear. For example, remove all traces of RSS from
enicpmd_vlan_offload_set() as it is confusing.

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 doc/guides/nics/features/enic.ini |   2 +
 drivers/net/enic/enic.h           |  20 +++-
 drivers/net/enic/enic_ethdev.c    | 117 ++++++++++++++++++++++-
 drivers/net/enic/enic_main.c      | 192 ++++++++++++++++++++++++++++----------
 drivers/net/enic/enic_res.c       |  20 ++++
 drivers/net/enic/enic_res.h       |   6 ++
 6 files changed, 301 insertions(+), 56 deletions(-)

diff --git a/doc/guides/nics/features/enic.ini b/doc/guides/nics/features/enic.ini
index 498341f07..e79d7277d 100644
--- a/doc/guides/nics/features/enic.ini
+++ b/doc/guides/nics/features/enic.ini
@@ -15,6 +15,8 @@ Promiscuous mode     = Y
 Unicast MAC filter   = Y
 Multicast MAC filter = Y
 RSS hash             = Y
+RSS key update       = Y
+RSS reta update      = Y
 SR-IOV               = Y
 VLAN filter          = Y
 CRC offload          = Y
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index e88af6bc9..d29939c94 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -146,6 +146,20 @@ struct enic {
 
 	LIST_HEAD(enic_flows, rte_flow) flows;
 	rte_spinlock_t flows_lock;
+
+	/* RSS */
+	uint16_t reta_size;
+	uint8_t hash_key_size;
+	uint64_t flow_type_rss_offloads; /* 0 indicates RSS not supported */
+	/*
+	 * Keep a copy of current RSS config for queries, as we cannot retrieve
+	 * it from the NIC.
+	 */
+	uint8_t rss_hash_type; /* NIC_CFG_RSS_HASH_TYPE flags */
+	uint8_t rss_enable;
+	uint64_t rss_hf; /* ETH_RSS flags */
+	union vnic_rss_key rss_key;
+	union vnic_rss_cpu rss_cpu;
 };
 
 /* Get the CQ index from a Start of Packet(SOP) RQ index */
@@ -239,8 +253,12 @@ void enic_free_rq(void *rxq);
 int enic_alloc_rq(struct enic *enic, uint16_t queue_idx,
 		  unsigned int socket_id, struct rte_mempool *mp,
 		  uint16_t nb_desc, uint16_t free_thresh);
-int enic_set_rss_nic_cfg(struct enic *enic);
 int enic_set_vnic_res(struct enic *enic);
+int enic_init_rss_nic_cfg(struct enic *enic);
+int enic_set_rss_conf(struct enic *enic,
+		      struct rte_eth_rss_conf *rss_conf);
+int enic_set_rss_reta(struct enic *enic, union vnic_rss_cpu *rss_cpu);
+int enic_set_vlan_strip(struct enic *enic);
 int enic_enable(struct enic *enic);
 int enic_disable(struct enic *enic);
 void enic_remove(struct enic *enic);
diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
index d84714efb..cbab7029b 100644
--- a/drivers/net/enic/enic_ethdev.c
+++ b/drivers/net/enic/enic_ethdev.c
@@ -345,8 +345,6 @@ static int enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 		else
 			enic->ig_vlan_strip_en = 0;
 	}
-	enic_set_rss_nic_cfg(enic);
-
 
 	if (mask & ETH_VLAN_FILTER_MASK) {
 		dev_warning(enic,
@@ -358,7 +356,7 @@ static int enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 			"Configuration of extended VLAN is not supported\n");
 	}
 
-	return 0;
+	return enic_set_vlan_strip(enic);
 }
 
 static int enicpmd_dev_configure(struct rte_eth_dev *eth_dev)
@@ -379,8 +377,16 @@ static int enicpmd_dev_configure(struct rte_eth_dev *eth_dev)
 	enic->hw_ip_checksum = !!(eth_dev->data->dev_conf.rxmode.offloads &
 				  DEV_RX_OFFLOAD_CHECKSUM);
 	ret = enicpmd_vlan_offload_set(eth_dev, ETH_VLAN_STRIP_MASK);
-
-	return ret;
+	if (ret) {
+		dev_err(enic, "Failed to configure VLAN offloads\n");
+		return ret;
+	}
+	/*
+	 * Initialize RSS with the default reta and key. If the user key is
+	 * given (rx_adv_conf.rss_conf.rss_key), will use that instead of the
+	 * default key.
+	 */
+	return enic_init_rss_nic_cfg(enic);
 }
 
 /* Start the device.
@@ -480,6 +486,9 @@ static void enicpmd_dev_info_get(struct rte_eth_dev *eth_dev,
 	device_info->default_rxconf = (struct rte_eth_rxconf) {
 		.rx_free_thresh = ENIC_DEFAULT_RX_FREE_THRESH
 	};
+	device_info->reta_size = enic->reta_size;
+	device_info->hash_key_size = enic->hash_key_size;
+	device_info->flow_type_rss_offloads = enic->flow_type_rss_offloads;
 }
 
 static const uint32_t *enicpmd_dev_supported_ptypes_get(struct rte_eth_dev *dev)
@@ -582,6 +591,100 @@ static int enicpmd_mtu_set(struct rte_eth_dev *eth_dev, uint16_t mtu)
 	return enic_set_mtu(enic, mtu);
 }
 
+static int enicpmd_dev_rss_reta_query(struct rte_eth_dev *dev,
+				      struct rte_eth_rss_reta_entry64
+				      *reta_conf,
+				      uint16_t reta_size)
+{
+	struct enic *enic = pmd_priv(dev);
+	uint16_t i, idx, shift;
+
+	ENICPMD_FUNC_TRACE();
+	if (reta_size != ENIC_RSS_RETA_SIZE) {
+		dev_err(enic, "reta_query: wrong reta_size. given=%u expected=%u\n",
+			reta_size, ENIC_RSS_RETA_SIZE);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < reta_size; i++) {
+		idx = i / RTE_RETA_GROUP_SIZE;
+		shift = i % RTE_RETA_GROUP_SIZE;
+		if (reta_conf[idx].mask & (1ULL << shift))
+			reta_conf[idx].reta[shift] = enic_sop_rq_idx_to_rte_idx(
+				enic->rss_cpu.cpu[i / 4].b[i % 4]);
+	}
+
+	return 0;
+}
+
+static int enicpmd_dev_rss_reta_update(struct rte_eth_dev *dev,
+				       struct rte_eth_rss_reta_entry64
+				       *reta_conf,
+				       uint16_t reta_size)
+{
+	struct enic *enic = pmd_priv(dev);
+	union vnic_rss_cpu rss_cpu;
+	uint16_t i, idx, shift;
+
+	ENICPMD_FUNC_TRACE();
+	if (reta_size != ENIC_RSS_RETA_SIZE) {
+		dev_err(enic, "reta_update: wrong reta_size. given=%u"
+			" expected=%u\n",
+			reta_size, ENIC_RSS_RETA_SIZE);
+		return -EINVAL;
+	}
+	/*
+	 * Start with the current reta and modify it per reta_conf, as we
+	 * need to push the entire reta even if we only modify one entry.
+	 */
+	rss_cpu = enic->rss_cpu;
+	for (i = 0; i < reta_size; i++) {
+		idx = i / RTE_RETA_GROUP_SIZE;
+		shift = i % RTE_RETA_GROUP_SIZE;
+		if (reta_conf[idx].mask & (1ULL << shift))
+			rss_cpu.cpu[i / 4].b[i % 4] =
+				enic_rte_rq_idx_to_sop_idx(
+					reta_conf[idx].reta[shift]);
+	}
+	return enic_set_rss_reta(enic, &rss_cpu);
+}
+
+static int enicpmd_dev_rss_hash_update(struct rte_eth_dev *dev,
+				       struct rte_eth_rss_conf *rss_conf)
+{
+	struct enic *enic = pmd_priv(dev);
+
+	ENICPMD_FUNC_TRACE();
+	return enic_set_rss_conf(enic, rss_conf);
+}
+
+static int enicpmd_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
+					 struct rte_eth_rss_conf *rss_conf)
+{
+	struct enic *enic = pmd_priv(dev);
+
+	ENICPMD_FUNC_TRACE();
+	if (rss_conf == NULL)
+		return -EINVAL;
+	if (rss_conf->rss_key != NULL &&
+	    rss_conf->rss_key_len < ENIC_RSS_HASH_KEY_SIZE) {
+		dev_err(enic, "rss_hash_conf_get: wrong rss_key_len. given=%u"
+			" expected=%u+\n",
+			rss_conf->rss_key_len, ENIC_RSS_HASH_KEY_SIZE);
+		return -EINVAL;
+	}
+	rss_conf->rss_hf = enic->rss_hf;
+	if (rss_conf->rss_key != NULL) {
+		int i;
+		for (i = 0; i < ENIC_RSS_HASH_KEY_SIZE; i++) {
+			rss_conf->rss_key[i] =
+				enic->rss_key.key[i / 10].b[i % 10];
+		}
+		rss_conf->rss_key_len = ENIC_RSS_HASH_KEY_SIZE;
+	}
+	return 0;
+}
+
 static const struct eth_dev_ops enicpmd_eth_dev_ops = {
 	.dev_configure        = enicpmd_dev_configure,
 	.dev_start            = enicpmd_dev_start,
@@ -622,6 +725,10 @@ static const struct eth_dev_ops enicpmd_eth_dev_ops = {
 	.mac_addr_add         = enicpmd_add_mac_addr,
 	.mac_addr_remove      = enicpmd_remove_mac_addr,
 	.filter_ctrl          = enicpmd_dev_filter_ctrl,
+	.reta_query           = enicpmd_dev_rss_reta_query,
+	.reta_update          = enicpmd_dev_rss_reta_update,
+	.rss_hash_conf_get    = enicpmd_dev_rss_hash_conf_get,
+	.rss_hash_update      = enicpmd_dev_rss_hash_update,
 };
 
 struct enic *enicpmd_list_head = NULL;
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index ec9d343fd..f00e816a1 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -889,44 +889,42 @@ static int enic_dev_open(struct enic *enic)
 	return err;
 }
 
-static int enic_set_rsskey(struct enic *enic)
+static int enic_set_rsskey(struct enic *enic, uint8_t *user_key)
 {
 	dma_addr_t rss_key_buf_pa;
 	union vnic_rss_key *rss_key_buf_va = NULL;
-	static union vnic_rss_key rss_key = {
-		.key = {
-			[0] = {.b = {85, 67, 83, 97, 119, 101, 115, 111, 109, 101}},
-			[1] = {.b = {80, 65, 76, 79, 117, 110, 105, 113, 117, 101}},
-			[2] = {.b = {76, 73, 78, 85, 88, 114, 111, 99, 107, 115}},
-			[3] = {.b = {69, 78, 73, 67, 105, 115, 99, 111, 111, 108}},
-		}
-	};
-	int err;
+	int err, i;
 	u8 name[NAME_MAX];
 
+	RTE_ASSERT(use_key != NULL);
 	snprintf((char *)name, NAME_MAX, "rss_key-%s", enic->bdf_name);
 	rss_key_buf_va = enic_alloc_consistent(enic, sizeof(union vnic_rss_key),
 		&rss_key_buf_pa, name);
 	if (!rss_key_buf_va)
 		return -ENOMEM;
 
-	rte_memcpy(rss_key_buf_va, &rss_key, sizeof(union vnic_rss_key));
+	for (i = 0; i < ENIC_RSS_HASH_KEY_SIZE; i++)
+		rss_key_buf_va->key[i / 10].b[i % 10] = user_key[i];
 
 	err = enic_set_rss_key(enic,
 		rss_key_buf_pa,
 		sizeof(union vnic_rss_key));
 
+	/* Save for later queries */
+	if (!err) {
+		rte_memcpy(&enic->rss_key, rss_key_buf_va,
+			   sizeof(union vnic_rss_key));
+	}
 	enic_free_consistent(enic, sizeof(union vnic_rss_key),
 		rss_key_buf_va, rss_key_buf_pa);
 
 	return err;
 }
 
-static int enic_set_rsscpu(struct enic *enic, u8 rss_hash_bits)
+int enic_set_rss_reta(struct enic *enic, union vnic_rss_cpu *rss_cpu)
 {
 	dma_addr_t rss_cpu_buf_pa;
 	union vnic_rss_cpu *rss_cpu_buf_va = NULL;
-	int i;
 	int err;
 	u8 name[NAME_MAX];
 
@@ -936,9 +934,7 @@ static int enic_set_rsscpu(struct enic *enic, u8 rss_hash_bits)
 	if (!rss_cpu_buf_va)
 		return -ENOMEM;
 
-	for (i = 0; i < (1 << rss_hash_bits); i++)
-		(*rss_cpu_buf_va).cpu[i / 4].b[i % 4] =
-			enic_rte_rq_idx_to_sop_idx(i % enic->rq_count);
+	rte_memcpy(rss_cpu_buf_va, rss_cpu, sizeof(union vnic_rss_cpu));
 
 	err = enic_set_rss_cpu(enic,
 		rss_cpu_buf_pa,
@@ -947,6 +943,9 @@ static int enic_set_rsscpu(struct enic *enic, u8 rss_hash_bits)
 	enic_free_consistent(enic, sizeof(union vnic_rss_cpu),
 		rss_cpu_buf_va, rss_cpu_buf_pa);
 
+	/* Save for later queries */
+	if (!err)
+		rte_memcpy(&enic->rss_cpu, rss_cpu, sizeof(union vnic_rss_cpu));
 	return err;
 }
 
@@ -956,8 +955,6 @@ static int enic_set_niccfg(struct enic *enic, u8 rss_default_cpu,
 	const u8 tso_ipid_split_en = 0;
 	int err;
 
-	/* Enable VLAN tag stripping */
-
 	err = enic_set_nic_cfg(enic,
 		rss_default_cpu, rss_hash_type,
 		rss_hash_bits, rss_base_cpu,
@@ -967,47 +964,50 @@ static int enic_set_niccfg(struct enic *enic, u8 rss_default_cpu,
 	return err;
 }
 
-int enic_set_rss_nic_cfg(struct enic *enic)
+/* Initialize RSS with defaults, called from dev_configure */
+int enic_init_rss_nic_cfg(struct enic *enic)
 {
-	const u8 rss_default_cpu = 0;
-	const u8 rss_hash_type = NIC_CFG_RSS_HASH_TYPE_IPV4 |
-	    NIC_CFG_RSS_HASH_TYPE_TCP_IPV4 |
-	    NIC_CFG_RSS_HASH_TYPE_IPV6 |
-	    NIC_CFG_RSS_HASH_TYPE_TCP_IPV6;
-	const u8 rss_hash_bits = 7;
-	const u8 rss_base_cpu = 0;
-	u8 rss_enable = ENIC_SETTING(enic, RSS) && (enic->rq_count > 1);
-
-	if (rss_enable) {
-		if (!enic_set_rsskey(enic)) {
-			if (enic_set_rsscpu(enic, rss_hash_bits)) {
-				rss_enable = 0;
-				dev_warning(enic, "RSS disabled, "\
-					"Failed to set RSS cpu indirection table.");
-			}
-		} else {
-			rss_enable = 0;
-			dev_warning(enic,
-				"RSS disabled, Failed to set RSS key.\n");
+	static uint8_t default_rss_key[] = {
+		85, 67, 83, 97, 119, 101, 115, 111, 109, 101,
+		80, 65, 76, 79, 117, 110, 105, 113, 117, 101,
+		76, 73, 78, 85, 88, 114, 111, 99, 107, 115,
+		69, 78, 73, 67, 105, 115, 99, 111, 111, 108,
+	};
+	struct rte_eth_rss_conf rss_conf;
+	union vnic_rss_cpu rss_cpu;
+	int ret, i;
+
+	rss_conf = enic->rte_dev->data->dev_conf.rx_adv_conf.rss_conf;
+	/*
+	 * If setting key for the first time, and the user gives us none, then
+	 * push the default key to NIC.
+	 */
+	if (rss_conf.rss_key == NULL) {
+		rss_conf.rss_key = default_rss_key;
+		rss_conf.rss_key_len = ENIC_RSS_HASH_KEY_SIZE;
+	}
+	ret = enic_set_rss_conf(enic, &rss_conf);
+	if (ret) {
+		dev_err(enic, "Failed to configure RSS\n");
+		return ret;
+	}
+	if (enic->rss_enable) {
+		/* If enabling RSS, use the default reta */
+		for (i = 0; i < ENIC_RSS_RETA_SIZE; i++) {
+			rss_cpu.cpu[i / 4].b[i % 4] =
+				enic_rte_rq_idx_to_sop_idx(i % enic->rq_count);
 		}
+		ret = enic_set_rss_reta(enic, &rss_cpu);
+		if (ret)
+			dev_err(enic, "Failed to set RSS indirection table\n");
 	}
-
-	return enic_set_niccfg(enic, rss_default_cpu, rss_hash_type,
-		rss_hash_bits, rss_base_cpu, rss_enable);
+	return ret;
 }
 
 int enic_setup_finish(struct enic *enic)
 {
-	int ret;
-
 	enic_init_soft_stats(enic);
 
-	ret = enic_set_rss_nic_cfg(enic);
-	if (ret) {
-		dev_err(enic, "Failed to config nic, aborting.\n");
-		return -1;
-	}
-
 	/* Default conf */
 	vnic_dev_packet_filter(enic->vdev,
 		1 /* directed  */,
@@ -1022,6 +1022,98 @@ int enic_setup_finish(struct enic *enic)
 	return 0;
 }
 
+static int enic_rss_conf_valid(struct enic *enic,
+			       struct rte_eth_rss_conf *rss_conf)
+{
+	/* RSS is disabled per VIC settings. Ignore rss_conf. */
+	if (enic->flow_type_rss_offloads == 0)
+		return 0;
+	if (rss_conf->rss_key != NULL &&
+	    rss_conf->rss_key_len != ENIC_RSS_HASH_KEY_SIZE) {
+		dev_err(enic, "Given rss_key is %d bytes, it must be %d\n",
+			rss_conf->rss_key_len, ENIC_RSS_HASH_KEY_SIZE);
+		return -EINVAL;
+	}
+	if (rss_conf->rss_hf != 0 &&
+	    (rss_conf->rss_hf & enic->flow_type_rss_offloads) == 0) {
+		dev_err(enic, "Given rss_hf contains none of the supported"
+			" types\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* Set hash type and key according to rss_conf */
+int enic_set_rss_conf(struct enic *enic, struct rte_eth_rss_conf *rss_conf)
+{
+	struct rte_eth_dev *eth_dev;
+	uint64_t rss_hf;
+	u8 rss_hash_type;
+	u8 rss_enable;
+	int ret;
+
+	RTE_ASSERT(rss_conf != NULL);
+	ret = enic_rss_conf_valid(enic, rss_conf);
+	if (ret) {
+		dev_err(enic, "RSS configuration (rss_conf) is invalid\n");
+		return ret;
+	}
+
+	eth_dev = enic->rte_dev;
+	rss_hash_type = 0;
+	rss_hf = rss_conf->rss_hf & enic->flow_type_rss_offloads;
+	if (enic->rq_count > 1 &&
+	    (eth_dev->data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_RSS_FLAG) &&
+	    rss_hf != 0) {
+		rss_enable = 1;
+		if (rss_hf & ETH_RSS_IPV4)
+			rss_hash_type |= NIC_CFG_RSS_HASH_TYPE_IPV4;
+		if (rss_hf & ETH_RSS_NONFRAG_IPV4_TCP)
+			rss_hash_type |= NIC_CFG_RSS_HASH_TYPE_TCP_IPV4;
+		if (rss_hf & ETH_RSS_IPV6)
+			rss_hash_type |= NIC_CFG_RSS_HASH_TYPE_IPV6;
+		if (rss_hf & ETH_RSS_NONFRAG_IPV6_TCP)
+			rss_hash_type |= NIC_CFG_RSS_HASH_TYPE_TCP_IPV6;
+		if (rss_hf & ETH_RSS_IPV6_EX)
+			rss_hash_type |= NIC_CFG_RSS_HASH_TYPE_IPV6_EX;
+		if (rss_hf & ETH_RSS_IPV6_TCP_EX)
+			rss_hash_type |= NIC_CFG_RSS_HASH_TYPE_TCP_IPV6_EX;
+	} else {
+		rss_enable = 0;
+		rss_hf = 0;
+	}
+
+	/* Set the hash key if provided */
+	if (rss_enable && rss_conf->rss_key) {
+		ret = enic_set_rsskey(enic, rss_conf->rss_key);
+		if (ret) {
+			dev_err(enic, "Failed to set RSS key\n");
+			return ret;
+		}
+	}
+
+	ret = enic_set_niccfg(enic, ENIC_RSS_DEFAULT_CPU, rss_hash_type,
+			      ENIC_RSS_HASH_BITS, ENIC_RSS_BASE_CPU,
+			      rss_enable);
+	if (!ret) {
+		enic->rss_hf = rss_hf;
+		enic->rss_hash_type = rss_hash_type;
+		enic->rss_enable = rss_enable;
+	}
+	return 0;
+}
+
+int enic_set_vlan_strip(struct enic *enic)
+{
+	/*
+	 * Unfortunately, VLAN strip on/off and RSS on/off are configured
+	 * together. So, re-do niccfg, preserving the current RSS settings.
+	 */
+	return enic_set_niccfg(enic, ENIC_RSS_DEFAULT_CPU, enic->rss_hash_type,
+			       ENIC_RSS_HASH_BITS, ENIC_RSS_BASE_CPU,
+			       enic->rss_enable);
+}
+
 void enic_add_packet_filter(struct enic *enic)
 {
 	/* Args -> directed, multicast, broadcast, promisc, allmulti */
diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c
index c99d61837..d8f7892c3 100644
--- a/drivers/net/enic/enic_res.c
+++ b/drivers/net/enic/enic_res.c
@@ -128,6 +128,26 @@ int enic_get_vnic_config(struct enic *enic)
 		c->intr_timer_usec,
 		c->loop_tag);
 
+	/* RSS settings from vNIC */
+	enic->reta_size = ENIC_RSS_RETA_SIZE;
+	enic->hash_key_size = ENIC_RSS_HASH_KEY_SIZE;
+	enic->flow_type_rss_offloads = 0;
+	if (ENIC_SETTING(enic, RSSHASH_IPV4))
+		enic->flow_type_rss_offloads |= ETH_RSS_IPV4;
+	if (ENIC_SETTING(enic, RSSHASH_TCPIPV4))
+		enic->flow_type_rss_offloads |= ETH_RSS_NONFRAG_IPV4_TCP;
+	if (ENIC_SETTING(enic, RSSHASH_IPV6))
+		enic->flow_type_rss_offloads |= ETH_RSS_IPV6;
+	if (ENIC_SETTING(enic, RSSHASH_TCPIPV6))
+		enic->flow_type_rss_offloads |= ETH_RSS_NONFRAG_IPV6_TCP;
+	if (ENIC_SETTING(enic, RSSHASH_IPV6_EX))
+		enic->flow_type_rss_offloads |= ETH_RSS_IPV6_EX;
+	if (ENIC_SETTING(enic, RSSHASH_TCPIPV6_EX))
+		enic->flow_type_rss_offloads |= ETH_RSS_IPV6_TCP_EX;
+	/* Zero offloads if RSS is not enabled */
+	if (!ENIC_SETTING(enic, RSS))
+		enic->flow_type_rss_offloads = 0;
+
 	return 0;
 }
 
diff --git a/drivers/net/enic/enic_res.h b/drivers/net/enic/enic_res.h
index cf3a6fde8..e68f1307b 100644
--- a/drivers/net/enic/enic_res.h
+++ b/drivers/net/enic/enic_res.h
@@ -31,6 +31,12 @@
 #define ENIC_DEFAULT_RX_FREE_THRESH	32
 #define ENIC_TX_XMIT_MAX		64
 
+#define ENIC_RSS_DEFAULT_CPU    0
+#define ENIC_RSS_BASE_CPU       0
+#define ENIC_RSS_HASH_BITS      7
+#define ENIC_RSS_RETA_SIZE      (1 << ENIC_RSS_HASH_BITS)
+#define ENIC_RSS_HASH_KEY_SIZE  40
+
 #define ENIC_SETTING(enic, f) ((enic->config.flags & VENETF_##f) ? 1 : 0)
 
 
-- 
2.12.0

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH] net/enic: heed the requested max Rx packet size
  2018-02-24 19:17 [PATCH] net/enic: remove 'extern' in .h file function declarations John Daley
  2018-02-24 19:17 ` [PATCH] net/enic: allow the user to change RSS settings John Daley
@ 2018-02-24 19:17 ` John Daley
  2018-02-24 19:17 ` [PATCH] net/enic: remove the VLAN filter handler John Daley
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-02-24 19:17 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

Currently, enic completely ignores the requested max Rx packet size
(rxmode.max_rx_pkt_len). The desired behavior is that the NIC hardware
drops packets larger than the requested size, even though they are
still smaller than MTU.

Cisco VIC does not have such a feature. But, we can accomplish a
similar (not same) effect by reducing the size of posted receive
buffers. Packets larger than the posted size get truncated, and the
receive handler drops them. This is also how the kernel enic driver
enforces the Rx side MTU.

This workaround works only when scatter mode is *not* used. When
scatter is used, there is currently no way to support
rxmode.max_rx_pkt_len, as the NIC always receives packets up to MTU.

For posterity, add a copious amount of comments regarding the
hardware's drop/receive behavior with respect to max/current MTU.

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 doc/guides/nics/enic.rst       |  1 +
 drivers/net/enic/enic.h        |  7 ++++++
 drivers/net/enic/enic_ethdev.c |  9 +++++++-
 drivers/net/enic/enic_main.c   | 49 ++++++++++++++++++++++++++++++++++++------
 4 files changed, 58 insertions(+), 8 deletions(-)

diff --git a/doc/guides/nics/enic.rst b/doc/guides/nics/enic.rst
index 4dffce1a6..0e655e9e3 100644
--- a/doc/guides/nics/enic.rst
+++ b/doc/guides/nics/enic.rst
@@ -371,6 +371,7 @@ Known bugs and unsupported features in this release
 - Setting of extended VLAN
 - UDP RSS hashing
 - MTU update only works if Scattered Rx mode is disabled
+- Maximum receive packet length is ignored if Scattered Rx mode is used
 
 Prerequisites
 -------------
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index d29939c94..1b3813a58 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -162,6 +162,13 @@ struct enic {
 	union vnic_rss_cpu rss_cpu;
 };
 
+/* Compute ethdev's max packet size from MTU */
+static inline uint32_t enic_mtu_to_max_rx_pktlen(uint32_t mtu)
+{
+	/* ethdev max size includes eth and crc whereas NIC MTU does not */
+	return mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
+}
+
 /* Get the CQ index from a Start of Packet(SOP) RQ index */
 static inline unsigned int enic_sop_rq_idx_to_cq_idx(unsigned int sop_idx)
 {
diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
index cbab7029b..bdbaf4cdf 100644
--- a/drivers/net/enic/enic_ethdev.c
+++ b/drivers/net/enic/enic_ethdev.c
@@ -470,7 +470,14 @@ static void enicpmd_dev_info_get(struct rte_eth_dev *eth_dev,
 	device_info->max_rx_queues = enic->conf_rq_count / 2;
 	device_info->max_tx_queues = enic->conf_wq_count;
 	device_info->min_rx_bufsize = ENIC_MIN_MTU;
-	device_info->max_rx_pktlen = enic->max_mtu + ETHER_HDR_LEN + 4;
+	/* "Max" mtu is not a typo. HW receives packet sizes up to the
+	 * max mtu regardless of the current mtu (vNIC's mtu). vNIC mtu is
+	 * a hint to the driver to size receive buffers accordingly so that
+	 * larger-than-vnic-mtu packets get truncated.. For DPDK, we let
+	 * the user decide the buffer size via rxmode.max_rx_pkt_len, basically
+	 * ignoring vNIC mtu.
+	 */
+	device_info->max_rx_pktlen = enic_mtu_to_max_rx_pktlen(enic->max_mtu);
 	device_info->max_mac_addrs = ENIC_MAX_MAC_ADDR;
 	device_info->rx_offload_capa =
 		DEV_RX_OFFLOAD_VLAN_STRIP |
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index f00e816a1..d4f478b5e 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -266,6 +266,8 @@ enic_alloc_rx_queue_mbufs(struct enic *enic, struct vnic_rq *rq)
 	struct rq_enet_desc *rqd = rq->ring.descs;
 	unsigned i;
 	dma_addr_t dma_addr;
+	uint32_t max_rx_pkt_len;
+	uint16_t rq_buf_len;
 
 	if (!rq->in_use)
 		return 0;
@@ -273,6 +275,18 @@ enic_alloc_rx_queue_mbufs(struct enic *enic, struct vnic_rq *rq)
 	dev_debug(enic, "queue %u, allocating %u rx queue mbufs\n", rq->index,
 		  rq->ring.desc_count);
 
+	/*
+	 * If *not* using scatter and the mbuf size is smaller than the
+	 * requested max packet size (max_rx_pkt_len), then reduce the
+	 * posted buffer size to max_rx_pkt_len. HW still receives packets
+	 * larger than max_rx_pkt_len, but they will be truncated, which we
+	 * drop in the rx handler. Not ideal, but better than returning
+	 * large packets when the user is not expecting them.
+	 */
+	max_rx_pkt_len = enic->rte_dev->data->dev_conf.rxmode.max_rx_pkt_len;
+	rq_buf_len = rte_pktmbuf_data_room_size(rq->mp) - RTE_PKTMBUF_HEADROOM;
+	if (max_rx_pkt_len < rq_buf_len && !rq->data_queue_enable)
+		rq_buf_len = max_rx_pkt_len;
 	for (i = 0; i < rq->ring.desc_count; i++, rqd++) {
 		mb = rte_mbuf_raw_alloc(rq->mp);
 		if (mb == NULL) {
@@ -287,7 +301,7 @@ enic_alloc_rx_queue_mbufs(struct enic *enic, struct vnic_rq *rq)
 		rq_enet_desc_enc(rqd, dma_addr,
 				(rq->is_sop ? RQ_ENET_TYPE_ONLY_SOP
 				: RQ_ENET_TYPE_NOT_SOP),
-				mb->buf_len - RTE_PKTMBUF_HEADROOM);
+				rq_buf_len);
 		rq->mbuf_ring[i] = mb;
 	}
 
@@ -581,7 +595,7 @@ int enic_alloc_rq(struct enic *enic, uint16_t queue_idx,
 	unsigned int mbuf_size, mbufs_per_pkt;
 	unsigned int nb_sop_desc, nb_data_desc;
 	uint16_t min_sop, max_sop, min_data, max_data;
-	uint16_t mtu = enic->rte_dev->data->mtu;
+	uint32_t max_rx_pkt_len;
 
 	rq_sop->is_sop = 1;
 	rq_sop->data_queue_idx = data_queue_idx;
@@ -599,22 +613,42 @@ int enic_alloc_rq(struct enic *enic, uint16_t queue_idx,
 
 	mbuf_size = (uint16_t)(rte_pktmbuf_data_room_size(mp) -
 			       RTE_PKTMBUF_HEADROOM);
+	/* max_rx_pkt_len includes the ethernet header and CRC. */
+	max_rx_pkt_len = enic->rte_dev->data->dev_conf.rxmode.max_rx_pkt_len;
 
 	if (enic->rte_dev->data->dev_conf.rxmode.offloads &
 	    DEV_RX_OFFLOAD_SCATTER) {
 		dev_info(enic, "Rq %u Scatter rx mode enabled\n", queue_idx);
-		/* ceil((mtu + ETHER_HDR_LEN + 4)/mbuf_size) */
-		mbufs_per_pkt = ((mtu + ETHER_HDR_LEN + 4) +
-				 (mbuf_size - 1)) / mbuf_size;
+		/* ceil((max pkt len)/mbuf_size) */
+		mbufs_per_pkt = (max_rx_pkt_len + mbuf_size - 1) / mbuf_size;
 	} else {
 		dev_info(enic, "Scatter rx mode disabled\n");
 		mbufs_per_pkt = 1;
+		if (max_rx_pkt_len > mbuf_size) {
+			dev_warning(enic, "The maximum Rx packet size (%u) is"
+				    " larger than the mbuf size (%u), and"
+				    " scatter is disabled. Larger packets will"
+				    " be truncated.\n",
+				    max_rx_pkt_len, mbuf_size);
+		}
 	}
 
 	if (mbufs_per_pkt > 1) {
 		dev_info(enic, "Rq %u Scatter rx mode in use\n", queue_idx);
 		rq_sop->data_queue_enable = 1;
 		rq_data->in_use = 1;
+		/*
+		 * HW does not directly support rxmode.max_rx_pkt_len. HW always
+		 * receives packet sizes up to the "max" MTU.
+		 * If not using scatter, we can achieve the effect of dropping
+		 * larger packets by reducing the size of posted buffers.
+		 * See enic_alloc_rx_queue_mbufs().
+		 */
+		if (max_rx_pkt_len <
+		    enic_mtu_to_max_rx_pktlen(enic->rte_dev->data->mtu)) {
+			dev_warning(enic, "rxmode.max_rx_pkt_len is ignored"
+				    " when scatter rx mode is in use.\n");
+		}
 	} else {
 		dev_info(enic, "Rq %u Scatter rx mode not being used\n",
 			 queue_idx);
@@ -654,8 +688,9 @@ int enic_alloc_rq(struct enic *enic, uint16_t queue_idx,
 		nb_data_desc = max_data;
 	}
 	if (mbufs_per_pkt > 1) {
-		dev_info(enic, "For mtu %d and mbuf size %d valid rx descriptor range is %d to %d\n",
-			 mtu, mbuf_size, min_sop + min_data,
+		dev_info(enic, "For max packet size %u and mbuf size %u valid"
+			 " rx descriptor range is %u to %u\n",
+			 max_rx_pkt_len, mbuf_size, min_sop + min_data,
 			 max_sop + max_data);
 	}
 	dev_info(enic, "Using %d rx descriptors (sop %d, data %d)\n",
-- 
2.12.0

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH] net/enic: remove the VLAN filter handler
  2018-02-24 19:17 [PATCH] net/enic: remove 'extern' in .h file function declarations John Daley
  2018-02-24 19:17 ` [PATCH] net/enic: allow the user to change RSS settings John Daley
  2018-02-24 19:17 ` [PATCH] net/enic: heed the requested max Rx packet size John Daley
@ 2018-02-24 19:17 ` John Daley
  2018-02-24 19:17 ` [PATCH] net/enic: add Rx/Tx queue configuration getters John Daley
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-02-24 19:17 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

VIC does not support VLAN filtering at the moment. The firmware does
accept the filter add/del commands and returns success. But, they are
no-ops. To avoid confusion, remove the filter set handler so the app
sees an error instead of silent failure.

Also during the device configure time, enicpmd_vlan_offload_set would
not print a warning message about unsupported VLAN filtering, because
the caller specifies only ETH_VLAN_STRIP_MASK. This is wrong, as we
should attempt to apply all requested offloads at the configure
time. So, pass all VLAN offload masks, which triggers a warning
message about VLAN filtering, if requested.

Finally, enicpmd_vlan_offload_set should check both mask and
rxmode.offloads, not just mask.

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 drivers/net/enic/enic_ethdev.c | 34 ++++++++++++++--------------------
 1 file changed, 14 insertions(+), 20 deletions(-)

diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
index bdbaf4cdf..e5523e311 100644
--- a/drivers/net/enic/enic_ethdev.c
+++ b/drivers/net/enic/enic_ethdev.c
@@ -318,40 +318,29 @@ static int enicpmd_dev_rx_queue_setup(struct rte_eth_dev *eth_dev,
 	return enicpmd_dev_setup_intr(enic);
 }
 
-static int enicpmd_vlan_filter_set(struct rte_eth_dev *eth_dev,
-	uint16_t vlan_id, int on)
-{
-	struct enic *enic = pmd_priv(eth_dev);
-	int err;
-
-	ENICPMD_FUNC_TRACE();
-	if (on)
-		err = enic_add_vlan(enic, vlan_id);
-	else
-		err = enic_del_vlan(enic, vlan_id);
-	return err;
-}
-
 static int enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 {
 	struct enic *enic = pmd_priv(eth_dev);
+	uint64_t offloads;
 
 	ENICPMD_FUNC_TRACE();
 
+	offloads = eth_dev->data->dev_conf.rxmode.offloads;
 	if (mask & ETH_VLAN_STRIP_MASK) {
-		if (eth_dev->data->dev_conf.rxmode.offloads &
-		    DEV_RX_OFFLOAD_VLAN_STRIP)
+		if (offloads & DEV_RX_OFFLOAD_VLAN_STRIP)
 			enic->ig_vlan_strip_en = 1;
 		else
 			enic->ig_vlan_strip_en = 0;
 	}
 
-	if (mask & ETH_VLAN_FILTER_MASK) {
+	if ((mask & ETH_VLAN_FILTER_MASK) &&
+	    (offloads & DEV_RX_OFFLOAD_VLAN_FILTER)) {
 		dev_warning(enic,
 			"Configuration of VLAN filter is not supported\n");
 	}
 
-	if (mask & ETH_VLAN_EXTEND_MASK) {
+	if ((mask & ETH_VLAN_EXTEND_MASK) &&
+	    (offloads & DEV_RX_OFFLOAD_VLAN_EXTEND)) {
 		dev_warning(enic,
 			"Configuration of extended VLAN is not supported\n");
 	}
@@ -362,6 +351,7 @@ static int enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 static int enicpmd_dev_configure(struct rte_eth_dev *eth_dev)
 {
 	int ret;
+	int mask;
 	struct enic *enic = pmd_priv(eth_dev);
 
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
@@ -376,7 +366,11 @@ static int enicpmd_dev_configure(struct rte_eth_dev *eth_dev)
 
 	enic->hw_ip_checksum = !!(eth_dev->data->dev_conf.rxmode.offloads &
 				  DEV_RX_OFFLOAD_CHECKSUM);
-	ret = enicpmd_vlan_offload_set(eth_dev, ETH_VLAN_STRIP_MASK);
+	/* All vlan offload masks to apply the current settings */
+	mask = ETH_VLAN_STRIP_MASK |
+		ETH_VLAN_FILTER_MASK |
+		ETH_VLAN_EXTEND_MASK;
+	ret = enicpmd_vlan_offload_set(eth_dev, mask);
 	if (ret) {
 		dev_err(enic, "Failed to configure VLAN offloads\n");
 		return ret;
@@ -710,7 +704,7 @@ static const struct eth_dev_ops enicpmd_eth_dev_ops = {
 	.dev_infos_get        = enicpmd_dev_info_get,
 	.dev_supported_ptypes_get = enicpmd_dev_supported_ptypes_get,
 	.mtu_set              = enicpmd_mtu_set,
-	.vlan_filter_set      = enicpmd_vlan_filter_set,
+	.vlan_filter_set      = NULL,
 	.vlan_tpid_set        = NULL,
 	.vlan_offload_set     = enicpmd_vlan_offload_set,
 	.vlan_strip_queue_set = NULL,
-- 
2.12.0

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH] net/enic: add Rx/Tx queue configuration getters
  2018-02-24 19:17 [PATCH] net/enic: remove 'extern' in .h file function declarations John Daley
                   ` (2 preceding siblings ...)
  2018-02-24 19:17 ` [PATCH] net/enic: remove the VLAN filter handler John Daley
@ 2018-02-24 19:17 ` John Daley
  2018-02-24 19:17 ` [PATCH] net/enic: allocate stats DMA buffer upfront during probe John Daley
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-02-24 19:17 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 drivers/net/enic/enic_ethdev.c | 76 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 65 insertions(+), 11 deletions(-)

diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
index e5523e311..6dd72729e 100644
--- a/drivers/net/enic/enic_ethdev.c
+++ b/drivers/net/enic/enic_ethdev.c
@@ -39,6 +39,19 @@ static const struct rte_pci_id pci_id_enic_map[] = {
 	{.vendor_id = 0, /* sentinel */},
 };
 
+#define ENIC_TX_OFFLOAD_CAPA (			\
+		DEV_TX_OFFLOAD_VLAN_INSERT |	\
+		DEV_TX_OFFLOAD_IPV4_CKSUM  |	\
+		DEV_TX_OFFLOAD_UDP_CKSUM   |	\
+		DEV_TX_OFFLOAD_TCP_CKSUM   |	\
+		DEV_TX_OFFLOAD_TCP_TSO)
+
+#define ENIC_RX_OFFLOAD_CAPA (			\
+		DEV_RX_OFFLOAD_VLAN_STRIP |	\
+		DEV_RX_OFFLOAD_IPV4_CKSUM |	\
+		DEV_RX_OFFLOAD_UDP_CKSUM  |	\
+		DEV_RX_OFFLOAD_TCP_CKSUM)
+
 RTE_INIT(enicpmd_init_log);
 static void
 enicpmd_init_log(void)
@@ -473,17 +486,8 @@ static void enicpmd_dev_info_get(struct rte_eth_dev *eth_dev,
 	 */
 	device_info->max_rx_pktlen = enic_mtu_to_max_rx_pktlen(enic->max_mtu);
 	device_info->max_mac_addrs = ENIC_MAX_MAC_ADDR;
-	device_info->rx_offload_capa =
-		DEV_RX_OFFLOAD_VLAN_STRIP |
-		DEV_RX_OFFLOAD_IPV4_CKSUM |
-		DEV_RX_OFFLOAD_UDP_CKSUM  |
-		DEV_RX_OFFLOAD_TCP_CKSUM;
-	device_info->tx_offload_capa =
-		DEV_TX_OFFLOAD_VLAN_INSERT |
-		DEV_TX_OFFLOAD_IPV4_CKSUM  |
-		DEV_TX_OFFLOAD_UDP_CKSUM   |
-		DEV_TX_OFFLOAD_TCP_CKSUM   |
-		DEV_TX_OFFLOAD_TCP_TSO;
+	device_info->rx_offload_capa = ENIC_RX_OFFLOAD_CAPA;
+	device_info->tx_offload_capa = ENIC_TX_OFFLOAD_CAPA;
 	device_info->default_rxconf = (struct rte_eth_rxconf) {
 		.rx_free_thresh = ENIC_DEFAULT_RX_FREE_THRESH
 	};
@@ -686,6 +690,54 @@ static int enicpmd_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
 	return 0;
 }
 
+static void enicpmd_dev_rxq_info_get(struct rte_eth_dev *dev,
+				     uint16_t rx_queue_id,
+				     struct rte_eth_rxq_info *qinfo)
+{
+	struct enic *enic = pmd_priv(dev);
+	struct vnic_rq *rq_sop;
+	struct vnic_rq *rq_data;
+	struct rte_eth_rxconf *conf;
+	uint16_t sop_queue_idx;
+	uint16_t data_queue_idx;
+
+	ENICPMD_FUNC_TRACE();
+	sop_queue_idx = enic_rte_rq_idx_to_sop_idx(rx_queue_id);
+	data_queue_idx = enic_rte_rq_idx_to_data_idx(rx_queue_id);
+	rq_sop = &enic->rq[sop_queue_idx];
+	rq_data = &enic->rq[data_queue_idx]; /* valid if data_queue_enable */
+	qinfo->mp = rq_sop->mp;
+	qinfo->scattered_rx = rq_sop->data_queue_enable;
+	qinfo->nb_desc = rq_sop->ring.desc_count;
+	if (qinfo->scattered_rx)
+		qinfo->nb_desc += rq_data->ring.desc_count;
+	conf = &qinfo->conf;
+	memset(conf, 0, sizeof(*conf));
+	conf->rx_free_thresh = rq_sop->rx_free_thresh;
+	conf->rx_drop_en = 1;
+	/*
+	 * Except VLAN stripping (port setting), all the checksum offloads
+	 * are always enabled.
+	 */
+	conf->offloads = ENIC_RX_OFFLOAD_CAPA;
+	if (!enic->ig_vlan_strip_en)
+		conf->offloads &= ~DEV_RX_OFFLOAD_VLAN_STRIP;
+	/* rx_thresh and other fields are not applicable for enic */
+}
+
+static void enicpmd_dev_txq_info_get(struct rte_eth_dev *dev,
+				     __rte_unused uint16_t tx_queue_id,
+				     struct rte_eth_txq_info *qinfo)
+{
+	struct enic *enic = pmd_priv(dev);
+
+	ENICPMD_FUNC_TRACE();
+	qinfo->nb_desc = enic->config.wq_desc_count;
+	memset(&qinfo->conf, 0, sizeof(qinfo->conf));
+	qinfo->conf.offloads = ENIC_TX_OFFLOAD_CAPA; /* not configurable */
+	/* tx_thresh, and all the other fields are not applicable for enic */
+}
+
 static const struct eth_dev_ops enicpmd_eth_dev_ops = {
 	.dev_configure        = enicpmd_dev_configure,
 	.dev_start            = enicpmd_dev_start,
@@ -718,6 +770,8 @@ static const struct eth_dev_ops enicpmd_eth_dev_ops = {
 	.rx_descriptor_done   = NULL,
 	.tx_queue_setup       = enicpmd_dev_tx_queue_setup,
 	.tx_queue_release     = enicpmd_dev_tx_queue_release,
+	.rxq_info_get         = enicpmd_dev_rxq_info_get,
+	.txq_info_get         = enicpmd_dev_txq_info_get,
 	.dev_led_on           = NULL,
 	.dev_led_off          = NULL,
 	.flow_ctrl_get        = NULL,
-- 
2.12.0

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH] net/enic: allocate stats DMA buffer upfront during probe
  2018-02-24 19:17 [PATCH] net/enic: remove 'extern' in .h file function declarations John Daley
                   ` (3 preceding siblings ...)
  2018-02-24 19:17 ` [PATCH] net/enic: add Rx/Tx queue configuration getters John Daley
@ 2018-02-24 19:17 ` John Daley
  2018-02-24 19:17 ` [PATCH] net/enic: support Rx queue interrupts John Daley
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-02-24 19:17 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim, stable

From: Hyong Youb Kim <hyonkim@cisco.com>

The driver provides a DMA buffer to the firmware when it requests port
stats. The NIC then fills that buffer with latest stats. Currently,
the driver allocates the DMA buffer the first time it requests stats
and saves it for later use. This can lead to crashes when
primary/secondary processes are involved. For example, the following
sequence crashes the secondary process.

1. Start a primary app that does not call rte_eth_stats_get()
2. dpdk-procinfo -- --stats

dpdk-procinfo crashes while trying to allocate the stats DMA buffer
because the alloc function pointer (vdev.alloc_consistent) is valid
only in the primary process, not in the secondary process.

Overwriting the alloc function pointer in the secondary process is not
an option, as it will simply make the pointer invalid in the primary
process. Instead, allocate the DMA buffer during probe so that only
the primary process does both allocate and free. This allows the
secondary process to dump stats as well.

Cc: stable@dpdk.org
Fixes: 9913fbb91df0 ("enic/base: common code")

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 drivers/net/enic/base/vnic_dev.c | 24 ++++++++++++++----------
 drivers/net/enic/base/vnic_dev.h |  1 +
 drivers/net/enic/enic_main.c     |  9 +++++++++
 3 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/drivers/net/enic/base/vnic_dev.c b/drivers/net/enic/base/vnic_dev.c
index 05b595eb8..1f8d222fc 100644
--- a/drivers/net/enic/base/vnic_dev.c
+++ b/drivers/net/enic/base/vnic_dev.c
@@ -587,17 +587,9 @@ int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats)
 {
 	u64 a0, a1;
 	int wait = 1000;
-	static u32 instance;
-	char name[NAME_MAX];
 
-	if (!vdev->stats) {
-		snprintf((char *)name, sizeof(name),
-			"vnic_stats-%u", instance++);
-		vdev->stats = vdev->alloc_consistent(vdev->priv,
-			sizeof(struct vnic_stats), &vdev->stats_pa, (u8 *)name);
-		if (!vdev->stats)
-			return -ENOMEM;
-	}
+	if (!vdev->stats)
+		return -ENOMEM;
 
 	*stats = vdev->stats;
 	a0 = vdev->stats_pa;
@@ -922,6 +914,18 @@ u32 vnic_dev_get_intr_coal_timer_max(struct vnic_dev *vdev)
 	return vdev->intr_coal_timer_info.max_usec;
 }
 
+int vnic_dev_alloc_stats_mem(struct vnic_dev *vdev)
+{
+	char name[NAME_MAX];
+	static u32 instance;
+
+	snprintf((char *)name, sizeof(name), "vnic_stats-%u", instance++);
+	vdev->stats = vdev->alloc_consistent(vdev->priv,
+					     sizeof(struct vnic_stats),
+					     &vdev->stats_pa, (u8 *)name);
+	return vdev->stats == NULL ? -ENOMEM : 0;
+}
+
 void vnic_dev_unregister(struct vnic_dev *vdev)
 {
 	if (vdev) {
diff --git a/drivers/net/enic/base/vnic_dev.h b/drivers/net/enic/base/vnic_dev.h
index 8c0992063..7e5736b4d 100644
--- a/drivers/net/enic/base/vnic_dev.h
+++ b/drivers/net/enic/base/vnic_dev.h
@@ -165,6 +165,7 @@ struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
 	void *priv, struct rte_pci_device *pdev, struct vnic_dev_bar *bar,
 	unsigned int num_bars);
 struct rte_pci_device *vnic_dev_get_pdev(struct vnic_dev *vdev);
+int vnic_dev_alloc_stats_mem(struct vnic_dev *vdev);
 int vnic_dev_cmd_init(struct vnic_dev *vdev, int fallback);
 int vnic_dev_get_size(void);
 int vnic_dev_int13(struct vnic_dev *vdev, u64 arg, u32 op);
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index d4f478b5e..bd4447f01 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -1478,6 +1478,15 @@ int enic_probe(struct enic *enic)
 		enic_alloc_consistent,
 		enic_free_consistent);
 
+	/*
+	 * Allocate the consistent memory for stats upfront so both primary and
+	 * secondary processes can dump stats.
+	 */
+	err = vnic_dev_alloc_stats_mem(enic->vdev);
+	if (err) {
+		dev_err(enic, "Failed to allocate cmd memory, aborting\n");
+		goto err_out_unregister;
+	}
 	/* Issue device open to get device in known state */
 	err = enic_dev_open(enic);
 	if (err) {
-- 
2.12.0

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH] net/enic: support Rx queue interrupts
  2018-02-24 19:17 [PATCH] net/enic: remove 'extern' in .h file function declarations John Daley
                   ` (4 preceding siblings ...)
  2018-02-24 19:17 ` [PATCH] net/enic: allocate stats DMA buffer upfront during probe John Daley
@ 2018-02-24 19:17 ` John Daley
  2018-02-24 19:17 ` [PATCH] doc: describe Rx bytes counter behavior for enic John Daley
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-02-24 19:17 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

Enable rx queue interrupts if the app requests them, and vNIC has
enough interrupt resources. Use interrupt vector 0 for link status and
errors. Use vector 1 for rx queue 0, vector 2 for rx queue 1, and so
on. So, with n rx queues, vNIC needs to have at n + 1 interrupts.

For VIC, enabling and disabling rx queue interrupts are simply
mask/unmask operations. VIC's credit based interrupt moderation is not
used, as the app wants to explicitly control when to enable/disable
interrupts.

This version requires MSI-X (vfio-pci). Sharing one interrupt for link
status and rx queues is possible, but is rather complex and has no
user demands.

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 doc/guides/nics/enic.rst          |   7 ++-
 doc/guides/nics/features/enic.ini |   1 +
 drivers/net/enic/enic.h           |  15 ++++-
 drivers/net/enic/enic_ethdev.c    |  22 +++++++
 drivers/net/enic/enic_main.c      | 123 ++++++++++++++++++++++++++++++++------
 drivers/net/enic/enic_res.c       |   3 +-
 6 files changed, 149 insertions(+), 22 deletions(-)

diff --git a/doc/guides/nics/enic.rst b/doc/guides/nics/enic.rst
index 0e655e9e3..7e19cf88a 100644
--- a/doc/guides/nics/enic.rst
+++ b/doc/guides/nics/enic.rst
@@ -114,11 +114,16 @@ Configuration information
 
   - **Interrupts**
 
-    Only one interrupt per vNIC interface should be configured in the UCS
+    At least one interrupt per vNIC interface should be configured in the UCS
     manager regardless of the number receive/transmit queues. The ENIC PMD
     uses this interrupt to get information about link status and errors
     in the fast path.
 
+    In addition to the interrupt for link status and errors, when using Rx queue
+    interrupts, increase the number of configured interrupts so that there is at
+    least one interrupt for each Rx queue. For example, if the app uses 3 Rx
+    queues and wants to use per-queue interrupts, configure 4 (3 + 1) interrupts.
+
 .. _enic-flow-director:
 
 Flow director support
diff --git a/doc/guides/nics/features/enic.ini b/doc/guides/nics/features/enic.ini
index e79d7277d..ea171a45b 100644
--- a/doc/guides/nics/features/enic.ini
+++ b/doc/guides/nics/features/enic.ini
@@ -6,6 +6,7 @@
 [Features]
 Link status          = Y
 Link status event    = Y
+Rx interrupt         = Y
 Queue start/stop     = Y
 MTU update           = Y
 Jumbo frame          = Y
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index 1b3813a58..adccc8ac5 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -49,6 +49,15 @@
 
 #define ENICPMD_FDIR_MAX           64
 
+/*
+ * Interrupt 0: LSC and errors
+ * Interrupt 1: rx queue 0
+ * Interrupt 2: rx queue 1
+ * ...
+ */
+#define ENICPMD_LSC_INTR_OFFSET 0
+#define ENICPMD_RXQ_INTR_OFFSET 1
+
 struct enic_fdir_node {
 	struct rte_eth_fdir_filter filter;
 	u16 fltr_id;
@@ -126,9 +135,9 @@ struct enic {
 	struct vnic_cq *cq;
 	unsigned int cq_count; /* equals rq_count + wq_count */
 
-	/* interrupt resource */
-	struct vnic_intr intr;
-	unsigned int intr_count;
+	/* interrupt vectors (len = conf_intr_count) */
+	struct vnic_intr *intr;
+	unsigned int intr_count; /* equals enabled interrupts (lsc + rxqs) */
 
 	/* software counters */
 	struct enic_soft_stats soft_stats;
diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
index 6dd72729e..2a289b6a4 100644
--- a/drivers/net/enic/enic_ethdev.c
+++ b/drivers/net/enic/enic_ethdev.c
@@ -738,6 +738,26 @@ static void enicpmd_dev_txq_info_get(struct rte_eth_dev *dev,
 	/* tx_thresh, and all the other fields are not applicable for enic */
 }
 
+static int enicpmd_dev_rx_queue_intr_enable(struct rte_eth_dev *eth_dev,
+					    uint16_t rx_queue_id)
+{
+	struct enic *enic = pmd_priv(eth_dev);
+
+	ENICPMD_FUNC_TRACE();
+	vnic_intr_unmask(&enic->intr[rx_queue_id + ENICPMD_RXQ_INTR_OFFSET]);
+	return 0;
+}
+
+static int enicpmd_dev_rx_queue_intr_disable(struct rte_eth_dev *eth_dev,
+					     uint16_t rx_queue_id)
+{
+	struct enic *enic = pmd_priv(eth_dev);
+
+	ENICPMD_FUNC_TRACE();
+	vnic_intr_mask(&enic->intr[rx_queue_id + ENICPMD_RXQ_INTR_OFFSET]);
+	return 0;
+}
+
 static const struct eth_dev_ops enicpmd_eth_dev_ops = {
 	.dev_configure        = enicpmd_dev_configure,
 	.dev_start            = enicpmd_dev_start,
@@ -770,6 +790,8 @@ static const struct eth_dev_ops enicpmd_eth_dev_ops = {
 	.rx_descriptor_done   = NULL,
 	.tx_queue_setup       = enicpmd_dev_tx_queue_setup,
 	.tx_queue_release     = enicpmd_dev_tx_queue_release,
+	.rx_queue_intr_enable = enicpmd_dev_rx_queue_intr_enable,
+	.rx_queue_intr_disable = enicpmd_dev_rx_queue_intr_disable,
 	.rxq_info_get         = enicpmd_dev_rxq_info_get,
 	.txq_info_get         = enicpmd_dev_txq_info_get,
 	.dev_led_on           = NULL,
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index bd4447f01..ff1b15be6 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -200,10 +200,16 @@ void enic_init_vnic_resources(struct enic *enic)
 {
 	unsigned int error_interrupt_enable = 1;
 	unsigned int error_interrupt_offset = 0;
+	unsigned int rxq_interrupt_enable = 0;
+	unsigned int rxq_interrupt_offset;
 	unsigned int index = 0;
 	unsigned int cq_idx;
 	struct vnic_rq *data_rq;
 
+	if (enic->rte_dev->data->dev_conf.intr_conf.rxq) {
+		rxq_interrupt_enable = 1;
+		rxq_interrupt_offset = ENICPMD_RXQ_INTR_OFFSET;
+	}
 	for (index = 0; index < enic->rq_count; index++) {
 		cq_idx = enic_cq_rq(enic, enic_rte_rq_idx_to_sop_idx(index));
 
@@ -225,11 +231,13 @@ void enic_init_vnic_resources(struct enic *enic)
 			0 /* cq_head */,
 			0 /* cq_tail */,
 			1 /* cq_tail_color */,
-			0 /* interrupt_enable */,
+			rxq_interrupt_enable,
 			1 /* cq_entry_enable */,
 			0 /* cq_message_enable */,
-			0 /* interrupt offset */,
+			rxq_interrupt_offset,
 			0 /* cq_message_addr */);
+		if (rxq_interrupt_enable)
+			rxq_interrupt_offset++;
 	}
 
 	for (index = 0; index < enic->wq_count; index++) {
@@ -252,10 +260,12 @@ void enic_init_vnic_resources(struct enic *enic)
 			(u64)enic->wq[index].cqmsg_rz->iova);
 	}
 
-	vnic_intr_init(&enic->intr,
-		enic->config.intr_timer_usec,
-		enic->config.intr_timer_type,
-		/*mask_on_assertion*/1);
+	for (index = 0; index < enic->intr_count; index++) {
+		vnic_intr_init(&enic->intr[index],
+			       enic->config.intr_timer_usec,
+			       enic->config.intr_timer_type,
+			       /*mask_on_assertion*/1);
+	}
 }
 
 
@@ -411,13 +421,62 @@ enic_intr_handler(void *arg)
 	struct rte_eth_dev *dev = (struct rte_eth_dev *)arg;
 	struct enic *enic = pmd_priv(dev);
 
-	vnic_intr_return_all_credits(&enic->intr);
+	vnic_intr_return_all_credits(&enic->intr[ENICPMD_LSC_INTR_OFFSET]);
 
 	enic_link_update(enic);
 	_rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
 	enic_log_q_error(enic);
 }
 
+static int enic_rxq_intr_init(struct enic *enic)
+{
+	struct rte_intr_handle *intr_handle;
+	uint32_t rxq_intr_count, i;
+	int err;
+
+	intr_handle = enic->rte_dev->intr_handle;
+	if (!enic->rte_dev->data->dev_conf.intr_conf.rxq)
+		return 0;
+	/*
+	 * Rx queue interrupts only work when we have MSI-X interrupts,
+	 * one per queue. Sharing one interrupt is technically
+	 * possible with VIC, but it is not worth the complications it brings.
+	 */
+	if (!rte_intr_cap_multiple(intr_handle)) {
+		dev_err(enic, "Rx queue interrupts require MSI-X interrupts"
+			" (vfio-pci driver)\n");
+		return -ENOTSUP;
+	}
+	rxq_intr_count = enic->intr_count - ENICPMD_RXQ_INTR_OFFSET;
+	err = rte_intr_efd_enable(intr_handle, rxq_intr_count);
+	if (err) {
+		dev_err(enic, "Failed to enable event fds for Rx queue"
+			" interrupts\n");
+		return err;
+	}
+	intr_handle->intr_vec = rte_zmalloc("enic_intr_vec",
+					    rxq_intr_count * sizeof(int), 0);
+	if (intr_handle->intr_vec == NULL) {
+		dev_err(enic, "Failed to allocate intr_vec\n");
+		return -ENOMEM;
+	}
+	for (i = 0; i < rxq_intr_count; i++)
+		intr_handle->intr_vec[i] = i + ENICPMD_RXQ_INTR_OFFSET;
+	return 0;
+}
+
+static void enic_rxq_intr_deinit(struct enic *enic)
+{
+	struct rte_intr_handle *intr_handle;
+
+	intr_handle = enic->rte_dev->intr_handle;
+	rte_intr_efd_disable(intr_handle);
+	if (intr_handle->intr_vec != NULL) {
+		rte_free(intr_handle->intr_vec);
+		intr_handle->intr_vec = NULL;
+	}
+}
+
 int enic_enable(struct enic *enic)
 {
 	unsigned int index;
@@ -434,6 +493,9 @@ int enic_enable(struct enic *enic)
 	if (eth_dev->data->dev_conf.intr_conf.lsc)
 		vnic_dev_notify_set(enic->vdev, 0);
 
+	err = enic_rxq_intr_init(enic);
+	if (err)
+		return err;
 	if (enic_clsf_init(enic))
 		dev_warning(enic, "Init of hash table for clsf failed."\
 			"Flow director feature will not work\n");
@@ -471,7 +533,8 @@ int enic_enable(struct enic *enic)
 		enic_intr_handler, (void *)enic->rte_dev);
 
 	rte_intr_enable(&(enic->pdev->intr_handle));
-	vnic_intr_unmask(&enic->intr);
+	/* Unmask LSC interrupt */
+	vnic_intr_unmask(&enic->intr[ENICPMD_LSC_INTR_OFFSET]);
 
 	return 0;
 }
@@ -479,17 +542,21 @@ int enic_enable(struct enic *enic)
 int enic_alloc_intr_resources(struct enic *enic)
 {
 	int err;
+	unsigned int i;
 
 	dev_info(enic, "vNIC resources used:  "\
 		"wq %d rq %d cq %d intr %d\n",
 		enic->wq_count, enic_vnic_rq_count(enic),
 		enic->cq_count, enic->intr_count);
 
-	err = vnic_intr_alloc(enic->vdev, &enic->intr, 0);
-	if (err)
-		enic_free_vnic_resources(enic);
-
-	return err;
+	for (i = 0; i < enic->intr_count; i++) {
+		err = vnic_intr_alloc(enic->vdev, &enic->intr[i], i);
+		if (err) {
+			enic_free_vnic_resources(enic);
+			return err;
+		}
+	}
+	return 0;
 }
 
 void enic_free_rq(void *rxq)
@@ -837,8 +904,11 @@ int enic_disable(struct enic *enic)
 	unsigned int i;
 	int err;
 
-	vnic_intr_mask(&enic->intr);
-	(void)vnic_intr_masked(&enic->intr); /* flush write */
+	for (i = 0; i < enic->intr_count; i++) {
+		vnic_intr_mask(&enic->intr[i]);
+		(void)vnic_intr_masked(&enic->intr[i]); /* flush write */
+	}
+	enic_rxq_intr_deinit(enic);
 	rte_intr_disable(&enic->pdev->intr_handle);
 	rte_intr_callback_unregister(&enic->pdev->intr_handle,
 				     enic_intr_handler,
@@ -881,7 +951,8 @@ int enic_disable(struct enic *enic)
 			vnic_rq_clean(&enic->rq[i], enic_free_rq_buf);
 	for (i = 0; i < enic->cq_count; i++)
 		vnic_cq_clean(&enic->cq[i]);
-	vnic_intr_clean(&enic->intr);
+	for (i = 0; i < enic->intr_count; i++)
+		vnic_intr_clean(&enic->intr[i]);
 
 	return 0;
 }
@@ -1170,6 +1241,7 @@ static void enic_dev_deinit(struct enic *enic)
 
 	rte_free(eth_dev->data->mac_addrs);
 	rte_free(enic->cq);
+	rte_free(enic->intr);
 	rte_free(enic->rq);
 	rte_free(enic->wq);
 }
@@ -1179,12 +1251,16 @@ int enic_set_vnic_res(struct enic *enic)
 {
 	struct rte_eth_dev *eth_dev = enic->rte_dev;
 	int rc = 0;
-	unsigned int required_rq, required_wq, required_cq;
+	unsigned int required_rq, required_wq, required_cq, required_intr;
 
 	/* Always use two vNIC RQs per eth_dev RQ, regardless of Rx scatter. */
 	required_rq = eth_dev->data->nb_rx_queues * 2;
 	required_wq = eth_dev->data->nb_tx_queues;
 	required_cq = eth_dev->data->nb_rx_queues + eth_dev->data->nb_tx_queues;
+	required_intr = 1; /* 1 for LSC even if intr_conf.lsc is 0 */
+	if (eth_dev->data->dev_conf.intr_conf.rxq) {
+		required_intr += eth_dev->data->nb_rx_queues;
+	}
 
 	if (enic->conf_rq_count < required_rq) {
 		dev_err(dev, "Not enough Receive queues. Requested:%u which uses %d RQs on VIC, Configured:%u\n",
@@ -1203,11 +1279,18 @@ int enic_set_vnic_res(struct enic *enic)
 			required_cq, enic->conf_cq_count);
 		rc = -EINVAL;
 	}
+	if (enic->conf_intr_count < required_intr) {
+		dev_err(dev, "Not enough Interrupts to support Rx queue"
+			" interrupts. Required:%u, Configured:%u\n",
+			required_intr, enic->conf_intr_count);
+		rc = -EINVAL;
+	}
 
 	if (rc == 0) {
 		enic->rq_count = eth_dev->data->nb_rx_queues;
 		enic->wq_count = eth_dev->data->nb_tx_queues;
 		enic->cq_count = enic->rq_count + enic->wq_count;
+		enic->intr_count = required_intr;
 	}
 
 	return rc;
@@ -1409,6 +1492,8 @@ static int enic_dev_init(struct enic *enic)
 	/* Queue counts may be zeros. rte_zmalloc returns NULL in that case. */
 	enic->cq = rte_zmalloc("enic_vnic_cq", sizeof(struct vnic_cq) *
 			       enic->conf_cq_count, 8);
+	enic->intr = rte_zmalloc("enic_vnic_intr", sizeof(struct vnic_intr) *
+				 enic->conf_intr_count, 8);
 	enic->rq = rte_zmalloc("enic_vnic_rq", sizeof(struct vnic_rq) *
 			       enic->conf_rq_count, 8);
 	enic->wq = rte_zmalloc("enic_vnic_wq", sizeof(struct vnic_wq) *
@@ -1417,6 +1502,10 @@ static int enic_dev_init(struct enic *enic)
 		dev_err(enic, "failed to allocate vnic_cq, aborting.\n");
 		return -1;
 	}
+	if (enic->conf_intr_count > 0 && enic->intr == NULL) {
+		dev_err(enic, "failed to allocate vnic_intr, aborting.\n");
+		return -1;
+	}
 	if (enic->conf_rq_count > 0 && enic->rq == NULL) {
 		dev_err(enic, "failed to allocate vnic_rq, aborting.\n");
 		return -1;
diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c
index d8f7892c3..e7ad6767e 100644
--- a/drivers/net/enic/enic_res.c
+++ b/drivers/net/enic/enic_res.c
@@ -222,7 +222,8 @@ void enic_free_vnic_resources(struct enic *enic)
 			vnic_rq_free(&enic->rq[i]);
 	for (i = 0; i < enic->cq_count; i++)
 		vnic_cq_free(&enic->cq[i]);
-	vnic_intr_free(&enic->intr);
+	for (i = 0; i < enic->intr_count; i++)
+		vnic_intr_free(&enic->intr[i]);
 }
 
 void enic_get_res_counts(struct enic *enic)
-- 
2.12.0

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH] doc: describe Rx bytes counter behavior for enic
  2018-02-24 19:17 [PATCH] net/enic: remove 'extern' in .h file function declarations John Daley
                   ` (5 preceding siblings ...)
  2018-02-24 19:17 ` [PATCH] net/enic: support Rx queue interrupts John Daley
@ 2018-02-24 19:17 ` John Daley
  2018-02-24 19:17 ` [PATCH] net/enic: use memcpy to avoid strict aliasing warnings John Daley
  2018-02-24 19:17 ` [PATCH] net/enic: support for meson John Daley
  8 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-02-24 19:17 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 doc/guides/nics/enic.rst | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/doc/guides/nics/enic.rst b/doc/guides/nics/enic.rst
index 7e19cf88a..0bc55936a 100644
--- a/doc/guides/nics/enic.rst
+++ b/doc/guides/nics/enic.rst
@@ -310,6 +310,14 @@ Limitations
     were added. Since there currently is no grouping or priority support,
     'catch-all' filters should be added last.
 
+- **Statistics**
+
+  - ``rx_good_bytes`` (ibytes) always includes VLAN header (4B) and CRC bytes (4B).
+  - When the NIC drops a packet because the Rx queue has no free buffers,
+    ``rx_good_bytes`` still increments by 4B if the packet is not VLAN tagged or
+    VLAN stripping is disabled, or by 8B if the packet is VLAN tagged and stripping
+    is enabled.
+
 How to build the suite
 ----------------------
 
-- 
2.12.0

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH] net/enic: use memcpy to avoid strict aliasing warnings
  2018-02-24 19:17 [PATCH] net/enic: remove 'extern' in .h file function declarations John Daley
                   ` (6 preceding siblings ...)
  2018-02-24 19:17 ` [PATCH] doc: describe Rx bytes counter behavior for enic John Daley
@ 2018-02-24 19:17 ` John Daley
  2018-02-24 19:17 ` [PATCH] net/enic: support for meson John Daley
  8 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-02-24 19:17 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 drivers/net/enic/enic_clsf.c | 21 ++++++++-------------
 1 file changed, 8 insertions(+), 13 deletions(-)

diff --git a/drivers/net/enic/enic_clsf.c b/drivers/net/enic/enic_clsf.c
index 3ef1d0832..9d95201ec 100644
--- a/drivers/net/enic/enic_clsf.c
+++ b/drivers/net/enic/enic_clsf.c
@@ -111,7 +111,6 @@ copy_fltr_v2(struct filter_v2 *fltr, struct rte_eth_fdir_input *input,
 	     struct rte_eth_fdir_masks *masks)
 {
 	struct filter_generic_1 *gp = &fltr->u.generic_1;
-	int i;
 
 	fltr->type = FILTER_DPDK_1;
 	memset(gp, 0, sizeof(*gp));
@@ -273,18 +272,14 @@ copy_fltr_v2(struct filter_v2 *fltr, struct rte_eth_fdir_input *input,
 			ipv6_mask.proto = masks->ipv6_mask.proto;
 			ipv6_val.proto = input->flow.ipv6_flow.proto;
 		}
-		for (i = 0; i < 4; i++) {
-			*(uint32_t *)&ipv6_mask.src_addr[i * 4] =
-					masks->ipv6_mask.src_ip[i];
-			*(uint32_t *)&ipv6_val.src_addr[i * 4] =
-					input->flow.ipv6_flow.src_ip[i];
-		}
-		for (i = 0; i < 4; i++) {
-			*(uint32_t *)&ipv6_mask.dst_addr[i * 4] =
-					masks->ipv6_mask.src_ip[i];
-			*(uint32_t *)&ipv6_val.dst_addr[i * 4] =
-					input->flow.ipv6_flow.dst_ip[i];
-		}
+		memcpy(ipv6_mask.src_addr, masks->ipv6_mask.src_ip,
+		       sizeof(ipv6_mask.src_addr));
+		memcpy(ipv6_val.src_addr, input->flow.ipv6_flow.src_ip,
+		       sizeof(ipv6_val.src_addr));
+		memcpy(ipv6_mask.dst_addr, masks->ipv6_mask.dst_ip,
+		       sizeof(ipv6_mask.dst_addr));
+		memcpy(ipv6_val.dst_addr, input->flow.ipv6_flow.dst_ip,
+		       sizeof(ipv6_val.dst_addr));
 		if (input->flow.ipv6_flow.tc) {
 			ipv6_mask.vtc_flow = masks->ipv6_mask.tc << 12;
 			ipv6_val.vtc_flow = input->flow.ipv6_flow.tc << 12;
-- 
2.12.0

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH] net/enic: support for meson
  2018-02-24 19:17 [PATCH] net/enic: remove 'extern' in .h file function declarations John Daley
                   ` (7 preceding siblings ...)
  2018-02-24 19:17 ` [PATCH] net/enic: use memcpy to avoid strict aliasing warnings John Daley
@ 2018-02-24 19:17 ` John Daley
  2018-03-06  1:46   ` [PATCH v2 00/10] enic patchset John Daley
  8 siblings, 1 reply; 44+ messages in thread
From: John Daley @ 2018-02-24 19:17 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---

Note: check-git-log.sh seems to fail when files in drivers/net are included
even if they are commited independently with the "drivers/net:" prefix.
Commiting both files at once. Please ignore check-git-log.sh failure
or suggest a petter prefix.

 drivers/net/enic/meson.build | 19 +++++++++++++++++++
 drivers/net/meson.build      |  2 +-
 2 files changed, 20 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/enic/meson.build

diff --git a/drivers/net/enic/meson.build b/drivers/net/enic/meson.build
new file mode 100644
index 000000000..bfd4e2373
--- /dev/null
+++ b/drivers/net/enic/meson.build
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Cisco Systems, Inc.
+
+sources = files(
+	'base/vnic_cq.c',
+	'base/vnic_dev.c',
+	'base/vnic_intr.c',
+	'base/vnic_rq.c',
+	'base/vnic_rss.c',
+	'base/vnic_wq.c',
+	'enic_clsf.c',
+	'enic_ethdev.c',
+	'enic_flow.c',
+	'enic_main.c',
+	'enic_res.c',
+	'enic_rxtx.c',
+	)
+deps += ['hash']
+includes += include_directories('base')
diff --git a/drivers/net/meson.build b/drivers/net/meson.build
index 704cbe3c8..f535baa13 100644
--- a/drivers/net/meson.build
+++ b/drivers/net/meson.build
@@ -2,7 +2,7 @@
 # Copyright(c) 2017 Intel Corporation
 
 drivers = ['af_packet', 'bonding',
-	'e1000', 'fm10k', 'i40e', 'ixgbe',
+	'e1000', 'enic', 'fm10k', 'i40e', 'ixgbe',
 	'null', 'octeontx', 'pcap', 'ring',
 	'sfc', 'thunderx']
 std_deps = ['ethdev', 'kvargs'] # 'ethdev' also pulls in mbuf, net, eal etc
-- 
2.12.0

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 00/10] enic patchset
  2018-02-24 19:17 ` [PATCH] net/enic: support for meson John Daley
@ 2018-03-06  1:46   ` John Daley
  2018-03-06  1:46     ` [PATCH v2 01/10] net/enic: remove 'extern' in .h file function declarations John Daley
                       ` (9 more replies)
  0 siblings, 10 replies; 44+ messages in thread
From: John Daley @ 2018-03-06  1:46 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, John Daley

v2: rebase, submit as patchset instead of individual patches so they
apply correctly.

Hyong Youb Kim (9):
  net/enic: allow the user to change RSS settings
  net/enic: heed the requested max Rx packet size
  net/enic: remove the VLAN filter handler
  net/enic: add Rx/Tx queue configuration getters
  net/enic: allocate stats DMA buffer upfront during probe
  net/enic: support Rx queue interrupts
  doc: describe Rx bytes counter behavior for enic
  net/enic: use memcpy to avoid strict aliasing warnings
  net/enic: support for meson

John Daley (1):
  net/enic: remove 'extern' in .h file function declarations

 doc/guides/nics/enic.rst          |  16 +-
 doc/guides/nics/features/enic.ini |   3 +
 drivers/net/enic/base/vnic_dev.c  |  24 ++-
 drivers/net/enic/base/vnic_dev.h  |   1 +
 drivers/net/enic/enic.h           | 120 +++++++-----
 drivers/net/enic/enic_clsf.c      |  21 +--
 drivers/net/enic/enic_ethdev.c    | 258 ++++++++++++++++++++++----
 drivers/net/enic/enic_main.c      | 373 ++++++++++++++++++++++++++++++--------
 drivers/net/enic/enic_res.c       |  23 ++-
 drivers/net/enic/enic_res.h       |   6 +
 drivers/net/enic/meson.build      |  19 ++
 drivers/net/meson.build           |   2 +-
 12 files changed, 686 insertions(+), 180 deletions(-)
 create mode 100644 drivers/net/enic/meson.build

-- 
2.16.2

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 01/10] net/enic: remove 'extern' in .h file function declarations
  2018-03-06  1:46   ` [PATCH v2 00/10] enic patchset John Daley
@ 2018-03-06  1:46     ` John Daley
  2018-03-08  2:46       ` [PATCH v3 00/10] enic PMD patchset John Daley
  2018-03-06  1:46     ` [PATCH v2 02/10] net/enic: allow the user to change RSS settings John Daley
                       ` (8 subsequent siblings)
  9 siblings, 1 reply; 44+ messages in thread
From: John Daley @ 2018-03-06  1:46 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, John Daley

Signed-off-by: John Daley <johndale@cisco.com>
Reviewed-by: Hyong Youb Kim <hyonkim@cisco.com>
---
 drivers/net/enic/enic.h | 80 ++++++++++++++++++++++++-------------------------
 1 file changed, 40 insertions(+), 40 deletions(-)

diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index c083985ee..e88af6bc9 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -220,54 +220,54 @@ enic_ring_incr(uint32_t n_descriptors, uint32_t idx)
 	return idx;
 }
 
-extern void enic_fdir_stats_get(struct enic *enic,
-	struct rte_eth_fdir_stats *stats);
-extern int enic_fdir_add_fltr(struct enic *enic,
-	struct rte_eth_fdir_filter *params);
-extern int enic_fdir_del_fltr(struct enic *enic,
-	struct rte_eth_fdir_filter *params);
-extern void enic_free_wq(void *txq);
-extern int enic_alloc_intr_resources(struct enic *enic);
-extern int enic_setup_finish(struct enic *enic);
-extern int enic_alloc_wq(struct enic *enic, uint16_t queue_idx,
-	unsigned int socket_id, uint16_t nb_desc);
-extern void enic_start_wq(struct enic *enic, uint16_t queue_idx);
-extern int enic_stop_wq(struct enic *enic, uint16_t queue_idx);
-extern void enic_start_rq(struct enic *enic, uint16_t queue_idx);
-extern int enic_stop_rq(struct enic *enic, uint16_t queue_idx);
-extern void enic_free_rq(void *rxq);
-extern int enic_alloc_rq(struct enic *enic, uint16_t queue_idx,
-	unsigned int socket_id, struct rte_mempool *mp,
-	uint16_t nb_desc, uint16_t free_thresh);
-extern int enic_set_rss_nic_cfg(struct enic *enic);
-extern int enic_set_vnic_res(struct enic *enic);
-extern int enic_enable(struct enic *enic);
-extern int enic_disable(struct enic *enic);
-extern void enic_remove(struct enic *enic);
-extern int enic_get_link_status(struct enic *enic);
-extern int enic_dev_stats_get(struct enic *enic,
-	struct rte_eth_stats *r_stats);
-extern void enic_dev_stats_clear(struct enic *enic);
-extern void enic_add_packet_filter(struct enic *enic);
+void enic_fdir_stats_get(struct enic *enic,
+			 struct rte_eth_fdir_stats *stats);
+int enic_fdir_add_fltr(struct enic *enic,
+		       struct rte_eth_fdir_filter *params);
+int enic_fdir_del_fltr(struct enic *enic,
+		       struct rte_eth_fdir_filter *params);
+void enic_free_wq(void *txq);
+int enic_alloc_intr_resources(struct enic *enic);
+int enic_setup_finish(struct enic *enic);
+int enic_alloc_wq(struct enic *enic, uint16_t queue_idx,
+		  unsigned int socket_id, uint16_t nb_desc);
+void enic_start_wq(struct enic *enic, uint16_t queue_idx);
+int enic_stop_wq(struct enic *enic, uint16_t queue_idx);
+void enic_start_rq(struct enic *enic, uint16_t queue_idx);
+int enic_stop_rq(struct enic *enic, uint16_t queue_idx);
+void enic_free_rq(void *rxq);
+int enic_alloc_rq(struct enic *enic, uint16_t queue_idx,
+		  unsigned int socket_id, struct rte_mempool *mp,
+		  uint16_t nb_desc, uint16_t free_thresh);
+int enic_set_rss_nic_cfg(struct enic *enic);
+int enic_set_vnic_res(struct enic *enic);
+int enic_enable(struct enic *enic);
+int enic_disable(struct enic *enic);
+void enic_remove(struct enic *enic);
+int enic_get_link_status(struct enic *enic);
+int enic_dev_stats_get(struct enic *enic,
+		       struct rte_eth_stats *r_stats);
+void enic_dev_stats_clear(struct enic *enic);
+void enic_add_packet_filter(struct enic *enic);
 int enic_set_mac_address(struct enic *enic, uint8_t *mac_addr);
 void enic_del_mac_address(struct enic *enic, int mac_index);
-extern unsigned int enic_cleanup_wq(struct enic *enic, struct vnic_wq *wq);
-extern void enic_send_pkt(struct enic *enic, struct vnic_wq *wq,
-			  struct rte_mbuf *tx_pkt, unsigned short len,
-			  uint8_t sop, uint8_t eop, uint8_t cq_entry,
-			  uint16_t ol_flags, uint16_t vlan_tag);
-
-extern void enic_post_wq_index(struct vnic_wq *wq);
-extern int enic_probe(struct enic *enic);
-extern int enic_clsf_init(struct enic *enic);
-extern void enic_clsf_destroy(struct enic *enic);
+unsigned int enic_cleanup_wq(struct enic *enic, struct vnic_wq *wq);
+void enic_send_pkt(struct enic *enic, struct vnic_wq *wq,
+		   struct rte_mbuf *tx_pkt, unsigned short len,
+		   uint8_t sop, uint8_t eop, uint8_t cq_entry,
+		   uint16_t ol_flags, uint16_t vlan_tag);
+
+void enic_post_wq_index(struct vnic_wq *wq);
+int enic_probe(struct enic *enic);
+int enic_clsf_init(struct enic *enic);
+void enic_clsf_destroy(struct enic *enic);
 uint16_t enic_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
 			uint16_t nb_pkts);
 uint16_t enic_dummy_recv_pkts(void *rx_queue,
 			      struct rte_mbuf **rx_pkts,
 			      uint16_t nb_pkts);
 uint16_t enic_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
-			       uint16_t nb_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);
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 02/10] net/enic: allow the user to change RSS settings
  2018-03-06  1:46   ` [PATCH v2 00/10] enic patchset John Daley
  2018-03-06  1:46     ` [PATCH v2 01/10] net/enic: remove 'extern' in .h file function declarations John Daley
@ 2018-03-06  1:46     ` John Daley
  2018-03-06  1:46     ` [PATCH v2 03/10] net/enic: heed the requested max Rx packet size John Daley
                       ` (7 subsequent siblings)
  9 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-03-06  1:46 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

Currently, when more than 1 receive queues are configured, the driver
always enables RSS with the driver's own default hash type, key, and
RETA. The user is unable to change any of the RSS settings. Address
this by implementing the ethdev RSS API as follows.

Correctly report the RETA size, key size, and supported hash types
through rte_eth_dev_info.

During dev_configure(), initialize RSS according to the device's
mq_mode and rss_conf. Start with the default RETA, and use the default
key unless a custom key is provided.

Add the RETA and rss_conf query/set handlers to let the user change
RSS settings after the initial configuration. The hardware is able to
change hash type, key, and RETA individually. So, the handlers change
only the affected settings.

Refactor/rename several functions in order to make their intentions
clear. For example, remove all traces of RSS from
enicpmd_vlan_offload_set() as it is confusing.

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 doc/guides/nics/features/enic.ini |   2 +
 drivers/net/enic/enic.h           |  20 +++-
 drivers/net/enic/enic_ethdev.c    | 117 ++++++++++++++++++++++-
 drivers/net/enic/enic_main.c      | 192 ++++++++++++++++++++++++++++----------
 drivers/net/enic/enic_res.c       |  20 ++++
 drivers/net/enic/enic_res.h       |   6 ++
 6 files changed, 301 insertions(+), 56 deletions(-)

diff --git a/doc/guides/nics/features/enic.ini b/doc/guides/nics/features/enic.ini
index 498341f07..e79d7277d 100644
--- a/doc/guides/nics/features/enic.ini
+++ b/doc/guides/nics/features/enic.ini
@@ -15,6 +15,8 @@ Promiscuous mode     = Y
 Unicast MAC filter   = Y
 Multicast MAC filter = Y
 RSS hash             = Y
+RSS key update       = Y
+RSS reta update      = Y
 SR-IOV               = Y
 VLAN filter          = Y
 CRC offload          = Y
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index e88af6bc9..d29939c94 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -146,6 +146,20 @@ struct enic {
 
 	LIST_HEAD(enic_flows, rte_flow) flows;
 	rte_spinlock_t flows_lock;
+
+	/* RSS */
+	uint16_t reta_size;
+	uint8_t hash_key_size;
+	uint64_t flow_type_rss_offloads; /* 0 indicates RSS not supported */
+	/*
+	 * Keep a copy of current RSS config for queries, as we cannot retrieve
+	 * it from the NIC.
+	 */
+	uint8_t rss_hash_type; /* NIC_CFG_RSS_HASH_TYPE flags */
+	uint8_t rss_enable;
+	uint64_t rss_hf; /* ETH_RSS flags */
+	union vnic_rss_key rss_key;
+	union vnic_rss_cpu rss_cpu;
 };
 
 /* Get the CQ index from a Start of Packet(SOP) RQ index */
@@ -239,8 +253,12 @@ void enic_free_rq(void *rxq);
 int enic_alloc_rq(struct enic *enic, uint16_t queue_idx,
 		  unsigned int socket_id, struct rte_mempool *mp,
 		  uint16_t nb_desc, uint16_t free_thresh);
-int enic_set_rss_nic_cfg(struct enic *enic);
 int enic_set_vnic_res(struct enic *enic);
+int enic_init_rss_nic_cfg(struct enic *enic);
+int enic_set_rss_conf(struct enic *enic,
+		      struct rte_eth_rss_conf *rss_conf);
+int enic_set_rss_reta(struct enic *enic, union vnic_rss_cpu *rss_cpu);
+int enic_set_vlan_strip(struct enic *enic);
 int enic_enable(struct enic *enic);
 int enic_disable(struct enic *enic);
 void enic_remove(struct enic *enic);
diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
index d84714efb..cbab7029b 100644
--- a/drivers/net/enic/enic_ethdev.c
+++ b/drivers/net/enic/enic_ethdev.c
@@ -345,8 +345,6 @@ static int enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 		else
 			enic->ig_vlan_strip_en = 0;
 	}
-	enic_set_rss_nic_cfg(enic);
-
 
 	if (mask & ETH_VLAN_FILTER_MASK) {
 		dev_warning(enic,
@@ -358,7 +356,7 @@ static int enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 			"Configuration of extended VLAN is not supported\n");
 	}
 
-	return 0;
+	return enic_set_vlan_strip(enic);
 }
 
 static int enicpmd_dev_configure(struct rte_eth_dev *eth_dev)
@@ -379,8 +377,16 @@ static int enicpmd_dev_configure(struct rte_eth_dev *eth_dev)
 	enic->hw_ip_checksum = !!(eth_dev->data->dev_conf.rxmode.offloads &
 				  DEV_RX_OFFLOAD_CHECKSUM);
 	ret = enicpmd_vlan_offload_set(eth_dev, ETH_VLAN_STRIP_MASK);
-
-	return ret;
+	if (ret) {
+		dev_err(enic, "Failed to configure VLAN offloads\n");
+		return ret;
+	}
+	/*
+	 * Initialize RSS with the default reta and key. If the user key is
+	 * given (rx_adv_conf.rss_conf.rss_key), will use that instead of the
+	 * default key.
+	 */
+	return enic_init_rss_nic_cfg(enic);
 }
 
 /* Start the device.
@@ -480,6 +486,9 @@ static void enicpmd_dev_info_get(struct rte_eth_dev *eth_dev,
 	device_info->default_rxconf = (struct rte_eth_rxconf) {
 		.rx_free_thresh = ENIC_DEFAULT_RX_FREE_THRESH
 	};
+	device_info->reta_size = enic->reta_size;
+	device_info->hash_key_size = enic->hash_key_size;
+	device_info->flow_type_rss_offloads = enic->flow_type_rss_offloads;
 }
 
 static const uint32_t *enicpmd_dev_supported_ptypes_get(struct rte_eth_dev *dev)
@@ -582,6 +591,100 @@ static int enicpmd_mtu_set(struct rte_eth_dev *eth_dev, uint16_t mtu)
 	return enic_set_mtu(enic, mtu);
 }
 
+static int enicpmd_dev_rss_reta_query(struct rte_eth_dev *dev,
+				      struct rte_eth_rss_reta_entry64
+				      *reta_conf,
+				      uint16_t reta_size)
+{
+	struct enic *enic = pmd_priv(dev);
+	uint16_t i, idx, shift;
+
+	ENICPMD_FUNC_TRACE();
+	if (reta_size != ENIC_RSS_RETA_SIZE) {
+		dev_err(enic, "reta_query: wrong reta_size. given=%u expected=%u\n",
+			reta_size, ENIC_RSS_RETA_SIZE);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < reta_size; i++) {
+		idx = i / RTE_RETA_GROUP_SIZE;
+		shift = i % RTE_RETA_GROUP_SIZE;
+		if (reta_conf[idx].mask & (1ULL << shift))
+			reta_conf[idx].reta[shift] = enic_sop_rq_idx_to_rte_idx(
+				enic->rss_cpu.cpu[i / 4].b[i % 4]);
+	}
+
+	return 0;
+}
+
+static int enicpmd_dev_rss_reta_update(struct rte_eth_dev *dev,
+				       struct rte_eth_rss_reta_entry64
+				       *reta_conf,
+				       uint16_t reta_size)
+{
+	struct enic *enic = pmd_priv(dev);
+	union vnic_rss_cpu rss_cpu;
+	uint16_t i, idx, shift;
+
+	ENICPMD_FUNC_TRACE();
+	if (reta_size != ENIC_RSS_RETA_SIZE) {
+		dev_err(enic, "reta_update: wrong reta_size. given=%u"
+			" expected=%u\n",
+			reta_size, ENIC_RSS_RETA_SIZE);
+		return -EINVAL;
+	}
+	/*
+	 * Start with the current reta and modify it per reta_conf, as we
+	 * need to push the entire reta even if we only modify one entry.
+	 */
+	rss_cpu = enic->rss_cpu;
+	for (i = 0; i < reta_size; i++) {
+		idx = i / RTE_RETA_GROUP_SIZE;
+		shift = i % RTE_RETA_GROUP_SIZE;
+		if (reta_conf[idx].mask & (1ULL << shift))
+			rss_cpu.cpu[i / 4].b[i % 4] =
+				enic_rte_rq_idx_to_sop_idx(
+					reta_conf[idx].reta[shift]);
+	}
+	return enic_set_rss_reta(enic, &rss_cpu);
+}
+
+static int enicpmd_dev_rss_hash_update(struct rte_eth_dev *dev,
+				       struct rte_eth_rss_conf *rss_conf)
+{
+	struct enic *enic = pmd_priv(dev);
+
+	ENICPMD_FUNC_TRACE();
+	return enic_set_rss_conf(enic, rss_conf);
+}
+
+static int enicpmd_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
+					 struct rte_eth_rss_conf *rss_conf)
+{
+	struct enic *enic = pmd_priv(dev);
+
+	ENICPMD_FUNC_TRACE();
+	if (rss_conf == NULL)
+		return -EINVAL;
+	if (rss_conf->rss_key != NULL &&
+	    rss_conf->rss_key_len < ENIC_RSS_HASH_KEY_SIZE) {
+		dev_err(enic, "rss_hash_conf_get: wrong rss_key_len. given=%u"
+			" expected=%u+\n",
+			rss_conf->rss_key_len, ENIC_RSS_HASH_KEY_SIZE);
+		return -EINVAL;
+	}
+	rss_conf->rss_hf = enic->rss_hf;
+	if (rss_conf->rss_key != NULL) {
+		int i;
+		for (i = 0; i < ENIC_RSS_HASH_KEY_SIZE; i++) {
+			rss_conf->rss_key[i] =
+				enic->rss_key.key[i / 10].b[i % 10];
+		}
+		rss_conf->rss_key_len = ENIC_RSS_HASH_KEY_SIZE;
+	}
+	return 0;
+}
+
 static const struct eth_dev_ops enicpmd_eth_dev_ops = {
 	.dev_configure        = enicpmd_dev_configure,
 	.dev_start            = enicpmd_dev_start,
@@ -622,6 +725,10 @@ static const struct eth_dev_ops enicpmd_eth_dev_ops = {
 	.mac_addr_add         = enicpmd_add_mac_addr,
 	.mac_addr_remove      = enicpmd_remove_mac_addr,
 	.filter_ctrl          = enicpmd_dev_filter_ctrl,
+	.reta_query           = enicpmd_dev_rss_reta_query,
+	.reta_update          = enicpmd_dev_rss_reta_update,
+	.rss_hash_conf_get    = enicpmd_dev_rss_hash_conf_get,
+	.rss_hash_update      = enicpmd_dev_rss_hash_update,
 };
 
 struct enic *enicpmd_list_head = NULL;
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index ec9d343fd..f00e816a1 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -889,44 +889,42 @@ static int enic_dev_open(struct enic *enic)
 	return err;
 }
 
-static int enic_set_rsskey(struct enic *enic)
+static int enic_set_rsskey(struct enic *enic, uint8_t *user_key)
 {
 	dma_addr_t rss_key_buf_pa;
 	union vnic_rss_key *rss_key_buf_va = NULL;
-	static union vnic_rss_key rss_key = {
-		.key = {
-			[0] = {.b = {85, 67, 83, 97, 119, 101, 115, 111, 109, 101}},
-			[1] = {.b = {80, 65, 76, 79, 117, 110, 105, 113, 117, 101}},
-			[2] = {.b = {76, 73, 78, 85, 88, 114, 111, 99, 107, 115}},
-			[3] = {.b = {69, 78, 73, 67, 105, 115, 99, 111, 111, 108}},
-		}
-	};
-	int err;
+	int err, i;
 	u8 name[NAME_MAX];
 
+	RTE_ASSERT(use_key != NULL);
 	snprintf((char *)name, NAME_MAX, "rss_key-%s", enic->bdf_name);
 	rss_key_buf_va = enic_alloc_consistent(enic, sizeof(union vnic_rss_key),
 		&rss_key_buf_pa, name);
 	if (!rss_key_buf_va)
 		return -ENOMEM;
 
-	rte_memcpy(rss_key_buf_va, &rss_key, sizeof(union vnic_rss_key));
+	for (i = 0; i < ENIC_RSS_HASH_KEY_SIZE; i++)
+		rss_key_buf_va->key[i / 10].b[i % 10] = user_key[i];
 
 	err = enic_set_rss_key(enic,
 		rss_key_buf_pa,
 		sizeof(union vnic_rss_key));
 
+	/* Save for later queries */
+	if (!err) {
+		rte_memcpy(&enic->rss_key, rss_key_buf_va,
+			   sizeof(union vnic_rss_key));
+	}
 	enic_free_consistent(enic, sizeof(union vnic_rss_key),
 		rss_key_buf_va, rss_key_buf_pa);
 
 	return err;
 }
 
-static int enic_set_rsscpu(struct enic *enic, u8 rss_hash_bits)
+int enic_set_rss_reta(struct enic *enic, union vnic_rss_cpu *rss_cpu)
 {
 	dma_addr_t rss_cpu_buf_pa;
 	union vnic_rss_cpu *rss_cpu_buf_va = NULL;
-	int i;
 	int err;
 	u8 name[NAME_MAX];
 
@@ -936,9 +934,7 @@ static int enic_set_rsscpu(struct enic *enic, u8 rss_hash_bits)
 	if (!rss_cpu_buf_va)
 		return -ENOMEM;
 
-	for (i = 0; i < (1 << rss_hash_bits); i++)
-		(*rss_cpu_buf_va).cpu[i / 4].b[i % 4] =
-			enic_rte_rq_idx_to_sop_idx(i % enic->rq_count);
+	rte_memcpy(rss_cpu_buf_va, rss_cpu, sizeof(union vnic_rss_cpu));
 
 	err = enic_set_rss_cpu(enic,
 		rss_cpu_buf_pa,
@@ -947,6 +943,9 @@ static int enic_set_rsscpu(struct enic *enic, u8 rss_hash_bits)
 	enic_free_consistent(enic, sizeof(union vnic_rss_cpu),
 		rss_cpu_buf_va, rss_cpu_buf_pa);
 
+	/* Save for later queries */
+	if (!err)
+		rte_memcpy(&enic->rss_cpu, rss_cpu, sizeof(union vnic_rss_cpu));
 	return err;
 }
 
@@ -956,8 +955,6 @@ static int enic_set_niccfg(struct enic *enic, u8 rss_default_cpu,
 	const u8 tso_ipid_split_en = 0;
 	int err;
 
-	/* Enable VLAN tag stripping */
-
 	err = enic_set_nic_cfg(enic,
 		rss_default_cpu, rss_hash_type,
 		rss_hash_bits, rss_base_cpu,
@@ -967,47 +964,50 @@ static int enic_set_niccfg(struct enic *enic, u8 rss_default_cpu,
 	return err;
 }
 
-int enic_set_rss_nic_cfg(struct enic *enic)
+/* Initialize RSS with defaults, called from dev_configure */
+int enic_init_rss_nic_cfg(struct enic *enic)
 {
-	const u8 rss_default_cpu = 0;
-	const u8 rss_hash_type = NIC_CFG_RSS_HASH_TYPE_IPV4 |
-	    NIC_CFG_RSS_HASH_TYPE_TCP_IPV4 |
-	    NIC_CFG_RSS_HASH_TYPE_IPV6 |
-	    NIC_CFG_RSS_HASH_TYPE_TCP_IPV6;
-	const u8 rss_hash_bits = 7;
-	const u8 rss_base_cpu = 0;
-	u8 rss_enable = ENIC_SETTING(enic, RSS) && (enic->rq_count > 1);
-
-	if (rss_enable) {
-		if (!enic_set_rsskey(enic)) {
-			if (enic_set_rsscpu(enic, rss_hash_bits)) {
-				rss_enable = 0;
-				dev_warning(enic, "RSS disabled, "\
-					"Failed to set RSS cpu indirection table.");
-			}
-		} else {
-			rss_enable = 0;
-			dev_warning(enic,
-				"RSS disabled, Failed to set RSS key.\n");
+	static uint8_t default_rss_key[] = {
+		85, 67, 83, 97, 119, 101, 115, 111, 109, 101,
+		80, 65, 76, 79, 117, 110, 105, 113, 117, 101,
+		76, 73, 78, 85, 88, 114, 111, 99, 107, 115,
+		69, 78, 73, 67, 105, 115, 99, 111, 111, 108,
+	};
+	struct rte_eth_rss_conf rss_conf;
+	union vnic_rss_cpu rss_cpu;
+	int ret, i;
+
+	rss_conf = enic->rte_dev->data->dev_conf.rx_adv_conf.rss_conf;
+	/*
+	 * If setting key for the first time, and the user gives us none, then
+	 * push the default key to NIC.
+	 */
+	if (rss_conf.rss_key == NULL) {
+		rss_conf.rss_key = default_rss_key;
+		rss_conf.rss_key_len = ENIC_RSS_HASH_KEY_SIZE;
+	}
+	ret = enic_set_rss_conf(enic, &rss_conf);
+	if (ret) {
+		dev_err(enic, "Failed to configure RSS\n");
+		return ret;
+	}
+	if (enic->rss_enable) {
+		/* If enabling RSS, use the default reta */
+		for (i = 0; i < ENIC_RSS_RETA_SIZE; i++) {
+			rss_cpu.cpu[i / 4].b[i % 4] =
+				enic_rte_rq_idx_to_sop_idx(i % enic->rq_count);
 		}
+		ret = enic_set_rss_reta(enic, &rss_cpu);
+		if (ret)
+			dev_err(enic, "Failed to set RSS indirection table\n");
 	}
-
-	return enic_set_niccfg(enic, rss_default_cpu, rss_hash_type,
-		rss_hash_bits, rss_base_cpu, rss_enable);
+	return ret;
 }
 
 int enic_setup_finish(struct enic *enic)
 {
-	int ret;
-
 	enic_init_soft_stats(enic);
 
-	ret = enic_set_rss_nic_cfg(enic);
-	if (ret) {
-		dev_err(enic, "Failed to config nic, aborting.\n");
-		return -1;
-	}
-
 	/* Default conf */
 	vnic_dev_packet_filter(enic->vdev,
 		1 /* directed  */,
@@ -1022,6 +1022,98 @@ int enic_setup_finish(struct enic *enic)
 	return 0;
 }
 
+static int enic_rss_conf_valid(struct enic *enic,
+			       struct rte_eth_rss_conf *rss_conf)
+{
+	/* RSS is disabled per VIC settings. Ignore rss_conf. */
+	if (enic->flow_type_rss_offloads == 0)
+		return 0;
+	if (rss_conf->rss_key != NULL &&
+	    rss_conf->rss_key_len != ENIC_RSS_HASH_KEY_SIZE) {
+		dev_err(enic, "Given rss_key is %d bytes, it must be %d\n",
+			rss_conf->rss_key_len, ENIC_RSS_HASH_KEY_SIZE);
+		return -EINVAL;
+	}
+	if (rss_conf->rss_hf != 0 &&
+	    (rss_conf->rss_hf & enic->flow_type_rss_offloads) == 0) {
+		dev_err(enic, "Given rss_hf contains none of the supported"
+			" types\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* Set hash type and key according to rss_conf */
+int enic_set_rss_conf(struct enic *enic, struct rte_eth_rss_conf *rss_conf)
+{
+	struct rte_eth_dev *eth_dev;
+	uint64_t rss_hf;
+	u8 rss_hash_type;
+	u8 rss_enable;
+	int ret;
+
+	RTE_ASSERT(rss_conf != NULL);
+	ret = enic_rss_conf_valid(enic, rss_conf);
+	if (ret) {
+		dev_err(enic, "RSS configuration (rss_conf) is invalid\n");
+		return ret;
+	}
+
+	eth_dev = enic->rte_dev;
+	rss_hash_type = 0;
+	rss_hf = rss_conf->rss_hf & enic->flow_type_rss_offloads;
+	if (enic->rq_count > 1 &&
+	    (eth_dev->data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_RSS_FLAG) &&
+	    rss_hf != 0) {
+		rss_enable = 1;
+		if (rss_hf & ETH_RSS_IPV4)
+			rss_hash_type |= NIC_CFG_RSS_HASH_TYPE_IPV4;
+		if (rss_hf & ETH_RSS_NONFRAG_IPV4_TCP)
+			rss_hash_type |= NIC_CFG_RSS_HASH_TYPE_TCP_IPV4;
+		if (rss_hf & ETH_RSS_IPV6)
+			rss_hash_type |= NIC_CFG_RSS_HASH_TYPE_IPV6;
+		if (rss_hf & ETH_RSS_NONFRAG_IPV6_TCP)
+			rss_hash_type |= NIC_CFG_RSS_HASH_TYPE_TCP_IPV6;
+		if (rss_hf & ETH_RSS_IPV6_EX)
+			rss_hash_type |= NIC_CFG_RSS_HASH_TYPE_IPV6_EX;
+		if (rss_hf & ETH_RSS_IPV6_TCP_EX)
+			rss_hash_type |= NIC_CFG_RSS_HASH_TYPE_TCP_IPV6_EX;
+	} else {
+		rss_enable = 0;
+		rss_hf = 0;
+	}
+
+	/* Set the hash key if provided */
+	if (rss_enable && rss_conf->rss_key) {
+		ret = enic_set_rsskey(enic, rss_conf->rss_key);
+		if (ret) {
+			dev_err(enic, "Failed to set RSS key\n");
+			return ret;
+		}
+	}
+
+	ret = enic_set_niccfg(enic, ENIC_RSS_DEFAULT_CPU, rss_hash_type,
+			      ENIC_RSS_HASH_BITS, ENIC_RSS_BASE_CPU,
+			      rss_enable);
+	if (!ret) {
+		enic->rss_hf = rss_hf;
+		enic->rss_hash_type = rss_hash_type;
+		enic->rss_enable = rss_enable;
+	}
+	return 0;
+}
+
+int enic_set_vlan_strip(struct enic *enic)
+{
+	/*
+	 * Unfortunately, VLAN strip on/off and RSS on/off are configured
+	 * together. So, re-do niccfg, preserving the current RSS settings.
+	 */
+	return enic_set_niccfg(enic, ENIC_RSS_DEFAULT_CPU, enic->rss_hash_type,
+			       ENIC_RSS_HASH_BITS, ENIC_RSS_BASE_CPU,
+			       enic->rss_enable);
+}
+
 void enic_add_packet_filter(struct enic *enic)
 {
 	/* Args -> directed, multicast, broadcast, promisc, allmulti */
diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c
index c99d61837..d8f7892c3 100644
--- a/drivers/net/enic/enic_res.c
+++ b/drivers/net/enic/enic_res.c
@@ -128,6 +128,26 @@ int enic_get_vnic_config(struct enic *enic)
 		c->intr_timer_usec,
 		c->loop_tag);
 
+	/* RSS settings from vNIC */
+	enic->reta_size = ENIC_RSS_RETA_SIZE;
+	enic->hash_key_size = ENIC_RSS_HASH_KEY_SIZE;
+	enic->flow_type_rss_offloads = 0;
+	if (ENIC_SETTING(enic, RSSHASH_IPV4))
+		enic->flow_type_rss_offloads |= ETH_RSS_IPV4;
+	if (ENIC_SETTING(enic, RSSHASH_TCPIPV4))
+		enic->flow_type_rss_offloads |= ETH_RSS_NONFRAG_IPV4_TCP;
+	if (ENIC_SETTING(enic, RSSHASH_IPV6))
+		enic->flow_type_rss_offloads |= ETH_RSS_IPV6;
+	if (ENIC_SETTING(enic, RSSHASH_TCPIPV6))
+		enic->flow_type_rss_offloads |= ETH_RSS_NONFRAG_IPV6_TCP;
+	if (ENIC_SETTING(enic, RSSHASH_IPV6_EX))
+		enic->flow_type_rss_offloads |= ETH_RSS_IPV6_EX;
+	if (ENIC_SETTING(enic, RSSHASH_TCPIPV6_EX))
+		enic->flow_type_rss_offloads |= ETH_RSS_IPV6_TCP_EX;
+	/* Zero offloads if RSS is not enabled */
+	if (!ENIC_SETTING(enic, RSS))
+		enic->flow_type_rss_offloads = 0;
+
 	return 0;
 }
 
diff --git a/drivers/net/enic/enic_res.h b/drivers/net/enic/enic_res.h
index cf3a6fde8..e68f1307b 100644
--- a/drivers/net/enic/enic_res.h
+++ b/drivers/net/enic/enic_res.h
@@ -31,6 +31,12 @@
 #define ENIC_DEFAULT_RX_FREE_THRESH	32
 #define ENIC_TX_XMIT_MAX		64
 
+#define ENIC_RSS_DEFAULT_CPU    0
+#define ENIC_RSS_BASE_CPU       0
+#define ENIC_RSS_HASH_BITS      7
+#define ENIC_RSS_RETA_SIZE      (1 << ENIC_RSS_HASH_BITS)
+#define ENIC_RSS_HASH_KEY_SIZE  40
+
 #define ENIC_SETTING(enic, f) ((enic->config.flags & VENETF_##f) ? 1 : 0)
 
 
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 03/10] net/enic: heed the requested max Rx packet size
  2018-03-06  1:46   ` [PATCH v2 00/10] enic patchset John Daley
  2018-03-06  1:46     ` [PATCH v2 01/10] net/enic: remove 'extern' in .h file function declarations John Daley
  2018-03-06  1:46     ` [PATCH v2 02/10] net/enic: allow the user to change RSS settings John Daley
@ 2018-03-06  1:46     ` John Daley
  2018-03-06  1:46     ` [PATCH v2 04/10] net/enic: remove the VLAN filter handler John Daley
                       ` (6 subsequent siblings)
  9 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-03-06  1:46 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

Currently, enic completely ignores the requested max Rx packet size
(rxmode.max_rx_pkt_len). The desired behavior is that the NIC hardware
drops packets larger than the requested size, even though they are
still smaller than MTU.

Cisco VIC does not have such a feature. But, we can accomplish a
similar (not same) effect by reducing the size of posted receive
buffers. Packets larger than the posted size get truncated, and the
receive handler drops them. This is also how the kernel enic driver
enforces the Rx side MTU.

This workaround works only when scatter mode is *not* used. When
scatter is used, there is currently no way to support
rxmode.max_rx_pkt_len, as the NIC always receives packets up to MTU.

For posterity, add a copious amount of comments regarding the
hardware's drop/receive behavior with respect to max/current MTU.

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 doc/guides/nics/enic.rst       |  1 +
 drivers/net/enic/enic.h        |  7 ++++++
 drivers/net/enic/enic_ethdev.c |  9 +++++++-
 drivers/net/enic/enic_main.c   | 49 ++++++++++++++++++++++++++++++++++++------
 4 files changed, 58 insertions(+), 8 deletions(-)

diff --git a/doc/guides/nics/enic.rst b/doc/guides/nics/enic.rst
index 4dffce1a6..0e655e9e3 100644
--- a/doc/guides/nics/enic.rst
+++ b/doc/guides/nics/enic.rst
@@ -371,6 +371,7 @@ Known bugs and unsupported features in this release
 - Setting of extended VLAN
 - UDP RSS hashing
 - MTU update only works if Scattered Rx mode is disabled
+- Maximum receive packet length is ignored if Scattered Rx mode is used
 
 Prerequisites
 -------------
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index d29939c94..1b3813a58 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -162,6 +162,13 @@ struct enic {
 	union vnic_rss_cpu rss_cpu;
 };
 
+/* Compute ethdev's max packet size from MTU */
+static inline uint32_t enic_mtu_to_max_rx_pktlen(uint32_t mtu)
+{
+	/* ethdev max size includes eth and crc whereas NIC MTU does not */
+	return mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
+}
+
 /* Get the CQ index from a Start of Packet(SOP) RQ index */
 static inline unsigned int enic_sop_rq_idx_to_cq_idx(unsigned int sop_idx)
 {
diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
index cbab7029b..bdbaf4cdf 100644
--- a/drivers/net/enic/enic_ethdev.c
+++ b/drivers/net/enic/enic_ethdev.c
@@ -470,7 +470,14 @@ static void enicpmd_dev_info_get(struct rte_eth_dev *eth_dev,
 	device_info->max_rx_queues = enic->conf_rq_count / 2;
 	device_info->max_tx_queues = enic->conf_wq_count;
 	device_info->min_rx_bufsize = ENIC_MIN_MTU;
-	device_info->max_rx_pktlen = enic->max_mtu + ETHER_HDR_LEN + 4;
+	/* "Max" mtu is not a typo. HW receives packet sizes up to the
+	 * max mtu regardless of the current mtu (vNIC's mtu). vNIC mtu is
+	 * a hint to the driver to size receive buffers accordingly so that
+	 * larger-than-vnic-mtu packets get truncated.. For DPDK, we let
+	 * the user decide the buffer size via rxmode.max_rx_pkt_len, basically
+	 * ignoring vNIC mtu.
+	 */
+	device_info->max_rx_pktlen = enic_mtu_to_max_rx_pktlen(enic->max_mtu);
 	device_info->max_mac_addrs = ENIC_MAX_MAC_ADDR;
 	device_info->rx_offload_capa =
 		DEV_RX_OFFLOAD_VLAN_STRIP |
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index f00e816a1..d4f478b5e 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -266,6 +266,8 @@ enic_alloc_rx_queue_mbufs(struct enic *enic, struct vnic_rq *rq)
 	struct rq_enet_desc *rqd = rq->ring.descs;
 	unsigned i;
 	dma_addr_t dma_addr;
+	uint32_t max_rx_pkt_len;
+	uint16_t rq_buf_len;
 
 	if (!rq->in_use)
 		return 0;
@@ -273,6 +275,18 @@ enic_alloc_rx_queue_mbufs(struct enic *enic, struct vnic_rq *rq)
 	dev_debug(enic, "queue %u, allocating %u rx queue mbufs\n", rq->index,
 		  rq->ring.desc_count);
 
+	/*
+	 * If *not* using scatter and the mbuf size is smaller than the
+	 * requested max packet size (max_rx_pkt_len), then reduce the
+	 * posted buffer size to max_rx_pkt_len. HW still receives packets
+	 * larger than max_rx_pkt_len, but they will be truncated, which we
+	 * drop in the rx handler. Not ideal, but better than returning
+	 * large packets when the user is not expecting them.
+	 */
+	max_rx_pkt_len = enic->rte_dev->data->dev_conf.rxmode.max_rx_pkt_len;
+	rq_buf_len = rte_pktmbuf_data_room_size(rq->mp) - RTE_PKTMBUF_HEADROOM;
+	if (max_rx_pkt_len < rq_buf_len && !rq->data_queue_enable)
+		rq_buf_len = max_rx_pkt_len;
 	for (i = 0; i < rq->ring.desc_count; i++, rqd++) {
 		mb = rte_mbuf_raw_alloc(rq->mp);
 		if (mb == NULL) {
@@ -287,7 +301,7 @@ enic_alloc_rx_queue_mbufs(struct enic *enic, struct vnic_rq *rq)
 		rq_enet_desc_enc(rqd, dma_addr,
 				(rq->is_sop ? RQ_ENET_TYPE_ONLY_SOP
 				: RQ_ENET_TYPE_NOT_SOP),
-				mb->buf_len - RTE_PKTMBUF_HEADROOM);
+				rq_buf_len);
 		rq->mbuf_ring[i] = mb;
 	}
 
@@ -581,7 +595,7 @@ int enic_alloc_rq(struct enic *enic, uint16_t queue_idx,
 	unsigned int mbuf_size, mbufs_per_pkt;
 	unsigned int nb_sop_desc, nb_data_desc;
 	uint16_t min_sop, max_sop, min_data, max_data;
-	uint16_t mtu = enic->rte_dev->data->mtu;
+	uint32_t max_rx_pkt_len;
 
 	rq_sop->is_sop = 1;
 	rq_sop->data_queue_idx = data_queue_idx;
@@ -599,22 +613,42 @@ int enic_alloc_rq(struct enic *enic, uint16_t queue_idx,
 
 	mbuf_size = (uint16_t)(rte_pktmbuf_data_room_size(mp) -
 			       RTE_PKTMBUF_HEADROOM);
+	/* max_rx_pkt_len includes the ethernet header and CRC. */
+	max_rx_pkt_len = enic->rte_dev->data->dev_conf.rxmode.max_rx_pkt_len;
 
 	if (enic->rte_dev->data->dev_conf.rxmode.offloads &
 	    DEV_RX_OFFLOAD_SCATTER) {
 		dev_info(enic, "Rq %u Scatter rx mode enabled\n", queue_idx);
-		/* ceil((mtu + ETHER_HDR_LEN + 4)/mbuf_size) */
-		mbufs_per_pkt = ((mtu + ETHER_HDR_LEN + 4) +
-				 (mbuf_size - 1)) / mbuf_size;
+		/* ceil((max pkt len)/mbuf_size) */
+		mbufs_per_pkt = (max_rx_pkt_len + mbuf_size - 1) / mbuf_size;
 	} else {
 		dev_info(enic, "Scatter rx mode disabled\n");
 		mbufs_per_pkt = 1;
+		if (max_rx_pkt_len > mbuf_size) {
+			dev_warning(enic, "The maximum Rx packet size (%u) is"
+				    " larger than the mbuf size (%u), and"
+				    " scatter is disabled. Larger packets will"
+				    " be truncated.\n",
+				    max_rx_pkt_len, mbuf_size);
+		}
 	}
 
 	if (mbufs_per_pkt > 1) {
 		dev_info(enic, "Rq %u Scatter rx mode in use\n", queue_idx);
 		rq_sop->data_queue_enable = 1;
 		rq_data->in_use = 1;
+		/*
+		 * HW does not directly support rxmode.max_rx_pkt_len. HW always
+		 * receives packet sizes up to the "max" MTU.
+		 * If not using scatter, we can achieve the effect of dropping
+		 * larger packets by reducing the size of posted buffers.
+		 * See enic_alloc_rx_queue_mbufs().
+		 */
+		if (max_rx_pkt_len <
+		    enic_mtu_to_max_rx_pktlen(enic->rte_dev->data->mtu)) {
+			dev_warning(enic, "rxmode.max_rx_pkt_len is ignored"
+				    " when scatter rx mode is in use.\n");
+		}
 	} else {
 		dev_info(enic, "Rq %u Scatter rx mode not being used\n",
 			 queue_idx);
@@ -654,8 +688,9 @@ int enic_alloc_rq(struct enic *enic, uint16_t queue_idx,
 		nb_data_desc = max_data;
 	}
 	if (mbufs_per_pkt > 1) {
-		dev_info(enic, "For mtu %d and mbuf size %d valid rx descriptor range is %d to %d\n",
-			 mtu, mbuf_size, min_sop + min_data,
+		dev_info(enic, "For max packet size %u and mbuf size %u valid"
+			 " rx descriptor range is %u to %u\n",
+			 max_rx_pkt_len, mbuf_size, min_sop + min_data,
 			 max_sop + max_data);
 	}
 	dev_info(enic, "Using %d rx descriptors (sop %d, data %d)\n",
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 04/10] net/enic: remove the VLAN filter handler
  2018-03-06  1:46   ` [PATCH v2 00/10] enic patchset John Daley
                       ` (2 preceding siblings ...)
  2018-03-06  1:46     ` [PATCH v2 03/10] net/enic: heed the requested max Rx packet size John Daley
@ 2018-03-06  1:46     ` John Daley
  2018-03-06  1:46     ` [PATCH v2 05/10] net/enic: add Rx/Tx queue configuration getters John Daley
                       ` (5 subsequent siblings)
  9 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-03-06  1:46 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

VIC does not support VLAN filtering at the moment. The firmware does
accept the filter add/del commands and returns success. But, they are
no-ops. To avoid confusion, remove the filter set handler so the app
sees an error instead of silent failure.

Also during the device configure time, enicpmd_vlan_offload_set would
not print a warning message about unsupported VLAN filtering, because
the caller specifies only ETH_VLAN_STRIP_MASK. This is wrong, as we
should attempt to apply all requested offloads at the configure
time. So, pass all VLAN offload masks, which triggers a warning
message about VLAN filtering, if requested.

Finally, enicpmd_vlan_offload_set should check both mask and
rxmode.offloads, not just mask.

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 drivers/net/enic/enic_ethdev.c | 34 ++++++++++++++--------------------
 1 file changed, 14 insertions(+), 20 deletions(-)

diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
index bdbaf4cdf..e5523e311 100644
--- a/drivers/net/enic/enic_ethdev.c
+++ b/drivers/net/enic/enic_ethdev.c
@@ -318,40 +318,29 @@ static int enicpmd_dev_rx_queue_setup(struct rte_eth_dev *eth_dev,
 	return enicpmd_dev_setup_intr(enic);
 }
 
-static int enicpmd_vlan_filter_set(struct rte_eth_dev *eth_dev,
-	uint16_t vlan_id, int on)
-{
-	struct enic *enic = pmd_priv(eth_dev);
-	int err;
-
-	ENICPMD_FUNC_TRACE();
-	if (on)
-		err = enic_add_vlan(enic, vlan_id);
-	else
-		err = enic_del_vlan(enic, vlan_id);
-	return err;
-}
-
 static int enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 {
 	struct enic *enic = pmd_priv(eth_dev);
+	uint64_t offloads;
 
 	ENICPMD_FUNC_TRACE();
 
+	offloads = eth_dev->data->dev_conf.rxmode.offloads;
 	if (mask & ETH_VLAN_STRIP_MASK) {
-		if (eth_dev->data->dev_conf.rxmode.offloads &
-		    DEV_RX_OFFLOAD_VLAN_STRIP)
+		if (offloads & DEV_RX_OFFLOAD_VLAN_STRIP)
 			enic->ig_vlan_strip_en = 1;
 		else
 			enic->ig_vlan_strip_en = 0;
 	}
 
-	if (mask & ETH_VLAN_FILTER_MASK) {
+	if ((mask & ETH_VLAN_FILTER_MASK) &&
+	    (offloads & DEV_RX_OFFLOAD_VLAN_FILTER)) {
 		dev_warning(enic,
 			"Configuration of VLAN filter is not supported\n");
 	}
 
-	if (mask & ETH_VLAN_EXTEND_MASK) {
+	if ((mask & ETH_VLAN_EXTEND_MASK) &&
+	    (offloads & DEV_RX_OFFLOAD_VLAN_EXTEND)) {
 		dev_warning(enic,
 			"Configuration of extended VLAN is not supported\n");
 	}
@@ -362,6 +351,7 @@ static int enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 static int enicpmd_dev_configure(struct rte_eth_dev *eth_dev)
 {
 	int ret;
+	int mask;
 	struct enic *enic = pmd_priv(eth_dev);
 
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
@@ -376,7 +366,11 @@ static int enicpmd_dev_configure(struct rte_eth_dev *eth_dev)
 
 	enic->hw_ip_checksum = !!(eth_dev->data->dev_conf.rxmode.offloads &
 				  DEV_RX_OFFLOAD_CHECKSUM);
-	ret = enicpmd_vlan_offload_set(eth_dev, ETH_VLAN_STRIP_MASK);
+	/* All vlan offload masks to apply the current settings */
+	mask = ETH_VLAN_STRIP_MASK |
+		ETH_VLAN_FILTER_MASK |
+		ETH_VLAN_EXTEND_MASK;
+	ret = enicpmd_vlan_offload_set(eth_dev, mask);
 	if (ret) {
 		dev_err(enic, "Failed to configure VLAN offloads\n");
 		return ret;
@@ -710,7 +704,7 @@ static const struct eth_dev_ops enicpmd_eth_dev_ops = {
 	.dev_infos_get        = enicpmd_dev_info_get,
 	.dev_supported_ptypes_get = enicpmd_dev_supported_ptypes_get,
 	.mtu_set              = enicpmd_mtu_set,
-	.vlan_filter_set      = enicpmd_vlan_filter_set,
+	.vlan_filter_set      = NULL,
 	.vlan_tpid_set        = NULL,
 	.vlan_offload_set     = enicpmd_vlan_offload_set,
 	.vlan_strip_queue_set = NULL,
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 05/10] net/enic: add Rx/Tx queue configuration getters
  2018-03-06  1:46   ` [PATCH v2 00/10] enic patchset John Daley
                       ` (3 preceding siblings ...)
  2018-03-06  1:46     ` [PATCH v2 04/10] net/enic: remove the VLAN filter handler John Daley
@ 2018-03-06  1:46     ` John Daley
  2018-03-06  1:46     ` [PATCH v2 06/10] net/enic: allocate stats DMA buffer upfront during probe John Daley
                       ` (4 subsequent siblings)
  9 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-03-06  1:46 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 drivers/net/enic/enic_ethdev.c | 76 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 65 insertions(+), 11 deletions(-)

diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
index e5523e311..6dd72729e 100644
--- a/drivers/net/enic/enic_ethdev.c
+++ b/drivers/net/enic/enic_ethdev.c
@@ -39,6 +39,19 @@ static const struct rte_pci_id pci_id_enic_map[] = {
 	{.vendor_id = 0, /* sentinel */},
 };
 
+#define ENIC_TX_OFFLOAD_CAPA (			\
+		DEV_TX_OFFLOAD_VLAN_INSERT |	\
+		DEV_TX_OFFLOAD_IPV4_CKSUM  |	\
+		DEV_TX_OFFLOAD_UDP_CKSUM   |	\
+		DEV_TX_OFFLOAD_TCP_CKSUM   |	\
+		DEV_TX_OFFLOAD_TCP_TSO)
+
+#define ENIC_RX_OFFLOAD_CAPA (			\
+		DEV_RX_OFFLOAD_VLAN_STRIP |	\
+		DEV_RX_OFFLOAD_IPV4_CKSUM |	\
+		DEV_RX_OFFLOAD_UDP_CKSUM  |	\
+		DEV_RX_OFFLOAD_TCP_CKSUM)
+
 RTE_INIT(enicpmd_init_log);
 static void
 enicpmd_init_log(void)
@@ -473,17 +486,8 @@ static void enicpmd_dev_info_get(struct rte_eth_dev *eth_dev,
 	 */
 	device_info->max_rx_pktlen = enic_mtu_to_max_rx_pktlen(enic->max_mtu);
 	device_info->max_mac_addrs = ENIC_MAX_MAC_ADDR;
-	device_info->rx_offload_capa =
-		DEV_RX_OFFLOAD_VLAN_STRIP |
-		DEV_RX_OFFLOAD_IPV4_CKSUM |
-		DEV_RX_OFFLOAD_UDP_CKSUM  |
-		DEV_RX_OFFLOAD_TCP_CKSUM;
-	device_info->tx_offload_capa =
-		DEV_TX_OFFLOAD_VLAN_INSERT |
-		DEV_TX_OFFLOAD_IPV4_CKSUM  |
-		DEV_TX_OFFLOAD_UDP_CKSUM   |
-		DEV_TX_OFFLOAD_TCP_CKSUM   |
-		DEV_TX_OFFLOAD_TCP_TSO;
+	device_info->rx_offload_capa = ENIC_RX_OFFLOAD_CAPA;
+	device_info->tx_offload_capa = ENIC_TX_OFFLOAD_CAPA;
 	device_info->default_rxconf = (struct rte_eth_rxconf) {
 		.rx_free_thresh = ENIC_DEFAULT_RX_FREE_THRESH
 	};
@@ -686,6 +690,54 @@ static int enicpmd_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
 	return 0;
 }
 
+static void enicpmd_dev_rxq_info_get(struct rte_eth_dev *dev,
+				     uint16_t rx_queue_id,
+				     struct rte_eth_rxq_info *qinfo)
+{
+	struct enic *enic = pmd_priv(dev);
+	struct vnic_rq *rq_sop;
+	struct vnic_rq *rq_data;
+	struct rte_eth_rxconf *conf;
+	uint16_t sop_queue_idx;
+	uint16_t data_queue_idx;
+
+	ENICPMD_FUNC_TRACE();
+	sop_queue_idx = enic_rte_rq_idx_to_sop_idx(rx_queue_id);
+	data_queue_idx = enic_rte_rq_idx_to_data_idx(rx_queue_id);
+	rq_sop = &enic->rq[sop_queue_idx];
+	rq_data = &enic->rq[data_queue_idx]; /* valid if data_queue_enable */
+	qinfo->mp = rq_sop->mp;
+	qinfo->scattered_rx = rq_sop->data_queue_enable;
+	qinfo->nb_desc = rq_sop->ring.desc_count;
+	if (qinfo->scattered_rx)
+		qinfo->nb_desc += rq_data->ring.desc_count;
+	conf = &qinfo->conf;
+	memset(conf, 0, sizeof(*conf));
+	conf->rx_free_thresh = rq_sop->rx_free_thresh;
+	conf->rx_drop_en = 1;
+	/*
+	 * Except VLAN stripping (port setting), all the checksum offloads
+	 * are always enabled.
+	 */
+	conf->offloads = ENIC_RX_OFFLOAD_CAPA;
+	if (!enic->ig_vlan_strip_en)
+		conf->offloads &= ~DEV_RX_OFFLOAD_VLAN_STRIP;
+	/* rx_thresh and other fields are not applicable for enic */
+}
+
+static void enicpmd_dev_txq_info_get(struct rte_eth_dev *dev,
+				     __rte_unused uint16_t tx_queue_id,
+				     struct rte_eth_txq_info *qinfo)
+{
+	struct enic *enic = pmd_priv(dev);
+
+	ENICPMD_FUNC_TRACE();
+	qinfo->nb_desc = enic->config.wq_desc_count;
+	memset(&qinfo->conf, 0, sizeof(qinfo->conf));
+	qinfo->conf.offloads = ENIC_TX_OFFLOAD_CAPA; /* not configurable */
+	/* tx_thresh, and all the other fields are not applicable for enic */
+}
+
 static const struct eth_dev_ops enicpmd_eth_dev_ops = {
 	.dev_configure        = enicpmd_dev_configure,
 	.dev_start            = enicpmd_dev_start,
@@ -718,6 +770,8 @@ static const struct eth_dev_ops enicpmd_eth_dev_ops = {
 	.rx_descriptor_done   = NULL,
 	.tx_queue_setup       = enicpmd_dev_tx_queue_setup,
 	.tx_queue_release     = enicpmd_dev_tx_queue_release,
+	.rxq_info_get         = enicpmd_dev_rxq_info_get,
+	.txq_info_get         = enicpmd_dev_txq_info_get,
 	.dev_led_on           = NULL,
 	.dev_led_off          = NULL,
 	.flow_ctrl_get        = NULL,
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 06/10] net/enic: allocate stats DMA buffer upfront during probe
  2018-03-06  1:46   ` [PATCH v2 00/10] enic patchset John Daley
                       ` (4 preceding siblings ...)
  2018-03-06  1:46     ` [PATCH v2 05/10] net/enic: add Rx/Tx queue configuration getters John Daley
@ 2018-03-06  1:46     ` John Daley
  2018-03-06  1:46     ` [PATCH v2 07/10] net/enic: support Rx queue interrupts John Daley
                       ` (3 subsequent siblings)
  9 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-03-06  1:46 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim, stable

From: Hyong Youb Kim <hyonkim@cisco.com>

The driver provides a DMA buffer to the firmware when it requests port
stats. The NIC then fills that buffer with latest stats. Currently,
the driver allocates the DMA buffer the first time it requests stats
and saves it for later use. This can lead to crashes when
primary/secondary processes are involved. For example, the following
sequence crashes the secondary process.

1. Start a primary app that does not call rte_eth_stats_get()
2. dpdk-procinfo -- --stats

dpdk-procinfo crashes while trying to allocate the stats DMA buffer
because the alloc function pointer (vdev.alloc_consistent) is valid
only in the primary process, not in the secondary process.

Overwriting the alloc function pointer in the secondary process is not
an option, as it will simply make the pointer invalid in the primary
process. Instead, allocate the DMA buffer during probe so that only
the primary process does both allocate and free. This allows the
secondary process to dump stats as well.

Cc: stable@dpdk.org
Fixes: 9913fbb91df0 ("enic/base: common code")

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 drivers/net/enic/base/vnic_dev.c | 24 ++++++++++++++----------
 drivers/net/enic/base/vnic_dev.h |  1 +
 drivers/net/enic/enic_main.c     |  9 +++++++++
 3 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/drivers/net/enic/base/vnic_dev.c b/drivers/net/enic/base/vnic_dev.c
index 05b595eb8..1f8d222fc 100644
--- a/drivers/net/enic/base/vnic_dev.c
+++ b/drivers/net/enic/base/vnic_dev.c
@@ -587,17 +587,9 @@ int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats)
 {
 	u64 a0, a1;
 	int wait = 1000;
-	static u32 instance;
-	char name[NAME_MAX];
 
-	if (!vdev->stats) {
-		snprintf((char *)name, sizeof(name),
-			"vnic_stats-%u", instance++);
-		vdev->stats = vdev->alloc_consistent(vdev->priv,
-			sizeof(struct vnic_stats), &vdev->stats_pa, (u8 *)name);
-		if (!vdev->stats)
-			return -ENOMEM;
-	}
+	if (!vdev->stats)
+		return -ENOMEM;
 
 	*stats = vdev->stats;
 	a0 = vdev->stats_pa;
@@ -922,6 +914,18 @@ u32 vnic_dev_get_intr_coal_timer_max(struct vnic_dev *vdev)
 	return vdev->intr_coal_timer_info.max_usec;
 }
 
+int vnic_dev_alloc_stats_mem(struct vnic_dev *vdev)
+{
+	char name[NAME_MAX];
+	static u32 instance;
+
+	snprintf((char *)name, sizeof(name), "vnic_stats-%u", instance++);
+	vdev->stats = vdev->alloc_consistent(vdev->priv,
+					     sizeof(struct vnic_stats),
+					     &vdev->stats_pa, (u8 *)name);
+	return vdev->stats == NULL ? -ENOMEM : 0;
+}
+
 void vnic_dev_unregister(struct vnic_dev *vdev)
 {
 	if (vdev) {
diff --git a/drivers/net/enic/base/vnic_dev.h b/drivers/net/enic/base/vnic_dev.h
index 8c0992063..7e5736b4d 100644
--- a/drivers/net/enic/base/vnic_dev.h
+++ b/drivers/net/enic/base/vnic_dev.h
@@ -165,6 +165,7 @@ struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
 	void *priv, struct rte_pci_device *pdev, struct vnic_dev_bar *bar,
 	unsigned int num_bars);
 struct rte_pci_device *vnic_dev_get_pdev(struct vnic_dev *vdev);
+int vnic_dev_alloc_stats_mem(struct vnic_dev *vdev);
 int vnic_dev_cmd_init(struct vnic_dev *vdev, int fallback);
 int vnic_dev_get_size(void);
 int vnic_dev_int13(struct vnic_dev *vdev, u64 arg, u32 op);
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index d4f478b5e..bd4447f01 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -1478,6 +1478,15 @@ int enic_probe(struct enic *enic)
 		enic_alloc_consistent,
 		enic_free_consistent);
 
+	/*
+	 * Allocate the consistent memory for stats upfront so both primary and
+	 * secondary processes can dump stats.
+	 */
+	err = vnic_dev_alloc_stats_mem(enic->vdev);
+	if (err) {
+		dev_err(enic, "Failed to allocate cmd memory, aborting\n");
+		goto err_out_unregister;
+	}
 	/* Issue device open to get device in known state */
 	err = enic_dev_open(enic);
 	if (err) {
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 07/10] net/enic: support Rx queue interrupts
  2018-03-06  1:46   ` [PATCH v2 00/10] enic patchset John Daley
                       ` (5 preceding siblings ...)
  2018-03-06  1:46     ` [PATCH v2 06/10] net/enic: allocate stats DMA buffer upfront during probe John Daley
@ 2018-03-06  1:46     ` John Daley
  2018-03-06  1:46     ` [PATCH v2 08/10] doc: describe Rx bytes counter behavior for enic John Daley
                       ` (2 subsequent siblings)
  9 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-03-06  1:46 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

Enable rx queue interrupts if the app requests them, and vNIC has
enough interrupt resources. Use interrupt vector 0 for link status and
errors. Use vector 1 for rx queue 0, vector 2 for rx queue 1, and so
on. So, with n rx queues, vNIC needs to have at n + 1 interrupts.

For VIC, enabling and disabling rx queue interrupts are simply
mask/unmask operations. VIC's credit based interrupt moderation is not
used, as the app wants to explicitly control when to enable/disable
interrupts.

This version requires MSI-X (vfio-pci). Sharing one interrupt for link
status and rx queues is possible, but is rather complex and has no
user demands.

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 doc/guides/nics/enic.rst          |   7 ++-
 doc/guides/nics/features/enic.ini |   1 +
 drivers/net/enic/enic.h           |  15 ++++-
 drivers/net/enic/enic_ethdev.c    |  22 +++++++
 drivers/net/enic/enic_main.c      | 123 ++++++++++++++++++++++++++++++++------
 drivers/net/enic/enic_res.c       |   3 +-
 6 files changed, 149 insertions(+), 22 deletions(-)

diff --git a/doc/guides/nics/enic.rst b/doc/guides/nics/enic.rst
index 0e655e9e3..7e19cf88a 100644
--- a/doc/guides/nics/enic.rst
+++ b/doc/guides/nics/enic.rst
@@ -114,11 +114,16 @@ Configuration information
 
   - **Interrupts**
 
-    Only one interrupt per vNIC interface should be configured in the UCS
+    At least one interrupt per vNIC interface should be configured in the UCS
     manager regardless of the number receive/transmit queues. The ENIC PMD
     uses this interrupt to get information about link status and errors
     in the fast path.
 
+    In addition to the interrupt for link status and errors, when using Rx queue
+    interrupts, increase the number of configured interrupts so that there is at
+    least one interrupt for each Rx queue. For example, if the app uses 3 Rx
+    queues and wants to use per-queue interrupts, configure 4 (3 + 1) interrupts.
+
 .. _enic-flow-director:
 
 Flow director support
diff --git a/doc/guides/nics/features/enic.ini b/doc/guides/nics/features/enic.ini
index e79d7277d..ea171a45b 100644
--- a/doc/guides/nics/features/enic.ini
+++ b/doc/guides/nics/features/enic.ini
@@ -6,6 +6,7 @@
 [Features]
 Link status          = Y
 Link status event    = Y
+Rx interrupt         = Y
 Queue start/stop     = Y
 MTU update           = Y
 Jumbo frame          = Y
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index 1b3813a58..adccc8ac5 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -49,6 +49,15 @@
 
 #define ENICPMD_FDIR_MAX           64
 
+/*
+ * Interrupt 0: LSC and errors
+ * Interrupt 1: rx queue 0
+ * Interrupt 2: rx queue 1
+ * ...
+ */
+#define ENICPMD_LSC_INTR_OFFSET 0
+#define ENICPMD_RXQ_INTR_OFFSET 1
+
 struct enic_fdir_node {
 	struct rte_eth_fdir_filter filter;
 	u16 fltr_id;
@@ -126,9 +135,9 @@ struct enic {
 	struct vnic_cq *cq;
 	unsigned int cq_count; /* equals rq_count + wq_count */
 
-	/* interrupt resource */
-	struct vnic_intr intr;
-	unsigned int intr_count;
+	/* interrupt vectors (len = conf_intr_count) */
+	struct vnic_intr *intr;
+	unsigned int intr_count; /* equals enabled interrupts (lsc + rxqs) */
 
 	/* software counters */
 	struct enic_soft_stats soft_stats;
diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
index 6dd72729e..2a289b6a4 100644
--- a/drivers/net/enic/enic_ethdev.c
+++ b/drivers/net/enic/enic_ethdev.c
@@ -738,6 +738,26 @@ static void enicpmd_dev_txq_info_get(struct rte_eth_dev *dev,
 	/* tx_thresh, and all the other fields are not applicable for enic */
 }
 
+static int enicpmd_dev_rx_queue_intr_enable(struct rte_eth_dev *eth_dev,
+					    uint16_t rx_queue_id)
+{
+	struct enic *enic = pmd_priv(eth_dev);
+
+	ENICPMD_FUNC_TRACE();
+	vnic_intr_unmask(&enic->intr[rx_queue_id + ENICPMD_RXQ_INTR_OFFSET]);
+	return 0;
+}
+
+static int enicpmd_dev_rx_queue_intr_disable(struct rte_eth_dev *eth_dev,
+					     uint16_t rx_queue_id)
+{
+	struct enic *enic = pmd_priv(eth_dev);
+
+	ENICPMD_FUNC_TRACE();
+	vnic_intr_mask(&enic->intr[rx_queue_id + ENICPMD_RXQ_INTR_OFFSET]);
+	return 0;
+}
+
 static const struct eth_dev_ops enicpmd_eth_dev_ops = {
 	.dev_configure        = enicpmd_dev_configure,
 	.dev_start            = enicpmd_dev_start,
@@ -770,6 +790,8 @@ static const struct eth_dev_ops enicpmd_eth_dev_ops = {
 	.rx_descriptor_done   = NULL,
 	.tx_queue_setup       = enicpmd_dev_tx_queue_setup,
 	.tx_queue_release     = enicpmd_dev_tx_queue_release,
+	.rx_queue_intr_enable = enicpmd_dev_rx_queue_intr_enable,
+	.rx_queue_intr_disable = enicpmd_dev_rx_queue_intr_disable,
 	.rxq_info_get         = enicpmd_dev_rxq_info_get,
 	.txq_info_get         = enicpmd_dev_txq_info_get,
 	.dev_led_on           = NULL,
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index bd4447f01..ff1b15be6 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -200,10 +200,16 @@ void enic_init_vnic_resources(struct enic *enic)
 {
 	unsigned int error_interrupt_enable = 1;
 	unsigned int error_interrupt_offset = 0;
+	unsigned int rxq_interrupt_enable = 0;
+	unsigned int rxq_interrupt_offset;
 	unsigned int index = 0;
 	unsigned int cq_idx;
 	struct vnic_rq *data_rq;
 
+	if (enic->rte_dev->data->dev_conf.intr_conf.rxq) {
+		rxq_interrupt_enable = 1;
+		rxq_interrupt_offset = ENICPMD_RXQ_INTR_OFFSET;
+	}
 	for (index = 0; index < enic->rq_count; index++) {
 		cq_idx = enic_cq_rq(enic, enic_rte_rq_idx_to_sop_idx(index));
 
@@ -225,11 +231,13 @@ void enic_init_vnic_resources(struct enic *enic)
 			0 /* cq_head */,
 			0 /* cq_tail */,
 			1 /* cq_tail_color */,
-			0 /* interrupt_enable */,
+			rxq_interrupt_enable,
 			1 /* cq_entry_enable */,
 			0 /* cq_message_enable */,
-			0 /* interrupt offset */,
+			rxq_interrupt_offset,
 			0 /* cq_message_addr */);
+		if (rxq_interrupt_enable)
+			rxq_interrupt_offset++;
 	}
 
 	for (index = 0; index < enic->wq_count; index++) {
@@ -252,10 +260,12 @@ void enic_init_vnic_resources(struct enic *enic)
 			(u64)enic->wq[index].cqmsg_rz->iova);
 	}
 
-	vnic_intr_init(&enic->intr,
-		enic->config.intr_timer_usec,
-		enic->config.intr_timer_type,
-		/*mask_on_assertion*/1);
+	for (index = 0; index < enic->intr_count; index++) {
+		vnic_intr_init(&enic->intr[index],
+			       enic->config.intr_timer_usec,
+			       enic->config.intr_timer_type,
+			       /*mask_on_assertion*/1);
+	}
 }
 
 
@@ -411,13 +421,62 @@ enic_intr_handler(void *arg)
 	struct rte_eth_dev *dev = (struct rte_eth_dev *)arg;
 	struct enic *enic = pmd_priv(dev);
 
-	vnic_intr_return_all_credits(&enic->intr);
+	vnic_intr_return_all_credits(&enic->intr[ENICPMD_LSC_INTR_OFFSET]);
 
 	enic_link_update(enic);
 	_rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
 	enic_log_q_error(enic);
 }
 
+static int enic_rxq_intr_init(struct enic *enic)
+{
+	struct rte_intr_handle *intr_handle;
+	uint32_t rxq_intr_count, i;
+	int err;
+
+	intr_handle = enic->rte_dev->intr_handle;
+	if (!enic->rte_dev->data->dev_conf.intr_conf.rxq)
+		return 0;
+	/*
+	 * Rx queue interrupts only work when we have MSI-X interrupts,
+	 * one per queue. Sharing one interrupt is technically
+	 * possible with VIC, but it is not worth the complications it brings.
+	 */
+	if (!rte_intr_cap_multiple(intr_handle)) {
+		dev_err(enic, "Rx queue interrupts require MSI-X interrupts"
+			" (vfio-pci driver)\n");
+		return -ENOTSUP;
+	}
+	rxq_intr_count = enic->intr_count - ENICPMD_RXQ_INTR_OFFSET;
+	err = rte_intr_efd_enable(intr_handle, rxq_intr_count);
+	if (err) {
+		dev_err(enic, "Failed to enable event fds for Rx queue"
+			" interrupts\n");
+		return err;
+	}
+	intr_handle->intr_vec = rte_zmalloc("enic_intr_vec",
+					    rxq_intr_count * sizeof(int), 0);
+	if (intr_handle->intr_vec == NULL) {
+		dev_err(enic, "Failed to allocate intr_vec\n");
+		return -ENOMEM;
+	}
+	for (i = 0; i < rxq_intr_count; i++)
+		intr_handle->intr_vec[i] = i + ENICPMD_RXQ_INTR_OFFSET;
+	return 0;
+}
+
+static void enic_rxq_intr_deinit(struct enic *enic)
+{
+	struct rte_intr_handle *intr_handle;
+
+	intr_handle = enic->rte_dev->intr_handle;
+	rte_intr_efd_disable(intr_handle);
+	if (intr_handle->intr_vec != NULL) {
+		rte_free(intr_handle->intr_vec);
+		intr_handle->intr_vec = NULL;
+	}
+}
+
 int enic_enable(struct enic *enic)
 {
 	unsigned int index;
@@ -434,6 +493,9 @@ int enic_enable(struct enic *enic)
 	if (eth_dev->data->dev_conf.intr_conf.lsc)
 		vnic_dev_notify_set(enic->vdev, 0);
 
+	err = enic_rxq_intr_init(enic);
+	if (err)
+		return err;
 	if (enic_clsf_init(enic))
 		dev_warning(enic, "Init of hash table for clsf failed."\
 			"Flow director feature will not work\n");
@@ -471,7 +533,8 @@ int enic_enable(struct enic *enic)
 		enic_intr_handler, (void *)enic->rte_dev);
 
 	rte_intr_enable(&(enic->pdev->intr_handle));
-	vnic_intr_unmask(&enic->intr);
+	/* Unmask LSC interrupt */
+	vnic_intr_unmask(&enic->intr[ENICPMD_LSC_INTR_OFFSET]);
 
 	return 0;
 }
@@ -479,17 +542,21 @@ int enic_enable(struct enic *enic)
 int enic_alloc_intr_resources(struct enic *enic)
 {
 	int err;
+	unsigned int i;
 
 	dev_info(enic, "vNIC resources used:  "\
 		"wq %d rq %d cq %d intr %d\n",
 		enic->wq_count, enic_vnic_rq_count(enic),
 		enic->cq_count, enic->intr_count);
 
-	err = vnic_intr_alloc(enic->vdev, &enic->intr, 0);
-	if (err)
-		enic_free_vnic_resources(enic);
-
-	return err;
+	for (i = 0; i < enic->intr_count; i++) {
+		err = vnic_intr_alloc(enic->vdev, &enic->intr[i], i);
+		if (err) {
+			enic_free_vnic_resources(enic);
+			return err;
+		}
+	}
+	return 0;
 }
 
 void enic_free_rq(void *rxq)
@@ -837,8 +904,11 @@ int enic_disable(struct enic *enic)
 	unsigned int i;
 	int err;
 
-	vnic_intr_mask(&enic->intr);
-	(void)vnic_intr_masked(&enic->intr); /* flush write */
+	for (i = 0; i < enic->intr_count; i++) {
+		vnic_intr_mask(&enic->intr[i]);
+		(void)vnic_intr_masked(&enic->intr[i]); /* flush write */
+	}
+	enic_rxq_intr_deinit(enic);
 	rte_intr_disable(&enic->pdev->intr_handle);
 	rte_intr_callback_unregister(&enic->pdev->intr_handle,
 				     enic_intr_handler,
@@ -881,7 +951,8 @@ int enic_disable(struct enic *enic)
 			vnic_rq_clean(&enic->rq[i], enic_free_rq_buf);
 	for (i = 0; i < enic->cq_count; i++)
 		vnic_cq_clean(&enic->cq[i]);
-	vnic_intr_clean(&enic->intr);
+	for (i = 0; i < enic->intr_count; i++)
+		vnic_intr_clean(&enic->intr[i]);
 
 	return 0;
 }
@@ -1170,6 +1241,7 @@ static void enic_dev_deinit(struct enic *enic)
 
 	rte_free(eth_dev->data->mac_addrs);
 	rte_free(enic->cq);
+	rte_free(enic->intr);
 	rte_free(enic->rq);
 	rte_free(enic->wq);
 }
@@ -1179,12 +1251,16 @@ int enic_set_vnic_res(struct enic *enic)
 {
 	struct rte_eth_dev *eth_dev = enic->rte_dev;
 	int rc = 0;
-	unsigned int required_rq, required_wq, required_cq;
+	unsigned int required_rq, required_wq, required_cq, required_intr;
 
 	/* Always use two vNIC RQs per eth_dev RQ, regardless of Rx scatter. */
 	required_rq = eth_dev->data->nb_rx_queues * 2;
 	required_wq = eth_dev->data->nb_tx_queues;
 	required_cq = eth_dev->data->nb_rx_queues + eth_dev->data->nb_tx_queues;
+	required_intr = 1; /* 1 for LSC even if intr_conf.lsc is 0 */
+	if (eth_dev->data->dev_conf.intr_conf.rxq) {
+		required_intr += eth_dev->data->nb_rx_queues;
+	}
 
 	if (enic->conf_rq_count < required_rq) {
 		dev_err(dev, "Not enough Receive queues. Requested:%u which uses %d RQs on VIC, Configured:%u\n",
@@ -1203,11 +1279,18 @@ int enic_set_vnic_res(struct enic *enic)
 			required_cq, enic->conf_cq_count);
 		rc = -EINVAL;
 	}
+	if (enic->conf_intr_count < required_intr) {
+		dev_err(dev, "Not enough Interrupts to support Rx queue"
+			" interrupts. Required:%u, Configured:%u\n",
+			required_intr, enic->conf_intr_count);
+		rc = -EINVAL;
+	}
 
 	if (rc == 0) {
 		enic->rq_count = eth_dev->data->nb_rx_queues;
 		enic->wq_count = eth_dev->data->nb_tx_queues;
 		enic->cq_count = enic->rq_count + enic->wq_count;
+		enic->intr_count = required_intr;
 	}
 
 	return rc;
@@ -1409,6 +1492,8 @@ static int enic_dev_init(struct enic *enic)
 	/* Queue counts may be zeros. rte_zmalloc returns NULL in that case. */
 	enic->cq = rte_zmalloc("enic_vnic_cq", sizeof(struct vnic_cq) *
 			       enic->conf_cq_count, 8);
+	enic->intr = rte_zmalloc("enic_vnic_intr", sizeof(struct vnic_intr) *
+				 enic->conf_intr_count, 8);
 	enic->rq = rte_zmalloc("enic_vnic_rq", sizeof(struct vnic_rq) *
 			       enic->conf_rq_count, 8);
 	enic->wq = rte_zmalloc("enic_vnic_wq", sizeof(struct vnic_wq) *
@@ -1417,6 +1502,10 @@ static int enic_dev_init(struct enic *enic)
 		dev_err(enic, "failed to allocate vnic_cq, aborting.\n");
 		return -1;
 	}
+	if (enic->conf_intr_count > 0 && enic->intr == NULL) {
+		dev_err(enic, "failed to allocate vnic_intr, aborting.\n");
+		return -1;
+	}
 	if (enic->conf_rq_count > 0 && enic->rq == NULL) {
 		dev_err(enic, "failed to allocate vnic_rq, aborting.\n");
 		return -1;
diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c
index d8f7892c3..e7ad6767e 100644
--- a/drivers/net/enic/enic_res.c
+++ b/drivers/net/enic/enic_res.c
@@ -222,7 +222,8 @@ void enic_free_vnic_resources(struct enic *enic)
 			vnic_rq_free(&enic->rq[i]);
 	for (i = 0; i < enic->cq_count; i++)
 		vnic_cq_free(&enic->cq[i]);
-	vnic_intr_free(&enic->intr);
+	for (i = 0; i < enic->intr_count; i++)
+		vnic_intr_free(&enic->intr[i]);
 }
 
 void enic_get_res_counts(struct enic *enic)
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 08/10] doc: describe Rx bytes counter behavior for enic
  2018-03-06  1:46   ` [PATCH v2 00/10] enic patchset John Daley
                       ` (6 preceding siblings ...)
  2018-03-06  1:46     ` [PATCH v2 07/10] net/enic: support Rx queue interrupts John Daley
@ 2018-03-06  1:46     ` John Daley
  2018-03-06  1:46     ` [PATCH v2 09/10] net/enic: use memcpy to avoid strict aliasing warnings John Daley
  2018-03-06  1:46     ` [PATCH v2 10/10] net/enic: support for meson John Daley
  9 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-03-06  1:46 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 doc/guides/nics/enic.rst | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/doc/guides/nics/enic.rst b/doc/guides/nics/enic.rst
index 7e19cf88a..0bc55936a 100644
--- a/doc/guides/nics/enic.rst
+++ b/doc/guides/nics/enic.rst
@@ -310,6 +310,14 @@ Limitations
     were added. Since there currently is no grouping or priority support,
     'catch-all' filters should be added last.
 
+- **Statistics**
+
+  - ``rx_good_bytes`` (ibytes) always includes VLAN header (4B) and CRC bytes (4B).
+  - When the NIC drops a packet because the Rx queue has no free buffers,
+    ``rx_good_bytes`` still increments by 4B if the packet is not VLAN tagged or
+    VLAN stripping is disabled, or by 8B if the packet is VLAN tagged and stripping
+    is enabled.
+
 How to build the suite
 ----------------------
 
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 09/10] net/enic: use memcpy to avoid strict aliasing warnings
  2018-03-06  1:46   ` [PATCH v2 00/10] enic patchset John Daley
                       ` (7 preceding siblings ...)
  2018-03-06  1:46     ` [PATCH v2 08/10] doc: describe Rx bytes counter behavior for enic John Daley
@ 2018-03-06  1:46     ` John Daley
  2018-03-06  1:46     ` [PATCH v2 10/10] net/enic: support for meson John Daley
  9 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-03-06  1:46 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 drivers/net/enic/enic_clsf.c | 21 ++++++++-------------
 1 file changed, 8 insertions(+), 13 deletions(-)

diff --git a/drivers/net/enic/enic_clsf.c b/drivers/net/enic/enic_clsf.c
index 3ef1d0832..9d95201ec 100644
--- a/drivers/net/enic/enic_clsf.c
+++ b/drivers/net/enic/enic_clsf.c
@@ -111,7 +111,6 @@ copy_fltr_v2(struct filter_v2 *fltr, struct rte_eth_fdir_input *input,
 	     struct rte_eth_fdir_masks *masks)
 {
 	struct filter_generic_1 *gp = &fltr->u.generic_1;
-	int i;
 
 	fltr->type = FILTER_DPDK_1;
 	memset(gp, 0, sizeof(*gp));
@@ -273,18 +272,14 @@ copy_fltr_v2(struct filter_v2 *fltr, struct rte_eth_fdir_input *input,
 			ipv6_mask.proto = masks->ipv6_mask.proto;
 			ipv6_val.proto = input->flow.ipv6_flow.proto;
 		}
-		for (i = 0; i < 4; i++) {
-			*(uint32_t *)&ipv6_mask.src_addr[i * 4] =
-					masks->ipv6_mask.src_ip[i];
-			*(uint32_t *)&ipv6_val.src_addr[i * 4] =
-					input->flow.ipv6_flow.src_ip[i];
-		}
-		for (i = 0; i < 4; i++) {
-			*(uint32_t *)&ipv6_mask.dst_addr[i * 4] =
-					masks->ipv6_mask.src_ip[i];
-			*(uint32_t *)&ipv6_val.dst_addr[i * 4] =
-					input->flow.ipv6_flow.dst_ip[i];
-		}
+		memcpy(ipv6_mask.src_addr, masks->ipv6_mask.src_ip,
+		       sizeof(ipv6_mask.src_addr));
+		memcpy(ipv6_val.src_addr, input->flow.ipv6_flow.src_ip,
+		       sizeof(ipv6_val.src_addr));
+		memcpy(ipv6_mask.dst_addr, masks->ipv6_mask.dst_ip,
+		       sizeof(ipv6_mask.dst_addr));
+		memcpy(ipv6_val.dst_addr, input->flow.ipv6_flow.dst_ip,
+		       sizeof(ipv6_val.dst_addr));
 		if (input->flow.ipv6_flow.tc) {
 			ipv6_mask.vtc_flow = masks->ipv6_mask.tc << 12;
 			ipv6_val.vtc_flow = input->flow.ipv6_flow.tc << 12;
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 10/10] net/enic: support for meson
  2018-03-06  1:46   ` [PATCH v2 00/10] enic patchset John Daley
                       ` (8 preceding siblings ...)
  2018-03-06  1:46     ` [PATCH v2 09/10] net/enic: use memcpy to avoid strict aliasing warnings John Daley
@ 2018-03-06  1:46     ` John Daley
  9 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-03-06  1:46 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---

 drivers/net/enic/meson.build | 19 +++++++++++++++++++
 drivers/net/meson.build      |  2 +-
 2 files changed, 20 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/enic/meson.build

diff --git a/drivers/net/enic/meson.build b/drivers/net/enic/meson.build
new file mode 100644
index 000000000..bfd4e2373
--- /dev/null
+++ b/drivers/net/enic/meson.build
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Cisco Systems, Inc.
+
+sources = files(
+	'base/vnic_cq.c',
+	'base/vnic_dev.c',
+	'base/vnic_intr.c',
+	'base/vnic_rq.c',
+	'base/vnic_rss.c',
+	'base/vnic_wq.c',
+	'enic_clsf.c',
+	'enic_ethdev.c',
+	'enic_flow.c',
+	'enic_main.c',
+	'enic_res.c',
+	'enic_rxtx.c',
+	)
+deps += ['hash']
+includes += include_directories('base')
diff --git a/drivers/net/meson.build b/drivers/net/meson.build
index 704cbe3c8..f535baa13 100644
--- a/drivers/net/meson.build
+++ b/drivers/net/meson.build
@@ -2,7 +2,7 @@
 # Copyright(c) 2017 Intel Corporation
 
 drivers = ['af_packet', 'bonding',
-	'e1000', 'fm10k', 'i40e', 'ixgbe',
+	'e1000', 'enic', 'fm10k', 'i40e', 'ixgbe',
 	'null', 'octeontx', 'pcap', 'ring',
 	'sfc', 'thunderx']
 std_deps = ['ethdev', 'kvargs'] # 'ethdev' also pulls in mbuf, net, eal etc
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 00/10] enic PMD patchset
  2018-03-06  1:46     ` [PATCH v2 01/10] net/enic: remove 'extern' in .h file function declarations John Daley
@ 2018-03-08  2:46       ` John Daley
  2018-03-08  2:46         ` [PATCH v3 01/10] net/enic: remove 'extern' in .h file function declarations John Daley
                           ` (10 more replies)
  0 siblings, 11 replies; 44+ messages in thread
From: John Daley @ 2018-03-08  2:46 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, John Daley

V2: rebase, submit as patchset instead of individual patches so they
apply correctly.
V3: try again submitting patches one at a time so they are applied
in order (tester seems to be applying patches in order received
instead of looking at patch ID).

Hyong Youb Kim (9):
  net/enic: allow the user to change RSS settings
  net/enic: heed the requested max Rx packet size
  net/enic: remove the VLAN filter handler
  net/enic: add Rx/Tx queue configuration getters
  net/enic: allocate stats DMA buffer upfront during probe
  net/enic: support Rx queue interrupts
  doc: describe Rx bytes counter behavior for enic
  net/enic: use memcpy to avoid strict aliasing warnings
  net/enic: support for meson

John Daley (1):
  net/enic: remove 'extern' in .h file function declarations

 doc/guides/nics/enic.rst          |  16 +-
 doc/guides/nics/features/enic.ini |   3 +
 drivers/net/enic/base/vnic_dev.c  |  24 ++-
 drivers/net/enic/base/vnic_dev.h  |   1 +
 drivers/net/enic/enic.h           | 120 +++++++-----
 drivers/net/enic/enic_clsf.c      |  21 +--
 drivers/net/enic/enic_ethdev.c    | 258 ++++++++++++++++++++++----
 drivers/net/enic/enic_main.c      | 373 ++++++++++++++++++++++++++++++--------
 drivers/net/enic/enic_res.c       |  23 ++-
 drivers/net/enic/enic_res.h       |   6 +
 drivers/net/enic/meson.build      |  19 ++
 drivers/net/meson.build           |   2 +-
 12 files changed, 686 insertions(+), 180 deletions(-)
 create mode 100644 drivers/net/enic/meson.build

-- 
2.16.2

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v3 01/10] net/enic: remove 'extern' in .h file function declarations
  2018-03-08  2:46       ` [PATCH v3 00/10] enic PMD patchset John Daley
@ 2018-03-08  2:46         ` John Daley
  2018-03-08  2:46         ` [PATCH v3 02/10] net/enic: allow the user to change RSS settings John Daley
                           ` (9 subsequent siblings)
  10 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-03-08  2:46 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, John Daley

Signed-off-by: John Daley <johndale@cisco.com>
Reviewed-by: Hyong Youb Kim <hyonkim@cisco.com>
---
 drivers/net/enic/enic.h | 80 ++++++++++++++++++++++++-------------------------
 1 file changed, 40 insertions(+), 40 deletions(-)

diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index c083985ee..e88af6bc9 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -220,54 +220,54 @@ enic_ring_incr(uint32_t n_descriptors, uint32_t idx)
 	return idx;
 }
 
-extern void enic_fdir_stats_get(struct enic *enic,
-	struct rte_eth_fdir_stats *stats);
-extern int enic_fdir_add_fltr(struct enic *enic,
-	struct rte_eth_fdir_filter *params);
-extern int enic_fdir_del_fltr(struct enic *enic,
-	struct rte_eth_fdir_filter *params);
-extern void enic_free_wq(void *txq);
-extern int enic_alloc_intr_resources(struct enic *enic);
-extern int enic_setup_finish(struct enic *enic);
-extern int enic_alloc_wq(struct enic *enic, uint16_t queue_idx,
-	unsigned int socket_id, uint16_t nb_desc);
-extern void enic_start_wq(struct enic *enic, uint16_t queue_idx);
-extern int enic_stop_wq(struct enic *enic, uint16_t queue_idx);
-extern void enic_start_rq(struct enic *enic, uint16_t queue_idx);
-extern int enic_stop_rq(struct enic *enic, uint16_t queue_idx);
-extern void enic_free_rq(void *rxq);
-extern int enic_alloc_rq(struct enic *enic, uint16_t queue_idx,
-	unsigned int socket_id, struct rte_mempool *mp,
-	uint16_t nb_desc, uint16_t free_thresh);
-extern int enic_set_rss_nic_cfg(struct enic *enic);
-extern int enic_set_vnic_res(struct enic *enic);
-extern int enic_enable(struct enic *enic);
-extern int enic_disable(struct enic *enic);
-extern void enic_remove(struct enic *enic);
-extern int enic_get_link_status(struct enic *enic);
-extern int enic_dev_stats_get(struct enic *enic,
-	struct rte_eth_stats *r_stats);
-extern void enic_dev_stats_clear(struct enic *enic);
-extern void enic_add_packet_filter(struct enic *enic);
+void enic_fdir_stats_get(struct enic *enic,
+			 struct rte_eth_fdir_stats *stats);
+int enic_fdir_add_fltr(struct enic *enic,
+		       struct rte_eth_fdir_filter *params);
+int enic_fdir_del_fltr(struct enic *enic,
+		       struct rte_eth_fdir_filter *params);
+void enic_free_wq(void *txq);
+int enic_alloc_intr_resources(struct enic *enic);
+int enic_setup_finish(struct enic *enic);
+int enic_alloc_wq(struct enic *enic, uint16_t queue_idx,
+		  unsigned int socket_id, uint16_t nb_desc);
+void enic_start_wq(struct enic *enic, uint16_t queue_idx);
+int enic_stop_wq(struct enic *enic, uint16_t queue_idx);
+void enic_start_rq(struct enic *enic, uint16_t queue_idx);
+int enic_stop_rq(struct enic *enic, uint16_t queue_idx);
+void enic_free_rq(void *rxq);
+int enic_alloc_rq(struct enic *enic, uint16_t queue_idx,
+		  unsigned int socket_id, struct rte_mempool *mp,
+		  uint16_t nb_desc, uint16_t free_thresh);
+int enic_set_rss_nic_cfg(struct enic *enic);
+int enic_set_vnic_res(struct enic *enic);
+int enic_enable(struct enic *enic);
+int enic_disable(struct enic *enic);
+void enic_remove(struct enic *enic);
+int enic_get_link_status(struct enic *enic);
+int enic_dev_stats_get(struct enic *enic,
+		       struct rte_eth_stats *r_stats);
+void enic_dev_stats_clear(struct enic *enic);
+void enic_add_packet_filter(struct enic *enic);
 int enic_set_mac_address(struct enic *enic, uint8_t *mac_addr);
 void enic_del_mac_address(struct enic *enic, int mac_index);
-extern unsigned int enic_cleanup_wq(struct enic *enic, struct vnic_wq *wq);
-extern void enic_send_pkt(struct enic *enic, struct vnic_wq *wq,
-			  struct rte_mbuf *tx_pkt, unsigned short len,
-			  uint8_t sop, uint8_t eop, uint8_t cq_entry,
-			  uint16_t ol_flags, uint16_t vlan_tag);
-
-extern void enic_post_wq_index(struct vnic_wq *wq);
-extern int enic_probe(struct enic *enic);
-extern int enic_clsf_init(struct enic *enic);
-extern void enic_clsf_destroy(struct enic *enic);
+unsigned int enic_cleanup_wq(struct enic *enic, struct vnic_wq *wq);
+void enic_send_pkt(struct enic *enic, struct vnic_wq *wq,
+		   struct rte_mbuf *tx_pkt, unsigned short len,
+		   uint8_t sop, uint8_t eop, uint8_t cq_entry,
+		   uint16_t ol_flags, uint16_t vlan_tag);
+
+void enic_post_wq_index(struct vnic_wq *wq);
+int enic_probe(struct enic *enic);
+int enic_clsf_init(struct enic *enic);
+void enic_clsf_destroy(struct enic *enic);
 uint16_t enic_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
 			uint16_t nb_pkts);
 uint16_t enic_dummy_recv_pkts(void *rx_queue,
 			      struct rte_mbuf **rx_pkts,
 			      uint16_t nb_pkts);
 uint16_t enic_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
-			       uint16_t nb_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);
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 02/10] net/enic: allow the user to change RSS settings
  2018-03-08  2:46       ` [PATCH v3 00/10] enic PMD patchset John Daley
  2018-03-08  2:46         ` [PATCH v3 01/10] net/enic: remove 'extern' in .h file function declarations John Daley
@ 2018-03-08  2:46         ` John Daley
  2018-03-09 14:35           ` Ferruh Yigit
  2018-03-08  2:46         ` [PATCH v3 03/10] net/enic: heed the requested max Rx packet size John Daley
                           ` (8 subsequent siblings)
  10 siblings, 1 reply; 44+ messages in thread
From: John Daley @ 2018-03-08  2:46 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

Currently, when more than 1 receive queues are configured, the driver
always enables RSS with the driver's own default hash type, key, and
RETA. The user is unable to change any of the RSS settings. Address
this by implementing the ethdev RSS API as follows.

Correctly report the RETA size, key size, and supported hash types
through rte_eth_dev_info.

During dev_configure(), initialize RSS according to the device's
mq_mode and rss_conf. Start with the default RETA, and use the default
key unless a custom key is provided.

Add the RETA and rss_conf query/set handlers to let the user change
RSS settings after the initial configuration. The hardware is able to
change hash type, key, and RETA individually. So, the handlers change
only the affected settings.

Refactor/rename several functions in order to make their intentions
clear. For example, remove all traces of RSS from
enicpmd_vlan_offload_set() as it is confusing.

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 doc/guides/nics/features/enic.ini |   2 +
 drivers/net/enic/enic.h           |  20 +++-
 drivers/net/enic/enic_ethdev.c    | 117 ++++++++++++++++++++++-
 drivers/net/enic/enic_main.c      | 192 ++++++++++++++++++++++++++++----------
 drivers/net/enic/enic_res.c       |  20 ++++
 drivers/net/enic/enic_res.h       |   6 ++
 6 files changed, 301 insertions(+), 56 deletions(-)

diff --git a/doc/guides/nics/features/enic.ini b/doc/guides/nics/features/enic.ini
index 498341f07..e79d7277d 100644
--- a/doc/guides/nics/features/enic.ini
+++ b/doc/guides/nics/features/enic.ini
@@ -15,6 +15,8 @@ Promiscuous mode     = Y
 Unicast MAC filter   = Y
 Multicast MAC filter = Y
 RSS hash             = Y
+RSS key update       = Y
+RSS reta update      = Y
 SR-IOV               = Y
 VLAN filter          = Y
 CRC offload          = Y
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index e88af6bc9..d29939c94 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -146,6 +146,20 @@ struct enic {
 
 	LIST_HEAD(enic_flows, rte_flow) flows;
 	rte_spinlock_t flows_lock;
+
+	/* RSS */
+	uint16_t reta_size;
+	uint8_t hash_key_size;
+	uint64_t flow_type_rss_offloads; /* 0 indicates RSS not supported */
+	/*
+	 * Keep a copy of current RSS config for queries, as we cannot retrieve
+	 * it from the NIC.
+	 */
+	uint8_t rss_hash_type; /* NIC_CFG_RSS_HASH_TYPE flags */
+	uint8_t rss_enable;
+	uint64_t rss_hf; /* ETH_RSS flags */
+	union vnic_rss_key rss_key;
+	union vnic_rss_cpu rss_cpu;
 };
 
 /* Get the CQ index from a Start of Packet(SOP) RQ index */
@@ -239,8 +253,12 @@ void enic_free_rq(void *rxq);
 int enic_alloc_rq(struct enic *enic, uint16_t queue_idx,
 		  unsigned int socket_id, struct rte_mempool *mp,
 		  uint16_t nb_desc, uint16_t free_thresh);
-int enic_set_rss_nic_cfg(struct enic *enic);
 int enic_set_vnic_res(struct enic *enic);
+int enic_init_rss_nic_cfg(struct enic *enic);
+int enic_set_rss_conf(struct enic *enic,
+		      struct rte_eth_rss_conf *rss_conf);
+int enic_set_rss_reta(struct enic *enic, union vnic_rss_cpu *rss_cpu);
+int enic_set_vlan_strip(struct enic *enic);
 int enic_enable(struct enic *enic);
 int enic_disable(struct enic *enic);
 void enic_remove(struct enic *enic);
diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
index d84714efb..cbab7029b 100644
--- a/drivers/net/enic/enic_ethdev.c
+++ b/drivers/net/enic/enic_ethdev.c
@@ -345,8 +345,6 @@ static int enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 		else
 			enic->ig_vlan_strip_en = 0;
 	}
-	enic_set_rss_nic_cfg(enic);
-
 
 	if (mask & ETH_VLAN_FILTER_MASK) {
 		dev_warning(enic,
@@ -358,7 +356,7 @@ static int enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 			"Configuration of extended VLAN is not supported\n");
 	}
 
-	return 0;
+	return enic_set_vlan_strip(enic);
 }
 
 static int enicpmd_dev_configure(struct rte_eth_dev *eth_dev)
@@ -379,8 +377,16 @@ static int enicpmd_dev_configure(struct rte_eth_dev *eth_dev)
 	enic->hw_ip_checksum = !!(eth_dev->data->dev_conf.rxmode.offloads &
 				  DEV_RX_OFFLOAD_CHECKSUM);
 	ret = enicpmd_vlan_offload_set(eth_dev, ETH_VLAN_STRIP_MASK);
-
-	return ret;
+	if (ret) {
+		dev_err(enic, "Failed to configure VLAN offloads\n");
+		return ret;
+	}
+	/*
+	 * Initialize RSS with the default reta and key. If the user key is
+	 * given (rx_adv_conf.rss_conf.rss_key), will use that instead of the
+	 * default key.
+	 */
+	return enic_init_rss_nic_cfg(enic);
 }
 
 /* Start the device.
@@ -480,6 +486,9 @@ static void enicpmd_dev_info_get(struct rte_eth_dev *eth_dev,
 	device_info->default_rxconf = (struct rte_eth_rxconf) {
 		.rx_free_thresh = ENIC_DEFAULT_RX_FREE_THRESH
 	};
+	device_info->reta_size = enic->reta_size;
+	device_info->hash_key_size = enic->hash_key_size;
+	device_info->flow_type_rss_offloads = enic->flow_type_rss_offloads;
 }
 
 static const uint32_t *enicpmd_dev_supported_ptypes_get(struct rte_eth_dev *dev)
@@ -582,6 +591,100 @@ static int enicpmd_mtu_set(struct rte_eth_dev *eth_dev, uint16_t mtu)
 	return enic_set_mtu(enic, mtu);
 }
 
+static int enicpmd_dev_rss_reta_query(struct rte_eth_dev *dev,
+				      struct rte_eth_rss_reta_entry64
+				      *reta_conf,
+				      uint16_t reta_size)
+{
+	struct enic *enic = pmd_priv(dev);
+	uint16_t i, idx, shift;
+
+	ENICPMD_FUNC_TRACE();
+	if (reta_size != ENIC_RSS_RETA_SIZE) {
+		dev_err(enic, "reta_query: wrong reta_size. given=%u expected=%u\n",
+			reta_size, ENIC_RSS_RETA_SIZE);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < reta_size; i++) {
+		idx = i / RTE_RETA_GROUP_SIZE;
+		shift = i % RTE_RETA_GROUP_SIZE;
+		if (reta_conf[idx].mask & (1ULL << shift))
+			reta_conf[idx].reta[shift] = enic_sop_rq_idx_to_rte_idx(
+				enic->rss_cpu.cpu[i / 4].b[i % 4]);
+	}
+
+	return 0;
+}
+
+static int enicpmd_dev_rss_reta_update(struct rte_eth_dev *dev,
+				       struct rte_eth_rss_reta_entry64
+				       *reta_conf,
+				       uint16_t reta_size)
+{
+	struct enic *enic = pmd_priv(dev);
+	union vnic_rss_cpu rss_cpu;
+	uint16_t i, idx, shift;
+
+	ENICPMD_FUNC_TRACE();
+	if (reta_size != ENIC_RSS_RETA_SIZE) {
+		dev_err(enic, "reta_update: wrong reta_size. given=%u"
+			" expected=%u\n",
+			reta_size, ENIC_RSS_RETA_SIZE);
+		return -EINVAL;
+	}
+	/*
+	 * Start with the current reta and modify it per reta_conf, as we
+	 * need to push the entire reta even if we only modify one entry.
+	 */
+	rss_cpu = enic->rss_cpu;
+	for (i = 0; i < reta_size; i++) {
+		idx = i / RTE_RETA_GROUP_SIZE;
+		shift = i % RTE_RETA_GROUP_SIZE;
+		if (reta_conf[idx].mask & (1ULL << shift))
+			rss_cpu.cpu[i / 4].b[i % 4] =
+				enic_rte_rq_idx_to_sop_idx(
+					reta_conf[idx].reta[shift]);
+	}
+	return enic_set_rss_reta(enic, &rss_cpu);
+}
+
+static int enicpmd_dev_rss_hash_update(struct rte_eth_dev *dev,
+				       struct rte_eth_rss_conf *rss_conf)
+{
+	struct enic *enic = pmd_priv(dev);
+
+	ENICPMD_FUNC_TRACE();
+	return enic_set_rss_conf(enic, rss_conf);
+}
+
+static int enicpmd_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
+					 struct rte_eth_rss_conf *rss_conf)
+{
+	struct enic *enic = pmd_priv(dev);
+
+	ENICPMD_FUNC_TRACE();
+	if (rss_conf == NULL)
+		return -EINVAL;
+	if (rss_conf->rss_key != NULL &&
+	    rss_conf->rss_key_len < ENIC_RSS_HASH_KEY_SIZE) {
+		dev_err(enic, "rss_hash_conf_get: wrong rss_key_len. given=%u"
+			" expected=%u+\n",
+			rss_conf->rss_key_len, ENIC_RSS_HASH_KEY_SIZE);
+		return -EINVAL;
+	}
+	rss_conf->rss_hf = enic->rss_hf;
+	if (rss_conf->rss_key != NULL) {
+		int i;
+		for (i = 0; i < ENIC_RSS_HASH_KEY_SIZE; i++) {
+			rss_conf->rss_key[i] =
+				enic->rss_key.key[i / 10].b[i % 10];
+		}
+		rss_conf->rss_key_len = ENIC_RSS_HASH_KEY_SIZE;
+	}
+	return 0;
+}
+
 static const struct eth_dev_ops enicpmd_eth_dev_ops = {
 	.dev_configure        = enicpmd_dev_configure,
 	.dev_start            = enicpmd_dev_start,
@@ -622,6 +725,10 @@ static const struct eth_dev_ops enicpmd_eth_dev_ops = {
 	.mac_addr_add         = enicpmd_add_mac_addr,
 	.mac_addr_remove      = enicpmd_remove_mac_addr,
 	.filter_ctrl          = enicpmd_dev_filter_ctrl,
+	.reta_query           = enicpmd_dev_rss_reta_query,
+	.reta_update          = enicpmd_dev_rss_reta_update,
+	.rss_hash_conf_get    = enicpmd_dev_rss_hash_conf_get,
+	.rss_hash_update      = enicpmd_dev_rss_hash_update,
 };
 
 struct enic *enicpmd_list_head = NULL;
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index ec9d343fd..f00e816a1 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -889,44 +889,42 @@ static int enic_dev_open(struct enic *enic)
 	return err;
 }
 
-static int enic_set_rsskey(struct enic *enic)
+static int enic_set_rsskey(struct enic *enic, uint8_t *user_key)
 {
 	dma_addr_t rss_key_buf_pa;
 	union vnic_rss_key *rss_key_buf_va = NULL;
-	static union vnic_rss_key rss_key = {
-		.key = {
-			[0] = {.b = {85, 67, 83, 97, 119, 101, 115, 111, 109, 101}},
-			[1] = {.b = {80, 65, 76, 79, 117, 110, 105, 113, 117, 101}},
-			[2] = {.b = {76, 73, 78, 85, 88, 114, 111, 99, 107, 115}},
-			[3] = {.b = {69, 78, 73, 67, 105, 115, 99, 111, 111, 108}},
-		}
-	};
-	int err;
+	int err, i;
 	u8 name[NAME_MAX];
 
+	RTE_ASSERT(use_key != NULL);
 	snprintf((char *)name, NAME_MAX, "rss_key-%s", enic->bdf_name);
 	rss_key_buf_va = enic_alloc_consistent(enic, sizeof(union vnic_rss_key),
 		&rss_key_buf_pa, name);
 	if (!rss_key_buf_va)
 		return -ENOMEM;
 
-	rte_memcpy(rss_key_buf_va, &rss_key, sizeof(union vnic_rss_key));
+	for (i = 0; i < ENIC_RSS_HASH_KEY_SIZE; i++)
+		rss_key_buf_va->key[i / 10].b[i % 10] = user_key[i];
 
 	err = enic_set_rss_key(enic,
 		rss_key_buf_pa,
 		sizeof(union vnic_rss_key));
 
+	/* Save for later queries */
+	if (!err) {
+		rte_memcpy(&enic->rss_key, rss_key_buf_va,
+			   sizeof(union vnic_rss_key));
+	}
 	enic_free_consistent(enic, sizeof(union vnic_rss_key),
 		rss_key_buf_va, rss_key_buf_pa);
 
 	return err;
 }
 
-static int enic_set_rsscpu(struct enic *enic, u8 rss_hash_bits)
+int enic_set_rss_reta(struct enic *enic, union vnic_rss_cpu *rss_cpu)
 {
 	dma_addr_t rss_cpu_buf_pa;
 	union vnic_rss_cpu *rss_cpu_buf_va = NULL;
-	int i;
 	int err;
 	u8 name[NAME_MAX];
 
@@ -936,9 +934,7 @@ static int enic_set_rsscpu(struct enic *enic, u8 rss_hash_bits)
 	if (!rss_cpu_buf_va)
 		return -ENOMEM;
 
-	for (i = 0; i < (1 << rss_hash_bits); i++)
-		(*rss_cpu_buf_va).cpu[i / 4].b[i % 4] =
-			enic_rte_rq_idx_to_sop_idx(i % enic->rq_count);
+	rte_memcpy(rss_cpu_buf_va, rss_cpu, sizeof(union vnic_rss_cpu));
 
 	err = enic_set_rss_cpu(enic,
 		rss_cpu_buf_pa,
@@ -947,6 +943,9 @@ static int enic_set_rsscpu(struct enic *enic, u8 rss_hash_bits)
 	enic_free_consistent(enic, sizeof(union vnic_rss_cpu),
 		rss_cpu_buf_va, rss_cpu_buf_pa);
 
+	/* Save for later queries */
+	if (!err)
+		rte_memcpy(&enic->rss_cpu, rss_cpu, sizeof(union vnic_rss_cpu));
 	return err;
 }
 
@@ -956,8 +955,6 @@ static int enic_set_niccfg(struct enic *enic, u8 rss_default_cpu,
 	const u8 tso_ipid_split_en = 0;
 	int err;
 
-	/* Enable VLAN tag stripping */
-
 	err = enic_set_nic_cfg(enic,
 		rss_default_cpu, rss_hash_type,
 		rss_hash_bits, rss_base_cpu,
@@ -967,47 +964,50 @@ static int enic_set_niccfg(struct enic *enic, u8 rss_default_cpu,
 	return err;
 }
 
-int enic_set_rss_nic_cfg(struct enic *enic)
+/* Initialize RSS with defaults, called from dev_configure */
+int enic_init_rss_nic_cfg(struct enic *enic)
 {
-	const u8 rss_default_cpu = 0;
-	const u8 rss_hash_type = NIC_CFG_RSS_HASH_TYPE_IPV4 |
-	    NIC_CFG_RSS_HASH_TYPE_TCP_IPV4 |
-	    NIC_CFG_RSS_HASH_TYPE_IPV6 |
-	    NIC_CFG_RSS_HASH_TYPE_TCP_IPV6;
-	const u8 rss_hash_bits = 7;
-	const u8 rss_base_cpu = 0;
-	u8 rss_enable = ENIC_SETTING(enic, RSS) && (enic->rq_count > 1);
-
-	if (rss_enable) {
-		if (!enic_set_rsskey(enic)) {
-			if (enic_set_rsscpu(enic, rss_hash_bits)) {
-				rss_enable = 0;
-				dev_warning(enic, "RSS disabled, "\
-					"Failed to set RSS cpu indirection table.");
-			}
-		} else {
-			rss_enable = 0;
-			dev_warning(enic,
-				"RSS disabled, Failed to set RSS key.\n");
+	static uint8_t default_rss_key[] = {
+		85, 67, 83, 97, 119, 101, 115, 111, 109, 101,
+		80, 65, 76, 79, 117, 110, 105, 113, 117, 101,
+		76, 73, 78, 85, 88, 114, 111, 99, 107, 115,
+		69, 78, 73, 67, 105, 115, 99, 111, 111, 108,
+	};
+	struct rte_eth_rss_conf rss_conf;
+	union vnic_rss_cpu rss_cpu;
+	int ret, i;
+
+	rss_conf = enic->rte_dev->data->dev_conf.rx_adv_conf.rss_conf;
+	/*
+	 * If setting key for the first time, and the user gives us none, then
+	 * push the default key to NIC.
+	 */
+	if (rss_conf.rss_key == NULL) {
+		rss_conf.rss_key = default_rss_key;
+		rss_conf.rss_key_len = ENIC_RSS_HASH_KEY_SIZE;
+	}
+	ret = enic_set_rss_conf(enic, &rss_conf);
+	if (ret) {
+		dev_err(enic, "Failed to configure RSS\n");
+		return ret;
+	}
+	if (enic->rss_enable) {
+		/* If enabling RSS, use the default reta */
+		for (i = 0; i < ENIC_RSS_RETA_SIZE; i++) {
+			rss_cpu.cpu[i / 4].b[i % 4] =
+				enic_rte_rq_idx_to_sop_idx(i % enic->rq_count);
 		}
+		ret = enic_set_rss_reta(enic, &rss_cpu);
+		if (ret)
+			dev_err(enic, "Failed to set RSS indirection table\n");
 	}
-
-	return enic_set_niccfg(enic, rss_default_cpu, rss_hash_type,
-		rss_hash_bits, rss_base_cpu, rss_enable);
+	return ret;
 }
 
 int enic_setup_finish(struct enic *enic)
 {
-	int ret;
-
 	enic_init_soft_stats(enic);
 
-	ret = enic_set_rss_nic_cfg(enic);
-	if (ret) {
-		dev_err(enic, "Failed to config nic, aborting.\n");
-		return -1;
-	}
-
 	/* Default conf */
 	vnic_dev_packet_filter(enic->vdev,
 		1 /* directed  */,
@@ -1022,6 +1022,98 @@ int enic_setup_finish(struct enic *enic)
 	return 0;
 }
 
+static int enic_rss_conf_valid(struct enic *enic,
+			       struct rte_eth_rss_conf *rss_conf)
+{
+	/* RSS is disabled per VIC settings. Ignore rss_conf. */
+	if (enic->flow_type_rss_offloads == 0)
+		return 0;
+	if (rss_conf->rss_key != NULL &&
+	    rss_conf->rss_key_len != ENIC_RSS_HASH_KEY_SIZE) {
+		dev_err(enic, "Given rss_key is %d bytes, it must be %d\n",
+			rss_conf->rss_key_len, ENIC_RSS_HASH_KEY_SIZE);
+		return -EINVAL;
+	}
+	if (rss_conf->rss_hf != 0 &&
+	    (rss_conf->rss_hf & enic->flow_type_rss_offloads) == 0) {
+		dev_err(enic, "Given rss_hf contains none of the supported"
+			" types\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* Set hash type and key according to rss_conf */
+int enic_set_rss_conf(struct enic *enic, struct rte_eth_rss_conf *rss_conf)
+{
+	struct rte_eth_dev *eth_dev;
+	uint64_t rss_hf;
+	u8 rss_hash_type;
+	u8 rss_enable;
+	int ret;
+
+	RTE_ASSERT(rss_conf != NULL);
+	ret = enic_rss_conf_valid(enic, rss_conf);
+	if (ret) {
+		dev_err(enic, "RSS configuration (rss_conf) is invalid\n");
+		return ret;
+	}
+
+	eth_dev = enic->rte_dev;
+	rss_hash_type = 0;
+	rss_hf = rss_conf->rss_hf & enic->flow_type_rss_offloads;
+	if (enic->rq_count > 1 &&
+	    (eth_dev->data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_RSS_FLAG) &&
+	    rss_hf != 0) {
+		rss_enable = 1;
+		if (rss_hf & ETH_RSS_IPV4)
+			rss_hash_type |= NIC_CFG_RSS_HASH_TYPE_IPV4;
+		if (rss_hf & ETH_RSS_NONFRAG_IPV4_TCP)
+			rss_hash_type |= NIC_CFG_RSS_HASH_TYPE_TCP_IPV4;
+		if (rss_hf & ETH_RSS_IPV6)
+			rss_hash_type |= NIC_CFG_RSS_HASH_TYPE_IPV6;
+		if (rss_hf & ETH_RSS_NONFRAG_IPV6_TCP)
+			rss_hash_type |= NIC_CFG_RSS_HASH_TYPE_TCP_IPV6;
+		if (rss_hf & ETH_RSS_IPV6_EX)
+			rss_hash_type |= NIC_CFG_RSS_HASH_TYPE_IPV6_EX;
+		if (rss_hf & ETH_RSS_IPV6_TCP_EX)
+			rss_hash_type |= NIC_CFG_RSS_HASH_TYPE_TCP_IPV6_EX;
+	} else {
+		rss_enable = 0;
+		rss_hf = 0;
+	}
+
+	/* Set the hash key if provided */
+	if (rss_enable && rss_conf->rss_key) {
+		ret = enic_set_rsskey(enic, rss_conf->rss_key);
+		if (ret) {
+			dev_err(enic, "Failed to set RSS key\n");
+			return ret;
+		}
+	}
+
+	ret = enic_set_niccfg(enic, ENIC_RSS_DEFAULT_CPU, rss_hash_type,
+			      ENIC_RSS_HASH_BITS, ENIC_RSS_BASE_CPU,
+			      rss_enable);
+	if (!ret) {
+		enic->rss_hf = rss_hf;
+		enic->rss_hash_type = rss_hash_type;
+		enic->rss_enable = rss_enable;
+	}
+	return 0;
+}
+
+int enic_set_vlan_strip(struct enic *enic)
+{
+	/*
+	 * Unfortunately, VLAN strip on/off and RSS on/off are configured
+	 * together. So, re-do niccfg, preserving the current RSS settings.
+	 */
+	return enic_set_niccfg(enic, ENIC_RSS_DEFAULT_CPU, enic->rss_hash_type,
+			       ENIC_RSS_HASH_BITS, ENIC_RSS_BASE_CPU,
+			       enic->rss_enable);
+}
+
 void enic_add_packet_filter(struct enic *enic)
 {
 	/* Args -> directed, multicast, broadcast, promisc, allmulti */
diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c
index c99d61837..d8f7892c3 100644
--- a/drivers/net/enic/enic_res.c
+++ b/drivers/net/enic/enic_res.c
@@ -128,6 +128,26 @@ int enic_get_vnic_config(struct enic *enic)
 		c->intr_timer_usec,
 		c->loop_tag);
 
+	/* RSS settings from vNIC */
+	enic->reta_size = ENIC_RSS_RETA_SIZE;
+	enic->hash_key_size = ENIC_RSS_HASH_KEY_SIZE;
+	enic->flow_type_rss_offloads = 0;
+	if (ENIC_SETTING(enic, RSSHASH_IPV4))
+		enic->flow_type_rss_offloads |= ETH_RSS_IPV4;
+	if (ENIC_SETTING(enic, RSSHASH_TCPIPV4))
+		enic->flow_type_rss_offloads |= ETH_RSS_NONFRAG_IPV4_TCP;
+	if (ENIC_SETTING(enic, RSSHASH_IPV6))
+		enic->flow_type_rss_offloads |= ETH_RSS_IPV6;
+	if (ENIC_SETTING(enic, RSSHASH_TCPIPV6))
+		enic->flow_type_rss_offloads |= ETH_RSS_NONFRAG_IPV6_TCP;
+	if (ENIC_SETTING(enic, RSSHASH_IPV6_EX))
+		enic->flow_type_rss_offloads |= ETH_RSS_IPV6_EX;
+	if (ENIC_SETTING(enic, RSSHASH_TCPIPV6_EX))
+		enic->flow_type_rss_offloads |= ETH_RSS_IPV6_TCP_EX;
+	/* Zero offloads if RSS is not enabled */
+	if (!ENIC_SETTING(enic, RSS))
+		enic->flow_type_rss_offloads = 0;
+
 	return 0;
 }
 
diff --git a/drivers/net/enic/enic_res.h b/drivers/net/enic/enic_res.h
index cf3a6fde8..e68f1307b 100644
--- a/drivers/net/enic/enic_res.h
+++ b/drivers/net/enic/enic_res.h
@@ -31,6 +31,12 @@
 #define ENIC_DEFAULT_RX_FREE_THRESH	32
 #define ENIC_TX_XMIT_MAX		64
 
+#define ENIC_RSS_DEFAULT_CPU    0
+#define ENIC_RSS_BASE_CPU       0
+#define ENIC_RSS_HASH_BITS      7
+#define ENIC_RSS_RETA_SIZE      (1 << ENIC_RSS_HASH_BITS)
+#define ENIC_RSS_HASH_KEY_SIZE  40
+
 #define ENIC_SETTING(enic, f) ((enic->config.flags & VENETF_##f) ? 1 : 0)
 
 
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 03/10] net/enic: heed the requested max Rx packet size
  2018-03-08  2:46       ` [PATCH v3 00/10] enic PMD patchset John Daley
  2018-03-08  2:46         ` [PATCH v3 01/10] net/enic: remove 'extern' in .h file function declarations John Daley
  2018-03-08  2:46         ` [PATCH v3 02/10] net/enic: allow the user to change RSS settings John Daley
@ 2018-03-08  2:46         ` John Daley
  2018-03-09 15:03           ` Ferruh Yigit
  2018-03-08  2:46         ` [PATCH v3 04/10] net/enic: remove the VLAN filter handler John Daley
                           ` (7 subsequent siblings)
  10 siblings, 1 reply; 44+ messages in thread
From: John Daley @ 2018-03-08  2:46 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

Currently, enic completely ignores the requested max Rx packet size
(rxmode.max_rx_pkt_len). The desired behavior is that the NIC hardware
drops packets larger than the requested size, even though they are
still smaller than MTU.

Cisco VIC does not have such a feature. But, we can accomplish a
similar (not same) effect by reducing the size of posted receive
buffers. Packets larger than the posted size get truncated, and the
receive handler drops them. This is also how the kernel enic driver
enforces the Rx side MTU.

This workaround works only when scatter mode is *not* used. When
scatter is used, there is currently no way to support
rxmode.max_rx_pkt_len, as the NIC always receives packets up to MTU.

For posterity, add a copious amount of comments regarding the
hardware's drop/receive behavior with respect to max/current MTU.

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 doc/guides/nics/enic.rst       |  1 +
 drivers/net/enic/enic.h        |  7 ++++++
 drivers/net/enic/enic_ethdev.c |  9 +++++++-
 drivers/net/enic/enic_main.c   | 49 ++++++++++++++++++++++++++++++++++++------
 4 files changed, 58 insertions(+), 8 deletions(-)

diff --git a/doc/guides/nics/enic.rst b/doc/guides/nics/enic.rst
index 4dffce1a6..0e655e9e3 100644
--- a/doc/guides/nics/enic.rst
+++ b/doc/guides/nics/enic.rst
@@ -371,6 +371,7 @@ Known bugs and unsupported features in this release
 - Setting of extended VLAN
 - UDP RSS hashing
 - MTU update only works if Scattered Rx mode is disabled
+- Maximum receive packet length is ignored if Scattered Rx mode is used
 
 Prerequisites
 -------------
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index d29939c94..1b3813a58 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -162,6 +162,13 @@ struct enic {
 	union vnic_rss_cpu rss_cpu;
 };
 
+/* Compute ethdev's max packet size from MTU */
+static inline uint32_t enic_mtu_to_max_rx_pktlen(uint32_t mtu)
+{
+	/* ethdev max size includes eth and crc whereas NIC MTU does not */
+	return mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
+}
+
 /* Get the CQ index from a Start of Packet(SOP) RQ index */
 static inline unsigned int enic_sop_rq_idx_to_cq_idx(unsigned int sop_idx)
 {
diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
index cbab7029b..bdbaf4cdf 100644
--- a/drivers/net/enic/enic_ethdev.c
+++ b/drivers/net/enic/enic_ethdev.c
@@ -470,7 +470,14 @@ static void enicpmd_dev_info_get(struct rte_eth_dev *eth_dev,
 	device_info->max_rx_queues = enic->conf_rq_count / 2;
 	device_info->max_tx_queues = enic->conf_wq_count;
 	device_info->min_rx_bufsize = ENIC_MIN_MTU;
-	device_info->max_rx_pktlen = enic->max_mtu + ETHER_HDR_LEN + 4;
+	/* "Max" mtu is not a typo. HW receives packet sizes up to the
+	 * max mtu regardless of the current mtu (vNIC's mtu). vNIC mtu is
+	 * a hint to the driver to size receive buffers accordingly so that
+	 * larger-than-vnic-mtu packets get truncated.. For DPDK, we let
+	 * the user decide the buffer size via rxmode.max_rx_pkt_len, basically
+	 * ignoring vNIC mtu.
+	 */
+	device_info->max_rx_pktlen = enic_mtu_to_max_rx_pktlen(enic->max_mtu);
 	device_info->max_mac_addrs = ENIC_MAX_MAC_ADDR;
 	device_info->rx_offload_capa =
 		DEV_RX_OFFLOAD_VLAN_STRIP |
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index f00e816a1..d4f478b5e 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -266,6 +266,8 @@ enic_alloc_rx_queue_mbufs(struct enic *enic, struct vnic_rq *rq)
 	struct rq_enet_desc *rqd = rq->ring.descs;
 	unsigned i;
 	dma_addr_t dma_addr;
+	uint32_t max_rx_pkt_len;
+	uint16_t rq_buf_len;
 
 	if (!rq->in_use)
 		return 0;
@@ -273,6 +275,18 @@ enic_alloc_rx_queue_mbufs(struct enic *enic, struct vnic_rq *rq)
 	dev_debug(enic, "queue %u, allocating %u rx queue mbufs\n", rq->index,
 		  rq->ring.desc_count);
 
+	/*
+	 * If *not* using scatter and the mbuf size is smaller than the
+	 * requested max packet size (max_rx_pkt_len), then reduce the
+	 * posted buffer size to max_rx_pkt_len. HW still receives packets
+	 * larger than max_rx_pkt_len, but they will be truncated, which we
+	 * drop in the rx handler. Not ideal, but better than returning
+	 * large packets when the user is not expecting them.
+	 */
+	max_rx_pkt_len = enic->rte_dev->data->dev_conf.rxmode.max_rx_pkt_len;
+	rq_buf_len = rte_pktmbuf_data_room_size(rq->mp) - RTE_PKTMBUF_HEADROOM;
+	if (max_rx_pkt_len < rq_buf_len && !rq->data_queue_enable)
+		rq_buf_len = max_rx_pkt_len;
 	for (i = 0; i < rq->ring.desc_count; i++, rqd++) {
 		mb = rte_mbuf_raw_alloc(rq->mp);
 		if (mb == NULL) {
@@ -287,7 +301,7 @@ enic_alloc_rx_queue_mbufs(struct enic *enic, struct vnic_rq *rq)
 		rq_enet_desc_enc(rqd, dma_addr,
 				(rq->is_sop ? RQ_ENET_TYPE_ONLY_SOP
 				: RQ_ENET_TYPE_NOT_SOP),
-				mb->buf_len - RTE_PKTMBUF_HEADROOM);
+				rq_buf_len);
 		rq->mbuf_ring[i] = mb;
 	}
 
@@ -581,7 +595,7 @@ int enic_alloc_rq(struct enic *enic, uint16_t queue_idx,
 	unsigned int mbuf_size, mbufs_per_pkt;
 	unsigned int nb_sop_desc, nb_data_desc;
 	uint16_t min_sop, max_sop, min_data, max_data;
-	uint16_t mtu = enic->rte_dev->data->mtu;
+	uint32_t max_rx_pkt_len;
 
 	rq_sop->is_sop = 1;
 	rq_sop->data_queue_idx = data_queue_idx;
@@ -599,22 +613,42 @@ int enic_alloc_rq(struct enic *enic, uint16_t queue_idx,
 
 	mbuf_size = (uint16_t)(rte_pktmbuf_data_room_size(mp) -
 			       RTE_PKTMBUF_HEADROOM);
+	/* max_rx_pkt_len includes the ethernet header and CRC. */
+	max_rx_pkt_len = enic->rte_dev->data->dev_conf.rxmode.max_rx_pkt_len;
 
 	if (enic->rte_dev->data->dev_conf.rxmode.offloads &
 	    DEV_RX_OFFLOAD_SCATTER) {
 		dev_info(enic, "Rq %u Scatter rx mode enabled\n", queue_idx);
-		/* ceil((mtu + ETHER_HDR_LEN + 4)/mbuf_size) */
-		mbufs_per_pkt = ((mtu + ETHER_HDR_LEN + 4) +
-				 (mbuf_size - 1)) / mbuf_size;
+		/* ceil((max pkt len)/mbuf_size) */
+		mbufs_per_pkt = (max_rx_pkt_len + mbuf_size - 1) / mbuf_size;
 	} else {
 		dev_info(enic, "Scatter rx mode disabled\n");
 		mbufs_per_pkt = 1;
+		if (max_rx_pkt_len > mbuf_size) {
+			dev_warning(enic, "The maximum Rx packet size (%u) is"
+				    " larger than the mbuf size (%u), and"
+				    " scatter is disabled. Larger packets will"
+				    " be truncated.\n",
+				    max_rx_pkt_len, mbuf_size);
+		}
 	}
 
 	if (mbufs_per_pkt > 1) {
 		dev_info(enic, "Rq %u Scatter rx mode in use\n", queue_idx);
 		rq_sop->data_queue_enable = 1;
 		rq_data->in_use = 1;
+		/*
+		 * HW does not directly support rxmode.max_rx_pkt_len. HW always
+		 * receives packet sizes up to the "max" MTU.
+		 * If not using scatter, we can achieve the effect of dropping
+		 * larger packets by reducing the size of posted buffers.
+		 * See enic_alloc_rx_queue_mbufs().
+		 */
+		if (max_rx_pkt_len <
+		    enic_mtu_to_max_rx_pktlen(enic->rte_dev->data->mtu)) {
+			dev_warning(enic, "rxmode.max_rx_pkt_len is ignored"
+				    " when scatter rx mode is in use.\n");
+		}
 	} else {
 		dev_info(enic, "Rq %u Scatter rx mode not being used\n",
 			 queue_idx);
@@ -654,8 +688,9 @@ int enic_alloc_rq(struct enic *enic, uint16_t queue_idx,
 		nb_data_desc = max_data;
 	}
 	if (mbufs_per_pkt > 1) {
-		dev_info(enic, "For mtu %d and mbuf size %d valid rx descriptor range is %d to %d\n",
-			 mtu, mbuf_size, min_sop + min_data,
+		dev_info(enic, "For max packet size %u and mbuf size %u valid"
+			 " rx descriptor range is %u to %u\n",
+			 max_rx_pkt_len, mbuf_size, min_sop + min_data,
 			 max_sop + max_data);
 	}
 	dev_info(enic, "Using %d rx descriptors (sop %d, data %d)\n",
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 04/10] net/enic: remove the VLAN filter handler
  2018-03-08  2:46       ` [PATCH v3 00/10] enic PMD patchset John Daley
                           ` (2 preceding siblings ...)
  2018-03-08  2:46         ` [PATCH v3 03/10] net/enic: heed the requested max Rx packet size John Daley
@ 2018-03-08  2:46         ` John Daley
  2018-03-08  2:46         ` [PATCH v3 05/10] net/enic: add Rx/Tx queue configuration getters John Daley
                           ` (6 subsequent siblings)
  10 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-03-08  2:46 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

VIC does not support VLAN filtering at the moment. The firmware does
accept the filter add/del commands and returns success. But, they are
no-ops. To avoid confusion, remove the filter set handler so the app
sees an error instead of silent failure.

Also during the device configure time, enicpmd_vlan_offload_set would
not print a warning message about unsupported VLAN filtering, because
the caller specifies only ETH_VLAN_STRIP_MASK. This is wrong, as we
should attempt to apply all requested offloads at the configure
time. So, pass all VLAN offload masks, which triggers a warning
message about VLAN filtering, if requested.

Finally, enicpmd_vlan_offload_set should check both mask and
rxmode.offloads, not just mask.

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 drivers/net/enic/enic_ethdev.c | 34 ++++++++++++++--------------------
 1 file changed, 14 insertions(+), 20 deletions(-)

diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
index bdbaf4cdf..e5523e311 100644
--- a/drivers/net/enic/enic_ethdev.c
+++ b/drivers/net/enic/enic_ethdev.c
@@ -318,40 +318,29 @@ static int enicpmd_dev_rx_queue_setup(struct rte_eth_dev *eth_dev,
 	return enicpmd_dev_setup_intr(enic);
 }
 
-static int enicpmd_vlan_filter_set(struct rte_eth_dev *eth_dev,
-	uint16_t vlan_id, int on)
-{
-	struct enic *enic = pmd_priv(eth_dev);
-	int err;
-
-	ENICPMD_FUNC_TRACE();
-	if (on)
-		err = enic_add_vlan(enic, vlan_id);
-	else
-		err = enic_del_vlan(enic, vlan_id);
-	return err;
-}
-
 static int enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 {
 	struct enic *enic = pmd_priv(eth_dev);
+	uint64_t offloads;
 
 	ENICPMD_FUNC_TRACE();
 
+	offloads = eth_dev->data->dev_conf.rxmode.offloads;
 	if (mask & ETH_VLAN_STRIP_MASK) {
-		if (eth_dev->data->dev_conf.rxmode.offloads &
-		    DEV_RX_OFFLOAD_VLAN_STRIP)
+		if (offloads & DEV_RX_OFFLOAD_VLAN_STRIP)
 			enic->ig_vlan_strip_en = 1;
 		else
 			enic->ig_vlan_strip_en = 0;
 	}
 
-	if (mask & ETH_VLAN_FILTER_MASK) {
+	if ((mask & ETH_VLAN_FILTER_MASK) &&
+	    (offloads & DEV_RX_OFFLOAD_VLAN_FILTER)) {
 		dev_warning(enic,
 			"Configuration of VLAN filter is not supported\n");
 	}
 
-	if (mask & ETH_VLAN_EXTEND_MASK) {
+	if ((mask & ETH_VLAN_EXTEND_MASK) &&
+	    (offloads & DEV_RX_OFFLOAD_VLAN_EXTEND)) {
 		dev_warning(enic,
 			"Configuration of extended VLAN is not supported\n");
 	}
@@ -362,6 +351,7 @@ static int enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 static int enicpmd_dev_configure(struct rte_eth_dev *eth_dev)
 {
 	int ret;
+	int mask;
 	struct enic *enic = pmd_priv(eth_dev);
 
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
@@ -376,7 +366,11 @@ static int enicpmd_dev_configure(struct rte_eth_dev *eth_dev)
 
 	enic->hw_ip_checksum = !!(eth_dev->data->dev_conf.rxmode.offloads &
 				  DEV_RX_OFFLOAD_CHECKSUM);
-	ret = enicpmd_vlan_offload_set(eth_dev, ETH_VLAN_STRIP_MASK);
+	/* All vlan offload masks to apply the current settings */
+	mask = ETH_VLAN_STRIP_MASK |
+		ETH_VLAN_FILTER_MASK |
+		ETH_VLAN_EXTEND_MASK;
+	ret = enicpmd_vlan_offload_set(eth_dev, mask);
 	if (ret) {
 		dev_err(enic, "Failed to configure VLAN offloads\n");
 		return ret;
@@ -710,7 +704,7 @@ static const struct eth_dev_ops enicpmd_eth_dev_ops = {
 	.dev_infos_get        = enicpmd_dev_info_get,
 	.dev_supported_ptypes_get = enicpmd_dev_supported_ptypes_get,
 	.mtu_set              = enicpmd_mtu_set,
-	.vlan_filter_set      = enicpmd_vlan_filter_set,
+	.vlan_filter_set      = NULL,
 	.vlan_tpid_set        = NULL,
 	.vlan_offload_set     = enicpmd_vlan_offload_set,
 	.vlan_strip_queue_set = NULL,
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 05/10] net/enic: add Rx/Tx queue configuration getters
  2018-03-08  2:46       ` [PATCH v3 00/10] enic PMD patchset John Daley
                           ` (3 preceding siblings ...)
  2018-03-08  2:46         ` [PATCH v3 04/10] net/enic: remove the VLAN filter handler John Daley
@ 2018-03-08  2:46         ` John Daley
  2018-03-08  2:46         ` [PATCH v3 06/10] net/enic: allocate stats DMA buffer upfront during probe John Daley
                           ` (5 subsequent siblings)
  10 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-03-08  2:46 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 drivers/net/enic/enic_ethdev.c | 76 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 65 insertions(+), 11 deletions(-)

diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
index e5523e311..6dd72729e 100644
--- a/drivers/net/enic/enic_ethdev.c
+++ b/drivers/net/enic/enic_ethdev.c
@@ -39,6 +39,19 @@ static const struct rte_pci_id pci_id_enic_map[] = {
 	{.vendor_id = 0, /* sentinel */},
 };
 
+#define ENIC_TX_OFFLOAD_CAPA (			\
+		DEV_TX_OFFLOAD_VLAN_INSERT |	\
+		DEV_TX_OFFLOAD_IPV4_CKSUM  |	\
+		DEV_TX_OFFLOAD_UDP_CKSUM   |	\
+		DEV_TX_OFFLOAD_TCP_CKSUM   |	\
+		DEV_TX_OFFLOAD_TCP_TSO)
+
+#define ENIC_RX_OFFLOAD_CAPA (			\
+		DEV_RX_OFFLOAD_VLAN_STRIP |	\
+		DEV_RX_OFFLOAD_IPV4_CKSUM |	\
+		DEV_RX_OFFLOAD_UDP_CKSUM  |	\
+		DEV_RX_OFFLOAD_TCP_CKSUM)
+
 RTE_INIT(enicpmd_init_log);
 static void
 enicpmd_init_log(void)
@@ -473,17 +486,8 @@ static void enicpmd_dev_info_get(struct rte_eth_dev *eth_dev,
 	 */
 	device_info->max_rx_pktlen = enic_mtu_to_max_rx_pktlen(enic->max_mtu);
 	device_info->max_mac_addrs = ENIC_MAX_MAC_ADDR;
-	device_info->rx_offload_capa =
-		DEV_RX_OFFLOAD_VLAN_STRIP |
-		DEV_RX_OFFLOAD_IPV4_CKSUM |
-		DEV_RX_OFFLOAD_UDP_CKSUM  |
-		DEV_RX_OFFLOAD_TCP_CKSUM;
-	device_info->tx_offload_capa =
-		DEV_TX_OFFLOAD_VLAN_INSERT |
-		DEV_TX_OFFLOAD_IPV4_CKSUM  |
-		DEV_TX_OFFLOAD_UDP_CKSUM   |
-		DEV_TX_OFFLOAD_TCP_CKSUM   |
-		DEV_TX_OFFLOAD_TCP_TSO;
+	device_info->rx_offload_capa = ENIC_RX_OFFLOAD_CAPA;
+	device_info->tx_offload_capa = ENIC_TX_OFFLOAD_CAPA;
 	device_info->default_rxconf = (struct rte_eth_rxconf) {
 		.rx_free_thresh = ENIC_DEFAULT_RX_FREE_THRESH
 	};
@@ -686,6 +690,54 @@ static int enicpmd_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
 	return 0;
 }
 
+static void enicpmd_dev_rxq_info_get(struct rte_eth_dev *dev,
+				     uint16_t rx_queue_id,
+				     struct rte_eth_rxq_info *qinfo)
+{
+	struct enic *enic = pmd_priv(dev);
+	struct vnic_rq *rq_sop;
+	struct vnic_rq *rq_data;
+	struct rte_eth_rxconf *conf;
+	uint16_t sop_queue_idx;
+	uint16_t data_queue_idx;
+
+	ENICPMD_FUNC_TRACE();
+	sop_queue_idx = enic_rte_rq_idx_to_sop_idx(rx_queue_id);
+	data_queue_idx = enic_rte_rq_idx_to_data_idx(rx_queue_id);
+	rq_sop = &enic->rq[sop_queue_idx];
+	rq_data = &enic->rq[data_queue_idx]; /* valid if data_queue_enable */
+	qinfo->mp = rq_sop->mp;
+	qinfo->scattered_rx = rq_sop->data_queue_enable;
+	qinfo->nb_desc = rq_sop->ring.desc_count;
+	if (qinfo->scattered_rx)
+		qinfo->nb_desc += rq_data->ring.desc_count;
+	conf = &qinfo->conf;
+	memset(conf, 0, sizeof(*conf));
+	conf->rx_free_thresh = rq_sop->rx_free_thresh;
+	conf->rx_drop_en = 1;
+	/*
+	 * Except VLAN stripping (port setting), all the checksum offloads
+	 * are always enabled.
+	 */
+	conf->offloads = ENIC_RX_OFFLOAD_CAPA;
+	if (!enic->ig_vlan_strip_en)
+		conf->offloads &= ~DEV_RX_OFFLOAD_VLAN_STRIP;
+	/* rx_thresh and other fields are not applicable for enic */
+}
+
+static void enicpmd_dev_txq_info_get(struct rte_eth_dev *dev,
+				     __rte_unused uint16_t tx_queue_id,
+				     struct rte_eth_txq_info *qinfo)
+{
+	struct enic *enic = pmd_priv(dev);
+
+	ENICPMD_FUNC_TRACE();
+	qinfo->nb_desc = enic->config.wq_desc_count;
+	memset(&qinfo->conf, 0, sizeof(qinfo->conf));
+	qinfo->conf.offloads = ENIC_TX_OFFLOAD_CAPA; /* not configurable */
+	/* tx_thresh, and all the other fields are not applicable for enic */
+}
+
 static const struct eth_dev_ops enicpmd_eth_dev_ops = {
 	.dev_configure        = enicpmd_dev_configure,
 	.dev_start            = enicpmd_dev_start,
@@ -718,6 +770,8 @@ static const struct eth_dev_ops enicpmd_eth_dev_ops = {
 	.rx_descriptor_done   = NULL,
 	.tx_queue_setup       = enicpmd_dev_tx_queue_setup,
 	.tx_queue_release     = enicpmd_dev_tx_queue_release,
+	.rxq_info_get         = enicpmd_dev_rxq_info_get,
+	.txq_info_get         = enicpmd_dev_txq_info_get,
 	.dev_led_on           = NULL,
 	.dev_led_off          = NULL,
 	.flow_ctrl_get        = NULL,
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 06/10] net/enic: allocate stats DMA buffer upfront during probe
  2018-03-08  2:46       ` [PATCH v3 00/10] enic PMD patchset John Daley
                           ` (4 preceding siblings ...)
  2018-03-08  2:46         ` [PATCH v3 05/10] net/enic: add Rx/Tx queue configuration getters John Daley
@ 2018-03-08  2:46         ` John Daley
  2018-03-08  2:46         ` [PATCH v3 07/10] net/enic: support Rx queue interrupts John Daley
                           ` (4 subsequent siblings)
  10 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-03-08  2:46 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim, stable

From: Hyong Youb Kim <hyonkim@cisco.com>

The driver provides a DMA buffer to the firmware when it requests port
stats. The NIC then fills that buffer with latest stats. Currently,
the driver allocates the DMA buffer the first time it requests stats
and saves it for later use. This can lead to crashes when
primary/secondary processes are involved. For example, the following
sequence crashes the secondary process.

1. Start a primary app that does not call rte_eth_stats_get()
2. dpdk-procinfo -- --stats

dpdk-procinfo crashes while trying to allocate the stats DMA buffer
because the alloc function pointer (vdev.alloc_consistent) is valid
only in the primary process, not in the secondary process.

Overwriting the alloc function pointer in the secondary process is not
an option, as it will simply make the pointer invalid in the primary
process. Instead, allocate the DMA buffer during probe so that only
the primary process does both allocate and free. This allows the
secondary process to dump stats as well.

Cc: stable@dpdk.org
Fixes: 9913fbb91df0 ("enic/base: common code")

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 drivers/net/enic/base/vnic_dev.c | 24 ++++++++++++++----------
 drivers/net/enic/base/vnic_dev.h |  1 +
 drivers/net/enic/enic_main.c     |  9 +++++++++
 3 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/drivers/net/enic/base/vnic_dev.c b/drivers/net/enic/base/vnic_dev.c
index 05b595eb8..1f8d222fc 100644
--- a/drivers/net/enic/base/vnic_dev.c
+++ b/drivers/net/enic/base/vnic_dev.c
@@ -587,17 +587,9 @@ int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats)
 {
 	u64 a0, a1;
 	int wait = 1000;
-	static u32 instance;
-	char name[NAME_MAX];
 
-	if (!vdev->stats) {
-		snprintf((char *)name, sizeof(name),
-			"vnic_stats-%u", instance++);
-		vdev->stats = vdev->alloc_consistent(vdev->priv,
-			sizeof(struct vnic_stats), &vdev->stats_pa, (u8 *)name);
-		if (!vdev->stats)
-			return -ENOMEM;
-	}
+	if (!vdev->stats)
+		return -ENOMEM;
 
 	*stats = vdev->stats;
 	a0 = vdev->stats_pa;
@@ -922,6 +914,18 @@ u32 vnic_dev_get_intr_coal_timer_max(struct vnic_dev *vdev)
 	return vdev->intr_coal_timer_info.max_usec;
 }
 
+int vnic_dev_alloc_stats_mem(struct vnic_dev *vdev)
+{
+	char name[NAME_MAX];
+	static u32 instance;
+
+	snprintf((char *)name, sizeof(name), "vnic_stats-%u", instance++);
+	vdev->stats = vdev->alloc_consistent(vdev->priv,
+					     sizeof(struct vnic_stats),
+					     &vdev->stats_pa, (u8 *)name);
+	return vdev->stats == NULL ? -ENOMEM : 0;
+}
+
 void vnic_dev_unregister(struct vnic_dev *vdev)
 {
 	if (vdev) {
diff --git a/drivers/net/enic/base/vnic_dev.h b/drivers/net/enic/base/vnic_dev.h
index 8c0992063..7e5736b4d 100644
--- a/drivers/net/enic/base/vnic_dev.h
+++ b/drivers/net/enic/base/vnic_dev.h
@@ -165,6 +165,7 @@ struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
 	void *priv, struct rte_pci_device *pdev, struct vnic_dev_bar *bar,
 	unsigned int num_bars);
 struct rte_pci_device *vnic_dev_get_pdev(struct vnic_dev *vdev);
+int vnic_dev_alloc_stats_mem(struct vnic_dev *vdev);
 int vnic_dev_cmd_init(struct vnic_dev *vdev, int fallback);
 int vnic_dev_get_size(void);
 int vnic_dev_int13(struct vnic_dev *vdev, u64 arg, u32 op);
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index d4f478b5e..bd4447f01 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -1478,6 +1478,15 @@ int enic_probe(struct enic *enic)
 		enic_alloc_consistent,
 		enic_free_consistent);
 
+	/*
+	 * Allocate the consistent memory for stats upfront so both primary and
+	 * secondary processes can dump stats.
+	 */
+	err = vnic_dev_alloc_stats_mem(enic->vdev);
+	if (err) {
+		dev_err(enic, "Failed to allocate cmd memory, aborting\n");
+		goto err_out_unregister;
+	}
 	/* Issue device open to get device in known state */
 	err = enic_dev_open(enic);
 	if (err) {
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 07/10] net/enic: support Rx queue interrupts
  2018-03-08  2:46       ` [PATCH v3 00/10] enic PMD patchset John Daley
                           ` (5 preceding siblings ...)
  2018-03-08  2:46         ` [PATCH v3 06/10] net/enic: allocate stats DMA buffer upfront during probe John Daley
@ 2018-03-08  2:46         ` John Daley
  2018-03-08  2:47         ` [PATCH v3 08/10] doc: describe Rx bytes counter behavior for enic John Daley
                           ` (3 subsequent siblings)
  10 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-03-08  2:46 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

Enable rx queue interrupts if the app requests them, and vNIC has
enough interrupt resources. Use interrupt vector 0 for link status and
errors. Use vector 1 for rx queue 0, vector 2 for rx queue 1, and so
on. So, with n rx queues, vNIC needs to have at n + 1 interrupts.

For VIC, enabling and disabling rx queue interrupts are simply
mask/unmask operations. VIC's credit based interrupt moderation is not
used, as the app wants to explicitly control when to enable/disable
interrupts.

This version requires MSI-X (vfio-pci). Sharing one interrupt for link
status and rx queues is possible, but is rather complex and has no
user demands.

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 doc/guides/nics/enic.rst          |   7 ++-
 doc/guides/nics/features/enic.ini |   1 +
 drivers/net/enic/enic.h           |  15 ++++-
 drivers/net/enic/enic_ethdev.c    |  22 +++++++
 drivers/net/enic/enic_main.c      | 123 ++++++++++++++++++++++++++++++++------
 drivers/net/enic/enic_res.c       |   3 +-
 6 files changed, 149 insertions(+), 22 deletions(-)

diff --git a/doc/guides/nics/enic.rst b/doc/guides/nics/enic.rst
index 0e655e9e3..7e19cf88a 100644
--- a/doc/guides/nics/enic.rst
+++ b/doc/guides/nics/enic.rst
@@ -114,11 +114,16 @@ Configuration information
 
   - **Interrupts**
 
-    Only one interrupt per vNIC interface should be configured in the UCS
+    At least one interrupt per vNIC interface should be configured in the UCS
     manager regardless of the number receive/transmit queues. The ENIC PMD
     uses this interrupt to get information about link status and errors
     in the fast path.
 
+    In addition to the interrupt for link status and errors, when using Rx queue
+    interrupts, increase the number of configured interrupts so that there is at
+    least one interrupt for each Rx queue. For example, if the app uses 3 Rx
+    queues and wants to use per-queue interrupts, configure 4 (3 + 1) interrupts.
+
 .. _enic-flow-director:
 
 Flow director support
diff --git a/doc/guides/nics/features/enic.ini b/doc/guides/nics/features/enic.ini
index e79d7277d..ea171a45b 100644
--- a/doc/guides/nics/features/enic.ini
+++ b/doc/guides/nics/features/enic.ini
@@ -6,6 +6,7 @@
 [Features]
 Link status          = Y
 Link status event    = Y
+Rx interrupt         = Y
 Queue start/stop     = Y
 MTU update           = Y
 Jumbo frame          = Y
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index 1b3813a58..adccc8ac5 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -49,6 +49,15 @@
 
 #define ENICPMD_FDIR_MAX           64
 
+/*
+ * Interrupt 0: LSC and errors
+ * Interrupt 1: rx queue 0
+ * Interrupt 2: rx queue 1
+ * ...
+ */
+#define ENICPMD_LSC_INTR_OFFSET 0
+#define ENICPMD_RXQ_INTR_OFFSET 1
+
 struct enic_fdir_node {
 	struct rte_eth_fdir_filter filter;
 	u16 fltr_id;
@@ -126,9 +135,9 @@ struct enic {
 	struct vnic_cq *cq;
 	unsigned int cq_count; /* equals rq_count + wq_count */
 
-	/* interrupt resource */
-	struct vnic_intr intr;
-	unsigned int intr_count;
+	/* interrupt vectors (len = conf_intr_count) */
+	struct vnic_intr *intr;
+	unsigned int intr_count; /* equals enabled interrupts (lsc + rxqs) */
 
 	/* software counters */
 	struct enic_soft_stats soft_stats;
diff --git a/drivers/net/enic/enic_ethdev.c b/drivers/net/enic/enic_ethdev.c
index 6dd72729e..2a289b6a4 100644
--- a/drivers/net/enic/enic_ethdev.c
+++ b/drivers/net/enic/enic_ethdev.c
@@ -738,6 +738,26 @@ static void enicpmd_dev_txq_info_get(struct rte_eth_dev *dev,
 	/* tx_thresh, and all the other fields are not applicable for enic */
 }
 
+static int enicpmd_dev_rx_queue_intr_enable(struct rte_eth_dev *eth_dev,
+					    uint16_t rx_queue_id)
+{
+	struct enic *enic = pmd_priv(eth_dev);
+
+	ENICPMD_FUNC_TRACE();
+	vnic_intr_unmask(&enic->intr[rx_queue_id + ENICPMD_RXQ_INTR_OFFSET]);
+	return 0;
+}
+
+static int enicpmd_dev_rx_queue_intr_disable(struct rte_eth_dev *eth_dev,
+					     uint16_t rx_queue_id)
+{
+	struct enic *enic = pmd_priv(eth_dev);
+
+	ENICPMD_FUNC_TRACE();
+	vnic_intr_mask(&enic->intr[rx_queue_id + ENICPMD_RXQ_INTR_OFFSET]);
+	return 0;
+}
+
 static const struct eth_dev_ops enicpmd_eth_dev_ops = {
 	.dev_configure        = enicpmd_dev_configure,
 	.dev_start            = enicpmd_dev_start,
@@ -770,6 +790,8 @@ static const struct eth_dev_ops enicpmd_eth_dev_ops = {
 	.rx_descriptor_done   = NULL,
 	.tx_queue_setup       = enicpmd_dev_tx_queue_setup,
 	.tx_queue_release     = enicpmd_dev_tx_queue_release,
+	.rx_queue_intr_enable = enicpmd_dev_rx_queue_intr_enable,
+	.rx_queue_intr_disable = enicpmd_dev_rx_queue_intr_disable,
 	.rxq_info_get         = enicpmd_dev_rxq_info_get,
 	.txq_info_get         = enicpmd_dev_txq_info_get,
 	.dev_led_on           = NULL,
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index bd4447f01..ff1b15be6 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -200,10 +200,16 @@ void enic_init_vnic_resources(struct enic *enic)
 {
 	unsigned int error_interrupt_enable = 1;
 	unsigned int error_interrupt_offset = 0;
+	unsigned int rxq_interrupt_enable = 0;
+	unsigned int rxq_interrupt_offset;
 	unsigned int index = 0;
 	unsigned int cq_idx;
 	struct vnic_rq *data_rq;
 
+	if (enic->rte_dev->data->dev_conf.intr_conf.rxq) {
+		rxq_interrupt_enable = 1;
+		rxq_interrupt_offset = ENICPMD_RXQ_INTR_OFFSET;
+	}
 	for (index = 0; index < enic->rq_count; index++) {
 		cq_idx = enic_cq_rq(enic, enic_rte_rq_idx_to_sop_idx(index));
 
@@ -225,11 +231,13 @@ void enic_init_vnic_resources(struct enic *enic)
 			0 /* cq_head */,
 			0 /* cq_tail */,
 			1 /* cq_tail_color */,
-			0 /* interrupt_enable */,
+			rxq_interrupt_enable,
 			1 /* cq_entry_enable */,
 			0 /* cq_message_enable */,
-			0 /* interrupt offset */,
+			rxq_interrupt_offset,
 			0 /* cq_message_addr */);
+		if (rxq_interrupt_enable)
+			rxq_interrupt_offset++;
 	}
 
 	for (index = 0; index < enic->wq_count; index++) {
@@ -252,10 +260,12 @@ void enic_init_vnic_resources(struct enic *enic)
 			(u64)enic->wq[index].cqmsg_rz->iova);
 	}
 
-	vnic_intr_init(&enic->intr,
-		enic->config.intr_timer_usec,
-		enic->config.intr_timer_type,
-		/*mask_on_assertion*/1);
+	for (index = 0; index < enic->intr_count; index++) {
+		vnic_intr_init(&enic->intr[index],
+			       enic->config.intr_timer_usec,
+			       enic->config.intr_timer_type,
+			       /*mask_on_assertion*/1);
+	}
 }
 
 
@@ -411,13 +421,62 @@ enic_intr_handler(void *arg)
 	struct rte_eth_dev *dev = (struct rte_eth_dev *)arg;
 	struct enic *enic = pmd_priv(dev);
 
-	vnic_intr_return_all_credits(&enic->intr);
+	vnic_intr_return_all_credits(&enic->intr[ENICPMD_LSC_INTR_OFFSET]);
 
 	enic_link_update(enic);
 	_rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
 	enic_log_q_error(enic);
 }
 
+static int enic_rxq_intr_init(struct enic *enic)
+{
+	struct rte_intr_handle *intr_handle;
+	uint32_t rxq_intr_count, i;
+	int err;
+
+	intr_handle = enic->rte_dev->intr_handle;
+	if (!enic->rte_dev->data->dev_conf.intr_conf.rxq)
+		return 0;
+	/*
+	 * Rx queue interrupts only work when we have MSI-X interrupts,
+	 * one per queue. Sharing one interrupt is technically
+	 * possible with VIC, but it is not worth the complications it brings.
+	 */
+	if (!rte_intr_cap_multiple(intr_handle)) {
+		dev_err(enic, "Rx queue interrupts require MSI-X interrupts"
+			" (vfio-pci driver)\n");
+		return -ENOTSUP;
+	}
+	rxq_intr_count = enic->intr_count - ENICPMD_RXQ_INTR_OFFSET;
+	err = rte_intr_efd_enable(intr_handle, rxq_intr_count);
+	if (err) {
+		dev_err(enic, "Failed to enable event fds for Rx queue"
+			" interrupts\n");
+		return err;
+	}
+	intr_handle->intr_vec = rte_zmalloc("enic_intr_vec",
+					    rxq_intr_count * sizeof(int), 0);
+	if (intr_handle->intr_vec == NULL) {
+		dev_err(enic, "Failed to allocate intr_vec\n");
+		return -ENOMEM;
+	}
+	for (i = 0; i < rxq_intr_count; i++)
+		intr_handle->intr_vec[i] = i + ENICPMD_RXQ_INTR_OFFSET;
+	return 0;
+}
+
+static void enic_rxq_intr_deinit(struct enic *enic)
+{
+	struct rte_intr_handle *intr_handle;
+
+	intr_handle = enic->rte_dev->intr_handle;
+	rte_intr_efd_disable(intr_handle);
+	if (intr_handle->intr_vec != NULL) {
+		rte_free(intr_handle->intr_vec);
+		intr_handle->intr_vec = NULL;
+	}
+}
+
 int enic_enable(struct enic *enic)
 {
 	unsigned int index;
@@ -434,6 +493,9 @@ int enic_enable(struct enic *enic)
 	if (eth_dev->data->dev_conf.intr_conf.lsc)
 		vnic_dev_notify_set(enic->vdev, 0);
 
+	err = enic_rxq_intr_init(enic);
+	if (err)
+		return err;
 	if (enic_clsf_init(enic))
 		dev_warning(enic, "Init of hash table for clsf failed."\
 			"Flow director feature will not work\n");
@@ -471,7 +533,8 @@ int enic_enable(struct enic *enic)
 		enic_intr_handler, (void *)enic->rte_dev);
 
 	rte_intr_enable(&(enic->pdev->intr_handle));
-	vnic_intr_unmask(&enic->intr);
+	/* Unmask LSC interrupt */
+	vnic_intr_unmask(&enic->intr[ENICPMD_LSC_INTR_OFFSET]);
 
 	return 0;
 }
@@ -479,17 +542,21 @@ int enic_enable(struct enic *enic)
 int enic_alloc_intr_resources(struct enic *enic)
 {
 	int err;
+	unsigned int i;
 
 	dev_info(enic, "vNIC resources used:  "\
 		"wq %d rq %d cq %d intr %d\n",
 		enic->wq_count, enic_vnic_rq_count(enic),
 		enic->cq_count, enic->intr_count);
 
-	err = vnic_intr_alloc(enic->vdev, &enic->intr, 0);
-	if (err)
-		enic_free_vnic_resources(enic);
-
-	return err;
+	for (i = 0; i < enic->intr_count; i++) {
+		err = vnic_intr_alloc(enic->vdev, &enic->intr[i], i);
+		if (err) {
+			enic_free_vnic_resources(enic);
+			return err;
+		}
+	}
+	return 0;
 }
 
 void enic_free_rq(void *rxq)
@@ -837,8 +904,11 @@ int enic_disable(struct enic *enic)
 	unsigned int i;
 	int err;
 
-	vnic_intr_mask(&enic->intr);
-	(void)vnic_intr_masked(&enic->intr); /* flush write */
+	for (i = 0; i < enic->intr_count; i++) {
+		vnic_intr_mask(&enic->intr[i]);
+		(void)vnic_intr_masked(&enic->intr[i]); /* flush write */
+	}
+	enic_rxq_intr_deinit(enic);
 	rte_intr_disable(&enic->pdev->intr_handle);
 	rte_intr_callback_unregister(&enic->pdev->intr_handle,
 				     enic_intr_handler,
@@ -881,7 +951,8 @@ int enic_disable(struct enic *enic)
 			vnic_rq_clean(&enic->rq[i], enic_free_rq_buf);
 	for (i = 0; i < enic->cq_count; i++)
 		vnic_cq_clean(&enic->cq[i]);
-	vnic_intr_clean(&enic->intr);
+	for (i = 0; i < enic->intr_count; i++)
+		vnic_intr_clean(&enic->intr[i]);
 
 	return 0;
 }
@@ -1170,6 +1241,7 @@ static void enic_dev_deinit(struct enic *enic)
 
 	rte_free(eth_dev->data->mac_addrs);
 	rte_free(enic->cq);
+	rte_free(enic->intr);
 	rte_free(enic->rq);
 	rte_free(enic->wq);
 }
@@ -1179,12 +1251,16 @@ int enic_set_vnic_res(struct enic *enic)
 {
 	struct rte_eth_dev *eth_dev = enic->rte_dev;
 	int rc = 0;
-	unsigned int required_rq, required_wq, required_cq;
+	unsigned int required_rq, required_wq, required_cq, required_intr;
 
 	/* Always use two vNIC RQs per eth_dev RQ, regardless of Rx scatter. */
 	required_rq = eth_dev->data->nb_rx_queues * 2;
 	required_wq = eth_dev->data->nb_tx_queues;
 	required_cq = eth_dev->data->nb_rx_queues + eth_dev->data->nb_tx_queues;
+	required_intr = 1; /* 1 for LSC even if intr_conf.lsc is 0 */
+	if (eth_dev->data->dev_conf.intr_conf.rxq) {
+		required_intr += eth_dev->data->nb_rx_queues;
+	}
 
 	if (enic->conf_rq_count < required_rq) {
 		dev_err(dev, "Not enough Receive queues. Requested:%u which uses %d RQs on VIC, Configured:%u\n",
@@ -1203,11 +1279,18 @@ int enic_set_vnic_res(struct enic *enic)
 			required_cq, enic->conf_cq_count);
 		rc = -EINVAL;
 	}
+	if (enic->conf_intr_count < required_intr) {
+		dev_err(dev, "Not enough Interrupts to support Rx queue"
+			" interrupts. Required:%u, Configured:%u\n",
+			required_intr, enic->conf_intr_count);
+		rc = -EINVAL;
+	}
 
 	if (rc == 0) {
 		enic->rq_count = eth_dev->data->nb_rx_queues;
 		enic->wq_count = eth_dev->data->nb_tx_queues;
 		enic->cq_count = enic->rq_count + enic->wq_count;
+		enic->intr_count = required_intr;
 	}
 
 	return rc;
@@ -1409,6 +1492,8 @@ static int enic_dev_init(struct enic *enic)
 	/* Queue counts may be zeros. rte_zmalloc returns NULL in that case. */
 	enic->cq = rte_zmalloc("enic_vnic_cq", sizeof(struct vnic_cq) *
 			       enic->conf_cq_count, 8);
+	enic->intr = rte_zmalloc("enic_vnic_intr", sizeof(struct vnic_intr) *
+				 enic->conf_intr_count, 8);
 	enic->rq = rte_zmalloc("enic_vnic_rq", sizeof(struct vnic_rq) *
 			       enic->conf_rq_count, 8);
 	enic->wq = rte_zmalloc("enic_vnic_wq", sizeof(struct vnic_wq) *
@@ -1417,6 +1502,10 @@ static int enic_dev_init(struct enic *enic)
 		dev_err(enic, "failed to allocate vnic_cq, aborting.\n");
 		return -1;
 	}
+	if (enic->conf_intr_count > 0 && enic->intr == NULL) {
+		dev_err(enic, "failed to allocate vnic_intr, aborting.\n");
+		return -1;
+	}
 	if (enic->conf_rq_count > 0 && enic->rq == NULL) {
 		dev_err(enic, "failed to allocate vnic_rq, aborting.\n");
 		return -1;
diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c
index d8f7892c3..e7ad6767e 100644
--- a/drivers/net/enic/enic_res.c
+++ b/drivers/net/enic/enic_res.c
@@ -222,7 +222,8 @@ void enic_free_vnic_resources(struct enic *enic)
 			vnic_rq_free(&enic->rq[i]);
 	for (i = 0; i < enic->cq_count; i++)
 		vnic_cq_free(&enic->cq[i]);
-	vnic_intr_free(&enic->intr);
+	for (i = 0; i < enic->intr_count; i++)
+		vnic_intr_free(&enic->intr[i]);
 }
 
 void enic_get_res_counts(struct enic *enic)
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 08/10] doc: describe Rx bytes counter behavior for enic
  2018-03-08  2:46       ` [PATCH v3 00/10] enic PMD patchset John Daley
                           ` (6 preceding siblings ...)
  2018-03-08  2:46         ` [PATCH v3 07/10] net/enic: support Rx queue interrupts John Daley
@ 2018-03-08  2:47         ` John Daley
  2018-03-08 22:14           ` Stephen Hemminger
  2018-03-08  2:47         ` [PATCH v3 09/10] net/enic: use memcpy to avoid strict aliasing warnings John Daley
                           ` (2 subsequent siblings)
  10 siblings, 1 reply; 44+ messages in thread
From: John Daley @ 2018-03-08  2:47 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 doc/guides/nics/enic.rst | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/doc/guides/nics/enic.rst b/doc/guides/nics/enic.rst
index 7e19cf88a..0bc55936a 100644
--- a/doc/guides/nics/enic.rst
+++ b/doc/guides/nics/enic.rst
@@ -310,6 +310,14 @@ Limitations
     were added. Since there currently is no grouping or priority support,
     'catch-all' filters should be added last.
 
+- **Statistics**
+
+  - ``rx_good_bytes`` (ibytes) always includes VLAN header (4B) and CRC bytes (4B).
+  - When the NIC drops a packet because the Rx queue has no free buffers,
+    ``rx_good_bytes`` still increments by 4B if the packet is not VLAN tagged or
+    VLAN stripping is disabled, or by 8B if the packet is VLAN tagged and stripping
+    is enabled.
+
 How to build the suite
 ----------------------
 
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 09/10] net/enic: use memcpy to avoid strict aliasing warnings
  2018-03-08  2:46       ` [PATCH v3 00/10] enic PMD patchset John Daley
                           ` (7 preceding siblings ...)
  2018-03-08  2:47         ` [PATCH v3 08/10] doc: describe Rx bytes counter behavior for enic John Daley
@ 2018-03-08  2:47         ` John Daley
  2018-03-08  2:47         ` [PATCH v3 10/10] net/enic: support for meson John Daley
  2018-03-09 16:00         ` [PATCH v3 00/10] enic PMD patchset Ferruh Yigit
  10 siblings, 0 replies; 44+ messages in thread
From: John Daley @ 2018-03-08  2:47 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 drivers/net/enic/enic_clsf.c | 21 ++++++++-------------
 1 file changed, 8 insertions(+), 13 deletions(-)

diff --git a/drivers/net/enic/enic_clsf.c b/drivers/net/enic/enic_clsf.c
index 3ef1d0832..9d95201ec 100644
--- a/drivers/net/enic/enic_clsf.c
+++ b/drivers/net/enic/enic_clsf.c
@@ -111,7 +111,6 @@ copy_fltr_v2(struct filter_v2 *fltr, struct rte_eth_fdir_input *input,
 	     struct rte_eth_fdir_masks *masks)
 {
 	struct filter_generic_1 *gp = &fltr->u.generic_1;
-	int i;
 
 	fltr->type = FILTER_DPDK_1;
 	memset(gp, 0, sizeof(*gp));
@@ -273,18 +272,14 @@ copy_fltr_v2(struct filter_v2 *fltr, struct rte_eth_fdir_input *input,
 			ipv6_mask.proto = masks->ipv6_mask.proto;
 			ipv6_val.proto = input->flow.ipv6_flow.proto;
 		}
-		for (i = 0; i < 4; i++) {
-			*(uint32_t *)&ipv6_mask.src_addr[i * 4] =
-					masks->ipv6_mask.src_ip[i];
-			*(uint32_t *)&ipv6_val.src_addr[i * 4] =
-					input->flow.ipv6_flow.src_ip[i];
-		}
-		for (i = 0; i < 4; i++) {
-			*(uint32_t *)&ipv6_mask.dst_addr[i * 4] =
-					masks->ipv6_mask.src_ip[i];
-			*(uint32_t *)&ipv6_val.dst_addr[i * 4] =
-					input->flow.ipv6_flow.dst_ip[i];
-		}
+		memcpy(ipv6_mask.src_addr, masks->ipv6_mask.src_ip,
+		       sizeof(ipv6_mask.src_addr));
+		memcpy(ipv6_val.src_addr, input->flow.ipv6_flow.src_ip,
+		       sizeof(ipv6_val.src_addr));
+		memcpy(ipv6_mask.dst_addr, masks->ipv6_mask.dst_ip,
+		       sizeof(ipv6_mask.dst_addr));
+		memcpy(ipv6_val.dst_addr, input->flow.ipv6_flow.dst_ip,
+		       sizeof(ipv6_val.dst_addr));
 		if (input->flow.ipv6_flow.tc) {
 			ipv6_mask.vtc_flow = masks->ipv6_mask.tc << 12;
 			ipv6_val.vtc_flow = input->flow.ipv6_flow.tc << 12;
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 10/10] net/enic: support for meson
  2018-03-08  2:46       ` [PATCH v3 00/10] enic PMD patchset John Daley
                           ` (8 preceding siblings ...)
  2018-03-08  2:47         ` [PATCH v3 09/10] net/enic: use memcpy to avoid strict aliasing warnings John Daley
@ 2018-03-08  2:47         ` John Daley
  2018-03-08  9:49           ` Bruce Richardson
  2018-03-09 16:00         ` [PATCH v3 00/10] enic PMD patchset Ferruh Yigit
  10 siblings, 1 reply; 44+ messages in thread
From: John Daley @ 2018-03-08  2:47 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: dev, Hyong Youb Kim

From: Hyong Youb Kim <hyonkim@cisco.com>

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 drivers/net/enic/meson.build | 19 +++++++++++++++++++
 drivers/net/meson.build      |  2 +-
 2 files changed, 20 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/enic/meson.build

diff --git a/drivers/net/enic/meson.build b/drivers/net/enic/meson.build
new file mode 100644
index 000000000..bfd4e2373
--- /dev/null
+++ b/drivers/net/enic/meson.build
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Cisco Systems, Inc.
+
+sources = files(
+	'base/vnic_cq.c',
+	'base/vnic_dev.c',
+	'base/vnic_intr.c',
+	'base/vnic_rq.c',
+	'base/vnic_rss.c',
+	'base/vnic_wq.c',
+	'enic_clsf.c',
+	'enic_ethdev.c',
+	'enic_flow.c',
+	'enic_main.c',
+	'enic_res.c',
+	'enic_rxtx.c',
+	)
+deps += ['hash']
+includes += include_directories('base')
diff --git a/drivers/net/meson.build b/drivers/net/meson.build
index 704cbe3c8..f535baa13 100644
--- a/drivers/net/meson.build
+++ b/drivers/net/meson.build
@@ -2,7 +2,7 @@
 # Copyright(c) 2017 Intel Corporation
 
 drivers = ['af_packet', 'bonding',
-	'e1000', 'fm10k', 'i40e', 'ixgbe',
+	'e1000', 'enic', 'fm10k', 'i40e', 'ixgbe',
 	'null', 'octeontx', 'pcap', 'ring',
 	'sfc', 'thunderx']
 std_deps = ['ethdev', 'kvargs'] # 'ethdev' also pulls in mbuf, net, eal etc
-- 
2.16.2

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 10/10] net/enic: support for meson
  2018-03-08  2:47         ` [PATCH v3 10/10] net/enic: support for meson John Daley
@ 2018-03-08  9:49           ` Bruce Richardson
  0 siblings, 0 replies; 44+ messages in thread
From: Bruce Richardson @ 2018-03-08  9:49 UTC (permalink / raw)
  To: John Daley; +Cc: ferruh.yigit, dev, Hyong Youb Kim

On Wed, Mar 07, 2018 at 06:47:02PM -0800, John Daley wrote:
> From: Hyong Youb Kim <hyonkim@cisco.com>
> 
> Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
> Reviewed-by: John Daley <johndale@cisco.com>
> ---
>  drivers/net/enic/meson.build | 19 +++++++++++++++++++
>  drivers/net/meson.build      |  2 +-
>  2 files changed, 20 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/net/enic/meson.build
> 
Patch LGTM

Acked-by: Bruce Richardson <bruce.richardson@intel.com>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 08/10] doc: describe Rx bytes counter behavior for enic
  2018-03-08  2:47         ` [PATCH v3 08/10] doc: describe Rx bytes counter behavior for enic John Daley
@ 2018-03-08 22:14           ` Stephen Hemminger
  2018-03-09  0:52             ` Hyong Youb Kim
  0 siblings, 1 reply; 44+ messages in thread
From: Stephen Hemminger @ 2018-03-08 22:14 UTC (permalink / raw)
  To: John Daley; +Cc: ferruh.yigit, dev, Hyong Youb Kim

On Wed,  7 Mar 2018 18:47:00 -0800
John Daley <johndale@cisco.com> wrote:

>      'catch-all' filters should be added last.
>  
> +- **Statistics**
> +
> +  - ``rx_good_bytes`` (ibytes) always includes VLAN header (4B) and CRC bytes (4B).
> +  - When the NIC drops a packet because the Rx queue has no free buffers,
> +    ``rx_good_bytes`` still increments by 4B if the packet is not VLAN tagged or
> +    VLAN stripping is disabled, or by 8B if the packet is VLAN tagged and stripping
> +    is enabled.

All drivers must provide consistent statistics!
That means do NOT include CRC in the rx byte counts.
Yes, several drivers in DPDK are already broken for this.

Otherwise there are cases like packets being forwarded from HW NIC to virtio and the counts
differ and customers think data is lots.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 08/10] doc: describe Rx bytes counter behavior for enic
  2018-03-08 22:14           ` Stephen Hemminger
@ 2018-03-09  0:52             ` Hyong Youb Kim
  2018-03-09  1:48               ` Stephen Hemminger
  0 siblings, 1 reply; 44+ messages in thread
From: Hyong Youb Kim @ 2018-03-09  0:52 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: John Daley, ferruh.yigit, dev

On Thu, Mar 08, 2018 at 02:14:27PM -0800, Stephen Hemminger wrote:
> On Wed,  7 Mar 2018 18:47:00 -0800
> John Daley <johndale@cisco.com> wrote:
> 
> >      'catch-all' filters should be added last.
> >  
> > +- **Statistics**
> > +
> > +  - ``rx_good_bytes`` (ibytes) always includes VLAN header (4B) and CRC bytes (4B).
> > +  - When the NIC drops a packet because the Rx queue has no free buffers,
> > +    ``rx_good_bytes`` still increments by 4B if the packet is not VLAN tagged or
> > +    VLAN stripping is disabled, or by 8B if the packet is VLAN tagged and stripping
> > +    is enabled.
> 
> All drivers must provide consistent statistics!
> That means do NOT include CRC in the rx byte counts.
> Yes, several drivers in DPDK are already broken for this.
> 
> Otherwise there are cases like packets being forwarded from HW NIC to virtio and the counts
> differ and customers think data is lots.

Thanks for sharing this specific use case issue.

We are aware that our current counters are non-standard. Newer 100G
hardware models have fixed the problem (i.e. no CRC bytes, no
incrementing of bytes when no buffers). We plan to update the doc
again when we add these newer models to the supported hardware list.

As for older models, we will see if we can fix up stats in software..

-Hyong

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 08/10] doc: describe Rx bytes counter behavior for enic
  2018-03-09  0:52             ` Hyong Youb Kim
@ 2018-03-09  1:48               ` Stephen Hemminger
  0 siblings, 0 replies; 44+ messages in thread
From: Stephen Hemminger @ 2018-03-09  1:48 UTC (permalink / raw)
  To: Hyong Youb Kim; +Cc: John Daley, ferruh.yigit, dev

On Fri, 9 Mar 2018 09:52:54 +0900
Hyong Youb Kim <hyonkim@cisco.com> wrote:

> On Thu, Mar 08, 2018 at 02:14:27PM -0800, Stephen Hemminger wrote:
> > On Wed,  7 Mar 2018 18:47:00 -0800
> > John Daley <johndale@cisco.com> wrote:
> >   
> > >      'catch-all' filters should be added last.
> > >  
> > > +- **Statistics**
> > > +
> > > +  - ``rx_good_bytes`` (ibytes) always includes VLAN header (4B) and CRC bytes (4B).
> > > +  - When the NIC drops a packet because the Rx queue has no free buffers,
> > > +    ``rx_good_bytes`` still increments by 4B if the packet is not VLAN tagged or
> > > +    VLAN stripping is disabled, or by 8B if the packet is VLAN tagged and stripping
> > > +    is enabled.  
> > 
> > All drivers must provide consistent statistics!
> > That means do NOT include CRC in the rx byte counts.
> > Yes, several drivers in DPDK are already broken for this.
> > 
> > Otherwise there are cases like packets being forwarded from HW NIC to virtio and the counts
> > differ and customers think data is lots.  
> 
> Thanks for sharing this specific use case issue.
> 
> We are aware that our current counters are non-standard. Newer 100G
> hardware models have fixed the problem (i.e. no CRC bytes, no
> incrementing of bytes when no buffers). We plan to update the doc
> again when we add these newer models to the supported hardware list.
> 
> As for older models, we will see if we can fix up stats in software..
> 
> -Hyong

Don't worry some of the Intel drivers are buggy last I checked.
Also make sure that when forwarding that bytes transmitted == bytes received.
There were some drivers adding CRC on the receive but no on transmit.

It maybe true that you want to count CRC if the CRC stripping flag is not set.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 02/10] net/enic: allow the user to change RSS settings
  2018-03-08  2:46         ` [PATCH v3 02/10] net/enic: allow the user to change RSS settings John Daley
@ 2018-03-09 14:35           ` Ferruh Yigit
  0 siblings, 0 replies; 44+ messages in thread
From: Ferruh Yigit @ 2018-03-09 14:35 UTC (permalink / raw)
  To: John Daley; +Cc: dev, Hyong Youb Kim

On 3/8/2018 2:46 AM, John Daley wrote:
> From: Hyong Youb Kim <hyonkim@cisco.com>
> 
> Currently, when more than 1 receive queues are configured, the driver
> always enables RSS with the driver's own default hash type, key, and
> RETA. The user is unable to change any of the RSS settings. Address
> this by implementing the ethdev RSS API as follows.
> 
> Correctly report the RETA size, key size, and supported hash types
> through rte_eth_dev_info.
> 
> During dev_configure(), initialize RSS according to the device's
> mq_mode and rss_conf. Start with the default RETA, and use the default
> key unless a custom key is provided.
> 
> Add the RETA and rss_conf query/set handlers to let the user change
> RSS settings after the initial configuration. The hardware is able to
> change hash type, key, and RETA individually. So, the handlers change
> only the affected settings.
> 
> Refactor/rename several functions in order to make their intentions
> clear. For example, remove all traces of RSS from
> enicpmd_vlan_offload_set() as it is confusing.
> 
> Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
> Reviewed-by: John Daley <johndale@cisco.com>

<...>

> @@ -889,44 +889,42 @@ static int enic_dev_open(struct enic *enic)
>  	return err;
>  }
>  
> -static int enic_set_rsskey(struct enic *enic)
> +static int enic_set_rsskey(struct enic *enic, uint8_t *user_key)
>  {
>  	dma_addr_t rss_key_buf_pa;
>  	union vnic_rss_key *rss_key_buf_va = NULL;
> -	static union vnic_rss_key rss_key = {
> -		.key = {
> -			[0] = {.b = {85, 67, 83, 97, 119, 101, 115, 111, 109, 101}},
> -			[1] = {.b = {80, 65, 76, 79, 117, 110, 105, 113, 117, 101}},
> -			[2] = {.b = {76, 73, 78, 85, 88, 114, 111, 99, 107, 115}},
> -			[3] = {.b = {69, 78, 73, 67, 105, 115, 99, 111, 111, 108}},
> -		}
> -	};
> -	int err;
> +	int err, i;
>  	u8 name[NAME_MAX];
>  
> +	RTE_ASSERT(use_key != NULL);

there is a typo, "use_key" should be "user_key" which is causing a build error.
If RTE_ASSERT used in the code, should test enabling CONFIG_RTE_ENABLE_ASSERT
option too.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 03/10] net/enic: heed the requested max Rx packet size
  2018-03-08  2:46         ` [PATCH v3 03/10] net/enic: heed the requested max Rx packet size John Daley
@ 2018-03-09 15:03           ` Ferruh Yigit
  2018-03-09 15:51             ` Ananyev, Konstantin
  0 siblings, 1 reply; 44+ messages in thread
From: Ferruh Yigit @ 2018-03-09 15:03 UTC (permalink / raw)
  To: John Daley; +Cc: dev, Hyong Youb Kim

On 3/8/2018 2:46 AM, John Daley wrote:
> From: Hyong Youb Kim <hyonkim@cisco.com>
> 
> Currently, enic completely ignores the requested max Rx packet size
> (rxmode.max_rx_pkt_len). The desired behavior is that the NIC hardware
> drops packets larger than the requested size, even though they are
> still smaller than MTU.

Your description looks reasonable but is there reason of two levels of limits,
max_rx_pkt_len and MTU, why not just use MTU. There is already a mail thread to
clarify max_rx_pkt_len [1].

Is this work based on an application that uses max_rx_pkt_len and to make PMD
compatible with that application? If so we can continue with patch, but if the
patch is to implement DPDK properly I suggest postponing this until
max_rx_pkt_len clarified.

[1]
https://dpdk.org/ml/archives/dev/2018-March/092178.html

> 
> Cisco VIC does not have such a feature. But, we can accomplish a
> similar (not same) effect by reducing the size of posted receive
> buffers. Packets larger than the posted size get truncated, and the
> receive handler drops them. This is also how the kernel enic driver
> enforces the Rx side MTU.
> 
> This workaround works only when scatter mode is *not* used. When
> scatter is used, there is currently no way to support
> rxmode.max_rx_pkt_len, as the NIC always receives packets up to MTU.
> 
> For posterity, add a copious amount of comments regarding the
> hardware's drop/receive behavior with respect to max/current MTU.
> 
> Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
> Reviewed-by: John Daley <johndale@cisco.com>

<...>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 03/10] net/enic: heed the requested max Rx packet size
  2018-03-09 15:03           ` Ferruh Yigit
@ 2018-03-09 15:51             ` Ananyev, Konstantin
  2018-03-09 15:57               ` Ferruh Yigit
  0 siblings, 1 reply; 44+ messages in thread
From: Ananyev, Konstantin @ 2018-03-09 15:51 UTC (permalink / raw)
  To: Yigit, Ferruh, John Daley; +Cc: dev, Hyong Youb Kim


Hi everyone,

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Ferruh Yigit
> Sent: Friday, March 9, 2018 3:04 PM
> To: John Daley <johndale@cisco.com>
> Cc: dev@dpdk.org; Hyong Youb Kim <hyonkim@cisco.com>
> Subject: Re: [dpdk-dev] [PATCH v3 03/10] net/enic: heed the requested max Rx packet size
> 
> On 3/8/2018 2:46 AM, John Daley wrote:
> > From: Hyong Youb Kim <hyonkim@cisco.com>
> >
> > Currently, enic completely ignores the requested max Rx packet size
> > (rxmode.max_rx_pkt_len). The desired behavior is that the NIC hardware
> > drops packets larger than the requested size, even though they are
> > still smaller than MTU.
> 
> Your description looks reasonable but is there reason of two levels of limits,
> max_rx_pkt_len and MTU, why not just use MTU. There is already a mail thread to
> clarify max_rx_pkt_len [1].
> 
> Is this work based on an application that uses max_rx_pkt_len and to make PMD
> compatible with that application? If so we can continue with patch, but if the
> patch is to implement DPDK properly I suggest postponing this until
> max_rx_pkt_len clarified.
> 
> [1]
> https://dpdk.org/ml/archives/dev/2018-March/092178.html

I think there are quite a lot apps these days that might rely on setting MTU via
rxmode.max_rx_pkt_len.
I think we need to support them till we (ever) deprecate rxmode.max_rx_pkt_len.
Konstantin

> 
> >
> > Cisco VIC does not have such a feature. But, we can accomplish a
> > similar (not same) effect by reducing the size of posted receive
> > buffers. Packets larger than the posted size get truncated, and the
> > receive handler drops them. This is also how the kernel enic driver
> > enforces the Rx side MTU.
> >
> > This workaround works only when scatter mode is *not* used. When
> > scatter is used, there is currently no way to support
> > rxmode.max_rx_pkt_len, as the NIC always receives packets up to MTU.
> >
> > For posterity, add a copious amount of comments regarding the
> > hardware's drop/receive behavior with respect to max/current MTU.
> >
> > Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
> > Reviewed-by: John Daley <johndale@cisco.com>
> 
> <...>


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 03/10] net/enic: heed the requested max Rx packet size
  2018-03-09 15:51             ` Ananyev, Konstantin
@ 2018-03-09 15:57               ` Ferruh Yigit
  2018-03-10  0:37                 ` Hyong Youb Kim
  0 siblings, 1 reply; 44+ messages in thread
From: Ferruh Yigit @ 2018-03-09 15:57 UTC (permalink / raw)
  To: Ananyev, Konstantin, John Daley; +Cc: dev, Hyong Youb Kim

On 3/9/2018 3:51 PM, Ananyev, Konstantin wrote:
> 
> Hi everyone,
> 
>> -----Original Message-----
>> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Ferruh Yigit
>> Sent: Friday, March 9, 2018 3:04 PM
>> To: John Daley <johndale@cisco.com>
>> Cc: dev@dpdk.org; Hyong Youb Kim <hyonkim@cisco.com>
>> Subject: Re: [dpdk-dev] [PATCH v3 03/10] net/enic: heed the requested max Rx packet size
>>
>> On 3/8/2018 2:46 AM, John Daley wrote:
>>> From: Hyong Youb Kim <hyonkim@cisco.com>
>>>
>>> Currently, enic completely ignores the requested max Rx packet size
>>> (rxmode.max_rx_pkt_len). The desired behavior is that the NIC hardware
>>> drops packets larger than the requested size, even though they are
>>> still smaller than MTU.
>>
>> Your description looks reasonable but is there reason of two levels of limits,
>> max_rx_pkt_len and MTU, why not just use MTU. There is already a mail thread to
>> clarify max_rx_pkt_len [1].
>>
>> Is this work based on an application that uses max_rx_pkt_len and to make PMD
>> compatible with that application? If so we can continue with patch, but if the
>> patch is to implement DPDK properly I suggest postponing this until
>> max_rx_pkt_len clarified.
>>
>> [1]
>> https://dpdk.org/ml/archives/dev/2018-March/092178.html
> 
> I think there are quite a lot apps these days that might rely on setting MTU via
> rxmode.max_rx_pkt_len.
> I think we need to support them till we (ever) deprecate rxmode.max_rx_pkt_len.

Right. I was trying to save effort in case something changes related
max_rx_pkt_len, but since it is not clear yet, will continue with this patch.

> Konstantin
> 
>>
>>>
>>> Cisco VIC does not have such a feature. But, we can accomplish a
>>> similar (not same) effect by reducing the size of posted receive
>>> buffers. Packets larger than the posted size get truncated, and the
>>> receive handler drops them. This is also how the kernel enic driver
>>> enforces the Rx side MTU.
>>>
>>> This workaround works only when scatter mode is *not* used. When
>>> scatter is used, there is currently no way to support
>>> rxmode.max_rx_pkt_len, as the NIC always receives packets up to MTU.
>>>
>>> For posterity, add a copious amount of comments regarding the
>>> hardware's drop/receive behavior with respect to max/current MTU.
>>>
>>> Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
>>> Reviewed-by: John Daley <johndale@cisco.com>
>>
>> <...>
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 00/10] enic PMD patchset
  2018-03-08  2:46       ` [PATCH v3 00/10] enic PMD patchset John Daley
                           ` (9 preceding siblings ...)
  2018-03-08  2:47         ` [PATCH v3 10/10] net/enic: support for meson John Daley
@ 2018-03-09 16:00         ` Ferruh Yigit
  2018-03-10  0:49           ` Hyong Youb Kim
  10 siblings, 1 reply; 44+ messages in thread
From: Ferruh Yigit @ 2018-03-09 16:00 UTC (permalink / raw)
  To: John Daley; +Cc: dev

On 3/8/2018 2:46 AM, John Daley wrote:
> V2: rebase, submit as patchset instead of individual patches so they
> apply correctly.
> V3: try again submitting patches one at a time so they are applied
> in order (tester seems to be applying patches in order received
> instead of looking at patch ID).
> 
> Hyong Youb Kim (9):
>   net/enic: allow the user to change RSS settings
>   net/enic: heed the requested max Rx packet size
>   net/enic: remove the VLAN filter handler
>   net/enic: add Rx/Tx queue configuration getters
>   net/enic: allocate stats DMA buffer upfront during probe
>   net/enic: support Rx queue interrupts
>   doc: describe Rx bytes counter behavior for enic
>   net/enic: use memcpy to avoid strict aliasing warnings
>   net/enic: support for meson
> 
> John Daley (1):
>   net/enic: remove 'extern' in .h file function declarations

Series applied to dpdk-next-net/master, thanks.

(typo in 2/10 fixed while applying)

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 03/10] net/enic: heed the requested max Rx packet size
  2018-03-09 15:57               ` Ferruh Yigit
@ 2018-03-10  0:37                 ` Hyong Youb Kim
  2018-03-14  0:56                   ` Ferruh Yigit
  0 siblings, 1 reply; 44+ messages in thread
From: Hyong Youb Kim @ 2018-03-10  0:37 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: Ananyev, Konstantin, John Daley, dev

On Fri, Mar 09, 2018 at 03:57:46PM +0000, Ferruh Yigit wrote:
> On 3/9/2018 3:51 PM, Ananyev, Konstantin wrote:
[...]
> >> Is this work based on an application that uses max_rx_pkt_len and to make PMD
> >> compatible with that application? If so we can continue with patch, but if the
> >> patch is to implement DPDK properly I suggest postponing this until
> >> max_rx_pkt_len clarified.
> >>
> >> [1]
> >> https://dpdk.org/ml/archives/dev/2018-March/092178.html
> > 
> > I think there are quite a lot apps these days that might rely on setting MTU via
> > rxmode.max_rx_pkt_len.
> > I think we need to support them till we (ever) deprecate rxmode.max_rx_pkt_len.
> 
> Right. I was trying to save effort in case something changes related
> max_rx_pkt_len, but since it is not clear yet, will continue with this patch.
> 
> > Konstantin
> > 

testpmd has a command to change max_rx_pkt_len, a few DTS test cases
rely on this feature to see if packets of certain sizes get dropped,
and so on. We worked on this patch to support these cases.

I prefer using only MTU, to follow the convention of most (all?)
OSes. Though, this feature (max_rx_pkt_len) seems to come straight
from an Intel 82599 feature. In its datasheet, see "8.2.3.22.13 Max
Frame Size -- MAXFRS". Like to understand use cases for that, if
anyone can share.

-Hyong

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 00/10] enic PMD patchset
  2018-03-09 16:00         ` [PATCH v3 00/10] enic PMD patchset Ferruh Yigit
@ 2018-03-10  0:49           ` Hyong Youb Kim
  0 siblings, 0 replies; 44+ messages in thread
From: Hyong Youb Kim @ 2018-03-10  0:49 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: John Daley, dev

On Fri, Mar 09, 2018 at 04:00:55PM +0000, Ferruh Yigit wrote:
[...]
> Series applied to dpdk-next-net/master, thanks.
> 
> (typo in 2/10 fixed while applying)

Thanks a lot for fixing that. Adding "build with assert enabled" to our checklist..

-Hyong

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 03/10] net/enic: heed the requested max Rx packet size
  2018-03-10  0:37                 ` Hyong Youb Kim
@ 2018-03-14  0:56                   ` Ferruh Yigit
  0 siblings, 0 replies; 44+ messages in thread
From: Ferruh Yigit @ 2018-03-14  0:56 UTC (permalink / raw)
  To: Hyong Youb Kim; +Cc: Ananyev, Konstantin, John Daley, dev, Wenzhuo Lu

On 3/10/2018 12:37 AM, Hyong Youb Kim wrote:
> On Fri, Mar 09, 2018 at 03:57:46PM +0000, Ferruh Yigit wrote:
>> On 3/9/2018 3:51 PM, Ananyev, Konstantin wrote:
> [...]
>>>> Is this work based on an application that uses max_rx_pkt_len and to make PMD
>>>> compatible with that application? If so we can continue with patch, but if the
>>>> patch is to implement DPDK properly I suggest postponing this until
>>>> max_rx_pkt_len clarified.
>>>>
>>>> [1]
>>>> https://dpdk.org/ml/archives/dev/2018-March/092178.html
>>>
>>> I think there are quite a lot apps these days that might rely on setting MTU via
>>> rxmode.max_rx_pkt_len.
>>> I think we need to support them till we (ever) deprecate rxmode.max_rx_pkt_len.
>>
>> Right. I was trying to save effort in case something changes related
>> max_rx_pkt_len, but since it is not clear yet, will continue with this patch.
>>
>>> Konstantin
>>>
> 
> testpmd has a command to change max_rx_pkt_len, a few DTS test cases
> rely on this feature to see if packets of certain sizes get dropped,
> and so on. We worked on this patch to support these cases.
> 
> I prefer using only MTU, to follow the convention of most (all?)
> OSes. Though, this feature (max_rx_pkt_len) seems to come straight
> from an Intel 82599 feature. In its datasheet, see "8.2.3.22.13 Max
> Frame Size -- MAXFRS". Like to understand use cases for that, if
> anyone can share.

ixgbe driver updates MAXFRS register in ixgbe_dev_mtu_set(), so mtu seems can
replace max_rx_pkt_len.

MAXFRS is for rx only, from datasheet description of it:
"This value has no effect on transmit frames; it is the responsibility of
software to limit the size of transmit frames"

This may be the reason a new variable has been created for rx_frames, to
differentiate it from mtu. Not sure if max rx and tx size can be different
values for ixgbe.

> 
> -Hyong
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

end of thread, other threads:[~2018-03-14  0:56 UTC | newest]

Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-24 19:17 [PATCH] net/enic: remove 'extern' in .h file function declarations John Daley
2018-02-24 19:17 ` [PATCH] net/enic: allow the user to change RSS settings John Daley
2018-02-24 19:17 ` [PATCH] net/enic: heed the requested max Rx packet size John Daley
2018-02-24 19:17 ` [PATCH] net/enic: remove the VLAN filter handler John Daley
2018-02-24 19:17 ` [PATCH] net/enic: add Rx/Tx queue configuration getters John Daley
2018-02-24 19:17 ` [PATCH] net/enic: allocate stats DMA buffer upfront during probe John Daley
2018-02-24 19:17 ` [PATCH] net/enic: support Rx queue interrupts John Daley
2018-02-24 19:17 ` [PATCH] doc: describe Rx bytes counter behavior for enic John Daley
2018-02-24 19:17 ` [PATCH] net/enic: use memcpy to avoid strict aliasing warnings John Daley
2018-02-24 19:17 ` [PATCH] net/enic: support for meson John Daley
2018-03-06  1:46   ` [PATCH v2 00/10] enic patchset John Daley
2018-03-06  1:46     ` [PATCH v2 01/10] net/enic: remove 'extern' in .h file function declarations John Daley
2018-03-08  2:46       ` [PATCH v3 00/10] enic PMD patchset John Daley
2018-03-08  2:46         ` [PATCH v3 01/10] net/enic: remove 'extern' in .h file function declarations John Daley
2018-03-08  2:46         ` [PATCH v3 02/10] net/enic: allow the user to change RSS settings John Daley
2018-03-09 14:35           ` Ferruh Yigit
2018-03-08  2:46         ` [PATCH v3 03/10] net/enic: heed the requested max Rx packet size John Daley
2018-03-09 15:03           ` Ferruh Yigit
2018-03-09 15:51             ` Ananyev, Konstantin
2018-03-09 15:57               ` Ferruh Yigit
2018-03-10  0:37                 ` Hyong Youb Kim
2018-03-14  0:56                   ` Ferruh Yigit
2018-03-08  2:46         ` [PATCH v3 04/10] net/enic: remove the VLAN filter handler John Daley
2018-03-08  2:46         ` [PATCH v3 05/10] net/enic: add Rx/Tx queue configuration getters John Daley
2018-03-08  2:46         ` [PATCH v3 06/10] net/enic: allocate stats DMA buffer upfront during probe John Daley
2018-03-08  2:46         ` [PATCH v3 07/10] net/enic: support Rx queue interrupts John Daley
2018-03-08  2:47         ` [PATCH v3 08/10] doc: describe Rx bytes counter behavior for enic John Daley
2018-03-08 22:14           ` Stephen Hemminger
2018-03-09  0:52             ` Hyong Youb Kim
2018-03-09  1:48               ` Stephen Hemminger
2018-03-08  2:47         ` [PATCH v3 09/10] net/enic: use memcpy to avoid strict aliasing warnings John Daley
2018-03-08  2:47         ` [PATCH v3 10/10] net/enic: support for meson John Daley
2018-03-08  9:49           ` Bruce Richardson
2018-03-09 16:00         ` [PATCH v3 00/10] enic PMD patchset Ferruh Yigit
2018-03-10  0:49           ` Hyong Youb Kim
2018-03-06  1:46     ` [PATCH v2 02/10] net/enic: allow the user to change RSS settings John Daley
2018-03-06  1:46     ` [PATCH v2 03/10] net/enic: heed the requested max Rx packet size John Daley
2018-03-06  1:46     ` [PATCH v2 04/10] net/enic: remove the VLAN filter handler John Daley
2018-03-06  1:46     ` [PATCH v2 05/10] net/enic: add Rx/Tx queue configuration getters John Daley
2018-03-06  1:46     ` [PATCH v2 06/10] net/enic: allocate stats DMA buffer upfront during probe John Daley
2018-03-06  1:46     ` [PATCH v2 07/10] net/enic: support Rx queue interrupts John Daley
2018-03-06  1:46     ` [PATCH v2 08/10] doc: describe Rx bytes counter behavior for enic John Daley
2018-03-06  1:46     ` [PATCH v2 09/10] net/enic: use memcpy to avoid strict aliasing warnings John Daley
2018-03-06  1:46     ` [PATCH v2 10/10] net/enic: support for meson John Daley

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.