[qca-nss-drv] Add framework for stats printing.

Provide a set of helper APIs to assist NSS sub-systems with
printing of stats in a consistent fashion.

Change-Id: Ia7b63abaf0b7c3d724df4012a48c8ce0384bdfb6
Signed-off-by: Siva Sai Krishna Marthy <smarthy@codeaurora.org>
Signed-off-by: Sakthi Vignesh Radhakrishnan <sradhakr@codeaurora.org>
diff --git a/Makefile b/Makefile
index 01315d7..ec9a4aa 100644
--- a/Makefile
+++ b/Makefile
@@ -24,12 +24,14 @@
 			nss_cmn.o \
 			nss_core.o \
 			nss_coredump.o \
+			nss_drv_stats.o \
 			nss_dynamic_interface.o \
 			nss_dynamic_interface_log.o \
 			nss_edma.o \
 			nss_edma_stats.o \
 			nss_eth_rx.o \
 			nss_eth_rx_stats.o \
+			nss_gmac_stats.o \
 			nss_gre.o \
 			nss_gre_log.o \
 			nss_gre_stats.o \
diff --git a/nss_c2c_rx_stats.c b/nss_c2c_rx_stats.c
index 0218df3..8308547 100644
--- a/nss_c2c_rx_stats.c
+++ b/nss_c2c_rx_stats.c
@@ -14,7 +14,6 @@
  **************************************************************************
  */
 
-#include "nss_stats.h"
 #include "nss_core.h"
 #include "nss_c2c_rx.h"
 
diff --git a/nss_c2c_tx_stats.c b/nss_c2c_tx_stats.c
index 61c5368..6fdb2e9 100644
--- a/nss_c2c_tx_stats.c
+++ b/nss_c2c_tx_stats.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, 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.
@@ -14,7 +14,6 @@
  **************************************************************************
  */
 
-#include "nss_stats.h"
 #include "nss_core.h"
 #include "nss_c2c_tx_stats.h"
 
diff --git a/nss_capwap_stats.c b/nss_capwap_stats.c
index 1f622ad..749c319 100644
--- a/nss_capwap_stats.c
+++ b/nss_capwap_stats.c
@@ -14,7 +14,7 @@
  **************************************************************************
  */
 
-#include "nss_stats.h"
+#include "nss_drv_stats.h"
 #include "nss_core.h"
 #include "nss_capwap.h"
 #include "nss_capwap_stats.h"
diff --git a/nss_core.c b/nss_core.c
index 4ff0fb6..bd5db14 100644
--- a/nss_core.c
+++ b/nss_core.c
@@ -686,7 +686,7 @@
 
 	uint16_t queue_offset = 0;
 
-	NSS_PKT_STATS_INC(&nss_top->stats_drv[NSS_STATS_DRV_RX_VIRTUAL]);
+	NSS_PKT_STATS_INC(&nss_top->stats_drv[NSS_DRV_STATS_RX_VIRTUAL]);
 
 	/*
 	 * Checksum is already done by NSS for packets forwarded to virtual interfaces
@@ -778,7 +778,7 @@
 	nss_phys_if_rx_callback_t cb;
 	uint16_t queue_offset = qid - NSS_IF_N2H_DATA_QUEUE_0;
 
-	NSS_PKT_STATS_INC(&nss_top->stats_drv[NSS_STATS_DRV_RX_PACKET]);
+	NSS_PKT_STATS_INC(&nss_top->stats_drv[NSS_DRV_STATS_RX_PACKET]);
 
 	/*
 	 * Check if NSS was able to obtain checksum
@@ -861,7 +861,7 @@
 	struct net_device *ndev = NULL;
 	nss_phys_if_rx_ext_data_callback_t ext_cb;
 
-	NSS_PKT_STATS_INC(&nss_top->stats_drv[NSS_STATS_DRV_RX_EXT_PACKET]);
+	NSS_PKT_STATS_INC(&nss_top->stats_drv[NSS_DRV_STATS_RX_EXT_PACKET]);
 
 	/*
 	 * Check if NSS was able to obtain checksum
@@ -900,7 +900,7 @@
 	struct nss_shaper_bounce_registrant *reg = NULL;
 	int32_t status;
 
-	NSS_PKT_STATS_DEC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NSS_SKB_COUNT]);
+	NSS_PKT_STATS_DEC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_NSS_SKB_COUNT]);
 
 	if (interface_num >= NSS_MAX_NET_INTERFACES) {
 		nss_warning("%p: Invalid interface_num: %d", nss_ctx, interface_num);
@@ -946,13 +946,13 @@
 		break;
 
 	case N2H_BUFFER_STATUS:
-		NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_RX_STATUS]);
+		NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_RX_STATUS]);
 		nss_core_handle_nss_status_pkt(nss_ctx, nbuf);
 		dev_kfree_skb_any(nbuf);
 		break;
 
 	case N2H_BUFFER_CRYPTO_RESP:
-		NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_RX_CRYPTO_RESP]);
+		NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_RX_CRYPTO_RESP]);
 		nss_core_handle_crypto_pkt(nss_ctx, interface_num, nbuf, napi);
 		break;
 
@@ -965,7 +965,7 @@
 		 * They are again marked with H2N_BUFFER_RATE_TEST buffer type so NSS can process
 		 * and count the test packets properly.
 		 */
-		NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_RX_STATUS]);
+		NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_RX_STATUS]);
 		status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_H2N_DATA_QUEUE, H2N_BUFFER_RATE_TEST, H2N_BIT_FLAG_BUFFER_REUSABLE);
 		if (unlikely(status != NSS_CORE_STATUS_SUCCESS)) {
 			dev_kfree_skb_any(nbuf);
@@ -1041,7 +1041,7 @@
 	/*
 	 * Track Number of Fragments processed. First && Last is not true fragment
 	 */
-	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_FRAG_SEG_PROCESSED]);
+	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_FRAG_SEG_PROCESSED]);
 
 	/*
 	 * NSS sent us an SG chain.
@@ -1087,7 +1087,7 @@
 		return false;
 	}
 
-	NSS_PKT_STATS_DEC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NSS_SKB_COUNT]);
+	NSS_PKT_STATS_DEC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_NSS_SKB_COUNT]);
 
 	/*
 	 * We've received a middle or a last segment.
@@ -1193,14 +1193,14 @@
 		 * NSS should playaround with data area and should not
 		 * touch HEADROOM area
 		 */
-		NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_RX_SIMPLE]);
+		NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_RX_SIMPLE]);
 		return true;
 	}
 
 	/*
 	 * Track number of skb chain processed. First && Last is not true segment.
 	 */
-	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_CHAIN_SEG_PROCESSED]);
+	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_CHAIN_SEG_PROCESSED]);
 
 	/*
 	 * NSS sent us an SG chain.
@@ -1214,7 +1214,7 @@
 		 */
 		if (unlikely(head)) {
 			nss_warning("%p: received the second head before a last", head);
-			NSS_PKT_STATS_DEC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NSS_SKB_COUNT]);
+			NSS_PKT_STATS_DEC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_NSS_SKB_COUNT]);
 			dev_kfree_skb_any(head);
 		}
 
@@ -1226,7 +1226,7 @@
 			 * We don't support chain in a chain.
 			 */
 			nss_warning("%p: skb already has a fraglist", nbuf);
-			NSS_PKT_STATS_DEC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NSS_SKB_COUNT]);
+			NSS_PKT_STATS_DEC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_NSS_SKB_COUNT]);
 			dev_kfree_skb_any(nbuf);
 			return false;
 		}
@@ -1254,7 +1254,7 @@
 		return false;
 	}
 
-	NSS_PKT_STATS_DEC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NSS_SKB_COUNT]);
+	NSS_PKT_STATS_DEC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_NSS_SKB_COUNT]);
 
 	/*
 	 * We've received a middle segment.
@@ -1308,7 +1308,7 @@
 	*nbuf_ptr = head;
 	*head_ptr = NULL;
 	*tail_ptr = NULL;
-	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_RX_SKB_FRAGLIST]);
+	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_RX_SKB_FRAGLIST]);
 	return true;
 }
 
@@ -1358,15 +1358,15 @@
 			 * Invalid opaque pointer
 			 */
 			nss_dump_desc(nss_ctx, desc);
-			NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_RX_BAD_DESCRIPTOR]);
+			NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_RX_BAD_DESCRIPTOR]);
 			goto next;
 		}
 
 		dma_unmap_single(nss_ctx->dev, (desc->buffer + desc->payload_offs), desc->payload_len, DMA_TO_DEVICE);
 		dev_kfree_skb_any(nbuf);
 
-		NSS_PKT_STATS_DEC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NSS_SKB_COUNT]);
-		NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_RX_EMPTY]);
+		NSS_PKT_STATS_DEC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_NSS_SKB_COUNT]);
+		NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_RX_EMPTY]);
 
 next:
 		hlos_index = (hlos_index + 1) & (mask);
@@ -1494,7 +1494,7 @@
 			 * Invalid opaque pointer
 			 */
 			nss_dump_desc(nss_ctx, desc);
-			NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_RX_BAD_DESCRIPTOR]);
+			NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_RX_BAD_DESCRIPTOR]);
 			goto next;
 		}
 
@@ -1528,7 +1528,7 @@
 				nss_warning("%p: we should not have an incomplete paged skb while"
 								" constructing a linear skb %p", nbuf, n2h_desc_ring->head);
 
-				NSS_PKT_STATS_DEC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NSS_SKB_COUNT]);
+				NSS_PKT_STATS_DEC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_NSS_SKB_COUNT]);
 				dev_kfree_skb_any(n2h_desc_ring->head);
 				n2h_desc_ring->head = NULL;
 			}
@@ -1536,7 +1536,7 @@
 			if (!nss_core_handle_nr_frag_skb(nss_ctx, &nbuf, &n2h_desc_ring->jumbo_start, desc, buffer_type)) {
 				goto next;
 			}
-			NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_RX_NR_FRAGS]);
+			NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_RX_NR_FRAGS]);
 			goto consume;
 		}
 
@@ -1548,7 +1548,7 @@
 			nss_warning("%p: we should not have an incomplete linear skb while"
 							" constructing a paged skb %p", nbuf, n2h_desc_ring->jumbo_start);
 
-			NSS_PKT_STATS_DEC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NSS_SKB_COUNT]);
+			NSS_PKT_STATS_DEC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_NSS_SKB_COUNT]);
 			dev_kfree_skb_any(n2h_desc_ring->jumbo_start);
 			n2h_desc_ring->jumbo_start = NULL;
 		}
@@ -1716,7 +1716,7 @@
 		 * We are holding this skb in NSS FW, let kmemleak know about it
 		 */
 		kmemleak_not_leak(nbuf);
-		NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NSS_SKB_COUNT]);
+		NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_NSS_SKB_COUNT]);
 		desc->opaque = (nss_ptr_t)nbuf;
 		desc->buffer = buffer;
 		desc->buffer_type = buffer_type;
@@ -1766,7 +1766,7 @@
 			/*
 			 * ERR:
 			 */
-			NSS_PKT_STATS_INC(&nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
+			NSS_PKT_STATS_INC(&nss_top->stats_drv[NSS_DRV_STATS_NBUF_ALLOC_FAILS]);
 			nss_warning("%p: Could not obtain empty jumbo mru buffer", nss_ctx);
 			break;
 		}
@@ -1790,7 +1790,7 @@
 		 * We are holding this skb in NSS FW, let kmemleak know about it
 		 */
 		kmemleak_not_leak(nbuf);
-		NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NSS_SKB_COUNT]);
+		NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_NSS_SKB_COUNT]);
 		desc->opaque = (nss_ptr_t)nbuf;
 		desc->buffer = buffer;
 		desc->buffer_type = H2N_BUFFER_EMPTY;
@@ -1815,7 +1815,7 @@
 	NSS_CORE_DMA_CACHE_MAINT(&if_map->h2n_hlos_index[NSS_IF_H2N_EMPTY_BUFFER_QUEUE], sizeof(uint32_t), DMA_TO_DEVICE);
 	NSS_CORE_DSB();
 
-	NSS_PKT_STATS_INC(&nss_top->stats_drv[NSS_STATS_DRV_TX_EMPTY]);
+	NSS_PKT_STATS_INC(&nss_top->stats_drv[NSS_DRV_STATS_TX_EMPTY]);
 }
 
 /*
@@ -1842,7 +1842,7 @@
 			/*
 			 * ERR:
 			 */
-			NSS_PKT_STATS_INC(&nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
+			NSS_PKT_STATS_INC(&nss_top->stats_drv[NSS_DRV_STATS_NBUF_ALLOC_FAILS]);
 			nss_warning("%p: Could not obtain empty buffer", nss_ctx);
 			break;
 		}
@@ -1865,7 +1865,7 @@
 		 * We are holding this skb in NSS FW, let kmemleak know about it
 		 */
 		kmemleak_not_leak(nbuf);
-		NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NSS_SKB_COUNT]);
+		NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_NSS_SKB_COUNT]);
 
 		desc->opaque = (nss_ptr_t)nbuf;
 		desc->buffer = buffer;
@@ -1904,7 +1904,7 @@
 	NSS_CORE_DMA_CACHE_MAINT(&if_map->h2n_hlos_index[NSS_IF_H2N_EMPTY_BUFFER_QUEUE], sizeof(uint32_t), DMA_TO_DEVICE);
 	NSS_CORE_DSB();
 
-	NSS_PKT_STATS_INC(&nss_top->stats_drv[NSS_STATS_DRV_TX_EMPTY]);
+	NSS_PKT_STATS_INC(&nss_top->stats_drv[NSS_DRV_STATS_TX_EMPTY]);
 }
 
 /*
@@ -1946,8 +1946,8 @@
 
 	if (paged_mode) {
 		nss_core_alloc_paged_buffers(nss_ctx, if_map, count, mask, hlos_index,
-					NSS_STATS_DRV_NBUF_ALLOC_FAILS, H2N_BUFFER_EMPTY,
-					NSS_IF_H2N_EMPTY_BUFFER_QUEUE, NSS_STATS_DRV_TX_EMPTY);
+					NSS_DRV_STATS_NBUF_ALLOC_FAILS, H2N_BUFFER_EMPTY,
+					NSS_IF_H2N_EMPTY_BUFFER_QUEUE, NSS_DRV_STATS_TX_EMPTY);
 	} else if (jumbo_mru) {
 		nss_core_alloc_jumbo_mru_buffers(nss_ctx, if_map, jumbo_mru, count,
 					mask, hlos_index);
@@ -1996,8 +1996,8 @@
 	}
 
 	nss_core_alloc_paged_buffers(nss_ctx, if_map, count, mask, hlos_index,
-			NSS_STATS_DRV_PAGED_BUF_ALLOC_FAILS, H2N_PAGED_BUFFER_EMPTY,
-			NSS_IF_H2N_EMPTY_PAGED_BUFFER_QUEUE, NSS_STATS_DRV_PAGED_TX_EMPTY);
+			NSS_DRV_STATS_PAGED_BUF_ALLOC_FAILS, H2N_PAGED_BUFFER_EMPTY,
+			NSS_IF_H2N_EMPTY_PAGED_BUFFER_QUEUE, NSS_DRV_STATS_PAGED_TX_EMPTY);
 
 	/*
 	 * Inform NSS that new buffers are available
@@ -2566,7 +2566,7 @@
 	 */
 	nss_skb_reuse(nbuf);
 
