wlan: Add Per packet stats.

As part of Per packet stats, periodical stats such
as data rate, rssi, seq. number, number of retries
etc would be sent to wifi hal layer for debugging.

Change-Id: I20651f38589abf031f04392f4c93d3511bdb3403
CRs-Fixed: 915570
diff --git a/CORE/HDD/inc/wlan_hdd_cfg.h b/CORE/HDD/inc/wlan_hdd_cfg.h
index d98bf55..b5f6c73 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg.h
@@ -2272,6 +2272,13 @@
 #define CFG_WLAN_LOGGING_NUM_BUF_MIN      ( 4  )
 #define CFG_WLAN_LOGGING_NUM_BUF_MAX      ( 64 )
 #define CFG_WLAN_LOGGING_NUM_BUF_DEFAULT  ( 32 )
+
+//Number of buffers to be used for WLAN logging
+#define CFG_WLAN_PKT_STATS_NUM_BUF_NAME     "wlanPerPktStatsNumBuf"
+#define CFG_WLAN_PKT_STATS_NUM_BUF_MIN      ( 4  )
+#define CFG_WLAN_PKT_STATS_NUM_BUF_MAX      ( 64 )
+#define CFG_WLAN_PKT_STATS_NUM_BUF_DEFAULT  ( 16 )
+
 #endif //WLAN_LOGGING_SOCK_SVC_ENABLE
 
 //Enable PerPKT stats Logging
@@ -3004,6 +3011,7 @@
    v_U32_t                     wlanLoggingFEToConsole;
    v_U32_t                     wlanLoggingNumBuf;
    v_U32_t                     wlanPerPktStatsLogEnable;
+   v_U32_t                     wlanPerPktStatsNumBuf;
 #endif
    v_BOOL_t                    ignorePeerErpInfo;
    v_BOOL_t                    initialScanSkipDFSCh;
diff --git a/CORE/HDD/src/wlan_hdd_cfg.c b/CORE/HDD/src/wlan_hdd_cfg.c
index 834ff92..71fa450 100644
--- a/CORE/HDD/src/wlan_hdd_cfg.c
+++ b/CORE/HDD/src/wlan_hdd_cfg.c
@@ -3052,6 +3052,7 @@
                  CFG_WLAN_LOGGING_NUM_BUF_DEFAULT,
                  CFG_WLAN_LOGGING_NUM_BUF_MIN,
                  CFG_WLAN_LOGGING_NUM_BUF_MAX ),
+
    REG_VARIABLE( CFG_WLAN_PKT_STATS_LOGGING_NAME, WLAN_PARAM_Integer,
                  hdd_config_t, wlanPerPktStatsLogEnable,
                  VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
@@ -3059,6 +3060,13 @@
                  CFG_WLAN_PKT_STATS_LOGGING_DISABLE,
                  CFG_WLAN_PKT_STATS_LOGGING_ENABLE ),
 
+   REG_VARIABLE( CFG_WLAN_PKT_STATS_NUM_BUF_NAME, WLAN_PARAM_Integer,
+                 hdd_config_t, wlanPerPktStatsNumBuf,
+                 VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
+                 CFG_WLAN_PKT_STATS_NUM_BUF_DEFAULT,
+                 CFG_WLAN_PKT_STATS_NUM_BUF_MIN,
+                 CFG_WLAN_PKT_STATS_NUM_BUF_MAX ),
+
 #endif //WLAN_LOGGING_SOCK_SVC_ENABLE
 
    REG_VARIABLE( CFG_IGNORE_PEER_ERP_INFO_NAME, WLAN_PARAM_Integer,
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index d9b3646..eac14c7 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -5822,13 +5822,15 @@
     hddLog(LOG1, FL("flag=%d"), start_log.flag);
 
     if ((RING_ID_PER_PACKET_STATS == start_log.ringId) &&
-                 !hdd_ctx->cfg_ini->wlanPerPktStatsLogEnable)
+                 (!hdd_ctx->cfg_ini->wlanPerPktStatsLogEnable ||
+        !vos_isPktStatsEnabled()))
+
     {
        hddLog(LOGE, FL("per pkt stats not enabled"));
        return -EINVAL;
     }
-    vos_set_ring_log_level(start_log.ringId, start_log.verboseLevel);
 
+    vos_set_ring_log_level(start_log.ringId, start_log.verboseLevel);
     return 0;
 }
 
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
index d45b07d..d0d70bf 100755
--- a/CORE/HDD/src/wlan_hdd_main.c
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -10293,7 +10293,9 @@
    {
        if(wlan_logging_sock_activate_svc(
                    pHddCtx->cfg_ini->wlanLoggingFEToConsole,
-                   pHddCtx->cfg_ini->wlanLoggingNumBuf))
+                   pHddCtx->cfg_ini->wlanLoggingNumBuf,
+                   pHddCtx->cfg_ini->wlanPerPktStatsLogEnable,
+                   pHddCtx->cfg_ini->wlanPerPktStatsNumBuf))
        {
            hddLog(VOS_TRACE_LEVEL_ERROR, "%s: wlan_logging_sock_activate_svc"
                    " failed", __func__);
diff --git a/CORE/HDD/src/wlan_hdd_wext.c b/CORE/HDD/src/wlan_hdd_wext.c
index 4e676d9..2502c81 100644
--- a/CORE/HDD/src/wlan_hdd_wext.c
+++ b/CORE/HDD/src/wlan_hdd_wext.c
@@ -172,6 +172,7 @@
 #endif
 #define  WE_SET_RTS_CTS_HTVHT             21
 #define  WE_SET_MONITOR_STATE             22
+#define  WE_SET_PKT_STATS_ENABLE_DISABLE  23
 
 /* Private ioctls and their sub-ioctls */
 #define WLAN_PRIV_SET_NONE_GET_INT    (SIOCIWFIRSTPRIV + 1)
@@ -3388,7 +3389,8 @@
    hstatus = sme_GetStatistics(WLAN_HDD_GET_HAL_CTX(pAdapter),
                                eCSR_HDD,
                                SME_SUMMARY_STATS |
-                               SME_GLOBAL_CLASSA_STATS,
+                               SME_GLOBAL_CLASSA_STATS |
+                               SME_PER_PKT_STATS,
                                hdd_get_station_statisticsCB,
                                0, // not periodic
                                FALSE, //non-cached results
@@ -5914,6 +5916,38 @@
            }
            break;
         }
+        case WE_SET_PKT_STATS_ENABLE_DISABLE:
+        {
+            hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
+            tAniWifiStartLog start_log;
+            if (!pHddCtx->cfg_ini->wlanPerPktStatsLogEnable ||
+                 !vos_isPktStatsEnabled())
+            {
+                hddLog(LOGE, FL("per pkt stats not enabled"));
+                return -EINVAL;
+            }
+            hddLog(LOG1, FL("Set Pkt Stats %d"), set_value);
+
+            if (1 == set_value || 0 == set_value)
+            {
+                start_log.ringId = RING_ID_PER_PACKET_STATS;
+                start_log.flag = 0;
+                if (set_value)
+                   start_log.verboseLevel = WLAN_LOG_LEVEL_ACTIVE;
+                else
+                   start_log.verboseLevel = WLAN_LOG_LEVEL_OFF;
+
+                vos_set_ring_log_level(start_log.ringId, start_log.verboseLevel);
+            }
+            else
+            {
+                hddLog(LOGE,
+                FL("Invalid value %d in WE_SET_PKT_STATS_ENABLE_DISABLE IOCTL"),
+                    set_value);
+                ret = -EINVAL;
+            }
+            break;
+        }
 
         default:
         {
@@ -10333,7 +10367,9 @@
     {   WE_SET_RTS_CTS_HTVHT,
         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
         0, "setRtsCtsHtVht" },
-
+    {   WE_SET_PKT_STATS_ENABLE_DISABLE,
+        IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+        0, "setPktStats" },
     /* handlers for main ioctl */
     {   WLAN_PRIV_SET_NONE_GET_INT,
         0,
diff --git a/CORE/MAC/inc/sirApi.h b/CORE/MAC/inc/sirApi.h
index 5cd541f..2293f5a 100644
--- a/CORE/MAC/inc/sirApi.h
+++ b/CORE/MAC/inc/sirApi.h
@@ -2114,7 +2114,8 @@
     PE_GLOBAL_CLASS_B_STATS_INFO    = 0x00000004,
     PE_GLOBAL_CLASS_C_STATS_INFO    = 0x00000008,
     PE_GLOBAL_CLASS_D_STATS_INFO    = 0x00000010,
-    PE_PER_STA_STATS_INFO           = 0x00000020
+    PE_PER_STA_STATS_INFO           = 0x00000020,
+    PE_PER_TX_PKT_STATS_INFO        = 0x00000040,
 }ePEStatsMask;
 
 /*
@@ -2427,6 +2428,13 @@
 
 }tAniPerStaStatsInfo, *tpAniPerStaStatsInfo;
 
+typedef struct sAniPerTxPktStatsInfo
+{
+    tANI_U32 lastTxRate;       // 802.11 data rate at which the last data frame is transmitted.
+    tANI_U8  txAvgRetry;      // Average number of retries per 10 packets.
+}tAniPerTxPktStatsInfo, *tpAniPerTxPktStatsInfo;
+
+
 /**********************PE Statistics end*************************/
 
 
diff --git a/CORE/MAC/src/include/sirParams.h b/CORE/MAC/src/include/sirParams.h
index 9a54ecf..7954ce0 100644
--- a/CORE/MAC/src/include/sirParams.h
+++ b/CORE/MAC/src/include/sirParams.h
@@ -131,6 +131,7 @@
    ENHANCED_TXBD_COMPLETION = 54,
    LOGGING_ENHANCEMENT   = 55,
    MEMORY_DUMP_SUPPORTED = 57,
+   PER_PKT_STATS_SUPPORTED  = 58,
    //MAX_FEATURE_SUPPORTED = 128
 } placeHolderInCapBitmap;
 
