diff --git a/Kbuild b/Kbuild
index 34ffe69f358c..ad45cfb02b9c 100644
--- a/Kbuild
+++ b/Kbuild
@@ -2554,6 +2554,7 @@ cppflags-$(CONFIG_FEATURE_WLAN_LPHB) += -DFEATURE_WLAN_LPHB
cppflags-$(CONFIG_QCA_SUPPORT_TX_THROTTLE) += -DQCA_SUPPORT_TX_THROTTLE
cppflags-$(CONFIG_WMI_INTERFACE_EVENT_LOGGING) += -DWMI_INTERFACE_EVENT_LOGGING
cppflags-$(CONFIG_WLAN_FEATURE_LINK_LAYER_STATS) += -DWLAN_FEATURE_LINK_LAYER_STATS
+cppflags-$(CONFIG_FEATURE_CLUB_LL_STATS_AND_GET_STATION) += -DFEATURE_CLUB_LL_STATS_AND_GET_STATION
cppflags-$(CONFIG_WLAN_FEATURE_MIB_STATS) += -DWLAN_FEATURE_MIB_STATS
cppflags-$(CONFIG_FEATURE_WLAN_EXTSCAN) += -DFEATURE_WLAN_EXTSCAN
cppflags-$(CONFIG_160MHZ_SUPPORT) += -DCONFIG_160MHZ_SUPPORT
diff --git a/configs/default_defconfig b/configs/default_defconfig
index ca54414cd7aa..286c9e0b8d7d 100644
--- a/configs/default_defconfig
+++ b/configs/default_defconfig
@@ -946,6 +946,7 @@ CONFIG_FEATURE_WLAN_LPHB := y
CONFIG_QCA_SUPPORT_TX_THROTTLE := y
CONFIG_WMI_INTERFACE_EVENT_LOGGING := y
CONFIG_WLAN_FEATURE_LINK_LAYER_STATS := y
+CONFIG_FEATURE_CLUB_LL_STATS_AND_GET_STATION := y
CONFIG_FEATURE_WLAN_EXTSCAN := n
CONFIG_WMI_BCN_OFFLOAD := y
CONFIG_160MHZ_SUPPORT := y
diff --git a/core/hdd/inc/hdd_config.h b/core/hdd/inc/hdd_config.h
index 3d70042bbe41..02ac93802f6a 100644
--- a/core/hdd/inc/hdd_config.h
+++ b/core/hdd/inc/hdd_config.h
@@ -1536,6 +1536,64 @@ struct dhcp_server {
#define CFG_WLAN_STA_PERIODIC_STATS
#endif /* WLAN_FEATURE_PERIODIC_STA_STATS */
+#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION
+/*
+ *
+ * club_get_sta_in_ll_stats_req - Flag used to club ll_stats and get_station
+ * requests in the driver
+ *
+ * @Min: 0
+ * @Max: 1
+ * Default: 1
+ *
+ * This ini param is used to enable/disable the feature for clubbing ll stats
+ * and get station requests.
+ *
+ * Supported Feature: STA
+ *
+ * Usage: External
+ *
+ *
+ */
+#define CFG_CLUB_LL_STA_AND_GET_STATION CFG_INI_BOOL( \
+ "club_get_sta_in_ll_stats_req", \
+ 1, \
+ "Club ll_stats and get station requests")
+
+/*
+ *
+ * sta_stats_cache_expiry_time - Expiry time for cached station stats
+ *
+ * @Min: 0
+ * @Max: 5000
+ * Default: 200
+ *
+ * This ini is used as duration in milliseconds for which cached station stats
+ * are valid. Driver sends the cached information as response, if it gets the
+ * get_station request with in this duration. Otherwise driver sends new
+ * request to the firmware to get the updated stats.
+ *
+ * Supported Feature: STA
+ *
+ * Usage: External
+ *
+ *
+ */
+#define CFG_STA_STATS_CACHE_EXPIRY CFG_INI_UINT( \
+ "sta_stats_cache_expiry_time", \
+ 0, \
+ 5000, \
+ 200, \
+ CFG_VALUE_OR_DEFAULT, \
+ "Station stats cache expiry")
+
+#define CFG_WLAN_CLUB_GET_STA_IN_LL_STA_REQ \
+ CFG(CFG_CLUB_LL_STA_AND_GET_STATION) \
+ CFG(CFG_STA_STATS_CACHE_EXPIRY)
+#else
+#define CFG_WLAN_CLUB_GET_STA_IN_LL_STA_REQ
+#endif /* FEATURE_CLUB_LL_STATS_AND_GET_STATION */
+
/**
* enum host_log_level - Debug verbose level imposed by user
* @HOST_LOG_LEVEL_NONE: no trace will be logged.
@@ -1652,6 +1710,7 @@ enum host_log_level {
CFG_ENABLE_QMI_STATS_ALL \
CFG_VC_MODE_BITMAP_ALL \
CFG_WLAN_AUTO_SHUTDOWN_ALL \
+ CFG_WLAN_CLUB_GET_STA_IN_LL_STA_REQ \
CFG_WLAN_LOGGING_SUPPORT_ALL \
CFG_WLAN_STA_PERIODIC_STATS \
CFG(CFG_ACTION_OUI_CCKM_1X1) \
diff --git a/core/hdd/inc/wlan_hdd_cfg.h b/core/hdd/inc/wlan_hdd_cfg.h
index 29f9fc86bced..76b602a28be7 100644
--- a/core/hdd/inc/wlan_hdd_cfg.h
+++ b/core/hdd/inc/wlan_hdd_cfg.h
@@ -257,6 +257,10 @@ struct hdd_config {
uint32_t periodic_stats_timer_duration;
#endif /* WLAN_FEATURE_PERIODIC_STA_STATS */
uint8_t nb_commands_interval;
+
+#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION
+ uint32_t sta_stats_cache_expiry_time;
+#endif
};
/**
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h
index b5417fc8b784..c885a39fa75a 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -701,6 +701,11 @@ struct hdd_stats {
struct hdd_eapol_stats_s hdd_eapol_stats;
struct hdd_dhcp_stats_s hdd_dhcp_stats;
struct pmf_bcn_protect_stats bcn_protect_stats;
+
+#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION
+ uint32_t sta_stats_cached_timestamp;
+ bool is_ll_stats_req_in_progress;
+#endif
};
/**
@@ -2072,6 +2077,9 @@ struct hdd_context {
qdf_workqueue_t *adapter_ops_wq;
struct hdd_adapter_ops_history adapter_ops_history;
bool ll_stats_per_chan_rx_tx_time;
+#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION
+ bool is_get_station_clubbed_in_ll_stats_req;
+#endif
#ifdef FEATURE_WPSS_THERMAL_MITIGATION
bool multi_client_thermal_mitigation;
#endif
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index 56831e2e4c70..46f4ddad76e6 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -1596,6 +1596,52 @@ static inline void hdd_update_roam_offload(struct hdd_context *hdd_ctx,
}
#endif
+#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION
+static void
+hdd_club_ll_stats_in_get_sta_cfg_update(struct hdd_config *config,
+ struct wlan_objmgr_psoc *psoc)
+{
+ config->sta_stats_cache_expiry_time =
+ cfg_get(psoc, CFG_STA_STATS_CACHE_EXPIRY);
+}
+
+static void
+hdd_update_feature_cfg_club_get_sta_in_ll_stats_req(
+ struct hdd_context *hdd_ctx,
+ struct wma_tgt_services *cfg)
+{
+ hdd_ctx->is_get_station_clubbed_in_ll_stats_req =
+ cfg->is_get_station_clubbed_in_ll_stats_req &&
+ cfg_get(hdd_ctx->psoc,
+ CFG_CLUB_LL_STA_AND_GET_STATION);
+}
+
+static void
+hdd_init_get_sta_in_ll_stats_config(struct hdd_adapter *adapter)
+{
+ adapter->hdd_stats.is_ll_stats_req_in_progress = false;
+ adapter->hdd_stats.sta_stats_cached_timestamp = 0;
+}
+#else
+static void
+hdd_club_ll_stats_in_get_sta_cfg_update(struct hdd_config *config,
+ struct wlan_objmgr_psoc *psoc)
+{
+}
+
+static void
+hdd_update_feature_cfg_club_get_sta_in_ll_stats_req(
+ struct hdd_context *hdd_ctx,
+ struct wma_tgt_services *cfg)
+{
+}
+
+static void
+hdd_init_get_sta_in_ll_stats_config(struct hdd_adapter *adapter)
+{
+}
+#endif /* FEATURE_CLUB_LL_STATS_AND_GET_STATION */
+
static void hdd_update_tgt_services(struct hdd_context *hdd_ctx,
struct wma_tgt_services *cfg)
{
@@ -1672,6 +1718,8 @@ static void hdd_update_tgt_services(struct hdd_context *hdd_ctx,
hdd_ctx->roam_ch_from_fw_supported = cfg->is_roam_scan_ch_to_host;
hdd_ctx->ll_stats_per_chan_rx_tx_time =
cfg->ll_stats_per_chan_rx_tx_time;
+
+ hdd_update_feature_cfg_club_get_sta_in_ll_stats_req(hdd_ctx, cfg);
}
/**
@@ -5136,6 +5184,8 @@ hdd_alloc_station_adapter(struct hdd_context *hdd_ctx, tSirMacAddr mac_addr,
adapter->start_time = qdf_system_ticks();
adapter->last_time = adapter->start_time;
+ hdd_init_get_sta_in_ll_stats_config(adapter);
+
return adapter;
free_net_dev:
@@ -11997,6 +12047,7 @@ static void hdd_cfg_params_init(struct hdd_context *hdd_ctx)
hdd_dp_cfg_update(psoc, hdd_ctx);
hdd_sar_cfg_update(config, psoc);
hdd_init_qmi_stats(config, psoc);
+ hdd_club_ll_stats_in_get_sta_cfg_update(config, psoc);
}
struct hdd_context *hdd_context_create(struct device *dev)
diff --git a/core/hdd/src/wlan_hdd_stats.c b/core/hdd/src/wlan_hdd_stats.c
index bc7ba42dee22..cd708851e659 100644
--- a/core/hdd/src/wlan_hdd_stats.c
+++ b/core/hdd/src/wlan_hdd_stats.c
@@ -180,6 +180,8 @@ static int rssi_mcs_tbl[][12] = {
{-76, -73, -71, -68, -64, -60, -59, -58, -53, -51, -46, -42} /* 80 */
};
+static bool get_station_fw_request_needed = true;
+
#ifdef WLAN_FEATURE_LINK_LAYER_STATS
/**
@@ -1567,6 +1569,271 @@ static void wlan_hdd_dealloc_ll_stats(void *priv)
qdf_list_destroy(&ll_stats_priv->ll_stats_q);
}
+#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION
+static void
+hdd_update_station_stats_cached_timestamp(struct hdd_adapter *adapter)
+{
+ adapter->hdd_stats.sta_stats_cached_timestamp =
+ qdf_system_ticks_to_msecs(qdf_system_ticks());
+}
+#else
+static void
+hdd_update_station_stats_cached_timestamp(struct hdd_adapter *adapter)
+{
+}
+#endif /* FEATURE_CLUB_LL_STATS_AND_GET_STATION */
+
+/*
+ * copy_station_stats_to_adapter() - Copy station stats to adapter
+ * @adapter: Pointer to the adapter
+ * @stats: Pointer to the station stats event
+ *
+ * Return: 0 if success, non-zero for failure
+ */
+static int copy_station_stats_to_adapter(struct hdd_adapter *adapter,
+ struct stats_event *stats)
+{
+ int ret = 0;
+ struct wlan_mlme_nss_chains *dynamic_cfg;
+ uint32_t tx_nss, rx_nss;
+ struct wlan_objmgr_vdev *vdev;
+
+ vdev = hdd_objmgr_get_vdev(adapter);
+ if (!vdev)
+ return -EINVAL;
+
+ /* save summary stats to legacy location */
+ qdf_mem_copy(adapter->hdd_stats.summary_stat.retry_cnt,
+ stats->vdev_summary_stats[0].stats.retry_cnt,
+ sizeof(adapter->hdd_stats.summary_stat.retry_cnt));
+ qdf_mem_copy(
+ adapter->hdd_stats.summary_stat.multiple_retry_cnt,
+ stats->vdev_summary_stats[0].stats.multiple_retry_cnt,
+ sizeof(adapter->hdd_stats.summary_stat.multiple_retry_cnt));
+ qdf_mem_copy(adapter->hdd_stats.summary_stat.tx_frm_cnt,
+ stats->vdev_summary_stats[0].stats.tx_frm_cnt,
+ sizeof(adapter->hdd_stats.summary_stat.tx_frm_cnt));
+ qdf_mem_copy(adapter->hdd_stats.summary_stat.fail_cnt,
+ stats->vdev_summary_stats[0].stats.fail_cnt,
+ sizeof(adapter->hdd_stats.summary_stat.fail_cnt));
+ adapter->hdd_stats.summary_stat.snr =
+ stats->vdev_summary_stats[0].stats.snr;
+ adapter->hdd_stats.summary_stat.rssi =
+ stats->vdev_summary_stats[0].stats.rssi;
+ adapter->hdd_stats.summary_stat.rx_frm_cnt =
+ stats->vdev_summary_stats[0].stats.rx_frm_cnt;
+ adapter->hdd_stats.summary_stat.frm_dup_cnt =
+ stats->vdev_summary_stats[0].stats.frm_dup_cnt;
+ adapter->hdd_stats.summary_stat.rts_fail_cnt =
+ stats->vdev_summary_stats[0].stats.rts_fail_cnt;
+ adapter->hdd_stats.summary_stat.ack_fail_cnt =
+ stats->vdev_summary_stats[0].stats.ack_fail_cnt;
+ adapter->hdd_stats.summary_stat.rts_succ_cnt =
+ stats->vdev_summary_stats[0].stats.rts_succ_cnt;
+ adapter->hdd_stats.summary_stat.rx_discard_cnt =
+ stats->vdev_summary_stats[0].stats.rx_discard_cnt;
+ adapter->hdd_stats.summary_stat.rx_error_cnt =
+ stats->vdev_summary_stats[0].stats.rx_error_cnt;
+ adapter->hdd_stats.peer_stats.rx_count =
+ stats->peer_adv_stats->rx_count;
+ adapter->hdd_stats.peer_stats.rx_bytes =
+ stats->peer_adv_stats->rx_bytes;
+ adapter->hdd_stats.peer_stats.fcs_count =
+ stats->peer_adv_stats->fcs_count;
+
+ dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
+ if (!dynamic_cfg) {
+ hdd_err("nss chain dynamic config NULL");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ switch (hdd_conn_get_connected_band(&adapter->session.station)) {
+ case BAND_2G:
+ tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_2GHZ];
+ rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_2GHZ];
+ break;
+ case BAND_5G:
+ tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_5GHZ];
+ rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_5GHZ];
+ break;
+ default:
+ tx_nss = wlan_vdev_mlme_get_nss(vdev);
+ rx_nss = wlan_vdev_mlme_get_nss(vdev);
+ }
+
+ /* Intersection of self and AP's NSS capability */
+ if (tx_nss > wlan_vdev_mlme_get_nss(vdev))
+ tx_nss = wlan_vdev_mlme_get_nss(vdev);
+
+ if (rx_nss > wlan_vdev_mlme_get_nss(vdev))
+ rx_nss = wlan_vdev_mlme_get_nss(vdev);
+
+ /* save class a stats to legacy location */
+ adapter->hdd_stats.class_a_stat.tx_nss = tx_nss;
+ adapter->hdd_stats.class_a_stat.rx_nss = rx_nss;
+ adapter->hdd_stats.class_a_stat.tx_rate = stats->tx_rate;
+ adapter->hdd_stats.class_a_stat.rx_rate = stats->rx_rate;
+ adapter->hdd_stats.class_a_stat.tx_rx_rate_flags = stats->tx_rate_flags;
+ adapter->hdd_stats.class_a_stat.tx_mcs_index =
+ sme_get_mcs_idx(stats->tx_rate, stats->tx_rate_flags,
+ &adapter->hdd_stats.class_a_stat.tx_nss,
+ &adapter->hdd_stats.class_a_stat.tx_dcm,
+ &adapter->hdd_stats.class_a_stat.tx_gi,
+ &adapter->hdd_stats.class_a_stat.
+ tx_mcs_rate_flags);
+
+ adapter->hdd_stats.class_a_stat.rx_mcs_index =
+ sme_get_mcs_idx(stats->rx_rate, stats->tx_rate_flags,
+ &adapter->hdd_stats.class_a_stat.rx_nss,
+ &adapter->hdd_stats.class_a_stat.rx_dcm,
+ &adapter->hdd_stats.class_a_stat.rx_gi,
+ &adapter->hdd_stats.class_a_stat.
+ rx_mcs_rate_flags);
+
+ /* save per chain rssi to legacy location */
+ qdf_mem_copy(adapter->hdd_stats.per_chain_rssi_stats.rssi,
+ stats->vdev_chain_rssi[0].chain_rssi,
+ sizeof(stats->vdev_chain_rssi[0].chain_rssi));
+ adapter->hdd_stats.bcn_protect_stats = stats->bcn_protect_stats;
+out:
+ hdd_objmgr_put_vdev(vdev);
+ return ret;
+}
+
+#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION
+/**
+ * cache_station_stats_cb() - cache_station_stats_cb callback function
+ * @ev: station stats buffer
+ * @cookie: cookie that contains the address of the adapter corresponding to
+ * the request
+ *
+ * Return: None
+ */
+static void cache_station_stats_cb(struct stats_event *ev, void *cookie)
+{
+ struct hdd_adapter *adapter = cookie;
+ struct hdd_context *hdd_ctx = adapter->hdd_ctx;
+ uint8_t vdev_id = adapter->vdev_id;
+
+ hdd_for_each_adapter_dev_held(hdd_ctx, adapter) {
+ if (adapter->vdev_id != vdev_id) {
+ dev_put(adapter->dev);
+ continue;
+ }
+ copy_station_stats_to_adapter(adapter, ev);
+ /* dev_put has to be done here */
+ dev_put(adapter->dev);
+ break;
+ }
+}
+
+static void
+wlan_hdd_set_station_stats_request_pending(struct hdd_adapter *adapter)
+{
+ struct wlan_objmgr_peer *peer;
+ struct request_info info = {0};
+ struct wlan_objmgr_vdev *vdev;
+
+ if (!adapter->hdd_ctx->is_get_station_clubbed_in_ll_stats_req)
+ return;
+
+ vdev = hdd_objmgr_get_vdev(adapter);
+ if (!vdev)
+ return;
+
+ if (adapter->hdd_stats.is_ll_stats_req_in_progress) {
+ hdd_err("Previous ll_stats request is in progress");
+ goto get_station_stats_fail;
+ }
+
+ adapter->hdd_stats.is_ll_stats_req_in_progress = true;
+
+ info.cookie = adapter;
+ info.u.get_station_stats_cb = cache_station_stats_cb;
+ info.vdev_id = adapter->vdev_id;
+ info.pdev_id = wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev(vdev));
+ peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_OSIF_ID);
+ if (!peer) {
+ osif_err("peer is null");
+ goto get_station_stats_fail;
+ }
+
+ qdf_mem_copy(info.peer_mac_addr, peer->macaddr, QDF_MAC_ADDR_SIZE);
+
+ wlan_objmgr_peer_release_ref(peer, WLAN_OSIF_ID);
+
+ ucfg_mc_cp_stats_set_pending_req(wlan_vdev_get_psoc(vdev),
+ TYPE_STATION_STATS, &info);
+
+get_station_stats_fail:
+ hdd_objmgr_put_vdev(vdev);
+}
+
+static void
+wlan_hdd_reset_station_stats_request_pending(struct wlan_objmgr_psoc *psoc,
+ struct hdd_adapter *adapter)
+{
+ QDF_STATUS status;
+ struct request_info last_req = {0};
+ bool pending = false;
+
+ if (!adapter->hdd_ctx->is_get_station_clubbed_in_ll_stats_req)
+ return;
+
+ adapter->hdd_stats.is_ll_stats_req_in_progress = false;
+
+ status = ucfg_mc_cp_stats_get_pending_req(psoc, TYPE_STATION_STATS,
+ &last_req);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ hdd_err("ucfg_mc_cp_stats_get_pending_req failed");
+ return;
+ }
+
+ ucfg_mc_cp_stats_reset_pending_req(psoc, TYPE_STATION_STATS,
+ &last_req, &pending);
+}
+
+static QDF_STATUS wlan_hdd_stats_request_needed(struct hdd_adapter *adapter)
+{
+ if (adapter->device_mode != QDF_STA_MODE)
+ return QDF_STATUS_SUCCESS;
+
+ if (!adapter->hdd_ctx->config) {
+ hdd_err("Invalid hdd config");
+ return QDF_STATUS_E_INVAL;
+ }
+ if (adapter->hdd_ctx->is_get_station_clubbed_in_ll_stats_req) {
+ uint32_t stats_cached_duration;
+
+ stats_cached_duration =
+ qdf_system_ticks_to_msecs(qdf_system_ticks()) -
+ adapter->hdd_stats.sta_stats_cached_timestamp;
+ if (stats_cached_duration <=
+ adapter->hdd_ctx->config->sta_stats_cache_expiry_time)
+ return QDF_STATUS_E_ALREADY;
+ }
+ return QDF_STATUS_SUCCESS;
+}
+
+#else
+static void
+wlan_hdd_set_station_stats_request_pending(struct hdd_adapter *adapter)
+{
+}
+
+static void
+wlan_hdd_reset_station_stats_request_pending(struct wlan_objmgr_psoc *psoc,
+ struct hdd_adapter *adapter)
+{
+}
+
+static QDF_STATUS wlan_hdd_stats_request_needed(struct hdd_adapter *adapter)
+{
+ return QDF_STATUS_SUCCESS;
+}
+#endif /* FEATURE_CLUB_LL_STATS_AND_GET_STATION */
+
static int wlan_hdd_send_ll_stats_req(struct hdd_adapter *adapter,
tSirLLStatsGetReq *req)
{
@@ -1584,11 +1851,15 @@ static int wlan_hdd_send_ll_stats_req(struct hdd_adapter *adapter,
.dealloc = wlan_hdd_dealloc_ll_stats,
};
- hdd_enter();
+ hdd_enter_dev(adapter->dev);
+
+ wlan_hdd_set_station_stats_request_pending(adapter);
request = osif_request_alloc(¶ms);
if (!request) {
hdd_err("Request Allocation Failure");
+ wlan_hdd_reset_station_stats_request_pending(hdd_ctx->psoc,
+ adapter);
return -ENOMEM;
}
@@ -1601,11 +1872,12 @@ static int wlan_hdd_send_ll_stats_req(struct hdd_adapter *adapter,
qdf_spinlock_create(&priv->ll_stats_lock);
qdf_list_create(&priv->ll_stats_q, HDD_LINK_STATS_MAX);
- if (QDF_STATUS_SUCCESS !=
- sme_ll_stats_get_req(hdd_ctx->mac_handle, req,
- cookie)) {
+ status = sme_ll_stats_get_req(hdd_ctx->mac_handle, req, cookie);
+ if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("sme_ll_stats_get_req Failed");
- ret = -EINVAL;
+ ret = qdf_status_to_os_return(status);
+ wlan_hdd_reset_station_stats_request_pending(hdd_ctx->psoc,
+ adapter);
goto exit;
}
ret = osif_request_wait_for_response(request);
@@ -1616,6 +1888,10 @@ static int wlan_hdd_send_ll_stats_req(struct hdd_adapter *adapter,
priv->request_bitmap = 0;
qdf_spin_unlock(&priv->ll_stats_lock);
ret = -ETIMEDOUT;
+ wlan_hdd_reset_station_stats_request_pending(hdd_ctx->psoc,
+ adapter);
+ } else {
+ hdd_update_station_stats_cached_timestamp(adapter);
}
qdf_spin_lock(&priv->ll_stats_lock);
status = qdf_list_remove_front(&priv->ll_stats_q, &ll_node);
@@ -1643,9 +1919,10 @@ int wlan_hdd_ll_stats_get(struct hdd_adapter *adapter, uint32_t req_id,
{
int errno;
tSirLLStatsGetReq get_req;
- struct hdd_station_ctx *hddstactx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
+ struct hdd_station_ctx *hddstactx =
+ WLAN_HDD_GET_STATION_CTX_PTR(adapter);
- hdd_enter();
+ hdd_enter_dev(adapter->dev);
if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
hdd_warn("Command not allowed in FTM mode");
@@ -3239,6 +3516,12 @@ int wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy,
return errno;
}
+
+#else
+static QDF_STATUS wlan_hdd_stats_request_needed(struct hdd_adapter *adapter)
+{
+ return QDF_STATUS_SUCCESS;
+}
#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
#ifdef WLAN_FEATURE_STATS_EXT
@@ -5256,8 +5539,10 @@ static int _wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
struct station_info *sinfo)
{
struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
+ struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
int errno;
+ QDF_STATUS status;
errno = wlan_hdd_validate_context(hdd_ctx);
if (errno)
@@ -5266,13 +5551,26 @@ static int _wlan_hdd_cfg80211_get_station(struct wiphy *wiphy,
if (!qdf_ctx)
return -EINVAL;
- errno = wlan_hdd_qmi_get_sync_resume(hdd_ctx, qdf_ctx->dev);
- if (errno)
- return errno;
+ status = wlan_hdd_stats_request_needed(adapter);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ if (status == QDF_STATUS_E_ALREADY)
+ get_station_fw_request_needed = false;
+ else
+ return -EINVAL;
+ }
+
+ if (get_station_fw_request_needed) {
+ errno = wlan_hdd_qmi_get_sync_resume(hdd_ctx, qdf_ctx->dev);
+ if (errno)
+ return errno;
+ }
errno = __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo);
- wlan_hdd_qmi_put_suspend(hdd_ctx, qdf_ctx->dev);
+ if (get_station_fw_request_needed)
+ wlan_hdd_qmi_put_suspend(hdd_ctx, qdf_ctx->dev);
+
+ get_station_fw_request_needed = true;
return errno;
}
@@ -6133,10 +6431,11 @@ int wlan_hdd_get_station_stats(struct hdd_adapter *adapter)
{
int ret = 0;
struct stats_event *stats;
- struct wlan_mlme_nss_chains *dynamic_cfg;
- uint32_t tx_nss, rx_nss;
struct wlan_objmgr_vdev *vdev;
+ if (!get_station_fw_request_needed)
+ return 0;
+
vdev = hdd_objmgr_get_vdev(adapter);
if (!vdev)
return -EINVAL;
@@ -6147,99 +6446,7 @@ int wlan_hdd_get_station_stats(struct hdd_adapter *adapter)
goto out;
}
- /* save summary stats to legacy location */
- qdf_mem_copy(adapter->hdd_stats.summary_stat.retry_cnt,
- stats->vdev_summary_stats[0].stats.retry_cnt,
- sizeof(adapter->hdd_stats.summary_stat.retry_cnt));
- qdf_mem_copy(adapter->hdd_stats.summary_stat.multiple_retry_cnt,
- stats->vdev_summary_stats[0].stats.multiple_retry_cnt,
- sizeof(adapter->hdd_stats.summary_stat.multiple_retry_cnt));
- qdf_mem_copy(adapter->hdd_stats.summary_stat.tx_frm_cnt,
- stats->vdev_summary_stats[0].stats.tx_frm_cnt,
- sizeof(adapter->hdd_stats.summary_stat.tx_frm_cnt));
- qdf_mem_copy(adapter->hdd_stats.summary_stat.fail_cnt,
- stats->vdev_summary_stats[0].stats.fail_cnt,
- sizeof(adapter->hdd_stats.summary_stat.fail_cnt));
- adapter->hdd_stats.summary_stat.snr =
- stats->vdev_summary_stats[0].stats.snr;
- adapter->hdd_stats.summary_stat.rssi =
- stats->vdev_summary_stats[0].stats.rssi;
- adapter->hdd_stats.summary_stat.rx_frm_cnt =
- stats->vdev_summary_stats[0].stats.rx_frm_cnt;
- adapter->hdd_stats.summary_stat.frm_dup_cnt =
- stats->vdev_summary_stats[0].stats.frm_dup_cnt;
- adapter->hdd_stats.summary_stat.rts_fail_cnt =
- stats->vdev_summary_stats[0].stats.rts_fail_cnt;
- adapter->hdd_stats.summary_stat.ack_fail_cnt =
- stats->vdev_summary_stats[0].stats.ack_fail_cnt;
- adapter->hdd_stats.summary_stat.rts_succ_cnt =
- stats->vdev_summary_stats[0].stats.rts_succ_cnt;
- adapter->hdd_stats.summary_stat.rx_discard_cnt =
- stats->vdev_summary_stats[0].stats.rx_discard_cnt;
- adapter->hdd_stats.summary_stat.rx_error_cnt =
- stats->vdev_summary_stats[0].stats.rx_error_cnt;
- adapter->hdd_stats.peer_stats.rx_count =
- stats->peer_adv_stats->rx_count;
- adapter->hdd_stats.peer_stats.rx_bytes =
- stats->peer_adv_stats->rx_bytes;
- adapter->hdd_stats.peer_stats.fcs_count =
- stats->peer_adv_stats->fcs_count;
-
- dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
- if (!dynamic_cfg) {
- hdd_err("nss chain dynamic config NULL");
- wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
- ret = -EINVAL;
- goto out;
- }
-
- switch (hdd_conn_get_connected_band(&adapter->session.station)) {
- case BAND_2G:
- tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_2GHZ];
- rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_2GHZ];
- break;
- case BAND_5G:
- tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_5GHZ];
- rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_5GHZ];
- break;
- default:
- tx_nss = wlan_vdev_mlme_get_nss(vdev);
- rx_nss = wlan_vdev_mlme_get_nss(vdev);
- }
- /* Intersection of self and AP's NSS capability */
- if (tx_nss > wlan_vdev_mlme_get_nss(vdev))
- tx_nss = wlan_vdev_mlme_get_nss(vdev);
-
- if (rx_nss > wlan_vdev_mlme_get_nss(vdev))
- rx_nss = wlan_vdev_mlme_get_nss(vdev);
-
- /* save class a stats to legacy location */
- adapter->hdd_stats.class_a_stat.tx_nss = tx_nss;
- adapter->hdd_stats.class_a_stat.rx_nss = rx_nss;
- adapter->hdd_stats.class_a_stat.tx_rate = stats->tx_rate;
- adapter->hdd_stats.class_a_stat.rx_rate = stats->rx_rate;
- adapter->hdd_stats.class_a_stat.tx_rx_rate_flags = stats->tx_rate_flags;
- adapter->hdd_stats.class_a_stat.tx_mcs_index =
- sme_get_mcs_idx(stats->tx_rate, stats->tx_rate_flags,
- &adapter->hdd_stats.class_a_stat.tx_nss,
- &adapter->hdd_stats.class_a_stat.tx_dcm,
- &adapter->hdd_stats.class_a_stat.tx_gi,
- &adapter->hdd_stats.class_a_stat.
- tx_mcs_rate_flags);
-
- adapter->hdd_stats.class_a_stat.rx_mcs_index =
- sme_get_mcs_idx(stats->rx_rate, stats->tx_rate_flags,
- &adapter->hdd_stats.class_a_stat.rx_nss,
- &adapter->hdd_stats.class_a_stat.rx_dcm,
- &adapter->hdd_stats.class_a_stat.rx_gi,
- &adapter->hdd_stats.class_a_stat.
- rx_mcs_rate_flags);
-
- /* save per chain rssi to legacy location */
- qdf_mem_copy(adapter->hdd_stats.per_chain_rssi_stats.rssi,
- stats->vdev_chain_rssi[0].chain_rssi,
- sizeof(stats->vdev_chain_rssi[0].chain_rssi));
- adapter->hdd_stats.bcn_protect_stats = stats->bcn_protect_stats;
+ copy_station_stats_to_adapter(adapter, stats);
wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
out:
diff --git a/core/hdd/src/wlan_hdd_stats.h b/core/hdd/src/wlan_hdd_stats.h
index 1a6b5fece30b..00fc80374c6b 100644
--- a/core/hdd/src/wlan_hdd_stats.h
+++ b/core/hdd/src/wlan_hdd_stats.h
@@ -34,8 +34,12 @@
#define DATA_RATE_11AC_MCS_MASK 0x03
+#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION
/* LL stats get request time out value */
+#define WLAN_WAIT_TIME_LL_STATS 2000
+#else
#define WLAN_WAIT_TIME_LL_STATS 800
+#endif
#define WLAN_HDD_TGT_NOISE_FLOOR_DBM (-96)
diff --git a/core/wma/inc/wma_tgt_cfg.h b/core/wma/inc/wma_tgt_cfg.h
index faffe1e7a1ae..e22a0ea7458c 100644
--- a/core/wma/inc/wma_tgt_cfg.h
+++ b/core/wma/inc/wma_tgt_cfg.h
@@ -45,6 +45,8 @@
* @bcn_reception_stats: Beacon Reception stats capability
* @is_roam_scan_ch_to_host: Get roam scan channels from fw supported
* @ll_stats_per_chan_rx_tx_time: Per channel tx and rx time support in ll stats
+ * @is_get_station_clubbed_in_ll_stats_req: Get station req support within ll
+ * stats req
*/
struct wma_tgt_services {
uint32_t sta_power_save;
@@ -79,6 +81,9 @@ struct wma_tgt_services {
bool bcn_reception_stats;
bool is_roam_scan_ch_to_host;
bool ll_stats_per_chan_rx_tx_time;
+#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION
+ bool is_get_station_clubbed_in_ll_stats_req;
+#endif
};
/**
diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c
index ffca70d356aa..04a00a9b25c7 100644
--- a/core/wma/src/wma_main.c
+++ b/core/wma/src/wma_main.c
@@ -2822,6 +2822,23 @@ static inline void wma_trace_init(void)
}
#endif
+#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION
+static void wma_get_service_cap_club_get_sta_in_ll_stats_req(
+ struct wmi_unified *wmi_handle,
+ struct wma_tgt_services *cfg)
+{
+ cfg->is_get_station_clubbed_in_ll_stats_req =
+ wmi_service_enabled(wmi_handle,
+ wmi_service_get_station_in_ll_stats_req);
+}
+#else
+static void wma_get_service_cap_club_get_sta_in_ll_stats_req(
+ struct wmi_unified *wmi_handle,
+ struct wma_tgt_services *cfg)
+{
+}
+#endif /* FEATURE_CLUB_LL_STATS_AND_GET_STATION */
+
/**
* wma_open() - Allocate wma context and initialize it.
* @cds_context: cds context
@@ -4647,6 +4664,8 @@ static inline void wma_update_target_services(struct wmi_unified *wmi_handle,
cfg->ll_stats_per_chan_rx_tx_time =
wmi_service_enabled(wmi_handle,
wmi_service_ll_stats_per_chan_rx_tx_time);
+
+ wma_get_service_cap_club_get_sta_in_ll_stats_req(wmi_handle, cfg);
}
/**
diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c
index edc81f842fa6..6d4e884a8881 100644
--- a/core/wma/src/wma_utils.c
+++ b/core/wma/src/wma_utils.c
@@ -2341,27 +2341,27 @@ void wma_register_ll_stats_event_handler(tp_wma_handle wma_handle)
wmi_unified_register_event_handler(wma_handle->wmi_handle,
wmi_iface_link_stats_event_id,
wma_unified_link_iface_stats_event_handler,
- WMA_RX_SERIALIZER_CTX);
+ WMA_RX_WORK_CTX);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
wmi_peer_link_stats_event_id,
wma_unified_link_peer_stats_event_handler,
- WMA_RX_SERIALIZER_CTX);
+ WMA_RX_WORK_CTX);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
wmi_radio_link_stats_link,
wma_unified_link_radio_stats_event_handler,
- WMA_RX_SERIALIZER_CTX);
+ WMA_RX_WORK_CTX);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
wmi_radio_tx_power_level_stats_event_id,
wma_unified_radio_tx_power_level_stats_event_handler,
- WMA_RX_SERIALIZER_CTX);
+ WMA_RX_WORK_CTX);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
wmi_peer_sta_ps_statechg_event_id,
wma_peer_ps_evt_handler,
- WMA_RX_SERIALIZER_CTX);
+ WMA_RX_WORK_CTX);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
wmi_report_stats_event_id,
wma_ll_stats_evt_handler,
- WMA_RX_SERIALIZER_CTX);
+ WMA_RX_WORK_CTX);
}
@@ -2440,6 +2440,30 @@ QDF_STATUS wma_process_ll_stats_set_req(tp_wma_handle wma,
return QDF_STATUS_SUCCESS;
}
+#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION
+static QDF_STATUS
+wma_send_ll_stats_get_cmd(tp_wma_handle wma_handle,
+ struct ll_stats_get_params *cmd)
+{
+ if (!(cfg_get(wma_handle->psoc, CFG_CLUB_LL_STA_AND_GET_STATION) &&
+ wmi_service_enabled(wma_handle->wmi_handle,
+ wmi_service_get_station_in_ll_stats_req)))
+ return wmi_unified_process_ll_stats_get_cmd(
+ wma_handle->wmi_handle, cmd);
+
+ return wmi_process_unified_ll_stats_get_sta_cmd(
+ wma_handle->wmi_handle, cmd);
+}
+#else
+static QDF_STATUS
+wma_send_ll_stats_get_cmd(tp_wma_handle wma_handle,
+ struct ll_stats_get_params *cmd)
+{
+ return wmi_unified_process_ll_stats_get_cmd(wma_handle->wmi_handle,
+ cmd);
+}
+#endif
+
QDF_STATUS wma_process_ll_stats_get_req(tp_wma_handle wma,
const tpSirLLStatsGetReq getReq)
{
@@ -2473,7 +2497,7 @@ QDF_STATUS wma_process_ll_stats_get_req(tp_wma_handle wma,
return QDF_STATUS_E_FAILURE;
}
qdf_mem_copy(cmd.peer_macaddr.bytes, addr, QDF_MAC_ADDR_SIZE);
- ret = wmi_unified_process_ll_stats_get_cmd(wma->wmi_handle, &cmd);
+ ret = wma_send_ll_stats_get_cmd(wma, &cmd);
if (ret) {
wma_err("Failed to send get link stats request");
return QDF_STATUS_E_FAILURE;