wlan: enhance debugging when Tx timeout is detected

Add debug information when tx timeout is detected for
AP mode, and if tx stall perisists issue SSR.
SSR may help is restoring Tx data and will also
help to collect ram-dumps for debugging the issue.

Change-Id: Ie62b127e2fb8ad8fa353cb2dc9c217d331caddad
CRs-Fixed: 685415
diff --git a/CORE/HDD/src/wlan_hdd_tx_rx.c b/CORE/HDD/src/wlan_hdd_tx_rx.c
index 72cc491..8224e88 100644
--- a/CORE/HDD/src/wlan_hdd_tx_rx.c
+++ b/CORE/HDD/src/wlan_hdd_tx_rx.c
@@ -47,6 +47,11 @@
 #include <linux/skbuff.h>
 #include <linux/etherdevice.h>
 #include <linux/ratelimit.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
+#include <soc/qcom/subsystem_restart.h>
+#else
+#include <mach/subsystem_restart.h>
+#endif
 
 #include <wlan_hdd_p2p.h>
 #include <linux/wireless.h>
@@ -79,6 +84,7 @@
 
 #define HDD_TX_TIMEOUT_RATELIMIT_INTERVAL 20*HZ
 #define HDD_TX_TIMEOUT_RATELIMIT_BURST    1
+#define HDD_TX_STALL_SSR_THRESHOLD        5
 
 static DEFINE_RATELIMIT_STATE(hdd_tx_timeout_rs,                 \
                               HDD_TX_TIMEOUT_RATELIMIT_INTERVAL, \
@@ -885,6 +891,9 @@
    struct netdev_queue *txq;
    int i = 0;
 
+   VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR,
+      "%s: Transmission timeout occurred", __func__);
+
    if ( NULL == pAdapter )
    {
       VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR,
@@ -893,8 +902,8 @@
       return;
    }
 
-   VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR,
-      "%s: Transmission timeout occurred", __func__);
+   ++pAdapter->hdd_stats.hddTxRxStats.txTimeoutCount;
+
    //Getting here implies we disabled the TX queues for too long. Queues are 
    //disabled either because of disassociation or low resource scenarios. In
    //case of disassociation it is ok to ignore this. But if associated, we have
@@ -924,6 +933,22 @@
    VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR,
               "carrier state: %d", netif_carrier_ok(dev));
 
+   /* continuousTxTimeoutCount will be reset whenever TL fetches packet
+    * from HDD
+    */
+   ++pAdapter->hdd_stats.hddTxRxStats.continuousTxTimeoutCount;
+
+   if (pAdapter->hdd_stats.hddTxRxStats.continuousTxTimeoutCount >
+       HDD_TX_STALL_SSR_THRESHOLD)
+   {
+       // Driver could not recover, issue SSR
+       VOS_TRACE(VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR,
+                 "%s: Cannot recover from Data stall Issue SSR",
+                   __func__);
+       subsystem_restart("wcnss");
+       return;
+   }
+
    /* If Tx stalled for a long time then *hdd_tx_timeout* is called
     * every 5sec. The TL debug spits out a lot of information on the
     * serial console, if it is called every time *hdd_tx_timeout* is
@@ -935,6 +960,7 @@
       hdd_wmm_tx_snapshot(pAdapter);
       WLANTL_TLDebugMessage(VOS_TRUE);
    }
+
 }
 
 
@@ -1531,6 +1557,7 @@
    ++pAdapter->stats.tx_packets;
    ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeued;
    ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeuedAC[ac];
+   pAdapter->hdd_stats.hddTxRxStats.continuousTxTimeoutCount = 0;
 
    if((pHddCtx->cfg_ini->thermalMitigationEnable) &&
       (WLAN_HDD_INFRA_STATION == pAdapter->device_mode))