Merge "[qca-nss-drv] Register bridge netdev in data plane"
diff --git a/exports/nss_n2h.h b/exports/nss_n2h.h
index 640d7d3..6c1f49a 100644
--- a/exports/nss_n2h.h
+++ b/exports/nss_n2h.h
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2014 - 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014 - 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.
@@ -55,9 +55,26 @@
 	NSS_TX_METADATA_TYPE_SET_WATER_MARK,
 	NSS_TX_METADATA_TYPE_GET_PAYLOAD_INFO,
 	NSS_TX_METADATA_TYPE_N2H_WIFI_POOL_BUF_CFG,
+	NSS_TX_DDR_INFO_VIA_N2H_CFG,
 	NSS_METADATA_TYPE_N2H_MAX,
 };
 
+/*
+ * n2h errors -- reference only.
+ */
+enum nss_n2h_error_types {
+	N2H_EUNKNOWN = 1,
+	N2H_ALREADY_CFG,		/* Already configured */
+	N2H_LOW_WATER_MIN_INVALID,	/* Low water's is lower than min */
+	N2H_HIGH_WATER_LESS_THAN_LOW,	/* High water is less than low water */
+	N2H_HIGH_WATER_LIMIT_INVALID,	/* High water limit is more than allowed */
+	N2H_LOW_WATER_LIMIT_INVALID,	/* Low water limit is more than allowed */
+	N2H_WATER_MARK_INVALID,		/* High-Low water is not at least in ring size difference */
+	N2H_EMPTY_BUFFER_TOO_HIGH,	/* Empty buffer size is more than allowed */
+	N2H_EMPTY_BUFFER_TOO_LOW,	/* Empty buffer size is too low */
+	N2H_MMU_ENTRY_IS_INVALID,	/* mmu DDR range entry is not ok to change */
+};
+
 struct nss_n2h_rps {
 	uint32_t enable; /* Enable NSS RPS */
 };
@@ -162,6 +179,14 @@
 };
 
 /*
+ * system DDR memory info needed by FW MMU to set range guardian
+ */
+struct nss_mmu_ddr_info {
+	uint32_t ddr_size;	/* total DDR size */
+	uint32_t start_address;	/* system DDR start address */
+};
+
+/*
  * Message structure to send/receive phys i/f commands
  */
 struct nss_n2h_msg {
@@ -182,6 +207,7 @@
 				/* Message: Gets payload info */
 		struct nss_n2h_wifi_payloads wp;
 				/* Message: Sets number of wifi payloads */
+		struct nss_mmu_ddr_info mmu;	/* use N2H for carrier, will change later */
 	} msg;
 };
 
diff --git a/nss_core.c b/nss_core.c
index fdad77b..1f8396d 100644
--- a/nss_core.c
+++ b/nss_core.c
@@ -21,6 +21,7 @@
 
 #include "nss_core.h"
 #include <linux/module.h>
+#include <linux/of.h>
 #include <nss_hal.h>
 #include <net/dst.h>
 #include <linux/etherdevice.h>