diff --git a/CORE/MAC/src/pe/lim/limLogDump.c b/CORE/MAC/src/pe/lim/limLogDump.c
index f0a6f45..8c642b8 100644
--- a/CORE/MAC/src/pe/lim/limLogDump.c
+++ b/CORE/MAC/src/pe/lim/limLogDump.c
@@ -1516,6 +1516,8 @@
         case 5:
             statsMask = PE_PER_STA_STATS_INFO;
             break;
+        case 6:
+            statsMask = PE_PER_TX_PKT_STATS_INFO;
         default:
             return p;
     }
diff --git a/CORE/MAC/src/pe/lim/limProcessMessageQueue.c b/CORE/MAC/src/pe/lim/limProcessMessageQueue.c
index cf8a6f5..2827caa 100644
--- a/CORE/MAC/src/pe/lim/limProcessMessageQueue.c
+++ b/CORE/MAC/src/pe/lim/limProcessMessageQueue.c
@@ -683,6 +683,7 @@
  */
 
 static void 
+
 limHandle80211Frames(tpAniSirGlobal pMac, tpSirMsgQ limMsg, tANI_U8 *pDeferMsg)
 {
     tANI_U8          *pRxPacketInfo = NULL;
diff --git a/CORE/SME/inc/csrInternal.h b/CORE/SME/inc/csrInternal.h
index 5f0a66c..9ba94a5 100644
--- a/CORE/SME/inc/csrInternal.h
+++ b/CORE/SME/inc/csrInternal.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -40,6 +40,8 @@
 #define CSRINTERNAL_H__
 
 #include "vos_status.h"
+#include "vos_utils.h"
+
 #include "vos_lock.h"
 
 #include "palTimer.h"
@@ -276,6 +278,7 @@
    eCsrGlobalClassCStats,
    eCsrGlobalClassDStats,
    eCsrPerStaStats,
+   eCsrPerPktStats,
    eCsrMaxStats
 }eCsrRoamStatsClassTypes;
 
@@ -992,6 +995,7 @@
     tCsrGlobalClassCStatsInfo  classCStatsInfo;
     tCsrGlobalClassDStatsInfo  classDStatsInfo;
     tCsrPerStaStatsInfo        perStaStatsInfo[CSR_MAX_STA];
+    tPerTxPacketFrmFw          perPktStatsInfo;
     tDblLinkList  statsClientReqList;
     tDblLinkList  peStatsReqList;
     tCsrTlStatsReqInfo  tlStatsReqInfo;
diff --git a/CORE/SME/inc/sme_Api.h b/CORE/SME/inc/sme_Api.h
index ea20757..0851895 100644
--- a/CORE/SME/inc/sme_Api.h
+++ b/CORE/SME/inc/sme_Api.h
@@ -78,6 +78,7 @@
 #define SME_GLOBAL_CLASSC_STATS   8
 #define SME_GLOBAL_CLASSD_STATS  16
 #define SME_PER_STA_STATS        32
+#define SME_PER_PKT_STATS        64
 
 #define SME_INVALID_COUNTRY_CODE "XX"
 
diff --git a/CORE/SME/src/csr/csrApiRoam.c b/CORE/SME/src/csr/csrApiRoam.c
index 97d06e3..c8bcaea 100644
--- a/CORE/SME/src/csr/csrApiRoam.c
+++ b/CORE/SME/src/csr/csrApiRoam.c
@@ -15399,6 +15399,7 @@
    v_PVOID_t  pvosGCtx;
    v_S7_t     rssi = 0, snr = 0;
    tANI_U32   *pRssi = NULL, *pSnr = NULL;
+   tAniPerTxPktStatsInfo * txPacketInfo;
    tANI_U32   linkCapacity;
    pSmeStatsRsp = (tAniGetPEStatsRsp *)pSirMsg;
    if(pSmeStatsRsp->rc)
@@ -15468,6 +15469,18 @@
             pStats += sizeof(tCsrPerStaStatsInfo);
             length -= sizeof(tCsrPerStaStatsInfo);
             break;
+         case eCsrPerPktStats:
+            smsLog( pMac, LOG2, FL("csrRoamStatsRspProcessor:PerPkt stats"));
+            vos_mem_zero(&pMac->roam.perPktStatsInfo, sizeof(tPerTxPacketFrmFw));
+            if (IS_FEATURE_SUPPORTED_BY_FW(PER_PKT_STATS_SUPPORTED))
+            {
+                txPacketInfo = (tAniPerTxPktStatsInfo *)pStats;
+                pMac->roam.perPktStatsInfo.lastTxRate = txPacketInfo->lastTxRate;
+                pMac->roam.perPktStatsInfo.txAvgRetry = txPacketInfo->txAvgRetry;
+                pStats += sizeof(tAniPerTxPktStatsInfo);
+                length -= sizeof(tAniPerTxPktStatsInfo);
+            }
+            break;
          default:
             smsLog( pMac, LOGW, FL("csrRoamStatsRspProcessor:unknown stats type"));
             break;
@@ -15489,7 +15502,8 @@
        /* If riva is not sending rssi, continue to use the hack */
        rssi = RSSI_HACK_BMPS;
    }
-
+   pMac->roam.perPktStatsInfo.avgRssi = rssi;
+   vos_updatePktStatsInfo(&pMac->roam.perPktStatsInfo);
    WDA_UpdateRssiBmps(pvosGCtx, pSmeStatsRsp->staId, rssi);
 
    if (length != 0)
@@ -17198,6 +17212,12 @@
                          sizeof(tCsrPerStaStatsInfo));
             pStats += sizeof(tCsrPerStaStatsInfo);
             break;
+         case eCsrPerPktStats:
+            smsLog( pMac, LOG2, FL("PerPkt stats"));
+            vos_mem_copy( pStats, (tANI_U8 *)&pMac->roam.perPktStatsInfo,
+                         sizeof(tPerTxPacketFrmFw));
+            pStats += sizeof(tPerTxPacketFrmFw);
+            break;
          default:
             smsLog( pMac, LOGE, FL("Unknown stats type and counter %d"), counter);
             break;
diff --git a/CORE/SVC/inc/wlan_logging_sock_svc.h b/CORE/SVC/inc/wlan_logging_sock_svc.h
index 34745c5..95f278d 100644
--- a/CORE/SVC/inc/wlan_logging_sock_svc.h
+++ b/CORE/SVC/inc/wlan_logging_sock_svc.h
@@ -42,13 +42,13 @@
 
 int wlan_logging_sock_init_svc(void);
 int wlan_logging_sock_deinit_svc(void);
-int wlan_logging_sock_activate_svc(int log_fe_to_console, int num_buf);
 int wlan_logging_flush_pkt_queue(void);
 int wlan_logging_sock_deactivate_svc(void);
 int wlan_log_to_user(VOS_TRACE_LEVEL log_level, char *to_be_sent, int length);
 int wlan_queue_logpkt_for_app(vos_pkt_t *pPacket, uint32 pkt_type);
 void wlan_process_done_indication(uint8 type, uint32 reason_code);
-
+int wlan_logging_sock_activate_svc(int log_fe_to_console, int num_buf,
+                             int pkt_stats_enabled, int pkt_stats_buff);
 void wlan_init_log_completion(void);
 int wlan_set_log_completion(uint32 is_fatal,
                             uint32 indicator,
@@ -80,4 +80,9 @@
 
 bool wlan_is_logger_thread(int threadId);
 void wlan_logging_reset_thread_stuck_count(int threadId);
+int wlan_pkt_stats_to_user(void *perPktStat);
+void wlan_disable_and_flush_pkt_stats(void);
+ void wlan_fillTxStruct(void *pktStat);
+ bool wlan_isPktStatsEnabled(void);
+
 #endif /* WLAN_LOGGING_SOCK_SVC_H */
diff --git a/CORE/SVC/src/logging/wlan_logging_sock_svc.c b/CORE/SVC/src/logging/wlan_logging_sock_svc.c
index 1d8b829..a8bee4d 100644
--- a/CORE/SVC/src/logging/wlan_logging_sock_svc.c
+++ b/CORE/SVC/src/logging/wlan_logging_sock_svc.c
@@ -43,6 +43,8 @@
 #include <linux/ratelimit.h>
 #include <asm/arch_timer.h>
 #include <vos_sched.h>
+#include <vos_utils.h>
+
 
 #define LOGGING_TRACE(level, args...) \
 		VOS_TRACE(VOS_MODULE_ID_SVC, level, ## args)
@@ -55,6 +57,8 @@
 #define ANI_NL_MSG_FW_LOG_PKT_TYPE 92
 #define INVALID_PID -1
 
+#define MAX_PKTSTATS_LOG_LENGTH 2048
+#define HOST_PKT_STATS_POST_MASK 0x004
 #define MAX_LOGMSG_LENGTH 4096
 #define LOGGER_MGMT_DATA_PKT_POST_MASK   0x001
 #define HOST_LOG_POST_MASK   0x002
@@ -71,6 +75,9 @@
 
 #define NL_BDCAST_RATELIMIT_INTERVAL (5*HZ)
 #define NL_BDCAST_RATELIMIT_BURST    1
+#define PTT_MSG_DIAG_CMDS_TYPE   0x5050
+#define DIAG_TYPE_LOGS   1
+
 
 /* Qtimer Frequency */
 #define QTIMER_FREQ      19200000
@@ -122,6 +129,17 @@
 	struct completion fw_mem_copy_to_user_completion;
 };
 
+struct pkt_stats_msg {
+	struct list_head node;
+	/* indicates the current filled log length in pktlogbuf */
+	struct sk_buff *skb;
+};
+
+struct perPktStatsInfo{
+    v_U32_t lastTxRate;           // 802.11 data rate at which the last data frame is transmitted.
+    v_U8_t  txAvgRetry;           // Average number of retries per 10 packets.
+    v_S7_t  avgRssi;              // Average of the Beacon RSSI.
+};
 
 struct wlan_logging {
 	/* Log Fatal and ERROR to console */
@@ -178,10 +196,21 @@
 	struct logger_log_complete log_complete;
 	spinlock_t bug_report_lock;
 	struct fw_mem_dump_logging fw_mem_dump_ctx;
+        int pkt_stat_num_buf;
+	unsigned int pkt_stat_drop_cnt;
+	struct list_head pkt_stat_free_list;
+	struct list_head pkt_stat_filled_list;
+	struct pkt_stats_msg *pkt_stats_pcur_node;
+	/* Index of the messages sent to userspace */
+	unsigned int pkt_stats_msg_idx;
+	bool pkt_stats_enabled;
+	spinlock_t pkt_stats_lock;
+	struct perPktStatsInfo txPktStatsInfo;
 };
 
 static struct wlan_logging gwlan_logging;
 static struct log_msg *gplog_msg;
+static struct pkt_stats_msg *pkt_stats_buffers;
 
 /* PID of the APP to log the message */
 static int gapp_pid = INVALID_PID;
@@ -367,6 +396,171 @@
 	return ret;
 }
 
