[qca-ssdk-shell]: add hppe rss hash feature

Change-Id: I63bb5327eb5cfe815659f01dfd1da036eb325d06
Signed-off-by: mingxinh <mingxinh@codeaurora.org>
diff --git a/config b/config
index c8b49c1..2e391a8 100755
--- a/config
+++ b/config
@@ -144,6 +144,7 @@
 IN_VSI=TRUE
 IN_CTRLPKT=TRUE
 IN_SERVCODE=TRUE
+IN_RSS_HASH=TRUE
 IN_PPPOE=TRUE
 IN_BM=TRUE
 IN_SHAPER=TRUE
diff --git a/include/api/api_desc.h b/include/api/api_desc.h
index 84337af..d1bac59 100755
--- a/include/api/api_desc.h
+++ b/include/api/api_desc.h
@@ -1743,6 +1743,16 @@
     SW_PARAM_DEF(SW_API_MIRROR_ANALYSIS_CONFIG_GET, SW_MIRR_DIRECTION, sizeof(fal_mirr_direction_t), SW_PARAM_IN, "Direction"), \
     SW_PARAM_DEF(SW_API_MIRROR_ANALYSIS_CONFIG_GET, SW_MIRR_ANALYSIS_CONFIG, sizeof(fal_mirr_analysis_config_t), SW_PARAM_PTR|SW_PARAM_OUT, "Config"),
 
+#define SW_API_RSS_HASH_CONFIG_SET_DESC \
+    SW_PARAM_DEF(SW_API_RSS_HASH_CONFIG_SET, SW_UINT32, 4, SW_PARAM_IN, "Dev ID"), \
+    SW_PARAM_DEF(SW_API_RSS_HASH_CONFIG_SET, SW_RSS_HASH_MODE, sizeof(fal_rss_hash_mode_t), SW_PARAM_IN, "Mode"), \
+    SW_PARAM_DEF(SW_API_RSS_HASH_CONFIG_SET, SW_RSS_HASH_CONFIG, sizeof(fal_rss_hash_config_t), SW_PARAM_PTR|SW_PARAM_IN, "Config"),
+
+#define SW_API_RSS_HASH_CONFIG_GET_DESC \
+    SW_PARAM_DEF(SW_API_RSS_HASH_CONFIG_GET, SW_UINT32, 4, SW_PARAM_IN, "Dev ID"), \
+    SW_PARAM_DEF(SW_API_RSS_HASH_CONFIG_GET, SW_RSS_HASH_MODE, sizeof(fal_rss_hash_mode_t), SW_PARAM_IN, "Mode"), \
+    SW_PARAM_DEF(SW_API_RSS_HASH_CONFIG_GET, SW_RSS_HASH_CONFIG, sizeof(fal_rss_hash_config_t), SW_PARAM_PTR|SW_PARAM_OUT, "Config"),
+
 
 #define SW_API_RATE_QU_EGRL_SET_DESC \
     SW_PARAM_DEF(SW_API_RATE_QU_EGRL_SET, SW_UINT32, 4, SW_PARAM_IN, "Dev ID"),\
diff --git a/include/api/sw_api.h b/include/api/sw_api.h
index 9503c5f..d62ae8d 100755
--- a/include/api/sw_api.h
+++ b/include/api/sw_api.h
@@ -180,6 +180,8 @@
 		SW_EGRESS_MODE,
 		SW_CTRLPKT_PROFILE,
 		SW_SERVCODE_CONFIG,
+		SW_RSS_HASH_MODE,
+		SW_RSS_HASH_CONFIG,
 	SW_MIRR_ANALYSIS_CONFIG,
 	SW_MIRR_DIRECTION,
         SW_L3_PARSER,
diff --git a/include/api/sw_ioctl.h b/include/api/sw_ioctl.h
index 59b9fd4..6a94cef 100755
--- a/include/api/sw_ioctl.h
+++ b/include/api/sw_ioctl.h
@@ -780,6 +780,11 @@
 #define SW_API_FLOW_HOST_DEL         (21  + SW_API_FLOW_OFFSET)
 #define SW_API_FLOW_HOST_GET         (22  + SW_API_FLOW_OFFSET)
 
