Merge "[qca-nss-drv] Correct NETIF flags check"
diff --git a/Makefile b/Makefile
index b8c176c..0cdc956 100644
--- a/Makefile
+++ b/Makefile
@@ -65,7 +65,7 @@
 ccflags-y += -DNSS_PM_DEBUG_LEVEL=0 -DNSS_PPP_SUPPORT=1
 
 ifneq ($(findstring 3.4, $(KERNELVERSION)),)
-NSS_CCFLAGS = -DNSS_DT_SUPPORT=0 -DNSS_FW_DBG_SUPPORT=1 -DNSS_PM_SUPPORT=1 -DNSS_EMPTY_BUFFER_SIZE=2048
+NSS_CCFLAGS = -DNSS_DT_SUPPORT=0 -DNSS_FW_DBG_SUPPORT=1 -DNSS_PM_SUPPORT=1 -DNSS_EMPTY_BUFFER_SIZE=1984
 else
 NSS_CCFLAGS = -DNSS_DT_SUPPORT=1 -DNSS_FW_DBG_SUPPORT=0 -DNSS_PM_SUPPORT=0 -DNSS_EMPTY_BUFFER_SIZE=1792
 ccflags-y += -I$(obj)
diff --git a/exports/nss_ipv4.h b/exports/nss_ipv4.h
index 3e8d786..eb103be 100644
--- a/exports/nss_ipv4.h
+++ b/exports/nss_ipv4.h
@@ -38,6 +38,7 @@
 	NSS_IPV4_RX_NODE_STATS_SYNC_MSG,	/**< IPv4 generic statistics sync message */
 	NSS_IPV4_TX_CONN_CFG_RULE_MSG,		/**< IPv4 number of connections supported rule message */
 	NSS_IPV4_TX_CREATE_MC_RULE_MSG,		/**< IPv4 multicast create rule message */
+	NSS_IPV4_TX_CONN_STATS_SYNC_MANY_MSG,	/**< IPv4 request FW to send many conn sync message */
 	NSS_IPV4_MAX_MSG_TYPES,			/**< IPv4 message max type number */
 };
 
@@ -350,6 +351,20 @@
 };
 
 /**
+ * The NSS IPv4 conn sync many structure.
+ */
+struct nss_ipv4_conn_sync_many_msg {
+	/* Request */
+	uint16_t index;		/**< Request conn stats from index */
+	uint16_t size;		/**< The buf size of this msg */
+
+	/* Response */
+	uint16_t next;		/**< FW response the next conn to be requested */
+	uint16_t count;		/**< How many conn_sync included in this msg */
+	struct nss_ipv4_conn_sync conn_sync[]; /**< Array for the stats */
+};
+
+/**
  * Exception events from bridge/route handler
  */
 enum exception_events_ipv4 {
@@ -480,7 +495,8 @@
 		struct nss_ipv4_conn_sync conn_stats;	/**< Message: connection stats sync */
 		struct nss_ipv4_node_sync node_stats;	/**< Message: node stats sync */
 		struct nss_ipv4_rule_conn_cfg_msg rule_conn_cfg;	/**< Message: rule connections supported */
-		struct nss_ipv4_mc_rule_create_msg mc_rule_create; /**<Message: Multicast rule create */
+		struct nss_ipv4_mc_rule_create_msg mc_rule_create; /**< Message: Multicast rule create */
+		struct nss_ipv4_conn_sync_many_msg conn_stats_many;	/**< Message: connection stats sync */
 	} msg;
 };
 
@@ -511,6 +527,17 @@
 extern nss_tx_status_t nss_ipv4_tx(struct nss_ctx_instance *nss_ctx, struct nss_ipv4_msg *msg);
 
 /**
+ * @brief Transmit an IPv4 message to the NSS with specified size
+ *
+ * @param nss_ctx NSS context
+ * @param msg The IPv4 message
+ * @param size Actual size of this msg
+ *
+ * @return nss_tx_status_t The status of the Tx operation
+ */
+extern nss_tx_status_t nss_ipv4_tx_with_size(struct nss_ctx_instance *nss_ctx, struct nss_ipv4_msg *msg, uint32_t size);
+
+/**
  * @brief Register a notifier callback for IPv4 messages from NSS
  *
  * @param cb The callback pointer
diff --git a/exports/nss_ipv6.h b/exports/nss_ipv6.h
index 8f6bbf7..b1b0d56 100644
--- a/exports/nss_ipv6.h
+++ b/exports/nss_ipv6.h
@@ -38,6 +38,7 @@
 	NSS_IPV6_RX_NODE_STATS_SYNC_MSG,	/**< IPv6 generic statistics sync message */
 	NSS_IPV6_TX_CONN_CFG_RULE_MSG,		/**< IPv6 connection cfg rule message */
 	NSS_IPV6_TX_CREATE_MC_RULE_MSG,		/**< IPv6 create multicast rule message */
+	NSS_IPV6_TX_CONN_STATS_SYNC_MANY_MSG,	/**< IPv6 connection stats sync many message */
 	NSS_IPV6_MAX_MSG_TYPES,
 };
 
@@ -394,6 +395,20 @@
 };
 
 /**
+ * NSS IPv6 connection stats sync many structure
+ */
+struct nss_ipv6_conn_sync_many_msg {
+	/* Request */
+	uint16_t index;		/**< Request conn stats from index */
+	uint16_t size;		/**< The buf size of this msg */
+
+	/* Response */
+	uint16_t next;		/**< FW response the next conn to be requested */
+	uint16_t count;		/**< How many conn_sync included in this msg */
+	struct nss_ipv6_conn_sync conn_sync[];	/**< Array for the stats */
+};
+
+/**
  * NSS IPv6 node stats sync structure
  */
 struct nss_ipv6_node_sync {
@@ -448,7 +463,8 @@
 		struct nss_ipv6_conn_sync conn_stats;		/**< Message: stats sync */
 		struct nss_ipv6_node_sync node_stats;		/**< Message: node stats sync */
 		struct nss_ipv6_rule_conn_cfg_msg rule_conn_cfg;/**< Message: rule conn cfg */
-		struct nss_ipv6_mc_rule_create_msg mc_rule_create; /**<Message: Multicast rule create */
+		struct nss_ipv6_mc_rule_create_msg mc_rule_create; /**< Message: Multicast rule create */
+		struct nss_ipv6_conn_sync_many_msg conn_stats_many; /**< Message: stats sync many */
 	} msg;
 };
 
@@ -477,6 +493,17 @@
 extern nss_tx_status_t nss_ipv6_tx(struct nss_ctx_instance *nss_ctx, struct nss_ipv6_msg *msg);
 
 /**
+ * @brief Transmit an IPv6 message to the NSS with specified size
+ *
+ * @param nss_ctx NSS context
+ * @param msg The IPv6 message
+ * @param size Actual size of this message
+ *
+ * @return nss_tx_status_t The status of the Tx operation
+ */
+extern nss_tx_status_t nss_ipv6_tx_with_size(struct nss_ctx_instance *nss_ctx, struct nss_ipv6_msg *msg, uint32_t size);
+
+/**
  * @brief Register a notifier callback for IPv6 messages from NSS
  *
  * @param cb The callback pointer
diff --git a/exports/nss_n2h.h b/exports/nss_n2h.h
index cb20caa..7290c97 100644
--- a/exports/nss_n2h.h
+++ b/exports/nss_n2h.h
@@ -27,13 +27,17 @@
 #ifndef __NSS_N2H_H
 #define __NSS_N2H_H
 
+#define MAX_PAGES_PER_MSG 32
+
 /*
  * Private data structure for configure general configs
  */
 struct nss_n2h_cfg_pvt {
 	struct semaphore sem;			/* Semaphore structure */
 	struct completion complete;		/* completion structure */
-	int current_value;			/* valid entry */
+	int empty_buf_pool;			/* valid entry */
+	int low_water;				/* valid entry */
+	int high_water;				/* valid entry */
 	int response;				/* Response from FW */
 };
 
@@ -45,6 +49,10 @@
 	NSS_TX_METADATA_TYPE_N2H_RPS_CFG,
 	NSS_TX_METADATA_TYPE_N2H_EMPTY_POOL_BUF_CFG,
 	NSS_TX_METADATA_TYPE_N2H_FLUSH_PAYLOADS,
+	NSS_TX_METADATA_TYPE_N2H_MITIGATION_CFG,
+	NSS_METADATA_TYPE_N2H_ADD_BUF_POOL,
+	NSS_TX_METADATA_TYPE_SET_WATER_MARK,
+	NSS_TX_METADATA_TYPE_GET_PAYLOAD_INFO,
 	NSS_METADATA_TYPE_N2H_MAX,
 };
 