-	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_BUFFER_REUSE]);
+	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_TX_BUFFER_REUSE]);
 	return 1;
 
 no_reuse:
@@ -2585,7 +2585,7 @@
 
 	NSS_CORE_DMA_CACHE_MAINT((void *)desc, sizeof(*desc), DMA_TO_DEVICE);
 
-	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_SIMPLE]);
+	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_TX_SIMPLE]);
 	return 1;
 }
 
@@ -2681,7 +2681,7 @@
 
 	NSS_CORE_DMA_CACHE_MAINT((void *)desc, sizeof(*desc), DMA_TO_DEVICE);
 
-	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_NR_FRAGS]);
+	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_TX_NR_FRAGS]);
 	return i+1;
 }
 
@@ -2800,7 +2800,7 @@
 	 * So, the information will be in the NSS-FW.
 	 */
 	skb_shinfo(nbuf)->frag_list = NULL;
-	NSS_PKT_STATS_ADD(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NSS_SKB_COUNT], i);
+	NSS_PKT_STATS_ADD(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_NSS_SKB_COUNT], i);
 
 	/*
 	 * Update bit flag for last descriptor.
@@ -2808,7 +2808,7 @@
 	desc->bit_flags |= H2N_BIT_FLAG_LAST_SEGMENT;
 	NSS_CORE_DMA_CACHE_MAINT((void *)desc, sizeof(*desc), DMA_TO_DEVICE);
 
-	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_FRAGLIST]);
+	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_TX_FRAGLIST]);
 	return i+1;
 }
 
@@ -2888,9 +2888,9 @@
 
 #if (NSS_PKT_STATS_ENABLED == 1)
 		if (nss_ctx->id == NSS_CORE_0) {
-			NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_QUEUE_FULL_0]);
+			NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_TX_QUEUE_FULL_0]);
 		} else if (nss_ctx->id == NSS_CORE_1) {
-			NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_QUEUE_FULL_1]);
+			NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_TX_QUEUE_FULL_1]);
 		} else {
 			nss_warning("%p: Invalid nss core: %d\n", nss_ctx, nss_ctx->id);
 		}
@@ -2986,7 +2986,7 @@
 	}
 #endif
 
-	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NSS_SKB_COUNT]);
+	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_NSS_SKB_COUNT]);
 
 	spin_unlock_bh(&h2n_desc_ring->lock);
 	return NSS_CORE_STATUS_SUCCESS;
@@ -3022,7 +3022,7 @@
 
 	nbuf = dev_alloc_skb(buf_size);
 	if (unlikely(!nbuf)) {
-		NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
+		NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_NBUF_ALLOC_FAILS]);
 		nss_warning("%p: interface: %d type: %d msg dropped as command allocation failed", nss_ctx, ncm->interface, ncm->type);
 		return NSS_TX_FAILURE;
 	}
@@ -3032,13 +3032,13 @@
 	status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_H2N_CMD_QUEUE, H2N_BUFFER_CTRL, H2N_BIT_FLAG_BUFFER_REUSABLE);
 	if (status != NSS_CORE_STATUS_SUCCESS) {
 		dev_kfree_skb_any(nbuf);
-		NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CMD_QUEUE_FULL]);
+		NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_TX_CMD_QUEUE_FULL]);
 		nss_warning("%p: interface: %d type: %d unable to enqueue message status %d\n", nss_ctx, ncm->interface, ncm->type, status);
 		return status;
 	}
 
 	nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
-	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CMD_REQ]);
+	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_TX_CMD_REQ]);
 	return status;
 }
 
@@ -3075,9 +3075,9 @@
 	/*
 	 * Count per queue and aggregate packet count
 	 */
-	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_PACKET_QUEUE_0 + queue_id]);
+	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_TX_PACKET_QUEUE_0 + queue_id]);
 #endif
-	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_PACKET]);
+	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_TX_PACKET]);
 	return status;
 }
 
diff --git a/nss_core.h b/nss_core.h
index 45cbd0a..061e96d 100644
--- a/nss_core.h
+++ b/nss_core.h
@@ -39,8 +39,9 @@
 #include "nss_hlos_if.h"
 #include "nss_oam.h"
 #include "nss_data_plane.h"
-#include "nss_stats.h"
+#include "nss_gmac_stats.h"
 #include "nss_meminfo.h"
+#include "nss_stats.h"
 
 /*
  * XXX:can't add this to api_if.h till the deprecated
@@ -324,69 +325,6 @@
 extern struct nss_top_instance nss_top_main;
 
 /*
- * HLOS driver statistics
- *
- * WARNING: There is a 1:1 mapping between values below and corresponding
- *	stats string array in nss_stats.c
- */
-enum nss_stats_drv {
-	NSS_STATS_DRV_NBUF_ALLOC_FAILS = 0,	/* NBUF allocation errors */
-	NSS_STATS_DRV_PAGED_BUF_ALLOC_FAILS,	/* Paged buf allocation errors */
-	NSS_STATS_DRV_TX_QUEUE_FULL_0,		/* Tx queue full for Core 0*/
-	NSS_STATS_DRV_TX_QUEUE_FULL_1,		/* Tx queue full for Core 1*/
-	NSS_STATS_DRV_TX_EMPTY,			/* H2N Empty buffers */
-	NSS_STATS_DRV_PAGED_TX_EMPTY,		/* H2N Paged Empty buffers */
-	NSS_STATS_DRV_TX_PACKET,		/* H2N Data packets */
-	NSS_STATS_DRV_TX_CMD_REQ,		/* H2N Control packets */
-	NSS_STATS_DRV_TX_CRYPTO_REQ,		/* H2N Crypto requests */
-	NSS_STATS_DRV_TX_BUFFER_REUSE,		/* H2N Reuse buffer count */
-	NSS_STATS_DRV_RX_EMPTY,			/* N2H Empty buffers */
-	NSS_STATS_DRV_RX_PACKET,		/* N2H Data packets */
-	NSS_STATS_DRV_RX_EXT_PACKET,		/* N2H EXT type packets */
-	NSS_STATS_DRV_RX_CMD_RESP,		/* N2H Command responses */
-	NSS_STATS_DRV_RX_STATUS,		/* N2H Status packets */
-	NSS_STATS_DRV_RX_CRYPTO_RESP,		/* N2H Crypto responses */
-	NSS_STATS_DRV_RX_VIRTUAL,		/* N2H Virtual packets */
-	NSS_STATS_DRV_TX_SIMPLE,		/* H2N Simple SKB Packets */
-	NSS_STATS_DRV_TX_NR_FRAGS,		/* H2N NR Frags SKB Packets */
-	NSS_STATS_DRV_TX_FRAGLIST,		/* H2N Fraglist SKB Packets */
-	NSS_STATS_DRV_RX_SIMPLE,		/* N2H Simple SKB Packets */
-	NSS_STATS_DRV_RX_NR_FRAGS,		/* N2H NR Frags SKB Packets */
-	NSS_STATS_DRV_RX_SKB_FRAGLIST,		/* N2H Fraglist SKB Packets */
-	NSS_STATS_DRV_RX_BAD_DESCRIPTOR,	/* N2H Bad descriptor reads */
-	NSS_STATS_DRV_NSS_SKB_COUNT,		/* NSS SKB Pool Count */
-	NSS_STATS_DRV_CHAIN_SEG_PROCESSED,	/* N2H SKB Chain Processed Count */
-	NSS_STATS_DRV_FRAG_SEG_PROCESSED,	/* N2H Frag Processed Count */
-	NSS_STATS_DRV_TX_CMD_QUEUE_FULL,	/* Tx H2N Control packets fail due to queue full */
-#ifdef NSS_MULTI_H2N_DATA_RING_SUPPORT
-	NSS_STATS_DRV_TX_PACKET_QUEUE_0,	/* H2N Data packets on queue0 */
-	NSS_STATS_DRV_TX_PACKET_QUEUE_1,        /* H2N Data packets on queue1 */
-	NSS_STATS_DRV_TX_PACKET_QUEUE_2,        /* H2N Data packets on queue2 */
-	NSS_STATS_DRV_TX_PACKET_QUEUE_3,        /* H2N Data packets on queue3 */
-	NSS_STATS_DRV_TX_PACKET_QUEUE_4,        /* H2N Data packets on queue4 */
-	NSS_STATS_DRV_TX_PACKET_QUEUE_5,        /* H2N Data packets on queue5 */
-	NSS_STATS_DRV_TX_PACKET_QUEUE_6,        /* H2N Data packets on queue6 */
-	NSS_STATS_DRV_TX_PACKET_QUEUE_7,        /* H2N Data packets on queue7 */
-#endif
-	NSS_STATS_DRV_MAX,
-};
-
-/*
- * GMAC node statistics
- *
- * WARNING: There is a 1:1 mapping between values below and corresponding
- *	stats string array in nss_stats.c
- */
-enum nss_stats_gmac {
-	NSS_STATS_GMAC_TOTAL_TICKS = 0,
-					/* Total clock ticks spend inside the GMAC */
-	NSS_STATS_GMAC_WORST_CASE_TICKS,
-					/* Worst case iteration of the GMAC in ticks */
-	NSS_STATS_GMAC_ITERATIONS,	/* Number of iterations around the GMAC */
-	NSS_STATS_GMAC_MAX,
-};
-
-/*
  * NSS core state
  */
 enum nss_core_state {
@@ -707,9 +645,9 @@
 	/*
 	 * Statistics for various interfaces
 	 */
-	atomic64_t stats_drv[NSS_STATS_DRV_MAX];
+	atomic64_t stats_drv[NSS_DRV_STATS_MAX];
 					/* Hlos driver statistics */
-	uint64_t stats_gmac[NSS_MAX_PHYSICAL_INTERFACES][NSS_STATS_GMAC_MAX];
+	uint64_t stats_gmac[NSS_MAX_PHYSICAL_INTERFACES][NSS_GMAC_STATS_MAX];
 					/* GMAC statistics */
 	uint64_t stats_node[NSS_MAX_NET_INTERFACES][NSS_STATS_NODE_MAX];
 					/* IPv4 statistics per interface */
diff --git a/nss_crypto.c b/nss_crypto.c
index b2603eb..01b4bb1 100644
--- a/nss_crypto.c
+++ b/nss_crypto.c
@@ -179,7 +179,7 @@
 	 */
 	nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
 
-	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CRYPTO_REQ]);
+	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_TX_CRYPTO_REQ]);
 
 	return NSS_TX_SUCCESS;
 }
diff --git a/nss_crypto_cmn.c b/nss_crypto_cmn.c
index 9a31e0f..3d2f2c8 100644
--- a/nss_crypto_cmn.c
+++ b/nss_crypto_cmn.c
@@ -251,7 +251,7 @@
 	 * Kick the NSS awake so it can process our new entry.
 	 */
 	nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
-	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CRYPTO_REQ]);
+	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_TX_CRYPTO_REQ]);
 
 	return NSS_TX_SUCCESS;
 }
