diff mbox

[dpdk-dev,v6,7/8] ethdev: support of multiple sizes of redirection table

Message ID 1416067424-31699-8-git-send-email-helin.zhang@intel.com (mailing list archive)
State Accepted, archived
Headers show

Commit Message

Helin Zhang Nov. 15, 2014, 4:03 p.m. UTC
As 40G NIC supports different sizes (128/512/64 entries) of
redirection table from that (128 entries) of 1G and 10G NICs,
support of multiple sizes of redirection table is needed.
It includes,
* Redefine 'struct rte_eth_rss_reta' in ethdev.
  - To 'struct rte_eth_rss_reta_entry64' which contains 64
    entries and 64 bits mask.
  - Array of above new structure can be used for any number of
    redirection table entries, as long as the number is multiple
    of 64. This is quite flexible for the future expanding of
    redirection table.
* Redefinition of relevant interfaces in ethdev.
  - Interface of reta update has been redefined with new parameters.
  - Interface of reta query has been redefined with new parameters.
* Rework of 1G PMD in igb.
  - reta update has been reworked.
  - reta query has been reworked.
* Rework of 10G PMD in ixgbe.
  - reta update has been reworked.
  - reta query has been reworked.
* Rework of 40G PMD (PF only) in i40e.
  - reta update has been reworked.
  - reta query has been reworked.
* Implement relevant commands in testpmd.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 app/test-pmd/cmdline.c              | 150 ++++++++++++++++++++++++++----------
 app/test-pmd/config.c               |  37 +++++----
 app/test-pmd/testpmd.h              |   4 +-
 lib/librte_ether/rte_ethdev.c       | 121 ++++++++++++++++++-----------
 lib/librte_ether/rte_ethdev.h       |  40 ++++++----
 lib/librte_pmd_e1000/igb_ethdev.c   | 118 +++++++++++++++-------------
 lib/librte_pmd_i40e/i40e_ethdev.c   |  93 ++++++++++++----------
 lib/librte_pmd_i40e/i40e_ethdev.h   |  13 +++-
 lib/librte_pmd_ixgbe/ixgbe_ethdev.c | 118 ++++++++++++++++------------
 9 files changed, 431 insertions(+), 263 deletions(-)

v2 changes:
* Put rework of updating/querying igb reta to a single patch.
* Put rework of updating/querying ixgbe reta to a single patch.
* Put rework of updating/querying i40e reta to a single patch.

v3 changes:
* Put all redefinitions of structures and interfaces into a single patch.
* Put all reworks of igb/igbe/i40e of supporting multiple sizes of reta into
  the same patch.
* Put all relevant testpmd reworks of supporting multiple sizes of reta into
  the same patch.

v4 changes:
* Renamed RTE_BIT_WIDTH_64 to RTE_RETA_GROUP_SIZE.
* Added more comments to rte_eth_dev_rss_reta_update() and
  rte_eth_dev_rss_reta_query().

v6 changes:
* Checking if the input parameter of reta size is 64 aligned has been added.
* Use macros to replace numerics in all the igb, ixgbe and i40e PMDs of
  updating/querying reta.
diff mbox

Patch

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index daba286..cf252e1 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -59,6 +59,7 @@ 
 #include <rte_cycles.h>
 #include <rte_memory.h>
 #include <rte_memzone.h>
+#include <rte_malloc.h>
 #include <rte_launch.h>
 #include <rte_tailq.h>
 #include <rte_eal.h>