@@ -52,8 +60,51 @@
 	uint32_t enable; /* Enable NSS RPS */
 };
 
+struct nss_n2h_mitigation {
+	uint32_t enable; /* Enable NSS MITIGATION */
+};
+
+struct nss_n2h_buf_pool {
+	uint32_t nss_buf_page_size;
+	uint32_t nss_buf_num_pages;
+	void *nss_buf_pool_vaddr[MAX_PAGES_PER_MSG];
+	uint32_t nss_buf_pool_addr[MAX_PAGES_PER_MSG];
+};
+
+/*
+ * Old way of setting number of empty pool buffers (payloads).
+ * NSS FW then sets low water mark to 'n - ring_size' and
+ * high water mark to 'n + ring_size'.
+ */
 struct nss_n2h_empty_pool_buf {
-	uint32_t pool_size; /* Empty pool buf size */
+	uint32_t pool_size;	/* Empty buffer pool size */
+};
+
+/*
+ * New way of setting low and high water marks in the NSS FW.
+ */
+struct nss_n2h_water_mark {
+	/*
+	 * Low water mark. Set it to 0 for system to determine automatically.
+	 */
+	uint32_t low_water;
+
+	/*
+	 * High water mark. Set it to 0 for system to determine automatically.
+	 */
+	uint32_t high_water;
+};
+
+struct nss_n2h_payload_info {
+	uint32_t pool_size;	/* Empty buffer pool size */
+	/*
+	 * Low water mark. Set it to 0 for system to determine automatically.
+	 */
+	uint32_t low_water;
+	/*
+	 * High water mark. Set it to 0 for system to determine automatically.
+	 */
+	uint32_t high_water;
 };
 
 struct nss_n2h_flush_payloads {
@@ -64,9 +115,9 @@
  * NSS Pbuf mgr stats
  */
 struct nss_n2h_pbuf_mgr_stats {
-	uint32_t pbuf_alloc_fails;		/* Pbuf ocm alloc fail */
-	uint32_t pbuf_free_count;		/* Pbuf ocm free count */
-	uint32_t pbuf_total_count;		/* Pbuf ocm total count */
+	uint32_t pbuf_alloc_fails;		/* Pbuf alloc fail */
+	uint32_t pbuf_free_count;		/* Pbuf free count */
+	uint32_t pbuf_total_count;		/* Pbuf total count */
 };
 
 /*
@@ -97,6 +148,7 @@
 	uint32_t h2n_data_bytes;	/* Data bytes received from HLOS */
 	uint32_t n2h_data_pkts;		/* Data packets sent to HLOS */
 	uint32_t n2h_data_bytes;	/* Data bytes sent to HLOS */
+	uint32_t tot_payloads;		/* Total number of payloads in NSS FW */
 };
 
 /*
@@ -111,6 +163,13 @@
 							/* Message: empty pool buf configuration */
 		struct nss_n2h_flush_payloads flush_payloads;
 							/* Message: flush payloads present in NSS */
+		struct nss_n2h_mitigation mitigation_cfg;
+							/* Message: Mitigation configuration */
+		struct nss_n2h_buf_pool buf_pool;	/* Message: pbuf coniguration */
+		struct nss_n2h_water_mark wm;
+				/* Message: Sets low and high water marks */
+		struct nss_n2h_payload_info payload_info;
+				/* Message: Gets payload info */
 	} msg;
 };
 
@@ -132,6 +191,18 @@
 extern nss_tx_status_t nss_n2h_rps_cfg(struct nss_ctx_instance *nss_ctx, int enable_rps);
 
 /*
+ * nss_n2h_mitigation_cfg()
+ * 	API to enable/disable Host MITIGATION support in NSS
+ */
+extern nss_tx_status_t nss_n2h_mitigation_cfg(struct nss_ctx_instance *nss_ctx, int enable_mitigation, nss_core_id_t nss_core);
+
+/*
+ * nss_n2h_buf_pool_cfg()
+ * 	API to increase the pbufs on NSS using Host memory
+ */
+extern nss_tx_status_t nss_n2h_buf_pool_cfg(struct nss_ctx_instance *nss_ctx, int nss_pbuf_pool_size, nss_core_id_t nss_core);
+
+/*
  * nss_n2h_empty_pool_buf_register_sysctl()
  *	API to register sysctl for empty pool buffer in n2h.
  */
diff --git a/exports/nss_wifi_vdev.h b/exports/nss_wifi_vdev.h
index 62175ef..b0a3726 100644
--- a/exports/nss_wifi_vdev.h
+++ b/exports/nss_wifi_vdev.h
@@ -41,6 +41,7 @@
 	NSS_WIFI_VDEV_SNOOPLIST_DENY_LIST_DELETE_MSG,
 	NSS_WIFI_VDEV_SNOOPLIST_DENY_LIST_DUMP_MSG,
 	NSS_WIFI_VDEV_SNOOPLIST_DUMP_MSG,
+	NSS_WIFI_VDEV_SNOOPLIST_RESET_MSG,
 	NSS_WIFI_VDEV_MAX_MSG
 };
 
diff --git a/nss_core.h b/nss_core.h
index 89638ed..38c586b 100755
--- a/nss_core.h
+++ b/nss_core.h
@@ -49,6 +49,8 @@
 /*
  * NSS debug macros
  */
+#define nss_info_always(s, ...) pr_alert(s, ##__VA_ARGS__)
+
 #if (NSS_DEBUG_LEVEL < 1)
 #define nss_assert(fmt, args...)
 #else
@@ -482,6 +484,7 @@
 	NSS_STATS_N2H_H2N_DATA_BYTES,		/* Data bytes received from HLOS */
 	NSS_STATS_N2H_N2H_DATA_PACKETS,		/* Data packets sent to HLOS */
 	NSS_STATS_N2H_N2H_DATA_BYTES,		/* Data bytes sent to HLOS */
+	NSS_STATS_N2H_N2H_TOT_PAYLOADS,		/* No. of payloads in NSS */
 
 	NSS_STATS_N2H_MAX,
 };
@@ -619,8 +622,10 @@
 					/* Host to NSS descriptor rings */
 	struct hlos_n2h_desc_ring n2h_desc_ring[15];
 					/* NSS to Host descriptor rings */
-	uint8_t n2h_rps_en;		/* N2H Enable Multiple queues for Data Packets */
+	uint16_t n2h_rps_en;		/* N2H Enable Multiple queues for Data Packets */
+	uint16_t n2h_mitigate_en;	/* N2H mitigation */
 	uint32_t max_buf_size;		/* Maximum buffer size */
+	uint32_t buf_sz_allocated;	/* size of bufs allocated from host */
 	nss_cmn_queue_decongestion_callback_t queue_decongestion_callback[NSS_MAX_CLIENTS];
 					/* Queue decongestion callbacks */
 	void *queue_decongestion_ctx[NSS_MAX_CLIENTS];
diff --git a/nss_data_plane.c b/nss_data_plane.c
index 1549b2e..d9c3d0d 100644
--- a/nss_data_plane.c
+++ b/nss_data_plane.c
@@ -20,7 +20,7 @@
 #include "nss_tx_rx_common.h"
 #include <nss_gmac_api_if.h>
 
-#define NSS_DP_SUPPORTED_FEATURES NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_FRAGLIST | (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_UFO)
+#define NSS_DP_SUPPORTED_FEATURES NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_FRAGLIST | (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_UFO)
 
 struct nss_data_plane_param nss_data_plane_params[NSS_MAX_PHYSICAL_INTERFACES];
 
diff --git a/nss_hal/fsm9010/nss_hal_pvt.c b/nss_hal/fsm9010/nss_hal_pvt.c
index 6c99955..8410373 100644
--- a/nss_hal/fsm9010/nss_hal_pvt.c
+++ b/nss_hal/fsm9010/nss_hal_pvt.c
@@ -436,7 +436,6 @@
 #endif
 		nss_eth_rx_register_handler();
 		nss_n2h_register_handler();
-		nss_virt_if_register_handler();
 		nss_lag_register_handler();
 		nss_dynamic_interface_register_handler();
 
diff --git a/nss_init.c b/nss_init.c
index dbc52dd..a41f463 100755
--- a/nss_init.c
+++ b/nss_init.c
@@ -47,12 +47,18 @@
 #include <linux/regulator/consumer.h>
 #include <linux/clk.h>
 
+#define NSS_N2H_MAX_BUF_POOL_SIZE (1024 * 1024 * 4) /* 4MB */
+
 /*
  * Global declarations
  */
 int nss_ctl_redirect __read_mostly = 0;
 int nss_ctl_debug __read_mostly = 0;
 int nss_rps_cfg __read_mostly = 0;
