qcacmn: Extract and populate peer_extd2 stats from fw
Presently, the driver doesnot extract the peer extended2 stats
(rx_bytes, rx_count, fcs_err) that are received from firmware.
Provide the support to extract and populate the peer extended stats2 at
the driver level.
Change-Id: If1f1bb1ef2d1202581744dd509d0da1da718d8c1
CRs-Fixed: 2397638
diff --git a/os_if/linux/cp_stats/src/wlan_cfg80211_mc_cp_stats.c b/os_if/linux/cp_stats/src/wlan_cfg80211_mc_cp_stats.c
index 3f18ed6..8c20932 100644
--- a/os_if/linux/cp_stats/src/wlan_cfg80211_mc_cp_stats.c
+++ b/os_if/linux/cp_stats/src/wlan_cfg80211_mc_cp_stats.c
@@ -51,6 +51,7 @@
qdf_mem_free(stats->cca_stats);
qdf_mem_free(stats->vdev_summary_stats);
qdf_mem_free(stats->vdev_chain_rssi);
+ qdf_mem_free(stats->peer_adv_stats);
}
/**
@@ -419,7 +420,7 @@
{
struct stats_event *priv;
struct osif_request *request;
- uint32_t summary_size, rssi_size;
+ uint32_t summary_size, rssi_size, peer_adv_size;
request = osif_request_get(cookie);
if (!request) {
@@ -430,8 +431,10 @@
priv = osif_request_priv(request);
summary_size = sizeof(*ev->vdev_summary_stats) * ev->num_summary_stats;
rssi_size = sizeof(*ev->vdev_chain_rssi) * ev->num_chain_rssi_stats;
+ peer_adv_size = sizeof(*ev->peer_adv_stats) * ev->num_peer_adv_stats;
+
if (summary_size == 0 || rssi_size == 0) {
- cfg80211_err("Invalid stats, summary size %d rssi size %d",
+ cfg80211_err("Invalid stats, summary %d rssi %d",
summary_size, rssi_size);
goto station_stats_cb_fail;
}
@@ -444,11 +447,21 @@
if (!priv->vdev_chain_rssi)
goto station_stats_cb_fail;
+ if (peer_adv_size) {
+ priv->peer_adv_stats = qdf_mem_malloc(peer_adv_size);
+ if (!priv->peer_adv_stats)
+ goto station_stats_cb_fail;
+
+ qdf_mem_copy(priv->peer_adv_stats, ev->peer_adv_stats,
+ peer_adv_size);
+ }
+
priv->num_summary_stats = ev->num_summary_stats;
priv->num_chain_rssi_stats = ev->num_chain_rssi_stats;
priv->tx_rate = ev->tx_rate;
priv->rx_rate = ev->rx_rate;
priv->tx_rate_flags = ev->tx_rate_flags;
+ priv->num_peer_adv_stats = ev->num_peer_adv_stats;
qdf_mem_copy(priv->vdev_chain_rssi, ev->vdev_chain_rssi, rssi_size);
qdf_mem_copy(priv->vdev_summary_stats, ev->vdev_summary_stats,
summary_size);
@@ -517,7 +530,8 @@
if (!priv->vdev_summary_stats || !priv->vdev_chain_rssi ||
priv->num_summary_stats == 0 || priv->num_chain_rssi_stats == 0) {
- cfg80211_err("Invalid stats, summary %d:%pK, rssi %d:%pK",
+ cfg80211_err("Invalid stats");
+ cfg80211_err("summary %d:%pK, rssi %d:%pK",
priv->num_summary_stats, priv->vdev_summary_stats,
priv->num_chain_rssi_stats, priv->vdev_chain_rssi);
*errno = -EINVAL;
@@ -533,6 +547,10 @@
priv->vdev_summary_stats = NULL;
out->vdev_chain_rssi = priv->vdev_chain_rssi;
priv->vdev_chain_rssi = NULL;
+ out->num_peer_adv_stats = priv->num_peer_adv_stats;
+ if (priv->peer_adv_stats)
+ out->peer_adv_stats = priv->peer_adv_stats;
+ priv->peer_adv_stats = NULL;
osif_request_put(request);
return out;
@@ -554,5 +572,6 @@
qdf_mem_free(stats->cca_stats);
qdf_mem_free(stats->vdev_summary_stats);
qdf_mem_free(stats->vdev_chain_rssi);
+ qdf_mem_free(stats->peer_adv_stats);
qdf_mem_free(stats);
}
diff --git a/target_if/cp_stats/src/target_if_mc_cp_stats.c b/target_if/cp_stats/src/target_if_mc_cp_stats.c
index ae16d45..f125f83 100644
--- a/target_if/cp_stats/src/target_if_mc_cp_stats.c
+++ b/target_if/cp_stats/src/target_if_mc_cp_stats.c
@@ -41,6 +41,8 @@
ev->pdev_stats = NULL;
qdf_mem_free(ev->peer_stats);
ev->peer_stats = NULL;
+ qdf_mem_free(ev->peer_adv_stats);
+ ev->peer_adv_stats = NULL;
qdf_mem_free(ev->cca_stats);
ev->cca_stats = NULL;
qdf_mem_free(ev->vdev_summary_stats);
@@ -94,7 +96,9 @@
QDF_STATUS status;
wmi_host_peer_stats peer_stats;
bool db2dbm_enabled;
+ struct wmi_host_peer_adv_stats *peer_adv_stats;
+ /* Extract peer_stats */
ev->num_peer_stats = stats_param->num_peer_stats;
if (!ev->num_peer_stats)
return QDF_STATUS_SUCCESS;
@@ -109,11 +113,11 @@
for (i = 0; i < ev->num_peer_stats; i++) {
status = wmi_extract_peer_stats(wmi_hdl, data, i, &peer_stats);
if (QDF_IS_STATUS_ERROR(status)) {
- cp_stats_err("wmi_extract_pdev_stats failed");
+ cp_stats_err("wmi_extract_peer_stats failed");
continue;
}
WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats.peer_macaddr,
- ev->peer_stats[i].peer_macaddr);
+ ev->peer_stats[i].peer_macaddr);
ev->peer_stats[i].tx_rate = peer_stats.peer_tx_rate;
ev->peer_stats[i].rx_rate = peer_stats.peer_rx_rate;
if (db2dbm_enabled)
@@ -123,6 +127,41 @@
TGT_NOISE_FLOOR_DBM;
}
+ /* Extract peer_adv_stats */
+ ev->num_peer_adv_stats = stats_param->num_peer_adv_stats;
+ if (!ev->num_peer_adv_stats)
+ return QDF_STATUS_SUCCESS;
+
+ ev->peer_adv_stats = qdf_mem_malloc(sizeof(*ev->peer_adv_stats) *
+ ev->num_peer_adv_stats);
+ if (!ev->peer_adv_stats)
+ return QDF_STATUS_E_NOMEM;
+
+ peer_adv_stats = qdf_mem_malloc(sizeof(*peer_adv_stats) *
+ ev->num_peer_adv_stats);
+ if (!peer_adv_stats) {
+ qdf_mem_free(ev->peer_adv_stats);
+ return QDF_STATUS_E_NOMEM;
+ }
+
+ status = wmi_extract_peer_adv_stats(wmi_hdl, data, peer_adv_stats);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ cp_stats_err("wmi_extract_peer_stats failed");
+ qdf_mem_free(peer_adv_stats);
+ qdf_mem_free(ev->peer_adv_stats);
+ ev->peer_adv_stats = NULL;
+ return QDF_STATUS_SUCCESS;
+ }
+
+ for (i = 0; i < ev->num_peer_adv_stats; i++) {
+ qdf_mem_copy(&ev->peer_adv_stats[i].peer_macaddr,
+ &peer_adv_stats[i].peer_macaddr,
+ WLAN_MACADDR_LEN);
+ ev->peer_adv_stats[i].fcs_count = peer_adv_stats[i].fcs_count;
+ ev->peer_adv_stats[i].rx_bytes = peer_adv_stats[i].rx_bytes;
+ ev->peer_adv_stats[i].rx_count = peer_adv_stats[i].rx_count;
+ }
+ qdf_mem_free(peer_adv_stats);
return QDF_STATUS_SUCCESS;
}
@@ -280,6 +319,7 @@
stats_param.num_pdev_stats, stats_param.num_vdev_stats,
stats_param.num_peer_stats, stats_param.num_rssi_stats);
+ ev->last_event = stats_param.last_event;
status = target_if_cp_stats_extract_pdev_stats(wmi_hdl, &stats_param,
ev, data);
if (QDF_IS_STATUS_ERROR(status))
@@ -506,6 +546,7 @@
WMI_REQUEST_PEER_STAT |
WMI_REQUEST_VDEV_STAT |
WMI_REQUEST_PDEV_STAT |
+ WMI_REQUEST_PEER_EXTD2_STAT |
WMI_REQUEST_RSSI_PER_CHAIN_STAT);
}
diff --git a/umac/cp_stats/core/src/wlan_cp_stats_defs.h b/umac/cp_stats/core/src/wlan_cp_stats_defs.h
index e37a1be..dcad1b2 100644
--- a/umac/cp_stats/core/src/wlan_cp_stats_defs.h
+++ b/umac/cp_stats/core/src/wlan_cp_stats_defs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -87,12 +87,14 @@
* struct peer_cp_stats - defines cp stats at peer object
* @peer_obj: pointer to peer
* @peer_stats: pointer to ic/mc specific stats
+ * @peer_adv_stats: pointer to peer adv stats
* @peer_comp_priv_obj[]: component's private object pointers
* @peer_cp_stats_lock: lock to protect object
*/
struct peer_cp_stats {
struct wlan_objmgr_peer *peer_obj;
void *peer_stats;
+ void *peer_adv_stats;
void *peer_comp_priv_obj[WLAN_CP_STATS_MAX_COMPONENTS];
qdf_spinlock_t peer_cp_stats_lock;
};
diff --git a/umac/cp_stats/dispatcher/inc/wlan_cp_stats_mc_defs.h b/umac/cp_stats/dispatcher/inc/wlan_cp_stats_mc_defs.h
index 9556a41..bfca991 100644
--- a/umac/cp_stats/dispatcher/inc/wlan_cp_stats_mc_defs.h
+++ b/umac/cp_stats/dispatcher/inc/wlan_cp_stats_mc_defs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -33,6 +33,9 @@
#define MAX_NUM_CHAINS 2
+#define IS_MSB_SET(__num) ((__num) & BIT(31))
+#define IS_LSB_SET(__num) ((__num) & BIT(0))
+
/**
* enum stats_req_type - enum indicating bit position of various stats type in
* request map
@@ -249,6 +252,20 @@
};
/**
+ * struct peer_adv_mc_cp_stats - peer specific adv stats
+ * @peer_macaddr: mac address
+ * @fcs_count: fcs count
+ * @rx_bytes: rx bytes
+ * @rx_count: rx count
+ */
+struct peer_adv_mc_cp_stats {
+ uint8_t peer_macaddr[WLAN_MACADDR_LEN];
+ uint32_t fcs_count;
+ uint32_t rx_count;
+ uint64_t rx_bytes;
+};
+
+/**
* struct congestion_stats_event: congestion stats event param
* @vdev_id: vdev_id of the event
* @congestion: the congestion percentage
@@ -284,6 +301,8 @@
* @pdev_stats: if populated array indicating pdev stats (index = pdev_id)
* @num_peer_stats: num peer stats
* @peer_stats: if populated array indicating peer stats
+ * @peer_adv_stats: if populated, indicates peer adv (extd2) stats
+ * @num_peer_adv_stats: number of peer adv (extd2) stats
* @cca_stats: if populated indicates congestion stats
* @num_summary_stats: number of summary stats
* @vdev_summary_stats: if populated indicates array of summary stats per vdev
@@ -291,12 +310,16 @@
* @vdev_chain_rssi: if populated indicates array of chain rssi per vdev
* @tx_rate: tx rate (kbps)
* @tx_rate_flags: tx rate flags, (enum tx_rate_info)
+ * @last_event: The LSB indicates if the event is the last event or not and the
+ * MSB indicates if this feature is supported by FW or not.
*/
struct stats_event {
uint32_t num_pdev_stats;
struct pdev_mc_cp_stats *pdev_stats;
uint32_t num_peer_stats;
struct peer_mc_cp_stats *peer_stats;
+ uint32_t num_peer_adv_stats;
+ struct peer_adv_mc_cp_stats *peer_adv_stats;
struct congestion_stats_event *cca_stats;
uint32_t num_summary_stats;
struct summary_stats_event *vdev_summary_stats;
@@ -305,6 +328,7 @@
uint32_t tx_rate;
uint32_t rx_rate;
enum tx_rate_info tx_rate_flags;
+ uint32_t last_event;
};
#endif /* CONFIG_MCL */
diff --git a/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c b/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c
index 5198424..721f707 100644
--- a/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c
+++ b/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c
@@ -213,6 +213,54 @@
}
static QDF_STATUS
+tgt_mc_cp_stats_update_peer_adv_stats(struct wlan_objmgr_psoc *psoc,
+ struct peer_adv_mc_cp_stats
+ *peer_adv_stats, uint32_t size)
+{
+ uint8_t *peer_mac_addr;
+ struct wlan_objmgr_peer *peer;
+ struct peer_adv_mc_cp_stats *peer_adv_mc_stats;
+ QDF_STATUS status = QDF_STATUS_SUCCESS;
+ struct peer_cp_stats *peer_cp_stats_priv;
+
+ if (!peer_adv_stats)
+ return QDF_STATUS_E_INVAL;
+
+ peer_mac_addr = peer_adv_stats->peer_macaddr;
+ peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac_addr,
+ WLAN_CP_STATS_ID);
+ if (!peer) {
+ cp_stats_err("peer is null");
+ return QDF_STATUS_E_EXISTS;
+ }
+ peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer);
+ if (!peer_cp_stats_priv) {
+ cp_stats_err("peer_cp_stats_priv is null");
+ status = QDF_STATUS_E_EXISTS;
+ goto end;
+ }
+ wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv);
+ peer_adv_mc_stats = peer_cp_stats_priv->peer_adv_stats;
+
+ qdf_mem_copy(peer_adv_mc_stats->peer_macaddr,
+ peer_adv_stats->peer_macaddr,
+ WLAN_MACADDR_LEN);
+ if (peer_adv_stats->fcs_count)
+ peer_adv_mc_stats->fcs_count = peer_adv_stats->fcs_count;
+ if (peer_adv_stats->rx_bytes)
+ peer_adv_mc_stats->rx_bytes = peer_adv_stats->rx_bytes;
+ if (peer_adv_stats->rx_count)
+ peer_adv_mc_stats->rx_count = peer_adv_stats->rx_count;
+ wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv);
+
+end:
+ if (peer)
+ wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID);
+
+ return status;
+}
+
+static QDF_STATUS
tgt_mc_cp_stats_update_peer_stats(struct wlan_objmgr_psoc *psoc,
struct peer_mc_cp_stats *peer_stats)
{
@@ -273,10 +321,6 @@
struct request_info last_req = {0};
uint32_t selected;
- if (!ev->peer_stats) {
- cp_stats_err("no peer stats");
- return;
- }
if (is_station_stats)
status = ucfg_mc_cp_stats_get_pending_req(psoc,
@@ -292,6 +336,11 @@
return;
}
+ if (!ev->peer_stats) {
+ cp_stats_debug("no peer stats");
+ goto extd2_stats;
+ }
+
selected = ev->num_peer_stats;
for (i = 0; i < ev->num_peer_stats; i++) {
status = tgt_mc_cp_stats_update_peer_stats(psoc,
@@ -311,10 +360,40 @@
/* no matched peer */
if (!QDF_IS_ADDR_BROADCAST(last_req.peer_mac_addr) &&
selected == ev->num_peer_stats) {
- cp_stats_err("peer not found stats");
+ cp_stats_err("peer not found for stats");
+ }
+
+extd2_stats:
+
+ if (!ev->peer_adv_stats) {
+ cp_stats_err("no peer_extd2 stats");
+ goto complete;
+ }
+ selected = ev->num_peer_adv_stats;
+ for (i = 0; i < ev->num_peer_adv_stats; i++) {
+ status = tgt_mc_cp_stats_update_peer_adv_stats(
+ psoc, &ev->peer_adv_stats[i],
+ ev->num_peer_adv_stats);
+ if (!QDF_IS_ADDR_BROADCAST(last_req.peer_mac_addr) &&
+ !qdf_mem_cmp(ev->peer_adv_stats[i].peer_macaddr,
+ last_req.peer_mac_addr,
+ WLAN_MACADDR_LEN)) {
+ /* mac is specified, but failed to update the peer */
+ if (QDF_IS_STATUS_ERROR(status))
+ return;
+
+ selected = i;
+ }
+ }
+
+ /* no matched peer */
+ if (!QDF_IS_ADDR_BROADCAST(last_req.peer_mac_addr) &&
+ selected == ev->num_peer_adv_stats) {
+ cp_stats_err("peer not found for extd stats");
return;
}
+complete:
if (is_station_stats)
return;
@@ -563,6 +642,10 @@
info.tx_rate_flags = vdev_mc_stats->tx_rate_flags;
wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv);
+ info.peer_adv_stats = qdf_mem_malloc(sizeof(*info.peer_adv_stats));
+ if (!info.peer_adv_stats)
+ goto end;
+
wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv);
peer_mc_stats = peer_cp_stats_priv->peer_stats;
/*
@@ -571,6 +654,14 @@
*/
info.tx_rate = peer_mc_stats->tx_rate / 100;
info.rx_rate = peer_mc_stats->rx_rate / 100;
+
+ if (peer_cp_stats_priv->peer_adv_stats) {
+ info.num_peer_adv_stats = 1;
+ qdf_mem_copy(info.peer_adv_stats,
+ peer_cp_stats_priv->peer_adv_stats,
+ sizeof(peer_cp_stats_priv->peer_adv_stats));
+ }
+
wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv);
end:
@@ -590,10 +681,14 @@
struct stats_event *ev)
{
QDF_STATUS status;
- bool is_peer_stats;
+ bool is_last_event;
struct request_info last_req = {0};
- is_peer_stats = (ev->peer_stats != NULL);
+ if (IS_MSB_SET(ev->last_event))
+ is_last_event = IS_LSB_SET(ev->last_event);
+ else
+ is_last_event = !!ev->peer_stats;
+
status = ucfg_mc_cp_stats_get_pending_req(psoc,
TYPE_STATION_STATS,
&last_req);
@@ -611,7 +706,7 @@
* PEER stats are the last stats sent for get_station statistics.
* reset type_map bit for station stats .
*/
- if (is_peer_stats) {
+ if (is_last_event) {
tgt_mc_cp_stats_prepare_n_send_raw_station_stats(psoc,
&last_req);
ucfg_mc_cp_stats_reset_pending_req(psoc, TYPE_STATION_STATS);
diff --git a/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c b/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c
index 7a77704..def4b8c 100644
--- a/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c
+++ b/umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c
@@ -85,11 +85,20 @@
if (!peer_cs->peer_stats)
return QDF_STATUS_E_NOMEM;
+ peer_cs->peer_adv_stats = qdf_mem_malloc(sizeof
+ (struct peer_adv_mc_cp_stats));
+ if (!peer_cs->peer_adv_stats) {
+ cp_stats_err("malloc failed");
+ qdf_mem_free(peer_cs->peer_stats);
+ return QDF_STATUS_E_NOMEM;
+ }
return QDF_STATUS_SUCCESS;
}
QDF_STATUS wlan_cp_stats_peer_cs_deinit(struct peer_cp_stats *peer_cs)
{
+ qdf_mem_free(peer_cs->peer_adv_stats);
+ peer_cs->peer_adv_stats = NULL;
qdf_mem_free(peer_cs->peer_stats);
peer_cs->peer_stats = NULL;
return QDF_STATUS_SUCCESS;
@@ -554,6 +563,7 @@
return;
qdf_mem_free(ev->pdev_stats);
+ qdf_mem_free(ev->peer_adv_stats);
qdf_mem_free(ev->peer_stats);
qdf_mem_free(ev->cca_stats);
qdf_mem_free(ev->vdev_summary_stats);