@@ -186,6 +187,11 @@  static void cmd_help_long_parsed(void *parsed_result,
 			"show port (info|stats|xstats|fdir|stat_qmap) (port_id|all)\n"
 			"    Display information for port_id, or all.\n\n"
 
+			"show port X rss reta (size) (mask0,mask1,...)\n"
+			"    Display the rss redirection table entry indicated"
+			" by masks on port X. size is used to indicate the"
+			" hardware supported reta size\n\n"
+
 			"show port rss-hash [key]\n"
 			"    Display the RSS hash functions and RSS hash key"
 			" of port X\n\n"
@@ -1562,11 +1568,13 @@  struct cmd_config_rss_reta {
 };
 
 static int
-parse_reta_config(const char *str, struct rte_eth_rss_reta *reta_conf)
+parse_reta_config(const char *str,
+		  struct rte_eth_rss_reta_entry64 *reta_conf,
+		  uint16_t nb_entries)
 {
 	int i;
 	unsigned size;
-	uint8_t hash_index;
+	uint16_t hash_index, idx, shift;
 	uint8_t nb_queue;
 	char s[256];
 	const char *p, *p0 = str;
@@ -1594,24 +1602,23 @@  parse_reta_config(const char *str, struct rte_eth_rss_reta *reta_conf)
 		for (i = 0; i < _NUM_FLD; i++) {
 			errno = 0;
 			int_fld[i] = strtoul(str_fld[i], &end, 0);
-			if (errno != 0 || end == str_fld[i] || int_fld[i] > 255)
+			if (errno != 0 || end == str_fld[i] ||
+					int_fld[i] > 65535)
 				return -1;
 		}
 
-		hash_index = (uint8_t)int_fld[FLD_HASH_INDEX];
+		hash_index = (uint16_t)int_fld[FLD_HASH_INDEX];
 		nb_queue = (uint8_t)int_fld[FLD_QUEUE];
 
-		if (hash_index >= ETH_RSS_RETA_NUM_ENTRIES) {
-			printf("Invalid RETA hash index=%d", hash_index);
+		if (hash_index >= nb_entries) {
+			printf("Invalid RETA hash index=%d\n", hash_index);
 			return -1;
 		}
 
-		if (hash_index < ETH_RSS_RETA_NUM_ENTRIES/2)
-			reta_conf->mask_lo |= (1ULL << hash_index);
-		else
-			reta_conf->mask_hi |= (1ULL << (hash_index - ETH_RSS_RETA_NUM_ENTRIES/2));
-
-		reta_conf->reta[hash_index] = nb_queue;
+		idx = hash_index / RTE_RETA_GROUP_SIZE;
+		shift = hash_index % RTE_RETA_GROUP_SIZE;
+		reta_conf[idx].mask |= (1ULL << shift);
+		reta_conf[idx].reta[shift] = nb_queue;
 	}
 
 	return 0;
@@ -1623,17 +1630,35 @@  cmd_set_rss_reta_parsed(void *parsed_result,
 			__attribute__((unused)) void *data)
 {
 	int ret;
-	struct rte_eth_rss_reta reta_conf;
+	struct rte_eth_dev_info dev_info;
+	struct rte_eth_rss_reta_entry64 reta_conf[8];
 	struct cmd_config_rss_reta *res = parsed_result;
 
-	memset(&reta_conf, 0, sizeof(struct rte_eth_rss_reta));
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(res->port_id, &dev_info);
+	if (dev_info.reta_size == 0) {
+		printf("Redirection table size is 0 which is "
+					"invalid for RSS\n");
+		return;
+	} else
+		printf("The reta size of port %d is %u\n",
+			res->port_id, dev_info.reta_size);
+	if (dev_info.reta_size > ETH_RSS_RETA_SIZE_512) {
+		printf("Currently do not support more than %u entries of "
+			"redirection table\n", ETH_RSS_RETA_SIZE_512);
+		return;
+	}
+
+	memset(reta_conf, 0, sizeof(reta_conf));
 	if (!strcmp(res->list_name, "reta")) {
-		if (parse_reta_config(res->list_of_items, &reta_conf)) {
-			printf("Invalid RSS Redirection Table config "
-							"entered\n");
+		if (parse_reta_config(res->list_of_items, reta_conf,
+						dev_info.reta_size)) {
+			printf("Invalid RSS Redirection Table "
+					"config entered\n");
 			return;
 		}
-		ret = rte_eth_dev_rss_reta_update(res->port_id, &reta_conf);
+		ret = rte_eth_dev_rss_reta_update(res->port_id,
+				reta_conf, dev_info.reta_size);
 		if (ret != 0)
 			printf("Bad redirection table parameter, "
 					"return code = %d \n", ret);
@@ -1675,26 +1700,73 @@  struct cmd_showport_reta {
 	uint8_t port_id;
 	cmdline_fixed_string_t rss;
 	cmdline_fixed_string_t reta;
-	uint64_t mask_lo;
-	uint64_t mask_hi;
+	uint16_t size;
+	cmdline_fixed_string_t list_of_items;
 };
 
-static void cmd_showport_reta_parsed(void *parsed_result,
-				__attribute__((unused)) struct cmdline *cl,
-				__attribute__((unused)) void *data)
+static int
+showport_parse_reta_config(struct rte_eth_rss_reta_entry64 *conf,
+			   uint16_t nb_entries,
+			   char *str)
 {
-	struct cmd_showport_reta *res = parsed_result;
-	struct rte_eth_rss_reta reta_conf;
+	uint32_t size;
+	const char *p, *p0 = str;
+	char s[256];
+	char *end;
+	char *str_fld[8];
+	uint16_t i, num = nb_entries / RTE_RETA_GROUP_SIZE;
+	int ret;
 
-	if ((res->mask_lo == 0) && (res->mask_hi == 0)) {
-		printf("Invalid RSS Redirection Table config entered\n");
-		return;
+	p = strchr(p0, '(');
+	if (p == NULL)
+		return -1;
+	p++;
+	p0 = strchr(p, ')');
+	if (p0 == NULL)
+		return -1;
+	size = p0 - p;
+	if (size >= sizeof(s)) {
+		printf("The string size exceeds the internal buffer size\n");
+		return -1;
 	}
+	snprintf(s, sizeof(s), "%.*s", size, p);
+	ret = rte_strsplit(s, sizeof(s), str_fld, num, ',');
+	if (ret <= 0 || ret != num) {
+		printf("The bits of masks do not match the number of "
+					"reta entries: %u\n", num);
+		return -1;
+	}
+	for (i = 0; i < ret; i++)
+		conf[i].mask = (uint64_t)strtoul(str_fld[i], &end, 0);
 
-	reta_conf.mask_lo = res->mask_lo;
-	reta_conf.mask_hi = res->mask_hi;
+	return 0;
+}
 
-	port_rss_reta_info(res->port_id,&reta_conf);
+static void
+cmd_showport_reta_parsed(void *parsed_result,
+			 __attribute__((unused)) struct cmdline *cl,
+			 __attribute__((unused)) void *data)
+{
+	struct cmd_showport_reta *res = parsed_result;
+	struct rte_eth_rss_reta_entry64 reta_conf[8];
+	struct rte_eth_dev_info dev_info;
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(res->port_id, &dev_info);
+	if (dev_info.reta_size == 0 || res->size != dev_info.reta_size ||
+				res->size > ETH_RSS_RETA_SIZE_512) {
+		printf("Invalid redirection table size: %u\n", res->size);
+		return;
+	}
+
+	memset(reta_conf, 0, sizeof(reta_conf));
+	if (showport_parse_reta_config(reta_conf, res->size,
+				res->list_of_items) < 0) {
+		printf("Invalid string: %s for reta masks\n",
+					res->list_of_items);
+		return;
+	}
+	port_rss_reta_info(res->port_id, reta_conf, res->size);
 }
 
 cmdline_parse_token_string_t cmd_showport_reta_show =
@@ -1707,24 +1779,24 @@  cmdline_parse_token_string_t cmd_showport_reta_rss =
 	TOKEN_STRING_INITIALIZER(struct cmd_showport_reta, rss, "rss");
 cmdline_parse_token_string_t cmd_showport_reta_reta =
 	TOKEN_STRING_INITIALIZER(struct cmd_showport_reta, reta, "reta");
-cmdline_parse_token_num_t cmd_showport_reta_mask_lo =
-	TOKEN_NUM_INITIALIZER(struct cmd_showport_reta, mask_lo, UINT64);
-cmdline_parse_token_num_t cmd_showport_reta_mask_hi =
-	TOKEN_NUM_INITIALIZER(struct cmd_showport_reta, mask_hi, UINT64);
+cmdline_parse_token_num_t cmd_showport_reta_size =
+	TOKEN_NUM_INITIALIZER(struct cmd_showport_reta, size, UINT16);
+cmdline_parse_token_string_t cmd_showport_reta_list_of_items =
+	TOKEN_STRING_INITIALIZER(struct cmd_showport_reta,
+					list_of_items, NULL);
 
 cmdline_parse_inst_t cmd_showport_reta = {
 	.f = cmd_showport_reta_parsed,
 	.data = NULL,
-	.help_str = "show port X rss reta mask_lo mask_hi (X = port number)\n\
-			(mask_lo and mask_hi is UINT64)",
+	.help_str = "show port X rss reta (size) (mask0,mask1,...)",
 	.tokens = {
 		(void *)&cmd_showport_reta_show,
 		(void *)&cmd_showport_reta_port,
 		(void *)&cmd_showport_reta_port_id,
 		(void *)&cmd_showport_reta_rss,
 		(void *)&cmd_showport_reta_reta,
-		(void *)&cmd_showport_reta_mask_lo,
-		(void *)&cmd_showport_reta_mask_hi,
+		(void *)&cmd_showport_reta_size,
+		(void *)&cmd_showport_reta_list_of_items,
 		NULL,
 	},
 };
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index 97a8715..749a23f 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -284,6 +284,7 @@  port_infos_display(portid_t port_id)
 	struct rte_port *port;
 	struct ether_addr mac_addr;
 	struct rte_eth_link link;
+	struct rte_eth_dev_info dev_info;
 	int vlan_offload;
 	struct rte_mempool * mp;
 	static const char *info_border = "*********************";
@@ -339,6 +340,11 @@  port_infos_display(portid_t port_id)
 		else
 			printf("  qinq(extend) off \n");
 	}
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+	if (dev_info.reta_size > 0)
+		printf("Redirection table size: %u\n", dev_info.reta_size);
 }
 
 int
@@ -758,36 +764,29 @@  rxtx_config_display(void)
 }
 
 void
-port_rss_reta_info(portid_t port_id,struct rte_eth_rss_reta *reta_conf)
+port_rss_reta_info(portid_t port_id,
+		   struct rte_eth_rss_reta_entry64 *reta_conf,
+		   uint16_t nb_entries)
 {
-	uint8_t i, j;
+	uint16_t i, idx, shift;
 	int ret;
 
 	if (port_id_is_invalid(port_id))
 		return;
 
-	ret = rte_eth_dev_rss_reta_query(port_id, reta_conf);
+	ret = rte_eth_dev_rss_reta_query(port_id, reta_conf, nb_entries);
 	if (ret != 0) {
 		printf("Failed to get RSS RETA info, return code = %d\n", ret);
 		return;
 	}
 
-	if (reta_conf->mask_lo != 0) {
-		for (i = 0; i< ETH_RSS_RETA_NUM_ENTRIES/2; i++) {
-			if (reta_conf->mask_lo & (uint64_t)(1ULL << i))
-				printf("RSS RETA configuration: hash index=%d,"
-					"queue=%d\n",i,reta_conf->reta[i]);
-		}
-	}
-
-	if (reta_conf->mask_hi != 0) {
-		for (i = 0; i< ETH_RSS_RETA_NUM_ENTRIES/2; i++) {
-			if(reta_conf->mask_hi & (uint64_t)(1ULL << i)) {
-				j = (uint8_t)(i + ETH_RSS_RETA_NUM_ENTRIES/2);
-				printf("RSS RETA configuration: hash index=%d,"
-					"queue=%d\n",j,reta_conf->reta[j]);
-			}
-		}
+	for (i = 0; i < nb_entries; i++) {
+		idx = i / RTE_RETA_GROUP_SIZE;
+		shift = i % RTE_RETA_GROUP_SIZE;
+		if (!(reta_conf[idx].mask & (1ULL << shift)))
+			continue;
+		printf("RSS RETA configuration: hash index=%u, queue=%u\n",
+					i, reta_conf[idx].reta[shift]);
 	}
 }
 
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 9cbfeac..10bf13f 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -533,7 +533,9 @@  void fdir_remove_perfect_filter(portid_t port_id, uint16_t soft_id,
 				struct rte_fdir_filter *fdir_filter);
 void fdir_set_masks(portid_t port_id, struct rte_fdir_masks *fdir_masks);
 
-void port_rss_reta_info(portid_t port_id, struct rte_eth_rss_reta *reta_conf);
+void port_rss_reta_info(portid_t port_id,
+			struct rte_eth_rss_reta_entry64 *reta_conf,
+			uint16_t nb_entries);
 
 void set_vf_traffic(portid_t port_id, uint8_t is_rx, uint16_t vf, uint8_t on);
 void set_vf_rx_vlan(portid_t port_id, uint16_t vlan_id,
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 8c65d72..3e2b5d8 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -1927,78 +1927,111 @@  rte_eth_dev_priority_flow_ctrl_set(uint8_t port_id, struct rte_eth_pfc_conf *pfc
 	return (-ENOTSUP);
 }
 
-int
-rte_eth_dev_rss_reta_update(uint8_t port_id, struct rte_eth_rss_reta *reta_conf)
+static inline int
+rte_eth_check_reta_mask(struct rte_eth_rss_reta_entry64 *reta_conf,
+			uint16_t reta_size)
 {
-	struct rte_eth_dev *dev;
-	uint16_t max_rxq;
-	uint8_t i,j;
+	uint16_t i, num;
 
-	if (port_id >= nb_ports) {
-		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
-		return (-ENODEV);
+	if (!reta_conf)
+		return -EINVAL;
+
+	if (reta_size != RTE_ALIGN(reta_size, RTE_RETA_GROUP_SIZE)) {
+		PMD_DEBUG_TRACE("Invalid reta size, should be %u aligned\n",
+							RTE_RETA_GROUP_SIZE);
+		return -EINVAL;
 	}
 
-	/* Invalid mask bit(s) setting */
-	if ((reta_conf->mask_lo == 0) && (reta_conf->mask_hi == 0)) {
-		PMD_DEBUG_TRACE("Invalid update mask bits for port=%d\n",port_id);
-		return (-EINVAL);
+	num = reta_size / RTE_RETA_GROUP_SIZE;
+	for (i = 0; i < num; i++) {
+		if (reta_conf[i].mask)
+			return 0;
 	}
 
-	dev = &rte_eth_devices[port_id];
-	max_rxq = (dev->data->nb_rx_queues <= ETH_RSS_RETA_MAX_QUEUE) ?
-		dev->data->nb_rx_queues : ETH_RSS_RETA_MAX_QUEUE;
-	if (reta_conf->mask_lo != 0) {
-		for (i = 0; i < ETH_RSS_RETA_NUM_ENTRIES/2; i++) {
-			if ((reta_conf->mask_lo & (1ULL << i)) &&
-				(reta_conf->reta[i] >= max_rxq)) {
-				PMD_DEBUG_TRACE("RETA hash index output"
-					"configration for port=%d,invalid"
-					"queue=%d\n",port_id,reta_conf->reta[i]);
+	return -EINVAL;
+}
 
-				return (-EINVAL);
-			}
+static inline int
+rte_eth_check_reta_entry(struct rte_eth_rss_reta_entry64 *reta_conf,
+			 uint16_t reta_size,
+			 uint8_t max_rxq)
+{
+	uint16_t i, idx, shift;
+
+	if (!reta_conf)
+		return -EINVAL;
+
+	if (max_rxq == 0) {
+		PMD_DEBUG_TRACE("No receive queue is available\n");
+		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] >= max_rxq)) {
+			PMD_DEBUG_TRACE("reta_conf[%u]->reta[%u]: %u exceeds "
+				"the maximum rxq index: %u\n", idx, shift,
+				reta_conf[idx].reta[shift], max_rxq);
+			return -EINVAL;
 		}
 	}
 
-	if (reta_conf->mask_hi != 0) {
-		for (i = 0; i< ETH_RSS_RETA_NUM_ENTRIES/2; i++) {
-			j = (uint8_t)(i + ETH_RSS_RETA_NUM_ENTRIES/2);
+	return 0;
+}
 
-			/* Check if the max entry >= 128 */
-			if ((reta_conf->mask_hi & (1ULL << i)) &&
-				(reta_conf->reta[j] >= max_rxq)) {
-				PMD_DEBUG_TRACE("RETA hash index output"
-					"configration for port=%d,invalid"
-					"queue=%d\n",port_id,reta_conf->reta[j]);
+int
+rte_eth_dev_rss_reta_update(uint8_t port_id,
+			    struct rte_eth_rss_reta_entry64 *reta_conf,
+			    uint16_t reta_size)
+{
+	struct rte_eth_dev *dev;
+	int ret;
 
-				return (-EINVAL);
-			}
-		}
+	if (port_id >= nb_ports) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
 	}
 
+	/* Check mask bits */
+	ret = rte_eth_check_reta_mask(reta_conf, reta_size);
+	if (ret < 0)
+		return ret;
+
+	dev = &rte_eth_devices[port_id];
+
+	/* Check entry value */
+	ret = rte_eth_check_reta_entry(reta_conf, reta_size,
+				dev->data->nb_rx_queues);
+	if (ret < 0)
+		return ret;
+
 	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->reta_update, -ENOTSUP);
-	return (*dev->dev_ops->reta_update)(dev, reta_conf);
+	return (*dev->dev_ops->reta_update)(dev, reta_conf, reta_size);
 }
 
 int
-rte_eth_dev_rss_reta_query(uint8_t port_id, struct rte_eth_rss_reta *reta_conf)
+rte_eth_dev_rss_reta_query(uint8_t port_id,
+			   struct rte_eth_rss_reta_entry64 *reta_conf,
+			   uint16_t reta_size)
 {
 	struct rte_eth_dev *dev;
+	int ret;
 
 	if (port_id >= nb_ports) {
 		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
-		return (-ENODEV);
+		return -ENODEV;
 	}
 
-	if((reta_conf->mask_lo == 0) && (reta_conf->mask_hi == 0)) {
-		PMD_DEBUG_TRACE("Invalid update mask bits for the port=%d\n",port_id);
-		return (-EINVAL);
-	}
+	/* Check mask bits */
+	ret = rte_eth_check_reta_mask(reta_conf, reta_size);
+	if (ret < 0)
+		return ret;
 
 	dev = &rte_eth_devices[port_id];
 	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->reta_query, -ENOTSUP);
-	return (*dev->dev_ops->reta_query)(dev, reta_conf);
+	return (*dev->dev_ops->reta_query)(dev, reta_conf, reta_size);
 }
 
 int
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 58dd2bf..fec4d4c 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -448,11 +448,10 @@  struct rte_eth_rss_conf {
  * Some RSS RETA sizes may not be supported by some drivers, check the
  * documentation or the description of relevant functions for more details.
  */
-#define ETH_RSS_RETA_NUM_ENTRIES 128
-#define ETH_RSS_RETA_MAX_QUEUE   16
 #define ETH_RSS_RETA_SIZE_64  64
 #define ETH_RSS_RETA_SIZE_128 128
 #define ETH_RSS_RETA_SIZE_512 512
+#define RTE_RETA_GROUP_SIZE   64
 
 /* Definitions used for VMDQ and DCB functionality */
 #define ETH_VMDQ_MAX_VLAN_FILTERS   64 /**< Maximum nb. of VMDQ vlan filters. */
@@ -516,15 +515,16 @@  struct rte_eth_vmdq_mirror_conf {
 };
 
 /**
- * A structure used to configure Redirection Table of  the Receive Side
- * Scaling (RSS) feature of an Ethernet port.
+ * A structure used to configure 64 entries of Redirection Table of the
+ * Receive Side Scaling (RSS) feature of an Ethernet port. To configure
+ * more than 64 entries supported by hardware, an array of this structure
+ * is needed.
  */
-struct rte_eth_rss_reta {
-	/** First 64 mask bits indicate which entry(s) need to updated/queried. */
-	uint64_t mask_lo;
-	/** Second 64 mask bits indicate which entry(s) need to updated/queried. */
-	uint64_t mask_hi;
-	uint8_t reta[ETH_RSS_RETA_NUM_ENTRIES];  /**< 128 RETA entries*/
+struct rte_eth_rss_reta_entry64 {
+	uint64_t mask;
+	/**< Mask bits indicate which entries need to be updated/queried. */
+	uint8_t reta[RTE_RETA_GROUP_SIZE];
+	/**< Group of 64 redirection table entries. */
 };
 
 /**
@@ -1221,11 +1221,13 @@  typedef int (*priority_flow_ctrl_set_t)(struct rte_eth_dev *dev,
 /**< @internal Setup priority flow control parameter on an Ethernet device */
 
 typedef int (*reta_update_t)(struct rte_eth_dev *dev,
-				struct rte_eth_rss_reta *reta_conf);
+			     struct rte_eth_rss_reta_entry64 *reta_conf,
+			     uint16_t reta_size);
 /**< @internal Update RSS redirection table on an Ethernet device */
 
 typedef int (*reta_query_t)(struct rte_eth_dev *dev,
-				struct rte_eth_rss_reta *reta_conf);
+			    struct rte_eth_rss_reta_entry64 *reta_conf,
+			    uint16_t reta_size);
 /**< @internal Query RSS redirection table on an Ethernet device */
 
 typedef int (*rss_hash_update_t)(struct rte_eth_dev *dev,
@@ -2961,14 +2963,18 @@  int rte_eth_dev_mac_addr_remove(uint8_t port, struct ether_addr *mac_addr);
  * @param port
  *   The port identifier of the Ethernet device.
  * @param reta_conf
- *    RETA to update.
+ *   RETA to update.
+ * @param reta_size
+ *   Redirection table size. The table size can be queried by
+ *   rte_eth_dev_info_get().
  * @return
  *   - (0) if successful.
  *   - (-ENOTSUP) if hardware doesn't support.
  *   - (-EINVAL) if bad parameter.
  */
 int rte_eth_dev_rss_reta_update(uint8_t port,
-			struct rte_eth_rss_reta *reta_conf);
+				struct rte_eth_rss_reta_entry64 *reta_conf,
+				uint16_t reta_size);
 
  /**
  * Query Redirection Table(RETA) of Receive Side Scaling of Ethernet device.
@@ -2977,13 +2983,17 @@  int rte_eth_dev_rss_reta_update(uint8_t port,
  *   The port identifier of the Ethernet device.
  * @param reta_conf
  *   RETA to query.
+ * @param reta_size
+ *   Redirection table size. The table size can be queried by
+ *   rte_eth_dev_info_get().
  * @return
  *   - (0) if successful.
  *   - (-ENOTSUP) if hardware doesn't support.
  *   - (-EINVAL) if bad parameter.
  */
 int rte_eth_dev_rss_reta_query(uint8_t port,
-			struct rte_eth_rss_reta *reta_conf);
+			       struct rte_eth_rss_reta_entry64 *reta_conf,
+			       uint16_t reta_size);
 
  /**
  * Updates unicast hash table for receiving packet with the given destination
diff --git a/lib/librte_pmd_e1000/igb_ethdev.c b/lib/librte_pmd_e1000/igb_ethdev.c
index bae4eb2..873d65e 100644
--- a/lib/librte_pmd_e1000/igb_ethdev.c
+++ b/lib/librte_pmd_e1000/igb_ethdev.c
@@ -69,6 +69,12 @@ 
 #define IGB_DEFAULT_TX_HTHRESH      0
 #define IGB_DEFAULT_TX_WTHRESH      0
 
+/* Bit shift and mask */
+#define IGB_4_BIT_WIDTH  (CHAR_BIT / 2)
+#define IGB_4_BIT_MASK   RTE_LEN2MASK(IGB_4_BIT_WIDTH, uint8_t)
+#define IGB_8_BIT_WIDTH  CHAR_BIT
+#define IGB_8_BIT_MASK   UINT8_MAX
+
 static int  eth_igb_configure(struct rte_eth_dev *dev);
 static int  eth_igb_start(struct rte_eth_dev *dev);
 static void eth_igb_stop(struct rte_eth_dev *dev);
@@ -138,10 +144,11 @@  static int igbvf_vlan_filter_set(struct rte_eth_dev *dev,
 static int igbvf_set_vfta(struct e1000_hw *hw, uint16_t vid, bool on);
 static void igbvf_set_vfta_all(struct rte_eth_dev *dev, bool on);
 static int eth_igb_rss_reta_update(struct rte_eth_dev *dev,
-		 struct rte_eth_rss_reta *reta_conf);
+				   struct rte_eth_rss_reta_entry64 *reta_conf,
+				   uint16_t reta_size);
 static int eth_igb_rss_reta_query(struct rte_eth_dev *dev,
-		struct rte_eth_rss_reta *reta_conf);
-
+				  struct rte_eth_rss_reta_entry64 *reta_conf,
+				  uint16_t reta_size);
 static int eth_igb_add_syn_filter(struct rte_eth_dev *dev,
 			struct rte_syn_filter *filter, uint16_t rx_queue);
 static int eth_igb_remove_syn_filter(struct rte_eth_dev *dev);
@@ -2303,38 +2310,40 @@  igbvf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 
 static int
 eth_igb_rss_reta_update(struct rte_eth_dev *dev,
-                                struct rte_eth_rss_reta *reta_conf)
+			struct rte_eth_rss_reta_entry64 *reta_conf,
+			uint16_t reta_size)
 {
-	uint8_t i,j,mask;
-	uint32_t reta;
-	struct e1000_hw *hw =
-			E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint8_t i, j, mask;
+	uint32_t reta, r;
+	uint16_t idx, shift;
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
-	/*
-	 * Update Redirection Table RETA[n],n=0...31,The redirection table has
-	 * 128-entries in 32 registers
-	 */
-	for(i = 0; i < ETH_RSS_RETA_NUM_ENTRIES; i += 4) {
-		if (i < ETH_RSS_RETA_NUM_ENTRIES/2)
-			mask = (uint8_t)((reta_conf->mask_lo >> i) & 0xF);
+	if (reta_size != ETH_RSS_RETA_SIZE_128) {
+		PMD_DRV_LOG(ERR, "The size of hash lookup table configured "
+			"(%d) doesn't match the number hardware can supported "
+			"(%d)\n", reta_size, ETH_RSS_RETA_SIZE_128);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < reta_size; i += IGB_4_BIT_WIDTH) {
+		idx = i / RTE_RETA_GROUP_SIZE;
+		shift = i % RTE_RETA_GROUP_SIZE;
+		mask = (uint8_t)((reta_conf[idx].mask >> shift) &
+						IGB_4_BIT_MASK);
+		if (!mask)
+			continue;
+		if (mask == IGB_4_BIT_MASK)
+			r = 0;
 		else
-			mask = (uint8_t)((reta_conf->mask_hi >>
-				(i - ETH_RSS_RETA_NUM_ENTRIES/2)) & 0xF);
-		if (mask != 0) {
-			reta = 0;
-			/* If all 4 entries were set,don't need read RETA register */
-			if (mask != 0xF)
-				reta = E1000_READ_REG(hw,E1000_RETA(i >> 2));
-
-			for (j = 0; j < 4; j++) {
-				if (mask & (0x1 << j)) {
-					if (mask != 0xF)
-						reta &= ~(0xFF << 8 * j);
-					reta |= reta_conf->reta[i + j] << 8 * j;
-				}
-			}
-			E1000_WRITE_REG(hw, E1000_RETA(i >> 2),reta);
+			r = E1000_READ_REG(hw, E1000_RETA(i >> 2));
+		for (j = 0, reta = 0; j < IGB_4_BIT_WIDTH; j++) {
+			if (mask & (0x1 << j))
+				reta |= reta_conf[idx].reta[shift + j] <<
+							(CHAR_BIT * j);
+			else
+				reta |= r & (IGB_8_BIT_MASK << (CHAR_BIT * j));
 		}
+		E1000_WRITE_REG(hw, E1000_RETA(i >> 2), reta);
 	}
 
 	return 0;
@@ -2342,31 +2351,34 @@  eth_igb_rss_reta_update(struct rte_eth_dev *dev,
 
 static int
 eth_igb_rss_reta_query(struct rte_eth_dev *dev,
-                                struct rte_eth_rss_reta *reta_conf)
+		       struct rte_eth_rss_reta_entry64 *reta_conf,
+		       uint16_t reta_size)
 {
-	uint8_t i,j,mask;
+	uint8_t i, j, mask;
 	uint32_t reta;
-	struct e1000_hw *hw =
-			E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint16_t idx, shift;
+	struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
-	/*
-	 * Read Redirection Table RETA[n],n=0...31,The redirection table has
-	 * 128-entries in 32 registers
-	 */
-	for(i = 0; i < ETH_RSS_RETA_NUM_ENTRIES; i += 4) {
-		if (i < ETH_RSS_RETA_NUM_ENTRIES/2)
-			mask = (uint8_t)((reta_conf->mask_lo >> i) & 0xF);
-		else
-			mask = (uint8_t)((reta_conf->mask_hi >>
-				(i - ETH_RSS_RETA_NUM_ENTRIES/2)) & 0xF);
-
-		if (mask != 0) {
-			reta = E1000_READ_REG(hw,E1000_RETA(i >> 2));
-			for (j = 0; j < 4; j++) {
-				if (mask & (0x1 << j))
-					reta_conf->reta[i + j] =
-						(uint8_t)((reta >> 8 * j) & 0xFF);
-			}
+	if (reta_size != ETH_RSS_RETA_SIZE_128) {
+		PMD_DRV_LOG(ERR, "The size of hash lookup table configured "
+			"(%d) doesn't match the number hardware can supported "
+			"(%d)\n", reta_size, ETH_RSS_RETA_SIZE_128);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < reta_size; i += IGB_4_BIT_WIDTH) {
+		idx = i / RTE_RETA_GROUP_SIZE;
+		shift = i % RTE_RETA_GROUP_SIZE;
+		mask = (uint8_t)((reta_conf[idx].mask >> shift) &
+						IGB_4_BIT_MASK);
+		if (!mask)
+			continue;
+		reta = E1000_READ_REG(hw, E1000_RETA(i >> 2));
+		for (j = 0; j < IGB_4_BIT_WIDTH; j++) {
+			if (mask & (0x1 << j))
+				reta_conf[idx].reta[shift + j] =
+					((reta >> (CHAR_BIT * j)) &
+						IGB_8_BIT_MASK);
 		}
 	}
 
diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 279ef52..3bd2416 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -73,14 +73,6 @@ 
 /* Maximun number of VSI */
 #define I40E_MAX_NUM_VSIS          (384UL)
 
-/* Bit shift and mask */
-#define I40E_16_BIT_SHIFT 16
-#define I40E_16_BIT_MASK  0xFFFF
-#define I40E_32_BIT_SHIFT 32
-#define I40E_32_BIT_MASK  0xFFFFFFFF
-#define I40E_48_BIT_SHIFT 48
-#define I40E_48_BIT_MASK  0xFFFFFFFFFFFFULL
-
 /* Default queue interrupt throttling time in microseconds*/
 #define I40E_ITR_INDEX_DEFAULT          0
 #define I40E_QUEUE_ITR_INTERVAL_DEFAULT 32 /* 32 us */
@@ -144,9 +136,11 @@  static void i40e_macaddr_add(struct rte_eth_dev *dev,
 			  uint32_t pool);
 static void i40e_macaddr_remove(struct rte_eth_dev *dev, uint32_t index);
 static int i40e_dev_rss_reta_update(struct rte_eth_dev *dev,
-				    struct rte_eth_rss_reta *reta_conf);
+				    struct rte_eth_rss_reta_entry64 *reta_conf,
+				    uint16_t reta_size);
 static int i40e_dev_rss_reta_query(struct rte_eth_dev *dev,
-				   struct rte_eth_rss_reta *reta_conf);
+				   struct rte_eth_rss_reta_entry64 *reta_conf,
+				   uint16_t reta_size);
 
 static int i40e_get_cap(struct i40e_hw *hw);
 static int i40e_pf_parameter_init(struct rte_eth_dev *dev);
@@ -1777,32 +1771,41 @@  i40e_mac_filter_handle(struct rte_eth_dev *dev, enum rte_filter_op filter_op,
 
 static int
 i40e_dev_rss_reta_update(struct rte_eth_dev *dev,
-			 struct rte_eth_rss_reta *reta_conf)
+			 struct rte_eth_rss_reta_entry64 *reta_conf,
+			 uint16_t reta_size)
 {
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
 	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	uint32_t lut, l;
-	uint8_t i, j, mask, max = ETH_RSS_RETA_NUM_ENTRIES / 2;
-
-	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);
+	uint16_t i, j, lut_size = pf->hash_lut_size;
+	uint16_t idx, shift;
+	uint8_t mask;
+
+	if (reta_size != lut_size ||
+		reta_size > ETH_RSS_RETA_SIZE_512) {
+		PMD_DRV_LOG(ERR, "The size of hash lookup table configured "
+			"(%d) doesn't match the number hardware can supported "
+					"(%d)\n", reta_size, lut_size);
+		return -EINVAL;
+	}
 
+	for (i = 0; i < reta_size; i += I40E_4_BIT_WIDTH) {
+		idx = i / RTE_RETA_GROUP_SIZE;
+		shift = i % RTE_RETA_GROUP_SIZE;
+		mask = (uint8_t)((reta_conf[idx].mask >> shift) &
+						I40E_4_BIT_MASK);
 		if (!mask)
 			continue;
-
-		if (mask == 0xF)
+		if (mask == I40E_4_BIT_MASK)
 			l = 0;
 		else
 			l = I40E_READ_REG(hw, I40E_PFQF_HLUT(i >> 2));
-
-		for (j = 0, lut = 0; j < 4; j++) {
+		for (j = 0, lut = 0; j < I40E_4_BIT_WIDTH; j++) {
 			if (mask & (0x1 << j))
-				lut |= reta_conf->reta[i + j] << (8 * j);
+				lut |= reta_conf[idx].reta[shift + j] <<
+							(CHAR_BIT * j);
 			else
-				lut |= l & (0xFF << (8 * j));
+				lut |= l & (I40E_8_BIT_MASK << (CHAR_BIT * j));
 		}
 		I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2), lut);
 	}
@@ -1812,27 +1815,37 @@  i40e_dev_rss_reta_update(struct rte_eth_dev *dev,
 
 static int
 i40e_dev_rss_reta_query(struct rte_eth_dev *dev,
-			struct rte_eth_rss_reta *reta_conf)
+			struct rte_eth_rss_reta_entry64 *reta_conf,
+			uint16_t reta_size)
 {
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
 	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	uint32_t lut;
-	uint8_t i, j, mask, max = ETH_RSS_RETA_NUM_ENTRIES / 2;
-
-	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);
+	uint16_t i, j, lut_size = pf->hash_lut_size;
+	uint16_t idx, shift;
+	uint8_t mask;
+
+	if (reta_size != lut_size ||
+		reta_size > ETH_RSS_RETA_SIZE_512) {
+		PMD_DRV_LOG(ERR, "The size of hash lookup table configured "
+			"(%d) doesn't match the number hardware can supported "
+					"(%d)\n", reta_size, lut_size);
+		return -EINVAL;
+	}
 
+	for (i = 0; i < reta_size; i += I40E_4_BIT_WIDTH) {
+		idx = i / RTE_RETA_GROUP_SIZE;
+		shift = i % RTE_RETA_GROUP_SIZE;
+		mask = (uint8_t)((reta_conf[idx].mask >> shift) &
+						I40E_4_BIT_MASK);
 		if (!mask)
 			continue;
 
 		lut = I40E_READ_REG(hw, I40E_PFQF_HLUT(i >> 2));
-		for (j = 0; j < 4; j++) {
+		for (j = 0; j < I40E_4_BIT_WIDTH; j++) {
 			if (mask & (0x1 << j))
-				reta_conf->reta[i + j] =
-					(uint8_t)((lut >> (8 * j)) & 0xFF);
+				reta_conf[idx].reta[shift] = ((lut >>
+					(CHAR_BIT * j)) & I40E_8_BIT_MASK);
 		}
 	}
 
@@ -3584,7 +3597,7 @@  i40e_stat_update_32(struct i40e_hw *hw,
 		*stat = (uint64_t)(new_data - *offset);
 	else
 		*stat = (uint64_t)((new_data +
-			((uint64_t)1 << I40E_32_BIT_SHIFT)) - *offset);
+			((uint64_t)1 << I40E_32_BIT_WIDTH)) - *offset);
 }
 
 static void
@@ -3599,7 +3612,7 @@  i40e_stat_update_48(struct i40e_hw *hw,
 
 	new_data = (uint64_t)I40E_READ_REG(hw, loreg);
 	new_data |= ((uint64_t)(I40E_READ_REG(hw, hireg) &
-			I40E_16_BIT_MASK)) << I40E_32_BIT_SHIFT;
+			I40E_16_BIT_MASK)) << I40E_32_BIT_WIDTH;
 
 	if (!offset_loaded)
 		*offset = new_data;
@@ -3608,7 +3621,7 @@  i40e_stat_update_48(struct i40e_hw *hw,
 		*stat = new_data - *offset;
 	else
 		*stat = (uint64_t)((new_data +
-			((uint64_t)1 << I40E_48_BIT_SHIFT)) - *offset);
+			((uint64_t)1 << I40E_48_BIT_WIDTH)) - *offset);
 
 	*stat &= I40E_48_BIT_MASK;
 }
