[dpdk-dev,1/3] i40evf: add RSS support in VF
diff mbox

Message ID 1405651521-14545-2-git-send-email-helin.zhang@intel.com
State Superseded, archived
Headers show

Commit Message

Helin Zhang July 18, 2014, 2:45 a.m. UTC
Add VF RSS support in Poll Mode Driver, as it is supported by hardware.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
Acked-by: Cunming Liang <cunming.liang@intel.com>
Acked-by: Jijiang Liu <jijiang.liu@intel.com>
---
 lib/librte_pmd_i40e/i40e_ethdev.c    |   4 +-
 lib/librte_pmd_i40e/i40e_ethdev.h    |  40 ++++++-
 lib/librte_pmd_i40e/i40e_ethdev_vf.c | 208 +++++++++++++++++++++++++++++++++++
 3 files changed, 249 insertions(+), 3 deletions(-)

Patch
diff mbox

diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 9ed31b5..85e8b18 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -3747,7 +3747,7 @@  DONE:
 }
 
 /* Configure hash enable flags for RSS */
-static uint64_t
+uint64_t
 i40e_config_hena(uint64_t flags)
 {
 	uint64_t hena = 0;
@@ -3782,7 +3782,7 @@  i40e_config_hena(uint64_t flags)
 }
 
 /* Parse the hash enable flags */
-static uint64_t
+uint64_t
 i40e_parse_hena(uint64_t flags)
 {
 	uint64_t rss_hf = 0;
diff --git a/lib/librte_pmd_i40e/i40e_ethdev.h b/lib/librte_pmd_i40e/i40e_ethdev.h
index 64deef2..1d42cd2 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.h
+++ b/lib/librte_pmd_i40e/i40e_ethdev.h
@@ -68,6 +68,36 @@ 
 		       I40E_FLAG_HEADER_SPLIT_ENABLED | \
 		       I40E_FLAG_FDIR)
 