+void wlan_fillTxStruct(void *pktStat)
+{
+	vos_mem_copy(&gwlan_logging.txPktStatsInfo,
+		(struct perPktStatsInfo *)pktStat,
+		sizeof(struct perPktStatsInfo));
+}
+
+bool wlan_isPktStatsEnabled(void)
+{
+	return gwlan_logging.pkt_stats_enabled;
+}
+
+
+
+/* Need to call this with spin_lock acquired */
+static int wlan_queue_pkt_stats_for_app(void)
+{
+	int ret = 0;
+
+	list_add_tail(&gwlan_logging.pkt_stats_pcur_node->node,
+			&gwlan_logging.pkt_stat_filled_list);
+
+	if (!list_empty(&gwlan_logging.pkt_stat_free_list)) {
+		/* Get buffer from free list */
+		gwlan_logging.pkt_stats_pcur_node =
+			(struct pkt_stats_msg *)(gwlan_logging.pkt_stat_free_list.next);
+		list_del_init(gwlan_logging.pkt_stat_free_list.next);
+	} else if (!list_empty(&gwlan_logging.pkt_stat_filled_list)) {
+		/* Get buffer from filled list */
+		/* This condition will drop the packet from being
+		 * indicated to app
+		 */
+		gwlan_logging.pkt_stats_pcur_node =
+			(struct pkt_stats_msg *)(gwlan_logging.pkt_stat_filled_list.next);
+		++gwlan_logging.pkt_stat_drop_cnt;
+		/* print every 64th drop count */
+		if (vos_is_multicast_logging() &&
+			(!(gwlan_logging.pkt_stat_drop_cnt % 0x40))) {
+			pr_err("%s: drop_count = %u  filled_length = %d\n",
+				__func__, gwlan_logging.pkt_stat_drop_cnt,
+				gwlan_logging.pkt_stats_pcur_node->skb->len);
+		}
+		list_del_init(gwlan_logging.pkt_stat_filled_list.next);
+		ret = 1;
+	}
+
+	/* Reset the current node values */
+	gwlan_logging.pkt_stats_pcur_node-> skb->len = 0;
+	return ret;
+}
+
+int wlan_pkt_stats_to_user(void *perPktStat)
+{
+	bool wake_up_thread = false;
+	tPerPacketStats *pktstats = perPktStat;
+	unsigned long flags;
+	tx_rx_pkt_stats rx_tx_stats;
+	int total_log_len = 0;
+	struct sk_buff *ptr;
+	tpSirMacMgmtHdr hdr;
+	uint32 rateIdx;
+
+	if (!vos_is_multicast_logging())
+	{
+		return -EIO;
+	}
+	if (vos_is_multicast_logging()) {
+
+	vos_mem_zero(&rx_tx_stats, sizeof(tx_rx_pkt_stats));
+
+	if (pktstats->is_rx){
+		rx_tx_stats.ps_hdr.flags = (1 << PKTLOG_FLG_FRM_TYPE_REMOTE_S);
+	}else{
+		rx_tx_stats.ps_hdr.flags = (1 << PKTLOG_FLG_FRM_TYPE_LOCAL_S);
+
+	}
+	/*Send log type as PKTLOG_TYPE_PKT_STAT (9)*/
+	rx_tx_stats.ps_hdr.log_type = PKTLOG_TYPE_PKT_STAT;
+	rx_tx_stats.ps_hdr.timestamp = vos_timer_get_system_ticks();
+	rx_tx_stats.ps_hdr.missed_cnt = 0;
+	rx_tx_stats.ps_hdr.size = sizeof(tx_rx_pkt_stats) -
+				sizeof(pkt_stats_hdr) + pktstats->data_len - IP_PLUS_80211_HDR_LEN;
+
+	rx_tx_stats.stats.flags |= PER_PACKET_ENTRY_FLAGS_TX_SUCCESS;
+	rx_tx_stats.stats.flags |= PER_PACKET_ENTRY_FLAGS_80211_HEADER;
+	if (pktstats->is_rx)
+		rx_tx_stats.stats.flags |= PER_PACKET_ENTRY_FLAGS_DIRECTION_TX;
+
+	hdr = (tpSirMacMgmtHdr)pktstats->data;
+	if (hdr->fc.wep)
+	   rx_tx_stats.stats.flags |= PER_PACKET_ENTRY_FLAGS_PROTECTED;
+
+	rx_tx_stats.stats.tid = pktstats->tid;
+	rx_tx_stats.stats.dxe_timestamp = pktstats->dxe_timestamp;
+
+	if (!pktstats->is_rx)
+	{
+		rx_tx_stats.stats.rssi = gwlan_logging.txPktStatsInfo.avgRssi;
+		rx_tx_stats.stats.num_retries = gwlan_logging.txPktStatsInfo.txAvgRetry;
+		rateIdx = gwlan_logging.txPktStatsInfo.lastTxRate;
+	}
+	else
+	{
+		rx_tx_stats.stats.rssi = pktstats->rssi;
+		rx_tx_stats.stats.num_retries = pktstats->num_retries;
+		rateIdx = pktstats->rate_idx;
+
+	}
+	rx_tx_stats.stats.link_layer_transmit_sequence = pktstats->seq_num;
+
+	/* Calculate rate and MCS from rate index */
+	if( rateIdx >= 210 && rateIdx <= 217)
+		rateIdx-=202;
+	if( rateIdx >= 218 && rateIdx <= 225 )
+		rateIdx-=210;
+	get_rate_and_MCS(&rx_tx_stats.stats, rateIdx);
+
+	vos_mem_copy(rx_tx_stats.stats.data,pktstats->data, pktstats->data_len);
+
+	/* 1+1 indicate '\n'+'\0' */
+	total_log_len = sizeof(tx_rx_pkt_stats) + pktstats->data_len - IP_PLUS_80211_HDR_LEN;
+	spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags);
+	// wlan logging svc resources are not yet initialized
+	if (!gwlan_logging.pkt_stats_pcur_node) {
+		pr_err("%s, logging svc not initialized", __func__);
+		spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
+		return -EIO;
+	}
+
+	;
+
+	 /* Check if we can accomodate more log into current node/buffer */
+	if (total_log_len + sizeof(vos_log_pktlog_info) + sizeof(tAniNlHdr) >=
+		skb_tailroom(gwlan_logging.pkt_stats_pcur_node->skb)) {
+		wake_up_thread = true;
+		wlan_queue_pkt_stats_for_app();
+	}
+	ptr = gwlan_logging.pkt_stats_pcur_node->skb;
+
+
+	vos_mem_copy(skb_put(ptr, total_log_len), &rx_tx_stats, total_log_len);
+	spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
+	/* Wakeup logger thread */
+	if ((true == wake_up_thread)) {
+			/* If there is logger app registered wakeup the logging
+			* thread
+			*/
+			set_bit(HOST_PKT_STATS_POST_MASK, &gwlan_logging.event_flag);
+			wake_up_interruptible(&gwlan_logging.wait_queue);
+		}
+	}
+	return 0;
+}
+
+void wlan_disable_and_flush_pkt_stats()
+{
+	unsigned long flags;
+	spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags);
+	if(gwlan_logging.pkt_stats_pcur_node->skb->len){
+		wlan_queue_pkt_stats_for_app();
+	}
+	spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
+	set_bit(HOST_PKT_STATS_POST_MASK, &gwlan_logging.event_flag);
+	wake_up_interruptible(&gwlan_logging.wait_queue);
+}
 
 int wlan_log_to_user(VOS_TRACE_LEVEL log_level, char *to_be_sent, int length)
 {
@@ -828,6 +1022,116 @@
 	return ret;
 }
 