diff --git a/lib/librte_pmd_i40e/i40e_ethdev.h b/lib/librte_pmd_i40e/i40e_ethdev.h
index dcb2adb..c30208e 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.h
+++ b/lib/librte_pmd_i40e/i40e_ethdev.h
@@ -67,6 +67,18 @@ 
 #define I40E_DEFAULT_TX_WTHRESH      0
 #define I40E_DEFAULT_TX_RSBIT_THRESH 32
 
+/* Bit shift and mask */
+#define I40E_4_BIT_WIDTH  (CHAR_BIT / 2)
+#define I40E_4_BIT_MASK   RTE_LEN2MASK(I40E_4_BIT_WIDTH, uint8_t)
+#define I40E_8_BIT_WIDTH  CHAR_BIT
+#define I40E_8_BIT_MASK   UINT8_MAX
+#define I40E_16_BIT_WIDTH (CHAR_BIT * 2)
+#define I40E_16_BIT_MASK  UINT16_MAX
+#define I40E_32_BIT_WIDTH (CHAR_BIT * 4)
+#define I40E_32_BIT_MASK  UINT32_MAX
+#define I40E_48_BIT_WIDTH (CHAR_BIT * 6)
+#define I40E_48_BIT_MASK  RTE_LEN2MASK(I40E_48_BIT_WIDTH, uint64_t)
+
 /* i40e flags */
 #define I40E_FLAG_RSS                   (1ULL << 0)
 #define I40E_FLAG_DCB                   (1ULL << 1)