+int nss_core0_mitigation_cfg __read_mostly = 1;
+int nss_core1_mitigation_cfg __read_mostly = 1;
+int nss_core0_add_buf_pool_size __read_mostly = 0;
+int nss_core1_add_buf_pool_size __read_mostly = 0;
 int nss_ctl_logbuf __read_mostly = 0;
 int nss_jumbo_mru  __read_mostly = 0;
 int nss_paged_mode __read_mostly = 0;
@@ -433,6 +439,146 @@
 }
 
 /*
+ * nss_mitigation_handler()
+ * Enable NSS MITIGATION
+ */
+static int nss_mitigationcfg_core0_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	struct nss_top_instance *nss_top = &nss_top_main;
+	struct nss_ctx_instance *nss_ctx = &nss_top->nss[NSS_CORE_0];
+	int ret;
+
+	ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
+	if (ret) {
+		return ret;
+	}
+
+	/*
+	 * It's a read operation
+	 */
+	if (!write) {
+		return ret;
+	}
+
+	if (!nss_core0_mitigation_cfg ) {
+		printk("Disabling NSS MITIGATION\n");
+		nss_n2h_mitigation_cfg(nss_ctx, 0, NSS_CORE_0);
+		return 0;
+	}
+	printk("Invalid input value.Valid value is 0, Runtime re-enabling not supported\n");
+	return -EINVAL;
+}
+
+/*
+ * nss_mitigation_handler()
+ * Enable NSS MITIGATION
+ */
+static int nss_mitigationcfg_core1_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	struct nss_top_instance *nss_top = &nss_top_main;
+	struct nss_ctx_instance *nss_ctx = &nss_top->nss[NSS_CORE_1];
+	int ret;
+
+	ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
+	if (ret) {
+		return ret;;
+	}
+
+	/*
+	 * It's a read operation
+	 */
+	if (!write) {
+		return ret;
+	}
+
+	if (!nss_core1_mitigation_cfg ) {
+		printk("Disabling NSS MITIGATION\n");
+		nss_n2h_mitigation_cfg(nss_ctx, 0, NSS_CORE_1);
+		return 0;
+	}
+	printk("Invalid input value.Valid value is 0, Runtime re-enabling not supported\n");
+	return -EINVAL;
+}
+
+/*
+ * nss_buf_handler()
+ *	Add extra NSS bufs from host memory
+ */
+static int nss_buf_cfg_core0_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	struct nss_top_instance *nss_top = &nss_top_main;
+	struct nss_ctx_instance *nss_ctx = &nss_top->nss[NSS_CORE_0];
+	int ret;
+
+	ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
+	if (ret) {
+		return ret;
+	}
+
+	/*
+	 * It's a read operation
+	 */
+	if (!write) {
+		return ret;
+	}
+
+	if (nss_ctx->buf_sz_allocated) {
+		nss_core0_add_buf_pool_size = nss_ctx->buf_sz_allocated;
+		return -EPERM;
+	}
+
+	if ((nss_core0_add_buf_pool_size >= 1) && (nss_core0_add_buf_pool_size <= NSS_N2H_MAX_BUF_POOL_SIZE)) {
+		printk("configuring additional NSS pbufs\n");
+		ret = nss_n2h_buf_pool_cfg(nss_ctx, nss_core0_add_buf_pool_size, NSS_CORE_0);
+		nss_core0_add_buf_pool_size = nss_ctx->buf_sz_allocated;
+		printk("additional pbufs of size %d got added to NSS\n", nss_ctx->buf_sz_allocated);
+		return ret;;
+	}
+
+	printk("Invalid input value. should be greater than 1 and less than %d\n", NSS_N2H_MAX_BUF_POOL_SIZE);
+	return -EINVAL;
+}
+
+/*
+ * nss_buf_handler()
+ *	Add extra NSS bufs from host memory
+ */
+static int nss_buf_cfg_core1_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	struct nss_top_instance *nss_top = &nss_top_main;
+	struct nss_ctx_instance *nss_ctx = &nss_top->nss[NSS_CORE_1];
+	int ret;
+
+	ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
+	if (ret) {
+		return ret;
+	}
+
+	/*
+	 * It's a read operation
+	 */
+	if (!write) {
+		return ret;
+	}
+
+	if (nss_ctx->buf_sz_allocated) {
+		nss_core1_add_buf_pool_size = nss_ctx->buf_sz_allocated;
+		return -EPERM;
+	}
+
+	if ((nss_core1_add_buf_pool_size >= 1) && (nss_core1_add_buf_pool_size <= NSS_N2H_MAX_BUF_POOL_SIZE)) {
+		printk("configuring additional NSS pbufs\n");
+		ret = nss_n2h_buf_pool_cfg(nss_ctx, nss_core1_add_buf_pool_size, NSS_CORE_1);
+		nss_core1_add_buf_pool_size = nss_ctx->buf_sz_allocated;
+		printk("additional pbufs of size %d got added to NSS\n", nss_ctx->buf_sz_allocated);
+		return ret;
+	}
+
+	printk("Invalid input value. should be greater than 1 and less than %d\n", NSS_N2H_MAX_BUF_POOL_SIZE);
+	return -EINVAL;
+}
+
+/*
  * nss_coredump_handler()
  *	Send Signal To Coredump NSS Cores
  */