+/* rss hash */
+#define SW_API_RSS_HASH_OFFSET		2400
+#define SW_API_RSS_HASH_CONFIG_SET	(0 + SW_API_RSS_HASH_OFFSET)
+#define SW_API_RSS_HASH_CONFIG_GET	(1 + SW_API_RSS_HASH_OFFSET)
+
 /* bm */
 #define SW_API_BM_OFFSET            3000
 #define SW_API_BM_CTRL_SET         (0  + SW_API_BM_OFFSET)
diff --git a/include/fal/fal.h b/include/fal/fal.h
index 4115fe8..df73997 100755
--- a/include/fal/fal.h
+++ b/include/fal/fal.h
@@ -50,6 +50,7 @@
 #include "fal_flow.h"
 #include "fal_ctrlpkt.h"
 #include "fal_servcode.h"
+#include "fal_rss_hash.h"
 #include "fal_pppoe.h"
 #include "fal_shaper.h"
 #include "fal_bm.h"
diff --git a/include/fal/fal_api.h b/include/fal/fal_api.h
index 7b69dd9..fdbac87 100755
--- a/include/fal/fal_api.h
+++ b/include/fal/fal_api.h
@@ -1697,6 +1697,19 @@
 #define SERVCODE_API_PARAM
 #endif
 
+#ifdef IN_RSS_HASH
+#define RSS_HASH_API \
+    SW_API_DEF(SW_API_RSS_HASH_CONFIG_SET, fal_rss_hash_config_set), \
+    SW_API_DEF(SW_API_RSS_HASH_CONFIG_GET, fal_rss_hash_config_get),
+
+#define RSS_HASH_API_PARAM \
+    SW_API_DESC(SW_API_RSS_HASH_CONFIG_SET) \
+    SW_API_DESC(SW_API_RSS_HASH_CONFIG_GET)
+#else
+#define RSS_HASH_API
+#define RSS_HASH_API_PARAM
+#endif
+
 #ifdef IN_SHAPER
 #define SHAPER_API \
     SW_API_DEF(SW_API_PORT_SHAPER_TIMESLOT_SET, fal_port_shaper_timeslot_set), \
@@ -1815,6 +1828,7 @@
     REG_API \
     CTRLPKT_API \
     SERVCODE_API \
+	RSS_HASH_API \
 	POLICER_API \
 	SHAPER_API \
     SW_API_DEF(SW_API_MAX, NULL),
@@ -1858,6 +1872,7 @@
     REG_API_PARAM \
     CTRLPKT_API_PARAM \
     SERVCODE_API_PARAM \
+	RSS_HASH_API_PARAM \
 	POLICER_API_PARAM \
 	SHAPER_API_PARAM \
     SW_PARAM_DEF(SW_API_MAX, SW_UINT32, 4, SW_PARAM_IN, "Dev ID"),
diff --git a/include/fal/fal_init.h b/include/fal/fal_init.h
index 29ab5f4..e00237c 100755
--- a/include/fal/fal_init.h
+++ b/include/fal/fal_init.h
@@ -35,6 +35,7 @@
 	FAL_MODULE_QOS,
 	FAL_MODULE_BM,
 	FAL_MODULE_SERVCODE,
+	FAL_MODULE_RSS_HASH,
 	FAL_MODULE_PPPOE,
 	FAL_MODULE_SHAPER,
 	FAL_MODULE_PORTCTRL,