@@ -282,7 +294,6 @@  struct i40e_pf {
 	uint16_t vf_nb_qps; /* The number of queue pairs of VF */
 	uint16_t fdir_nb_qps; /* The number of queue pairs of Flow Director */
 	uint16_t hash_lut_size; /* The size of hash lookup table */
-
 	/* store VXLAN UDP ports */
 	uint16_t vxlan_ports[I40E_MAX_PF_UDP_OFFLOAD_PORTS];
 	uint16_t vxlan_bitmap; /* Vxlan bit mask */
diff --git a/lib/librte_pmd_ixgbe/ixgbe_ethdev.c b/lib/librte_pmd_ixgbe/ixgbe_ethdev.c
index 099dfb0..08e3db4 100644
--- a/lib/librte_pmd_ixgbe/ixgbe_ethdev.c
+++ b/lib/librte_pmd_ixgbe/ixgbe_ethdev.c
@@ -106,6 +106,12 @@ 
 #define IXGBE_DEFAULT_TX_WTHRESH      0
 #define IXGBE_DEFAULT_TX_RSBIT_THRESH 32
 
+/* Bit shift and mask */
+#define IXGBE_4_BIT_WIDTH  (CHAR_BIT / 2)
+#define IXGBE_4_BIT_MASK   RTE_LEN2MASK(IXGBE_4_BIT_WIDTH, uint8_t)
+#define IXGBE_8_BIT_WIDTH  CHAR_BIT
+#define IXGBE_8_BIT_MASK   UINT8_MAX
+
 #define IXGBEVF_PMD_NAME "rte_ixgbevf_pmd" /* PMD name */
 
 #define IXGBE_QUEUE_STAT_COUNTERS (sizeof(hw_stats->qprc) / sizeof(hw_stats->qprc[0]))
@@ -159,9 +165,11 @@  static int ixgbe_flow_ctrl_set(struct rte_eth_dev *dev,
 static int ixgbe_priority_flow_ctrl_set(struct rte_eth_dev *dev,
 		struct rte_eth_pfc_conf *pfc_conf);
 static int ixgbe_dev_rss_reta_update(struct rte_eth_dev *dev,
-		struct rte_eth_rss_reta *reta_conf);
+			struct rte_eth_rss_reta_entry64 *reta_conf,
+			uint16_t reta_size);
 static int ixgbe_dev_rss_reta_query(struct rte_eth_dev *dev,
-		struct rte_eth_rss_reta *reta_conf);
+			struct rte_eth_rss_reta_entry64 *reta_conf,
+			uint16_t reta_size);
 static void ixgbe_dev_link_status_print(struct rte_eth_dev *dev);
 static int ixgbe_dev_lsc_interrupt_setup(struct rte_eth_dev *dev);
 static int ixgbe_dev_interrupt_get_status(struct rte_eth_dev *dev);