+#define I40E_RSS_OFFLOAD_ALL ( \
+	ETH_RSS_NONF_IPV4_UDP | \
+	ETH_RSS_NONF_IPV4_TCP | \
+	ETH_RSS_NONF_IPV4_SCTP | \
+	ETH_RSS_NONF_IPV4_OTHER | \
+	ETH_RSS_FRAG_IPV4 | \
+	ETH_RSS_NONF_IPV6_UDP | \
+	ETH_RSS_NONF_IPV6_TCP | \
+	ETH_RSS_NONF_IPV6_SCTP | \
+	ETH_RSS_NONF_IPV6_OTHER | \
+	ETH_RSS_FRAG_IPV6 | \
+	ETH_RSS_L2_PAYLOAD)
+
+/* All bits of RSS hash enable */
+#define I40E_RSS_HENA_ALL ( \
+	(1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | \
+	(1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | \
+	(1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | \
+	(1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | \
+	(1ULL << I40E_FILTER_PCTYPE_FRAG_IPV4) | \
+	(1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | \
+	(1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | \
+	(1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | \
+	(1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | \
+	(1ULL << I40E_FILTER_PCTYPE_FRAG_IPV6) | \
+	(1ULL << I40E_FILTER_PCTYPE_FCOE_OX) | \
+	(1ULL << I40E_FILTER_PCTYPE_FCOE_RX) | \
+	(1ULL << I40E_FILTER_PCTYPE_FCOE_OTHER) | \
+	(1ULL << I40E_FILTER_PCTYPE_L2_PAYLOAD))
+
 struct i40e_adapter;
 
 TAILQ_HEAD(i40e_mac_filter_list, i40e_mac_filter);
@@ -253,6 +283,8 @@  struct i40e_vf_tx_queues {
  * Structure to store private data specific for VF instance.
  */
 struct i40e_vf {
+	struct i40e_adapter *adapter; /* The adapter this VF associate to */
+	struct rte_eth_dev_data *dev_data; /* Pointer to the device data */
 	uint16_t num_queue_pairs;
 	uint16_t max_pkt_len; /* Maximum packet length */
 	bool promisc_unicast_enabled;
@@ -310,8 +342,10 @@  int i40e_dev_link_update(struct rte_eth_dev *dev,
 void i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi);
 void i40e_vsi_queues_unbind_intr(struct i40e_vsi *vsi);
 int i40e_vsi_vlan_pvid_set(struct i40e_vsi *vsi,
-				struct i40e_vsi_vlan_pvid_info *info);
+			   struct i40e_vsi_vlan_pvid_info *info);
 int i40e_vsi_config_vlan_stripping(struct i40e_vsi *vsi, bool on);
+uint64_t i40e_config_hena(uint64_t flags);
+uint64_t i40e_parse_hena(uint64_t flags);
 
 /* I40E_DEV_PRIVATE_TO */
 #define I40E_DEV_PRIVATE_TO_PF(adapter) \
@@ -361,6 +395,10 @@  i40e_get_vsi_from_adapter(struct i40e_adapter *adapter)
 #define I40E_PF_TO_ADAPTER(pf) \
 	((struct i40e_adapter *)pf->adapter)
 
+/* I40E_VF_TO */
+#define I40E_VF_TO_HW(vf) \
+	(&(((struct i40e_vf *)vf)->adapter->hw))
+
 static inline void
 i40e_init_adminq_parameter(struct i40e_hw *hw)
 {
diff --git a/lib/librte_pmd_i40e/i40e_ethdev_vf.c b/lib/librte_pmd_i40e/i40e_ethdev_vf.c
index 2726bfb..bef34cb 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev_vf.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev_vf.c
@@ -125,6 +125,19 @@  static void i40evf_dev_allmulticast_disable(struct rte_eth_dev *dev);
 static int i40evf_get_link_status(struct rte_eth_dev *dev,
 				  struct rte_eth_link *link);
 static int i40evf_init_vlan(struct rte_eth_dev *dev);
+static int i40evf_config_rss(struct i40e_vf *vf);
+static int i40evf_dev_rss_reta_update(struct rte_eth_dev *dev,
+				      struct rte_eth_rss_reta *reta_conf);
+static int i40evf_dev_rss_reta_query(struct rte_eth_dev *dev,
+				     struct rte_eth_rss_reta *reta_conf);
+static int i40evf_dev_rss_hash_update(struct rte_eth_dev *dev,
+				      struct rte_eth_rss_conf *rss_conf);
+static int i40evf_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
+					struct rte_eth_rss_conf *rss_conf);
+
+/* Default hash key buffer for RSS */
+static uint32_t rss_key_default[I40E_VFQF_HKEY_MAX_INDEX + 1];
+
 static struct eth_dev_ops i40evf_eth_dev_ops = {
 	.dev_configure        = i40evf_dev_configure,
 	.dev_start            = i40evf_dev_start,
@@ -144,6 +157,10 @@  static struct eth_dev_ops i40evf_eth_dev_ops = {
 	.rx_queue_release     = i40e_dev_rx_queue_release,
 	.tx_queue_setup       = i40e_dev_tx_queue_setup,
 	.tx_queue_release     = i40e_dev_tx_queue_release,
+	.reta_update          = i40evf_dev_rss_reta_update,
+	.reta_query           = i40evf_dev_rss_reta_query,
+	.rss_hash_update      = i40evf_dev_rss_hash_update,
+	.rss_hash_conf_get    = i40evf_dev_rss_hash_conf_get,
 };
 
 static int
@@ -941,6 +958,8 @@  i40evf_init_vf(struct rte_eth_dev *dev)
 	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
 
+	vf->adapter = I40E_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+	vf->dev_data = dev->data;
 	err = i40evf_set_mac_type(hw);
 	if (err) {
 		PMD_INIT_LOG(ERR, "set_mac_type failed: %d\n", err);
@@ -1194,11 +1213,13 @@  i40evf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 static int
 i40evf_rx_init(struct rte_eth_dev *dev)
 {
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
 	uint16_t i, j;
 	struct i40e_rx_queue **rxq =
 		(struct i40e_rx_queue **)dev->data->rx_queues;
 	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
+	i40evf_config_rss(vf);
 	for (i = 0; i < dev->data->nb_rx_queues; i++) {
 		if (i40e_alloc_rx_queue_mbufs(rxq[i]) != 0) {
 			PMD_DRV_LOG(ERR, "alloc rx queues mbufs failed\n");
@@ -1445,3 +1466,190 @@  i40evf_dev_close(struct rte_eth_dev *dev)
 	i40evf_reset_vf(hw);
 	i40e_shutdown_adminq(hw);
 }
+
+static int
+i40evf_hw_rss_hash_set(struct i40e_hw *hw, struct rte_eth_rss_conf *rss_conf)
+{
+	uint32_t *hash_key;
+	uint8_t hash_key_len;
+	uint64_t rss_hf, hena;
+
+	hash_key = (uint32_t *)(rss_conf->rss_key);
+	hash_key_len = rss_conf->rss_key_len;
+	if (hash_key != NULL && hash_key_len >=
+		(I40E_VFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) {
+		uint16_t i;
+
+		for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++)
+			I40E_WRITE_REG(hw, I40E_VFQF_HKEY(i), hash_key[i]);
+	}
+
+	rss_hf = rss_conf->rss_hf;
+	hena = (uint64_t)I40E_READ_REG(hw, I40E_VFQF_HENA(0));
+	hena |= ((uint64_t)I40E_READ_REG(hw, I40E_VFQF_HENA(1))) << 32;
+	hena &= ~I40E_RSS_HENA_ALL;
+	hena |= i40e_config_hena(rss_hf);
+	I40E_WRITE_REG(hw, I40E_VFQF_HENA(0), (uint32_t)hena);
+	I40E_WRITE_REG(hw, I40E_VFQF_HENA(1), (uint32_t)(hena >> 32));
+	I40EVF_WRITE_FLUSH(hw);
+
+	return 0;
+}
+
+static void
+i40evf_disable_rss(struct i40e_vf *vf)
+{
+	struct i40e_hw *hw = I40E_VF_TO_HW(vf);
+	uint64_t hena;
+
+	hena = (uint64_t)I40E_READ_REG(hw, I40E_VFQF_HENA(0));
+	hena |= ((uint64_t)I40E_READ_REG(hw, I40E_VFQF_HENA(1))) << 32;
+	hena &= ~I40E_RSS_HENA_ALL;
+	I40E_WRITE_REG(hw, I40E_VFQF_HENA(0), (uint32_t)hena);
+	I40E_WRITE_REG(hw, I40E_VFQF_HENA(1), (uint32_t)(hena >> 32));
+	I40EVF_WRITE_FLUSH(hw);
+}
+
+static int
+i40evf_config_rss(struct i40e_vf *vf)
+{
+	struct i40e_hw *hw = I40E_VF_TO_HW(vf);
+	struct rte_eth_rss_conf rss_conf;
+	uint32_t i, j, lut = 0, nb_q = (I40E_VFQF_HLUT_MAX_INDEX + 1) * 4;
+
+	if (vf->dev_data->dev_conf.rxmode.mq_mode != ETH_MQ_RX_RSS) {
+		i40evf_disable_rss(vf);
+		PMD_DRV_LOG(DEBUG, "RSS not configured\n");
+		return 0;
+	}
+
+	/* Fill out the look up table */
+	for (i = 0, j = 0; i < nb_q; i++, j++) {
+		if (j >= vf->num_queue_pairs)
+			j = 0;
+		lut = (lut << 8) | j;
+		if ((i & 3) == 3)
+			I40E_WRITE_REG(hw, I40E_VFQF_HLUT(i >> 2), lut);
+	}
+
+	rss_conf = vf->dev_data->dev_conf.rx_adv_conf.rss_conf;
+	if ((rss_conf.rss_hf & I40E_RSS_OFFLOAD_ALL) == 0) {
+		i40evf_disable_rss(vf);
+		PMD_DRV_LOG(DEBUG, "No hash flag is set\n");
+		return 0;
+	}
+
+	if (rss_conf.rss_key == NULL || rss_conf.rss_key_len < nb_q) {
+		/* Calculate the default hash key */
+		for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++)
+			rss_key_default[i] = (uint32_t)rte_rand();
+		rss_conf.rss_key = (uint8_t *)rss_key_default;
+		rss_conf.rss_key_len = nb_q;
+	}
+
+	return i40evf_hw_rss_hash_set(hw, &rss_conf);
+}
+
+static int
+i40evf_dev_rss_reta_update(struct rte_eth_dev *dev,
+			   struct rte_eth_rss_reta *reta_conf)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint8_t i, j, mask, max = ETH_RSS_RETA_NUM_ENTRIES / 2;
+	uint32_t lut, l;
+
+	for (i = 0; i < ETH_RSS_RETA_NUM_ENTRIES; i += 4) {
+		if (i < max)
+			mask = (uint8_t)((reta_conf->mask_lo >> i) & 0xF);
+		else
+			mask = (uint8_t)((reta_conf->mask_hi >>
+						(i - max)) & 0xF);
+		if (!mask)
+			continue;
+		if (mask == 0xf)
+			l = 0;
+		else
+			l = I40E_READ_REG(hw, I40E_VFQF_HLUT(i >> 2));
+
+		for (j = 0, lut = 0; j < 4; j++) {
+			if (mask & (0x1 << j))
+				lut |= reta_conf->reta[i + j] << (8 * j);
+			else
+				lut |= l & (0xff << (8 * j));
+		}
+		I40E_WRITE_REG(hw, I40E_VFQF_HLUT(i >> 2), lut);
+	}
+
+	return 0;
+}
+
+static int
+i40evf_dev_rss_reta_query(struct rte_eth_dev *dev,
+			  struct rte_eth_rss_reta *reta_conf)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint8_t i, j, mask, max = ETH_RSS_RETA_NUM_ENTRIES / 2;
+	uint32_t lut;
+
+	for (i = 0; i < ETH_RSS_RETA_NUM_ENTRIES; i += 4) {
+		if (i < max)
+			mask = (uint8_t)((reta_conf->mask_lo >> i) & 0xF);
+		else
+			mask = (uint8_t)((reta_conf->mask_hi >>
+						(i - max)) & 0xF);
+		if (!mask)
+			continue;
+		lut = I40E_READ_REG(hw, I40E_VFQF_HLUT(i >> 2));
+		for (j = 0; j < 4; j++) {
+			if (mask & (0x1 << j))
+				reta_conf->reta[i + j] =
+					(uint8_t)((lut >> (8 * j)) & 0xFF);
+		}
+	}
+
+	return 0;
+}
+
+static int
+i40evf_dev_rss_hash_update(struct rte_eth_dev *dev,
+			   struct rte_eth_rss_conf *rss_conf)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint64_t rss_hf = rss_conf->rss_hf & I40E_RSS_OFFLOAD_ALL;
+	uint64_t hena;
+
+	hena = (uint64_t)I40E_READ_REG(hw, I40E_VFQF_HENA(0));
+	hena |= ((uint64_t)I40E_READ_REG(hw, I40E_VFQF_HENA(1))) << 32;
+	if (!(hena & I40E_RSS_HENA_ALL)) { /* RSS disabled */
+		if (rss_hf != 0) /* Enable RSS */
+			return -EINVAL;
+		return 0;
+	}
+
+	/* RSS enabled */
+	if (rss_hf == 0) /* Disable RSS */
+		return -EINVAL;
+
+	return i40evf_hw_rss_hash_set(hw, rss_conf);
+}
+
+static int
+i40evf_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
+			     struct rte_eth_rss_conf *rss_conf)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *hash_key = (uint32_t *)(rss_conf->rss_key);
+	uint64_t hena;
+	uint16_t i;
+
+	if (hash_key) {
+		for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++)
+			hash_key[i] = I40E_READ_REG(hw, I40E_VFQF_HKEY(i));
+		rss_conf->rss_key_len = i * sizeof(uint32_t);
+	}
+	hena = (uint64_t)I40E_READ_REG(hw, I40E_VFQF_HENA(0));
+	hena |= ((uint64_t)I40E_READ_REG(hw, I40E_VFQF_HENA(1))) << 32;
+	rss_conf->rss_hf = i40e_parse_hena(hena);
+
+	return 0;
+}