diff --git a/Kbuild b/Kbuild
index e08db33f8af3..44264c04bf4c 100644
--- a/Kbuild
+++ b/Kbuild
@@ -84,6 +84,10 @@ HDD_OBJS := $(HDD_SRC_DIR)/wlan_hdd_assoc.o \
$(HDD_SRC_DIR)/wlan_hdd_wmm.o \
$(HDD_SRC_DIR)/wlan_hdd_wowl.o
+ifeq ($(CONFIG_WLAN_FEATURE_PERIODIC_STA_STATS), y)
+HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_periodic_sta_stats.o
+endif
+
ifeq ($(CONFIG_WLAN_WEXT_SUPPORT_ENABLE), y)
HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_wext.o \
$(HDD_SRC_DIR)/wlan_hdd_hostapd_wext.o
@@ -2390,6 +2394,7 @@ cppflags-y += -DMSM_PLATFORM
endif
cppflags-$(CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH) += -DWLAN_FEATURE_DP_BUS_BANDWIDTH
+cppflags-$(CONFIG_WLAN_FEATURE_PERIODIC_STA_STATS) += -DWLAN_FEATURE_PERIODIC_STA_STATS
cppflags-y += -DQCA_SUPPORT_TXRX_LOCAL_PEER_ID
diff --git a/core/hdd/inc/hdd_config.h b/core/hdd/inc/hdd_config.h
index c5dde815b54e..acb902394a2f 100644
--- a/core/hdd/inc/hdd_config.h
+++ b/core/hdd/inc/hdd_config.h
@@ -1362,6 +1362,70 @@ struct dhcp_server {
CFG_VALUE_OR_DEFAULT, \
"Disable wow feature")
+#ifdef WLAN_FEATURE_PERIODIC_STA_STATS
+/*
+ *
+ * periodic_stats_timer_interval - Print selective stats on this specified
+ * interval
+ *
+ * @Min: 0
+ * @Max: 10000
+ * Default: 3000
+ *
+ * This ini is used to specify interval in milliseconds for periodic stats
+ * timer. This timer will print selective stats after expiration of each
+ * interval. STA starts this periodic timer after initial connection or after
+ * roaming is successful. This will be restarted for every
+ * periodic_stats_timer_interval till the periodic_stats_timer_duration expires.
+ *
+ * Supported Feature: STA
+ *
+ * Usage: Internal
+ *
+ *
+ */
+#define CFG_PERIODIC_STATS_TIMER_INTERVAL CFG_INI_UINT( \
+ "periodic_stats_timer_interval", \
+ 0, \
+ 10000, \
+ 3000, \
+ CFG_VALUE_OR_DEFAULT, \
+ "Periodic stats timer interval")
+
+/*
+ *
+ * periodic_stats_timer_duration - Used as duration for which periodic timer
+ * should run
+ *
+ * @Min: 0
+ * @Max: 60000
+ * Default: 30000
+ *
+ * This ini is used as duration in milliseconds for which periodic stats timer
+ * should run. This periodic timer will print selective stats for every
+ * periodic_stats_timer_interval until this duration is reached.
+ *
+ * Supported Feature: STA
+ *
+ * Usage: Internal
+ *
+ *
+ */
+#define CFG_PERIODIC_STATS_TIMER_DURATION CFG_INI_UINT( \
+ "periodic_stats_timer_duration", \
+ 0, \
+ 60000, \
+ 30000, \
+ CFG_VALUE_OR_DEFAULT, \
+ "Periodic stats timer duration")
+
+#define CFG_WLAN_STA_PERIODIC_STATS \
+ CFG(CFG_PERIODIC_STATS_TIMER_DURATION) \
+ CFG(CFG_PERIODIC_STATS_TIMER_INTERVAL)
+#else
+#define CFG_WLAN_STA_PERIODIC_STATS
+#endif /* WLAN_FEATURE_PERIODIC_STA_STATS */
+
/**
* enum host_log_level - Debug verbose level imposed by user
* @HOST_LOG_LEVEL_NONE: no trace will be logged.
@@ -1478,6 +1542,7 @@ enum host_log_level {
CFG_VC_MODE_BITMAP_ALL \
CFG_WLAN_AUTO_SHUTDOWN_ALL \
CFG_WLAN_LOGGING_SUPPORT_ALL \
+ CFG_WLAN_STA_PERIODIC_STATS \
CFG(CFG_ACTION_OUI_CCKM_1X1) \
CFG(CFG_ACTION_OUI_CONNECT_1X1) \
CFG(CFG_ACTION_OUI_CONNECT_1X1_WITH_1_CHAIN) \
diff --git a/core/hdd/inc/wlan_hdd_cfg.h b/core/hdd/inc/wlan_hdd_cfg.h
index 069356d61d73..9288c980844f 100644
--- a/core/hdd/inc/wlan_hdd_cfg.h
+++ b/core/hdd/inc/wlan_hdd_cfg.h
@@ -244,6 +244,13 @@ struct hdd_config {
#endif
bool get_roam_chan_from_fw;
uint32_t fisa_enable;
+
+#ifdef WLAN_FEATURE_PERIODIC_STA_STATS
+ /* Periodicity of logging */
+ uint32_t periodic_stats_timer_interval;
+ /* Duration for which periodic logging should be done */
+ uint32_t periodic_stats_timer_duration;
+#endif /* WLAN_FEATURE_PERIODIC_STA_STATS */
};
/**
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h
index 5f20ffc8a3e9..72a19c59d34e 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -1315,6 +1315,14 @@ struct hdd_adapter {
uint32_t motion_det_baseline_value;
#endif /* WLAN_FEATURE_MOTION_DETECTION */
enum qca_disconnect_reason_codes last_disconnect_reason;
+
+#ifdef WLAN_FEATURE_PERIODIC_STA_STATS
+ /* Indicate whether to display sta periodic stats */
+ bool is_sta_periodic_stats_enabled;
+ uint16_t periodic_stats_timer_count;
+ uint32_t periodic_stats_timer_counter;
+ qdf_mutex_t sta_periodic_stats_lock;
+#endif /* WLAN_FEATURE_PERIODIC_STA_STATS */
};
#define WLAN_HDD_GET_STATION_CTX_PTR(adapter) (&(adapter)->session.station)
diff --git a/core/hdd/inc/wlan_hdd_periodic_sta_stats.h b/core/hdd/inc/wlan_hdd_periodic_sta_stats.h
new file mode 100644
index 000000000000..61725404d760
--- /dev/null
+++ b/core/hdd/inc/wlan_hdd_periodic_sta_stats.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2020, 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.
+ */
+
+/**
+ * DOC : wlan_hdd_periodic_sta_stats.h
+ *
+ * WLAN Host Device Driver periodic STA statistics related implementation
+ *
+ */
+
+#if !defined(WLAN_HDD_PERIODIC_STA_STATS_H)
+#define WLAN_HDD_PERIODIC_STA_STATS_H
+
+#ifdef WLAN_FEATURE_PERIODIC_STA_STATS
+/*
+ * Used to get device name from the adapter
+ */
+#define WLAN_HDD_GET_DEV_NAME(adapter) ((adapter)->dev->name)
+
+/**
+ * hdd_periodic_sta_stats_config() - Initialize periodic stats configuration
+ * @config: Pointer to hdd configuration
+ * @psoc: Pointer to psoc
+ *
+ * Return: none
+ */
+void hdd_periodic_sta_stats_config(struct hdd_config *config,
+ struct wlan_objmgr_psoc *psoc);
+
+/**
+ * hdd_periodic_sta_stats_init() - Initialize periodic stats display flag
+ * @adapter: Pointer to the station adapter
+ *
+ * Return: none
+ */
+void hdd_periodic_sta_stats_init(struct hdd_adapter *adapter);
+
+/**
+ * hdd_periodic_sta_stats_display() - Display periodic stats at STA
+ * @hdd_ctx: hdd context
+ *
+ * Return: none
+ */
+void hdd_periodic_sta_stats_display(struct hdd_context *hdd_ctx);
+
+/**
+ * hdd_periodic_sta_stats_start() - Start displaying periodic stats for STA
+ * @adapter: Pointer to the station adapter
+ *
+ * Return: none
+ */
+void hdd_periodic_sta_stats_start(struct hdd_adapter *adapter);
+
+/**
+ * hdd_periodic_sta_stats_stop() - Stop displaying periodic stats for STA
+ * @adapter: Pointer to the station adapter
+ *
+ * Return: none
+ */
+void hdd_periodic_sta_stats_stop(struct hdd_adapter *adapter);
+
+/**
+ * hdd_periodic_sta_stats_mutex_create() - Create mutex for STA periodic stats
+ * @adapter: Pointer to the station adapter
+ *
+ * Return: none
+ */
+void hdd_periodic_sta_stats_mutex_create(struct hdd_adapter *adapter);
+
+/**
+ * hdd_periodic_sta_stats_mutex_destroy() - Destroy STA periodic stats mutex
+ * @adapter: Pointer to the station adapter
+ *
+ * Return: none
+ */
+void hdd_periodic_sta_stats_mutex_destroy(struct hdd_adapter *adapter);
+
+#else
+static inline void
+hdd_periodic_sta_stats_display(struct hdd_context *hdd_ctx) {}
+
+static inline void
+hdd_periodic_sta_stats_config(struct hdd_config *config,
+ struct wlan_objmgr_psoc *psoc) {}
+
+static inline void hdd_periodic_sta_stats_start(struct hdd_adapter *adapter) {}
+
+static inline void hdd_periodic_sta_stats_stop(struct hdd_adapter *adapter) {}
+
+static inline void
+hdd_periodic_sta_stats_init(struct hdd_adapter *adapter) {}
+
+static inline void
+hdd_periodic_sta_stats_mutex_create(struct hdd_adapter *adapter) {}
+
+static inline void
+hdd_periodic_sta_stats_mutex_destroy(struct hdd_adapter *adapter) {}
+
+#endif /* end #ifdef WLAN_FEATURE_PERIODIC_STA_STATS */
+
+#endif /* end #if !defined(WLAN_HDD_PERIODIC_STA_STATS_H) */
diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c
index 10f7b94d4a67..169f2f3b66cd 100644
--- a/core/hdd/src/wlan_hdd_assoc.c
+++ b/core/hdd/src/wlan_hdd_assoc.c
@@ -72,6 +72,7 @@
#include "wlan_blm_ucfg_api.h"
#include "wlan_hdd_sta_info.h"
#include "wlan_hdd_ftm_time_sync.h"
+#include "wlan_hdd_periodic_sta_stats.h"
#include
#include "wlan_pkt_capture_ucfg_api.h"
@@ -1722,6 +1723,8 @@ static QDF_STATUS hdd_dis_connect_handler(struct hdd_adapter *adapter,
WLAN_IPA_STA_DISCONNECT,
sta_ctx->conn_info.bssid.bytes);
+ hdd_periodic_sta_stats_stop(adapter);
+
#ifdef FEATURE_WLAN_AUTO_SHUTDOWN
wlan_hdd_auto_shutdown_enable(hdd_ctx, true);
#endif
@@ -3640,6 +3643,8 @@ hdd_association_completion_handler(struct hdd_adapter *adapter,
policy_mgr_check_concurrent_intf_and_restart_sap(hdd_ctx->psoc);
}
+ hdd_periodic_sta_stats_start(adapter);
+
return QDF_STATUS_SUCCESS;
}
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index 7aa815c58d66..b07bf368d0be 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -48,6 +48,7 @@
#include "wlan_hdd_ftm.h"
#include "wlan_hdd_power.h"
#include "wlan_hdd_stats.h"
+#include "wlan_hdd_periodic_sta_stats.h"
#include "wlan_hdd_scan.h"
#include "wlan_policy_mgr_ucfg.h"
#include "wlan_osif_priv.h"
@@ -5238,6 +5239,7 @@ static void hdd_cleanup_adapter(struct hdd_context *hdd_ctx,
hdd_nud_deinit_tracking(adapter);
hdd_mic_deinit_work(adapter);
qdf_mutex_destroy(&adapter->disconnection_status_lock);
+ hdd_periodic_sta_stats_mutex_destroy(adapter);
hdd_apf_context_destroy(adapter);
qdf_spinlock_destroy(&adapter->vdev_lock);
hdd_sta_info_deinit(&adapter->sta_info_list);
@@ -5896,6 +5898,7 @@ struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx, uint8_t sessio
adapter->device_mode == QDF_P2P_DEVICE_MODE)
hdd_sysfs_create_adapter_root_obj(adapter);
qdf_mutex_create(&adapter->disconnection_status_lock);
+ hdd_periodic_sta_stats_mutex_create(adapter);
break;
@@ -6028,6 +6031,8 @@ struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx, uint8_t sessio
if (adapter->device_mode == QDF_STA_MODE)
wlan_hdd_debugfs_csr_init(adapter);
+ hdd_periodic_sta_stats_init(adapter);
+
return adapter;
err_free_netdev:
@@ -8808,6 +8813,8 @@ static void hdd_pld_request_bus_bandwidth(struct hdd_context *hdd_ctx,
}
hdd_display_periodic_stats(hdd_ctx, (total_pkts > 0) ? true : false);
+
+ hdd_periodic_sta_stats_display(hdd_ctx);
}
#ifdef QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK
@@ -10614,6 +10621,7 @@ static void hdd_cfg_params_init(struct hdd_context *hdd_ctx)
config->enable_sar_conversion = cfg_get(psoc, CFG_SAR_CONVERSION);
config->is_wow_disabled = cfg_get(psoc, CFG_WOW_DISABLE);
+ hdd_periodic_sta_stats_config(config, psoc);
hdd_init_vc_mode_cfg_bitmap(config, psoc);
hdd_init_runtime_pm(config, psoc);
hdd_init_wlan_auto_shutdown(config, psoc);
diff --git a/core/hdd/src/wlan_hdd_periodic_sta_stats.c b/core/hdd/src/wlan_hdd_periodic_sta_stats.c
new file mode 100644
index 000000000000..1627f8528a1f
--- /dev/null
+++ b/core/hdd/src/wlan_hdd_periodic_sta_stats.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2020, 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.
+ */
+
+/**
+ * DOC : wlan_hdd_periodic_sta_stats.c
+ *
+ * WLAN Host Device Driver periodic STA statistics related implementation
+ *
+ */
+
+#include "wlan_hdd_main.h"
+#include "cfg_ucfg_api.h"
+#include "wlan_hdd_periodic_sta_stats.h"
+
+void hdd_periodic_sta_stats_config(struct hdd_config *config,
+ struct wlan_objmgr_psoc *psoc)
+{
+ config->periodic_stats_timer_interval =
+ cfg_get(psoc, CFG_PERIODIC_STATS_TIMER_INTERVAL);
+ config->periodic_stats_timer_duration =
+ cfg_get(psoc, CFG_PERIODIC_STATS_TIMER_DURATION);
+}
+
+void hdd_periodic_sta_stats_init(struct hdd_adapter *adapter)
+{
+ adapter->is_sta_periodic_stats_enabled = false;
+}
+
+void hdd_periodic_sta_stats_display(struct hdd_context *hdd_ctx)
+{
+ struct hdd_adapter *adapter;
+ struct hdd_stats sta_stats;
+ struct hdd_config *hdd_cfg;
+ char *dev_name;
+ bool should_log;
+
+ if (!hdd_ctx)
+ return;
+
+ hdd_for_each_adapter(hdd_ctx, adapter) {
+ should_log = false;
+
+ if (adapter->device_mode != QDF_STA_MODE)
+ continue;
+
+ hdd_cfg = hdd_ctx->config;
+ qdf_mutex_acquire(&adapter->sta_periodic_stats_lock);
+
+ if (!adapter->is_sta_periodic_stats_enabled) {
+ qdf_mutex_release(&adapter->sta_periodic_stats_lock);
+ continue;
+ }
+
+ adapter->periodic_stats_timer_counter++;
+ if ((adapter->periodic_stats_timer_counter *
+ GET_BW_COMPUTE_INTV(hdd_cfg)) >=
+ hdd_cfg->periodic_stats_timer_interval) {
+ should_log = true;
+
+ adapter->periodic_stats_timer_count--;
+ if (adapter->periodic_stats_timer_count == 0)
+ adapter->is_sta_periodic_stats_enabled = false;
+ adapter->periodic_stats_timer_counter = 0;
+ }
+ qdf_mutex_release(&adapter->sta_periodic_stats_lock);
+
+ if (should_log) {
+ dev_name = WLAN_HDD_GET_DEV_NAME(adapter);
+ sta_stats = adapter->hdd_stats;
+ hdd_nofl_info("%s: Tx ARP requests: %d", dev_name,
+ sta_stats.hdd_arp_stats.tx_arp_req_count);
+ hdd_nofl_info("%s: Rx ARP responses: %d", dev_name,
+ sta_stats.hdd_arp_stats.rx_arp_rsp_count);
+ hdd_nofl_info("%s: Tx DNS requests: %d", dev_name,
+ sta_stats.hdd_dns_stats.tx_dns_req_count);
+ hdd_nofl_info("%s: Rx DNS responses: %d", dev_name,
+ sta_stats.hdd_dns_stats.rx_dns_rsp_count);
+ }
+ }
+}
+
+void hdd_periodic_sta_stats_start(struct hdd_adapter *adapter)
+{
+ struct hdd_config *hdd_cfg = adapter->hdd_ctx->config;
+
+ if ((adapter->device_mode == QDF_STA_MODE) &&
+ (hdd_cfg->periodic_stats_timer_interval > 0)) {
+ qdf_mutex_acquire(&adapter->sta_periodic_stats_lock);
+
+ adapter->periodic_stats_timer_count =
+ hdd_cfg->periodic_stats_timer_duration /
+ hdd_cfg->periodic_stats_timer_interval;
+ adapter->periodic_stats_timer_counter = 0;
+ if (adapter->periodic_stats_timer_count > 0)
+ adapter->is_sta_periodic_stats_enabled = true;
+
+ qdf_mutex_release(&adapter->sta_periodic_stats_lock);
+ }
+}
+
+void hdd_periodic_sta_stats_stop(struct hdd_adapter *adapter)
+{
+ struct hdd_config *hdd_cfg = adapter->hdd_ctx->config;
+
+ if ((adapter->device_mode == QDF_STA_MODE) &&
+ (hdd_cfg->periodic_stats_timer_interval > 0)) {
+ qdf_mutex_acquire(&adapter->sta_periodic_stats_lock);
+
+ /* Stop the periodic ARP and DNS stats timer */
+ adapter->periodic_stats_timer_count = 0;
+ adapter->is_sta_periodic_stats_enabled = false;
+
+ qdf_mutex_release(&adapter->sta_periodic_stats_lock);
+ }
+}
+
+void hdd_periodic_sta_stats_mutex_create(struct hdd_adapter *adapter)
+{
+ qdf_mutex_create(&adapter->sta_periodic_stats_lock);
+}
+
+void hdd_periodic_sta_stats_mutex_destroy(struct hdd_adapter *adapter)
+{
+ qdf_mutex_destroy(&adapter->sta_periodic_stats_lock);
+}
+