@@ -2715,38 +2723,42 @@  ixgbe_priority_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_pfc_conf *p
 
 static int
 ixgbe_dev_rss_reta_update(struct rte_eth_dev *dev,
-				struct rte_eth_rss_reta *reta_conf)
+			  struct rte_eth_rss_reta_entry64 *reta_conf,
+			  uint16_t reta_size)
 {
-	uint8_t i,j,mask;
-	uint32_t reta;
-	struct ixgbe_hw *hw =
-			IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint8_t i, j, mask;
+	uint32_t reta, r;
+	uint16_t idx, shift;
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
 	PMD_INIT_FUNC_TRACE();
-	/*
-	* Update Redirection Table RETA[n],n=0...31,The redirection table has
-	* 128-entries in 32 registers
-	 */
-	for(i = 0; i < ETH_RSS_RETA_NUM_ENTRIES; i += 4) {
-		if (i < ETH_RSS_RETA_NUM_ENTRIES/2)
-			mask = (uint8_t)((reta_conf->mask_lo >> i) & 0xF);
+	if (reta_size != ETH_RSS_RETA_SIZE_128) {
+		PMD_DRV_LOG(ERR, "The size of hash lookup table configured "
+			"(%d) doesn't match the number hardware can supported "
+			"(%d)\n", reta_size, ETH_RSS_RETA_SIZE_128);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < reta_size; i += IXGBE_4_BIT_WIDTH) {
+		idx = i / RTE_RETA_GROUP_SIZE;
+		shift = i % RTE_RETA_GROUP_SIZE;
+		mask = (uint8_t)((reta_conf[idx].mask >> shift) &
+						IXGBE_4_BIT_MASK);
+		if (!mask)
+			continue;
+		if (mask == IXGBE_4_BIT_MASK)
+			r = 0;
 		else
-			mask = (uint8_t)((reta_conf->mask_hi >>
-				(i - ETH_RSS_RETA_NUM_ENTRIES/2)) & 0xF);
-		if (mask != 0) {
-			reta = 0;
-			if (mask != 0xF)
-				reta = IXGBE_READ_REG(hw,IXGBE_RETA(i >> 2));
-
-			for (j = 0; j < 4; j++) {
-				if (mask & (0x1 << j)) {
-					if (mask != 0xF)
-						reta &= ~(0xFF << 8 * j);
-					reta |= reta_conf->reta[i + j] << 8*j;
-				}
-			}
-			IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2),reta);
+			r = IXGBE_READ_REG(hw, IXGBE_RETA(i >> 2));
+		for (j = 0, reta = 0; j < IXGBE_4_BIT_WIDTH; j++) {
+			if (mask & (0x1 << j))
+				reta |= reta_conf[idx].reta[shift + j] <<
+							(CHAR_BIT * j);
+			else
+				reta |= r & (IXGBE_8_BIT_MASK <<
+						(CHAR_BIT * j));
 		}
+		IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta);
 	}
 
 	return 0;