+
+static int send_per_pkt_stats_to_user(void)
+{
+	int ret = -1;
+	struct pkt_stats_msg *plog_msg;
+	unsigned long flags;
+	struct sk_buff *skb_new = NULL;
+	vos_log_pktlog_info pktlog;
+	tAniNlHdr msg_header;
+	int extra_header_len, nl_payload_len;
+	static int nlmsg_seq;
+	static int rate_limit;
+	int diag_type;
+
+	while (!list_empty(&gwlan_logging.pkt_stat_filled_list)
+		&& !gwlan_logging.exit) {
+		skb_new= dev_alloc_skb(MAX_PKTSTATS_LOG_LENGTH);
+		if (skb_new == NULL) {
+			if (!rate_limit) {
+				pr_err("%s: dev_alloc_skb() failed for msg size[%d] drop count = %u\n",
+					__func__, MAX_LOGMSG_LENGTH,
+					gwlan_logging.drop_count);
+			}
+			rate_limit = 1;
+			ret = -ENOMEM;
+			break;
+		}
+
+		spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags);
+
+		plog_msg = (struct pkt_stats_msg *)
+			(gwlan_logging.pkt_stat_filled_list.next);
+		list_del_init(gwlan_logging.pkt_stat_filled_list.next);
+		spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
+
+		vos_mem_zero(&pktlog, sizeof(vos_log_pktlog_info));
+		vos_log_set_code(&pktlog, LOG_WLAN_PKT_LOG_INFO_C);
+
+		pktlog.version = VERSION_LOG_WLAN_PKT_LOG_INFO_C;
+		pktlog.buf_len = plog_msg->skb->len;
+		vos_log_set_length(&pktlog.log_hdr, plog_msg->skb->len +
+					sizeof(vos_log_pktlog_info));
+		pktlog.seq_no = gwlan_logging.pkt_stats_msg_idx++;
+
+		if (unlikely(skb_headroom(plog_msg->skb) < sizeof(vos_log_pktlog_info))) {
+			pr_err("VPKT [%d]: Insufficient headroom, head[%p],"
+				" data[%p], req[%zu]", __LINE__, plog_msg->skb->head,
+				plog_msg->skb->data, sizeof(msg_header));
+			ret = -EIO;
+			goto err;
+		}
+		vos_mem_copy(skb_push(plog_msg->skb, sizeof(vos_log_pktlog_info)), &pktlog,
+							sizeof(vos_log_pktlog_info));
+
+		if (unlikely(skb_headroom(plog_msg->skb) < sizeof(int))) {
+			pr_err("VPKT [%d]: Insufficient headroom, head[%p],"
+				" data[%p], req[%zu]", __LINE__, plog_msg->skb->head,
+				plog_msg->skb->data, sizeof(int));
+			ret = -EIO;
+			goto err;
+		}
+
+		diag_type = DIAG_TYPE_LOGS;
+		vos_mem_copy(skb_push(plog_msg->skb, sizeof(int)), &diag_type,
+									 sizeof(int));
+
+		extra_header_len = sizeof(msg_header.radio) + sizeof(tAniHdr);
+		nl_payload_len = NLMSG_ALIGN(extra_header_len + plog_msg->skb->len);
+
+		msg_header.nlh.nlmsg_type = ANI_NL_MSG_PUMAC;
+		msg_header.nlh.nlmsg_len = nl_payload_len;
+		msg_header.nlh.nlmsg_flags = NLM_F_REQUEST;
+		msg_header.nlh.nlmsg_pid = 0;
+		msg_header.nlh.nlmsg_seq = nlmsg_seq++;
+
+		msg_header.radio = 0;
+
+		msg_header.wmsg.type = PTT_MSG_DIAG_CMDS_TYPE;
+		msg_header.wmsg.length = plog_msg->skb->len;
+
+		if (unlikely(skb_headroom(plog_msg->skb) < sizeof(msg_header))) {
+			pr_err("VPKT [%d]: Insufficient headroom, head[%p],"
+				" data[%p], req[%zu]", __LINE__, plog_msg->skb->head,
+				plog_msg->skb->data, sizeof(msg_header));
+			ret = -EIO;
+			goto err;
+		}
+
+		vos_mem_copy(skb_push(plog_msg->skb, sizeof(msg_header)), &msg_header,
+							sizeof(msg_header));
+
+		ret = nl_srv_bcast(plog_msg->skb);
+		if (ret < 0) {
+			pr_info("%s: Send Failed %d drop_count = %u\n",
+				__func__, ret, ++gwlan_logging.fw_log_pkt_drop_cnt);
+		} else {
+			ret = 0;
+		}
+err:
+		spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags);
+		plog_msg->skb = skb_new;
+		list_add_tail(&plog_msg->node,
+				&gwlan_logging.pkt_stat_free_list);
+		spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags);
+		ret = 0;
+	}
+
+	return ret;
+}
+
 /**
  * wlan_logging_detect_thread_stuck_cb()- Call back of the
  * thread stuck timer to detect thread stuck
@@ -918,8 +1222,9 @@
 		   test_bit(LOGGER_FATAL_EVENT_POST_MASK,
 						&gwlan_logging.event_flag) ||
 		   test_bit(LOGGER_FW_MEM_DUMP_PKT_POST_MASK,&gwlan_logging.event_flag) ||
-		   test_bit(LOGGER_FW_MEM_DUMP_PKT_POST_DONE_MASK, &gwlan_logging.event_flag)));
-
+		   test_bit(LOGGER_FW_MEM_DUMP_PKT_POST_DONE_MASK, &gwlan_logging.event_flag)||
+		   test_bit(HOST_PKT_STATS_POST_MASK,
+						 &gwlan_logging.event_flag)));
 
 		if (ret_wait_status == -ERESTARTSYS) {
 			pr_err("%s: wait_event return -ERESTARTSYS", __func__);
@@ -973,6 +1278,10 @@
 				wlan_indicate_mem_dump_complete(true);
 		}
 
+		if (test_and_clear_bit(HOST_PKT_STATS_POST_MASK,
+			&gwlan_logging.event_flag)) {
+			send_per_pkt_stats_to_user();
+		}
 	}
 
 	vos_timer_destroy(&gwlan_logging.threadStuckTimer);
@@ -1098,10 +1407,15 @@
 }
 
 
-int wlan_logging_sock_activate_svc(int log_fe_to_console, int num_buf)
+int wlan_logging_sock_activate_svc(int log_fe_to_console, int num_buf,
+								int pkt_stats_enabled, int pkt_stats_buff)
 {
-	int i = 0;
+	int i, j = 0;
 	unsigned long irq_flag;
+	bool failure = FALSE;
+
+	pr_info("%s: Initalizing FEConsoleLog = %d NumBuff = %d\n",
+			__func__, log_fe_to_console, num_buf);
 
 	gapp_pid = INVALID_PID;
 
@@ -1129,13 +1443,60 @@
 		(gwlan_logging.free_list.next);
 	list_del_init(gwlan_logging.free_list.next);
 	spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag);
+	if(pkt_stats_enabled)
+	{
+		pr_info("%s: Initalizing Pkt stats pkt_stats_buff = %d\n",
+			__func__, pkt_stats_buff);
+		pkt_stats_buffers = (struct pkt_stats_msg *) kzalloc(
+			 pkt_stats_buff * sizeof(struct pkt_stats_msg), GFP_KERNEL);
+		if (!pkt_stats_buffers) {
+			pr_err("%s: Could not allocate memory for Pkt stats\n", __func__);
+			failure = TRUE;
+			goto err;
+		}
 
+		gwlan_logging.pkt_stat_num_buf = pkt_stats_buff;
+
+		gwlan_logging.pkt_stats_msg_idx = 0;
+		INIT_LIST_HEAD(&gwlan_logging.pkt_stat_free_list);
+		INIT_LIST_HEAD(&gwlan_logging.pkt_stat_filled_list);
+
+		for (i = 0; i < pkt_stats_buff; i++) {
+			pkt_stats_buffers[i].skb= dev_alloc_skb(MAX_PKTSTATS_LOG_LENGTH);
+			if (pkt_stats_buffers[i].skb == NULL)
+			{
+				pr_err("%s: Memory alloc failed for skb",__func__);
+				/* free previously allocated skb and return;*/
+				for (j = 0; j<i ; j++)
+				{
+					dev_kfree_skb(pkt_stats_buffers[j].skb);
+				}
+			spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag);
+			vos_mem_free(pkt_stats_buffers);
+			pkt_stats_buffers = NULL;
+			spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag);
+			failure = TRUE;
+			goto err;
+			}
+			list_add(&pkt_stats_buffers[i].node,
+								&gwlan_logging.pkt_stat_free_list);
+
+		}
+		gwlan_logging.pkt_stats_pcur_node = (struct pkt_stats_msg *)
+			(gwlan_logging.pkt_stat_free_list.next);
+		list_del_init(gwlan_logging.pkt_stat_free_list.next);
+		gwlan_logging.pkt_stats_enabled = TRUE;
+	}
+err:
+	if (failure)
+	gwlan_logging.pkt_stats_enabled = false;
 	init_waitqueue_head(&gwlan_logging.wait_queue);
 	gwlan_logging.exit = false;
 	clear_bit(HOST_LOG_POST_MASK, &gwlan_logging.event_flag);
 	clear_bit(LOGGER_MGMT_DATA_PKT_POST_MASK, &gwlan_logging.event_flag);
 	clear_bit(LOGGER_FW_LOG_PKT_POST_MASK, &gwlan_logging.event_flag);
 	clear_bit(LOGGER_FATAL_EVENT_POST_MASK, &gwlan_logging.event_flag);
+        clear_bit(HOST_PKT_STATS_POST_MASK, &gwlan_logging.event_flag);
 	init_completion(&gwlan_logging.shutdown_comp);
 	gwlan_logging.thread = kthread_create(wlan_logging_thread, NULL,
 					"wlan_logging_thread");
@@ -1207,6 +1568,7 @@
 int wlan_logging_sock_deactivate_svc(void)
 {
 	unsigned long irq_flag;
+	int i;
 
 	if (!gplog_msg)
 		return 0;
@@ -1228,6 +1590,20 @@
 	gwlan_logging.pcur_node = NULL;
 	spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag);
 
+	spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag);
+	/* free allocated skb */
+	for (i = 0; i < gwlan_logging.pkt_stat_num_buf; i++)
+	{
+		if (pkt_stats_buffers[i].skb)
+			dev_kfree_skb(pkt_stats_buffers[i].skb);
+	}
+	if(pkt_stats_buffers)
+		vos_mem_free(pkt_stats_buffers);
+	pkt_stats_buffers = NULL;
+	gwlan_logging.pkt_stats_pcur_node = NULL;
+	gwlan_logging.pkt_stats_enabled = false;
+	spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag);
+
 	wlan_logging_flush_pkt_queue();
 
 	return 0;
@@ -1239,8 +1615,10 @@
 	spin_lock_init(&gwlan_logging.data_mgmt_pkt_lock);
 	spin_lock_init(&gwlan_logging.fw_log_pkt_lock);
 	spin_lock_init(&gwlan_logging.fw_mem_dump_ctx.fw_mem_dump_lock);
+	spin_lock_init(&gwlan_logging.pkt_stats_lock);
 	gapp_pid = INVALID_PID;
 	gwlan_logging.pcur_node = NULL;
+	gwlan_logging.pkt_stats_pcur_node= NULL;
 
 	wlan_init_log_completion();
 
