qcacld-3.0: Return LL stats resp in caller context

Return response for Link Layer stats command in caller
thread's context.

Change-Id: I8a6a0b21d7915cd21422dbef9b87fa17d99fb244
CRs-Fixed: 2619295
This commit is contained in:
Rachit Kankane 2020-02-28 08:13:22 +05:30 committed by nshrivas
parent 95068d734f
commit 66b4b30bcf

View File

@ -82,6 +82,8 @@
#define HDD_INFO_FCS_ERROR_COUNT BIT_ULL(NL80211_STA_INFO_FCS_ERROR_COUNT)
#endif /* kernel version less than 4.0.0 && no_backport */
#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
@ -174,14 +176,39 @@ static int rssi_mcs_tbl[][12] = {
#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;
};
/**
* 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;
};
/*
@ -1002,72 +1029,115 @@ hdd_link_layer_process_radio_stats(struct hdd_adapter *adapter,
hdd_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(struct hdd_adapter *adapter,
uint32_t more_data, void *data, uint32_t num_radio,
uint32_t resp_id)
static void hdd_process_ll_stats(tSirLLStatsResults *results,
struct osif_request *request)
{
if (DEBUGFS_LLSTATS_REQID == resp_id)
hdd_debugfs_process_radio_stats(adapter, more_data,
(struct wifi_radio_stats *)data, num_radio);
else
hdd_link_layer_process_radio_stats(adapter, more_data,
(struct wifi_radio_stats *)data, num_radio);
struct hdd_ll_stats_priv *priv = osif_request_priv(request);
struct hdd_ll_stats *stats = NULL;
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(struct wifi_radio_stats));
if (!stats->result) {
qdf_mem_free(stats);
goto exit;
}
qdf_mem_copy(stats->result, results->results,
sizeof(struct wifi_radio_stats));
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(struct
wifi_interface_stats));
if (!stats->result) {
qdf_mem_free(stats);
goto exit;
}
qdf_mem_copy(stats->result, results->results,
sizeof(struct wifi_interface_stats));
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(struct wifi_peer_stat));
if (!stats->result) {
qdf_mem_free(stats);
goto exit;
}
qdf_mem_copy(stats->result, results->results,
sizeof(struct wifi_peer_stat));
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:
osif_request_complete(request);
}
/**
* 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(struct hdd_adapter *adapter,
void *data, uint32_t num_peers,
uint32_t resp_id)
static void hdd_debugfs_process_ll_stats(struct hdd_adapter *adapter,
tSirLLStatsResults *results,
struct osif_request *request)
{
if (DEBUGFS_LLSTATS_REQID == resp_id)
hdd_debugfs_process_iface_stats(adapter, data, num_peers);
else
hdd_link_layer_process_iface_stats(adapter, data, num_peers);
}
struct hdd_ll_stats_priv *priv = osif_request_priv(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(struct hdd_adapter *adapter,
uint32_t more_data, void *data, uint32_t resp_id)
{
if (DEBUGFS_LLSTATS_REQID == resp_id)
hdd_debugfs_process_peer_stats(adapter, data);
else
hdd_link_layer_process_peer_stats(adapter, more_data, data);
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)
osif_request_complete(request);
}
void wlan_hdd_cfg80211_link_layer_stats_callback(hdd_handle_t hdd_handle,
@ -1111,8 +1181,7 @@ void wlan_hdd_cfg80211_link_layer_stats_callback(hdd_handle_t hdd_handle,
priv = osif_request_priv(request);
/* validate response received from target */
if ((priv->request_id != results->rspId) ||
!(priv->request_bitmap & results->paramId)) {
if (priv->request_id != results->rspId) {
hdd_err("Request id %d response id %d request bitmap 0x%x response bitmap 0x%x",
priv->request_id, results->rspId,
priv->request_bitmap, results->paramId);
@ -1120,52 +1189,15 @@ void wlan_hdd_cfg80211_link_layer_stats_callback(hdd_handle_t hdd_handle,
return;
}
if (results->paramId & WMI_LINK_STATS_RADIO) {
hdd_ll_process_radio_stats(adapter,
results->moreResultToFollow,
results->results,
results->num_radio,
results->rspId);
if (!results->moreResultToFollow)
priv->request_bitmap &= ~(WMI_LINK_STATS_RADIO);
} else if (results->paramId &
WMI_LINK_STATS_IFACE) {
hdd_ll_process_iface_stats(adapter,
results->results,
results->num_peers,
results->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 (!results->num_peers)
priv->request_bitmap &=
~(WMI_LINK_STATS_ALL_PEER);
priv->request_bitmap &= ~(WMI_LINK_STATS_IFACE);
} else if (results->
paramId & WMI_LINK_STATS_ALL_PEER) {
hdd_ll_process_peer_stats(adapter,
results->moreResultToFollow,
results->results,
results->rspId);
if (!results->moreResultToFollow)
priv->request_bitmap &=
~(WMI_LINK_STATS_ALL_PEER);
} else {
hdd_err("INVALID LL_STATS_NOTIFY RESPONSE");
if (results->rspId == DEBUGFS_LLSTATS_REQID) {
hdd_debugfs_process_ll_stats(adapter, results, request);
} else {
qdf_spin_lock(&priv->ll_stats_lock);
if (priv->request_bitmap)
hdd_process_ll_stats(results, request);
qdf_spin_unlock(&priv->ll_stats_lock);
}
/* complete response event if all requests are completed */
if (!priv->request_bitmap)
osif_request_complete(request);
osif_request_put(request);
break;
}
@ -1344,12 +1376,41 @@ const struct nla_policy qca_wlan_vendor_ll_get_policy[
[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK] = {.type = NLA_U32}
};
static int wlan_hdd_send_ll_stats_req(struct hdd_context *hdd_ctx,
static void wlan_hdd_handle_ll_stats(struct hdd_adapter *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");
}
}
static int wlan_hdd_send_ll_stats_req(struct hdd_adapter *adapter,
tSirLLStatsGetReq *req)
{
int ret;
int ret = 0;
struct hdd_ll_stats_priv *priv;
struct hdd_ll_stats *stats = NULL;
struct osif_request *request;
qdf_list_node_t *ll_node;
QDF_STATUS status;
struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
void *cookie;
static const struct osif_request_params params = {
.priv_size = sizeof(*priv),
@ -1370,6 +1431,8 @@ static int wlan_hdd_send_ll_stats_req(struct hdd_context *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->mac_handle, req,
@ -1378,18 +1441,34 @@ static int wlan_hdd_send_ll_stats_req(struct hdd_context *hdd_ctx,
ret = -EINVAL;
goto exit;
}
ret = osif_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;
}
hdd_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:
hdd_exit();
osif_request_put(request);
return ret;
}
@ -1399,7 +1478,6 @@ 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_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
hdd_enter();
@ -1423,7 +1501,7 @@ int wlan_hdd_ll_stats_get(struct hdd_adapter *adapter, uint32_t req_id,
get_req.staId = adapter->vdev_id;
rtnl_lock();
errno = wlan_hdd_send_ll_stats_req(hdd_ctx, &get_req);
errno = wlan_hdd_send_ll_stats_req(adapter, &get_req);
rtnl_unlock();
if (errno)
hdd_err("Send LL stats req failed, id:%u, mask:%d, session:%d",
@ -1509,7 +1587,7 @@ __wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
if (wlan_hdd_validate_vdev_id(adapter->vdev_id))
return -EINVAL;
ret = wlan_hdd_send_ll_stats_req(hdd_ctx, &LinkLayerStatsGetReq);
ret = wlan_hdd_send_ll_stats_req(adapter, &LinkLayerStatsGetReq);
if (0 != ret) {
hdd_err("Failed to send LL stats request (id:%u)",
LinkLayerStatsGetReq.reqId);