@@ -563,6 +709,34 @@
 		.proc_handler   	= &nss_rpscfg_handler,
 	},
 	{
+		.procname               = "mitigation_core0",
+		.data                   = &nss_core0_mitigation_cfg,
+		.maxlen                 = sizeof(int),
+		.mode                   = 0644,
+		.proc_handler           = &nss_mitigationcfg_core0_handler,
+	},
+	{
+		.procname               = "mitigation_core1",
+		.data                   = &nss_core1_mitigation_cfg,
+		.maxlen                 = sizeof(int),
+		.mode                   = 0644,
+		.proc_handler           = &nss_mitigationcfg_core1_handler,
+	},
+	{
+		.procname               = "extra_pbuf_core0",
+		.data                   = &nss_core0_add_buf_pool_size,
+		.maxlen                 = sizeof(int),
+		.mode                   = 0644,
+		.proc_handler   	= &nss_buf_cfg_core0_handler,
+	},
+	{
+		.procname               = "extra_pbuf_core1",
+		.data                   = &nss_core1_add_buf_pool_size,
+		.maxlen                 = sizeof(int),
+		.mode                   = 0644,
+		.proc_handler   	= &nss_buf_cfg_core1_handler,
+	},
+	{
 		.procname               = "logbuf",
 		.data                   = &nss_ctl_logbuf,
 		.maxlen                 = sizeof(int),
@@ -641,8 +815,8 @@
 	 */
 	cmn = of_find_node_by_name(NULL, "nss-common");
 	if (!cmn) {
-		nss_info("cannot find nss-common node\n");
-		return -EFAULT;
+		nss_info_always("qca-nss-drv.ko is loaded for symbol link\n");
+		return 0;
 	}
 
 	if (of_address_to_resource(cmn, 0, &res_nss_fpb_base) != 0) {
@@ -759,6 +933,19 @@
  */
 static void __exit nss_cleanup(void)
 {
+#if (NSS_DT_SUPPORT == 1)
+	struct device_node *cmn = NULL;
+
+	/*
+	 * Get reference to NSS common device node
+	 */
+	cmn = of_find_node_by_name(NULL, "nss-common");
+	if (!cmn) {
+		nss_info_always("cannot find nss-common node, maybe just for symbol link\n");
+		return;
+	}
+#endif
+
 	nss_info("Exit NSS driver");
 
 	if (nss_dev_header)
diff --git a/nss_ipv4.c b/nss_ipv4.c
index de99ece..6c73c7c 100644
--- a/nss_ipv4.c
+++ b/nss_ipv4.c
@@ -54,6 +54,27 @@
 }
 
 /*
+ * nss_ipv4_driver_conn_sync_many_update()
+ *	Update driver specific information from the conn_sync_many messsage.
+ */
+static void nss_ipv4_driver_conn_sync_many_update(struct nss_ctx_instance *nss_ctx, struct nss_ipv4_conn_sync_many_msg *nicsm)
+{
+	int i;
+
+	/*
+	 * Sanity check for the stats count
+	 */
+	if (nicsm->count * sizeof(struct nss_ipv4_conn_sync) >= nicsm->size) {
+		nss_warning("%p: stats sync count %u exceeds the size of this msg %u", nss_ctx, nicsm->count, nicsm->size);
+		return;
+	}
+
+	for (i = 0; i < nicsm->count; i++) {
+		nss_ipv4_driver_conn_sync_update(nss_ctx, &nicsm->conn_sync[i]);
+	}
+}
+
+/*
  * nss_ipv4_driver_node_sync_update)
  *	Update driver specific information from the messsage.
  */
@@ -138,6 +159,13 @@
 		 */
 		nss_ipv4_driver_conn_sync_update(nss_ctx, &nim->msg.conn_stats);
 		break;
+
+	case NSS_IPV4_TX_CONN_STATS_SYNC_MANY_MSG:
+		/*
+		 * Update driver statistics on connection sync many.
+		 */
+		nss_ipv4_driver_conn_sync_many_update(nss_ctx, &nim->msg.conn_stats_many);
+		break;
 	}
 
 	/*
@@ -164,10 +192,10 @@
 }
 
 /*
- * nss_ipv4_tx()
- *	Transmit an ipv4 message to the FW.
+ * nss_ipv4_tx_with_size()
+ *	Transmit an ipv4 message to the FW with a specified size.
  */
-nss_tx_status_t nss_ipv4_tx(struct nss_ctx_instance *nss_ctx, struct nss_ipv4_msg *nim)
+nss_tx_status_t nss_ipv4_tx_with_size(struct nss_ctx_instance *nss_ctx, struct nss_ipv4_msg *nim, uint32_t size)
 {
 	struct nss_ipv4_msg *nim2;
 	struct nss_cmn_msg *ncm = &nim->cm;
@@ -198,7 +226,12 @@
 		return NSS_TX_FAILURE;
 	}
 
-	nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
+	if(size > PAGE_SIZE) {
+		nss_warning("%p: tx request size too large: %u", nss_ctx, size);
+		return NSS_TX_FAILURE;
+	}
+
+	nbuf = dev_alloc_skb(size);
 	if (unlikely(!nbuf)) {
 		NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
 		nss_warning("%p: msg dropped as command allocation failed", nss_ctx);
@@ -226,6 +259,15 @@
 }
 
 /*
+ * nss_ipv4_tx()
+ *	Transmit an ipv4 message to the FW.
+ */
+nss_tx_status_t nss_ipv4_tx(struct nss_ctx_instance *nss_ctx, struct nss_ipv4_msg *nim)
+{
+	return nss_ipv4_tx_with_size(nss_ctx, nim, NSS_NBUF_PAYLOAD_SIZE);
+}
+
+/*
  **********************************
  Register/Unregister/Miscellaneous APIs
  **********************************
@@ -487,6 +529,7 @@
 }
 
 EXPORT_SYMBOL(nss_ipv4_tx);
+EXPORT_SYMBOL(nss_ipv4_tx_with_size);
 EXPORT_SYMBOL(nss_ipv4_notify_register);
 EXPORT_SYMBOL(nss_ipv4_notify_unregister);
 EXPORT_SYMBOL(nss_ipv4_get_mgr);
diff --git a/nss_ipv6.c b/nss_ipv6.c
index 16067a4..ffd2032 100644
--- a/nss_ipv6.c
+++ b/nss_ipv6.c
@@ -53,6 +53,27 @@
 }
 
 /*
+ * nss_ipv6_driver_conn_sync_many_update()
+ *	Update driver specific information from the conn_sync_many messsage.
+ */
+static void nss_ipv6_driver_conn_sync_many_update(struct nss_ctx_instance *nss_ctx, struct nss_ipv6_conn_sync_many_msg *nicsm)
+{
+	uint32_t i;
+
+	/*
+	 * Sanity check for the stats count
+	 */
+	if (nicsm->count * sizeof(struct nss_ipv6_conn_sync) >= nicsm->size) {
+		nss_warning("%p: stats sync count %u exceeds the size of this msg %u", nss_ctx, nicsm->count, nicsm->size);
+		return;
+	}
+
+	for (i = 0; i < nicsm->count; i++) {
+		nss_ipv6_driver_conn_sync_update(nss_ctx, &nicsm->conn_sync[i]);
+	}
+}
+
+/*
  * nss_ipv6_driver_node_sync_update)
  *	Update driver specific information from the messsage.
  */
@@ -141,6 +162,13 @@
 		 */
 		nss_ipv6_driver_conn_sync_update(nss_ctx, &nim->msg.conn_stats);
 		break;
+
+	case NSS_IPV6_TX_CONN_STATS_SYNC_MANY_MSG:
+		/*
+		 * Update driver statistics on connection sync many.
+		 */
+		nss_ipv6_driver_conn_sync_many_update(nss_ctx, &nim->msg.conn_stats_many);
+		break;
 	}
 
 	/*
@@ -167,10 +195,10 @@
 }
 
 /*
- * nss_ipv6_tx()
- *	Transmit an ipv6 message to the FW.
+ * nss_ipv6_tx_with_size()
+ *	Transmit an ipv6 message to the FW with a specified size.
  */
-nss_tx_status_t nss_ipv6_tx(struct nss_ctx_instance *nss_ctx, struct nss_ipv6_msg *nim)
+nss_tx_status_t nss_ipv6_tx_with_size(struct nss_ctx_instance *nss_ctx, struct nss_ipv6_msg *nim, uint32_t size)
 {
 	struct nss_ipv6_msg *nim2;
 	struct nss_cmn_msg *ncm = &nim->cm;
@@ -201,7 +229,12 @@
 		return NSS_TX_FAILURE;
 	}
 
-	nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
+	if(size > PAGE_SIZE) {
+		nss_warning("%p: tx request size too large: %u", nss_ctx, size);
+		return NSS_TX_FAILURE;
+	}
+
+	nbuf = dev_alloc_skb(size);
 	if (unlikely(!nbuf)) {
 		NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
 		nss_warning("%p: msg dropped as command allocation failed", nss_ctx);
@@ -229,6 +262,15 @@
 }
 
 /*
+ * nss_ipv6_tx()
+ *	Transmit an ipv4 message to the FW.
+ */
+nss_tx_status_t nss_ipv6_tx(struct nss_ctx_instance *nss_ctx, struct nss_ipv6_msg *nim)
+{
+	return nss_ipv6_tx_with_size(nss_ctx, nim, NSS_NBUF_PAYLOAD_SIZE);
+}
+
+/*
  **********************************
  Register/Unregister/Miscellaneous APIs
  **********************************
@@ -487,6 +529,7 @@
 }
 
 EXPORT_SYMBOL(nss_ipv6_tx);
+EXPORT_SYMBOL(nss_ipv6_tx_with_size);
 EXPORT_SYMBOL(nss_ipv6_notify_register);
 EXPORT_SYMBOL(nss_ipv6_notify_unregister);
 EXPORT_SYMBOL(nss_ipv6_get_mgr);
diff --git a/nss_n2h.c b/nss_n2h.c
index ca87dbd..486a41b 100755
--- a/nss_n2h.c
+++ b/nss_n2h.c
@@ -20,19 +20,14 @@
  */
 
 #include "nss_tx_rx_common.h"
+#include <asm/cacheflush.h>
 
-#define NSS_CORE_0			0
-#define NSS_CORE_1			1
 
-/*
- * This number is chosen becuase currently default IPV4 + IPV6
- * connection size is 1024 + 1024 = 2048.
- *  FYI: However this doesnt have any impact on n2h/ipv6 connections
- */
-#define NSS_N2H_MIN_EMPTY_POOL_BUF_SZ		2048
+#define NSS_N2H_MIN_EMPTY_POOL_BUF_SZ		32
 #define NSS_N2H_DEFAULT_EMPTY_POOL_BUF_SZ	8192
 
-int nss_n2h_empty_pool_buf_cfg[NSS_MAX_CORES] __read_mostly = {NSS_N2H_DEFAULT_EMPTY_POOL_BUF_SZ, NSS_N2H_DEFAULT_EMPTY_POOL_BUF_SZ};
+int nss_n2h_empty_pool_buf_cfg[NSS_MAX_CORES] __read_mostly = {-1, -1};
+int nss_n2h_water_mark[NSS_MAX_CORES][2] __read_mostly = {{-1, -1}, {-1, -1} };
 
 struct nss_n2h_registered_data {
 	nss_n2h_msg_callback_t n2h_callback;
@@ -42,6 +37,8 @@
 static struct nss_n2h_cfg_pvt nss_n2h_nepbcfgp[NSS_MAX_CORES];
 static struct nss_n2h_registered_data nss_n2h_rd[NSS_MAX_CORES];
 static struct nss_n2h_cfg_pvt nss_n2h_rcp;
+static struct nss_n2h_cfg_pvt nss_n2h_mitigationcp[NSS_CORE_MAX];
+static struct nss_n2h_cfg_pvt nss_n2h_bufcp[NSS_CORE_MAX];
 
 /*
  * nss_n2h_stats_sync()
@@ -103,6 +100,11 @@
 	nss_ctx->stats_n2h[NSS_STATS_N2H_N2H_DATA_PACKETS] += nnss->n2h_data_pkts;
 	nss_ctx->stats_n2h[NSS_STATS_N2H_N2H_DATA_BYTES] += nnss->n2h_data_bytes;
 
+	/*
+	 * Payloads related stats
+	 */
+	nss_ctx->stats_n2h[NSS_STATS_N2H_N2H_TOT_PAYLOADS] = nnss->tot_payloads;
+
 	spin_unlock_bh(&nss_top->stats_lock);
 }
 