@@ -1250,6 +1628,7 @@
 int wlan_logging_sock_deinit_svc(void)
 {
 	gwlan_logging.pcur_node = NULL;
+	gwlan_logging.pkt_stats_pcur_node = NULL;
 	gapp_pid = INVALID_PID;
 
 	wlan_deinit_log_completion();
diff --git a/CORE/VOSS/inc/event_defs.h b/CORE/VOSS/inc/event_defs.h
index 4d2ba20..38a1694 100644
--- a/CORE/VOSS/inc/event_defs.h
+++ b/CORE/VOSS/inc/event_defs.h
@@ -1903,7 +1903,6 @@
   EVENT_SNS_DRV_OPMODE_CHANGE = 0x768,
   EVENT_WLAN_EAPOL = 0xA8D,/* 18 bytes payload */
   EVENT_WLAN_WAKE_LOCK = 0xAA2, /* 96 bytes payload */
-
   EVENT_NEXT_UNUSED_EVENT,
   EVENT_RSVD_START = 0x0800,
   EVENT_RSVD_END   = 0x083F,
diff --git a/CORE/VOSS/inc/log_codes.h b/CORE/VOSS/inc/log_codes.h
index d5e4e9e..250727d 100644
--- a/CORE/VOSS/inc/log_codes.h
+++ b/CORE/VOSS/inc/log_codes.h
@@ -2010,8 +2010,11 @@
 
 #define LOG_TRSP_DATA_STALL_C                                       ((0x801) + LOG_1X_BASE_C)
 
+#define LOG_WLAN_PKT_LOG_INFO_C                                     ((0x8E0) + LOG_1X_BASE_C)
+
+
 /* The last defined DMSS log code */
-#define LOG_1X_LAST_C                                   ((0x801) + LOG_1X_BASE_C)
+#define LOG_1X_LAST_C                                   ((0x8E0) + LOG_1X_BASE_C)
 
 
 /* This is only here for old (pre equipment ID update) logging code */
diff --git a/CORE/VOSS/inc/vos_api.h b/CORE/VOSS/inc/vos_api.h
index 2cd0e03..99746e5 100644
--- a/CORE/VOSS/inc/vos_api.h
+++ b/CORE/VOSS/inc/vos_api.h
@@ -483,8 +483,12 @@
 v_U8_t vos_is_multicast_logging(void);
 void vos_set_ring_log_level(v_U32_t ring_id, v_U32_t log_level);
 v_U8_t vos_get_ring_log_level(v_U32_t ring_id);
+void get_rate_and_MCS(per_packet_stats *stats, uint32 rateindex);
+
 v_BOOL_t vos_isUnloadInProgress(void);
 v_BOOL_t vos_isLoadUnloadInProgress(void);
 
 void vos_probe_threads(void);
+void vos_per_pkt_stats_to_user(void *perPktStat);
+void vos_updatePktStatsInfo(void * pktStat);
 #endif // if !defined __VOS_NVITEM_H
diff --git a/CORE/VOSS/inc/vos_diag_core_log.h b/CORE/VOSS/inc/vos_diag_core_log.h
index 9a95c4a..f400dd5 100644
--- a/CORE/VOSS/inc/vos_diag_core_log.h
+++ b/CORE/VOSS/inc/vos_diag_core_log.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -65,6 +65,86 @@
 #define VOS_LOG_MAX_NUM_HO_CANDIDATE_APS                    20
 #define VOS_LOG_MAX_WOW_PTRN_SIZE                           128
 #define VOS_LOG_MAX_WOW_PTRN_MASK_SIZE                      16
+/*802.11 Header for management packets and 802.11 plus IP header for Data packets*/
+# define IP_PLUS_80211_HDR_LEN                              52
+/* Version to be updated whenever format of vos_log_pktlog_info changes */
+#define VERSION_LOG_WLAN_PKT_LOG_INFO_C                     1
+
+enum {
+   PKTLOG_FLG_FRM_TYPE_LOCAL_S = 0,
+   PKTLOG_FLG_FRM_TYPE_REMOTE_S,
+   PKTLOG_FLG_FRM_TYPE_UNKNOWN_S
+};
+
+/* Format of the packet stats event*/
+typedef struct {
+   v_U16_t flags;
+   v_U16_t missed_cnt;
+   v_U16_t log_type;
+   v_U16_t size;
+   v_U32_t timestamp;
+}__attribute__((packed))pkt_stats_hdr ;
+
+/* Per packet data info */
+#define PER_PACKET_ENTRY_FLAGS_DIRECTION_TX  1    // 0: TX, 1: RX
+#define PER_PACKET_ENTRY_FLAGS_TX_SUCCESS    2    // whether packet was transmitted or
+                                                  // received/decrypted successfully
+#define PER_PACKET_ENTRY_FLAGS_80211_HEADER  4    // has full 802.11 header, else has 802.3 header
+#define PER_PACKET_ENTRY_FLAGS_PROTECTED     8    // whether packet was encrypted
+#define STATS_MAX_RATE_INDEX      136
+
+
+enum {
+   S_BW20,
+   S_BW40,
+   S_BW80,
+   S_BW160
+};
+enum {
+   PREAMBLE_CCK,
+   PREAMBLE_OFDM,
+   PREAMBLE_HT,
+   PREAMBLE_VHT
+};
+
+typedef struct{
+   v_U16_t rate;
+   v_U16_t preamble;
+   v_U8_t bw;
+   v_U8_t short_gi;
+}rateidx_to_rate_bw_preamble_sgi;
+
+
+typedef struct {
+   v_U16_t rate       :  4;
+   v_U16_t nss        :  2;
+   v_U16_t preamble   :  2;
+   v_U16_t bw         :  2;
+   v_U16_t short_gi   :  1;
+   v_U16_t reserved   :  5;
+} mcs_stats;
+
+typedef struct {
+   v_U8_t  flags;
+   v_U8_t  tid;     // transmit or received tid
+   mcs_stats MCS;    // modulation and bandwidth
+   v_S7_t  rssi;    // TX: RSSI of ACK for that packet
+                // RX: RSSI of packet
+   v_U8_t  num_retries;                   // number of attempted retries
+   v_U16_t last_transmit_rate;           // last transmit rate in .5 mbps
+   v_U16_t link_layer_transmit_sequence; // receive sequence for that MPDU packet
+   v_U64_t dxe_timestamp;     // DXE timestamp
+   v_U64_t start_contention_timestamp; // 0 Not supported
+   v_U64_t transmit_success_timestamp; // 0 Not Supported
+   v_U8_t data[IP_PLUS_80211_HDR_LEN]; // 802.11 Header for management packets and 802.11 plus IP header for Data packets
+} __attribute__((packed)) per_packet_stats;
+
+typedef struct
+{
+   pkt_stats_hdr ps_hdr;
+   per_packet_stats stats;
+}tx_rx_pkt_stats;
+
 
 /*---------------------------------------------------------------------------
    This packet contains the scan results of the recent scan operation 
@@ -367,6 +447,23 @@
   v_S7_t            rssi;
 } vos_log_rssi_pkt_type;
 
+/**
+ * struct vos_log_pktlog_info - Packet log info
+ * @log_hdr: Log header
+ * @buf_len: Length of the buffer that follows
+ * @buf:     Buffer containing the packet log info
+ *
+ * Structure containing the packet log information
+ * LOG_WLAN_PKT_LOG_INFO_C          0x18E0
+ */
+typedef struct
+{
+  log_hdr_type log_hdr;
+  uint32_t version;
+  uint32_t seq_no;
+  uint32_t buf_len;
+}__attribute__((packed))vos_log_pktlog_info;
+
 /*------------------------------------------------------------------------- 
   Function declarations and documenation
   ------------------------------------------------------------------------*/
diff --git a/CORE/VOSS/inc/vos_utils.h b/CORE/VOSS/inc/vos_utils.h
index 5755336..814eb2e 100644
--- a/CORE/VOSS/inc/vos_utils.h
+++ b/CORE/VOSS/inc/vos_utils.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -59,6 +59,13 @@
 #define VOS_BAND_5GHZ          2
 
 #define VOS_24_GHZ_CHANNEL_14  14
+
+
+/* Type of packet log events.
+ */
+#define PKTLOG_TYPE_PKT_STAT         9
+
+
 /*-------------------------------------------------------------------------- 
   Type declarations
   ------------------------------------------------------------------------*/
@@ -165,6 +172,25 @@
 void vos_get_wlan_unsafe_channel(v_U16_t *unsafeChannelList,
                     v_U16_t buffer_size, v_U16_t *unsafeChannelCount);
 
+typedef struct {
+    v_BOOL_t  is_rx;
+    v_U8_t  tid;     // transmit or received tid
+    v_U8_t  num_retries;                   // number of attempted retries
+    v_U8_t  rssi;    // TX: RSSI of ACK for that packet
+                    // RX: RSSI of packet
+    v_U32_t rate_idx;           // last transmit rate in .5 mbps
+    v_U16_t seq_num; // receive sequence for that MPDU packet
+    v_U64_t dxe_timestamp;     // DXE timestamp
+    v_U32_t data_len;
+    v_U8_t data[52]; // 802.11 Header for management packets and 802.11 plus IP header for Data packets
+} tPerPacketStats;
+
+typedef struct {
+    v_U32_t lastTxRate;           // 802.11 data rate at which the last data frame is transmitted.
+    v_U8_t  txAvgRetry;           // Average number of retries per 10 packets.
+    v_S7_t  avgRssi;              // Average of the Beacon RSSI.
+} tPerTxPacketFrmFw;
+
 #define ROAM_DELAY_TABLE_SIZE   10
 
 enum e_roaming_event
@@ -293,4 +319,8 @@
 void    vos_reset_roam_timer_log(void);
 void    vos_dump_roam_time_log_service(void);
 void    vos_record_roam_event(enum e_roaming_event, void *pBuff, v_ULONG_t buff_len);
+v_U32_t vos_copy_80211_header(void *pBuff, v_U8_t *dst, v_U8_t frametype,
+                              v_U8_t Qos);
+extern  v_U8_t vos_get_ring_log_level(v_U32_t ring_id);
+bool vos_isPktStatsEnabled(void);
 #endif // #if !defined __VOSS_UTILS_H
diff --git a/CORE/VOSS/src/vos_api.c b/CORE/VOSS/src/vos_api.c
index 2bd28d9..9bb72ad 100644
--- a/CORE/VOSS/src/vos_api.c
+++ b/CORE/VOSS/src/vos_api.c
@@ -69,6 +69,7 @@
 #include "wlan_hdd_main.h"
 #include <linux/vmalloc.h>
 #include "wlan_hdd_cfg80211.h"
+#include "vos_diag_core_log.h"
 
 #include <linux/wcnss_wlan.h>
 
@@ -1854,6 +1855,29 @@
 #endif
 }
 
