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;