From ebcefb30448f9ff841c7806e4df2c1ecb3505f27 Mon Sep 17 00:00:00 2001 From: Rajasekaran Kalidoss Date: Thu, 26 Nov 2020 21:20:26 +0530 Subject: [PATCH] qcacld-3.0: Add support for ctrl path stats infrastructure Implement support for sending new control path stats infrastructure via WMI_REQUEST_CTRL_PATH_STATS_CMDID and WMI_CTRL_PATH_STATS_EVENTID in cp stats component. Also add support for TWT Get statistics through this new method. Change-Id: I62b3a525cde797cd5b809ca9e8e6c91d5651c6b4 CRs-Fixed: 2851016 --- Kbuild | 5 +- .../dispatcher/inc/wlan_cp_stats_mc_defs.h | 6 +- .../dispatcher/inc/wlan_cp_stats_mc_tgt_api.h | 23 +- .../inc/wlan_cp_stats_mc_ucfg_api.h | 29 +- .../dispatcher/src/wlan_cp_stats_mc_tgt_api.c | 62 +++++ core/hdd/src/wlan_hdd_twt.c | 244 ++++++++++++++++- .../cp_stats/src/wlan_cfg80211_mc_cp_stats.c | 250 ++++++++++++++++++ 7 files changed, 610 insertions(+), 9 deletions(-) diff --git a/Kbuild b/Kbuild index 22c95cc8ef84..f442a6922fcd 100644 --- a/Kbuild +++ b/Kbuild @@ -2036,7 +2036,9 @@ CP_STATS_OBJS := $(CP_MC_STATS_COMPONENT_SRC)/wlan_cp_stats_mc_tgt_api.o \ $(CP_STATS_CORE_SRC)/wlan_cp_stats_obj_mgr_handler.o \ $(CP_STATS_CORE_SRC)/wlan_cp_stats_ol_api.o \ $(CP_MC_STATS_OS_IF_SRC)/wlan_cfg80211_mc_cp_stats.o \ - $(CP_STATS_DISPATCHER_SRC)/wlan_cp_stats_utils_api.o + $(CP_STATS_DISPATCHER_SRC)/wlan_cp_stats_utils_api.o \ + $(WLAN_COMMON_ROOT)/target_if/cp_stats/src/target_if_cp_stats.o \ + $(CP_STATS_DISPATCHER_SRC)/wlan_cp_stats_ucfg_api.o endif $(call add-wlan-objs,cp_stats,$(CP_STATS_OBJS)) @@ -2652,6 +2654,7 @@ cppflags-$(CONFIG_WLAN_WEXT_SUPPORT_ENABLE) += -DWLAN_WEXT_SUPPORT_ENABLE cppflags-$(CONFIG_WLAN_LOGGING_SOCK_SVC) += -DWLAN_LOGGING_SOCK_SVC_ENABLE cppflags-$(CONFIG_WLAN_LOGGING_BUFFERS_DYNAMICALLY) += -DWLAN_LOGGING_BUFFERS_DYNAMICALLY cppflags-$(CONFIG_WLAN_FEATURE_FILS) += -DWLAN_FEATURE_FILS_SK +cppflags-$(CONFIG_CP_STATS) += -DWLAN_SUPPORT_INFRA_CTRL_PATH_STATS cppflags-$(CONFIG_CP_STATS) += -DQCA_SUPPORT_CP_STATS cppflags-$(CONFIG_CP_STATS) += -DQCA_SUPPORT_MC_CP_STATS cppflags-$(CONFIG_DCS) += -DDCS_INTERFERENCE_DETECTION diff --git a/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_defs.h b/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_defs.h index ad126a99fa75..622026352f51 100644 --- a/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_defs.h +++ b/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_defs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2021 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 @@ -31,6 +31,10 @@ /* For WMI_MAX_CHAINS */ #include "wmi_unified.h" +#ifdef QCA_SUPPORT_MC_CP_STATS +#include "wlan_cp_stats_public_structs.h" +#endif + #ifdef WLAN_SUPPORT_TWT #include diff --git a/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_tgt_api.h b/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_tgt_api.h index 1244dfece80a..f822c39094ae 100644 --- a/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_tgt_api.h +++ b/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_tgt_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2018, 2021 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 @@ -48,14 +48,31 @@ uint8_t target_if_mc_cp_get_mac_id(struct vdev_mlme_obj *vdev_mlme); * @psoc: pointer to psoc object * @event: event parameters * + * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes on + * failure + */ +QDF_STATUS +tgt_mc_cp_stats_process_stats_event(struct wlan_objmgr_psoc *psoc, + struct stats_event *ev); + +#ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS +/** + * tgt_mc_cp_stats_process_infra_stats_event(): API to process event from + * cp stats infrastrucure + * @psoc: pointer to psoc object + * @infra_event: infra cp stats event parameters + * * Return: status of operation */ -QDF_STATUS tgt_mc_cp_stats_process_stats_event(struct wlan_objmgr_psoc *psoc, - struct stats_event *event); +QDF_STATUS tgt_mc_cp_stats_process_infra_stats_event( + struct wlan_objmgr_psoc *psoc, + struct infra_cp_stats_event *infra_event); +#endif /** * tgt_send_mc_cp_stats_req(): API to send stats request to lmac * @psoc: pointer to psoc object + * @req: pointer to stats request * * Return: status of operation */ diff --git a/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h b/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h index 177a1a820011..8f51c3c557aa 100644 --- a/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h +++ b/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2021 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 @@ -153,6 +153,20 @@ QDF_STATUS ucfg_mc_cp_stats_send_stats_request(struct wlan_objmgr_vdev *vdev, enum stats_req_type type, struct request_info *info); +/** + * wlan_cfg80211_mc_twt_get_infra_cp_stats() - send twt get statistic request + * @vdev: pointer to vdev object + * @dialog_id: TWT session dialog id + * @twt_peer_mac: mac address of the peer + * @errno: error code + * + * Return: pointer to infra cp stats event for success or NULL for failure + */ +struct infra_cp_stats_event * +wlan_cfg80211_mc_twt_get_infra_cp_stats(struct wlan_objmgr_vdev *vdev, + uint32_t dialog_id, + uint8_t twt_peer_mac[QDF_MAC_ADDR_SIZE], + int *errno); /** * ucfg_mc_cp_stats_get_tx_power() - API to fetch tx_power * @vdev: pointer to vdev object @@ -184,7 +198,6 @@ bool ucfg_mc_cp_stats_is_req_pending(struct wlan_objmgr_psoc *psoc, QDF_STATUS ucfg_mc_cp_stats_set_pending_req(struct wlan_objmgr_psoc *psoc, enum stats_req_type type, struct request_info *req); - /** * ucfg_mc_cp_stats_reset_pending_req() - API to reset pending request * @psoc: pointer to psoc object @@ -213,10 +226,20 @@ QDF_STATUS ucfg_mc_cp_stats_get_pending_req(struct wlan_objmgr_psoc *psoc, enum stats_req_type type, struct request_info *info); +/** + * ucfg_mc_infra_cp_stats_free_stats_resources() - API to free buffers within + * infra cp stats_event structure + * @ev: structure whose buffer are to freed + * + * Return: none + */ +void +ucfg_mc_infra_cp_stats_free_stats_resources(struct infra_cp_stats_event *ev); + /** * ucfg_mc_cp_stats_free_stats_resources() - API to free buffers within stats_event * structure - * @ev: strcture whose buffer are to freed + * @ev: structure whose buffer are to freed * * Return: none */ diff --git a/components/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c b/components/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c index c46ff2b3f55d..77daf6c0bd76 100644 --- a/components/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c +++ b/components/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c @@ -26,10 +26,12 @@ #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" static bool tgt_mc_cp_stats_is_last_event(struct stats_event *ev, enum stats_req_type stats_type) @@ -51,10 +53,25 @@ static bool tgt_mc_cp_stats_is_last_event(struct stats_event *ev, 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 + 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); } static void tgt_mc_cp_stats_extract_tx_power(struct wlan_objmgr_psoc *psoc, @@ -614,6 +631,37 @@ tgt_mc_cp_stats_extract_peer_stats_info_ext(struct wlan_objmgr_psoc *psoc, } } +#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; + void *context; + + 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 */ + static void tgt_mc_cp_stats_extract_cca_stats(struct wlan_objmgr_psoc *psoc, struct stats_event *ev) { @@ -977,6 +1025,20 @@ static void tgt_mc_cp_send_lost_link_stats(struct wlan_objmgr_psoc *psoc, 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) { diff --git a/core/hdd/src/wlan_hdd_twt.c b/core/hdd/src/wlan_hdd_twt.c index 650a19148d55..557bff3acd09 100644 --- a/core/hdd/src/wlan_hdd_twt.c +++ b/core/hdd/src/wlan_hdd_twt.c @@ -87,6 +87,11 @@ qca_wlan_vendor_twt_resume_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAX + 1 [QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT2_TWT] = {.type = NLA_U32 }, }; +static const struct nla_policy +qca_wlan_vendor_twt_stats_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID] = {.type = NLA_U8 }, +}; + const struct nla_policy wlan_hdd_wifi_twt_config_policy[ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX + 1] = { @@ -1289,6 +1294,25 @@ static int hdd_twt_setup_session(struct hdd_adapter *adapter, return ret; } +/** + * hdd_get_twt_get_stats_event_len() - calculate length of skb + * required for sending twt get statistics command responses. + * + * Return: length of skb + */ +static uint32_t hdd_get_twt_get_stats_event_len(void) +{ + uint32_t len = 0; + + len += NLMSG_HDRLEN; + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */ + len += nla_total_size(sizeof(u8)); + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS */ + len += nla_total_size(sizeof(u8)); + + return len; +} + /** * hdd_get_twt_event_len() - calculate length of skb * required for sending twt terminate, pause and resume @@ -2257,7 +2281,6 @@ static int hdd_twt_resume_session(struct hdd_adapter *adapter, hdd_sta_ctx->conn_info.conn_state); return -EINVAL; } - qdf_mem_copy(params.peer_macaddr, hdd_sta_ctx->conn_info.bssid.bytes, QDF_MAC_ADDR_SIZE); params.vdev_id = adapter->vdev_id; @@ -2313,6 +2336,221 @@ static int hdd_twt_resume_session(struct hdd_adapter *adapter, return ret; } +static uint32_t get_session_wake_duration(uint32_t dialog_id) +{ + return 0; +} + +/** + * hdd_twt_pack_get_stats_resp_nlmsg()- Packs and sends twt get stats response + * @reply_skb: pointer to response skb buffer + * @params: Ponter to twt session parameter buffer + * @num_session_stats: number of twt statistics + * + * Return: QDF_STATUS_SUCCESS on success, else other qdf error values + */ +static QDF_STATUS +hdd_twt_pack_get_stats_resp_nlmsg(struct sk_buff *reply_skb, + struct twt_infra_cp_stats_event *params, + uint32_t num_session_stats) +{ + struct nlattr *config_attr, *nla_params; + int i, attr; + uint32_t wake_duration; + + config_attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS); + if (!config_attr) { + hdd_err("get_params nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + for (i = 0; i < num_session_stats; i++) { + + nla_params = nla_nest_start(reply_skb, i); + if (!nla_params) { + hdd_err("get_stats nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAC_ADDR; + if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE, + params[i].peer_macaddr.bytes)) { + hdd_err("get_stats failed to put mac_addr"); + return QDF_STATUS_E_INVAL; + } + hdd_debug("get_stats peer mac_addr " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(params[i].peer_macaddr.bytes)); + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID; + if (nla_put_u8(reply_skb, attr, params[i].dialog_id)) { + hdd_err("get_stats failed to put dialog_id"); + return QDF_STATUS_E_INVAL; + } + + hdd_debug("%d wake duration %d num sp cycles %d", + params[i].dialog_id, wake_duration, + params[i].num_sp_cycles); + wake_duration = get_session_wake_duration(params[i].dialog_id); + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_SESSION_WAKE_DURATION; + if (nla_put_u32(reply_skb, attr, wake_duration)) { + hdd_err("get_params failed to put Wake duration"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS; + if (nla_put_u32(reply_skb, attr, params[i].num_sp_cycles)) { + hdd_err("get_params failed to put num_sp_cycles"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVG_WAKE_DURATION; + if (nla_put_u32(reply_skb, attr, params[i].avg_sp_dur_us)) { + hdd_err("get_params failed to put avg_sp_dur_us"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_MIN_WAKE_DURATION; + if (nla_put_u32(reply_skb, attr, params[i].min_sp_dur_us)) { + hdd_err("get_params failed to put min_sp_dur_us"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX_WAKE_DURATION; + if (nla_put_u32(reply_skb, attr, params[i].max_sp_dur_us)) { + hdd_err("get_params failed to put max_sp_dur_us"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_MPDU; + if (nla_put_u32(reply_skb, attr, params[i].tx_mpdu_per_sp)) { + hdd_err("get_params failed to put tx_mpdu_per_sp"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_MPDU; + if (nla_put_u32(reply_skb, attr, params[i].rx_mpdu_per_sp)) { + hdd_err("get_params failed to put rx_mpdu_per_sp"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_PACKET_SIZE; + if (nla_put_u32(reply_skb, attr, params[i].tx_bytes_per_sp)) { + hdd_err("get_params failed to put tx_bytes_per_sp"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_PACKET_SIZE; + if (nla_put_u32(reply_skb, attr, params[i].rx_bytes_per_sp)) { + hdd_err("get_params failed to put rx_bytes_per_sp"); + return QDF_STATUS_E_INVAL; + } + + nla_nest_end(reply_skb, nla_params); + } + nla_nest_end(reply_skb, config_attr); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_twt_get_session_traffic_stats() - Obtains twt session traffic statistics + * and sends response to the user space + * @adapter: hdd_adapter + * @dialog_id: dialog id of the twt session + * @peer_mac: Mac address of the peer + * + * Return: QDF_STATUS_SUCCESS on success, else other qdf error values + */ +static QDF_STATUS +hdd_twt_request_session_traffic_stats(struct hdd_adapter *adapter, + uint32_t dialog_id, uint8_t *peer_mac) +{ + int errno; + int skb_len; + struct sk_buff *reply_skb; + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct infra_cp_stats_event *event; + + if (!adapter || !peer_mac) + return status; + + event = wlan_cfg80211_mc_twt_get_infra_cp_stats(adapter->vdev, + dialog_id, + peer_mac, + &errno); + if (!event) + return errno; + + skb_len = hdd_get_twt_get_stats_event_len(); + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb( + adapter->hdd_ctx->wiphy, + skb_len); + if (!reply_skb) { + hdd_err("Get stats - alloc reply_skb failed"); + return -ENOMEM; + } + + status = hdd_twt_pack_get_stats_resp_nlmsg( + reply_skb, + event->twt_infra_cp_stats, + event->num_twt_infra_cp_stats); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Get stats - Failed to pack nl response"); + wlan_cfg80211_vendor_free_skb(reply_skb); + return qdf_status_to_os_return(status); + } + + return wlan_cfg80211_vendor_cmd_reply(reply_skb); +} + +/** + * hdd_twt_get_session_stats() - Parses twt nl attrributes, obtains twt + * session parameters based on dialog_id and returns to user via nl layer + * @adapter: hdd_adapter + * @twt_param_attr: twt nl attributes + * + * Return: 0 on success, negative value on failure + */ +static int hdd_twt_get_session_traffic_stats(struct hdd_adapter *adapter, + struct nlattr *twt_param_attr) +{ + struct hdd_station_ctx *hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX + 1]; + int ret, id; + QDF_STATUS qdf_status; + uint32_t dialog_id; + uint8_t peer_mac[QDF_MAC_ADDR_SIZE]; + + ret = wlan_cfg80211_nla_parse_nested( + tb, + QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX, + twt_param_attr, + qca_wlan_vendor_twt_stats_dialog_policy); + if (ret) + return ret; + + id = QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID; + if (tb[id]) + dialog_id = (uint32_t)nla_get_u8(tb[id]); + else + dialog_id = 0; + + hdd_debug("get_stats dialog_id %d", dialog_id); + + qdf_mem_copy(peer_mac, + hdd_sta_ctx->conn_info.bssid.bytes, + QDF_MAC_ADDR_SIZE); + hdd_debug("get_stats peer mac_addr " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac)); + + qdf_status = hdd_twt_request_session_traffic_stats(adapter, + dialog_id, peer_mac); + + return qdf_status_to_os_return(qdf_status); +} + /** * hdd_twt_notify_pack_nlmsg() - pack the skb with * twt notify event from firmware @@ -2447,6 +2685,10 @@ static int hdd_twt_configure(struct hdd_adapter *adapter, case QCA_WLAN_TWT_GET_CAPABILITIES: ret = hdd_twt_get_capabilities(adapter, twt_param_attr); break; + case QCA_WLAN_TWT_GET_STATS: + ret = hdd_twt_get_session_traffic_stats(adapter, + twt_param_attr); + break; default: hdd_err("Invalid TWT Operation"); ret = -EINVAL; diff --git a/os_if/cp_stats/src/wlan_cfg80211_mc_cp_stats.c b/os_if/cp_stats/src/wlan_cfg80211_mc_cp_stats.c index fbe196fcead9..9d9a2a75ca47 100644 --- a/os_if/cp_stats/src/wlan_cfg80211_mc_cp_stats.c +++ b/os_if/cp_stats/src/wlan_cfg80211_mc_cp_stats.c @@ -23,6 +23,7 @@ */ #include +#include #include #include #include @@ -50,6 +51,41 @@ static void wlan_free_mib_stats(struct stats_event *stats) } #endif +#ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS +#ifdef WLAN_SUPPORT_TWT +static void wlan_cfg80211_infra_cp_stats_twt_dealloc(void *priv) +{ + struct infra_cp_stats_event *stats = priv; + + qdf_mem_free(stats->twt_infra_cp_stats); + stats->twt_infra_cp_stats = NULL; +} +#else +static void wlan_cfg80211_infra_cp_stats_twt_dealloc(void *priv) +{ +} +#endif /* WLAN_SUPPORT_TWT */ + +/** + * wlan_cfg80211_mc_infra_cp_stats_dealloc() - callback to free priv + * allocations for infra cp stats + * @priv: Pointer to priv data statucture + * + * Return: None + */ +static inline +void wlan_cfg80211_mc_infra_cp_stats_dealloc(void *priv) +{ + struct infra_cp_stats_event *stats = priv; + + if (!stats) { + osif_err("infar_cp_stats is NULL"); + return; + } + wlan_cfg80211_infra_cp_stats_twt_dealloc(priv); +} +#endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */ + /** * wlan_cfg80211_mc_cp_stats_dealloc() - callback to free priv * allocations for stats @@ -522,6 +558,220 @@ station_stats_cb_fail: osif_request_put(request); } +#ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS + +#ifdef WLAN_SUPPORT_TWT +static void get_twt_infra_cp_stats(struct infra_cp_stats_event *ev, + struct infra_cp_stats_event *priv) + +{ + priv->num_twt_infra_cp_stats = ev->num_twt_infra_cp_stats; + priv->twt_infra_cp_stats->dialog_id = ev->twt_infra_cp_stats->dialog_id; + priv->twt_infra_cp_stats->status = ev->twt_infra_cp_stats->status; + priv->twt_infra_cp_stats->num_sp_cycles = + ev->twt_infra_cp_stats->num_sp_cycles; + priv->twt_infra_cp_stats->avg_sp_dur_us = + ev->twt_infra_cp_stats->avg_sp_dur_us; + priv->twt_infra_cp_stats->min_sp_dur_us = + ev->twt_infra_cp_stats->min_sp_dur_us; + priv->twt_infra_cp_stats->max_sp_dur_us = + ev->twt_infra_cp_stats->max_sp_dur_us; + priv->twt_infra_cp_stats->tx_mpdu_per_sp = + ev->twt_infra_cp_stats->tx_mpdu_per_sp; + priv->twt_infra_cp_stats->rx_mpdu_per_sp = + ev->twt_infra_cp_stats->rx_mpdu_per_sp; + priv->twt_infra_cp_stats->tx_bytes_per_sp = + ev->twt_infra_cp_stats->tx_bytes_per_sp; + priv->twt_infra_cp_stats->rx_bytes_per_sp = + ev->twt_infra_cp_stats->rx_bytes_per_sp; +} + +static void +wlan_cfg80211_mc_infra_cp_free_twt_stats(struct infra_cp_stats_event *stats) +{ + qdf_mem_free(stats->twt_infra_cp_stats); +} +#else +static void get_twt_infra_cp_stats(struct infra_cp_stats_event *ev, + struct infra_cp_stats_event *priv) +{ +} + +static void +wlan_cfg80211_mc_infra_cp_free_twt_stats(struct infra_cp_stats_event *stats) +{ +} +#endif /* WLAN_SUPPORT_TWT */ + +static inline void +wlan_cfg80211_mc_infra_cp_stats_free_stats_event( + struct infra_cp_stats_event *stats) +{ + if (!stats) + return; + wlan_cfg80211_mc_infra_cp_free_twt_stats(stats); + qdf_mem_free(stats); +} + +/** + * infra_cp_stats_response_cb() - callback function to handle stats event + * @ev: stats event buffer + * @cookie: a cookie for the request context + * + * Return: None + */ +static inline +void infra_cp_stats_response_cb(struct infra_cp_stats_event *ev, + void *cookie) +{ + struct infra_cp_stats_event *priv; + struct osif_request *request; + + request = osif_request_get(cookie); + if (!request) { + osif_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + + priv->action = ev->action; + priv->request_id = ev->request_id; + priv->status = ev->status; + get_twt_infra_cp_stats(ev, priv); + + osif_request_complete(request); + osif_request_put(request); +} + +#ifdef WLAN_SUPPORT_TWT +/*Infra limits Add comment here*/ +#define MAX_TWT_STAT_VDEV_ENTRIES 1 +#define MAX_TWT_STAT_MAC_ADDR_ENTRIES 1 +struct infra_cp_stats_event * +wlan_cfg80211_mc_twt_get_infra_cp_stats(struct wlan_objmgr_vdev *vdev, + uint32_t dialog_id, + uint8_t twt_peer_mac[QDF_MAC_ADDR_SIZE], + int *errno) +{ + void *cookie; + QDF_STATUS status; + struct infra_cp_stats_event *priv, *out; + struct twt_infra_cp_stats_event *twt_event; + struct wlan_objmgr_peer *peer; + struct osif_request *request; + struct infra_cp_stats_cmd_info info = {0}; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = 2 * CP_STATS_WAIT_TIME_STAT, + .dealloc = wlan_cfg80211_mc_infra_cp_stats_dealloc, + }; + + osif_debug("Enter"); + + out = qdf_mem_malloc(sizeof(*out)); + if (!out) { + *errno = -ENOMEM; + return NULL; + } + + out->twt_infra_cp_stats = + qdf_mem_malloc(sizeof(*out->twt_infra_cp_stats)); + if (!out->twt_infra_cp_stats) { + *errno = -ENOMEM; + return NULL; + } + + request = osif_request_alloc(¶ms); + if (!request) { + qdf_mem_free(out); + *errno = -ENOMEM; + return NULL; + } + + cookie = osif_request_cookie(request); + priv = osif_request_priv(request); + + priv->twt_infra_cp_stats = + qdf_mem_malloc(sizeof(*priv->twt_infra_cp_stats)); + if (!priv->twt_infra_cp_stats) { + *errno = -ENOMEM; + return NULL; + } + twt_event = priv->twt_infra_cp_stats; + + info.request_cookie = cookie; + info.stats_id = TYPE_REQ_CTRL_PATH_TWT_STAT; + info.action = ACTION_REQ_CTRL_PATH_STAT_GET; + info.infra_cp_stats_resp_cb = infra_cp_stats_response_cb; + info.num_pdev_ids = 0; + info.num_vdev_ids = MAX_TWT_STAT_VDEV_ENTRIES; + info.vdev_id[0] = wlan_vdev_get_id(vdev); + info.num_mac_addr_list = MAX_TWT_STAT_MAC_ADDR_ENTRIES; + qdf_mem_copy(&info.peer_mac_addr[0], twt_peer_mac, QDF_MAC_ADDR_SIZE); + + info.dialog_id = dialog_id; + info.num_pdev_ids = 0; + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_CP_STATS_ID); + if (!peer) { + osif_err("peer is null"); + *errno = -EINVAL; + goto get_twt_stats_fail; + } + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + + status = ucfg_infra_cp_stats_register_resp_cb(wlan_vdev_get_psoc(vdev), + &info); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to register resp callback: %d", status); + *errno = qdf_status_to_os_return(status); + goto get_twt_stats_fail; + } + + status = ucfg_send_infra_cp_stats_request(vdev, &info); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to send twt stats request status: %d", + status); + *errno = qdf_status_to_os_return(status); + goto get_twt_stats_fail; + } + + *errno = osif_request_wait_for_response(request); + if (*errno) { + osif_err("wait failed or timed out ret: %d", *errno); + goto get_twt_stats_fail; + } + + out->num_twt_infra_cp_stats = priv->num_twt_infra_cp_stats; + out->request_id = priv->request_id; + out->twt_infra_cp_stats->dialog_id = twt_event->dialog_id; + out->twt_infra_cp_stats->status = twt_event->status; + out->twt_infra_cp_stats->num_sp_cycles = twt_event->num_sp_cycles; + out->twt_infra_cp_stats->avg_sp_dur_us = twt_event->avg_sp_dur_us; + out->twt_infra_cp_stats->min_sp_dur_us = twt_event->min_sp_dur_us; + out->twt_infra_cp_stats->max_sp_dur_us = twt_event->max_sp_dur_us; + out->twt_infra_cp_stats->tx_mpdu_per_sp = twt_event->tx_mpdu_per_sp; + out->twt_infra_cp_stats->rx_mpdu_per_sp = twt_event->rx_mpdu_per_sp; + out->twt_infra_cp_stats->tx_bytes_per_sp = twt_event->tx_bytes_per_sp; + out->twt_infra_cp_stats->rx_bytes_per_sp = twt_event->rx_bytes_per_sp; + osif_request_put(request); + + osif_debug("Exit"); + + return out; + +get_twt_stats_fail: + osif_request_put(request); + wlan_cfg80211_mc_infra_cp_stats_free_stats_event(out); + + osif_debug("Exit"); + + return NULL; +} +#endif +#endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */ + struct stats_event * wlan_cfg80211_mc_cp_stats_get_station_stats(struct wlan_objmgr_vdev *vdev, int *errno)