+void vos_per_pkt_stats_to_user(void *perPktStat)
+{
+#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE
+     wlan_pkt_stats_to_user(perPktStat);
+#else
+     return;
+#endif
+
+
+
+}
+
+void vos_updatePktStatsInfo(void * pktStat)
+{
+#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE
+     wlan_fillTxStruct(pktStat);
+#else
+     return;
+#endif
+
+}
+
+
 /**---------------------------------------------------------------------------
   
   \brief vos_mq_post_message() - post a message to a message queue
@@ -2981,6 +3005,9 @@
         return;
     } else if (ring_id == RING_ID_PER_PACKET_STATS) {
         vos_context->packet_stats_log_level = log_val;
+        if (WLAN_LOG_LEVEL_ACTIVE != log_val)
+            wlan_disable_and_flush_pkt_stats();
+
         return;
     }
 }
@@ -3012,3 +3039,170 @@
 
     return WLAN_LOG_LEVEL_OFF;
 }
+
+/* elements are rate, preamable, bw, short_gi */
+rateidx_to_rate_bw_preamble_sgi   rateidx_to_rate_bw_preamble_sgi_table[] =
+{
+/*11B CCK Long preamble (0-3)*/
+{ 10, PREAMBLE_CCK, S_BW20, 0},{ 20, PREAMBLE_CCK, S_BW20, 0},
+{ 55, PREAMBLE_CCK, S_BW20, 0},{ 110, PREAMBLE_CCK, S_BW20, 0},
+/*11B CCK Short preamble (4-7)*/
+{ 10, PREAMBLE_CCK, S_BW20, 0},{ 20, PREAMBLE_CCK, S_BW20, 0},
+{ 55, PREAMBLE_CCK, S_BW20, 0},{ 110, PREAMBLE_CCK, S_BW20, 0},
+/*11G/A (8-15)*/
+{ 60, PREAMBLE_OFDM, S_BW20, 0},{ 90, PREAMBLE_OFDM, S_BW20, 0},
+{ 120, PREAMBLE_OFDM, S_BW20, 0},{ 180, PREAMBLE_OFDM, S_BW20, 0},
+{ 240, PREAMBLE_OFDM, S_BW20, 0},{ 360, PREAMBLE_OFDM, S_BW20, 0},
+{ 480, PREAMBLE_OFDM, S_BW20, 0},{ 540, PREAMBLE_OFDM, S_BW20, 0},
+/*HT20 LGI MCS 0-7 (16-23)*/
+{ 65, PREAMBLE_HT, S_BW20, 0},{ 130, PREAMBLE_HT, S_BW20, 0},
+{ 195, PREAMBLE_HT, S_BW20, 0},{ 260, PREAMBLE_HT, S_BW20, 0},
+{ 390, PREAMBLE_HT, S_BW20, 0},{ 520, PREAMBLE_HT, S_BW20, 0},
+{ 585, PREAMBLE_HT, S_BW20, 0},{ 650, PREAMBLE_HT, S_BW20, 0},
+/*HT20 SGI MCS 0-7 (24-31)*/
+{ 72, PREAMBLE_HT, S_BW20, 1},{ 144, PREAMBLE_HT, S_BW20, 1},
+{ 217, PREAMBLE_HT, S_BW20, 1},{ 289, PREAMBLE_HT, S_BW20, 1},
+{ 433, PREAMBLE_HT, S_BW20, 1},{ 578, PREAMBLE_HT, S_BW20, 1},
+{ 650, PREAMBLE_HT, S_BW20, 1},{ 722, PREAMBLE_HT, S_BW20, 1},
+/*HT20 Greenfield MCS 0-7 rates (32-39)*/
+{ 65, PREAMBLE_HT, S_BW20, 0},{ 130, PREAMBLE_HT, S_BW20, 0},
+{ 195, PREAMBLE_HT, S_BW20, 0},{ 260, PREAMBLE_HT, S_BW20, 0},
+{ 390, PREAMBLE_HT, S_BW20, 0},{ 520, PREAMBLE_HT, S_BW20, 0},
+{ 585, PREAMBLE_HT, S_BW20, 0},{ 650, PREAMBLE_HT, S_BW20, 0},
+/*HT40 LGI MCS 0-7 (40-47)*/
+{ 135, PREAMBLE_HT, S_BW40, 0},{ 270, PREAMBLE_HT, S_BW40, 0},
+{ 405, PREAMBLE_HT, S_BW40, 0},{ 540, PREAMBLE_HT, S_BW40, 0},
+{ 810, PREAMBLE_HT, S_BW40, 0},{ 1080, PREAMBLE_HT, S_BW40, 0},
+{ 1215, PREAMBLE_HT, S_BW40, 0},{ 1350, PREAMBLE_HT, S_BW40, 0},
+/*HT40 SGI MCS 0-7 (48-55)*/
+{ 150, PREAMBLE_HT, S_BW40, 1},{ 300, PREAMBLE_HT, S_BW40, 1},
+{ 450, PREAMBLE_HT, S_BW40, 1},{ 600, PREAMBLE_HT, S_BW40, 1},
+{ 900, PREAMBLE_HT, S_BW40, 1},{ 1200, PREAMBLE_HT, S_BW40, 1},
+{ 1350, PREAMBLE_HT, S_BW40, 1},{ 1500, PREAMBLE_HT, S_BW40, 1},
+/*HT40 Greenfield MCS 0-7 rates (56-63) 64-65 are dummy*/
+{ 135, PREAMBLE_HT, S_BW40, 0},{ 270, PREAMBLE_HT, S_BW40, 0},
+{ 405, PREAMBLE_HT, S_BW40, 0},{ 540, PREAMBLE_HT, S_BW40, 0},
+{ 810, PREAMBLE_HT, S_BW40, 0},{ 1080, PREAMBLE_HT, S_BW40, 0},
+{ 1215, PREAMBLE_HT, S_BW40, 0},{ 1350, PREAMBLE_HT, S_BW40, 0},
+/*64-65 are dummy*/
+{ 1350, PREAMBLE_HT, S_BW40, 0},{ 1350, PREAMBLE_HT, S_BW40, 0},
+/*VHT20 LGI  MCS 0-9 rates (66-75)*/
+{ 65, PREAMBLE_VHT, S_BW20, 0},{ 130, PREAMBLE_VHT, S_BW20, 0},
+{ 195, PREAMBLE_VHT, S_BW20, 0},{ 260, PREAMBLE_VHT, S_BW20, 0},
+{ 390, PREAMBLE_VHT, S_BW20, 0},{ 520, PREAMBLE_VHT, S_BW20, 0},
+{ 585, PREAMBLE_VHT, S_BW20, 0},{ 650, PREAMBLE_VHT, S_BW20, 0},
+{ 780, PREAMBLE_VHT, S_BW20, 0},{ 865, PREAMBLE_VHT, S_BW20, 0},
+/*76-77 are dummy*/
+{ 865, PREAMBLE_VHT, S_BW20, 0},{ 865, PREAMBLE_VHT, S_BW20, 0},
+/*VHT20 SGI MCS 0-9 rates (78-87)*/
+{ 72, PREAMBLE_VHT, S_BW20, 1},{ 144, PREAMBLE_VHT, S_BW20, 1},
+{ 217, PREAMBLE_VHT, S_BW20, 1},{ 289, PREAMBLE_VHT, S_BW20, 1},
+{ 433, PREAMBLE_VHT, S_BW20, 1},{ 578, PREAMBLE_VHT, S_BW20, 1},
+{ 650, PREAMBLE_VHT, S_BW20, 1},{ 722, PREAMBLE_VHT, S_BW20, 1},
+{ 867, PREAMBLE_VHT, S_BW20, 1},{ 961, PREAMBLE_VHT, S_BW20, 1},
+/*88-89 are dummy*/
+{ 961, PREAMBLE_VHT, S_BW20, 1},{ 961, PREAMBLE_VHT, S_BW20, 1},
+/*VHT40 LGI MCS 0-9 rates (90-101) 98,101 is Dummy*/
+{ 135, PREAMBLE_VHT, S_BW40, 0},{ 270, PREAMBLE_VHT, S_BW40, 0},
+{ 405, PREAMBLE_VHT, S_BW40, 0},{ 540, PREAMBLE_VHT, S_BW40, 0},
+{ 810, PREAMBLE_VHT, S_BW40, 0},{ 1080, PREAMBLE_VHT, S_BW40, 0},
+{ 1215, PREAMBLE_VHT, S_BW40, 0},{ 1350, PREAMBLE_VHT, S_BW40, 0},
+{ 1350, PREAMBLE_VHT, S_BW40, 0},{ 1620, PREAMBLE_VHT, S_BW40, 0},
+{ 1800, PREAMBLE_VHT, S_BW40, 0},{ 1800, PREAMBLE_VHT, S_BW40, 0},
+/*VHT40 SGI MCS 0-9 rates (102-112) 110, 113 is Dummy*/
+{ 150, PREAMBLE_VHT, S_BW40, 1},{ 300, PREAMBLE_VHT, S_BW40, 1},
+{ 450, PREAMBLE_VHT, S_BW40, 1},{ 600, PREAMBLE_VHT, S_BW40, 1},
+{ 900, PREAMBLE_VHT, S_BW40, 1},{ 1200, PREAMBLE_VHT, S_BW40, 1},
+{ 1350, PREAMBLE_VHT, S_BW40, 1},{ 1500, PREAMBLE_VHT, S_BW40, 1},
+{ 1500, PREAMBLE_VHT, S_BW40, 1},{ 1800, PREAMBLE_VHT, S_BW40, 1},
+{ 2000, PREAMBLE_VHT, S_BW40, 1},{ 2000, PREAMBLE_VHT, S_BW40, 1},
+/*VHT80 LGI MCS 0-9 rates (114-125) 122, 125 is Dummy*/
+{ 293, PREAMBLE_VHT, S_BW80, 0},{ 585, PREAMBLE_VHT, S_BW80, 0},
+{ 878, PREAMBLE_VHT, S_BW80, 0},{ 1170, PREAMBLE_VHT, S_BW80, 0},
+{ 1755, PREAMBLE_VHT, S_BW80, 0},{ 2340, PREAMBLE_VHT, S_BW80, 0},
+{ 2633, PREAMBLE_VHT, S_BW80, 0},{ 2925, PREAMBLE_VHT, S_BW80, 0},
+{ 2925, PREAMBLE_VHT, S_BW80, 0},{ 3510, PREAMBLE_VHT, S_BW80, 0},
+{ 3900, PREAMBLE_VHT, S_BW80, 0},{ 3900, PREAMBLE_VHT, S_BW80, 0},
+/*VHT80 SGI MCS 0-9 rates (126-136) 134 is Dummy*/
+{ 325, PREAMBLE_VHT, S_BW80, 1},{ 650, PREAMBLE_VHT, S_BW80, 1},
+{ 975, PREAMBLE_VHT, S_BW80, 1},{ 1300, PREAMBLE_VHT, S_BW80, 1},
+{ 1950, PREAMBLE_VHT, S_BW80, 1},{ 2600, PREAMBLE_VHT, S_BW80, 1},
+{ 2925, PREAMBLE_VHT, S_BW80, 1},{ 3250, PREAMBLE_VHT, S_BW80, 1},
+{ 3250, PREAMBLE_VHT, S_BW80, 1},{ 3900, PREAMBLE_VHT, S_BW80, 1},
+{ 4333, PREAMBLE_VHT, S_BW80, 1},
+};
+
+void get_rate_and_MCS(per_packet_stats *stats, uint32 rateindex)
+{
+    rateidx_to_rate_bw_preamble_sgi *ratetbl;
+
+    if (STATS_MAX_RATE_INDEX < rateindex)
+        rateindex = STATS_MAX_RATE_INDEX;
+    ratetbl= &rateidx_to_rate_bw_preamble_sgi_table[rateindex];
+    stats->last_transmit_rate = ratetbl->rate/5;
+    stats->MCS.nss = 0;
+    if (0 <= rateindex && rateindex <= 7)
+        stats->MCS.rate = 7 - rateindex;
+    else if (8 <= rateindex && rateindex <= 15)
+    {
+        switch(rateindex)
+        {
+            case 8:stats->MCS.rate = 3; break;
+            case 9:stats->MCS.rate = 7; break;
+            case 10:stats->MCS.rate = 2; break;
+            case 11:stats->MCS.rate = 6; break;
+            case 12:stats->MCS.rate = 1; break;
+            case 13:stats->MCS.rate = 5; break;
+            case 14:stats->MCS.rate = 0; break;
+            case 15:stats->MCS.rate = 4; break;
+        }
+    }
+    else if(16 <= rateindex && rateindex <= 23)
+        stats->MCS.rate = rateindex - 16;
+    else if(24 <= rateindex  && rateindex <= 31)
+        stats->MCS.rate =  rateindex - 24;
+    else if(32 <= rateindex  && rateindex <= 39)
+        stats->MCS.rate = rateindex - 32;
+    else if(40 <= rateindex && rateindex <= 47)
+        stats->MCS.rate = rateindex - 40;
+    else if(48 <= rateindex && rateindex <= 55)
+        stats->MCS.rate = rateindex - 48;
+    else if(56 <= rateindex && rateindex <= 63)
+        stats->MCS.rate = rateindex - 56;
+    else if(66 <= rateindex && rateindex <= 75)
+        stats->MCS.rate = rateindex - 66;
+    else if(78 <= rateindex && rateindex <= 87)
+        stats->MCS.rate = rateindex - 78;
+    else if(90 <= rateindex && rateindex <= 100)
+        stats->MCS.rate = rateindex - 90;
+    else if(78 <= rateindex && rateindex <= 87)
+        stats->MCS.rate = rateindex - 78;
+    else if(90 <= rateindex && rateindex <= 97)
+        stats->MCS.rate = rateindex - 90;
+    else if(99 <= rateindex && rateindex <= 100)
+        stats->MCS.rate = rateindex - 91;
+    else if(102 <= rateindex && rateindex <= 109)
+        stats->MCS.rate = rateindex - 102;
+    else if(111 <= rateindex && rateindex <= 112)
+        stats->MCS.rate = rateindex - 103;
+    else if(114 <= rateindex && rateindex <= 121)
+        stats->MCS.rate = rateindex - 114;
+    else if(123 <= rateindex && rateindex <= 124)
+        stats->MCS.rate = rateindex - 115;
+    else if(126 <= rateindex && rateindex <= 133)
+        stats->MCS.rate = rateindex - 126;
+    else if(135 <= rateindex && rateindex <= 136)
+        stats->MCS.rate = rateindex - 127;
+    else /*Invalid rate index mark it 0*/
+        stats->MCS.rate = 0;
+    stats->MCS.preamble = ratetbl->preamble;
+    stats->MCS.bw = ratetbl->bw;
+    stats->MCS.short_gi = ratetbl->short_gi;
+}
+
+bool vos_isPktStatsEnabled(void)
+{
+    bool value;
+    value = wlan_isPktStatsEnabled();
+    return (value);
+}
diff --git a/CORE/VOSS/src/vos_utils.c b/CORE/VOSS/src/vos_utils.c
index 834b21b..e137fc3 100644
--- a/CORE/VOSS/src/vos_utils.c
+++ b/CORE/VOSS/src/vos_utils.c
@@ -760,6 +760,10 @@
 #define VOS_QOS_DATA_VALUE                              ( 0x88 )
 #define VOS_NON_QOS_DATA_VALUE                          ( 0x80 )
 