@@ -316,12 +317,86 @@
 }
 
 /*
+ * nss_get_ddr_info()
+ *	get DDR start address and size from device tree.
+ */
+static void nss_get_ddr_info(struct nss_mmu_ddr_info *mmu, char *name)
+{
+	struct device_node *node = of_find_node_by_name(NULL, name);
+	if (node) {
+		int len;
+		const __be32 *ppp = (int32_t*)of_get_property(node, "reg", &len);
+		if (ppp && len == sizeof(ppp[0]) * 2) {
+			mmu->start_address = be32_to_cpup(ppp);
+			mmu->ddr_size = be32_to_cpup(&ppp[1]);
+			of_node_put(node);
+			nss_info_always("%s: %x %x prop len %d\n", name,
+				mmu->start_address, mmu->ddr_size, len);
+			return;
+		}
+		of_node_put(node);
+		nss_info_always("incorrect memory info %p len %d\n",
+			ppp, len);
+	}
+
+	/*
+	 * boilerplate for setting customer values;
+	 * start_address = 0 will not change default start address
+	 * set in NSS FW (likely 0x4000_0000)
+	 */
+	mmu->start_address = 0;
+	mmu->ddr_size = 1 << 30;
+	nss_warning("of_find_node_by_name for %s failed: use default 1GB\n", name);
+}
+
+/*
+ * nss_send_ddr_info()
+ *	Send DDR info to NSS
+ */
+static int32_t nss_send_ddr_info(struct nss_ctx_instance *nss_own)
+{
+	struct sk_buff *nbuf;
+	int32_t status;
+	struct nss_n2h_msg *nnm;
+	atomic64_t *stats;
+
+	nss_info("%p: send DDR info\n", nss_own);
+
+	nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
+	if (unlikely(!nbuf)) {
+		struct nss_top_instance *nss_top = nss_own->nss_top;
+		stats = &nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS];
+
+		NSS_PKT_STATS_INCREMENT(nss_own, stats);
+		nss_warning("%p: Unable to allocate memory for 'tx DDR info'", nss_own);
+		return NSS_CORE_STATUS_FAILURE;
+	}
+
+	nnm = (struct nss_n2h_msg *)skb_put(nbuf, sizeof(struct nss_n2h_msg));
+	nss_cmn_msg_init(&nnm->cm, NSS_N2H_INTERFACE, NSS_TX_DDR_INFO_VIA_N2H_CFG,
+			sizeof(struct nss_mmu_ddr_info), NULL, NULL);
+
+	nss_get_ddr_info(&nnm->msg.mmu, "memory");
+
+	status = nss_core_send_buffer(nss_own, 0, nbuf, NSS_IF_CMD_QUEUE, H2N_BUFFER_CTRL, 0);
+	if (unlikely(status != NSS_CORE_STATUS_SUCCESS)) {
+		dev_kfree_skb_any(nbuf);
+		nss_warning("%p: Unable to enqueue 'tx DDR info'\n", nss_own);
+		return NSS_CORE_STATUS_FAILURE;
+	}
+
+	nss_hal_send_interrupt(nss_own, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
+
+	return NSS_CORE_STATUS_SUCCESS;
+}
+
+/*
  * nss_core_cause_to_queue()
  *	Map interrupt cause to queue id
  */
 static inline uint16_t nss_core_cause_to_queue(uint16_t cause)
 {
-	if (likely(cause == NSS_N2H_INTR_DATA_COMMAND_QUEUE)) {
+	if (likely(cause == NSS_N2H_INTR_DATA_QUEUE_0)) {
 		return NSS_IF_DATA_QUEUE_0;
 	}
 
@@ -329,6 +404,14 @@
 		return NSS_IF_DATA_QUEUE_1;
 	}
 
+	if (likely(cause == NSS_N2H_INTR_DATA_QUEUE_2)) {
+		return NSS_IF_DATA_QUEUE_2;
+	}
+
+	if (likely(cause == NSS_N2H_INTR_DATA_QUEUE_3)) {
+		return NSS_IF_DATA_QUEUE_3;
+	}
+
 	if (likely(cause == NSS_N2H_INTR_EMPTY_BUFFER_QUEUE)) {
 		return NSS_IF_EMPTY_BUFFER_QUEUE;
 	}
@@ -623,6 +706,11 @@
 
 	NSS_PKT_STATS_DECREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NSS_SKB_COUNT]);
 