diff --git a/nss_drv_stats.c b/nss_drv_stats.c
new file mode 100644
index 0000000..1f93f79
--- /dev/null
+++ b/nss_drv_stats.c
@@ -0,0 +1,196 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2013-2019, 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 "nss_core.h"
+#include "nss_drv_stats.h"
+
+/*
+ * nss_drv_stats_str
+ *	Host driver stats strings.
+ */
+static int8_t *nss_drv_stats_str[NSS_DRV_STATS_MAX] = {
+	"nbuf_alloc_errors",
+	"paged_buf_alloc_errors",
+	"tx_queue_full[0]",
+	"tx_queue_full[1]",
+	"tx_buffers_empty",
+	"tx_paged_buffers_empty",
+	"tx_buffers_pkt",
+	"tx_buffers_cmd",
+	"tx_buffers_crypto",
+	"tx_buffers_reuse",
+	"rx_buffers_empty",
+	"rx_buffers_pkt",
+	"rx_buffers_ext_pkt",
+	"rx_buffers_cmd_resp",
+	"rx_buffers_status_sync",
+	"rx_buffers_crypto",
+	"rx_buffers_virtual",
+	"tx_skb_simple",
+	"tx_skb_nr_frags",
+	"tx_skb_fraglist",
+	"rx_skb_simple",
+	"rx_skb_nr_frags",
+	"rx_skb_fraglist",
+	"rx_bad_desciptor",
+	"nss_skb_count",
+	"rx_chain_seg_processed",
+	"rx_frag_seg_processed",
+	"tx_buffers_cmd_queue_full",
+#ifdef NSS_MULTI_H2N_DATA_RING_SUPPORT
+	"tx_buffers_data_queue_0",
+	"tx_buffers_data_queue_1",
+	"tx_buffers_data_queue_2",
+	"tx_buffers_data_queue_3",
+	"tx_buffers_data_queue_4",
+	"tx_buffers_data_queue_5",
+	"tx_buffers_data_queue_6",
+	"tx_buffers_data_queue_7",
+#endif
+};
+
+/*
+ * nss_drv_stats_read()
+ *	Read HLOS driver stats.
+ */
+ssize_t nss_drv_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
+{
+	int32_t i;
+
+	/*
+	 * max output lines = #stats + start tag line + end tag line + three blank lines.
+	 */
+	uint32_t max_output_lines = NSS_DRV_STATS_MAX + 5;
+	size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
+	size_t size_wr = 0;
+	ssize_t bytes_read = 0;
+	uint64_t *stats_shadow;
+
+	char *lbuf = kzalloc(size_al, GFP_KERNEL);
+	if (unlikely(lbuf == NULL)) {
+		nss_warning("Could not allocate memory for local statistics buffer");
+		return 0;
+	}
+
+	stats_shadow = kzalloc(NSS_DRV_STATS_MAX * 8, GFP_KERNEL);
+	if (unlikely(stats_shadow == NULL)) {
+		nss_warning("Could not allocate memory for local shadow buffer");
+		kfree(lbuf);
+		return 0;
+	}
+
+	size_wr = scnprintf(lbuf, size_al, "drv stats start:\n\n");
+	for (i = 0; (i < NSS_DRV_STATS_MAX); i++) {
+		stats_shadow[i] = NSS_PKT_STATS_READ(&nss_top_main.stats_drv[i]);
+	}
+
+	for (i = 0; (i < NSS_DRV_STATS_MAX); i++) {
+		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
+					"%s = %llu\n", nss_drv_stats_str[i], stats_shadow[i]);
+	}
+
+	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\ndrv stats end\n\n");
+	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
+	kfree(lbuf);
+	kfree(stats_shadow);
+
+	return bytes_read;
+}
+
+/*
+ * nss_wt_stats_read()
+ *           Reads and formats worker thread statistics and outputs them to ubuf.
+ *
+ * TODO: Move function to nss_wt_stats.c file.
+ */
+ssize_t nss_wt_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
+{
+	struct nss_stats_data *data = fp->private_data;
+	struct nss_ctx_instance *nss_ctx = data->nss_ctx;
+	struct nss_project_irq_stats *shadow;
+	uint32_t thread_count = nss_ctx->worker_thread_count;
+	uint32_t irq_count = nss_ctx->irq_count;
+
+	/*
+	 * Three lines for each IRQ
+	 */
+	uint32_t max_output_lines = thread_count * 3 * irq_count;
+	size_t size_al = max_output_lines * NSS_STATS_MAX_STR_LENGTH;
+	size_t size_wr = 0;
+	ssize_t bytes_read = 0;
+	char *lbuf;
+	int i;
+	int j;
+
+	lbuf = kzalloc(size_al, GFP_KERNEL);
+	if (unlikely(!lbuf)) {
+		nss_warning("Could not allocate memory for local statistics buffer\n");
+		return 0;
+	}
+
+	shadow = kzalloc(thread_count * irq_count * sizeof(struct nss_project_irq_stats), GFP_KERNEL);
+	if (unlikely(!shadow)) {
+		nss_warning("Could not allocate memory for stats shadow\n");
+		kfree(lbuf);
+		return 0;
+	}
+
+	spin_lock_bh(&nss_top_main.stats_lock);
+	if (unlikely(!nss_ctx->wt_stats)) {
+		spin_unlock_bh(&nss_top_main.stats_lock);
+		nss_warning("Worker thread statistics not allocated\n");
+		kfree(lbuf);
+		kfree(shadow);
+		return 0;
+	}
+	for (i = 0; i < thread_count; ++i) {
+
+		/*
+		 * The statistics shadow is an array with thread_count * irq_count
+		 * items in it. Each item is located at the index:
+		 *      (thread number) * (irq_count) + (irq number)
+		 * thus simulating a two-dimensional array.
+		 */
+		for (j = 0; j < irq_count; ++j) {
+			shadow[i * irq_count + j] = nss_ctx->wt_stats[i].irq_stats[j];
+		}
+	}
+	spin_unlock_bh(&nss_top_main.stats_lock);
+
+	for (i = 0; i < thread_count; ++i) {
+		for (j = 0; j < irq_count; ++j) {
+			struct nss_project_irq_stats *is = &(shadow[i * irq_count + j]);
+			if (!(is->count)) {
+				continue;
+			}
+
+			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
+				"t-%d:irq-%d callback: 0x%x, count: %llu\n",
+				i, j, is->callback, is->count);
+			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
+				"t-%d:irq-%d tick min: %10u  avg: %10u  max:%10u\n",
+				i, j, is->ticks_min, is->ticks_avg, is->ticks_max);
+			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
+				"t-%d:irq-%d insn min: %10u  avg: %10u  max:%10u\n\n",
+				i, j, is->insn_min, is->insn_avg, is->insn_max);
+		}
+	}
+	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
+	kfree(lbuf);
+	kfree(shadow);
+
+	return bytes_read;
+}
diff --git a/nss_drv_stats.h b/nss_drv_stats.h
new file mode 100644
index 0000000..06dce55
--- /dev/null
+++ b/nss_drv_stats.h
@@ -0,0 +1,77 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2016-2017, 2019 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.
+ **************************************************************************
+ */
+
+/*
+ * nss_drv_stats.h
+ *	NSS driver stats header file.
+ */
+
+#ifndef __NSS_DRV_STATS_H
+#define __NSS_DRV_STATS_H
+
+#include <linux/debugfs.h>
+
+/*
+ * HLOS driver statistics
+ *
+ * WARNING: There is a 1:1 mapping between values below and corresponding
+ *	stats string array in nss_stats.c.
+ */
+enum NSS_DRV_STATS {
+	NSS_DRV_STATS_NBUF_ALLOC_FAILS = 0,	/* NBUF allocation errors */
+	NSS_DRV_STATS_PAGED_BUF_ALLOC_FAILS,	/* Paged buf allocation errors */
+	NSS_DRV_STATS_TX_QUEUE_FULL_0,		/* Tx queue full for Core 0*/
+	NSS_DRV_STATS_TX_QUEUE_FULL_1,		/* Tx queue full for Core 1*/
+	NSS_DRV_STATS_TX_EMPTY,			/* H2N Empty buffers */
+	NSS_DRV_STATS_PAGED_TX_EMPTY,		/* H2N Paged Empty buffers */
+	NSS_DRV_STATS_TX_PACKET,		/* H2N Data packets */
+	NSS_DRV_STATS_TX_CMD_REQ,		/* H2N Control packets */
+	NSS_DRV_STATS_TX_CRYPTO_REQ,		/* H2N Crypto requests */
+	NSS_DRV_STATS_TX_BUFFER_REUSE,		/* H2N Reuse buffer count */
+	NSS_DRV_STATS_RX_EMPTY,			/* N2H Empty buffers */
+	NSS_DRV_STATS_RX_PACKET,		/* N2H Data packets */
+	NSS_DRV_STATS_RX_EXT_PACKET,		/* N2H EXT type packets */
+	NSS_DRV_STATS_RX_CMD_RESP,		/* N2H Command responses */
+	NSS_DRV_STATS_RX_STATUS,		/* N2H Status packets */
+	NSS_DRV_STATS_RX_CRYPTO_RESP,		/* N2H Crypto responses */
+	NSS_DRV_STATS_RX_VIRTUAL,		/* N2H Virtual packets */
+	NSS_DRV_STATS_TX_SIMPLE,		/* H2N Simple SKB Packets */
+	NSS_DRV_STATS_TX_NR_FRAGS,		/* H2N NR Frags SKB Packets */
+	NSS_DRV_STATS_TX_FRAGLIST,		/* H2N Fraglist SKB Packets */
+	NSS_DRV_STATS_RX_SIMPLE,		/* N2H Simple SKB Packets */
+	NSS_DRV_STATS_RX_NR_FRAGS,		/* N2H NR Frags SKB Packets */
+	NSS_DRV_STATS_RX_SKB_FRAGLIST,		/* N2H Fraglist SKB Packets */
+	NSS_DRV_STATS_RX_BAD_DESCRIPTOR,	/* N2H Bad descriptor reads */
+	NSS_DRV_STATS_NSS_SKB_COUNT,		/* NSS SKB Pool Count */
+	NSS_DRV_STATS_CHAIN_SEG_PROCESSED,	/* N2H SKB Chain Processed Count */
+	NSS_DRV_STATS_FRAG_SEG_PROCESSED,	/* N2H Frag Processed Count */
+	NSS_DRV_STATS_TX_CMD_QUEUE_FULL,	/* Tx H2N Control packets fail due to queue full */
+#ifdef NSS_MULTI_H2N_DATA_RING_SUPPORT
+	NSS_DRV_STATS_TX_PACKET_QUEUE_0,	/* H2N Data packets on queue0 */
+	NSS_DRV_STATS_TX_PACKET_QUEUE_1,	/* H2N Data packets on queue1 */
+	NSS_DRV_STATS_TX_PACKET_QUEUE_2,	/* H2N Data packets on queue2 */
+	NSS_DRV_STATS_TX_PACKET_QUEUE_3,	/* H2N Data packets on queue3 */
+	NSS_DRV_STATS_TX_PACKET_QUEUE_4,	/* H2N Data packets on queue4 */
+	NSS_DRV_STATS_TX_PACKET_QUEUE_5,	/* H2N Data packets on queue5 */
+	NSS_DRV_STATS_TX_PACKET_QUEUE_6,	/* H2N Data packets on queue6 */
+	NSS_DRV_STATS_TX_PACKET_QUEUE_7,	/* H2N Data packets on queue7 */
+#endif
+	NSS_DRV_STATS_MAX,
+};
+
+extern ssize_t nss_drv_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos);
+extern ssize_t nss_wt_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos);
+#endif /* __NSS_DRV_STATS_H */
diff --git a/nss_dtls_cmn.c b/nss_dtls_cmn.c
index c0d76b6..b382f9d 100644
--- a/nss_dtls_cmn.c
+++ b/nss_dtls_cmn.c
@@ -22,7 +22,7 @@
 #define NSS_DTLS_CMN_STATS_MAX_LINES (NSS_STATS_NODE_MAX + 32)
 #define NSS_DTLS_CMN_STATS_SIZE_PER_IF (NSS_STATS_MAX_STR_LENGTH * NSS_DTLS_CMN_STATS_MAX_LINES)
 /*
- * Private data structure
+ * Private data structure.
  */
 static struct nss_dtls_cmn_cmn_pvt {
 	struct semaphore sem;
@@ -46,7 +46,7 @@
 
 	/*
 	 * Update common node stats,
-	 * Note: DTLS only supports a single queue for RX
+	 * Note: DTLS only supports a single queue for RX.
 	 */
 	if_stats = nss_top->stats_node[ncm->interface];
 	if_stats[NSS_STATS_NODE_RX_PKTS] += msg_stats->pkt.rx_packets;
@@ -102,7 +102,7 @@
 		}
 
 		len += scnprintf(buf + len, size - len, "\n-------------------\n");
-		len = nss_stats_fill_common_stats(if_num, buf, len, size - len);
+		len = nss_stats_fill_common_stats(if_num, buf, len, size - len, "dtls_cmn");
 	}
 
 	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, buf, len);
@@ -112,7 +112,7 @@
 }
 
 /*
- * nss_dtls_cmn_stats_ops
+ * nss_dtls_cmn_stats_ops.
  */
 NSS_STATS_DECLARE_FILE_OPERATIONS(dtls_cmn)
 
@@ -138,7 +138,7 @@
 
 /*
  * nss_dtls_cmn_handler()
- *	Handle NSS -> HLOS messages for dtls tunnel
+ *	Handle NSS -> HLOS messages for dtls tunnel.
  */
 static void nss_dtls_cmn_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, void *data)
 {
@@ -166,7 +166,7 @@
 		nss_dtls_cmn_stats_sync(nss_ctx, ncm);
 
 	/*
-	 * Update the callback and app_data for NOTIFY messages
+	 * Update the callback and app_data for NOTIFY messages.
 	 */
 	if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) {
 		ncm->cb = (nss_ptr_t)nss_top_main.if_rx_msg_callback[ncm->interface];
@@ -174,7 +174,7 @@
 	}
 
 	/*
-	 * Log failures
+	 * Log failures.
 	 */
 	nss_core_log_msg_failures(nss_ctx, ncm);
 
@@ -184,13 +184,13 @@
 	nss_dtls_cmn_log_rx_msg((struct nss_dtls_cmn_msg *)ncm);
 
 	/*
-	 * Callback
+	 * Callback.
 	 */
 	cb = (nss_dtls_cmn_msg_callback_t)ncm->cb;
 	app_data = (void *)ncm->app_data;
 
 	/*
-	 * Call DTLS session callback
+	 * Call DTLS session callback.
 	 */
 	if (!cb) {
 		nss_warning("%p: No callback for dtls session interface %d", nss_ctx, ncm->interface);
@@ -210,7 +210,7 @@
 	/*
 	 * This callback is for synchronous operation. The caller sends its
 	 * response pointer which needs to be loaded with the response
-	 * data arriving from the NSS
+	 * data arriving from the NSS.
 	 */
 	enum nss_dtls_cmn_error *resp = (enum nss_dtls_cmn_error *)app_data;
 
@@ -222,7 +222,7 @@
 
 /*
  * nss_dtls_cmn_tx_buf()
- *	Transmit buffer over DTLS interface
+ *	Transmit buffer over DTLS interface.
  */
 nss_tx_status_t nss_dtls_cmn_tx_buf(struct sk_buff *skb, uint32_t if_num, struct nss_ctx_instance *nss_ctx)
 {
@@ -235,7 +235,7 @@
 
 /*
  * nss_dtls_cmn_tx_msg()
- *	Transmit a DTLS message to NSS firmware
+ *	Transmit a DTLS message to NSS firmware.
  */
 nss_tx_status_t nss_dtls_cmn_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_dtls_cmn_msg *msg)
 {
@@ -273,7 +273,7 @@
 	int ret;
 
 	/*
-	 * Length of the message should be the based on type
+	 * Length of the message should be the based on type.
 	 */
 	if (len > sizeof(ndcm_local.msg)) {
 		nss_warning("%p: (%u)Bad message length(%u) for type (%d)", nss_ctx, if_num, len, type);
@@ -281,7 +281,7 @@
 	}
 
 	/*
-	 * Response buffer is a required for copying the response for message
+	 * Response buffer is a required for copying the response for message.
 	 */
 	if (!resp) {
 		nss_warning("%p: (%u)Response buffer is empty, type(%d)", nss_ctx, if_num, type);
@@ -293,13 +293,13 @@
 	 * memory is only updated when the current outstanding request is waiting.
 	 * This can be solved by introducing sequence no. in messages and only completing
 	 * the message if the sequence no. matches. For now this is solved by passing
-	 * a known memory dtls_cmn_pvt.resp
+	 * a known memory dtls_cmn_pvt.resp.
 	 */
 	down(&dtls_cmn_pvt.sem);
 
 	/*
 	 * We need to copy the message content into the actual message
-	 * to be sent to NSS
+	 * to be sent to NSS.
 	 */
 	nss_dtls_cmn_msg_init(&ndcm_local, if_num, type, len, nss_dtls_cmn_callback, &dtls_cmn_pvt.resp);
 	memcpy(&ndcm_local.msg, &ndcm->msg, len);
@@ -318,18 +318,18 @@
 	}
 
 	/*
-	 * Read memory barrier
+	 * Read memory barrier.
 	 */
 	smp_rmb();
 
 	/*
-	 * Copy the response received
+	 * Copy the response received.
 	 */
 	*resp = dtls_cmn_pvt.resp;
 
 	/*
 	 * Only in case of non-error response we will
-	 * indicate success
+	 * indicate success.
 	 */
 	if (dtls_cmn_pvt.resp != NSS_DTLS_CMN_ERROR_NONE)
 		status = NSS_TX_FAILURE;
@@ -424,7 +424,7 @@
 	nss_top_main.if_rx_msg_callback[if_num] = ev_cb;
 
 	/*
-	 * Atomically set the bitmap for the interface number
+	 * Atomically set the bitmap for the interface number.
 	 */
 	set_bit(if_num, dtls_cmn_pvt.if_map);
 	return nss_ctx;
@@ -445,7 +445,7 @@
 	}
 
 	/*
-	 * Atomically clear the bitmap for the interface number
+	 * Atomically clear the bitmap for the interface number.
 	 */
 	clear_bit(if_num, dtls_cmn_pvt.if_map);
 
diff --git a/nss_dtls_stats.c b/nss_dtls_stats.c
index 13b9aae..5a00b80 100644
--- a/nss_dtls_stats.c
+++ b/nss_dtls_stats.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017, 2019 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.
@@ -14,13 +14,12 @@
  **************************************************************************
  */
 
-#include "nss_stats.h"
 #include "nss_core.h"
 #include "nss_dtls_stats.h"
 
 /*
  * nss_dtls_stats_session_str
- *	DTLS statistics strings for nss session stats
+ *	DTLS statistics strings for nss session stats.
  */
 static int8_t *nss_dtls_stats_session_str[NSS_DTLS_STATS_SESSION_MAX] = {
 	"RX_PKTS",
@@ -63,7 +62,7 @@
 
 /*
  * nss_dtls_stats_read()
- * 	Read DTLS session statistics
+ * 	Read DTLS session statistics.
  */
 static ssize_t nss_dtls_stats_read(struct file *fp, char __user *ubuf,
 				   size_t sz, loff_t *ppos)
@@ -92,12 +91,12 @@
 	}
 
 	/*
-	 * Get all stats
+	 * Get all stats.
 	 */
 	nss_dtls_session_stats_get(dtls_session_stats);
 
 	/*
-	 * Session stats
+	 * Session stats.
 	 */
 	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
 			     "\nDTLS session stats start:\n\n");