+//802.11 header wil have 24 byte excluding qos
+#define VOS_802_11_HEADER_SIZE ( 24 )
+#define VOS_QOS_SIZE ( 2 )
+#define VOS_LLC_HEADER_SIZE   (8)
 
 // Frame Type definitions
 #define VOS_MAC_MGMT_FRAME    0x0
@@ -1468,3 +1472,45 @@
          "||== END ====================="
          "===============================||\n");
 }
+
+v_U32_t vos_copy_80211_header(void *pBuff, v_U8_t *dst, v_U8_t frametype, v_U8_t qos)
+{
+    vos_pkt_t *vos_pkt = NULL;
+    struct sk_buff *skb = NULL;
+    v_U8_t length_to_copy;
+
+    vos_pkt = (vos_pkt_t *)pBuff;
+
+    if(!vos_pkt || !dst)
+    {
+       VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                 "vos_pkt/dst is null");
+       return 0;
+    }
+    skb = vos_pkt->pSkb;
+    if(!skb)
+    {
+       VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                   " skb is null");
+       return 0;
+    }
+    length_to_copy = VOS_802_11_HEADER_SIZE;
+
+    if(VOS_MAC_DATA_FRAME == frametype)
+    {
+       if(qos)
+          length_to_copy += VOS_QOS_SIZE;
+       length_to_copy += VOS_LLC_HEADER_SIZE;
+    }
+
+    if (unlikely(length_to_copy > skb->len))
+    {
+        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                  "%s Packet overflow, length_to_copy %d len %d",
+                  __func__,  length_to_copy, skb->len);
+        return 0;
+    }
+
+    vos_mem_copy(dst,skb->data,length_to_copy);
+    return length_to_copy;
+}
diff --git a/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h b/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h
index 76b3395..85fd4c2 100644
--- a/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h
+++ b/CORE/WDI/CP/inc/wlan_qct_wdi_dp.h
@@ -139,6 +139,9 @@
 
 #define WDI_DPU_FEEDBACK_OFFSET       1
 
+#define WDI_MAC_LLC_HEADER_SIZE       8
+
+
 // Frame Type definitions
 
 #define WDI_MAC_MGMT_FRAME    0x0
@@ -336,6 +339,9 @@
 
 #define WDI_TX_BD_SET_MPDU_HEADER_LEN( _bd, _len )       (((WDI_TxBdType*)_bd)->mpduHeaderLength = _len)
 
+#define WDI_TX_BD_GET_MPDU_HEADER_LEN( _bd )               (((WDI_TxBdType*)_bd)->mpduHeaderLength)
+
+
 #define WDI_TX_BD_SET_MPDU_LEN( _bd, _len )              (((WDI_TxBdType*)_bd)->mpduLength = _len)
 
 #define WDI_RX_BD_GET_BA_OPCODE(_pvBDHeader)        (((WDI_RxBdType*)_pvBDHeader)->reorderOpcode)
diff --git a/CORE/WDI/CP/src/wlan_qct_wdi.c b/CORE/WDI/CP/src/wlan_qct_wdi.c
index d8007e6..8127230 100644
--- a/CORE/WDI/CP/src/wlan_qct_wdi.c
+++ b/CORE/WDI/CP/src/wlan_qct_wdi.c
@@ -204,7 +204,9 @@
    ,MGMT_FRAME_LOGGING             //53
    ,ENHANCED_TXBD_COMPLETION       //54
    ,LOGGING_ENHANCEMENT            //55
+   ,FEATURE_NOT_SUPPORTED          //56
    ,MEMORY_DUMP_SUPPORTED          //57