@@ -132,6 +134,10 @@
 		nss_info("NSS N2H rps_en %d \n",nnm->msg.rps_cfg.enable);
 		break;
 
+	case NSS_TX_METADATA_TYPE_N2H_MITIGATION_CFG:
+		nss_info("NSS N2H mitigation_dis %d \n",nnm->msg.mitigation_cfg.enable);
+		break;
+
 	case NSS_TX_METADATA_TYPE_N2H_EMPTY_POOL_BUF_CFG:
 		nss_info("%p: empty pool buf cfg response from FW", nss_ctx);
 		break;
@@ -209,43 +215,157 @@
 }
 
 /*
- * nss_n2h_empty_pool_buf_cfg_core1_callback()
- *	call back function for the n2h connection configuration handler
+ * nss_n2h_mitigation_cfg_callback()
+ *	call back function for mitigation configuration
  */
-static void nss_n2h_empty_pool_buf_cfg_callback(void *app_data,
-						struct nss_n2h_msg *nnm)
+static void nss_n2h_mitigation_cfg_callback(void *app_data, struct nss_n2h_msg *nnm)
 {
 	int core_num = (int)app_data;
+	struct nss_top_instance *nss_top = &nss_top_main;
+	struct nss_ctx_instance *nss_ctx = &nss_top->nss[core_num];
+
+	if (nnm->cm.response != NSS_CMN_RESPONSE_ACK) {
+
+		/*
+		 * Error, hence we are not updating the nss_n2h_mitigate_en
+		 */
+		nss_n2h_mitigationcp[core_num].response = NSS_FAILURE;
+		complete(&nss_n2h_mitigationcp[core_num].complete);
+		nss_warning("core%d: MITIGATION configuration failed : %d\n", core_num, nnm->cm.error);
+		return;
+	}
+
+	nss_info("core%d: MITIGATION configuration succeeded: %d\n", core_num, nnm->cm.error);
+
+	nss_ctx->n2h_mitigate_en = nnm->msg.mitigation_cfg.enable;
+	nss_n2h_mitigationcp[core_num].response = NSS_SUCCESS;
+	complete(&nss_n2h_mitigationcp[core_num].complete);
+}
+
+/*
+ * nss_n2h_buf_cfg_callback()
+ *	call back function for pbuf configuration
+ */
+static void nss_n2h_bufs_cfg_callback(void *app_data, struct nss_n2h_msg *nnm)
+{
+	int core_num = (int)app_data;
+	unsigned int allocated_sz;
+
+	struct nss_top_instance *nss_top = &nss_top_main;
+	struct nss_ctx_instance *nss_ctx = &nss_top->nss[core_num];
+
+	if (nnm->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nss_n2h_bufcp[core_num].response = NSS_FAILURE;
+		nss_warning("core%d: buf configuration failed : %d\n", core_num, nnm->cm.error);
+		goto done;
+	}
+
+	nss_info("core%d: buf configuration succeeded: %d\n", core_num, nnm->cm.error);
+
+	allocated_sz = nnm->msg.buf_pool.nss_buf_page_size * nnm->msg.buf_pool.nss_buf_num_pages;
+	nss_ctx->buf_sz_allocated += allocated_sz;
+
+	nss_n2h_bufcp[core_num].response = NSS_SUCCESS;
+
+done:
+	complete(&nss_n2h_bufcp[core_num].complete);
+}
+
+/*
+ * nss_n2h_payload_stats_callback()
+ *	It gets called response to payload accounting.
+ */
+static void nss_n2h_payload_stats_callback(void *app_data,
+					struct nss_n2h_msg *nnm)
+{
+	int core_num = (int)app_data;
+
 	if (nnm->cm.response != NSS_CMN_RESPONSE_ACK) {
 		struct nss_n2h_empty_pool_buf *nnepbcm;
 		nnepbcm = &nnm->msg.empty_pool_buf_cfg;
 
-		/*
-		 * Error, hence we are not updating the nss_n2h_empty_pool_buf
-		 * Restore the current_value to its previous state
-		 */
-		nss_warning("Core %d empty pool buf set failure: %d\n", core_num, nnm->cm.error);
+		nss_warning("%d: core empty pool buf set failure: %d\n",
+				core_num, nnm->cm.error);
 		nss_n2h_nepbcfgp[core_num].response = NSS_FAILURE;
 		complete(&nss_n2h_nepbcfgp[core_num].complete);
 		return;
 	}
 
-	/*
-	 * Sucess at NSS FW, hence updating nss_n2h_empty_pool_buf, with the valid value
-	 * saved at the sysctl handler.
-	 */
-	nss_info("Core %d empty pool buf set success: %d\n", core_num, nnm->cm.error);
+	if (nnm->cm.type == NSS_TX_METADATA_TYPE_GET_PAYLOAD_INFO) {
+		nss_n2h_nepbcfgp[core_num].empty_buf_pool =
+			ntohl(nnm->msg.payload_info.pool_size);
+		nss_n2h_nepbcfgp[core_num].low_water =
+			ntohl(nnm->msg.payload_info.low_water);
+		nss_n2h_nepbcfgp[core_num].high_water =
+			ntohl(nnm->msg.payload_info.high_water);
+	}
+
 	nss_n2h_nepbcfgp[core_num].response = NSS_SUCCESS;
 	complete(&nss_n2h_nepbcfgp[core_num].complete);
 }
 
 /*
- * nss_n2h_empty_pool_buf_core1_handler()
- *	Sets the number of connections for IPv4
+ * nss_n2h_get_payload_info()
+ *	Gets Payload information
  */