@@ -139,7 +138,7 @@
 }
 
 /*
- * nss_dtls_stats_ops
+ * nss_dtls_stats_ops.
  */
 NSS_STATS_DECLARE_FILE_OPERATIONS(dtls)
 
diff --git a/nss_edma_stats.c b/nss_edma_stats.c
index 2d6c57d..659222f 100644
--- a/nss_edma_stats.c
+++ b/nss_edma_stats.c
@@ -19,7 +19,6 @@
  *	NSS EDMA statistics APIs
  */
 
-#include "nss_stats.h"
 #include "nss_tx_rx_common.h"
 #include "nss_edma_stats.h"
 
diff --git a/nss_eth_rx_stats.c b/nss_eth_rx_stats.c
index 617e846..b61ee35 100644
--- a/nss_eth_rx_stats.c
+++ b/nss_eth_rx_stats.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017, 2019 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.
@@ -14,13 +14,12 @@
  **************************************************************************
  */
 
-#include "nss_stats.h"
 #include "nss_core.h"
 #include "nss_eth_rx_stats.h"
 
 /*
  * nss_eth_rx_stats_str
- *	eth_rx stats strings
+ *	eth_rx stats strings.
  */
 static int8_t *nss_eth_rx_stats_str[NSS_ETH_RX_STATS_MAX] = {
 	"ticks",
@@ -30,7 +29,7 @@
 
 /*
  * nss_eth_rx_exception_stats_str
- *	Interface stats strings for unknown exceptions
+ *	Interface stats strings for unknown exceptions.
  */
 static int8_t *nss_eth_rx_exception_stats_str[NSS_ETH_RX_EXCEPTION_EVENT_MAX] = {
 	"UNKNOWN_L3_PROTOCOL",
@@ -44,14 +43,14 @@
 
 /*
  * nss_eth_rx_stats_read()
- *	Read ETH_RX stats
+ *	Read ETH_RX stats.
  */
 static ssize_t nss_eth_rx_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
 {
 	int32_t i;
 
 	/*
-	 * max output lines = #stats + start tag line + end tag line + three blank lines
+	 * max output lines = #stats + start tag line + end tag line + three blank lines.
 	 */
 	uint32_t max_output_lines = (NSS_STATS_NODE_MAX + 2) + (NSS_ETH_RX_STATS_MAX + 3) + (NSS_ETH_RX_EXCEPTION_EVENT_MAX + 3) + 5;
 	size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
@@ -66,7 +65,7 @@
 	}
 
 	/*
-	 * Note: The assumption here is that we do not have more than 64 stats
+	 * Note: The assumption here is that we do not have more than 64 stats.
 	 */
 	stats_shadow = kzalloc(64 * 8, GFP_KERNEL);
 	if (unlikely(stats_shadow == NULL)) {
@@ -77,10 +76,10 @@
 
 	size_wr = scnprintf(lbuf, size_al, "eth_rx stats start:\n\n");
 
-	size_wr = nss_stats_fill_common_stats(NSS_ETH_RX_INTERFACE, lbuf, size_wr, size_al);
+	size_wr = nss_stats_fill_common_stats(NSS_ETH_RX_INTERFACE, lbuf, size_wr, size_al, "eth_rx");
 
 	/*
-	 * eth_rx node stats
+	 * eth_rx node stats.
 	 */
 	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\neth_rx node stats:\n\n");
 	spin_lock_bh(&nss_top_main.stats_lock);
@@ -96,7 +95,7 @@
 	}
 
 	/*
-	 * Exception stats
+	 * Exception stats.
 	 */
 	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\neth_rx exception stats:\n\n");
 
@@ -121,7 +120,7 @@
 }
 
 /*
- * nss_eth_rx_stats_ops
+ * nss_eth_rx_stats_ops.
  */
 NSS_STATS_DECLARE_FILE_OPERATIONS(eth_rx)
 
diff --git a/nss_gmac_stats.c b/nss_gmac_stats.c
new file mode 100644
index 0000000..59982cf
--- /dev/null
+++ b/nss_gmac_stats.c
@@ -0,0 +1,84 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2016-2017, 2019, 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 "nss_core.h"
+#include "nss_gmac_stats.h"
+
+/*
+ * nss_gmac_stats_str
+ *	GMAC stats strings.
+ */
+static int8_t *nss_gmac_stats_str[NSS_GMAC_STATS_MAX] = {
+	"ticks",
+	"worst_ticks",
+	"iterations"
+};
+
+/*
+ * nss_gmac_stats_read()
+ *	Read GMAC stats.
+ */
+ssize_t nss_gmac_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
+{
+	uint32_t i, id;
+
+	/*
+	 * max output lines = ((#stats + start tag + one blank) * #GMACs) + start/end tag + 3 blank.
+	 */
+	uint32_t max_output_lines = ((NSS_GMAC_STATS_MAX + 2) * NSS_MAX_PHYSICAL_INTERFACES) + 5;
+	size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
+	size_t size_wr = 0;
+	ssize_t bytes_read = 0;
+	uint64_t *stats_shadow;
+
+	char *lbuf = kzalloc(size_al, GFP_KERNEL);
+	if (unlikely(lbuf == NULL)) {
+		nss_warning("Could not allocate memory for local statistics buffer");
+		return 0;
+	}
+
+	stats_shadow = kzalloc(NSS_GMAC_STATS_MAX * 8, GFP_KERNEL);
+	if (unlikely(stats_shadow == NULL)) {
+		nss_warning("Could not allocate memory for local shadow buffer");
+		kfree(lbuf);
+		return 0;
+	}
+
+	size_wr = scnprintf(lbuf, size_al, "gmac stats start:\n\n");
+
+	for (id = 0; id < NSS_MAX_PHYSICAL_INTERFACES; id++) {
+		spin_lock_bh(&nss_top_main.stats_lock);
+		for (i = 0; (i < NSS_GMAC_STATS_MAX); i++) {
+			stats_shadow[i] = nss_top_main.stats_gmac[id][i];
+		}
+
+		spin_unlock_bh(&nss_top_main.stats_lock);
+
+		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "GMAC ID: %d\n", id);
+		for (i = 0; (i < NSS_GMAC_STATS_MAX); i++) {
+			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
+					"%s = %llu\n", nss_gmac_stats_str[i], stats_shadow[i]);
+		}
+		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n");
+	}
+
+	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\ngmac stats end\n\n");
+	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
+	kfree(lbuf);
+	kfree(stats_shadow);
+
+	return bytes_read;
+}
diff --git a/nss_gmac_stats.h b/nss_gmac_stats.h
new file mode 100644
index 0000000..21795db
--- /dev/null
+++ b/nss_gmac_stats.h
@@ -0,0 +1,33 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2016-2017, 2019 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.
+ **************************************************************************
+ */
+
+#ifndef __NSS_GMAC_STATS_H
+#define __NSS_GMAC_STATS_H
+
+#include <linux/debugfs.h>
+
+/*
+ * GMAC node statistics
+ */
+enum nss_stats_gmac {
+	NSS_GMAC_STATS_TOTAL_TICKS,		/* Total clock ticks spend inside the GMAC */
+	NSS_GMAC_STATS_WORST_CASE_TICKS,	/* Worst case iteration of the GMAC in ticks */
+	NSS_GMAC_STATS_ITERATIONS,		/* Number of iterations around the GMAC */
+	NSS_GMAC_STATS_MAX,
+};
+
+extern ssize_t nss_gmac_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos);
+#endif /* __NSS_GMAC_STATS_H */
diff --git a/nss_gre_redir_lag_ds_stats.c b/nss_gre_redir_lag_ds_stats.c
index 6e04b9c..edba015 100644
--- a/nss_gre_redir_lag_ds_stats.c
+++ b/nss_gre_redir_lag_ds_stats.c
@@ -15,7 +15,6 @@
  */
 
 #include "nss_core.h"
-#include "nss_stats.h"
 #include "nss_gre_redir_lag.h"
 #include "nss_gre_redir_lag_ds_stats.h"
 
diff --git a/nss_gre_redir_lag_us_stats.c b/nss_gre_redir_lag_us_stats.c
index 4408849..68ef37b 100644
--- a/nss_gre_redir_lag_us_stats.c
+++ b/nss_gre_redir_lag_us_stats.c
@@ -15,7 +15,6 @@
  */
 
 #include "nss_core.h"
-#include "nss_stats.h"
 #include "nss_gre_redir_lag.h"
 #include "nss_gre_redir_lag_us_stats.h"
 
diff --git a/nss_gre_redir_stats.c b/nss_gre_redir_stats.c
index 3dd7e6b..4b83cee 100644
--- a/nss_gre_redir_stats.c
+++ b/nss_gre_redir_stats.c
@@ -15,7 +15,6 @@
  */
 
 #include "nss_core.h"
-#include "nss_stats.h"
 #include "nss_gre_redir.h"
 #include "nss_gre_redir_stats.h"
 
diff --git a/nss_gre_stats.c b/nss_gre_stats.c
index e5226be..82c90a4 100644
--- a/nss_gre_stats.c
+++ b/nss_gre_stats.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019, 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.
@@ -21,7 +21,6 @@
  */
 
 #include "nss_tx_rx_common.h"
-#include "nss_stats.h"
 #include "nss_gre_stats.h"
 
 /*
diff --git a/nss_igs_stats.c b/nss_igs_stats.c
index 4e76582..867a31d 100644
--- a/nss_igs_stats.c
+++ b/nss_igs_stats.c
@@ -183,7 +183,7 @@
 						igs_shadow_stats[id].if_num);
 			}
 
-			size_wr = nss_stats_fill_common_stats(igs_shadow_stats[id].if_num, lbuf, size_wr, size_al);
+			size_wr = nss_stats_fill_common_stats(igs_shadow_stats[id].if_num, lbuf, size_wr, size_al, "igs");
 
 			/*
 			 * IGS exception stats.
diff --git a/nss_init.c b/nss_init.c
index 39f4652..af109c3 100644
--- a/nss_init.c
+++ b/nss_init.c
@@ -747,6 +747,11 @@
 	nss_c2c_tx_register_sysctl();
 
 	/*
+	 * Registering sysctl for for printing non zero stats.
+	 */
+	nss_stats_register_sysctl();
+
+	/*
 	 * Register sysctl for project config
 	 */
 	nss_project_register_sysctl();
diff --git a/nss_ipsec_cmn.c b/nss_ipsec_cmn.c
index 8baa37d..9607901 100644
--- a/nss_ipsec_cmn.c
+++ b/nss_ipsec_cmn.c
@@ -117,7 +117,7 @@
 		}
 
 		len += scnprintf(buf + len, size - len, "\n-------------------\n");
-		len = nss_stats_fill_common_stats(if_num, buf, len, size - len);
+		len = nss_stats_fill_common_stats(if_num, buf, len, size - len, "ipsec_cmn");
 	}
 
 	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, buf, len);
diff --git a/nss_ipv4_reasm.c b/nss_ipv4_reasm.c
index 6837544..cc0069e 100644
--- a/nss_ipv4_reasm.c
+++ b/nss_ipv4_reasm.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2014, 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, 2017, 2019 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.
@@ -19,7 +19,6 @@
  *	NSS IPv4 Reassembly APIs
  */
 #include "nss_tx_rx_common.h"
-#include "nss_stats.h"
 #include "nss_ipv4_reasm_stats.h"
 
 /*
diff --git a/nss_ipv4_reasm_stats.c b/nss_ipv4_reasm_stats.c
index 7d2791f..b55247f 100644
--- a/nss_ipv4_reasm_stats.c
+++ b/nss_ipv4_reasm_stats.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017, 2019 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.
@@ -14,7 +14,6 @@
  **************************************************************************
  */
 
-#include "nss_stats.h"
 #include "nss_core.h"
 #include "nss_ipv4_reasm_stats.h"
 
@@ -60,7 +59,7 @@
 
 	size_wr = scnprintf(lbuf, size_al, "ipv4 reasm stats start:\n\n");
 
-	size_wr = nss_stats_fill_common_stats(NSS_IPV4_REASM_INTERFACE, lbuf, size_wr, size_al);
+	size_wr = nss_stats_fill_common_stats(NSS_IPV4_REASM_INTERFACE, lbuf, size_wr, size_al, "ipv4_reasm");
 
 	/*
 	 * IPv4 reasm node stats
diff --git a/nss_ipv4_stats.c b/nss_ipv4_stats.c
index b3a7f69..3ebaa9b 100644
--- a/nss_ipv4_stats.c
+++ b/nss_ipv4_stats.c
@@ -14,7 +14,6 @@
  **************************************************************************
  */
 
-#include "nss_stats.h"
 #include "nss_core.h"
 #include <nss_ipv4.h>
 #include "nss_ipv4_stats.h"
@@ -23,88 +22,87 @@
  * nss_ipv4_exception_stats_str
  *	Interface stats strings for ipv4 exceptions
  */