+	if (interface_num >= NSS_MAX_NET_INTERFACES) {
+		nss_warning("%p: Invalid interface_num: %d", nss_ctx, interface_num);
+		return;
+	}
+
 	switch (buffer_type) {
 	case N2H_BUFFER_SHAPER_BOUNCED_INTERFACE:
 		reg = &nss_top->bounce_interface_registrants[interface_num];
@@ -1250,6 +1338,7 @@
 		 */
 		if (unlikely(nss_ctx->state == NSS_CORE_STATE_UNINITIALIZED)) {
 			nss_core_init_nss(nss_ctx, if_map);
+			nss_send_ddr_info(nss_ctx);
 
 #if (NSS_MAX_CORES > 1)
 			/*
@@ -1473,10 +1562,10 @@
 		return NSS_N2H_INTR_TX_UNBLOCKED;
 	}
 
-	if (cause & NSS_N2H_INTR_DATA_COMMAND_QUEUE) {
+	if (cause & NSS_N2H_INTR_DATA_QUEUE_0) {
 		*type = NSS_INTR_CAUSE_QUEUE;
 		*weight = NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT;
-		return NSS_N2H_INTR_DATA_COMMAND_QUEUE;
+		return NSS_N2H_INTR_DATA_QUEUE_0;
 	}
 
 	if (cause & NSS_N2H_INTR_DATA_QUEUE_1) {
@@ -1485,6 +1574,18 @@
 		return NSS_N2H_INTR_DATA_QUEUE_1;
 	}
 
+	if (cause & NSS_N2H_INTR_DATA_QUEUE_2) {
+		*type = NSS_INTR_CAUSE_QUEUE;
+		*weight = NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT;
+		return NSS_N2H_INTR_DATA_QUEUE_2;
+	}
+
+	if (cause & NSS_N2H_INTR_DATA_QUEUE_3) {
+		*type = NSS_INTR_CAUSE_QUEUE;
+		*weight = NSS_DATA_COMMAND_BUFFER_PROCESSING_WEIGHT;
+		return NSS_N2H_INTR_DATA_QUEUE_3;
+	}
+
 	if (cause & NSS_N2H_INTR_COREDUMP_COMPLETE_0) {
 		printk("NSS core 0 signal COREDUMP COMPLETE %x ", cause);
 		*type = NSS_INTR_CAUSE_EMERGENCY;
diff --git a/nss_core.h b/nss_core.h
index c7faa01..738f36b 100644
--- a/nss_core.h
+++ b/nss_core.h
@@ -123,6 +123,8 @@
 #define NSS_IF_EMPTY_BUFFER_QUEUE 0
 #define NSS_IF_DATA_QUEUE_0 1
 #define NSS_IF_DATA_QUEUE_1 2
+#define NSS_IF_DATA_QUEUE_2 3
+#define NSS_IF_DATA_QUEUE_3 4
 #define NSS_IF_CMD_QUEUE 1
 
 /*
@@ -154,12 +156,13 @@
 /*
  * NSS maximum data queue per core
  */
-#define NSS_MAX_DATA_QUEUE 2
+#define NSS_MAX_DATA_QUEUE 4
 
 /*
- * NSS maximum IRQ per interrupt instance
+ * NSS maximum IRQ per interrupt instance/core
  */
-#define NSS_MAX_IRQ_PER_INSTANCE 5
+#define NSS_MAX_IRQ_PER_INSTANCE 4
+#define NSS_MAX_IRQ_PER_CORE 7
 
 /*
  * NSS maximum clients
@@ -822,6 +825,8 @@
 					/* HLOS IRQ numbers bind to this instance */
 	uint32_t shift_factor;		/* Shift factor for this IRQ queue */
 	uint32_t cause;			/* Interrupt cause carried forward to BH */
+	uint32_t queue_cause;		/* Queue cause bind to this interrupt ctx */
+	char irq_name[11];		/* IRQ name bind to this interrupt ctx */
 	struct net_device *ndev;	/* Netdev associated with this interrupt ctx */
 	struct napi_struct napi;	/* NAPI handler */
 };
@@ -1166,6 +1171,7 @@
 	uint32_t average_inst;	/* average of inst for nss core */
 	uint32_t coredump;	/* cmd coredump buffer */
 };