-static int nss_n2h_set_empty_pool_buf(ctl_table *ctl, int write, void __user *buffer,
-					size_t *lenp, loff_t *ppos,
-					int core_num, int *new_val)
+static int nss_n2h_get_payload_info(ctl_table *ctl, int write,
+			void __user *buffer, size_t *lenp, loff_t *ppos,
+			int core_num)
+{
+	struct nss_top_instance *nss_top = &nss_top_main;
+	struct nss_ctx_instance *nss_ctx = &nss_top->nss[core_num];
+	struct nss_n2h_msg nnm;
+	struct nss_n2h_payload_info *nnepbcm;
+	nss_tx_status_t nss_tx_status;
+	int ret = NSS_FAILURE;
+
+	/*
+	 * Note that semaphore should be already held.
+	 */
+
+	nss_n2h_msg_init(&nnm, NSS_N2H_INTERFACE,
+			NSS_TX_METADATA_TYPE_GET_PAYLOAD_INFO,
+			sizeof(struct nss_n2h_payload_info),
+			nss_n2h_payload_stats_callback,
+			(void *)core_num);
+
+	nnepbcm = &nnm.msg.payload_info;
+	nss_tx_status = nss_n2h_tx_msg(nss_ctx, &nnm);
+
+	if (nss_tx_status != NSS_TX_SUCCESS) {
+		nss_warning("%p: core %d nss_tx error errorn",
+				nss_ctx, core_num);
+		return NSS_FAILURE;
+	}
+
+	/*
+	 * Blocking call, wait till we get ACK for this msg.
+	 */
+	ret = wait_for_completion_timeout(&nss_n2h_nepbcfgp[core_num].complete,
+			msecs_to_jiffies(NSS_CONN_CFG_TIMEOUT));
+	if (ret == 0) {
+		nss_warning("%p: core %d waiting for ack timed out\n", nss_ctx,
+				core_num);
+		return NSS_FAILURE;
+	}
+
+	if (NSS_FAILURE == nss_n2h_nepbcfgp[core_num].response) {
+		nss_warning("%p: core %d response returned failure\n", nss_ctx,
+				core_num);
+		return NSS_FAILURE;
+	}
+
+	return NSS_SUCCESS;
+}
+
+/*
+ * nss_n2h_set_empty_pool_buf()
+ *	Sets empty pool buffer
+ */
+static int nss_n2h_set_empty_pool_buf(ctl_table *ctl, int write,
+				void __user *buffer,
+				size_t *lenp, loff_t *ppos,
+				int core_num, int *new_val)
 {
 	struct nss_top_instance *nss_top = &nss_top_main;
 	struct nss_ctx_instance *nss_ctx = &nss_top->nss[core_num];
@@ -262,23 +382,31 @@
 	/*
 	 * Take snap shot of current value
 	 */
-	nss_n2h_nepbcfgp[core_num].current_value = *new_val;
+	nss_n2h_nepbcfgp[core_num].empty_buf_pool = *new_val;
 
-	/*
-	 * Write the variable with user input
-	 */
+	if (!write) {
+		ret = nss_n2h_get_payload_info(ctl, write, buffer, lenp, ppos,
+				core_num);
+		*new_val = nss_n2h_nepbcfgp[core_num].empty_buf_pool;
+		if (ret == NSS_FAILURE) {
+			up(&nss_n2h_nepbcfgp[core_num].sem);
+			return -EBUSY;
+		}
+
+		up(&nss_n2h_nepbcfgp[core_num].sem);
+
+		ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
+		return ret;
+	}
+
 	ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
-	if (ret || (!write)) {
+	if (ret) {
 		up(&nss_n2h_nepbcfgp[core_num].sem);
 		return ret;
 	}
 
-	/*
-	 * Input for n2h should be atleast 2048 to support defalt connections
-	 * of 1024 (IPV4) + 1024 (IPV6) connections.
-	 */
 	if ((*new_val < NSS_N2H_MIN_EMPTY_POOL_BUF_SZ)) {
-		nss_warning("%p: core %d setting %d is less than minimum number of buffer",
+		nss_warning("%p: core %d setting %d < min number of buffer",
 				nss_ctx, core_num, *new_val);
 		goto failure;
 	}
@@ -289,7 +417,7 @@
 	nss_n2h_msg_init(&nnm, NSS_N2H_INTERFACE,
 			NSS_TX_METADATA_TYPE_N2H_EMPTY_POOL_BUF_CFG,
 			sizeof(struct nss_n2h_empty_pool_buf),
-			nss_n2h_empty_pool_buf_cfg_callback,
+			nss_n2h_payload_stats_callback,
 			(void *)core_num);
 
 	nnepbcm = &nnm.msg.empty_pool_buf_cfg;
@@ -297,7 +425,7 @@
 	nss_tx_status = nss_n2h_tx_msg(nss_ctx, &nnm);
 
 	if (nss_tx_status != NSS_TX_SUCCESS) {
-		nss_warning("%p: core %d nss_tx error setting empty pool buffer: %d\n",
+		nss_warning("%p: core %d nss_tx error empty pool buffer: %d\n",
 				nss_ctx, core_num, *new_val);
 		goto failure;
 	}
@@ -305,9 +433,11 @@
 	/*
 	 * Blocking call, wait till we get ACK for this msg.
 	 */
-	ret = wait_for_completion_timeout(&nss_n2h_nepbcfgp[core_num].complete, msecs_to_jiffies(NSS_CONN_CFG_TIMEOUT));
+	ret = wait_for_completion_timeout(&nss_n2h_nepbcfgp[core_num].complete,
+			msecs_to_jiffies(NSS_CONN_CFG_TIMEOUT));
 	if (ret == 0) {
-		nss_warning("%p: core %d Waiting for ack timed out\n", nss_ctx, core_num);
+		nss_warning("%p: core %d Waiting for ack timed out\n", nss_ctx,
+			core_num);
 		goto failure;
 	}
 
@@ -327,7 +457,133 @@
 	/*
 	 * Restore the current_value to its previous state
 	 */
-	*new_val = nss_n2h_nepbcfgp[core_num].current_value;
+	*new_val = nss_n2h_nepbcfgp[core_num].empty_buf_pool;
+	up(&nss_n2h_nepbcfgp[core_num].sem);
+	return NSS_FAILURE;
+}
+
+/*
+ * nss_n2h_set_water_mark()
+ *	Sets water mark for N2H SOS
+ */
+static int nss_n2h_set_water_mark(ctl_table *ctl, int write,
+					void __user *buffer,
+					size_t *lenp, loff_t *ppos,
+					int core_num, int *low, int *high)
+{
+	struct nss_top_instance *nss_top = &nss_top_main;
+	struct nss_ctx_instance *nss_ctx = &nss_top->nss[core_num];
+	struct nss_n2h_msg nnm;
+	struct nss_n2h_water_mark *wm;
+	nss_tx_status_t nss_tx_status;
+	int ret = NSS_FAILURE;
+
+	/*
+	 * Acquiring semaphore
+	 */
+	down(&nss_n2h_nepbcfgp[core_num].sem);
+
+	/*
+	 * Take snap shot of current value
+	 */
+	nss_n2h_nepbcfgp[core_num].low_water = *low;
+	nss_n2h_nepbcfgp[core_num].high_water = *high;
+
+	if (!write) {
+		ret = nss_n2h_get_payload_info(ctl, write, buffer, lenp, ppos,
+				core_num);
+		*low = nss_n2h_nepbcfgp[core_num].low_water;
+		*high = nss_n2h_nepbcfgp[core_num].high_water;
+
+		if (ret == NSS_FAILURE) {
+			up(&nss_n2h_nepbcfgp[core_num].sem);
+			return -EBUSY;
+		}
+
+		up(&nss_n2h_nepbcfgp[core_num].sem);
+		ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
+		return ret;
+	}
+
+	ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
+	if (ret) {
+		up(&nss_n2h_nepbcfgp[core_num].sem);
+		return ret;
+	}
+
+	/*
+	 * If either low or high water mark is not set then we do
+	 * nothing.
+	 */
+	if (*low == -1 || *high == -1)
+		goto failure;
+
+	if ((*low < NSS_N2H_MIN_EMPTY_POOL_BUF_SZ) ||
+		(*high < NSS_N2H_MIN_EMPTY_POOL_BUF_SZ)) {
+		nss_warning("%p: core %d setting %d, %d < min number of buffer",
+				nss_ctx, core_num, *low, *high);
+		goto failure;
+	}
+
+	if ((*low > (NSS_N2H_DEFAULT_EMPTY_POOL_BUF_SZ * 2)) ||
+		(*high > (NSS_N2H_DEFAULT_EMPTY_POOL_BUF_SZ * 2))) {
+		nss_warning("%p: core %d setting %d, %d is > upper limit",
+				nss_ctx, core_num, *low, *high);
+		goto failure;
+	}
+
+	if (*low > *high) {
+		nss_warning("%p: core %d setting low %d is more than high %d",
+				nss_ctx, core_num, *low, *high);
+		goto failure;
+	}
+
+	nss_info("%p: core %d number of low : %d and high : %d\n",
+		nss_ctx, core_num, *low, *high);
+
+	nss_n2h_msg_init(&nnm, NSS_N2H_INTERFACE,
+			NSS_TX_METADATA_TYPE_SET_WATER_MARK,
+			sizeof(struct nss_n2h_water_mark),
+			nss_n2h_payload_stats_callback,
+			(void *)core_num);
+
+	wm = &nnm.msg.wm;
+	wm->low_water = htonl(*low);
+	wm->high_water = htonl(*high);
+	nss_tx_status = nss_n2h_tx_msg(nss_ctx, &nnm);
+
+	if (nss_tx_status != NSS_TX_SUCCESS) {
+		nss_warning("%p: core %d nss_tx error setting : %d, %d\n",
+				nss_ctx, core_num, *low, *high);
+		goto failure;
+	}
+
+	/*
+	 * Blocking call, wait till we get ACK for this msg.
+	 */
+	ret = wait_for_completion_timeout(&nss_n2h_nepbcfgp[core_num].complete,
+			msecs_to_jiffies(NSS_CONN_CFG_TIMEOUT));
+	if (ret == 0) {
+		nss_warning("%p: core %d Waiting for ack timed out\n", nss_ctx,
+			core_num);
+		goto failure;
+	}
+
+	/*
+	 * ACK/NACK received from NSS FW
+	 */
+	if (NSS_FAILURE == nss_n2h_nepbcfgp[core_num].response)
+		goto failure;
+
+	up(&nss_n2h_nepbcfgp[core_num].sem);
+	return NSS_SUCCESS;
+
+failure:
+	/*
+	 * Restore the current_value to its previous state
+	 */
+	*low = nss_n2h_nepbcfgp[core_num].low_water;
+	*high = nss_n2h_nepbcfgp[core_num].high_water;
 	up(&nss_n2h_nepbcfgp[core_num].sem);
 	return -EINVAL;
 }
@@ -371,11 +627,11 @@
  *	Sets the number of empty buffer for core 1
  */
 static int nss_n2h_empty_pool_buf_cfg_core1_handler(ctl_table *ctl,
-						    int write, void __user *buffer,
-						    size_t *lenp, loff_t *ppos)
+				int write, void __user *buffer,
+				size_t *lenp, loff_t *ppos)
 {
 	return nss_n2h_set_empty_pool_buf(ctl, write, buffer, lenp, ppos,
-					NSS_CORE_1, &nss_n2h_empty_pool_buf_cfg[NSS_CORE_1]);
+			NSS_CORE_1, &nss_n2h_empty_pool_buf_cfg[NSS_CORE_1]);
 }
 
 /*
@@ -383,11 +639,37 @@
  *	Sets the number of empty buffer for core 0
  */
 static int nss_n2h_empty_pool_buf_cfg_core0_handler(ctl_table *ctl,
-						    int write, void __user *buffer,
-						    size_t *lenp, loff_t *ppos)
+				int write, void __user *buffer,
+				size_t *lenp, loff_t *ppos)
 {
 	return nss_n2h_set_empty_pool_buf(ctl, write, buffer, lenp, ppos,
-					NSS_CORE_0, &nss_n2h_empty_pool_buf_cfg[NSS_CORE_0]);
+			NSS_CORE_0, &nss_n2h_empty_pool_buf_cfg[NSS_CORE_0]);
+}
+
+/*
+ * nss_n2h_water_mark_core1_handler()
+ *	Sets water mark for core 1
+ */
+static int nss_n2h_water_mark_core1_handler(ctl_table *ctl,
+			int write, void __user *buffer,
+			size_t *lenp, loff_t *ppos)
+{
+	return nss_n2h_set_water_mark(ctl, write, buffer, lenp, ppos,
+			NSS_CORE_1, &nss_n2h_water_mark[NSS_CORE_1][0],
+			&nss_n2h_water_mark[NSS_CORE_1][1]);
+}
+
+/*
+ * nss_n2h_water_mark_core0_handler()
+ *	Sets water mark for core 0
+ */
+static int nss_n2h_water_mark_core0_handler(ctl_table *ctl,
+			int write, void __user *buffer,
+			size_t *lenp, loff_t *ppos)
+{
+	return nss_n2h_set_water_mark(ctl, write, buffer, lenp, ppos,
+			NSS_CORE_0, &nss_n2h_water_mark[NSS_CORE_0][0],
+			&nss_n2h_water_mark[NSS_CORE_0][1]);
 }
 
 /*
@@ -443,20 +725,188 @@
 	return NSS_SUCCESS;
 }
 
+/*
+ * nss_n2h_mitigation_cfg()
+ *	Send Message to NSS to disable MITIGATION.
+ */
+nss_tx_status_t nss_n2h_mitigation_cfg(struct nss_ctx_instance *nss_ctx, int enable_mitigation, nss_core_id_t core_num)
+{
+	struct nss_n2h_msg nnm;
+	struct nss_n2h_mitigation *mitigation_cfg;
+	nss_tx_status_t nss_tx_status;
+	int ret;
+
+	nss_assert(core_num < NSS_CORE_MAX);
+
+	down(&nss_n2h_mitigationcp[core_num].sem);
+	nss_n2h_msg_init(&nnm, NSS_N2H_INTERFACE, NSS_TX_METADATA_TYPE_N2H_MITIGATION_CFG,
+			sizeof(struct nss_n2h_mitigation),
+			nss_n2h_mitigation_cfg_callback,
+			(void *)core_num);
+
+	mitigation_cfg = &nnm.msg.mitigation_cfg;
+	mitigation_cfg->enable = enable_mitigation;
+
+	nss_tx_status = nss_n2h_tx_msg(nss_ctx, &nnm);
+
+	if (nss_tx_status != NSS_TX_SUCCESS) {
+		nss_warning("%p: nss_tx error setting mitigation\n", nss_ctx);
+		goto failure;
+	}
+
+	/*
+	 * Blocking call, wait till we get ACK for this msg.
+	 */
+	ret = wait_for_completion_timeout(&nss_n2h_mitigationcp[core_num].complete, msecs_to_jiffies(NSS_CONN_CFG_TIMEOUT));
+	if (ret == 0) {
+		nss_warning("%p: Waiting for ack timed out\n", nss_ctx);
+		goto failure;
+	}
+
+	/*
+	 * ACK/NACK received from NSS FW
+	 */
+	if (NSS_FAILURE == nss_n2h_mitigationcp[core_num].response) {
+		goto failure;
+	}
+
+	up(&nss_n2h_mitigationcp[core_num].sem);
+	return NSS_SUCCESS;
+
+failure:
+	up(&nss_n2h_mitigationcp[core_num].sem);
+	return NSS_FAILURE;
+}
+
+static inline void nss_n2h_buf_pool_free(struct nss_n2h_buf_pool *buf_pool)
+{
+	int page_count;
+	for (page_count = 0; page_count < buf_pool->nss_buf_num_pages; page_count++) {
+		kfree(buf_pool->nss_buf_pool_vaddr[page_count]);
+	}
+}
+
+/*
+ * nss_n2h_buf_cfg()
+ *	Send Message to NSS to enable pbufs.
+ */
+nss_tx_status_t nss_n2h_buf_pool_cfg(struct nss_ctx_instance *nss_ctx,
+	       				int buf_pool_size, nss_core_id_t core_num)
+{
+	static struct nss_n2h_msg nnm;
+	struct nss_n2h_buf_pool *buf_pool;
+	nss_tx_status_t nss_tx_status;
+	int ret;
+	int page_count;
+	int num_pages = ALIGN(buf_pool_size, PAGE_SIZE)/PAGE_SIZE;
+
+	nss_assert(core_num < NSS_CORE_MAX);
+
+	nss_n2h_msg_init(&nnm, NSS_N2H_INTERFACE, NSS_METADATA_TYPE_N2H_ADD_BUF_POOL,
+			sizeof(struct nss_n2h_buf_pool),
+			nss_n2h_bufs_cfg_callback,
+			(void *)core_num);
+
+	do {
+
+		down(&nss_n2h_bufcp[core_num].sem);
+
+		buf_pool = &nnm.msg.buf_pool;
+		buf_pool->nss_buf_page_size = PAGE_SIZE;
+
+		for (page_count = 0; page_count < MAX_PAGES_PER_MSG && num_pages; page_count++, num_pages--) {
+
+			void *kern_addr = kzalloc(PAGE_SIZE, GFP_ATOMIC);
+			if (!kern_addr) {
+				BUG_ON(!page_count);
+				break;
+			}
+			BUG_ON((long unsigned int)kern_addr % PAGE_SIZE);
+
+			buf_pool->nss_buf_pool_vaddr[page_count] = kern_addr;
+			buf_pool->nss_buf_pool_addr[page_count] = dma_map_single(NULL, kern_addr, PAGE_SIZE, DMA_TO_DEVICE);
+		}
+
+		buf_pool->nss_buf_num_pages = page_count;
+		nss_tx_status = nss_n2h_tx_msg(nss_ctx, &nnm);
+		if (nss_tx_status != NSS_TX_SUCCESS) {
+
+			nss_n2h_buf_pool_free(buf_pool);
+			nss_warning("%p: nss_tx error setting pbuf\n", nss_ctx);
+			goto failure;
+		}
+
+		/*
+	 	 * Blocking call, wait till we get ACK for this msg.
+	 	 */
+		ret = wait_for_completion_timeout(&nss_n2h_bufcp[core_num].complete, msecs_to_jiffies(NSS_CONN_CFG_TIMEOUT));
+		if (ret == 0) {
+			nss_warning("%p: Waiting for ack timed out\n", nss_ctx);
+			goto failure;
+		}
+
+		/*
+		 * ACK/NACK received from NSS FW
+		 */
+		if (NSS_FAILURE == nss_n2h_bufcp[core_num].response) {
+
+			nss_n2h_buf_pool_free(buf_pool);
+			goto failure;
+		}
+
+		up(&nss_n2h_bufcp[core_num].sem);
+	} while(num_pages);
+
+	return NSS_SUCCESS;
+failure:
+	up(&nss_n2h_bufcp[core_num].sem);
+	return NSS_FAILURE;
+}
+
+
+
 static ctl_table nss_n2h_table[] = {
 	{
-		.procname		= "n2h_empty_pool_buf_core0",
-		.data			= &nss_n2h_empty_pool_buf_cfg[NSS_CORE_0],
-		.maxlen			= sizeof(int),
-		.mode			= 0644,
-		.proc_handler   	= &nss_n2h_empty_pool_buf_cfg_core0_handler,
+		.procname	= "n2h_empty_pool_buf_core0",
+		.data		= &nss_n2h_empty_pool_buf_cfg[NSS_CORE_0],
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &nss_n2h_empty_pool_buf_cfg_core0_handler,
 	},
 	{
-		.procname		= "n2h_empty_pool_buf_core1",
-		.data			= &nss_n2h_empty_pool_buf_cfg[NSS_CORE_1],
-		.maxlen			= sizeof(int),
-		.mode			= 0644,
-		.proc_handler   	= &nss_n2h_empty_pool_buf_cfg_core1_handler,
+		.procname	= "n2h_empty_pool_buf_core1",
+		.data		= &nss_n2h_empty_pool_buf_cfg[NSS_CORE_1],
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &nss_n2h_empty_pool_buf_cfg_core1_handler,
+	},
+	{
+		.procname	= "n2h_low_water_core0",
+		.data		= &nss_n2h_water_mark[NSS_CORE_0][0],
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &nss_n2h_water_mark_core0_handler,
+	},
+	{
+		.procname	= "n2h_low_water_core1",
+		.data		= &nss_n2h_water_mark[NSS_CORE_1][0],
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &nss_n2h_water_mark_core1_handler,
+	},
+	{
+		.procname	= "n2h_high_water_core0",
+		.data		= &nss_n2h_water_mark[NSS_CORE_0][1],
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &nss_n2h_water_mark_core0_handler,
+	},
+	{
+		.procname	= "n2h_high_water_core1",
+		.data		= &nss_n2h_water_mark[NSS_CORE_1][1],
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &nss_n2h_water_mark_core1_handler,
 	},
 
 	{ }
@@ -518,14 +968,24 @@
 	 */
 	sema_init(&nss_n2h_nepbcfgp[NSS_CORE_0].sem, 1);
 	init_completion(&nss_n2h_nepbcfgp[NSS_CORE_0].complete);
-	nss_n2h_nepbcfgp[NSS_CORE_0].current_value = nss_n2h_empty_pool_buf_cfg[NSS_CORE_0];
+	nss_n2h_nepbcfgp[NSS_CORE_0].empty_buf_pool =
+		nss_n2h_empty_pool_buf_cfg[NSS_CORE_0];
+	nss_n2h_nepbcfgp[NSS_CORE_0].low_water =
+		nss_n2h_water_mark[NSS_CORE_0][0];
+	nss_n2h_nepbcfgp[NSS_CORE_0].high_water =
+		nss_n2h_water_mark[NSS_CORE_0][1];
 
 	/*
 	 * Core1
 	 */
 	sema_init(&nss_n2h_nepbcfgp[NSS_CORE_1].sem, 1);
 	init_completion(&nss_n2h_nepbcfgp[NSS_CORE_1].complete);
-	nss_n2h_nepbcfgp[NSS_CORE_1].current_value = nss_n2h_empty_pool_buf_cfg[NSS_CORE_1];
+	nss_n2h_nepbcfgp[NSS_CORE_1].empty_buf_pool =
+		nss_n2h_empty_pool_buf_cfg[NSS_CORE_1];
+	nss_n2h_nepbcfgp[NSS_CORE_1].low_water =
+		nss_n2h_water_mark[NSS_CORE_1][0];
+	nss_n2h_nepbcfgp[NSS_CORE_1].high_water =
+		nss_n2h_water_mark[NSS_CORE_1][1];
 }
 
 /*
@@ -636,6 +1096,29 @@
 	sema_init(&nss_n2h_rcp.sem, 1);
 	init_completion(&nss_n2h_rcp.complete);
 
+	/*
+	 * MITIGATION sema init for core0
+	 */
+	sema_init(&nss_n2h_mitigationcp[NSS_CORE_0].sem, 1);
+	init_completion(&nss_n2h_mitigationcp[NSS_CORE_0].complete);
+
+	/*
+	 * MITIGATION sema init for core1
+	 */
+	sema_init(&nss_n2h_mitigationcp[NSS_CORE_1].sem, 1);
+	init_completion(&nss_n2h_mitigationcp[NSS_CORE_1].complete);
+
+	/*
+	 * PBUF addition sema init for core0
+	 */
+	sema_init(&nss_n2h_bufcp[NSS_CORE_0].sem, 1);
+	init_completion(&nss_n2h_bufcp[NSS_CORE_0].complete);
+
+	/*
+	 * PBUF addition sema init for core1
+	 */
+	sema_init(&nss_n2h_bufcp[NSS_CORE_1].sem, 1);
+	init_completion(&nss_n2h_bufcp[NSS_CORE_1].complete);
 
 	nss_n2h_notify_register(NSS_CORE_0, NULL, NULL);
 	nss_n2h_notify_register(NSS_CORE_1, NULL, NULL);