-static int8_t *nss_ipv4_exception_stats_str[NSS_IPV4_EXCEPTION_EVENT_MAX] = {
-	"IPV4_ICMP_HEADER_INCOMPLETE",
-	"IPV4_ICMP_UNHANDLED_TYPE",
-	"IPV4_ICMP_IPV4_HEADER_INCOMPLETE",
-	"IPV4_ICMP_IPV4_UDP_HEADER_INCOMPLETE",
-	"IPV4_ICMP_IPV4_TCP_HEADER_INCOMPLETE",
-	"IPV4_ICMP_SIPV4_UNKNOWN_PROTOCOL",
-	"IPV4_ICMP_NO_ICME",
-	"IPV4_ICMP_FLUSH_TO_HOST",
-	"IPV4_TCP_HEADER_INCOMPLETE",
-	"IPV4_TCP_NO_ICME",
-	"IPV4_TCP_IP_OPTION",
-	"IPV4_TCP_IP_FRAGMENT",
-	"IPV4_TCP_SMALL_TTL",
-	"IPV4_TCP_NEEDS_FRAGMENTATION",
-	"IPV4_TCP_FLAGS",
-	"IPV4_TCP_SEQ_EXCEEDS_RIGHT_EDGE",
-	"IPV4_TCP_SMALL_DATA_OFFS",
-	"IPV4_TCP_BAD_SACK",
-	"IPV4_TCP_BIG_DATA_OFFS",
-	"IPV4_TCP_SEQ_BEFORE_LEFT_EDGE",
-	"IPV4_TCP_ACK_EXCEEDS_RIGHT_EDGE",
-	"IPV4_TCP_ACK_BEFORE_LEFT_EDGE",
-	"IPV4_UDP_HEADER_INCOMPLETE",
-	"IPV4_UDP_NO_ICME",
-	"IPV4_UDP_IP_OPTION",
-	"IPV4_UDP_IP_FRAGMENT",
-	"IPV4_UDP_SMALL_TTL",
-	"IPV4_UDP_NEEDS_FRAGMENTATION",
-	"IPV4_WRONG_TARGET_MAC",
-	"IPV4_HEADER_INCOMPLETE",
-	"IPV4_BAD_TOTAL_LENGTH",
-	"IPV4_BAD_CHECKSUM",
-	"IPV4_NON_INITIAL_FRAGMENT",
-	"IPV4_DATAGRAM_INCOMPLETE",
-	"IPV4_OPTIONS_INCOMPLETE",
-	"IPV4_UNKNOWN_PROTOCOL",
-	"IPV4_ESP_HEADER_INCOMPLETE",
-	"IPV4_ESP_NO_ICME",
-	"IPV4_ESP_IP_OPTION",
-	"IPV4_ESP_IP_FRAGMENT",
-	"IPV4_ESP_SMALL_TTL",
-	"IPV4_ESP_NEEDS_FRAGMENTATION",
-	"IPV4_INGRESS_VID_MISMATCH",
-	"IPV4_INGRESS_VID_MISSING",
-	"IPV4_6RD_NO_ICME",
-	"IPV4_6RD_IP_OPTION",
-	"IPV4_6RD_IP_FRAGMENT",
-	"IPV4_6RD_NEEDS_FRAGMENTATION",
-	"IPV4_DSCP_MARKING_MISMATCH",
-	"IPV4_VLAN_MARKING_MISMATCH",
-	"IPV4_INTERFACE_MISMATCH",
-	"IPV4_GRE_HEADER_INCOMPLETE",
-	"IPV4_GRE_NO_ICME",
-	"IPV4_GRE_IP_OPTION",
-	"IPV4_GRE_IP_FRAGMENT",
-	"IPV4_GRE_SMALL_TTL",
-	"IPV4_GRE_NEEDS_FRAGMENTATION",
-	"IPV4_PPTP_GRE_SESSION_MATCH_FAIL",
-	"IPV4_PPTP_GRE_INVALID_PROTO",
-	"IPV4_PPTP_GRE_NO_CME",
-	"IPV4_PPTP_GRE_IP_OPTION",
-	"IPV4_PPTP_GRE_IP_FRAGMENT",
-	"IPV4_PPTP_GRE_SMALL_TTL",
-	"IPV4_PPTP_GRE_NEEDS_FRAGMENTATION",
-	"IPV4_DESTROY",
-	"IPV4_FRAG_DF_SET",
-	"IPV4_FRAG_FAIL",
-	"IPV4_ICMP_IPV4_UDPLITE_HEADER_INCOMPLETE",
-	"IPV4_UDPLITE_HEADER_INCOMPLETE",
-	"IPV4_UDPLITE_NO_ICME",
-	"IPV4_UDPLITE_IP_OPTION",
-	"IPV4_UDPLITE_IP_FRAGMENT",
-	"IPV4_UDPLITE_SMALL_TTL",
-	"IPV4_UDPLITE_NEEDS_FRAGMENTATION",
-	"IPV4_MC_UDP_NO_ICME",
-	"IPV4_MC_MEM_ALLOC_FAILURE",
-	"IPV4_MC_UPDATE_FAILURE",
-	"IPV4_MC_PBUF_ALLOC_FAILURE",
-	"IPV4_PPPOE_BRIDGE_NO_ICME"
+struct nss_stats_info nss_ipv4_exception_stats_str[NSS_IPV4_EXCEPTION_EVENT_MAX] = {
+	{"icmp_hdr_incomplete"			, NSS_STATS_TYPE_EXCEPTION},
+	{"icmp_unhandled_type"			, NSS_STATS_TYPE_EXCEPTION},
+	{"icmp_ipv4_hdr_incomplete"		, NSS_STATS_TYPE_EXCEPTION},
+	{"icmp_ipv4_udp_hdr_incomplete"		, NSS_STATS_TYPE_EXCEPTION},
+	{"tcp_header_incomplete"		, NSS_STATS_TYPE_EXCEPTION},
+	{"icmp_sipv4_unknown_protocol"		, NSS_STATS_TYPE_EXCEPTION},
+	{"icmp_no_icme"				, NSS_STATS_TYPE_EXCEPTION},
+	{"icmp_flush_to_host"			, NSS_STATS_TYPE_EXCEPTION},
+	{"tcp_header_incomplete"		, NSS_STATS_TYPE_EXCEPTION},
+	{"tcp_no_icme"				, NSS_STATS_TYPE_EXCEPTION},
+	{"tcp_ip_option"			, NSS_STATS_TYPE_EXCEPTION},
+	{"tcp_ip_fragment"			, NSS_STATS_TYPE_EXCEPTION},
+	{"tcp_small_ttl"			, NSS_STATS_TYPE_EXCEPTION},
+	{"tcp_needs_fragmentation"		, NSS_STATS_TYPE_EXCEPTION},
+	{"tcp_flags"				, NSS_STATS_TYPE_EXCEPTION},
+	{"tcp_seq_exceeds_right_edge"		, NSS_STATS_TYPE_EXCEPTION},
+	{"tcp_small_data_offs"			, NSS_STATS_TYPE_EXCEPTION},
+	{"tcp_bad_sack"				, NSS_STATS_TYPE_EXCEPTION},
+	{"tcp_big_data_offs"			, NSS_STATS_TYPE_EXCEPTION},
+	{"tcp_seq_before_left_edge"		, NSS_STATS_TYPE_EXCEPTION},
+	{"tcp_ack_exceeds_right_edge"		, NSS_STATS_TYPE_EXCEPTION},
+	{"tcp_ack_before_left_edge"		, NSS_STATS_TYPE_EXCEPTION},
+	{"udp_header_incomplete"		, NSS_STATS_TYPE_EXCEPTION},
+	{"udp_no_icme"				, NSS_STATS_TYPE_EXCEPTION},
+	{"udp_ip_option"			, NSS_STATS_TYPE_EXCEPTION},
+	{"udp_ip_fragment"			, NSS_STATS_TYPE_EXCEPTION},
+	{"udp_small_ttl"			, NSS_STATS_TYPE_EXCEPTION},
+	{"udp_needs_fragmentation"		, NSS_STATS_TYPE_EXCEPTION},
+	{"wrong_target_mac"			, NSS_STATS_TYPE_EXCEPTION},
+	{"header_incomplete"			, NSS_STATS_TYPE_EXCEPTION},
+	{"bad_total_length"			, NSS_STATS_TYPE_EXCEPTION},
+	{"bad_checksum"				, NSS_STATS_TYPE_EXCEPTION},
+	{"non_initial_fragment"			, NSS_STATS_TYPE_EXCEPTION},
+	{"datagram_incomplete"			, NSS_STATS_TYPE_EXCEPTION},
+	{"options_incomplete"			, NSS_STATS_TYPE_EXCEPTION},
+	{"unknown_protocol"			, NSS_STATS_TYPE_EXCEPTION},
+	{"esp_header_incomplete"		, NSS_STATS_TYPE_EXCEPTION},
+	{"esp_no_icme"				, NSS_STATS_TYPE_EXCEPTION},
+	{"esp_ip_option"			, NSS_STATS_TYPE_EXCEPTION},
+	{"esp_ip_fragment"			, NSS_STATS_TYPE_EXCEPTION},
+	{"esp_small_ttl"			, NSS_STATS_TYPE_EXCEPTION},
+	{"esp_needs_fragmentation"		, NSS_STATS_TYPE_EXCEPTION},
+	{"ingress_vid_mismatch"			, NSS_STATS_TYPE_EXCEPTION},
+	{"ingress_vid_missing"			, NSS_STATS_TYPE_EXCEPTION},
+	{"6rd_no_icme"				, NSS_STATS_TYPE_EXCEPTION},
+	{"6rd_ip_option"			, NSS_STATS_TYPE_EXCEPTION},
+	{"6rd_ip_fragment"			, NSS_STATS_TYPE_EXCEPTION},
+	{"6rd_needs_fragmentation"		, NSS_STATS_TYPE_EXCEPTION},
+	{"dscp_marking_mismatch"		, NSS_STATS_TYPE_EXCEPTION},
+	{"vlan_marking_mismatch"		, NSS_STATS_TYPE_EXCEPTION},
+	{"interface_mismatch"			, NSS_STATS_TYPE_EXCEPTION},
+	{"gre_header_incomplete"		, NSS_STATS_TYPE_EXCEPTION},
+	{"gre_no_icme"				, NSS_STATS_TYPE_EXCEPTION},
+	{"gre_ip_option"			, NSS_STATS_TYPE_EXCEPTION},
+	{"gre_ip_fragment"			, NSS_STATS_TYPE_EXCEPTION},
+	{"gre_small_ttl"			, NSS_STATS_TYPE_EXCEPTION},
+	{"gre_needs_fragmentation"		, NSS_STATS_TYPE_EXCEPTION},
+	{"pptp_gre_session_match_fail"		, NSS_STATS_TYPE_EXCEPTION},
+	{"pptp_gre_invalid_proto"		, NSS_STATS_TYPE_EXCEPTION},
+	{"pptp_gre_no_cme"			, NSS_STATS_TYPE_EXCEPTION},
+	{"pptp_gre_ip_option"			, NSS_STATS_TYPE_EXCEPTION},
+	{"pptp_gre_ip_fragment"			, NSS_STATS_TYPE_EXCEPTION},
+	{"pptp_gre_small_ttl"			, NSS_STATS_TYPE_EXCEPTION},
+	{"pptp_gre_needs_fragmentation"		, NSS_STATS_TYPE_EXCEPTION},
+	{"destroy"				, NSS_STATS_TYPE_EXCEPTION},
+	{"frag_df_set"				, NSS_STATS_TYPE_EXCEPTION},
+	{"frag_fail"				, NSS_STATS_TYPE_EXCEPTION},
+	{"icmp_ipv4_udplite_header_incomplete"	, NSS_STATS_TYPE_EXCEPTION},
+	{"udplite_header_incomplete"		, NSS_STATS_TYPE_EXCEPTION},
+	{"udplite_no_icme"			, NSS_STATS_TYPE_EXCEPTION},
+	{"udplite_ip_option"			, NSS_STATS_TYPE_EXCEPTION},
+	{"udplite_ip_fragment"			, NSS_STATS_TYPE_EXCEPTION},
+	{"udplite_small_ttl"			, NSS_STATS_TYPE_EXCEPTION},
+	{"udplite_needs_fragmentation"		, NSS_STATS_TYPE_EXCEPTION},
+	{"mc_udp_no_icme"			, NSS_STATS_TYPE_EXCEPTION},
+	{"mc_mem_alloc_failure"			, NSS_STATS_TYPE_EXCEPTION},
+	{"mc_update_failure"			, NSS_STATS_TYPE_EXCEPTION},
+	{"mc_pbuf_alloc_failure"		, NSS_STATS_TYPE_EXCEPTION},
+	{"pppoe_bridge_no_icme"			, NSS_STATS_TYPE_EXCEPTION}
 };
-
 uint64_t nss_ipv4_stats[NSS_IPV4_STATS_MAX];
 uint64_t nss_ipv4_exception_stats[NSS_IPV4_EXCEPTION_EVENT_MAX];
 
@@ -112,28 +110,28 @@
  * nss_ipv4_stats_str
  *	IPv4 stats strings
  */
-static int8_t *nss_ipv4_stats_str[NSS_IPV4_STATS_MAX] = {
-	"rx_pkts",
-	"rx_bytes",
-	"tx_pkts",
-	"tx_bytes",
-	"create_requests",
-	"create_collisions",
-	"create_invalid_interface",
-	"destroy_requests",
-	"destroy_misses",
-	"hash_hits",
-	"hash_reorders",
-	"flushes",
-	"evictions",
-	"fragmentations",
-	"by_rule_drops",
-	"mc_create_requests",
-	"mc_update_requests",
-	"mc_create_invalid_interface",
-	"mc_destroy_requests",
-	"mc_destroy_misses",
-	"mc_flushes"
+struct nss_stats_info nss_ipv4_stats_str[NSS_IPV4_STATS_MAX] = {
+	{"rx_pkts"			, NSS_STATS_TYPE_SPECIAL},
+	{"rx_bytes"			, NSS_STATS_TYPE_SPECIAL},
+	{"tx_pkts"			, NSS_STATS_TYPE_SPECIAL},
+	{"tx_bytes"			, NSS_STATS_TYPE_SPECIAL},
+	{"create_requests"		, NSS_STATS_TYPE_SPECIAL},
+	{"create_collisions"		, NSS_STATS_TYPE_SPECIAL},
+	{"create_invalid_interface"	, NSS_STATS_TYPE_SPECIAL},
+	{"destroy_requests"		, NSS_STATS_TYPE_SPECIAL},
+	{"destroy_misses"		, NSS_STATS_TYPE_SPECIAL},
+	{"hash_hits"			, NSS_STATS_TYPE_SPECIAL},
+	{"hash_reorders"		, NSS_STATS_TYPE_SPECIAL},
+	{"flushes"			, NSS_STATS_TYPE_SPECIAL},
+	{"evictions"			, NSS_STATS_TYPE_SPECIAL},
+	{"fragmentations"		, NSS_STATS_TYPE_SPECIAL},
+	{"by_rule_drops"		, NSS_STATS_TYPE_DROP},
+	{"mc_create_requests"		, NSS_STATS_TYPE_SPECIAL},
+	{"mc_update_requests"		, NSS_STATS_TYPE_SPECIAL},
+	{"mc_create_invalid_interface"	, NSS_STATS_TYPE_SPECIAL},
+	{"mc_destroy_requests"		, NSS_STATS_TYPE_SPECIAL},
+	{"mc_destroy_misses"		, NSS_STATS_TYPE_SPECIAL},
+	{"mc_flushes" 			, NSS_STATS_TYPE_SPECIAL}
 };
 
 /*
@@ -143,10 +141,12 @@
 static ssize_t nss_ipv4_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
 {
 	int32_t i;
+
 	/*
-	 * max output lines = #stats + start tag line + end tag line + three blank lines
+	 * max output lines = #stats + Number of Extra outputlines for future reference to add new stats +
+	 * start tag line + end tag line + three blank lines
 	 */
-	uint32_t max_output_lines = (NSS_STATS_NODE_MAX + 2) + (NSS_IPV4_STATS_MAX + 3) + (NSS_IPV4_EXCEPTION_EVENT_MAX + 3) + 5;
+	uint32_t max_output_lines = NSS_STATS_NODE_MAX + NSS_IPV4_STATS_MAX + NSS_IPV4_EXCEPTION_EVENT_MAX + NSS_STATS_EXTRA_OUTPUT_LINES;
 	size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
 	size_t size_wr = 0;
 	ssize_t bytes_read = 0;
@@ -167,46 +167,29 @@
 		kfree(lbuf);
 		return 0;
 	}
-
-	size_wr = scnprintf(lbuf, size_al, "ipv4 stats start:\n\n");
-
-	size_wr = nss_stats_fill_common_stats(NSS_IPV4_RX_INTERFACE, lbuf, size_wr, size_al);
+	size_wr = nss_stats_banner(lbuf, size_wr, size_al, "ipv4");
+	size_wr = nss_stats_fill_common_stats(NSS_IPV4_RX_INTERFACE, lbuf, size_wr, size_al, "ipv4");
 
 	/*
 	 * IPv4 node stats
 	 */
-	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nipv4 node stats:\n\n");
-
 	spin_lock_bh(&nss_top_main.stats_lock);
-	for (i = 0; (i < NSS_IPV4_STATS_MAX); i++) {
+	for (i = 0; i < NSS_IPV4_STATS_MAX; i++) {
 		stats_shadow[i] = nss_ipv4_stats[i];
 	}
 
 	spin_unlock_bh(&nss_top_main.stats_lock);
-
-	for (i = 0; (i < NSS_IPV4_STATS_MAX); i++) {
-		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
-					"%s = %llu\n", nss_ipv4_stats_str[i], stats_shadow[i]);
-	}
+	size_wr = nss_stats_print("ipv4", NULL, NSS_STATS_SINGLE_CORE, NSS_STATS_SINGLE_INSTANCE, nss_ipv4_stats_str, stats_shadow, NSS_IPV4_STATS_MAX, lbuf, size_wr, size_al);
 
 	/*
 	 * Exception stats
 	 */
-	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nipv4 exception stats:\n\n");
-
 	spin_lock_bh(&nss_top_main.stats_lock);
 	for (i = 0; (i < NSS_IPV4_EXCEPTION_EVENT_MAX); i++) {
 		stats_shadow[i] = nss_ipv4_exception_stats[i];
 	}
-
 	spin_unlock_bh(&nss_top_main.stats_lock);
-
-	for (i = 0; (i < NSS_IPV4_EXCEPTION_EVENT_MAX); i++) {
-		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
-					"%s = %llu\n", nss_ipv4_exception_stats_str[i], stats_shadow[i]);
-	}
-
-	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nipv4 stats end\n\n");
+	size_wr = nss_stats_print("ipv4", NULL, NSS_STATS_SINGLE_CORE, NSS_STATS_SINGLE_INSTANCE, nss_ipv4_exception_stats_str, stats_shadow, NSS_IPV4_EXCEPTION_EVENT_MAX, lbuf, size_wr, size_al);
 	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
 	kfree(lbuf);
 	kfree(stats_shadow);