+extern struct nss_cmd_buffer nss_cmd_buf;
 
 /*
  * The scales for NSS
@@ -1233,17 +1239,17 @@
  *      Platform data per core
  */
 struct nss_platform_data {
-	uint32_t id;					/* NSS core ID */
-	uint32_t num_queue;				/* No. of queues supported per core */
-	uint32_t num_irq;				/* No. of irq binded per queue */
-	uint32_t irq[5];				/* IRQ numbers per queue */
-	void __iomem *nmap;				/* Virtual addr of NSS CSM space */
-	void __iomem *vmap;				/* Virtual addr of NSS virtual register map */
+	uint32_t id;				/* NSS core ID */
+	uint32_t num_queue;			/* No. of queues supported per core */
+	uint32_t num_irq;			/* No. of irq binded per queue */
+	uint32_t irq[NSS_MAX_IRQ_PER_CORE];	/* IRQ numbers per queue */
+	void __iomem *nmap;			/* Virtual addr of NSS CSM space */
+	void __iomem *vmap;			/* Virtual addr of NSS virtual register map */
 	void __iomem *qgic_map;			/* Virtual addr of QGIC interrupt register */
-	uint32_t nphys;					/* Physical addr of NSS CSM space */
-	uint32_t vphys;					/* Physical addr of NSS virtual register map */
-	uint32_t qgic_phys;				/* Physical addr of QGIC virtual register map */
-	uint32_t load_addr;				/* Load address of NSS firmware */
+	uint32_t nphys;				/* Physical addr of NSS CSM space */
+	uint32_t vphys;				/* Physical addr of NSS virtual register map */
+	uint32_t qgic_phys;			/* Physical addr of QGIC virtual register map */
+	uint32_t load_addr;			/* Load address of NSS firmware */
 
 	enum nss_feature_enabled capwap_enabled;
 				/* Does this core handle capwap? */
@@ -1385,7 +1391,7 @@
 /*
  * APIs provided by nss_freq.c
  */
-extern void nss_freq_sched_change(nss_freq_scales_t index, bool auto_scale);
+extern bool nss_freq_sched_change(nss_freq_scales_t index, bool auto_scale);
 
 /*
  * APIs for PPE
diff --git a/nss_coredump.c b/nss_coredump.c
index 1d870a2..4692d48 100644
--- a/nss_coredump.c
+++ b/nss_coredump.c
@@ -151,11 +151,21 @@
 		if (nss_ctx != nss_own) {
 			if (nss_ctx->state & NSS_CORE_STATE_FW_DEAD ||
 					!nss_ctx->nmap) {
-				/*
-				 * cannot call atomic_notifier_chain_unregister?
-				 * (&panic_notifier_list, &nss_panic_nb);
-				 */
-				panic("NSS FW coredump: bringing system down\n");
+				if (nss_cmd_buf.coredump & 0xFFFFFFFE) {
+					/*
+					 * bit 1 is used for testing coredump. Any other
+					 * bit(s) (value other than 0/1) disable panic
+					 * in order to use mdump utility: see mdump/src/README
+					 * for more info.
+					 */
+					nss_info_always("NSS core dump completed and please use mdump to collect dump data\n");
+				} else {
+					/*
+					 * cannot call atomic_notifier_chain_unregister?
+					 * (&panic_notifier_list, &nss_panic_nb);
+					 */
+					panic("NSS FW coredump: bringing system down\n");
+				}
 			}
 			nss_warning("notify NSS FW %p for coredump\n",
 				nss_ctx->nmap);
diff --git a/nss_crypto.c b/nss_crypto.c
index 200deab..cc1808a 100644
--- a/nss_crypto.c
+++ b/nss_crypto.c
@@ -129,12 +129,7 @@
 		return NSS_TX_FAILURE_NOT_READY;
 	}
 
