/* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. 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 * above copyright notice and this permission notice appear in all * copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /** * DOC:wlan_cp_stats_mc_tgt_api.c * * This file provide API definitions to update control plane statistics received * from southbound interface */ #include "wlan_cp_stats_mc_defs.h" #include "target_if_cp_stats.h" #include "wlan_cp_stats_tgt_api.h" #include "wlan_cp_stats_ucfg_api.h" #include "wlan_cp_stats_mc_tgt_api.h" #include #include #include "../../core/src/wlan_cp_stats_defs.h" #include "../../core/src/wlan_cp_stats_obj_mgr_handler.h" #include "son_api.h" #include "wlan_policy_mgr_api.h" static bool tgt_mc_cp_stats_is_last_event(struct stats_event *ev, enum stats_req_type stats_type) { bool is_last_event; if (IS_MSB_SET(ev->last_event)) { is_last_event = IS_LSB_SET(ev->last_event); } else { if (stats_type == TYPE_CONNECTION_TX_POWER) is_last_event = true; else is_last_event = !!ev->peer_stats; } if (is_last_event) cp_stats_debug("Last stats event"); return is_last_event; } #ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS static void tgt_cp_stats_register_infra_cp_stats_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops) { rx_ops->cp_stats_rx_ops.process_infra_stats_event = tgt_mc_cp_stats_process_infra_stats_event; } #else static void tgt_cp_stats_register_infra_cp_stats_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops) { } #endif #ifdef WLAN_FEATURE_BIG_DATA_STATS static void tgt_cp_stats_register_big_data_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops) { rx_ops->cp_stats_rx_ops.process_big_data_stats_event = tgt_mc_cp_stats_process_big_data_stats_event; } static QDF_STATUS send_big_data_stats_req(struct wlan_lmac_if_cp_stats_tx_ops *tx_ops, struct wlan_objmgr_psoc *psoc, struct request_info *req) { if (!tx_ops->send_req_big_data_stats) { cp_stats_err("could not get send_req_big_data_stats"); return QDF_STATUS_E_NULL_VALUE; } return tx_ops->send_req_big_data_stats(psoc, req); } #else static void tgt_cp_stats_register_big_data_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops) {} static QDF_STATUS send_big_data_stats_req(struct wlan_lmac_if_cp_stats_tx_ops *tx_ops, struct wlan_objmgr_psoc *psoc, struct request_info *req) { return QDF_STATUS_SUCCESS; } #endif void tgt_cp_stats_register_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops) { rx_ops->cp_stats_rx_ops.process_stats_event = tgt_mc_cp_stats_process_stats_event; tgt_cp_stats_register_infra_cp_stats_rx_ops(rx_ops); tgt_cp_stats_register_big_data_rx_ops(rx_ops); } static void tgt_mc_cp_stats_extract_tx_power(struct wlan_objmgr_psoc *psoc, struct stats_event *ev, bool is_station_stats) { int32_t max_pwr = 0; uint8_t pdev_id; uint8_t mac_id = 0; QDF_STATUS status; struct wlan_objmgr_pdev *pdev; struct request_info last_req = {0}; struct wlan_objmgr_vdev *vdev = NULL; struct pdev_mc_cp_stats *pdev_mc_stats; struct pdev_cp_stats *pdev_cp_stats_priv; if (!ev->pdev_stats) return; if (is_station_stats) status = ucfg_mc_cp_stats_get_pending_req(psoc, TYPE_STATION_STATS, &last_req); else status = ucfg_mc_cp_stats_get_pending_req(psoc, TYPE_CONNECTION_TX_POWER, &last_req); if (QDF_IS_STATUS_ERROR(status)) { cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); goto end; } vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, last_req.vdev_id, WLAN_CP_STATS_ID); if (!vdev) { cp_stats_err("vdev is null"); goto end; } pdev = wlan_vdev_get_pdev(vdev); if (!pdev) { cp_stats_err("pdev is null"); goto end; } pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); if (pdev_id >= ev->num_pdev_stats) { cp_stats_err("pdev_id: %d invalid", pdev_id); goto end; } pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev); if (!pdev_cp_stats_priv) { cp_stats_err("pdev_cp_stats_priv is null"); goto end; } mac_id = policy_mgr_mode_get_macid_by_vdev_id(psoc, last_req.vdev_id); wlan_cp_stats_pdev_obj_lock(pdev_cp_stats_priv); pdev_mc_stats = pdev_cp_stats_priv->pdev_stats; if (!is_station_stats && pdev_mc_stats->max_pwr != ev->pdev_stats[pdev_id].max_pwr) wlan_son_deliver_tx_power(vdev, ev->pdev_stats[pdev_id].max_pwr); if (mac_id == ev->mac_seq_num) max_pwr = pdev_mc_stats->max_pwr = ev->pdev_stats[pdev_id].max_pwr; wlan_cp_stats_pdev_obj_unlock(pdev_cp_stats_priv); end: if (vdev) wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); } static void peer_rssi_iterator(struct wlan_objmgr_pdev *pdev, void *peer, void *arg) { struct stats_event *ev; struct peer_mc_cp_stats *peer_mc_stats; struct peer_cp_stats *peer_cp_stats_priv; struct peer_extd_stats *peer_extd_mc_stats; if (WLAN_PEER_SELF == wlan_peer_get_peer_type(peer)) { cp_stats_debug("ignore self peer: "QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(wlan_peer_get_macaddr(peer))); return; } peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer); if (!peer_cp_stats_priv) { cp_stats_err("peer cp stats object is null"); return; } wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv); peer_mc_stats = peer_cp_stats_priv->peer_stats; ev = arg; ev->peer_stats[ev->num_peer_stats] = *peer_mc_stats; ev->num_peer_stats++; peer_extd_mc_stats = peer_mc_stats->extd_stats; ev->peer_extended_stats[ev->num_peer_extd_stats] = *peer_extd_mc_stats; ev->num_peer_extd_stats++; wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv); } static void tgt_mc_cp_stats_prepare_raw_peer_rssi(struct wlan_objmgr_psoc *psoc, struct request_info *last_req) { uint8_t *mac_addr; uint16_t peer_count; struct stats_event ev = {0}; struct wlan_objmgr_pdev *pdev; struct wlan_objmgr_vdev *vdev; struct wlan_objmgr_peer *peer = NULL; struct peer_mc_cp_stats *peer_mc_stats; struct peer_extd_stats *peer_mc_extd_stats; struct peer_cp_stats *peer_cp_stats_priv; void (*get_peer_rssi_cb)(struct stats_event *ev, void *cookie); get_peer_rssi_cb = last_req->u.get_peer_rssi_cb; if (!get_peer_rssi_cb) { cp_stats_debug("get_peer_rssi_cb is null"); return; } vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, last_req->vdev_id, WLAN_CP_STATS_ID); if (!vdev) { cp_stats_err("vdev is null"); goto end; } mac_addr = last_req->peer_mac_addr; if (QDF_IS_ADDR_BROADCAST(mac_addr)) { pdev = wlan_vdev_get_pdev(vdev); peer_count = wlan_pdev_get_peer_count(pdev); ev.peer_stats = qdf_mem_malloc(sizeof(*ev.peer_stats) * peer_count); if (!ev.peer_stats) goto end; ev.peer_extended_stats = qdf_mem_malloc(sizeof(*ev.peer_extended_stats) * peer_count); if (!ev.peer_extended_stats) goto end; wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_PEER_OP, peer_rssi_iterator, &ev, true, WLAN_CP_STATS_ID); } else { peer = wlan_objmgr_get_peer(psoc, last_req->pdev_id, mac_addr, WLAN_CP_STATS_ID); if (!peer) { cp_stats_debug("peer[" QDF_MAC_ADDR_FMT "] is null", QDF_MAC_ADDR_REF(mac_addr)); goto end; } peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer); if (!peer_cp_stats_priv) { cp_stats_err("peer cp stats object is null"); goto end; } ev.peer_stats = qdf_mem_malloc(sizeof(*ev.peer_stats)); if (!ev.peer_stats) goto end; ev.num_peer_stats = 1; ev.peer_extended_stats = qdf_mem_malloc(sizeof(*ev.peer_extended_stats)); if (!ev.peer_extended_stats) goto end; ev.num_peer_extd_stats = 1; wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv); peer_mc_stats = peer_cp_stats_priv->peer_stats; *ev.peer_stats = *peer_mc_stats; peer_mc_extd_stats = peer_mc_stats->extd_stats; *ev.peer_extended_stats = *peer_mc_extd_stats; wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv); } end: get_peer_rssi_cb(&ev, last_req->cookie); ucfg_mc_cp_stats_free_stats_resources(&ev); if (vdev) wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); if (peer) wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); } 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_mc_cp_stats *peer_mc_stats; 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_debug("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_mc_stats = peer_cp_stats_priv->peer_stats; peer_adv_mc_stats = peer_mc_stats->adv_stats; qdf_mem_copy(peer_adv_mc_stats->peer_macaddr, peer_adv_stats->peer_macaddr, QDF_MAC_ADDR_SIZE); 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) { uint8_t *peer_mac_addr; struct wlan_objmgr_peer *peer; struct peer_mc_cp_stats *peer_mc_stats; QDF_STATUS status = QDF_STATUS_SUCCESS; struct peer_cp_stats *peer_cp_stats_priv; if (!peer_stats) return QDF_STATUS_E_INVAL; peer_mac_addr = peer_stats->peer_macaddr; peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac_addr, WLAN_CP_STATS_ID); if (!peer) { cp_stats_debug("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_mc_stats = peer_cp_stats_priv->peer_stats; qdf_mem_copy(peer_mc_stats->peer_macaddr, peer_stats->peer_macaddr, QDF_MAC_ADDR_SIZE); if (peer_stats->tx_rate) peer_mc_stats->tx_rate = peer_stats->tx_rate; if (peer_stats->rx_rate) peer_mc_stats->rx_rate = peer_stats->rx_rate; if (peer_stats->peer_rssi) peer_mc_stats->peer_rssi = peer_stats->peer_rssi; cp_stats_nofl_debug("PEER STATS: peer_mac="QDF_MAC_ADDR_FMT", tx_rate=%u, rx_rate=%u, peer_rssi=%d", QDF_MAC_ADDR_REF(peer_mc_stats->peer_macaddr), peer_mc_stats->tx_rate, peer_mc_stats->rx_rate, peer_mc_stats->peer_rssi); 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_extd_stats( struct wlan_objmgr_psoc *psoc, struct peer_extd_stats *peer_extended_stats) { uint8_t *peer_mac_addr; struct wlan_objmgr_peer *peer; struct peer_mc_cp_stats *peer_mc_stats; struct peer_extd_stats *peer_extd_mc_stats; QDF_STATUS status = QDF_STATUS_SUCCESS; struct peer_cp_stats *peer_cp_stats_priv; if (!peer_extended_stats) return QDF_STATUS_E_INVAL; peer_mac_addr = peer_extended_stats->peer_macaddr; peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac_addr, WLAN_CP_STATS_ID); if (!peer) { cp_stats_debug("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_mc_stats = peer_cp_stats_priv->peer_stats; peer_extd_mc_stats = peer_mc_stats->extd_stats; if (!peer_extd_mc_stats) { wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv); cp_stats_err("No peer_extd_mc_stats"); status = QDF_STATUS_E_INVAL; goto end; } qdf_mem_copy(peer_extd_mc_stats->peer_macaddr, peer_extended_stats->peer_macaddr, QDF_MAC_ADDR_SIZE); if (peer_extended_stats->rx_mc_bc_cnt) peer_extd_mc_stats->rx_mc_bc_cnt = peer_extended_stats->rx_mc_bc_cnt; wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv); cp_stats_debug("peer_mac="QDF_MAC_ADDR_FMT", rx_mc_bc_cnt=%u", QDF_MAC_ADDR_REF(peer_extended_stats->peer_macaddr), peer_extended_stats->rx_mc_bc_cnt); end: wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); return status; } static void tgt_mc_cp_stats_extract_peer_extd_stats( struct wlan_objmgr_psoc *psoc, struct stats_event *ev) { uint32_t i, selected; QDF_STATUS status; struct request_info last_req = {0}; status = ucfg_mc_cp_stats_get_pending_req(psoc, TYPE_PEER_STATS, &last_req); if (QDF_IS_STATUS_ERROR(status)) { cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); return; } selected = ev->num_peer_extd_stats; for (i = 0; i < ev->num_peer_extd_stats; i++) { status = tgt_mc_cp_stats_update_peer_extd_stats( psoc, &ev->peer_extended_stats[i]); if (!QDF_IS_ADDR_BROADCAST(last_req.peer_mac_addr) && !qdf_mem_cmp(ev->peer_extended_stats[i].peer_macaddr, last_req.peer_mac_addr, QDF_MAC_ADDR_SIZE)) { /* 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_extd_stats) { cp_stats_rl_err("peer not found stats"); return; } } static void tgt_mc_cp_stats_extract_peer_stats(struct wlan_objmgr_psoc *psoc, struct stats_event *ev, bool is_station_stats) { uint32_t i; QDF_STATUS status; struct request_info last_req = {0}; bool pending = false; uint32_t selected; if (is_station_stats) status = ucfg_mc_cp_stats_get_pending_req(psoc, TYPE_STATION_STATS, &last_req); else status = ucfg_mc_cp_stats_get_pending_req(psoc, TYPE_PEER_STATS, &last_req); if (QDF_IS_STATUS_ERROR(status)) { cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); return; } if (!ev->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, &ev->peer_stats[i]); if (!QDF_IS_ADDR_BROADCAST(last_req.peer_mac_addr) && !qdf_mem_cmp(ev->peer_stats[i].peer_macaddr, last_req.peer_mac_addr, QDF_MAC_ADDR_SIZE)) { /* 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_stats) cp_stats_debug("peer not found for stats"); extd2_stats: if (!ev->peer_adv_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, QDF_MAC_ADDR_SIZE)) { /* 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_debug("peer not found for extd stats"); complete: if (is_station_stats) return; tgt_mc_cp_stats_extract_peer_extd_stats(psoc, ev); if (tgt_mc_cp_stats_is_last_event(ev, TYPE_PEER_STATS)) { ucfg_mc_cp_stats_reset_pending_req(psoc, TYPE_PEER_STATS, &last_req, &pending); if (pending && last_req.u.get_peer_rssi_cb) tgt_mc_cp_stats_prepare_raw_peer_rssi(psoc, &last_req); } } #ifdef WLAN_FEATURE_MIB_STATS static void tgt_mc_cp_stats_extract_mib_stats(struct wlan_objmgr_psoc *psoc, struct stats_event *ev) { QDF_STATUS status; struct request_info last_req = {0}; bool pending = false; if (!ev->mib_stats) { cp_stats_debug("no mib stats"); return; } status = ucfg_mc_cp_stats_get_pending_req(psoc, TYPE_MIB_STATS, &last_req); if (QDF_IS_STATUS_ERROR(status)) { cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); return; } if (tgt_mc_cp_stats_is_last_event(ev, TYPE_MIB_STATS)) { ucfg_mc_cp_stats_reset_pending_req(psoc, TYPE_MIB_STATS, &last_req, &pending); if (last_req.u.get_mib_stats_cb && pending) last_req.u.get_mib_stats_cb(ev, last_req.cookie); } } #else static void tgt_mc_cp_stats_extract_mib_stats(struct wlan_objmgr_psoc *psoc, struct stats_event *ev) { } #endif static void tgt_mc_cp_stats_extract_peer_stats_info_ext(struct wlan_objmgr_psoc *psoc, struct stats_event *ev) { QDF_STATUS status; struct request_info last_req = {0}; bool pending = false; if (!ev->peer_stats_info_ext || ev->num_peer_stats_info_ext == 0) { cp_stats_debug("no peer_stats_info_ext"); return; } status = ucfg_mc_cp_stats_get_pending_req(psoc, TYPE_PEER_STATS_INFO_EXT, &last_req); if (QDF_IS_STATUS_ERROR(status)) { cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); return; } ucfg_mc_cp_stats_reset_pending_req(psoc, TYPE_PEER_STATS_INFO_EXT, &last_req, &pending); if (last_req.u.get_peer_stats_cb && pending) { last_req.u.get_peer_stats_cb(ev, last_req.cookie); last_req.u.get_peer_stats_cb = NULL; } } #ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS #ifdef WLAN_SUPPORT_TWT static void tgt_mc_infra_cp_stats_extract_twt_stats(struct wlan_objmgr_psoc *psoc, struct infra_cp_stats_event *ev) { QDF_STATUS status; get_infra_cp_stats_cb resp_cb = NULL; void *context = NULL; status = wlan_cp_stats_infra_cp_get_context(psoc, &resp_cb, &context); if (QDF_IS_STATUS_ERROR(status)) { cp_stats_err("ucfg_get_infra_cp_stats_context failed"); return; } cp_stats_debug("num_twt_infra_cp_stats = %d action %d", ev->num_twt_infra_cp_stats, ev->action); if (resp_cb) resp_cb(ev, context); } #else static void tgt_mc_infra_cp_stats_extract_twt_stats(struct wlan_objmgr_psoc *psoc, struct infra_cp_stats_event *ev) { } #endif #endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */ #ifdef WLAN_FEATURE_MEDIUM_ASSESS static void tgt_mc_cp_stats_extract_congestion_stats(struct wlan_objmgr_psoc *psoc, struct stats_event *ev) { QDF_STATUS status; uint8_t i, index; struct request_info last_req = {0}; struct medium_assess_data data[WLAN_UMAC_MAX_RP_PID] = { {0} }; bool is_last_event = tgt_mc_cp_stats_is_last_event(ev, TYPE_CONGESTION_STATS); if (!(ev->num_pdev_stats || ev->num_pdev_extd_stats)) { cp_stats_err("no congestion sta for pdev"); return; } status = ucfg_mc_cp_stats_get_pending_req(psoc, TYPE_CONGESTION_STATS, &last_req); if (QDF_IS_STATUS_ERROR(status)) { cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); return; } for (i = 0; (i < ev->num_pdev_stats) && (i < WLAN_UMAC_MAX_RP_PID); i++){ index = ev->pdev_stats[i].pdev_id; if (index >= WLAN_UMAC_MAX_RP_PID) { cp_stats_err("part1 pdev id error"); continue; } data[index].part1_valid = true; data[index].cycle_count = ev->pdev_stats[i].cycle_count; data[index].rx_clear_count = ev->pdev_stats[i].rx_clear_count; data[index].tx_frame_count = ev->pdev_stats[i].tx_frame_count; } for (i = 0; (i < ev->num_pdev_extd_stats) && (i < WLAN_UMAC_MAX_RP_PID); i++){ index = ev->pdev_extd_stats[i].pdev_id; if (index >= WLAN_UMAC_MAX_RP_PID) { cp_stats_err("part2 pdev id error"); continue; } data[index].part2_valid = true; data[index].my_rx_count = ev->pdev_extd_stats[i].my_rx_count; } if (last_req.u.congestion_notif_cb) last_req.u.congestion_notif_cb(last_req.vdev_id, data, is_last_event); } #else static void tgt_mc_cp_stats_extract_congestion_stats(struct wlan_objmgr_psoc *psoc, struct stats_event *ev) { } #endif #ifdef WLAN_FEATURE_11BE_MLO static void update_ml_vdev_id_from_stats_event(struct request_info *req, uint8_t *vdev_id) { if (!req->ml_vdev_info.ml_vdev_count) { *vdev_id = req->vdev_id; return; } if (*vdev_id == WLAN_UMAC_VDEV_ID_MAX || *vdev_id >= WLAN_MAX_VDEVS) { cp_stats_err("Invalid vdev[%u] sent by firmware", *vdev_id); *vdev_id = WLAN_UMAC_VDEV_ID_MAX; } } #else static inline void update_ml_vdev_id_from_stats_event(struct request_info *req, uint8_t *vdev_id) { *vdev_id = req->vdev_id; } #endif static void tgt_mc_cp_stats_extract_cca_stats(struct wlan_objmgr_psoc *psoc, struct stats_event *ev) { struct wlan_objmgr_vdev *vdev; struct vdev_mc_cp_stats *vdev_mc_stats; struct vdev_cp_stats *vdev_cp_stats_priv; if (!ev->cca_stats) return; vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, ev->cca_stats->vdev_id, WLAN_CP_STATS_ID); if (!vdev) { cp_stats_err("vdev is null"); return; } vdev_cp_stats_priv = wlan_cp_stats_get_vdev_stats_obj(vdev); if (!vdev_cp_stats_priv) { cp_stats_err("vdev cp stats object is null"); goto end; } wlan_cp_stats_vdev_obj_lock(vdev_cp_stats_priv); vdev_mc_stats = vdev_cp_stats_priv->vdev_stats; vdev_mc_stats->cca.congestion = ev->cca_stats->congestion; wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv); end: wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); } static void tgt_mc_cp_stats_extract_pmf_bcn_stats(struct wlan_objmgr_psoc *psoc, struct stats_event *ev) { QDF_STATUS status; struct request_info last_req = {0}; struct wlan_objmgr_vdev *vdev; struct vdev_mc_cp_stats *vdev_mc_stats; struct vdev_cp_stats *vdev_cp_stats_priv; status = ucfg_mc_cp_stats_get_pending_req(psoc, TYPE_STATION_STATS, &last_req); if (QDF_IS_STATUS_ERROR(status)) { cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); return; } vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, last_req.vdev_id, WLAN_CP_STATS_ID); if (!vdev) { cp_stats_err("vdev is null"); return; } vdev_cp_stats_priv = wlan_cp_stats_get_vdev_stats_obj(vdev); if (!vdev_cp_stats_priv) { cp_stats_err("vdev cp stats object is null"); wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); return; } wlan_cp_stats_vdev_obj_lock(vdev_cp_stats_priv); vdev_mc_stats = vdev_cp_stats_priv->vdev_stats; if (ev->bcn_protect_stats.pmf_bcn_stats_valid) vdev_mc_stats->pmf_bcn_stats = ev->bcn_protect_stats; wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv); wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); } static void tgt_mc_cp_stats_extract_vdev_summary_stats( struct wlan_objmgr_psoc *psoc, struct stats_event *ev) { uint8_t i, vdev_id = WLAN_INVALID_VDEV_ID; QDF_STATUS status; struct wlan_objmgr_peer *peer = NULL; struct request_info last_req = {0}; struct wlan_objmgr_vdev *vdev; struct peer_mc_cp_stats *peer_mc_stats; struct vdev_mc_cp_stats *vdev_mc_stats; struct peer_cp_stats *peer_cp_stats_priv; struct vdev_cp_stats *vdev_cp_stats_priv; if (!ev->vdev_summary_stats) return; status = ucfg_mc_cp_stats_get_pending_req(psoc, TYPE_STATION_STATS, &last_req); if (QDF_IS_STATUS_ERROR(status)) { cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); return; } for (i = 0; i < ev->num_summary_stats; i++) { vdev_id = ev->vdev_summary_stats[i].vdev_id; update_ml_vdev_id_from_stats_event(&last_req, &vdev_id); if (ev->vdev_summary_stats[i].vdev_id == vdev_id) break; } if (i == ev->num_summary_stats) { cp_stats_debug("vdev_id %d not found", vdev_id); return; } if (vdev_id == WLAN_INVALID_VDEV_ID) return; vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_CP_STATS_ID); if (!vdev) { cp_stats_err("vdev is null"); return; } vdev_cp_stats_priv = wlan_cp_stats_get_vdev_stats_obj(vdev); if (!vdev_cp_stats_priv) { cp_stats_err("vdev cp stats object is null"); goto end; } wlan_cp_stats_vdev_obj_lock(vdev_cp_stats_priv); vdev_mc_stats = vdev_cp_stats_priv->vdev_stats; qdf_mem_copy(&vdev_mc_stats->vdev_summary_stats, &ev->vdev_summary_stats[i].stats, sizeof(vdev_mc_stats->vdev_summary_stats)); wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv); peer = wlan_objmgr_get_peer(psoc, last_req.pdev_id, last_req.peer_mac_addr, WLAN_CP_STATS_ID); if (!peer) { cp_stats_debug("peer is null "QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(last_req.peer_mac_addr)); goto end; } peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer); if (!peer_cp_stats_priv) { cp_stats_err("peer cp stats object is null"); goto end; } wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv); peer_mc_stats = peer_cp_stats_priv->peer_stats; peer_mc_stats->peer_rssi = ev->vdev_summary_stats[i].stats.rssi; wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv); end: if (peer) wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); } static void tgt_mc_cp_stats_extract_vdev_chain_rssi_stats( struct wlan_objmgr_psoc *psoc, struct stats_event *ev) { uint8_t i, j, vdev_id; QDF_STATUS status; struct request_info last_req = {0}; struct wlan_objmgr_vdev *vdev; struct vdev_mc_cp_stats *vdev_mc_stats; struct vdev_cp_stats *vdev_cp_stats_priv; if (!ev->vdev_chain_rssi) return; status = ucfg_mc_cp_stats_get_pending_req(psoc, TYPE_STATION_STATS, &last_req); if (QDF_IS_STATUS_ERROR(status)) { cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); return; } for (i = 0; i < ev->num_chain_rssi_stats; i++) { vdev_id = ev->vdev_chain_rssi[i].vdev_id; update_ml_vdev_id_from_stats_event(&last_req, &vdev_id); if (ev->vdev_chain_rssi[i].vdev_id != vdev_id) continue; vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_CP_STATS_ID); if (!vdev) { cp_stats_err("vdev is null"); return; } vdev_cp_stats_priv = wlan_cp_stats_get_vdev_stats_obj(vdev); if (!vdev_cp_stats_priv) { cp_stats_err("vdev cp stats object is null"); wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); return; } wlan_cp_stats_vdev_obj_lock(vdev_cp_stats_priv); vdev_mc_stats = vdev_cp_stats_priv->vdev_stats; for (j = 0; j < MAX_NUM_CHAINS; j++) { vdev_mc_stats->chain_rssi[j] = ev->vdev_chain_rssi[i].chain_rssi[j]; } wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv); wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); } } static void tgt_mc_cp_stats_extract_vdev_extd_stats(struct wlan_objmgr_psoc *psoc, struct stats_event *ev) { uint8_t i, vdev_id; QDF_STATUS status; struct request_info last_req = {0}; struct wlan_objmgr_vdev *vdev; struct vdev_mc_cp_stats *vdev_mc_stats; struct vdev_cp_stats *vdev_cp_stats_priv; if (!ev->vdev_extd_stats) return; status = ucfg_mc_cp_stats_get_pending_req(psoc, TYPE_STATION_STATS, &last_req); if (QDF_IS_STATUS_ERROR(status)) { cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); return; } for (i = 0; i < ev->num_vdev_extd_stats; i++) { vdev_id = ev->vdev_extd_stats[i].vdev_id; vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_CP_STATS_ID); if (!vdev) { cp_stats_err("vdev is null"); return; } vdev_cp_stats_priv = wlan_cp_stats_get_vdev_stats_obj(vdev); if (!vdev_cp_stats_priv) { cp_stats_err("vdev cp stats object is null"); wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); return; } wlan_cp_stats_vdev_obj_lock(vdev_cp_stats_priv); vdev_mc_stats = vdev_cp_stats_priv->vdev_stats; qdf_mem_copy(&vdev_mc_stats->vdev_extd_stats, &ev->vdev_extd_stats[i], sizeof(vdev_mc_stats->vdev_extd_stats)); wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv); wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); } } static QDF_STATUS tgt_send_vdev_mc_cp_stats(struct wlan_objmgr_psoc *psoc, struct stats_event *ev, struct request_info *last_req) { struct wlan_objmgr_vdev *vdev; struct vdev_mc_cp_stats *vdev_mc_stats; struct vdev_cp_stats *vdev_cp_stats_priv; if (!ev || !last_req) return QDF_STATUS_E_NULL_VALUE; vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, last_req->vdev_id, WLAN_CP_STATS_ID); if (!vdev) { cp_stats_err("vdev object is null"); return QDF_STATUS_E_NULL_VALUE; } vdev_cp_stats_priv = wlan_cp_stats_get_vdev_stats_obj(vdev); if (!vdev_cp_stats_priv) { cp_stats_err("vdev cp stats object is null"); wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); return QDF_STATUS_E_NULL_VALUE; } wlan_cp_stats_vdev_obj_lock(vdev_cp_stats_priv); vdev_mc_stats = vdev_cp_stats_priv->vdev_stats; ev->vdev_summary_stats[0].vdev_id = last_req->vdev_id; ev->vdev_summary_stats[0].stats = vdev_mc_stats->vdev_summary_stats; ev->vdev_chain_rssi[0].vdev_id = last_req->vdev_id; qdf_mem_copy(ev->vdev_chain_rssi[0].chain_rssi, vdev_mc_stats->chain_rssi, sizeof(vdev_mc_stats->chain_rssi)); ev->tx_rate_flags = vdev_mc_stats->tx_rate_flags; ev->bcn_protect_stats = vdev_mc_stats->pmf_bcn_stats; qdf_mem_copy(&ev->vdev_extd_stats[0], &vdev_mc_stats->vdev_extd_stats, sizeof(vdev_mc_stats->vdev_extd_stats)); wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv); wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); return QDF_STATUS_SUCCESS; } static QDF_STATUS tgt_send_peer_mc_cp_stats(struct wlan_objmgr_psoc *psoc, struct stats_event *ev, struct request_info *last_req) { struct wlan_objmgr_peer *peer; struct peer_mc_cp_stats *peer_mc_stats; struct peer_cp_stats *peer_cp_stats_priv; if (!ev || !last_req) return QDF_STATUS_E_NULL_VALUE; peer = wlan_objmgr_get_peer(psoc, last_req->pdev_id, last_req->peer_mac_addr, WLAN_CP_STATS_ID); if (!peer) { cp_stats_debug("peer object is null"); return QDF_STATUS_E_NULL_VALUE; } peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer); if (!peer_cp_stats_priv) { cp_stats_err("peer cp stats object is null"); wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); return QDF_STATUS_E_NULL_VALUE; } wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv); peer_mc_stats = peer_cp_stats_priv->peer_stats; /* * The linkspeed returned by fw is in kbps so convert * it in units of 100kbps which is expected by UMAC */ ev->tx_rate = peer_mc_stats->tx_rate / 100; ev->rx_rate = peer_mc_stats->rx_rate / 100; if (peer_mc_stats->adv_stats) { ev->num_peer_adv_stats = 1; qdf_mem_copy(ev->peer_adv_stats, peer_mc_stats->adv_stats, sizeof(*peer_mc_stats->adv_stats)); } wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv); wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); return QDF_STATUS_SUCCESS; } static QDF_STATUS tgt_send_pdev_mc_cp_stats(struct wlan_objmgr_psoc *psoc, struct stats_event *ev, struct request_info *last_req) { struct wlan_objmgr_pdev *pdev; struct wlan_objmgr_vdev *vdev = NULL; struct pdev_mc_cp_stats *pdev_mc_stats; struct pdev_cp_stats *pdev_cp_stats_priv; int pdev_id; if (!ev || !last_req) return QDF_STATUS_E_NULL_VALUE; vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, last_req->vdev_id, WLAN_CP_STATS_ID); if (!vdev) { cp_stats_err("vdev is null"); return QDF_STATUS_E_NULL_VALUE; } pdev = wlan_vdev_get_pdev(vdev); if (!pdev) { cp_stats_err("pdev is null"); goto end; } pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); if (pdev_id != last_req->pdev_id) { cp_stats_err("pdev_id: %d invalid", pdev_id); goto end; } pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev); if (!pdev_cp_stats_priv) { cp_stats_err("pdev_cp_stats_priv is null"); goto end; } wlan_cp_stats_pdev_obj_lock(pdev_cp_stats_priv); pdev_mc_stats = pdev_cp_stats_priv->pdev_stats; qdf_mem_copy(ev->pdev_stats, pdev_mc_stats, sizeof(*pdev_mc_stats)); wlan_cp_stats_pdev_obj_unlock(pdev_cp_stats_priv); wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); return QDF_STATUS_SUCCESS; end: wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); return QDF_STATUS_E_NULL_VALUE; } static QDF_STATUS tgt_mc_cp_stats_get_tx_power(struct wlan_objmgr_vdev *vdev, int *dbm) { struct wlan_objmgr_pdev *pdev; struct pdev_mc_cp_stats *pdev_mc_stats; struct pdev_cp_stats *pdev_cp_stats_priv; struct vdev_mc_cp_stats *vdev_mc_stats; struct vdev_cp_stats *vdev_cp_stat; uint32_t vdev_power = 0; vdev_cp_stat = wlan_cp_stats_get_vdev_stats_obj(vdev); if (vdev_cp_stat) { wlan_cp_stats_vdev_obj_lock(vdev_cp_stat); vdev_mc_stats = vdev_cp_stat->vdev_stats; vdev_power = vdev_mc_stats->vdev_extd_stats.vdev_tx_power; wlan_cp_stats_vdev_obj_unlock(vdev_cp_stat); if (vdev_power) { *dbm = vdev_power; return QDF_STATUS_SUCCESS; } } pdev = wlan_vdev_get_pdev(vdev); pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev); if (!pdev_cp_stats_priv) { cp_stats_err("pdev cp stats object is null"); return QDF_STATUS_E_NULL_VALUE; } wlan_cp_stats_pdev_obj_lock(pdev_cp_stats_priv); pdev_mc_stats = pdev_cp_stats_priv->pdev_stats; *dbm = pdev_mc_stats->max_pwr; wlan_cp_stats_pdev_obj_unlock(pdev_cp_stats_priv); return QDF_STATUS_SUCCESS; } static void tgt_mc_cp_stats_extract_vdev_and_extd_stats(struct wlan_objmgr_psoc *psoc, struct stats_event *ev) { QDF_STATUS status; struct request_info last_req = {0}; bool pending = false; int32_t max_pwr = 0; struct wlan_objmgr_vdev *vdev = NULL; status = ucfg_mc_cp_stats_get_pending_req(psoc, TYPE_CONNECTION_TX_POWER, &last_req); if (QDF_IS_STATUS_ERROR(status)) { cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); return; } if (ev->pdev_stats) tgt_mc_cp_stats_extract_tx_power(psoc, ev, false); else if (ev->vdev_extd_stats) tgt_mc_cp_stats_extract_vdev_extd_stats(psoc, ev); vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, last_req.vdev_id, WLAN_CP_STATS_ID); if (!vdev) { cp_stats_err("vdev is null"); return; } tgt_mc_cp_stats_get_tx_power(vdev, &max_pwr); wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); if (tgt_mc_cp_stats_is_last_event(ev, TYPE_CONNECTION_TX_POWER)) { ucfg_mc_cp_stats_reset_pending_req(psoc, TYPE_CONNECTION_TX_POWER, &last_req, &pending); if (last_req.u.get_tx_power_cb && pending) last_req.u.get_tx_power_cb(max_pwr, last_req.cookie); } } static void tgt_mc_cp_stats_send_raw_station_stats(struct wlan_objmgr_psoc *psoc, struct request_info *last_req) { /* station_stats to be given to userspace thread */ struct stats_event info = {0}; void (*get_station_stats_cb)(struct stats_event *info, void *cookie); QDF_STATUS status; get_station_stats_cb = last_req->u.get_station_stats_cb; if (!get_station_stats_cb) { cp_stats_err("callback is null"); return; } info.num_summary_stats = 1; info.num_chain_rssi_stats = 1; info.num_vdev_extd_stats = 1; info.vdev_summary_stats = qdf_mem_malloc( sizeof(*info.vdev_summary_stats)); info.vdev_chain_rssi = qdf_mem_malloc(sizeof(*info.vdev_chain_rssi)); info.vdev_extd_stats = qdf_mem_malloc(sizeof(*info.vdev_extd_stats)); if (!info.vdev_summary_stats || !info.vdev_chain_rssi || !info.vdev_extd_stats) goto end; status = tgt_send_vdev_mc_cp_stats(psoc, &info, last_req); if (QDF_IS_STATUS_ERROR(status)) { cp_stats_err("tgt_send_vdev_mc_cp_stats failed"); goto end; } info.peer_adv_stats = qdf_mem_malloc(sizeof(*info.peer_adv_stats)); if (!info.peer_adv_stats) goto end; status = tgt_send_peer_mc_cp_stats(psoc, &info, last_req); if (QDF_IS_STATUS_ERROR(status)) { cp_stats_err("tgt_send_peer_mc_cp_stats failed"); goto end; } info.num_pdev_stats = 1; info.pdev_stats = qdf_mem_malloc(sizeof(*info.pdev_stats)); if (!info.pdev_stats) goto end; status = tgt_send_pdev_mc_cp_stats(psoc, &info, last_req); if (QDF_IS_STATUS_ERROR(status)) { cp_stats_err("tgt_send_pdev_mc_cp_stats failed"); goto end; } end: get_station_stats_cb(&info, last_req->cookie); ucfg_mc_cp_stats_free_stats_resources(&info); } #ifdef WLAN_FEATURE_11BE_MLO static void tgt_mc_cp_stats_prepare_n_send_raw_station_stats(struct wlan_objmgr_psoc *psoc, struct request_info *last_req) { uint8_t i; if (!last_req->ml_vdev_info.ml_vdev_count) { cp_stats_nofl_debug("Invoking get_station_cb for vdev_id[%d]", last_req->vdev_id); tgt_mc_cp_stats_send_raw_station_stats(psoc, last_req); return; } for (i = 0; i < last_req->ml_vdev_info.ml_vdev_count; i++) { last_req->vdev_id = last_req->ml_vdev_info.ml_vdev_id[i]; qdf_mem_copy(last_req->peer_mac_addr, &(last_req->ml_peer_mac_addr[i][0]), QDF_MAC_ADDR_SIZE); cp_stats_nofl_debug("Invoking get_station_cb for ml vdev_id[%d]", last_req->vdev_id); tgt_mc_cp_stats_send_raw_station_stats(psoc, last_req); } } #else static void tgt_mc_cp_stats_prepare_n_send_raw_station_stats(struct wlan_objmgr_psoc *psoc, struct request_info *last_req) { tgt_mc_cp_stats_send_raw_station_stats(psoc, last_req); } #endif static void tgt_mc_cp_stats_extract_station_stats( struct wlan_objmgr_psoc *psoc, struct stats_event *ev) { QDF_STATUS status; struct request_info last_req = {0}; bool pending = false; status = ucfg_mc_cp_stats_get_pending_req(psoc, TYPE_STATION_STATS, &last_req); if (QDF_IS_STATUS_ERROR(status)) { cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); return; } tgt_mc_cp_stats_extract_tx_power(psoc, ev, true); tgt_mc_cp_stats_extract_peer_stats(psoc, ev, true); tgt_mc_cp_stats_extract_vdev_summary_stats(psoc, ev); tgt_mc_cp_stats_extract_vdev_chain_rssi_stats(psoc, ev); tgt_mc_cp_stats_extract_pmf_bcn_stats(psoc, ev); tgt_mc_cp_stats_extract_vdev_extd_stats(psoc, ev); /* * PEER stats are the last stats sent for get_station statistics. * reset type_map bit for station stats . */ if (tgt_mc_cp_stats_is_last_event(ev, TYPE_STATION_STATS)) { ucfg_mc_cp_stats_reset_pending_req(psoc, TYPE_STATION_STATS, &last_req, &pending); if (pending && last_req.u.get_station_stats_cb) tgt_mc_cp_stats_prepare_n_send_raw_station_stats( psoc, &last_req); } } static void tgt_mc_cp_send_lost_link_stats(struct wlan_objmgr_psoc *psoc, struct stats_event *ev) { struct psoc_cp_stats *psoc_cp_stats_priv; psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); if (psoc_cp_stats_priv && psoc_cp_stats_priv->legacy_stats_cb) psoc_cp_stats_priv->legacy_stats_cb(ev); } #ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS QDF_STATUS tgt_mc_cp_stats_process_infra_stats_event( struct wlan_objmgr_psoc *psoc, struct infra_cp_stats_event *infra_event) { if (!infra_event) return QDF_STATUS_E_NULL_VALUE; tgt_mc_infra_cp_stats_extract_twt_stats(psoc, infra_event); return QDF_STATUS_SUCCESS; } #endif QDF_STATUS tgt_mc_cp_stats_process_stats_event(struct wlan_objmgr_psoc *psoc, struct stats_event *ev) { if (ucfg_mc_cp_stats_is_req_pending(psoc, TYPE_CONNECTION_TX_POWER)) tgt_mc_cp_stats_extract_vdev_and_extd_stats(psoc, ev); if (ucfg_mc_cp_stats_is_req_pending(psoc, TYPE_PEER_STATS)) tgt_mc_cp_stats_extract_peer_stats(psoc, ev, false); if (ucfg_mc_cp_stats_is_req_pending(psoc, TYPE_STATION_STATS)) tgt_mc_cp_stats_extract_station_stats(psoc, ev); if (ucfg_mc_cp_stats_is_req_pending(psoc, TYPE_MIB_STATS)) tgt_mc_cp_stats_extract_mib_stats(psoc, ev); if (ucfg_mc_cp_stats_is_req_pending(psoc, TYPE_PEER_STATS_INFO_EXT)) tgt_mc_cp_stats_extract_peer_stats_info_ext(psoc, ev); if (ucfg_mc_cp_stats_is_req_pending(psoc, TYPE_CONGESTION_STATS)) tgt_mc_cp_stats_extract_congestion_stats(psoc, ev); tgt_mc_cp_stats_extract_cca_stats(psoc, ev); tgt_mc_cp_send_lost_link_stats(psoc, ev); return QDF_STATUS_SUCCESS; } #ifdef WLAN_FEATURE_BIG_DATA_STATS QDF_STATUS tgt_mc_cp_stats_process_big_data_stats_event(struct wlan_objmgr_psoc *psoc, struct big_data_stats_event *ev) { QDF_STATUS status; struct request_info last_req = {0}; bool pending = false; if (!ev) { cp_stats_err("invalid data"); return QDF_STATUS_E_INVAL; } status = ucfg_mc_cp_stats_get_pending_req(psoc, TYPE_BIG_DATA_STATS, &last_req); if (QDF_IS_STATUS_ERROR(status)) { cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); return QDF_STATUS_E_FAILURE; } ucfg_mc_cp_stats_reset_pending_req(psoc, TYPE_BIG_DATA_STATS, &last_req, &pending); if (last_req.u.get_big_data_stats_cb && pending) { last_req.u.get_big_data_stats_cb(ev, last_req.cookie); last_req.u.get_big_data_stats_cb = NULL; } else { cp_stats_err("callback to send big data stats not found"); return QDF_STATUS_E_FAILURE; } return QDF_STATUS_SUCCESS; } #endif QDF_STATUS tgt_mc_cp_stats_inc_wake_lock_stats(struct wlan_objmgr_psoc *psoc, uint32_t reason, struct wake_lock_stats *stats, uint32_t *unspecified_wake_count) { struct wlan_lmac_if_cp_stats_tx_ops *tx_ops; tx_ops = target_if_cp_stats_get_tx_ops(psoc); if (!tx_ops || !tx_ops->inc_wake_lock_stats) return QDF_STATUS_E_NULL_VALUE; tx_ops->inc_wake_lock_stats(reason, stats, unspecified_wake_count); return QDF_STATUS_SUCCESS; } QDF_STATUS tgt_send_mc_cp_stats_req(struct wlan_objmgr_psoc *psoc, enum stats_req_type type, struct request_info *req) { struct wlan_lmac_if_cp_stats_tx_ops *tx_ops; QDF_STATUS status; tx_ops = target_if_cp_stats_get_tx_ops(psoc); if (!tx_ops) { cp_stats_err("could not get tx_ops"); return QDF_STATUS_E_NULL_VALUE; } switch (type) { case TYPE_PEER_STATS_INFO_EXT: if (!tx_ops->send_req_peer_stats) { cp_stats_err("could not get send_req_peer_stats"); return QDF_STATUS_E_NULL_VALUE; } status = tx_ops->send_req_peer_stats(psoc, req); break; case TYPE_BIG_DATA_STATS: status = send_big_data_stats_req(tx_ops, psoc, req); break; default: if (!tx_ops->send_req_stats) { cp_stats_err("could not get send_req_stats"); return QDF_STATUS_E_NULL_VALUE; } status = tx_ops->send_req_stats(psoc, type, req); } return status; } QDF_STATUS tgt_set_pdev_stats_update_period(struct wlan_objmgr_psoc *psoc, uint8_t pdev_id, uint32_t val) { struct wlan_lmac_if_cp_stats_tx_ops *tx_ops; QDF_STATUS status; tx_ops = target_if_cp_stats_get_tx_ops(psoc); if (!tx_ops || !tx_ops->set_pdev_stats_update_period) { cp_stats_err("could not get tx_ops"); return QDF_STATUS_E_NULL_VALUE; } status = tx_ops->set_pdev_stats_update_period(psoc, pdev_id, val); return status; }