+   ,PER_PKT_STATS_SUPPORTED        //58
 };
 
 /*-------------------------------------------------------------------------- 
@@ -1493,6 +1495,11 @@
                      case MEMORY_DUMP_SUPPORTED:snprintf(pCapStr, sizeof("FW_MEM_DUMP_LOGGING"), "%s", "FW_MEM_DUMP_LOGGING");
                           pCapStr += strlen("FW_MEM_DUMP_LOGGING");
                           break;
+                     case PER_PKT_STATS_SUPPORTED: snprintf(pCapStr, sizeof("PER_PKT_STATS_SUPPORTED"), "%s", "PER_PKT_STATS_SUPPORTED");
+                          pCapStr += strlen("PER_PKT_STATS_SUPPORTED");
+                          break;
+
+
                  }
                  *pCapStr++ = ',';
                  *pCapStr++ = ' ';
diff --git a/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c b/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c
index 806ac92..bfb3ed9 100644
--- a/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c
+++ b/CORE/WDI/TRP/DTS/src/wlan_qct_wdi_dts.c
@@ -49,6 +49,7 @@
 #include "vos_utils.h"
 #include "vos_api.h"
 
+
 static WDTS_TransportDriverTrype gTransportDriver = {
   WLANDXE_Open, 
   WLANDXE_Start, 
@@ -536,6 +537,8 @@
   WDI_DS_RxMetaInfoType     *pRxMetadata;
   wpt_uint8                  isFcBd = 0;
   WDI_DS_LoggingSessionType *pLoggingSession;
+  tPerPacketStats             rxStats = {0};
+
   tpSirMacFrameCtl  pMacFrameCtl;
   // Do Sanity checks
   if(NULL == pContext || NULL == pFrame){
@@ -780,6 +783,30 @@
       {
           vos_record_roam_event(e_DXE_RX_PKT_TIME, (void *)pFrame, pRxMetadata->type);
       }
+      if ((WLAN_LOG_LEVEL_ACTIVE ==
+            vos_get_ring_log_level(RING_ID_PER_PACKET_STATS)) &&
+          !(WDI_MAC_CTRL_FRAME == pRxMetadata->type) &&
+          !((WDI_MAC_MGMT_FRAME== pRxMetadata->type) &&
+          ((WDI_MAC_MGMT_BEACON == (pRxMetadata->subtype)) ||
+          (WDI_MAC_MGMT_PROBE_REQ == (pRxMetadata->subtype)) ||
+          (WDI_MAC_MGMT_PROBE_RSP == (pRxMetadata->subtype)))))
+      {
+          vos_mem_zero(&rxStats,sizeof(tPerPacketStats));
+          /* Peer tx packet and it is an Rx packet for us */
+          rxStats.is_rx= VOS_TRUE;
+          rxStats.tid = ucTid;
+          rxStats.rssi = (pRxMetadata->rssi0 > pRxMetadata->rssi1)?
+                                pRxMetadata->rssi0 : pRxMetadata->rssi1;
+          rxStats.rate_idx = pRxMetadata->rateIndex;
+          rxStats.seq_num = pRxMetadata->currentPktSeqNo;
+          rxStats.dxe_timestamp = vos_timer_get_system_ticks();
+          rxStats.data_len = ucMPDUHLen;
+          if(WDI_MAC_DATA_FRAME== pRxMetadata->type)
+             rxStats.data_len += WDI_MAC_LLC_HEADER_SIZE;
+          vos_mem_copy(rxStats.data,pRxMetadata->mpduHeaderPtr,rxStats.data_len);
+
+          wpalPerPktSerialize(&rxStats);
+      }
       // Invoke Rx complete callback
       pClientData->receiveFrameCB(pClientData->pCallbackContext, pFrame);  
   }
@@ -1022,6 +1049,7 @@
   WDI_DS_TxMetaInfoType     *pTxMetadata;
   WDTS_ChannelType channel = WDTS_CHANNEL_TX_LOW_PRI;
   wpt_status status = eWLAN_PAL_STATUS_SUCCESS;
+  tPerPacketStats               txPktStat = {0};
 
   // extract metadata from PAL packet
   pTxMetadata = WDI_DS_ExtractTxMetaData(pFrame);
@@ -1056,6 +1084,24 @@
 #endif
   // Send packet to  Transport Driver. 
   status =  gTransportDriver.xmit(pDTDriverContext, pFrame, channel);
+  if ((WLAN_LOG_LEVEL_ACTIVE ==
+           vos_get_ring_log_level(RING_ID_PER_PACKET_STATS)) &&
+       !(pTxMetadata->frmType & WDI_MAC_CTRL_FRAME) &&
+      !((WDI_MAC_MGMT_FRAME== pTxMetadata->frmType) &&
+        ((WDI_MAC_MGMT_BEACON == (pTxMetadata->typeSubtype & 0x0F)) ||
+        (WDI_MAC_MGMT_PROBE_REQ == (pTxMetadata->typeSubtype & 0x0F)) ||
+        (WDI_MAC_MGMT_PROBE_RSP == (pTxMetadata->typeSubtype & 0x0F))))){
+
+      vos_mem_zero(&txPktStat,sizeof(tPerPacketStats));
+      txPktStat.tid = pTxMetadata->fUP;
+      txPktStat.dxe_timestamp = vos_timer_get_system_ticks();
+      /*HW limitation cant get the seq number*/
+      txPktStat.seq_num = 0;
+      txPktStat.data_len =
+      vos_copy_80211_header((void *)pFrame, txPktStat.data,
+                   pTxMetadata->frmType, pTxMetadata->qosEnabled);
+      wpalPerPktSerialize(&txPktStat);
+  }
   if (((WDI_ControlBlockType *)pContext)->roamDelayStatsEnabled)
   {
       vos_record_roam_event(e_DXE_FIRST_XMIT_TIME, (void *)pFrame, pTxMetadata->frmType);
diff --git a/CORE/WDI/WPAL/inc/wlan_qct_pal_packet.h b/CORE/WDI/WPAL/inc/wlan_qct_pal_packet.h
index 59a2024..9a2dea1 100644
--- a/CORE/WDI/WPAL/inc/wlan_qct_pal_packet.h
+++ b/CORE/WDI/WPAL/inc/wlan_qct_pal_packet.h
@@ -448,4 +448,20 @@
 (
    wpt_packet *pFrame, wpt_uint32 pktType
 );
+
+/*---------------------------------------------------------------------------
+    wpalPerPktSerialize - Serialize perpkt data to logger thread
+
+    Param:
+
+
+    Return:
+        NONE
+
+---------------------------------------------------------------------------*/
+void wpalPerPktSerialize
+(
+   void *perPktStat
+);
+
 #endif // __WLAN_QCT_PAL_PACKET_H
diff --git a/CORE/WDI/WPAL/src/wlan_qct_pal_packet.c b/CORE/WDI/WPAL/src/wlan_qct_pal_packet.c
index cef17f9..c8dcf28 100644
--- a/CORE/WDI/WPAL/src/wlan_qct_pal_packet.c
+++ b/CORE/WDI/WPAL/src/wlan_qct_pal_packet.c
@@ -1035,3 +1035,22 @@
 {
     vos_logger_pkt_serialize(WPAL_TO_VOS_PKT(pFrame), pktType);
 }
+
+
+/*---------------------------------------------------------------------------
+    wpalPerPktSerialize - Serialize perpkt data to logger thread
+
+    Param:
+
+
+    Return:
+        NONE
+
+---------------------------------------------------------------------------*/
+void wpalPerPktSerialize
+(
+   void *perPktStat
+)
+{
+   vos_per_pkt_stats_to_user(perPktStat);
+}
diff --git a/riva/inc/wlan_hal_msg.h b/riva/inc/wlan_hal_msg.h
index a55950e..c3d332e 100644
--- a/riva/inc/wlan_hal_msg.h
+++ b/riva/inc/wlan_hal_msg.h
@@ -801,7 +801,8 @@
     HAL_GLOBAL_CLASS_B_STATS_INFO    = 0x00000004,
     HAL_GLOBAL_CLASS_C_STATS_INFO    = 0x00000008,
     HAL_GLOBAL_CLASS_D_STATS_INFO    = 0x00000010,
-    HAL_PER_STA_STATS_INFO           = 0x00000020
+    HAL_PER_STA_STATS_INFO           = 0x00000020,
+    HAL_PER_TX_PKT_STATS_INFO        = 0x00000040
 }eHalStatsMask;
 
 /* BT-AMP events type */
@@ -825,6 +826,7 @@
     PE_GLOBAL_CLASS_C_STATS_INFO    = 0x00000008,
     PE_GLOBAL_CLASS_D_STATS_INFO    = 0x00000010,
     PE_PER_STA_STATS_INFO           = 0x00000020,
+    PE_PER_TX_PKT_STATS_INFO        = 0x00000040,
     PE_STATS_TYPE_MAX = WLAN_HAL_MAX_ENUM_SIZE //This and beyond are invalid values
 }ePEStatsMask;
 
@@ -3212,6 +3214,15 @@
                                     //is transmitted
 }tAniPerStaStatsInfo, *tpAniPerStaStatsInfo;
 
+// The following stats are averaged over the time between two consecutive GET_STATS_REQ messages.
+typedef PACKED_PRE struct PACKED_POST
+{
+    tANI_U32 lastTxRate;           // 802.11 data rate at which the last data frame is transmitted.
+    tANI_U8  txAvgRetry;           // Average number of retries per 10 packets.
+    tANI_U32 reserved;
+    tANI_U32 reserved1;
+}tAniPerTxPktStatsInfo, *tpAniPerTxPktStatsInfo;
+
 typedef PACKED_PRE struct PACKED_POST
 {
    /* Success or Failure */
@@ -6783,6 +6794,7 @@
     ENHANCED_TXBD_COMPLETION = 54,
     LOGGING_ENHANCEMENT    = 55,
     MEMORY_DUMP_SUPPORTED  = 57,
+    PER_PKT_STATS_SUPPORTED  = 58,
     MAX_FEATURE_SUPPORTED  = 128,
 } placeHolderInCapBitmap;