diff options
author | Rachit Kankane <rkankane@codeaurora.org> | 2020-02-28 08:13:22 +0530 |
---|---|---|
committer | Isaac Chiou <isaacchiou@google.com> | 2020-05-27 18:51:07 +0800 |
commit | 16127b946cfbe2363cd8b4358d307a8526758066 (patch) | |
tree | 83aeca47e1036a7caea7dc0852a84442d8ef2fcc | |
parent | 60cc09490d380cf1e312b1cb3cec6d38e8b670a5 (diff) | |
download | qcacld-16127b946cfbe2363cd8b4358d307a8526758066.tar.gz |
qcacld-3.0: Return LL stats resp in caller context
Return response for Link Layer stats command in caller
thread's context
Bug: 153415344
Change-Id: I8a6a0b21d7915cd21422dbef9b87fa17d99fb244
CRs-Fixed: 2619295
-rw-r--r-- | core/hdd/src/wlan_hdd_stats.c | 314 | ||||
-rw-r--r-- | core/hdd/src/wlan_hdd_stats.h | 6 |
2 files changed, 198 insertions, 122 deletions
diff --git a/core/hdd/src/wlan_hdd_stats.c b/core/hdd/src/wlan_hdd_stats.c index 4c1a561199..962c630baf 100644 --- a/core/hdd/src/wlan_hdd_stats.c +++ b/core/hdd/src/wlan_hdd_stats.c @@ -38,6 +38,8 @@ #include "wma_api.h" #include "wma.h" +#define HDD_LINK_STATS_MAX 5 + /* 11B, 11G Rate table include Basic rate and Extended rate * The IDX field is the rate index * The HI field is the rate when RSSI is strong or being ignored @@ -128,10 +130,29 @@ static int rssi_mcs_tbl[][10] = { {-76, -73, -71, -68, -64, -60, -59, -58, -53, -51} /* 80 */ }; - #ifdef WLAN_FEATURE_LINK_LAYER_STATS /** + * struct hdd_ll_stats - buffered hdd link layer stats + * @ll_stats_node: pointer to next stats buffered in scheduler thread context + * @result_param_id: Received link layer stats ID + * @result: received stats from FW + * @more_data: if more stats are pending + * @no_of_radios: no of radios + * @no_of_peers: no of peers + */ +struct hdd_ll_stats { + qdf_list_node_t ll_stats_node; + u32 result_param_id; + void *result; + u32 more_data; + union { + u32 no_of_radios; + u32 no_of_peers; + } stats_nradio_npeer; +}; + +/** * put_wifi_rate_stat() - put wifi rate stats * @stats: Pointer to stats context * @vendor_event: Pointer to vendor event @@ -957,74 +978,114 @@ static void hdd_link_layer_process_radio_stats(hdd_adapter_t *pAdapter, EXIT(); } -/** - * hdd_ll_process_radio_stats() - Wrapper function for cfg80211/debugfs - * @adapter: Pointer to device adapter - * @more_data: More data - * @data: Pointer to stats data - * @num_radios: Number of radios - * @resp_id: Response ID from FW - * - * Receiving Link Layer Radio statistics from FW. This function is a wrapper - * function which calls cfg80211/debugfs functions based on the response ID. - * - * Return: None - */ -static void hdd_ll_process_radio_stats(hdd_adapter_t *adapter, - uint32_t more_data, void *data, uint32_t num_radio, - uint32_t resp_id) +static void hdd_process_ll_stats(tSirLLStatsResults *results, + struct hdd_request *request) { - if (DEBUGFS_LLSTATS_REQID == resp_id) - hdd_debugfs_process_radio_stats(adapter, more_data, - (tpSirWifiRadioStat)data, num_radio); - else - hdd_link_layer_process_radio_stats(adapter, more_data, - (tpSirWifiRadioStat)data, num_radio); -} + struct hdd_ll_stats_priv *priv = hdd_request_priv(request); + struct hdd_ll_stats *stats = NULL; -/** - * hdd_ll_process_iface_stats() - Wrapper function for cfg80211/debugfs - * @adapter: Pointer to device adapter - * @data: Pointer to stats data - * @num_peers: Number of peers - * @resp_id: Response ID from FW - * - * Receiving Link Layer Radio statistics from FW. This function is a wrapper - * function which calls cfg80211/debugfs functions based on the response ID. - * - * Return: None - */ -static void hdd_ll_process_iface_stats(hdd_adapter_t *adapter, - void *data, uint32_t num_peers, uint32_t resp_id) -{ - if (DEBUGFS_LLSTATS_REQID == resp_id) - hdd_debugfs_process_iface_stats(adapter, - (tpSirWifiIfaceStat) data, num_peers); - else - hdd_link_layer_process_iface_stats(adapter, - (tpSirWifiIfaceStat) data, num_peers); + if (!(priv->request_bitmap & results->paramId)) + return; + + if (results->paramId & WMI_LINK_STATS_RADIO) { + stats = qdf_mem_malloc(sizeof(*stats)); + if (!stats) + goto exit; + + stats->result_param_id = WMI_LINK_STATS_RADIO; + stats->result = qdf_mem_malloc(sizeof(tSirWifiRadioStat)); + if (!stats->result) { + qdf_mem_free(stats); + goto exit; + } + + qdf_mem_copy(stats->result, results->results, + sizeof(tSirWifiRadioStat)); + stats->stats_nradio_npeer.no_of_radios = results->num_radio; + stats->more_data = results->moreResultToFollow; + if (!results->moreResultToFollow) + priv->request_bitmap &= ~stats->result_param_id; + } else if (results->paramId & WMI_LINK_STATS_IFACE) { + stats = qdf_mem_malloc(sizeof(*stats)); + if (!stats) + goto exit; + + stats->result_param_id = WMI_LINK_STATS_IFACE; + stats->stats_nradio_npeer.no_of_peers = results->num_peers; + stats->result = qdf_mem_malloc(sizeof(tSirWifiIfaceStat)); + if (!stats->result) { + qdf_mem_free(stats); + goto exit; + } + qdf_mem_copy(stats->result, results->results, + sizeof(tpSirWifiIfaceStat)); + if (!results->num_peers) + priv->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER); + priv->request_bitmap &= ~stats->result_param_id; + } else if (results->paramId & WMI_LINK_STATS_ALL_PEER) { + stats = qdf_mem_malloc(sizeof(*stats)); + if (!stats) + goto exit; + + stats->result_param_id = WMI_LINK_STATS_ALL_PEER; + stats->result = qdf_mem_malloc(sizeof(tSirWifiPeerStat)); + if (!stats->result) { + qdf_mem_free(stats); + goto exit; + } + + qdf_mem_copy(stats->result, results->results, + sizeof(tSirWifiPeerStat)); + stats->more_data = results->moreResultToFollow; + if (!results->moreResultToFollow) + priv->request_bitmap &= ~stats->result_param_id; + } else { + hdd_err("INVALID LL_STATS_NOTIFY RESPONSE"); + } + /* send indication to caller thread */ + if (stats) + qdf_list_insert_back(&priv->ll_stats_q, &stats->ll_stats_node); + + if (!priv->request_bitmap) +exit: + hdd_request_complete(request); } -/** - * hdd_ll_process_peer_stats() - Wrapper function for cfg80211/debugfs - * @adapter: Pointer to device adapter - * @more_data: More data - * @data: Pointer to stats data - * @resp_id: Response ID from FW - * - * Receiving Link Layer Radio statistics from FW. This function is a wrapper - * function which calls cfg80211/debugfs functions based on the response ID. - * - * Return: None - */ -static void hdd_ll_process_peer_stats(hdd_adapter_t *adapter, - uint32_t more_data, void *data, uint32_t resp_id) +static void hdd_debugfs_process_ll_stats(hdd_adapter_t *adapter, + tSirLLStatsResults *results, + struct hdd_request *request) { - if (DEBUGFS_LLSTATS_REQID == resp_id) - hdd_debugfs_process_peer_stats(adapter, data); - else - hdd_link_layer_process_peer_stats(adapter, more_data, - (tpSirWifiPeerStat) data); + struct hdd_ll_stats_priv *priv = hdd_request_priv(request); + + if (results->paramId & WMI_LINK_STATS_RADIO) { + hdd_debugfs_process_radio_stats(adapter, + results->moreResultToFollow, + results->results, + results->num_radio); + if (!results->moreResultToFollow) + priv->request_bitmap &= ~(WMI_LINK_STATS_RADIO); + } else if (results->paramId & WMI_LINK_STATS_IFACE) { + hdd_debugfs_process_iface_stats(adapter, results->results, + results->num_peers); + + /* Firmware doesn't send peerstats event if no peers are + * connected. HDD should not wait for any peerstats in + * this case and return the status to middleware after + * receiving iface stats + */ + + if (!results->num_peers) + priv->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER); + } else if (results->paramId & WMI_LINK_STATS_ALL_PEER) { + hdd_debugfs_process_peer_stats(adapter, results->results); + if (!results->moreResultToFollow) + priv->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER); + } else { + hdd_err("INVALID LL_STATS_NOTIFY RESPONSE"); + } + + if (!priv->request_bitmap) + hdd_request_complete(request); } /** @@ -1084,61 +1145,25 @@ void wlan_hdd_cfg80211_link_layer_stats_callback(void *ctx, int indType, priv = hdd_request_priv(request); /* validate response received from target */ - if ((priv->request_id != linkLayerStatsResults->rspId) || - !(priv->request_bitmap & linkLayerStatsResults->paramId)) { - hdd_err("Error : Request id %d response id %d request bitmap 0x%x response bitmap 0x%x", - priv->request_id, linkLayerStatsResults->rspId, - priv->request_bitmap, linkLayerStatsResults->paramId); + if (priv->request_id != linkLayerStatsResults->rspId) { + hdd_err("Request id %d response id %d request bitmap 0x%x response bitmap 0x%x", + priv->request_id, linkLayerStatsResults->rspId, + priv->request_bitmap, linkLayerStatsResults->paramId); hdd_request_put(request); return; } - if (linkLayerStatsResults->paramId & WMI_LINK_STATS_RADIO) { - hdd_ll_process_radio_stats(pAdapter, - linkLayerStatsResults->moreResultToFollow, - linkLayerStatsResults->results, - linkLayerStatsResults->num_radio, - linkLayerStatsResults->rspId); - - if (!linkLayerStatsResults->moreResultToFollow) - priv->request_bitmap &= ~(WMI_LINK_STATS_RADIO); - - } else if (linkLayerStatsResults->paramId & - WMI_LINK_STATS_IFACE) { - hdd_ll_process_iface_stats(pAdapter, - linkLayerStatsResults->results, - linkLayerStatsResults->num_peers, - linkLayerStatsResults->rspId); - - /* Firmware doesn't send peerstats event if no peers are - * connected. HDD should not wait for any peerstats in - * this case and return the status to middleware after - * receiving iface stats - */ - if (!linkLayerStatsResults->num_peers) - priv->request_bitmap &= - ~(WMI_LINK_STATS_ALL_PEER); - priv->request_bitmap &= ~(WMI_LINK_STATS_IFACE); - - } else if (linkLayerStatsResults-> - paramId & WMI_LINK_STATS_ALL_PEER) { - hdd_ll_process_peer_stats(pAdapter, - linkLayerStatsResults->moreResultToFollow, - linkLayerStatsResults->results, - linkLayerStatsResults->rspId); - - if (!linkLayerStatsResults->moreResultToFollow) - priv->request_bitmap &= - ~(WMI_LINK_STATS_ALL_PEER); - - } else { - hdd_err("INVALID LL_STATS_NOTIFY RESPONSE"); + if (linkLayerStatsResults->rspId == DEBUGFS_LLSTATS_REQID) { + hdd_debugfs_process_ll_stats(pAdapter, + linkLayerStatsResults, + request); + } else { + qdf_spin_lock(&priv->ll_stats_lock); + if (priv->request_bitmap) + hdd_process_ll_stats(linkLayerStatsResults, request); + qdf_spin_unlock(&priv->ll_stats_lock); } - /* complete response event if all requests are completed */ - if (!priv->request_bitmap) - hdd_request_complete(request); - hdd_request_put(request); break; } @@ -1304,6 +1329,31 @@ nla_policy [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK] = {.type = NLA_U32} }; +static void wlan_hdd_handle_ll_stats(hdd_adapter_t *adapter, + struct hdd_ll_stats *stats) +{ + switch (stats->result_param_id) { + case WMI_LINK_STATS_RADIO: + hdd_link_layer_process_radio_stats(adapter, stats->more_data, + stats->result, + stats->stats_nradio_npeer. + no_of_radios); + break; + case WMI_LINK_STATS_IFACE: + hdd_link_layer_process_iface_stats(adapter, stats->result, + stats->stats_nradio_npeer. + no_of_peers); + break; + case WMI_LINK_STATS_ALL_PEER: + hdd_link_layer_process_peer_stats(adapter, + stats->more_data, + stats->result); + break; + default: + hdd_err("not requested event"); + } +} + /** * wlan_hdd_send_ll_stats_req() - send LL stats request * @hdd_ctx: pointer to hdd context @@ -1311,12 +1361,16 @@ nla_policy * * Return: 0 if success, non-zero if failure */ -static int wlan_hdd_send_ll_stats_req(hdd_context_t *hdd_ctx, +static int wlan_hdd_send_ll_stats_req(hdd_adapter_t *adapter, tSirLLStatsGetReq *req) { int ret = 0; - struct hdd_ll_stats_priv *priv = NULL; + struct hdd_ll_stats_priv *priv; + struct hdd_ll_stats *stats = NULL; struct hdd_request *request = NULL; + qdf_list_node_t *ll_node; + QDF_STATUS status; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); void *cookie = NULL; static const struct hdd_request_params params = { .priv_size = sizeof(*priv), @@ -1337,6 +1391,8 @@ static int wlan_hdd_send_ll_stats_req(hdd_context_t *hdd_ctx, priv->request_id = req->reqId; priv->request_bitmap = req->paramIdMask; + 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->hHal, req, cookie)) { @@ -1344,18 +1400,34 @@ static int wlan_hdd_send_ll_stats_req(hdd_context_t *hdd_ctx, ret = -EINVAL; goto exit; } - ret = hdd_request_wait_for_response(request); if (ret) { hdd_err("Target response timed out request id %d request bitmap 0x%x", priv->request_id, priv->request_bitmap); + qdf_spin_lock(&priv->ll_stats_lock); + priv->request_bitmap = 0; + qdf_spin_unlock(&priv->ll_stats_lock); ret = -ETIMEDOUT; - goto exit; } - EXIT(); - + qdf_spin_lock(&priv->ll_stats_lock); + status = qdf_list_remove_front(&priv->ll_stats_q, &ll_node); + qdf_spin_unlock(&priv->ll_stats_lock); + while (QDF_IS_STATUS_SUCCESS(status)) { + stats = qdf_container_of(ll_node, struct hdd_ll_stats, + ll_stats_node); + if (ret != -ETIMEDOUT) + wlan_hdd_handle_ll_stats(adapter, stats); + qdf_mem_free(stats->result); + qdf_mem_free(stats); + qdf_spin_lock(&priv->ll_stats_lock); + status = qdf_list_remove_front(&priv->ll_stats_q, &ll_node); + qdf_spin_unlock(&priv->ll_stats_lock); + } + qdf_list_destroy(&priv->ll_stats_q); exit: + EXIT(); hdd_request_put(request); + return ret; } @@ -1397,7 +1469,7 @@ int wlan_hdd_ll_stats_get(hdd_adapter_t *adapter, uint32_t req_id, } rtnl_lock(); - ret = wlan_hdd_send_ll_stats_req(hdd_ctx, &get_req); + ret = wlan_hdd_send_ll_stats_req(adapter, &get_req); rtnl_unlock(); if (0 != ret) hdd_err("Send LL stats req failed, id:%u, mask:%d, session:%d", @@ -1484,7 +1556,7 @@ __wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy, return -EINVAL; } - ret = wlan_hdd_send_ll_stats_req(pHddCtx, &LinkLayerStatsGetReq); + ret = wlan_hdd_send_ll_stats_req(pAdapter, &LinkLayerStatsGetReq); if (0 != ret) { hdd_err("Failed to send LL stats request (id:%u)", LinkLayerStatsGetReq.reqId); diff --git a/core/hdd/src/wlan_hdd_stats.h b/core/hdd/src/wlan_hdd_stats.h index cb030553d1..a2c736f7fc 100644 --- a/core/hdd/src/wlan_hdd_stats.h +++ b/core/hdd/src/wlan_hdd_stats.h @@ -84,13 +84,17 @@ struct index_data_rate_type { /** * struct hdd_ll_stats_priv - hdd link layer stats private - * + * @ll_stats: head to different link layer stats received in scheduler + * thread context * @request_id: userspace-assigned link layer stats request id * @request_bitmap: userspace-assigned link layer stats request bitmap + * @ll_stats_lock: Lock to serially access request_bitmap */ struct hdd_ll_stats_priv { + qdf_list_t ll_stats_q; uint32_t request_id; uint32_t request_bitmap; + qdf_spinlock_t ll_stats_lock; }; /* |