prima: Synchronize get link layer stats vendor command
Synchronize get link layer stats vendor command.
Change-Id: Ie43406762feac98eb4962716f28733e2645c93b6
CRs-Fixed: 891513
diff --git a/CORE/HDD/inc/wlan_hdd_cfg80211.h b/CORE/HDD/inc/wlan_hdd_cfg80211.h
index 2db93da..c90e83b 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg80211.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg80211.h
@@ -323,6 +323,28 @@
QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_AFTER_LAST - 1,
};
+/**
+ * enum qca_wlan_vendor_attr_ll_stats_results_type - ll stats result type
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_INVALID: Initial invalid value
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO: Link layer stats type radio
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_IFACE: Link layer stats type interface
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_PEER: Link layer stats type peer
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_AFTER_LAST: Last value
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_MAX: Max value
+ */
+enum qca_wlan_vendor_attr_ll_stats_results_type {
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_INVALID = 0,
+
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO = 1,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_IFACE,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_PEER,
+
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_MAX =
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_AFTER_LAST - 1
+};
+
enum qca_wlan_vendor_attr_ll_stats_results
{
QCA_WLAN_VENDOR_ATTR_LL_STATS_INVALID = 0,
@@ -561,6 +583,9 @@
/* Unsigned 32bit value */
QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME,
+ /* Unsigned 32bit value to indicate ll stats result type */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX =
@@ -874,6 +899,7 @@
#define WIFI_FEATURE_EPR 0x4000 /* Enhanced power reporting */
#define WIFI_FEATURE_AP_STA 0x8000 /* Support for AP STA
Concurrency */
+
/* Add more features here */
enum qca_wlan_vendor_attr_set_no_dfs_flag
{
diff --git a/CORE/HDD/inc/wlan_hdd_main.h b/CORE/HDD/inc/wlan_hdd_main.h
index 98b39cb..274d508 100644
--- a/CORE/HDD/inc/wlan_hdd_main.h
+++ b/CORE/HDD/inc/wlan_hdd_main.h
@@ -1206,6 +1206,23 @@
struct mutex macSpoofingLock;
}macAddrSpoof_t;
+#define WLAN_WAIT_TIME_LL_STATS 5000
+
+#ifdef WLAN_FEATURE_LINK_LAYER_STATS
+/**
+ * struct hdd_ll_stats_context - hdd link layer stats context
+ *
+ * @request_id: userspace-assigned link layer stats request id
+ * @request_bitmap: userspace-assigned link layer stats request bitmap
+ * @response_event: LL stats request wait event
+ */
+struct hdd_ll_stats_context {
+ uint32_t request_id;
+ uint32_t request_bitmap;
+ struct completion response_event;
+};
+#endif /* End of WLAN_FEATURE_LINK_LAYER_STATS */
+
/** Adapter stucture definition */
struct hdd_context_s
@@ -1427,6 +1444,9 @@
struct mutex wmmLock;
v_BOOL_t mgmt_frame_logging;
v_BOOL_t isSetBandByNL;
+#ifdef WLAN_FEATURE_LINK_LAYER_STATS
+ struct hdd_ll_stats_context ll_stats_context;
+#endif /* End of WLAN_FEATURE_LINK_LAYER_STATS */
};
@@ -1671,4 +1691,26 @@
int hdd_sta_id_find_from_mac_addr(hdd_adapter_t *pAdapter,
v_MACADDR_t *mac_addr_in);
void hdd_init_frame_logging(hdd_context_t *pHddCtx);
+
+#ifdef WLAN_FEATURE_LINK_LAYER_STATS
+/**
+ * hdd_init_ll_stats_ctx() - initialize link layer stats context
+ * @hdd_ctx: Pointer to hdd context
+ *
+ * Return: none
+ */
+static inline void hdd_init_ll_stats_ctx(hdd_context_t *hdd_ctx)
+{
+ init_completion(&hdd_ctx->ll_stats_context.response_event);
+ hdd_ctx->ll_stats_context.request_bitmap = 0;
+
+ return;
+}
+#else
+static inline void hdd_init_ll_stat_ctx(void)
+{
+ return;
+}
+#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
+
#endif // end #if !defined( WLAN_HDD_MAIN_H )
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 90c62ff..5e1ab6a 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -1074,6 +1074,9 @@
if (nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_IFACE) ||
+ nla_put_u32(vendor_event,
QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX,
pWifiIfaceStat->beaconRx) ||
nla_put_u32(vendor_event,
@@ -1316,21 +1319,19 @@
* that number of rates shall not exceed beyond 50 with
* the sizeof (tSirWifiRateStat) being 32.
*/
- vendor_event = cfg80211_vendor_event_alloc(pHddCtx->wiphy,
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
- NULL,
-#endif
- LL_STATS_EVENT_BUF_SIZE + NLMSG_HDRLEN,
- QCA_NL80211_VENDOR_SUBCMD_LL_PEER_INFO_STATS_INDEX,
- GFP_KERNEL);
+ vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy,
+ LL_STATS_EVENT_BUF_SIZE);
if (!vendor_event)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
- "%s: cfg80211_vendor_event_alloc failed",
+ "%s: cfg80211_vendor_cmd_alloc_reply_skb failed",
__func__);
return;
}
if (nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_PEER) ||
+ nla_put_u32(vendor_event,
QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS,
pWifiPeerStat->numPeers))
{
@@ -1383,8 +1384,7 @@
nla_nest_end(vendor_event, peers);
}
nla_nest_end(vendor_event, peerInfo);
- cfg80211_vendor_event(vendor_event, GFP_KERNEL);
-
+ cfg80211_vendor_cmd_reply(vendor_event);
EXIT();
}
@@ -1416,17 +1416,12 @@
* a call on the limit based on the data requirements on
* interface statistics.
*/
- vendor_event = cfg80211_vendor_event_alloc(pHddCtx->wiphy,
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
- NULL,
-#endif
- LL_STATS_EVENT_BUF_SIZE + NLMSG_HDRLEN,
- QCA_NL80211_VENDOR_SUBCMD_LL_IFACE_STATS_INDEX,
- GFP_KERNEL);
+ vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy,
+ LL_STATS_EVENT_BUF_SIZE);
if (!vendor_event)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
- FL("cfg80211_vendor_event_alloc failed") );
+ FL("cfg80211_vendor_cmd_alloc_reply_skb failed") );
return;
}
@@ -1541,7 +1536,7 @@
}
}
- cfg80211_vendor_event(vendor_event, GFP_KERNEL);
+ cfg80211_vendor_cmd_reply(vendor_event);
EXIT();
}
@@ -1596,22 +1591,19 @@
* sizeof (tSirWifiChannelStats) being 24 bytes.
*/
- vendor_event = cfg80211_vendor_event_alloc(pHddCtx->wiphy,
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
- NULL,
-#endif
- LL_STATS_EVENT_BUF_SIZE + NLMSG_HDRLEN ,
- QCA_NL80211_VENDOR_SUBCMD_LL_RADIO_STATS_INDEX,
- GFP_KERNEL);
-
+ vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy,
+ LL_STATS_EVENT_BUF_SIZE);
if (!vendor_event)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
- FL("cfg80211_vendor_event_alloc failed") );
+ FL("cfg80211_vendor_cmd_alloc_reply_skb failed") );
return;
}
if (nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO) ||
+ nla_put_u32(vendor_event,
QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID,
pWifiRadioStat->radio) ||
nla_put_u32(vendor_event,
@@ -1724,7 +1716,7 @@
}
nla_nest_end(vendor_event, chList);
- cfg80211_vendor_event(vendor_event, GFP_KERNEL);
+ cfg80211_vendor_cmd_reply(vendor_event);
EXIT();
return;
@@ -1741,6 +1733,7 @@
{
hdd_context_t *pHddCtx = (hdd_context_t *)pCtx;
hdd_adapter_t *pAdapter = NULL;
+ struct hdd_ll_stats_context *context;
tpSirLLStatsResults linkLayerStatsResults = (tpSirLLStatsResults)pRsp;
int status;
@@ -1786,21 +1779,46 @@
hddLog(VOS_TRACE_LEVEL_INFO,
"LL_STATS RESULTS RESPONSE result = %p",
linkLayerStatsResults->result);
+ spin_lock(&hdd_context_lock);
+ context = &pHddCtx->ll_stats_context;
+ /* validate response received from target */
+ if ((context->request_id != linkLayerStatsResults->respId) ||
+ !(context->request_bitmap & linkLayerStatsResults->paramId))
+ {
+ spin_unlock(&hdd_context_lock);
+ hddLog(LOGE,
+ FL("Error : Request id %d response id %d request bitmap 0x%x"
+ "response bitmap 0x%x"),
+ context->request_id, linkLayerStatsResults->respId,
+ context->request_bitmap, linkLayerStatsResults->paramId);
+ return;
+ }
+ spin_unlock(&hdd_context_lock);
+
if ( linkLayerStatsResults->paramId & WMI_LINK_STATS_RADIO )
{
hdd_link_layer_process_radio_stats(pAdapter,
(v_VOID_t *)linkLayerStatsResults->result);
+ spin_lock(&hdd_context_lock);
+ context->request_bitmap &= ~(WMI_LINK_STATS_RADIO);
+ spin_unlock(&hdd_context_lock);
}
else if ( linkLayerStatsResults->paramId & WMI_LINK_STATS_IFACE )
{
hdd_link_layer_process_iface_stats(pAdapter,
(v_VOID_t *)linkLayerStatsResults->result);
+ spin_lock(&hdd_context_lock);
+ context->request_bitmap &= ~(WMI_LINK_STATS_IFACE);
+ spin_unlock(&hdd_context_lock);
}
else if ( linkLayerStatsResults->paramId &
WMI_LINK_STATS_ALL_PEER )
{
hdd_link_layer_process_peer_stats(pAdapter,
(v_VOID_t *)linkLayerStatsResults->result);
+ spin_lock(&hdd_context_lock);
+ context->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER);
+ spin_unlock(&hdd_context_lock);
} /* WMI_LINK_STATS_ALL_PEER */
else
{
@@ -1808,6 +1826,12 @@
FL("INVALID LL_STATS_NOTIFY RESPONSE ***********"));
}
+ spin_lock(&hdd_context_lock);
+ /* complete response event if all requests are completed */
+ if (0 == context->request_bitmap)
+ complete(&context->response_event);
+ spin_unlock(&hdd_context_lock);
+
break;
}
default:
@@ -1968,6 +1992,8 @@
const void *data,
int data_len)
{
+ unsigned long rc;
+ struct hdd_ll_stats_context *context;
hdd_context_t *pHddCtx = wiphy_priv(wiphy);
struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1];
tSirLLStatsGetReq linkLayerStatsGetReq;
@@ -2064,6 +2090,13 @@
"LL_STATS_GET paramIdMask = %d",
linkLayerStatsGetReq.paramIdMask);
+ spin_lock(&hdd_context_lock);
+ context = &pHddCtx->ll_stats_context;
+ context->request_id = linkLayerStatsGetReq.reqId;
+ context->request_bitmap = linkLayerStatsGetReq.paramIdMask;
+ INIT_COMPLETION(context->response_event);
+ spin_unlock(&hdd_context_lock);
+
if (eHAL_STATUS_SUCCESS != sme_LLStatsGetReq( pHddCtx->hHal,
&linkLayerStatsGetReq))
{
@@ -2072,6 +2105,16 @@
return -EINVAL;
}
+ rc = wait_for_completion_timeout(&context->response_event,
+ msecs_to_jiffies(WLAN_WAIT_TIME_LL_STATS));
+ if (!rc)
+ {
+ hddLog(LOGE,
+ FL("Target response timed out request id %d request bitmap 0x%x"),
+ context->request_id, context->request_bitmap);
+ return -ETIMEDOUT;
+ }
+
EXIT();
return 0;
}
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
index 06886e6..d3e7c8a 100755
--- a/CORE/HDD/src/wlan_hdd_main.c
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -9490,6 +9490,8 @@
init_completion(&pHddCtx->wiphy_channel_update_event);
init_completion(&pHddCtx->ssr_comp_var);
+ hdd_init_ll_stats_ctx(pHddCtx);
+
#ifdef CONFIG_ENABLE_LINUX_REG
init_completion(&pHddCtx->linux_reg_req);
#else