diff --git a/include/fal/fal_rss_hash.h b/include/fal/fal_rss_hash.h
new file mode 100755
index 0000000..a37e329
--- /dev/null
+++ b/include/fal/fal_rss_hash.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all copies.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/**
+ * @defgroup fal_gen FAL_RSS_HASH
+ * @{
+ */
+#ifndef _FAL_RSS_HASH_H_
+#define _FAL_RSS_HASH_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif                          /* __cplusplus */
+
+#include "common/sw.h"
+#include "fal/fal_type.h"
+
+typedef enum
+{
+	FAL_RSS_HASH_IPV4V6 = 0,
+	FAL_RSS_HASH_IPV4ONLY = 1,
+	FAL_RSS_HASH_IPV6ONLY = 2,
+} fal_rss_hash_mode_t;
+
+typedef struct
+{
+	a_uint32_t 	hash_mask; /* final hash value bits */
+	a_bool_t	hash_fragment_mode; /* enable fragment mode or not */
+	a_uint32_t	hash_seed; /* rss hash seed value */
+	a_uint32_t	hash_sip_mix; /* source ip hash mix */
+	a_uint32_t	hash_dip_mix; /* dest ip hash mix */
+	a_uint8_t	hash_protocol_mix; /* L4 protocol hash mix */
+	a_uint8_t	hash_sport_mix; /* L4 source port hash mix */
+	a_uint8_t	hash_dport_mix; /* L4 dest port hash mix */
+	a_uint32_t	hash_fin_inner; /* hash fin inner mix */
+	a_uint32_t	hash_fin_outer; /* hash fin outer mix */
+} fal_rss_hash_config_t;
+
+enum {
+	FUNC_RSS_HASH_CONFIG_SET = 0,
+	FUNC_RSS_HASH_CONFIG_GET,
+};
+
+sw_error_t
+fal_rss_hash_config_set(a_uint32_t dev_id, fal_rss_hash_mode_t mode, fal_rss_hash_config_t * config);
+
+sw_error_t
+fal_rss_hash_config_get(a_uint32_t dev_id, fal_rss_hash_mode_t mode, fal_rss_hash_config_t * config);
+
+#ifdef __cplusplus
+}
+#endif                          /* __cplusplus */
+#endif                          /* _FAL_RSS_HASH_H_ */
+/**
+ * @}
+ */
+
diff --git a/include/shell/shell_io.h b/include/shell/shell_io.h
index af52b0a..983cf31 100755
--- a/include/shell/shell_io.h
+++ b/include/shell/shell_io.h
@@ -765,6 +765,15 @@
 cmd_data_print_servcode_config(a_uint8_t * param_name, a_uint32_t * buf, a_uint32_t size);
 
 sw_error_t
+cmd_data_check_rss_hash_mode(char *cmd_str, a_uint32_t * arg_val, a_uint32_t size);
+
+sw_error_t
+cmd_data_check_rss_hash_config(char *info, fal_rss_hash_config_t *val, a_uint32_t size);
+
+void
+cmd_data_print_rss_hash_config(a_uint8_t * param_name, a_uint32_t * buf, a_uint32_t size);
+
+sw_error_t
 cmd_data_check_port_policer_config(char *cmd_str, void * val, a_uint32_t size);
 
 sw_error_t
diff --git a/make/linux_opt.mk b/make/linux_opt.mk
index e0cf4ba..9854ce1 100755
--- a/make/linux_opt.mk
+++ b/make/linux_opt.mk
@@ -106,6 +106,10 @@
   MODULE_CFLAG += -DIN_SERVCODE
 endif
 
+ifeq (TRUE, $(IN_RSS_HASH))
+  MODULE_CFLAG += -DIN_RSS_HASH
+endif
+
 ifeq (TRUE, $(IN_MACBLOCK))
   MODULE_CFLAG += -DIN_MACBLOCK
 endif
diff --git a/src/fal_uk/Makefile b/src/fal_uk/Makefile
index 6555b8d..2d27883 100755
--- a/src/fal_uk/Makefile
+++ b/src/fal_uk/Makefile
@@ -93,6 +93,10 @@
   SRC_LIST += fal_servcode.c
 endif
 
+ifeq (TRUE, $(IN_RSS_HASH))
+  SRC_LIST += fal_rss_hash.c
+endif
+
 ifeq (TRUE, $(IN_VSI))
   SRC_LIST += fal_vsi.c
 endif