diff --git a/nss_ipv6_reasm_stats.c b/nss_ipv6_reasm_stats.c
index f896406..7d5301c 100644
--- a/nss_ipv6_reasm_stats.c
+++ b/nss_ipv6_reasm_stats.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017, 2019 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.
@@ -14,7 +14,6 @@
  **************************************************************************
  */
 
-#include "nss_stats.h"
 #include "nss_core.h"
 #include "nss_ipv6_reasm_stats.h"
 
@@ -61,7 +60,7 @@
 
 	size_wr = scnprintf(lbuf, size_al, "ipv6 reasm stats start:\n\n");
 
-	size_wr = nss_stats_fill_common_stats(NSS_IPV6_REASM_INTERFACE, lbuf, size_wr, size_al);
+	size_wr = nss_stats_fill_common_stats(NSS_IPV6_REASM_INTERFACE, lbuf, size_wr, size_al, "ipv6_reasm");
 
 	/*
 	 * Ipv6 reasm node stats
diff --git a/nss_ipv6_stats.c b/nss_ipv6_stats.c
index 501a4de..dc1c4cd 100644
--- a/nss_ipv6_stats.c
+++ b/nss_ipv6_stats.c
@@ -14,7 +14,6 @@
  **************************************************************************
  */
 
-#include "nss_stats.h"
 #include "nss_core.h"
 #include <nss_ipv6.h>
 #include "nss_ipv6_stats.h"
@@ -149,7 +148,7 @@
 
 	size_wr = scnprintf(lbuf, size_al, "ipv6 stats start:\n\n");
 
-	size_wr = nss_stats_fill_common_stats(NSS_IPV6_RX_INTERFACE, lbuf, size_wr, size_al);
+	size_wr = nss_stats_fill_common_stats(NSS_IPV6_RX_INTERFACE, lbuf, size_wr, size_al, "ipv6");
 
 	/*
 	 * IPv6 node stats
diff --git a/nss_lso_rx_stats.c b/nss_lso_rx_stats.c
index 92aa6ea..f34eacd 100644
--- a/nss_lso_rx_stats.c
+++ b/nss_lso_rx_stats.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017, 2019 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.
@@ -14,7 +14,6 @@
  **************************************************************************
  */
 
-#include "nss_stats.h"
 #include "nss_core.h"
 #include "nss_lso_rx.h"
 
@@ -63,7 +62,7 @@
 
 	size_wr = scnprintf(lbuf, size_al, "lso_rx stats start:\n\n");
 
-	size_wr = nss_stats_fill_common_stats(NSS_LSO_RX_INTERFACE, lbuf, size_wr, size_al);
+	size_wr = nss_stats_fill_common_stats(NSS_LSO_RX_INTERFACE, lbuf, size_wr, size_al, "lso_rx");
 
 	/*
 	 * lso_rx node stats
diff --git a/nss_map_t_stats.c b/nss_map_t_stats.c
index 8406d2e..c635cc0 100644
--- a/nss_map_t_stats.c
+++ b/nss_map_t_stats.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017, 2019 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.
@@ -14,7 +14,6 @@
  **************************************************************************
  */
 
-#include "nss_stats.h"
 #include "nss_core.h"
 #include "nss_map_t_stats.h"
 
diff --git a/nss_n2h_stats.c b/nss_n2h_stats.c
index d772001..91a343b 100644
--- a/nss_n2h_stats.c
+++ b/nss_n2h_stats.c
@@ -14,7 +14,6 @@
  **************************************************************************
  */
 
-#include "nss_stats.h"
 #include "nss_core.h"
 #include "nss_n2h_stats.h"
 
diff --git a/nss_phys_if.c b/nss_phys_if.c
index 217f04d..4f9b20f 100644
--- a/nss_phys_if.c
+++ b/nss_phys_if.c
@@ -55,11 +55,11 @@
 	uint64_t *top_stats = &(nss_top->stats_gmac[id][0]);
 
 	spin_lock_bh(&nss_top->stats_lock);
-	top_stats[NSS_STATS_GMAC_TOTAL_TICKS] += stats->estats.gmac_total_ticks;
-	if (unlikely(top_stats[NSS_STATS_GMAC_WORST_CASE_TICKS] < stats->estats.gmac_worst_case_ticks)) {
-		top_stats[NSS_STATS_GMAC_WORST_CASE_TICKS] = stats->estats.gmac_worst_case_ticks;
+	top_stats[NSS_GMAC_STATS_TOTAL_TICKS] += stats->estats.gmac_total_ticks;
+	if (unlikely(top_stats[NSS_GMAC_STATS_WORST_CASE_TICKS] < stats->estats.gmac_worst_case_ticks)) {
+		top_stats[NSS_GMAC_STATS_WORST_CASE_TICKS] = stats->estats.gmac_worst_case_ticks;
 	}
-	top_stats[NSS_STATS_GMAC_ITERATIONS] += stats->estats.gmac_iterations;
+	top_stats[NSS_GMAC_STATS_ITERATIONS] += stats->estats.gmac_iterations;
 	spin_unlock_bh(&nss_top->stats_lock);
 }
 
diff --git a/nss_portid_stats.c b/nss_portid_stats.c
index 4400bfd..4e7a74e 100644
--- a/nss_portid_stats.c
+++ b/nss_portid_stats.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, 2019 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.
@@ -14,7 +14,6 @@
  **************************************************************************
  */
 
-#include "nss_stats.h"
 #include "nss_core.h"
 #include "nss_portid_stats.h"
 
@@ -62,7 +61,7 @@
 
 	size_wr = scnprintf(lbuf, size_al, "portid stats start:\n\n");
 
-	size_wr = nss_stats_fill_common_stats(NSS_PORTID_INTERFACE, lbuf, size_wr, size_al);
+	size_wr = nss_stats_fill_common_stats(NSS_PORTID_INTERFACE, lbuf, size_wr, size_al, "portid");
 
 	/*
 	 * PortID node stats
diff --git a/nss_pppoe_stats.c b/nss_pppoe_stats.c
index b7cc748..dfc76bc 100644
--- a/nss_pppoe_stats.c
+++ b/nss_pppoe_stats.c
@@ -14,7 +14,6 @@
  **************************************************************************
  */
 
-#include "nss_stats.h"
 #include "nss_core.h"
 
 /*
diff --git a/nss_pptp_stats.c b/nss_pptp_stats.c
index 651980f..00e164a 100644
--- a/nss_pptp_stats.c
+++ b/nss_pptp_stats.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2019, 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.
@@ -14,7 +14,6 @@
  **************************************************************************
  */
 
-#include "nss_stats.h"
 #include "nss_core.h"
 #include "nss_pptp_stats.h"
 
diff --git a/nss_qrfs_stats.c b/nss_qrfs_stats.c
index 0dbb120..462fa9b 100644
--- a/nss_qrfs_stats.c
+++ b/nss_qrfs_stats.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, 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.
@@ -14,7 +14,6 @@
  **************************************************************************
  */
 
-#include "nss_stats.h"
 #include "nss_core.h"
 #include "nss_qrfs_stats.h"
 
diff --git a/nss_qvpn_stats.c b/nss_qvpn_stats.c
index 68f2e5f..98bcbf1 100644
--- a/nss_qvpn_stats.c
+++ b/nss_qvpn_stats.c
@@ -14,7 +14,6 @@
  **************************************************************************
  */
 
-#include "nss_stats.h"
 #include "nss_core.h"
 #include <nss_qvpn.h>
 
@@ -62,7 +61,7 @@
 		}
 
 		len += scnprintf(buf + len, size - len, "\n-------------------\n");
-		len = nss_stats_fill_common_stats(if_num, buf, len, size - len);
+		len = nss_stats_fill_common_stats(if_num, buf, len, size - len, "qvpn");
 	}
 
 	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, buf, len);
diff --git a/nss_shaper.c b/nss_shaper.c
index 2e97486..a6031d0 100644
--- a/nss_shaper.c
+++ b/nss_shaper.c
@@ -296,7 +296,7 @@
 	}
 	nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
 
-	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_PACKET]);
+	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_TX_PACKET]);
 	return NSS_TX_SUCCESS;
 }
 
@@ -341,7 +341,7 @@
 	}
 	nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
 
-	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_PACKET]);
+	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_TX_PACKET]);
 	return NSS_TX_SUCCESS;
 }
 
diff --git a/nss_sjack_stats.c b/nss_sjack_stats.c
index ce3458e..39a9436 100644
--- a/nss_sjack_stats.c
+++ b/nss_sjack_stats.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, 2019 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.
@@ -14,7 +14,6 @@
  **************************************************************************
  */
 
-#include "nss_stats.h"
 #include "nss_core.h"
 #include "nss_sjack_stats.h"
 
@@ -48,7 +47,7 @@
 
 	size_wr = scnprintf(lbuf, size_al, "sjack stats start:\n\n");
 
-	size_wr = nss_stats_fill_common_stats(NSS_SJACK_INTERFACE, lbuf, size_wr, size_al);
+	size_wr = nss_stats_fill_common_stats(NSS_SJACK_INTERFACE, lbuf, size_wr, size_al, "sjack");
 
 	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nsjack stats end\n\n");
 
diff --git a/nss_stats.c b/nss_stats.c
index 24a9715..f6d6f41 100644
--- a/nss_stats.c
+++ b/nss_stats.c
@@ -14,86 +14,344 @@
  **************************************************************************
  */
 
-/*
- * nss_stats.c
- *	NSS stats APIs
- *
- */
-
-#include "nss_tx_rx_common.h"
 #include "nss_core.h"
-#include "nss_stats.h"
 
 /*
- * nss_stats_str_drv
- *	Host driver stats strings
+ * Maximum banner length:
  */
-static int8_t *nss_stats_str_drv[NSS_STATS_DRV_MAX] = {
-	"nbuf_alloc_errors",
-	"paged_buf_alloc_errors",
-	"tx_queue_full[0]",
-	"tx_queue_full[1]",
-	"tx_buffers_empty",
-	"tx_paged_buffers_empty",
-	"tx_buffers_pkt",
-	"tx_buffers_cmd",
-	"tx_buffers_crypto",
-	"tx_buffers_reuse",
-	"rx_buffers_empty",
-	"rx_buffers_pkt",
-	"rx_buffer_ext_pkt",
-	"rx_buffers_cmd_resp",
-	"rx_buffers_status_sync",
-	"rx_buffers_crypto",
-	"rx_buffers_virtual",
-	"tx_skb_simple",
-	"tx_skb_nr_frags",
-	"tx_skb_fraglist",
-	"rx_skb_simple",
-	"rx_skb_nr_frags",
-	"rx_skb_fraglist",
-	"rx_bad_desciptor",
-	"nss_skb_count",
-	"rx_chain_seg_processed",
-	"rx_frag_seg_processed",
-	"tx_buffers_cmd_queue_full",
-#ifdef NSS_MULTI_H2N_DATA_RING_SUPPORT
-	"tx_buffers_data_queue_0",
-	"tx_buffers_data_queue_1",
-	"tx_buffers_data_queue_2",
-	"tx_buffers_data_queue_3",
-	"tx_buffers_data_queue_4",
-	"tx_buffers_data_queue_5",
-	"tx_buffers_data_queue_6",
-	"tx_buffers_data_queue_7",
-#endif
-};
+#define NSS_STATS_BANNER_MAX_LENGTH 80
 
 /*
- * nss_stats_str_gmac
- *	GMAC stats strings
+ * Maximum number of digits a stats value can have:
  */
-static int8_t *nss_stats_str_gmac[NSS_STATS_GMAC_MAX] = {
-	"ticks",
-	"worst_ticks",
-	"iterations"
-};
+#define NSS_STATS_DIGITS_MAX 16
 
 /*
- * nss_stats_str_node
- *	Interface stats strings per node
+ * Max characters for a node name.
  */