-
-	if (NSS_NBUF_PAYLOAD_SIZE < sizeof(struct nss_crypto_msg)) {
-		nss_warning("%p: tx message request is too large: %d (desired), %d (requested)", nss_ctx,
-				NSS_NBUF_PAYLOAD_SIZE, (int)sizeof(struct nss_crypto_msg));
-		return NSS_TX_FAILURE_TOO_LARGE;
-	}
+	BUILD_BUG_ON(NSS_NBUF_PAYLOAD_SIZE < sizeof(struct nss_crypto_msg));
 
 	if (ncm->interface != NSS_CRYPTO_INTERFACE) {
 		nss_warning("%p: tx message request for another interface: %d", nss_ctx, ncm->interface);
diff --git a/nss_freq.c b/nss_freq.c
index d5e6fa9..86adbb6 100644
--- a/nss_freq.c
+++ b/nss_freq.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2013, 2015-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013, 2015-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.
@@ -24,7 +24,6 @@
 #define NSS_ACK_STARTED 0
 #define NSS_ACK_FINISHED 1
 
-extern struct nss_cmd_buffer nss_cmd_buf;
 extern struct nss_frequency_statistics nss_freq_stat;
 extern struct nss_runtime_sampling nss_runtime_samples;
 extern struct workqueue_struct *nss_wq;
@@ -71,7 +70,7 @@
  * nss_freq_queue_work()
  *	Queue Work to the NSS Workqueue based on Current index.
  */
-static int nss_freq_queue_work(void)
+static bool nss_freq_queue_work(void)
 {
 	nss_freq_scales_t index = nss_runtime_samples.freq_scale_index;
 
@@ -83,9 +82,7 @@
 	/*
 	 * schedule freq change with autoscale ON
 	 */
-	nss_freq_sched_change(index, true);
-
-	return 0;
+	return nss_freq_sched_change(index, true);
 }
 
 /*
@@ -171,7 +168,7 @@
 			 * If fail to increase frequency, decrease index
 			 */
 			nss_trace("frequency increase to %d inst:%x > maximum:%x\n", nss_runtime_samples.freq_scale[nss_runtime_samples.freq_scale_index].frequency, sample, maximum);
-			if (nss_freq_queue_work()) {
+			if (!nss_freq_queue_work()) {
 				nss_runtime_samples.freq_scale_index--;
 			}
 		}
@@ -198,7 +195,7 @@
 			 * If fail to decrease frequency, increase index
 			 */
 			nss_trace("frequency decrease to %d inst:%x < minumum:%x\n", nss_runtime_samples.freq_scale[nss_runtime_samples.freq_scale_index].frequency, nss_runtime_samples.average, minimum);
-			if (nss_freq_queue_work()) {
+			if (!nss_freq_queue_work()) {
 				nss_runtime_samples.freq_scale_index++;
 			}
 		}
@@ -282,17 +279,17 @@
  * nss_freq_sched_change()
  *	schedule a frequency work
  */
-void nss_freq_sched_change(nss_freq_scales_t index, bool auto_scale)
+bool nss_freq_sched_change(nss_freq_scales_t index, bool auto_scale)
 {
 	if (index >= NSS_FREQ_MAX_SCALE) {
 		nss_info("NSS freq scale beyond limit\n");
-		return;
+		return false;
 	}
 
 	nss_work = (nss_work_t *)kmalloc(sizeof(nss_work_t), GFP_ATOMIC);
 	if (!nss_work) {
 		nss_info("NSS Freq WQ kmalloc fail");
-		return;
+		return false;
 	}
 
 	INIT_WORK((struct work_struct *)nss_work, nss_wq_function);
@@ -302,6 +299,8 @@
 	nss_work->stats_enable = auto_scale;
 	nss_cmd_buf.current_freq = nss_work->frequency;
 	queue_work(nss_wq, (struct work_struct *)nss_work);
+
+	return true;
 }
 
 /*
diff --git a/nss_hal/include/nss_hal.h b/nss_hal/include/nss_hal.h
index 004dbba..1ac6e20 100644
--- a/nss_hal/include/nss_hal.h
+++ b/nss_hal/include/nss_hal.h
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2013, 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013, 2016-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.
@@ -43,13 +43,12 @@
 #endif
 
 #define NSS_HAL_SUPPORTED_INTERRUPTS (NSS_N2H_INTR_EMPTY_BUFFER_QUEUE | \
-					NSS_N2H_INTR_DATA_COMMAND_QUEUE | \
+					NSS_N2H_INTR_DATA_QUEUE_0 | \
 					NSS_N2H_INTR_DATA_QUEUE_1 | \
 					NSS_N2H_INTR_EMPTY_BUFFERS_SOS | \
 					NSS_N2H_INTR_TX_UNBLOCKED | \
 					NSS_N2H_INTR_COREDUMP_COMPLETE_0 | \
 					NSS_N2H_INTR_COREDUMP_COMPLETE_1)
-#define NSS_MAX_IRQ_PER_QUEUE 5
 
 /*
  * nss_hal_read_interrupt_cause()
diff --git a/nss_hal/include/nss_regs.h b/nss_hal/include/nss_regs.h
index b33b0b8..9af9508 100644
--- a/nss_hal/include/nss_regs.h
+++ b/nss_hal/include/nss_regs.h
@@ -60,8 +60,10 @@
  * both NSS cores may generate interrupt simultaneously
  */
 #define NSS_N2H_INTR_EMPTY_BUFFER_QUEUE		(1 << 0)
-#define NSS_N2H_INTR_DATA_COMMAND_QUEUE		(1 << 1)
+#define NSS_N2H_INTR_DATA_QUEUE_0		(1 << 1)
 #define NSS_N2H_INTR_DATA_QUEUE_1		(1 << 2)
+#define NSS_N2H_INTR_DATA_QUEUE_2		(1 << 3)
+#define NSS_N2H_INTR_DATA_QUEUE_3		(1 << 4)
 #define NSS_N2H_INTR_EMPTY_BUFFERS_SOS		(1 << 10)
 #define NSS_N2H_INTR_TX_UNBLOCKED		(1 << 11)
 #define NSS_N2H_INTR_COREDUMP_COMPLETE_1	(1 << 13)
diff --git a/nss_hal/ipq807x/nss_hal_pvt.c b/nss_hal/ipq807x/nss_hal_pvt.c
index f082ee6..b03534c 100644
--- a/nss_hal/ipq807x/nss_hal_pvt.c
+++ b/nss_hal/ipq807x/nss_hal_pvt.c
@@ -54,11 +54,11 @@
 /*
  * nss_hal_handle_data_cmd_irq()
  */
-static irqreturn_t nss_hal_handle_data_cmd_irq(int irq, void *ctx)
+static irqreturn_t nss_hal_handle_data_cmd_queue_irq(int irq, void *ctx)
 {
 	struct int_ctx_instance *int_ctx = (struct int_ctx_instance *) ctx;
 
-	int_ctx->cause |= NSS_N2H_INTR_DATA_COMMAND_QUEUE;
+	int_ctx->cause |= int_ctx->queue_cause;
 
 	if (napi_schedule_prep(&int_ctx->napi))
 		__napi_schedule(&int_ctx->napi);
@@ -97,21 +97,6 @@
 }
 
 /*
- * nss_hal_handle_data_queue_one_irq()
- */
-static irqreturn_t nss_hal_handle_data_queue_one_irq(int irq, void *ctx)
-{
-	struct int_ctx_instance *int_ctx = (struct int_ctx_instance *) ctx;
-
-	int_ctx->cause |= NSS_N2H_INTR_DATA_QUEUE_1;
-
-	if (napi_schedule_prep(&int_ctx->napi))
-		__napi_schedule(&int_ctx->napi);
-
-	return IRQ_HANDLED;
-}
-
-/*
  * nss_hal_handle_tx_unblock_irq()
  */
 static irqreturn_t nss_hal_handle_tx_unblock_irq(int irq, void *ctx)
@@ -429,15 +414,19 @@
 	int err;
 
 	/*
-	 * Queue1 use the last (#5) IRQ and queue0 use #1 to #4
+	 * Queue0-3 use the IRQ #4 to #7, and are mapped to cause bit 1 to 4
 	 */
-	if (qnum == 1) {
-		err = request_irq(npd->irq[4], nss_hal_handle_data_queue_one_irq, 0, "nss_queue1", int_ctx);
-		if (err) {
-			nss_info_always("%p: IRQ%d request failed", int_ctx, npd->irq[4]);
-			return err;
-		}
-		int_ctx->irq[0] = npd->irq[4];
+	snprintf(int_ctx->irq_name, 11, "nss_queue%d", qnum);
+	int_ctx->queue_cause = (1 << (qnum+1));
+	err = request_irq(npd->irq[qnum+3], nss_hal_handle_data_cmd_queue_irq, 0, int_ctx->irq_name, int_ctx);
+	if (err) {
+		nss_info_always("%p: IRQ%d request failed", int_ctx, npd->irq[qnum+3]);
+		return err;
+	}
+
+	int_ctx->irq[0] = npd->irq[qnum+3];
+
+	if (qnum) {
 		return 0;
 	}
 
@@ -446,28 +435,24 @@
 		nss_info_always("%p: IRQ%d request failed", int_ctx, npd->irq[0]);
 		return err;
 	}
-	int_ctx->irq[0] = npd->irq[0];
 
-	err = request_irq(npd->irq[1], nss_hal_handle_data_cmd_irq, 0, "nss_queue0", int_ctx);
+	int_ctx->irq[1] = npd->irq[0];
+
+	err = request_irq(npd->irq[1], nss_hal_handle_empty_buff_queue_irq, 0, "nss_empty_buf_queue", int_ctx);
 	if (err) {
 		nss_info_always("%p: IRQ%d request failed", int_ctx, npd->irq[1]);
 		return err;
 	}
-	int_ctx->irq[1] = npd->irq[1];
 
-	err = request_irq(npd->irq[2], nss_hal_handle_empty_buff_queue_irq, 0, "nss_empty_buf_queue", int_ctx);
+	int_ctx->irq[2] = npd->irq[1];
+
+	err = request_irq(npd->irq[2], nss_hal_handle_tx_unblock_irq, 0, "nss-tx-unblock", int_ctx);
 	if (err) {
 		nss_info_always("%p: IRQ%d request failed", int_ctx, npd->irq[2]);
 		return err;
 	}
-	int_ctx->irq[2] = npd->irq[2];
 
-	err = request_irq(npd->irq[3], nss_hal_handle_tx_unblock_irq, 0, "nss-tx-unblock", int_ctx);
-	if (err) {
-		nss_info_always("%p: IRQ%d request failed", int_ctx, npd->irq[3]);
-		return err;
-	}
-	int_ctx->irq[3] = npd->irq[3];
+	int_ctx->irq[3] = npd->irq[2];
 
 	return 0;
 }