diff --git a/src/fal_uk/fal_rss_hash.c b/src/fal_uk/fal_rss_hash.c
new file mode 100755
index 0000000..28b67b5
--- /dev/null
+++ b/src/fal_uk/fal_rss_hash.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all copies.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+
+#include "sw.h"
+#include "sw_ioctl.h"
+#include "fal_rss_hash.h"
+#include "fal_uk_if.h"
+
+sw_error_t
+fal_rss_hash_config_set(a_uint32_t dev_id, fal_rss_hash_mode_t mode, fal_rss_hash_config_t * config)
+{
+    sw_error_t rv;
+
+    rv = sw_uk_exec(SW_API_RSS_HASH_CONFIG_SET, dev_id, mode,
+                    config);
+    return rv;
+}
+
+sw_error_t
+fal_rss_hash_config_get(a_uint32_t dev_id, fal_rss_hash_mode_t mode, fal_rss_hash_config_t * config)
+{
+    sw_error_t rv;
+
+    rv = sw_uk_exec(SW_API_RSS_HASH_CONFIG_GET, dev_id, mode,
+                    config);
+    return rv;
+}
+
diff --git a/src/shell/shell_config.c b/src/shell/shell_config.c
index de3bfbd..be89308 100755
--- a/src/shell/shell_config.c
+++ b/src/shell/shell_config.c
@@ -953,6 +953,18 @@
     },
 #endif
 
+	/*RSS HASH*/
+#ifdef IN_RSS_HASH
+	{
+		"rsshash", "config rss hash code",
+		{
+			{"Config", "set", "set ipv4/ipv6 rss hash code", "<ipv4v6|ipv4|ipv6>", SW_API_RSS_HASH_CONFIG_SET, NULL},
+			{"Config", "get", "get ipv4/ipv6 rss hash code", "<ipv4v6|ipv4|ipv6>", SW_API_RSS_HASH_CONFIG_GET, NULL},
+			{NULL, NULL, NULL, NULL, (int)NULL, NULL}/*end of desc*/
+		},
+	},
+#endif
+
 #ifdef IN_POLICER
 	{
 		"policer", "config policer",
diff --git a/src/shell/shell_io.c b/src/shell/shell_io.c
index 0bef767..c810334 100755
--- a/src/shell/shell_io.c
+++ b/src/shell/shell_io.c
@@ -289,6 +289,8 @@
     SW_TYPE_DEF(SW_EGRESS_MODE, cmd_data_check_egress_mode, cmd_data_print_egress_mode),
     SW_TYPE_DEF(SW_CTRLPKT_PROFILE, cmd_data_check_ctrlpkt_profile, cmd_data_print_ctrlpkt_profile),
     SW_TYPE_DEF(SW_SERVCODE_CONFIG, cmd_data_check_servcode_config, cmd_data_print_servcode_config),
+    SW_TYPE_DEF(SW_RSS_HASH_MODE, cmd_data_check_rss_hash_mode, NULL),
+    SW_TYPE_DEF(SW_RSS_HASH_CONFIG, cmd_data_check_rss_hash_config, cmd_data_print_rss_hash_config),
     SW_TYPE_DEF(SW_L3_PARSER, cmd_data_check_l3_parser, cmd_data_print_l3_parser),
     SW_TYPE_DEF(SW_L4_PARSER, cmd_data_check_l4_parser, cmd_data_print_l4_parser),
     SW_TYPE_DEF(SW_EXP_CTRL, cmd_data_check_exp_ctrl, cmd_data_print_exp_ctrl),
@@ -23204,6 +23206,301 @@
 }
 
 sw_error_t