-static int8_t *nss_stats_str_node[NSS_STATS_NODE_MAX] = {
-	"rx_packets",
-	"rx_bytes",
-	"tx_packets",
-	"tx_bytes",
-	"rx_queue_0_dropped",
-	"rx_queue_1_dropped",
-	"rx_queue_2_dropped",
-	"rx_queue_3_dropped",
+#define NSS_STATS_NODE_NAME_MAX 24
+
+/*
+ * common stats
+ */
+struct nss_stats_info nss_stats_str_node[NSS_STATS_NODE_MAX] = {
+	{"rx_pkts"		, NSS_STATS_TYPE_COMMON},
+	{"rx_byts"		, NSS_STATS_TYPE_COMMON},
+	{"tx_pkts"		, NSS_STATS_TYPE_COMMON},
+	{"tx_byts"		, NSS_STATS_TYPE_COMMON},
+	{"rx_queue[0]_drops"	, NSS_STATS_TYPE_DROP},
+	{"rx_queue[1]_drops"	, NSS_STATS_TYPE_DROP},
+	{"rx_queue[2]_drops"	, NSS_STATS_TYPE_DROP},
+	{"rx_queue[3]_drops"	, NSS_STATS_TYPE_DROP}
 };
 
+int nonzero_stats_print = 0;
+
+/*
+ * nss_stats_spacing()
+ *	Framework to maintain consistent spacing between stats value and stats type.
+ */
+static size_t nss_stats_spacing(uint64_t stats_val, char *lbuf, size_t size_wr, size_t size_al)
+{
+	int i;
+	int digit_counter = (stats_val == 0 ? 1 : 0);
+	while (stats_val != 0) {
+		/*
+		 * TODO: need to check for (nss_ptr_t)
+		 */
+		stats_val = (nss_ptr_t)stats_val / 10;
+		digit_counter++;
+	}
+
+	for (i = 0; i < NSS_STATS_DIGITS_MAX - digit_counter; i++) {
+		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, " ");
+	}
+
+	return size_wr;
+}
+
+/*
+ * nss_stats_nonzero_handler()
+ *	Handler to take nonzero stats print configuration.
+ */
+static int nss_stats_nonzero_handler(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	int ret;
+	ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
+	return ret;
+}
+
+static struct ctl_table nss_stats_table[] = {
+	{
+		.procname		= "non_zero_stats",
+		.data			= &nonzero_stats_print,
+		.maxlen			= sizeof(int),
+		.mode			= 0644,
+		.proc_handler		= &nss_stats_nonzero_handler,
+	},
+	{ }
+};
+
+static struct ctl_table nss_stats_dir[] = {
+	{
+		.procname		= "stats",
+		.mode			= 0555,
+		.child			= nss_stats_table,
+	},
+	{ }
+};
+
+static struct ctl_table nss_stats_root_dir[] = {
+	{
+		.procname		= "nss",
+		.mode			= 0555,
+		.child			= nss_stats_dir,
+	},
+	{ }
+};
+
+static struct ctl_table nss_stats_root[] = {
+	{
+		.procname		= "dev",
+		.mode			= 0555,
+		.child			= nss_stats_root_dir,
+	},
+	{ }
+};
+static struct ctl_table_header *nss_stats_header;
+
+/*
+ * nss_stats_register_sysctl()
+ * 	Register a sysctl table for stats.
+ */
+void nss_stats_register_sysctl(void)
+{
+	/*
+	 * Register sysctl table.
+	 */
+	nss_stats_header = register_sysctl_table(nss_stats_root);
+}
+
+/*
+ * nss_stats_open()
+ * 	Opens stats file.
+ */
+int nss_stats_open(struct inode *inode, struct file *filp)
+{
+	struct nss_stats_data *data = NULL;
+
+	data = kzalloc(sizeof(struct nss_stats_data), GFP_KERNEL);
+	if (!data) {
+		return -ENOMEM;
+	}
+
+	memset(data, 0, sizeof (struct nss_stats_data));
+	data->if_num = NSS_DYNAMIC_IF_START;
+	data->index = 0;
+	data->edma_id = (nss_ptr_t)inode->i_private;
+	data->nss_ctx = (struct nss_ctx_instance *)(inode->i_private);
+	filp->private_data = data;
+
+	return 0;
+}
+
+/*
+ * nss_stats_release()
+ * 	Releases stats file.
+ */
+int nss_stats_release(struct inode *inode, struct file *filp)
+{
+	struct nss_stats_data *data = filp->private_data;
+
+	if (data) {
+		kfree(data);
+	}
+
+	return 0;
+}
+
+/*
+ * nss_stats_clean()
+ *	Cleanup NSS statistics files.
+ */
+void nss_stats_clean(void)
+{
+	/*
+	 * Remove debugfs tree
+	 */
+	if (likely(nss_top_main.top_dentry != NULL)) {
+		debugfs_remove_recursive(nss_top_main.top_dentry);
+		nss_top_main.top_dentry = NULL;
+	}
+}
+
+/*
+ * nss_stats_fill_common_stats()
+ *	Fill common node statistics.
+ */
+size_t nss_stats_fill_common_stats(uint32_t if_num, char *lbuf, size_t size_wr, size_t size_al, char *node)
+{
+	uint64_t stats_val[NSS_STATS_NODE_MAX];
+	int i;
+	spin_lock_bh(&nss_top_main.stats_lock);
+	for (i = 0; i < NSS_STATS_NODE_MAX; i++) {
+		stats_val[i] = nss_top_main.stats_node[if_num][i];
+	}
+
+	spin_unlock_bh(&nss_top_main.stats_lock);
+	size_wr = nss_stats_print(node, NULL, NSS_STATS_SINGLE_CORE, NSS_STATS_SINGLE_INSTANCE, nss_stats_str_node, stats_val, NSS_STATS_NODE_MAX, lbuf, size_wr, size_al);
+	return size_wr;
+}
+
+/*
+ * nss_stats_banner()
+ *	Printing banner for node.
+ */
+size_t nss_stats_banner(char *lbuf, size_t size_wr, size_t size_al, char *node)
+{
+	uint16_t banner_char_length, i;
+	char node_upr[NSS_STATS_NODE_NAME_MAX + 1];
+
+	if (strlen(node) > NSS_STATS_NODE_NAME_MAX) {
+		nss_warning("Node name %s larger than %d characters\n", node, NSS_STATS_NODE_NAME_MAX);
+		return 0;
+	}
+
+	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n");
+	for (i = 0; i < NSS_STATS_BANNER_MAX_LENGTH ; i++) {
+		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "_");
+	}
+
+	banner_char_length = (uint16_t)((NSS_STATS_BANNER_MAX_LENGTH - (strlen(node) + 2)) / 2);
+
+	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n\n");
+	for (i = 0; i < banner_char_length; i++) {
+		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "<");
+	}
+
+	strlcpy(node_upr, node, NSS_STATS_NODE_NAME_MAX);
+	for (i = 0; node_upr[i] != '\0' && i < NSS_STATS_NODE_NAME_MAX; i++) {
+		node_upr[i] = toupper(node_upr[i]);
+	}
+
+	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, " %s ", node);
+	for (i = 0; i < banner_char_length; i++) {
+		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, ">");
+	}
+
+	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n");
+	for (i = 0; i < NSS_STATS_BANNER_MAX_LENGTH; i++) {
+		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "_");
+	}
+
+	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n\n");
+	return size_wr;
+}
+
+/*
+ * nss_stats_print()
+ *	Helper API to print stats.
+ */
+size_t nss_stats_print(char *node, char *stat_details, int core_num, int instance, struct nss_stats_info *stats_info, uint64_t *stats_val, uint16_t max, char *lbuf, size_t size_wr, size_t size_al)
+{
+	uint16_t i, j;
+	uint16_t maxlen = 0;
+	char stats_string[NSS_STATS_MAX_STR_LENGTH];
+	char node_lwr[NSS_STATS_NODE_NAME_MAX + 1];
+
+	if (strlen(node) > NSS_STATS_NODE_NAME_MAX) {
+		nss_warning("Node name %s (%u chars) is longer than max chars of %d\n",
+				node, (uint32_t)strlen(node), NSS_STATS_NODE_NAME_MAX);
+		return 0;
+	}
+
+	/*
+	 * Calculating the maximum of the array for indentation purposes.
+	 */
+	for (i = 0; i < max; i++){
+		if (strlen(stats_info[i].stats_name) > maxlen) {
+			maxlen = strlen(stats_info[i].stats_name);
+		}
+	}
+
+	if (core_num >= 0) {
+		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n***** \n");
+		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "***** CORE %d \n", core_num);
+		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "*****\n");
+	}
+
+	if (stat_details != NULL) {
+		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n#%s\n\n", stat_details);
+	}
+
+	for (i = 0; i < max; i++){
+		if (nonzero_stats_print == 1 && stats_val[i] == 0) {
+			continue;
+		}
+
+		strlcpy(stats_string, stats_info[i].stats_name, NSS_STATS_MAX_STR_LENGTH);
+
+		/*
+		 * Converting  uppercase to lower case.
+		 */
+		for (j = 0; stats_string[j] != '\0' && j < NSS_STATS_MAX_STR_LENGTH; j++) {
+			stats_string[j] = tolower(stats_string[j]);
+		}
+
+		strlcpy(node_lwr, node, NSS_STATS_NODE_NAME_MAX);
+		for (j = 0; node_lwr[j] != '\0' && j < NSS_STATS_NODE_NAME_MAX; j++) {
+			node_lwr[j] = tolower(node_lwr[j]);
+		}
+
+		/*
+		 * Space before %s is needed to avoid printing stat name from start of the line.
+		 */
+		if (instance < 0) {
+			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\t%s_%s", node_lwr, stats_string);
+		} else {
+			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\t%s[%d]_%s", node_lwr, instance, stats_string);
+		}
+
+		for (j = 0; j < (1 + maxlen - strlen(stats_string)); j++){
+			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, " ");
+		}
+
+		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "= %llu", stats_val[i]);
+		size_wr = nss_stats_spacing(stats_val[i], lbuf, size_wr, size_al);
+
+		/*
+		 * Switch case will take care of the indentation and spacing details.
+		 */
+		switch (stats_info[i].stats_type) {
+		case NSS_STATS_TYPE_COMMON:
+			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "common\n");
+			break;
+
+		case NSS_STATS_TYPE_SPECIAL:
+			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "special\n");
+			break;
+
+		case NSS_STATS_TYPE_DROP:
+			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "drop\n");
+			break;
+
+		case NSS_STATS_TYPE_ERROR:
+			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "error\n");
+			break;
+
+		case NSS_STATS_TYPE_EXCEPTION:
+			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "exception\n");
+			break;
+
+		default:
+			nss_warning("unknown statistics type");
+			break;
+		}
+	}
+
+	return size_wr;
+}
+
 /*
  * nss_stats_create_dentry()
  *	Create statistics debug entry for subsystem.
@@ -106,250 +364,8 @@
 }
 
 /*
- * nss_stats_fill_common_stats()
- *	Fill common node statistics.
+ * TODO: Move the rest of the code to (nss_wt_stats.c, nss_gmac_stats.c, nss_drv_stats.c) accordingly.
  */