@@ -2754,32 +2766,36 @@  ixgbe_dev_rss_reta_update(struct rte_eth_dev *dev,
 
 static int
 ixgbe_dev_rss_reta_query(struct rte_eth_dev *dev,
-				struct rte_eth_rss_reta *reta_conf)
+			 struct rte_eth_rss_reta_entry64 *reta_conf,
+			 uint16_t reta_size)
 {
-	uint8_t i,j,mask;
+	uint8_t i, j, mask;
 	uint32_t reta;
-	struct ixgbe_hw *hw =
-			IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint16_t idx, shift;
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
 	PMD_INIT_FUNC_TRACE();
-	/*
-	 * Read Redirection Table RETA[n],n=0...31,The redirection table has
-	 * 128-entries in 32 registers
-	 */
-	for(i = 0; i < ETH_RSS_RETA_NUM_ENTRIES; i += 4) {
-		if (i < ETH_RSS_RETA_NUM_ENTRIES/2)
-			mask = (uint8_t)((reta_conf->mask_lo >> i) & 0xF);
-		else
-			mask = (uint8_t)((reta_conf->mask_hi >>
-				(i - ETH_RSS_RETA_NUM_ENTRIES/2)) & 0xF);
-
-		if (mask != 0) {
-			reta = IXGBE_READ_REG(hw,IXGBE_RETA(i >> 2));
-			for (j = 0; j < 4; j++) {
-				if (mask & (0x1 << j))
-					reta_conf->reta[i + j] =
-						(uint8_t)((reta >> 8 * j) & 0xFF);
-			}
+	if (reta_size != ETH_RSS_RETA_SIZE_128) {
+		PMD_DRV_LOG(ERR, "The size of hash lookup table configured "
+			"(%d) doesn't match the number hardware can supported "
+				"(%d)\n", reta_size, ETH_RSS_RETA_SIZE_128);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ETH_RSS_RETA_SIZE_128; i += IXGBE_4_BIT_WIDTH) {
+		idx = i / RTE_RETA_GROUP_SIZE;
+		shift = i % RTE_RETA_GROUP_SIZE;
+		mask = (uint8_t)((reta_conf[idx].mask >> shift) &
+						IXGBE_4_BIT_MASK);
+		if (!mask)
+			continue;
+
+		reta = IXGBE_READ_REG(hw, IXGBE_RETA(i >> 2));
+		for (j = 0; j < IXGBE_4_BIT_WIDTH; j++) {
+			if (mask & (0x1 << j))
+				reta_conf[idx].reta[shift + j] =
+					((reta >> (CHAR_BIT * j)) &
+						IXGBE_8_BIT_MASK);
 		}
 	}