+cmd_data_check_rss_hash_mode(char *cmd_str, a_uint32_t * arg_val, a_uint32_t size)
+{
+    if (cmd_str == NULL)
+        return SW_BAD_PARAM;
+
+    if (!strcasecmp(cmd_str, "ipv4v6"))
+    {
+        *arg_val = FAL_RSS_HASH_IPV4V6;
+    }
+    else if (!strcasecmp(cmd_str, "ipv4"))
+    {
+        *arg_val = FAL_RSS_HASH_IPV4ONLY;
+    }
+    else if (!strcasecmp(cmd_str, "ipv6"))
+    {
+        *arg_val = FAL_RSS_HASH_IPV6ONLY;
+    }
+    else
+    {
+        //dprintf("input error \n");
+        return SW_BAD_VALUE;
+    }
+
+    return SW_OK;
+}
+
+sw_error_t
+cmd_data_check_rss_hash_config(char *info, fal_rss_hash_config_t *val, a_uint32_t size)
+{
+	char *cmd = NULL;
+	sw_error_t rv;
+	fal_rss_hash_config_t entry;
+
+	memset(&entry, 0, sizeof (fal_rss_hash_config_t));
+
+	do
+	{
+		cmd = get_sub_cmd("hash_mask", "0");
+		SW_RTN_ON_NULL_PARAM(cmd);
+
+		if (!strncasecmp(cmd, "quit", 4))
+		{
+			return SW_BAD_VALUE;
+		}
+		else if (!strncasecmp(cmd, "help", 4))
+		{
+			dprintf("hash_mask: 0 - 0x1fffff\n");
+			rv = SW_BAD_VALUE;
+		}
+		else
+		{
+			rv = cmd_data_check_uint32(cmd, &entry.hash_mask, sizeof (a_uint32_t));
+			if (SW_OK != rv)
+				dprintf("hash_mask: 0 - 0x1fffff\n");
+		}
+	}
+	while (talk_mode && (SW_OK != rv));
+
+	do
+	{
+		cmd = get_sub_cmd("hash_fragment_mode", "no");
+		SW_RTN_ON_NULL_PARAM(cmd);
+
+		if (!strncasecmp(cmd, "quit", 4))
+		{
+			return SW_BAD_VALUE;
+		}
+		else if (!strncasecmp(cmd, "help", 4))
+		{
+			dprintf("usage: <yes/no/y/n>\n");
+			rv = SW_BAD_VALUE;
+		}
+		else
+		{
+			rv = cmd_data_check_confirm(cmd, A_FALSE, &entry.hash_fragment_mode,
+					sizeof (a_bool_t));
+			if (SW_OK != rv)
+				dprintf("usage: <yes/no/y/n>\n");
+		}
+	}
+	while (talk_mode && (SW_OK != rv));
+
+	do
+	{
+		cmd = get_sub_cmd("hash_seed", "0");
+		SW_RTN_ON_NULL_PARAM(cmd);
+
+		if (!strncasecmp(cmd, "quit", 4))
+		{
+			return SW_BAD_VALUE;
+		}
+		else if (!strncasecmp(cmd, "help", 4))
+		{
+			dprintf("hash_mask: 0 - 0xffffffff\n");
+			rv = SW_BAD_VALUE;
+		}
+		else
+		{
+			rv = cmd_data_check_uint32(cmd, &entry.hash_seed, sizeof (a_uint32_t));
+			if (SW_OK != rv)
+				dprintf("hash_mask: 0 - ffffffff\n");
+		}
+	}
+	while (talk_mode && (SW_OK != rv));
+
+	do
+	{
+		cmd = get_sub_cmd("hash_sip_mix", "0");
+		SW_RTN_ON_NULL_PARAM(cmd);
+
+		if (!strncasecmp(cmd, "quit", 4))
+		{
+			return SW_BAD_VALUE;
+		}
+		else if (!strncasecmp(cmd, "help", 4))
+		{
+			dprintf("hash_mask: 0 - 0xfffff\n");
+			rv = SW_BAD_VALUE;
+		}
+		else
+		{
+			rv = cmd_data_check_uint32(cmd, &entry.hash_sip_mix, sizeof (a_uint32_t));
+			if (SW_OK != rv)
+				dprintf("hash_mask: 0 - 0xfffff\n");
+		}
+	}
+	while (talk_mode && (SW_OK != rv));
+
+	do
+	{
+		cmd = get_sub_cmd("hash_dip_mix", "0");
+		SW_RTN_ON_NULL_PARAM(cmd);
+
+		if (!strncasecmp(cmd, "quit", 4))
+		{
+			return SW_BAD_VALUE;
+		}
+		else if (!strncasecmp(cmd, "help", 4))
+		{
+			dprintf("hash_mask: 0 - 0xfffff\n");
+			rv = SW_BAD_VALUE;
+		}
+		else
+		{
+			rv = cmd_data_check_uint32(cmd, &entry.hash_dip_mix, sizeof (a_uint32_t));
+			if (SW_OK != rv)
+				dprintf("hash_mask: 0 - 0xfffff\n");
+		}
+	}
+	while (talk_mode && (SW_OK != rv));
+
+	do
+	{
+		cmd = get_sub_cmd("hash_protocol_mix", "0");
+		SW_RTN_ON_NULL_PARAM(cmd);
+
+		if (!strncasecmp(cmd, "quit", 4))
+		{
+			return SW_BAD_VALUE;
+		}
+		else if (!strncasecmp(cmd, "help", 4))
+		{
+			dprintf("hash_mask: 0 - 0x1f\n");
+			rv = SW_BAD_VALUE;
+		}
+		else
+		{
+			rv = cmd_data_check_uint32(cmd, &entry.hash_protocol_mix, sizeof (a_uint32_t));
+			if (SW_OK != rv)
+				dprintf("hash_mask: 0 - 0x1f\n");
+		}
+	}
+	while (talk_mode && (SW_OK != rv));
+
+	do
+	{
+		cmd = get_sub_cmd("hash_sport_mix", "0");
+		SW_RTN_ON_NULL_PARAM(cmd);
+
+		if (!strncasecmp(cmd, "quit", 4))
+		{
+			return SW_BAD_VALUE;
+		}
+		else if (!strncasecmp(cmd, "help", 4))
+		{
+			dprintf("hash_mask: 0 - 0x1f\n");
+			rv = SW_BAD_VALUE;
+		}
+		else
+		{
+			rv = cmd_data_check_uint32(cmd, &entry.hash_sport_mix, sizeof (a_uint32_t));
+			if (SW_OK != rv)
+				dprintf("hash_mask: 0 - 0x1f\n");
+		}
+	}
+	while (talk_mode && (SW_OK != rv));
+
+	do
+	{
+		cmd = get_sub_cmd("hash_dport_mix", "0");
+		SW_RTN_ON_NULL_PARAM(cmd);
+
+		if (!strncasecmp(cmd, "quit", 4))
+		{
+			return SW_BAD_VALUE;
+		}
+		else if (!strncasecmp(cmd, "help", 4))
+		{
+			dprintf("hash_mask: 0 - 0x1f\n");
+			rv = SW_BAD_VALUE;
+		}
+		else
+		{
+			rv = cmd_data_check_uint32(cmd, &entry.hash_dport_mix, sizeof (a_uint32_t));
+			if (SW_OK != rv)
+				dprintf("hash_mask: 0 - 0x1f\n");
+		}
+	}
+	while (talk_mode && (SW_OK != rv));
+
+	do
+	{
+		cmd = get_sub_cmd("hash_fin_inner", "0");
+		SW_RTN_ON_NULL_PARAM(cmd);
+
+		if (!strncasecmp(cmd, "quit", 4))
+		{
+			return SW_BAD_VALUE;
+		}
+		else if (!strncasecmp(cmd, "help", 4))
+		{
+			dprintf("hash_mask: 0 - 0x1ffffff\n");
+			rv = SW_BAD_VALUE;
+		}
+		else
+		{
+			rv = cmd_data_check_uint32(cmd, &entry.hash_fin_inner, sizeof (a_uint32_t));
+			if (SW_OK != rv)
+				dprintf("hash_mask: 0 - 0x1ffffff\n");
+		}
+	}
+	while (talk_mode && (SW_OK != rv));
+
+	do
+	{
+		cmd = get_sub_cmd("hash_fin_outer", "0");
+		SW_RTN_ON_NULL_PARAM(cmd);
+
+		if (!strncasecmp(cmd, "quit", 4))
+		{
+			return SW_BAD_VALUE;
+		}
+		else if (!strncasecmp(cmd, "help", 4))
+		{
+			dprintf("hash_mask: 0 - 0x1ffffff\n");
+			rv = SW_BAD_VALUE;
+		}
+		else
+		{
+			rv = cmd_data_check_uint32(cmd, &entry.hash_fin_outer, sizeof (a_uint32_t));
+			if (SW_OK != rv)
+				dprintf("hash_mask: 0 - 0x1ffffff\n");
+		}
+	}
+	while (talk_mode && (SW_OK != rv));
+
+	*val = entry;
+	return SW_OK;
+}
+
+void
+cmd_data_print_rss_hash_config(a_uint8_t * param_name, a_uint32_t * buf, a_uint32_t size)
+{
+	fal_rss_hash_config_t *entry;
+
+	entry = (fal_rss_hash_config_t *) buf;
+
+	dprintf("\nhash_mask:0x%x  hash_fragment_mode:%s\n",
+				entry->hash_mask,
+				entry->hash_fragment_mode? "ENABLE" : "DISABLE");
+	dprintf("hash_seed:0x%x  hash_sip_mix:0x%x\n",
+				entry->hash_seed,
+				entry->hash_sip_mix);
+	dprintf("hash_dip_mix:0x%x  hash_protocol_mix:0x%x\n",
+				entry->hash_dip_mix,
+				entry->hash_protocol_mix);
+	dprintf("hash_sport_mix:0x%x  hash_dport_mix:0x%x\n",
+				entry->hash_sport_mix,
+				entry->hash_dport_mix);
+	dprintf("hash_fin_inner:0x%x  hash_fin_outer:0x%x\n",
+				entry->hash_fin_inner,
+				entry->hash_fin_outer);
+}
+
+sw_error_t
 cmd_data_check_flow_host(char *cmd_str, void * val, a_uint32_t size)
 {
         fal_flow_host_entry_t *flow_host = (fal_flow_host_entry_t *)val;
diff --git a/src/shell/shell_module_ctrl.c b/src/shell/shell_module_ctrl.c
index 9081435..7fd3f2f 100755
--- a/src/shell/shell_module_ctrl.c
+++ b/src/shell/shell_module_ctrl.c
@@ -81,6 +81,8 @@
         *arg_val = FAL_MODULE_BM;
     } else if (!strcasecmp(cmd_str, "servcode")) {
         *arg_val = FAL_MODULE_SERVCODE;
+    } else if (!strcasecmp(cmd_str, "rsshash")) {
+        *arg_val = FAL_MODULE_RSS_HASH;
     } else if (!strcasecmp(cmd_str, "pppoe")) {
         *arg_val = FAL_MODULE_PPPOE;
     } else if (!strcasecmp(cmd_str, "portctrl")) {
@@ -135,6 +137,8 @@
         dprintf("bm");
     } else if (*(a_uint32_t *) buf == FAL_MODULE_SERVCODE) {
         dprintf("servcode");
+    } else if (*(a_uint32_t *) buf == FAL_MODULE_RSS_HASH) {
+        dprintf("rsshash");
     } else if (*(a_uint32_t *) buf == FAL_MODULE_PPPOE) {
         dprintf("pppoe");
     } else if (*(a_uint32_t *) buf == FAL_MODULE_PORTCTRL) {
@@ -500,6 +504,28 @@
 	return;
 }
 
