diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 1dbe57fd07db..34f49abdec73 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -127,6 +127,9 @@ #else #define HDD_TX_TIMEOUT msecs_to_jiffies(5000) #endif + +#define HDD_TX_STALL_THRESHOLD 4 + /** Hdd Default MTU */ #define HDD_DEFAULT_MTU (1500) @@ -446,6 +449,11 @@ struct hdd_tx_rx_stats { __u32 txflow_pause_cnt; __u32 txflow_unpause_cnt; __u32 txflow_timer_cnt; + + /*tx timeout stats*/ + __u32 tx_timeout_cnt; + __u32 cont_txtimeout_cnt; + u64 jiffies_last_txtimeout; }; #ifdef WLAN_FEATURE_11W diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c index db645067c857..1983675b101b 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -1780,6 +1780,9 @@ static QDF_STATUS hdd_dis_connect_handler(struct hdd_adapter *adapter, adapter->sessionId); } wlan_hdd_clear_link_layer_stats(adapter); + + adapter->hdd_stats.hddTxRxStats.cont_txtimeout_cnt = 0; + /* Unblock anyone waiting for disconnect to complete */ complete(&adapter->disconnect_comp_var); diff --git a/core/hdd/src/wlan_hdd_softap_tx_rx.c b/core/hdd/src/wlan_hdd_softap_tx_rx.c index 7e3cf012c458..c25c8a40b238 100644 --- a/core/hdd/src/wlan_hdd_softap_tx_rx.c +++ b/core/hdd/src/wlan_hdd_softap_tx_rx.c @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include "wlan_p2p_ucfg_api.h" #ifdef IPA_OFFLOAD @@ -293,6 +293,8 @@ static int __hdd_softap_hard_start_xmit(struct sk_buff *skb, uint32_t num_seg; ++adapter->hdd_stats.hddTxRxStats.txXmitCalled; + adapter->hdd_stats.hddTxRxStats.cont_txtimeout_cnt = 0; + /* Prevent this function from being called during SSR since TL * context may not be reinitialized at this time which may * lead to a crash. @@ -503,30 +505,6 @@ int hdd_softap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) return ret; } -#ifdef FEATURE_WLAN_DIAG_SUPPORT -/** - * hdd_wlan_datastall_sap_event()- Send SAP datastall information - * - * This Function send send SAP datastall diag event - * - * Return: void. - */ -static void hdd_wlan_datastall_sap_event(void) -{ - WLAN_HOST_DIAG_EVENT_DEF(sap_data_stall, - struct host_event_wlan_datastall); - qdf_mem_zero(&sap_data_stall, sizeof(sap_data_stall)); - sap_data_stall.reason = SOFTAP_TX_TIMEOUT; - WLAN_HOST_DIAG_EVENT_REPORT(&sap_data_stall, - EVENT_WLAN_SOFTAP_DATASTALL); -} -#else -static inline void hdd_wlan_datastall_sap_event(void) -{ - -} -#endif - /** * __hdd_softap_tx_timeout() - TX timeout handler * @dev: pointer to network device @@ -542,6 +520,7 @@ static void __hdd_softap_tx_timeout(struct net_device *dev) struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); struct hdd_context *hdd_ctx; struct netdev_queue *txq; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); int i; DPTRACE(qdf_dp_trace(NULL, QDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT, @@ -574,7 +553,21 @@ static void __hdd_softap_tx_timeout(struct net_device *dev) cdp_dump_flow_pool_info(cds_get_context(QDF_MODULE_ID_SOC)); QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, "carrier state: %d", netif_carrier_ok(dev)); - hdd_wlan_datastall_sap_event(); + + ++adapter->hdd_stats.hddTxRxStats.tx_timeout_cnt; + ++adapter->hdd_stats.hddTxRxStats.cont_txtimeout_cnt; + + if (adapter->hdd_stats.hddTxRxStats.cont_txtimeout_cnt > + HDD_TX_STALL_THRESHOLD) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "Detected data stall due to continuous TX timeouts"); + adapter->hdd_stats.hddTxRxStats.cont_txtimeout_cnt = 0; + cdp_post_data_stall_event(soc, + DATA_STALL_LOG_INDICATOR_HOST_DRIVER, + DATA_STALL_LOG_HOST_SOFTAP_TX_TIMEOUT, + 0xFF, 0xFF, + DATA_STALL_LOG_RECOVERY_TRIGGER_PDR); + } } /** diff --git a/core/hdd/src/wlan_hdd_tx_rx.c b/core/hdd/src/wlan_hdd_tx_rx.c index 4df9eb049b3b..a2645b6851b2 100644 --- a/core/hdd/src/wlan_hdd_tx_rx.c +++ b/core/hdd/src/wlan_hdd_tx_rx.c @@ -60,7 +60,7 @@ #include #include "wlan_hdd_nan_datapath.h" #include "pld_common.h" -#include +#include #include "wlan_hdd_rx_monitor.h" #include "wlan_hdd_power.h" #include @@ -583,6 +583,8 @@ static int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) #endif ++adapter->hdd_stats.hddTxRxStats.txXmitCalled; + adapter->hdd_stats.hddTxRxStats.cont_txtimeout_cnt = 0; + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO_HIGH, "Recovery in progress, dropping the packet"); @@ -849,28 +851,6 @@ QDF_STATUS hdd_get_peer_sta_id(struct hdd_station_ctx *sta_ctx, return QDF_STATUS_E_FAILURE; } -#ifdef FEATURE_WLAN_DIAG_SUPPORT -/** - * hdd_wlan_datastall_sta_event()- send sta datastall information - * - * This Function send send sta datastall status diag event - * - * Return: void. - */ -static void hdd_wlan_datastall_sta_event(void) -{ - WLAN_HOST_DIAG_EVENT_DEF(sta_data_stall, - struct host_event_wlan_datastall); - qdf_mem_zero(&sta_data_stall, sizeof(sta_data_stall)); - sta_data_stall.reason = STA_TX_TIMEOUT; - WLAN_HOST_DIAG_EVENT_REPORT(&sta_data_stall, EVENT_WLAN_STA_DATASTALL); -} -#else -static inline void hdd_wlan_datastall_sta_event(void) -{ -} -#endif - /** * __hdd_tx_timeout() - TX timeout handler * @dev: pointer to network device @@ -886,6 +866,8 @@ static void __hdd_tx_timeout(struct net_device *dev) struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); struct hdd_context *hdd_ctx; struct netdev_queue *txq; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + u64 diff_jiffies; int i = 0; TX_TIMEOUT_TRACE(dev, QDF_MODULE_ID_HDD_DATA); @@ -912,7 +894,45 @@ static void __hdd_tx_timeout(struct net_device *dev) hdd_ctx = WLAN_HDD_GET_CTX(adapter); wlan_hdd_display_netif_queue_history(hdd_ctx); cdp_dump_flow_pool_info(cds_get_context(QDF_MODULE_ID_SOC)); - hdd_wlan_datastall_sta_event(); + + ++adapter->hdd_stats.hddTxRxStats.tx_timeout_cnt; + ++adapter->hdd_stats.hddTxRxStats.cont_txtimeout_cnt; + + diff_jiffies = jiffies - + adapter->hdd_stats.hddTxRxStats.jiffies_last_txtimeout; + + if ((adapter->hdd_stats.hddTxRxStats.cont_txtimeout_cnt > 1) && + (diff_jiffies > (HDD_TX_TIMEOUT * 2))) { + /* + * In case when there is no traffic is running, it may + * possible tx time-out may once happen and later system + * recovered then continuous tx timeout count has to be + * reset as it is gets modified only when traffic is running. + * If over a period of time if this count reaches to threshold + * then host triggers a false subsystem restart. In genuine + * time out case kernel will call the tx time-out back to back + * at interval of HDD_TX_TIMEOUT. Here now check if previous + * TX TIME out has occurred more than twice of HDD_TX_TIMEOUT + * back then host may recovered here from data stall. + */ + adapter->hdd_stats.hddTxRxStats.cont_txtimeout_cnt = 0; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, + "Reset continous tx timeout stat"); + } + + adapter->hdd_stats.hddTxRxStats.jiffies_last_txtimeout = jiffies; + + if (adapter->hdd_stats.hddTxRxStats.cont_txtimeout_cnt > + HDD_TX_STALL_THRESHOLD) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "Data stall due to continuous TX timeouts"); + adapter->hdd_stats.hddTxRxStats.cont_txtimeout_cnt = 0; + cdp_post_data_stall_event(soc, + DATA_STALL_LOG_INDICATOR_HOST_DRIVER, + DATA_STALL_LOG_HOST_STA_TX_TIMEOUT, + 0xFF, 0xFF, + DATA_STALL_LOG_RECOVERY_TRIGGER_PDR); + } } /**