diff --git a/nss_hal/nss_hal.c b/nss_hal/nss_hal.c
index 537bde1..7970602 100644
--- a/nss_hal/nss_hal.c
+++ b/nss_hal/nss_hal.c
@@ -142,12 +142,17 @@
 {
 	int i;
 
-	for (i = 0; i < NSS_MAX_IRQ_PER_QUEUE; i++) {
+	for (i = 0; i < NSS_MAX_IRQ_PER_INSTANCE; i++) {
 		if (int_ctx->irq[i]) {
 			free_irq(int_ctx->irq[i], int_ctx);
 			int_ctx->irq[i] = 0;
 		}
 	}
+
+	if (!int_ctx->ndev) {
+		return;
+	}
+
 	unregister_netdev(int_ctx->ndev);
 	free_netdev(int_ctx->ndev);
 	int_ctx->ndev = NULL;
@@ -196,7 +201,6 @@
 	err = nss_top->hal_ops->request_irq_for_queue(nss_ctx, npd, qnum);
 	if (err) {
 		nss_warning("%p: IRQ request for queue %d failed", nss_ctx, qnum);
-		nss_hal_clean_up_netdevice(int_ctx);
 		return err;
 	}
 
@@ -312,26 +316,10 @@
 	nss_info("%d:ctx=%p, vphys=%x, vmap=%p, nphys=%x, nmap=%p", nss_ctx->id,
 			nss_ctx, nss_ctx->vphys, nss_ctx->vmap, nss_ctx->nphys, nss_ctx->nmap);
 
-	/*
-	 * Register netdevice for queue 0
-	 */
-	err = nss_hal_register_netdevice(nss_ctx, npd, 0);
-	if (err) {
-		goto err_init;
-	}
-
-	/*
-	 * Check if second interrupt is supported on this nss core
-	 */
-	if (npd->num_queue > 1) {
-		nss_info("%d: This NSS core supports two interrupts", nss_dev->id);
-
-		/*
-		 * Register netdevice for queue 1
-		 */
-		err = nss_hal_register_netdevice(nss_ctx, npd, 1);
+	for (i = 0; i < npd->num_queue; i++) {
+		err = nss_hal_register_netdevice(nss_ctx, npd, i);
 		if (err) {
-			goto err_register_netdev_0;
+			goto err_register_netdevice;
 		}
 	}
 
@@ -523,7 +511,7 @@
 	 */
 	err = nss_top->hal_ops->core_reset(nss_dev, nss_ctx->nmap, nss_ctx->load, nss_top->clk_src);
 	if (err) {
-		goto err_register_netdev_1;
+		goto err_register_netdevice;
 	}
 
 	/*
@@ -562,11 +550,10 @@
 	nss_info("%p: All resources initialized and nss core%d has been brought out of reset", nss_ctx, nss_dev->id);
 	goto out;
 
-err_register_netdev_1:
-	nss_hal_clean_up_netdevice(&nss_ctx->int_ctx[1]);
-
-err_register_netdev_0:
-	nss_hal_clean_up_netdevice(&nss_ctx->int_ctx[0]);
+err_register_netdevice:
+	for (i = 0; i < npd->num_queue; i++) {
+		nss_hal_clean_up_netdevice(&nss_ctx->int_ctx[i]);
+	}
 
 err_init:
 	if (nss_dev->dev.of_node) {
diff --git a/nss_init.c b/nss_init.c
index f35e793..05314b1 100644
--- a/nss_init.c
+++ b/nss_init.c
@@ -464,7 +464,12 @@
 
 	ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
 	if (!ret) {
-		if ((write) && (nss_ctl_debug != 0)) {
+		/*
+		 * if nss_cmd_buf.coredump is not 0 or 1, panic will be disabled
+		 * when NSS FW crashes, so OEM/ODM have a chance to use mdump
+		 * to dump crash dump (coredump) and send dump to us for analysis.
+		 */
+		if ((write) && (nss_ctl_debug != 0) && nss_cmd_buf.coredump == 1) {
 			printk("Coredumping to DDR\n");
 			nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_TRIGGER_COREDUMP);
 		}
diff --git a/nss_ipsec.c b/nss_ipsec.c
index 0a91a0a..b0b3009 100644
--- a/nss_ipsec.c
+++ b/nss_ipsec.c
@@ -178,11 +178,7 @@
 		return NSS_TX_FAILURE_NOT_READY;
 	}
 
-	if (NSS_NBUF_PAYLOAD_SIZE < sizeof(struct nss_ipsec_msg)) {
-		nss_ipsec_warning("%p: tx message request is too large: %d (desired), %d (requested)", nss_ctx,
-				NSS_NBUF_PAYLOAD_SIZE, (int)sizeof(struct nss_ipsec_msg));
-		return NSS_TX_FAILURE_TOO_LARGE;
-	}
+	BUILD_BUG_ON(NSS_NBUF_PAYLOAD_SIZE < sizeof(struct nss_ipsec_msg));
 
 	if ((ncm->interface != NSS_IPSEC_ENCAP_IF_NUMBER) && (ncm->interface != NSS_IPSEC_DECAP_IF_NUMBER)) {
 		nss_ipsec_warning("%p: tx message request for another interface: %d", nss_ctx, ncm->interface);
diff --git a/nss_virt_if.c b/nss_virt_if.c
index c476a41..b4eed1f 100644
--- a/nss_virt_if.c
+++ b/nss_virt_if.c
@@ -160,7 +160,7 @@
  *	Send a message from HLOS to NSS synchronously.
  */
 static nss_tx_status_t nss_virt_if_tx_msg_sync(struct nss_virt_if_handle *handle,
-							struct nss_virt_if_msg *nvim)
+						struct nss_virt_if_msg *nvim)
 {
 	nss_tx_status_t status;
 	int ret = 0;
@@ -870,7 +870,7 @@
 				nss_virt_if_data_callback_t data_callback,
 				struct net_device *netdev)
 {
-	struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
+	struct nss_ctx_instance *nss_ctx;
 	int32_t if_num;
 
 	if (!handle) {
@@ -878,6 +878,7 @@
 		return;
 	}
 
+	nss_ctx = handle->nss_ctx;
 	if_num = handle->if_num;
 
 	nss_ctx->subsys_dp_register[if_num].ndev = netdev;
@@ -894,7 +895,7 @@
  */
 void nss_virt_if_unregister(struct nss_virt_if_handle *handle)
 {
-	struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
+	struct nss_ctx_instance *nss_ctx;
 	int32_t if_num;
 
 	if (!handle) {
@@ -902,6 +903,7 @@
 		return;
 	}
 
+	nss_ctx = handle->nss_ctx;
 	if_num = handle->if_num;
 
 	nss_ctx->subsys_dp_register[if_num].ndev = NULL;