diff --git a/nss_phys_if.c b/nss_phys_if.c
index 6da204d..b8af1c2 100644
--- a/nss_phys_if.c
+++ b/nss_phys_if.c
@@ -600,6 +600,13 @@
 
 	nss_ctx->max_buf_size = ((mtu_sz + ETH_HLEN + SMP_CACHE_BYTES - 1) & ~(SMP_CACHE_BYTES - 1)) + NSS_NBUF_PAD_EXTRA;
 
+	/*
+	 * max_buf_size should not be lesser than NSS_NBUF_PAYLOAD_SIZE
+	 */
+	if (nss_ctx->max_buf_size < NSS_NBUF_PAYLOAD_SIZE) {
+		nss_ctx->max_buf_size = NSS_NBUF_PAYLOAD_SIZE;
+	}
+
 	nss_info("Current mtu:%u mtu_sz:%u max_buf_size:%d\n", mtu, mtu_sz, nss_ctx->max_buf_size);
 
 	if (mtu_sz > nss_ctx->nss_top->prev_mtu_sz) {
diff --git a/nss_pm.h b/nss_pm.h
index 2a2cb8d..1b2d27e 100644
--- a/nss_pm.h
+++ b/nss_pm.h
@@ -115,8 +115,8 @@
 		{\
 			.src = MSM_BUS_MASTER_NSS_CRYPTO5_0, \
 			.dst = MSM_BUS_SLAVE_EBI_CH0, \
-			.ab = (_data_bw) * 16 * 1000000ULL, \
-			.ib = (_data_bw) * 16 * 1000000ULL, \
+			.ab = 0, \
+			.ib = 0, \
 		}, \
 		{ \
 			.src =  MSM_BUS_MASTER_NSS_CRYPTO5_0, \
diff --git a/nss_stats.c b/nss_stats.c
index d5ed3e5..b5f1373 100644
--- a/nss_stats.c
+++ b/nss_stats.c
@@ -150,6 +150,7 @@
 	"h2n_data_bytes",
 	"n2h_data_packets",
 	"n2h_data_bytes",
+	"n2h_tot_payloads",
 };
 
 /*
diff --git a/nss_tx_rx_virt_if.c b/nss_tx_rx_virt_if.c
index bd59d4e..87e7e6d 100644
--- a/nss_tx_rx_virt_if.c
+++ b/nss_tx_rx_virt_if.c
@@ -119,7 +119,7 @@
 	 * to the same callback/app_data.
 	 */
 	if (ncm->response == NSS_CMM_RESPONSE_NOTIFY) {
-		ncm->cb = (uint32_t)nss_ctx->nss_top->virt_if_msg_callback[ncm->interface];
+		ncm->cb = (uint32_t)nss_ctx->nss_top->if_rx_msg_callback[ncm->interface];
 		ncm->app_data = (uint32_t)nss_ctx->nss_top->subsys_dp_register[ncm->interface].ndev;
 	}
 
@@ -180,6 +180,8 @@
 	nss_top_main.subsys_dp_register[if_num].app_data = NULL;
 	nss_top_main.subsys_dp_register[if_num].features = (uint32_t)netdev->features;
 
+	nss_top_main.if_rx_msg_callback[if_num] = NULL;
+
 	return ctx;
 }
 
diff --git a/nss_virt_if.c b/nss_virt_if.c
index 92b80e8..8a14d63 100644
--- a/nss_virt_if.c
+++ b/nss_virt_if.c
@@ -117,7 +117,7 @@
 	 * to the same callback/app_data.
 	 */
 	if (ncm->response == NSS_CMM_RESPONSE_NOTIFY) {
-		ncm->cb = (uint32_t)nss_ctx->nss_top->virt_if_msg_callback[ncm->interface];
+		ncm->cb = (uint32_t)nss_ctx->nss_top->if_rx_msg_callback[ncm->interface];
 		ncm->app_data = (uint32_t)nss_ctx->nss_top->subsys_dp_register[ncm->interface].ndev;
 	}
 
@@ -887,6 +887,8 @@
 	nss_top_main.subsys_dp_register[if_num].cb = data_callback;
 	nss_top_main.subsys_dp_register[if_num].app_data = NULL;
 	nss_top_main.subsys_dp_register[if_num].features = (uint32_t)netdev->features;
+
+	nss_top_main.if_rx_msg_callback[if_num] = NULL;
 }
 EXPORT_SYMBOL(nss_virt_if_register);