-size_t nss_stats_fill_common_stats(uint32_t if_num, char *lbuf, size_t size_wr, size_t size_al)
-{
-	uint64_t stats_shadow[NSS_STATS_NODE_MAX];
-	int i;
-
-	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "common node stats:\n\n");
-	spin_lock_bh(&nss_top_main.stats_lock);
-	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
-		stats_shadow[i] = nss_top_main.stats_node[if_num][i];
-	}
-	spin_unlock_bh(&nss_top_main.stats_lock);
-
-	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
-		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
-					"%s = %llu\n", nss_stats_str_node[i], stats_shadow[i]);
-	}
-
-	return size_wr;
-}
-
-/*
- * nss_drv_stats_read()
- *	Read HLOS driver stats
- */
-static ssize_t nss_drv_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
-{
-	int32_t i;
-
-	/*
-	 * max output lines = #stats + start tag line + end tag line + three blank lines
-	 */
-	uint32_t max_output_lines = NSS_STATS_DRV_MAX + 5;
-	size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
-	size_t size_wr = 0;
-	ssize_t bytes_read = 0;
-	uint64_t *stats_shadow;
-
-	char *lbuf = kzalloc(size_al, GFP_KERNEL);
-	if (unlikely(lbuf == NULL)) {
-		nss_warning("Could not allocate memory for local statistics buffer");
-		return 0;
-	}
-
-	stats_shadow = kzalloc(NSS_STATS_DRV_MAX * 8, GFP_KERNEL);
-	if (unlikely(stats_shadow == NULL)) {
-		nss_warning("Could not allocate memory for local shadow buffer");
-		kfree(lbuf);
-		return 0;
-	}
-
-	size_wr = scnprintf(lbuf, size_al, "drv stats start:\n\n");
-	for (i = 0; (i < NSS_STATS_DRV_MAX); i++) {
-		stats_shadow[i] = NSS_PKT_STATS_READ(&nss_top_main.stats_drv[i]);
-	}
-
-	for (i = 0; (i < NSS_STATS_DRV_MAX); i++) {
-		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
-					"%s = %llu\n", nss_stats_str_drv[i], stats_shadow[i]);
-	}
-
-	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\ndrv stats end\n\n");
-	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
-	kfree(lbuf);
-	kfree(stats_shadow);
-
-	return bytes_read;
-}
-
-/*
- * nss_gmac_stats_read()
- *	Read GMAC stats
- */
-static ssize_t nss_gmac_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
-{
-	uint32_t i, id;
-
-	/*
-	 * max output lines = ((#stats + start tag + one blank) * #GMACs) + start/end tag + 3 blank
-	 */
-	uint32_t max_output_lines = ((NSS_STATS_GMAC_MAX + 2) * NSS_MAX_PHYSICAL_INTERFACES) + 5;
-	size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
-	size_t size_wr = 0;
-	ssize_t bytes_read = 0;
-	uint64_t *stats_shadow;
-
-	char *lbuf = kzalloc(size_al, GFP_KERNEL);
-	if (unlikely(lbuf == NULL)) {
-		nss_warning("Could not allocate memory for local statistics buffer");
-		return 0;
-	}
-
-	stats_shadow = kzalloc(NSS_STATS_GMAC_MAX * 8, GFP_KERNEL);
-	if (unlikely(stats_shadow == NULL)) {
-		nss_warning("Could not allocate memory for local shadow buffer");
-		kfree(lbuf);
-		return 0;
-	}
-
-	size_wr = scnprintf(lbuf, size_al, "gmac stats start:\n\n");
-
-	for (id = 0; id < NSS_MAX_PHYSICAL_INTERFACES; id++) {
-		spin_lock_bh(&nss_top_main.stats_lock);
-		for (i = 0; (i < NSS_STATS_GMAC_MAX); i++) {
-			stats_shadow[i] = nss_top_main.stats_gmac[id][i];
-		}
-
-		spin_unlock_bh(&nss_top_main.stats_lock);
-
-		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "GMAC ID: %d\n", id);
-		for (i = 0; (i < NSS_STATS_GMAC_MAX); i++) {
-			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
-					"%s = %llu\n", nss_stats_str_gmac[i], stats_shadow[i]);
-		}
-		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n");
-	}
-
-	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\ngmac stats end\n\n");
-	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
-	kfree(lbuf);
-	kfree(stats_shadow);
-
-	return bytes_read;
-}
-
-/*
- * nss_wt_stats_read()
- *	Reads and formats worker thread statistics and outputs them to ubuf
- */
-static ssize_t nss_wt_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
-{
-	struct nss_stats_data *data = fp->private_data;
-	struct nss_ctx_instance *nss_ctx = data->nss_ctx;
-	struct nss_project_irq_stats *shadow;
-	uint32_t thread_count = nss_ctx->worker_thread_count;
-	uint32_t irq_count = nss_ctx->irq_count;
-
-	/*
-	 * Three lines for each IRQ
-	 */
-	uint32_t max_output_lines = thread_count * 3 * irq_count;
-	size_t size_al = max_output_lines * NSS_STATS_MAX_STR_LENGTH;
-	size_t size_wr = 0;
-	ssize_t bytes_read = 0;
-	char *lbuf;
-	int i;
-	int j;
-
-	lbuf = kzalloc(size_al, GFP_KERNEL);
-	if (unlikely(!lbuf)) {
-		nss_warning("Could not allocate memory for local statistics buffer\n");
-		return 0;
-	}
-
-	shadow = kzalloc(thread_count * irq_count * sizeof(struct nss_project_irq_stats), GFP_KERNEL);
-	if (unlikely(!shadow)) {
-		nss_warning("Could not allocate memory for stats shadow\n");
-		kfree(lbuf);
-		return 0;
-	}
-
-	spin_lock_bh(&nss_top_main.stats_lock);
-	if (unlikely(!nss_ctx->wt_stats)) {
-		spin_unlock_bh(&nss_top_main.stats_lock);
-		nss_warning("Worker thread statistics not allocated\n");
-		kfree(lbuf);
-		kfree(shadow);
-		return 0;
-	}
-	for (i = 0; i < thread_count; ++i) {
-
-		/*
-		 * The statistics shadow is an array with thread_count * irq_count
-		 * items in it. Each item is located at the index:
-		 *      (thread number) * (irq_count) + (irq number)
-		 * thus simulating a two-dimensional array.
-		 */
-		for (j = 0; j < irq_count; ++j) {
-			shadow[i * irq_count + j] = nss_ctx->wt_stats[i].irq_stats[j];
-		}
-	}
-	spin_unlock_bh(&nss_top_main.stats_lock);
-
-	for (i = 0; i < thread_count; ++i) {
-		for (j = 0; j < irq_count; ++j) {
-			struct nss_project_irq_stats *is = &(shadow[i * irq_count + j]);
-			if (!(is->count)) {
-				continue;
-			}
-
-			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
-				"t-%d:irq-%d callback: 0x%x, count: %llu\n",
-				i, j, is->callback, is->count);
-			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
-				"t-%d:irq-%d tick min: %10u  avg: %10u  max:%10u\n",
-				i, j, is->ticks_min, is->ticks_avg, is->ticks_max);
-			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
-				"t-%d:irq-%d insn min: %10u  avg: %10u  max:%10u\n\n",
-				i, j, is->insn_min, is->insn_avg, is->insn_max);
-		}
-	}
-	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
-	kfree(lbuf);
-	kfree(shadow);
-
-	return bytes_read;
-}
-
-/*
- * nss_stats_open()
- */
-int nss_stats_open(struct inode *inode, struct file *filp)
-{
-	struct nss_stats_data *data = NULL;
-
-	data = kzalloc(sizeof(struct nss_stats_data), GFP_KERNEL);
-	if (!data) {
-		return -ENOMEM;
-	}
-	memset(data, 0, sizeof (struct nss_stats_data));
-	data->if_num = NSS_DYNAMIC_IF_START;
-	data->index = 0;
-	data->edma_id = (nss_ptr_t)inode->i_private;
-	data->nss_ctx = (struct nss_ctx_instance *)(inode->i_private);
-	filp->private_data = data;
-
-	return 0;
-}
-
-/*
- * nss_stats_release()
- */
-int nss_stats_release(struct inode *inode, struct file *filp)
-{
-	struct nss_stats_data *data = filp->private_data;
-
-	if (data) {
-		kfree(data);
-	}
-
-	return 0;
-}
 
 /*
  * drv_stats_ops
@@ -367,23 +383,8 @@
 NSS_STATS_DECLARE_FILE_OPERATIONS(wt)
 
 /*
- * nss_stats_clean()
- *	Cleanup NSS statistics files
- */
-void nss_stats_clean(void)
-{
-	/*
-	 * Remove debugfs tree
-	 */
-	if (likely(nss_top_main.top_dentry != NULL)) {
-		debugfs_remove_recursive(nss_top_main.top_dentry);
-		nss_top_main.top_dentry = NULL;
-	}
-}
-
-/*
  * nss_stats_init()
- *	Enable NSS statistics
+ * 	Enable NSS statistics.
  */
 void nss_stats_init(void)
 {
@@ -400,8 +401,8 @@
 		nss_warning("Failed to create qca-nss-drv directory in debugfs");
 
 		/*
-		 * Non availability of debugfs directory is not a catastrophy
-		 * We can still go ahead with other initialization
+		 * Non availability of debugfs directory is not a catastrophy.
+		 * We can still go ahead with other initialization.
 		 */
 		return;
 	}
@@ -411,14 +412,14 @@
 		nss_warning("Failed to create qca-nss-drv directory in debugfs");
 
 		/*
-		 * Non availability of debugfs directory is not a catastrophy
-		 * We can still go ahead with rest of initialization
+		 * Non availability of debugfs directory is not a catastrophy.
+		 * We can still go ahead with rest of initialization.
 		 */
 		return;
 	}
 
 	/*
-	 * Create files to obtain statistics
+	 * Create files to obtain statistics.
 	 */
 
 	/*
diff --git a/nss_stats.h b/nss_stats.h
index b973bab..1c9feec 100644
--- a/nss_stats.h
+++ b/nss_stats.h
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, 2019 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.
@@ -16,13 +16,25 @@
 
 /*
  * nss_stats.h
- *	NSS driver stats header file.
+ *	printing stats header file
  */
 
-#ifndef __NSS_STATS_H
-#define __NSS_STATS_H
+#ifndef __NSS_STATS_PRINT_H
+#define __NSS_STATS_PRINT_H
+#include <linux/ctype.h>
+#include <nss_drv_stats.h>
+#include <nss_def.h>
 
-#include <linux/debugfs.h>
+/*
+ * Defines to be used by single instance/core packages.
+*/
+#define NSS_STATS_SINGLE_CORE -1
+#define NSS_STATS_SINGLE_INSTANCE -1
+
+/*
+ * Number of Extra outputlines for future reference to add new stats + start tag line + end tag line + three blank lines
+ */
+#define NSS_STATS_EXTRA_OUTPUT_LINES 35
 
 /*
  * Maximum string length:
@@ -33,8 +45,9 @@
 
 /*
  * Node statistics
+ *	Common stats for packet processing nodes.
  */
-enum nss_stats_node {
+enum NSS_STATS_NODE {
 	NSS_STATS_NODE_RX_PKTS,		/* Accelerated node RX packets */
 	NSS_STATS_NODE_RX_BYTES,	/* Accelerated node RX bytes */
 	NSS_STATS_NODE_TX_PKTS,		/* Accelerated node TX packets */
@@ -47,10 +60,23 @@
 					/* Accelerated node RX Queue 2 dropped */
 	NSS_STATS_NODE_RX_QUEUE_3_DROPPED,
 					/* Accelerated node RX Queue 3 dropped */
-
 	NSS_STATS_NODE_MAX,
 };
 
+/*
+ * Stats_type
+ *	List of stats categories.
+ */
+enum nss_stats_types {
+	NSS_STATS_TYPE_COMMON,		/* Common pnode stats */
+	NSS_STATS_TYPE_DROP,		/* Packet drop stats */
+	NSS_STATS_TYPE_ERROR,		/* HW/SW errors different from drop or exception stats. */
+					/* e.g. EDMA HW error, payload alloc failure */
+	NSS_STATS_TYPE_EXCEPTION,	/* Packet exception (to host) stats */
+	NSS_STATS_TYPE_SPECIAL,		/* Stats that don't fall into above types */
+	NSS_STATS_TYPE_MAX
+};
+
 #define NSS_STATS_DECLARE_FILE_OPERATIONS(name) \
 static const struct file_operations nss_##name##_stats_ops = { \
 	.open = nss_stats_open, \
@@ -70,9 +96,20 @@
 				/**< The core for project stats */
 };
 
-int nss_stats_release(struct inode *inode, struct file *filp);
-int nss_stats_open(struct inode *inode, struct file *filp);
-void nss_stats_create_dentry(char *name, const struct file_operations *ops);
-size_t nss_stats_fill_common_stats(uint32_t if_num, char *lbuf, size_t size_wr, size_t size_al);
+/*
+ * Structure definition carrying stats info.
+ */
+struct nss_stats_info {
+	char stats_name[NSS_STATS_MAX_STR_LENGTH];	/* stat name */
+	enum nss_stats_types stats_type;		/* enum that tags stat type  */
+};
 
+extern void nss_stats_register_sysctl(void);
+void nss_stats_init(void);
+extern int nss_stats_release(struct inode *inode, struct file *filp);
+extern int nss_stats_open(struct inode *inode, struct file *filp);
+void nss_stats_create_dentry(char *name, const struct file_operations *ops);
+extern size_t nss_stats_fill_common_stats(uint32_t if_num, char *lbuf, size_t size_wr, size_t size_al, char *node);
+extern size_t nss_stats_banner(char *lbuf ,size_t size_wr, size_t size_al, char *node);
+extern size_t nss_stats_print(char *node, char *stat_details, int core_num, int instance, struct nss_stats_info *stats_info, uint64_t *stats_val, uint16_t max, char *lbuf, size_t size_wr, size_t size_al);
 #endif /* __NSS_STATS_H */
diff --git a/nss_trustsec_tx_stats.c b/nss_trustsec_tx_stats.c
index 5c624e9..cf6fd5b 100644
--- a/nss_trustsec_tx_stats.c
+++ b/nss_trustsec_tx_stats.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017, 2019 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.
@@ -15,7 +15,6 @@
  */
 
 #include "nss_tx_rx_common.h"
-#include "nss_stats.h"
 #include "nss_trustsec_tx_stats.h"
 
 /*
@@ -106,7 +105,7 @@
 	/*
 	 * Common node stats
 	 */
-	size_wr = nss_stats_fill_common_stats(NSS_TRUSTSEC_TX_INTERFACE, lbuf, size_wr, size_al);
+	size_wr = nss_stats_fill_common_stats(NSS_TRUSTSEC_TX_INTERFACE, lbuf, size_wr, size_al, "trustsec_tx");
 
 	/*
 	 * TrustSec TX node stats
diff --git a/nss_unaligned_stats.c b/nss_unaligned_stats.c
index 6b8f166..af0fd74 100644
--- a/nss_unaligned_stats.c
+++ b/nss_unaligned_stats.c
@@ -15,7 +15,6 @@
  */
 
 #include "nss_tx_rx_common.h"
-#include "nss_stats.h"
 #include "nss_unaligned_stats.h"
 
 /*
diff --git a/nss_virt_if_stats.c b/nss_virt_if_stats.c
index 5920ca8..d43b72c 100644
--- a/nss_virt_if_stats.c
+++ b/nss_virt_if_stats.c
@@ -14,7 +14,6 @@
  **************************************************************************
  */
 
-#include "nss_stats.h"
 #include "nss_core.h"
 #include "nss_virt_if_stats.h"
 
diff --git a/nss_vxlan_stats.c b/nss_vxlan_stats.c
index 670a092..c56e191 100644
--- a/nss_vxlan_stats.c
+++ b/nss_vxlan_stats.c
@@ -51,7 +51,7 @@
 		if (if_num == NSS_VXLAN_INTERFACE) {
 			len += scnprintf(buf + len, size - len, "\nBase node if_num:%03u", if_num);
 			len += scnprintf(buf + len, size - len, "\n-------------------\n");
-			len = nss_stats_fill_common_stats(if_num, buf, len, size - len);
+			len = nss_stats_fill_common_stats(if_num, buf, len, size - len, "vxlan");
 			continue;
 		}
 
@@ -70,7 +70,7 @@
 		}
 
 		len += scnprintf(buf + len, size - len, "\n-------------------\n");
-		len = nss_stats_fill_common_stats(if_num, buf, len, size - len);
+		len = nss_stats_fill_common_stats(if_num, buf, len, size - len, "vxlan");
 	}
 
 	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, buf, len);
diff --git a/nss_wifi_if_stats.c b/nss_wifi_if_stats.c
index 3308884..19c1c36 100644
--- a/nss_wifi_if_stats.c
+++ b/nss_wifi_if_stats.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, 2019 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.
@@ -14,7 +14,6 @@
  **************************************************************************
  */
 
-#include "nss_stats.h"
 #include "nss_core.h"
 #include "nss_wifi_if.h"
 
diff --git a/nss_wifi_stats.c b/nss_wifi_stats.c
index c925f71..ff4c34b 100644
--- a/nss_wifi_stats.c
+++ b/nss_wifi_stats.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, 2019 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.
@@ -14,7 +14,6 @@
  **************************************************************************
  */
 
-#include "nss_stats.h"
 #include "nss_core.h"
 #include "nss_wifi.h"
 #include "nss_wifi_stats.h"
diff --git a/nss_wifi_vdev.c b/nss_wifi_vdev.c
index d4b29cd..49e8ce6 100644
--- a/nss_wifi_vdev.c
+++ b/nss_wifi_vdev.c
@@ -146,7 +146,7 @@
 
 /*
  * nss_wifi_vdev_tx_msg_ext()
- *	Send special data packet with metadata for vap processing
+ * 	Send special data packet with metadata for vap processing
  */
 nss_tx_status_t nss_wifi_vdev_tx_msg_ext(struct nss_ctx_instance *nss_ctx, struct sk_buff *os_buf)
 {
@@ -187,7 +187,7 @@
 
 	nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
 
-	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CMD_REQ]);
+	NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_TX_CMD_REQ]);
 
 return status;
 }
@@ -195,7 +195,7 @@
 
 /*
  * nss_wifi_vdev_tx_buf
- *	Send data packet for vap processing
+ * 	Send data packet for vap processing
  */
 nss_tx_status_t nss_wifi_vdev_tx_buf(struct nss_ctx_instance *nss_ctx, struct sk_buff *os_buf, uint32_t if_num)
 {
diff --git a/nss_wifili_stats.c b/nss_wifili_stats.c
index 25b4ed0..ff359d8 100644
--- a/nss_wifili_stats.c
+++ b/nss_wifili_stats.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019, 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.
@@ -21,7 +21,6 @@
 
 #include "nss_tx_rx_common.h"
 #include "nss_core.h"
-#include "nss_stats.h"
 #include "nss_wifili_if.h"
 #include "nss_wifili_stats.h"
 
diff --git a/nss_wifili_stats.h b/nss_wifili_stats.h
index 043f84e..ed69925 100644
--- a/nss_wifili_stats.h
+++ b/nss_wifili_stats.h
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019, 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.
@@ -23,7 +23,6 @@
 #define __NSS_WIFILI_STATS_H
 
 #include "nss_core.h"
-#include "nss_stats.h"
 #include "nss_wifili_if.h"
 
 /*