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:
parent
95068d734f
commit
66b4b30bcf
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user