+static void cmd_data_print_rss_hash_func_ctrl(fal_func_ctrl_t *p)
+{
+	a_uint32_t func = 0;
+	char *func_name[FUNC_RSS_HASH_CONFIG_GET+1] ={
+		"FUNC_RSS_HASH_CONFIG_SET",
+		"FUNC_RSS_HASH_CONFIG_GET",
+	};
+
+	for(func = FUNC_RSS_HASH_CONFIG_SET; func <= FUNC_RSS_HASH_CONFIG_GET; func++)
+	{
+		if(p->bitmap[0] & (1<<func))
+		{
+			dprintf("%d  %s  registered\n", func, func_name[func]);
+		}
+		else
+		{
+			dprintf("%d  %s  unregistered\n", func, func_name[func]);
+		}
+	}
+	return;
+}
+
 static void cmd_data_print_pppoe_func_ctrl(fal_func_ctrl_t *p)
 {
 	a_uint32_t func = 0;
@@ -968,6 +994,8 @@
 		cmd_data_print_bm_func_ctrl(p);
 	} else if (module == FAL_MODULE_SERVCODE) {
 		cmd_data_print_servcode_func_ctrl(p);
+	} else if (module == FAL_MODULE_RSS_HASH) {
+		cmd_data_print_rss_hash_func_ctrl(p);
 	} else if (module == FAL_MODULE_PPPOE) {
 		cmd_data_print_pppoe_func_ctrl(p);
 	} else if (module == FAL_MODULE_PORTCTRL) {