diff --git a/umac/cp_stats/core/src/wlan_cp_stats_obj_mgr_handler.c b/umac/cp_stats/core/src/wlan_cp_stats_obj_mgr_handler.c index 6523cee1c2..1a48948333 100644 --- a/umac/cp_stats/core/src/wlan_cp_stats_obj_mgr_handler.c +++ b/umac/cp_stats/core/src/wlan_cp_stats_obj_mgr_handler.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 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 @@ -462,5 +463,275 @@ wlan_cp_stats_send_infra_cp_req(struct wlan_objmgr_psoc *psoc, } return tx_ops->send_req_infra_cp_stats(psoc, req); } + +#if defined(WLAN_SUPPORT_TWT) && defined (WLAN_TWT_CONV_SUPPORTED) +/** + * wlan_cp_stats_twt_get_peer_session_param() - Obtains twt session parameters + * of a peer if twt session is valid + * @mc_cp_stats: pointer to peer specific stats + * @param: Pointer to copy twt session parameters + * @num_twt_sessions Pointer holding total number of valid twt sessions + * + * Return: QDF_STATUS success if valid twt session parameters are obtained + * else other qdf error values + */ +static QDF_STATUS +wlan_cp_stats_twt_get_peer_session_param(struct peer_cp_stats *peer_cp_stat_prv, + struct twt_session_stats_info *params, + int *num_twt_session) +{ + struct twt_session_stats_info *twt_params; + QDF_STATUS qdf_status = QDF_STATUS_E_INVAL; + uint32_t event_type; + int i; + + if (!peer_cp_stat_prv || !params) + return qdf_status; + + for (i = 0; i < TWT_PEER_MAX_SESSIONS; i++) { + twt_params = &peer_cp_stat_prv->twt_param[i]; + event_type = peer_cp_stat_prv->twt_param[i].event_type; + + /* Check twt session is established */ + + if (event_type == HOST_TWT_SESSION_SETUP || + event_type == HOST_TWT_SESSION_UPDATE) { + qdf_mem_copy(¶ms[*num_twt_session], twt_params, + sizeof(*twt_params)); + qdf_status = QDF_STATUS_SUCCESS; + *num_twt_session += 1; + } + } + + return qdf_status; +} + +/** + * wlan_cp_stats_twt_get_all_peer_session_params()- Retrieves twt session + * parameters of all peers with valid twt session + * @psoc_obj: psoc object + * @vdvev_id: vdev_id + * @params: array of pointer to store peer twt session parameters + * + * Return: total number of valid twt sessions + */ +static int +wlan_cp_stats_twt_get_all_peer_session_params( + struct wlan_objmgr_psoc *psoc_obj, + uint8_t vdev_id, + struct twt_session_stats_info *params) +{ + qdf_list_t *peer_list; + struct wlan_objmgr_peer *peer, *peer_next; + struct wlan_objmgr_vdev *vdev; + struct peer_cp_stats *cp_stats_peer_obj, *peer_cp_stat_prv; + int num_twt_session = 0; + enum QDF_OPMODE opmode; + uint16_t sap_num_peer; + + if (!psoc_obj) { + cp_stats_err("psoc is NULL"); + return num_twt_session; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc_obj, vdev_id, + WLAN_CP_STATS_ID); + if (!vdev) { + cp_stats_err("vdev is NULL, vdev_id: %d", vdev_id); + return num_twt_session; + } + + sap_num_peer = wlan_vdev_get_peer_count(vdev); + opmode = wlan_vdev_mlme_get_opmode(vdev); + + peer_list = &vdev->vdev_objmgr.wlan_peer_list; + if (!peer_list) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); + cp_stats_err("Peer list for vdev obj is NULL"); + return num_twt_session; + } + + peer = wlan_vdev_peer_list_peek_active_head(vdev, peer_list, + WLAN_CP_STATS_ID); + while (peer) { + cp_stats_peer_obj = wlan_objmgr_peer_get_comp_private_obj( + peer, WLAN_UMAC_COMP_CP_STATS); + + peer_cp_stat_prv = wlan_cp_stats_get_peer_stats_obj(peer); + if (peer_cp_stat_prv) { + wlan_cp_stats_peer_obj_lock(peer_cp_stat_prv); + wlan_cp_stats_twt_get_peer_session_param( + peer_cp_stat_prv, + params, + &num_twt_session); + wlan_cp_stats_peer_obj_unlock(peer_cp_stat_prv); + } + + if (opmode == QDF_STA_MODE && + num_twt_session >= TWT_PEER_MAX_SESSIONS) { + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + goto done; + } + + if (opmode == QDF_SAP_MODE && + num_twt_session >= (sap_num_peer * TWT_PEER_MAX_SESSIONS)) { + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + goto done; + } + + peer_next = wlan_peer_get_next_active_peer_of_vdev( + vdev, peer_list, peer, + WLAN_CP_STATS_ID); + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + peer = peer_next; + } +done: + if (!num_twt_session) + cp_stats_err("Unable to find a peer with twt session established"); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); + return num_twt_session; +} + +/** + * wlan_cp_stats_twt_get_peer_session_param_by_dlg_id() - Finds a Peer twt + * session with dialog id matching with input dialog id. If a match is found + * copies the twt session parameters + * @peer_cp_stats_priv: pointer to peer specific stats + * @input_dialog_id: input dialog id + * @dest_param: Pointer to copy twt session parameters when a peer with + * given dialog id is found + * @num_twt_session: Pointer holding total number of valid twt session + * + * Return: Success if stats are copied for a peer with given dialog, + * else failure + */ +static QDF_STATUS +wlan_cp_stats_twt_get_peer_session_param_by_dlg_id( + struct peer_cp_stats *peer_cp_stats_priv, + uint32_t input_dialog_id, + struct twt_session_stats_info *dest_param, + int *num_twt_session) +{ + struct twt_session_stats_info *src_param; + uint32_t event_type; + int i = 0; + QDF_STATUS qdf_status = QDF_STATUS_E_INVAL; + + if (!peer_cp_stats_priv || !dest_param) + return qdf_status; + + for (i = 0; i < TWT_PEER_MAX_SESSIONS; i++) { + event_type = peer_cp_stats_priv->twt_param[i].event_type; + src_param = &peer_cp_stats_priv->twt_param[i]; + if (!event_type || + (src_param->dialog_id != input_dialog_id && + input_dialog_id != TWT_ALL_SESSIONS_DIALOG_ID)) + continue; + + if (event_type == HOST_TWT_SESSION_SETUP || + event_type == HOST_TWT_SESSION_UPDATE) { + qdf_mem_copy(&dest_param[*num_twt_session], src_param, + sizeof(*src_param)); + qdf_status = QDF_STATUS_SUCCESS; + *num_twt_session += 1; + if (*num_twt_session >= TWT_PEER_MAX_SESSIONS) + break; + } + } + + return qdf_status; +} + +/** + * wlan_cp_stats_twt_get_single_peer_session_params()- Extracts twt session + * parameters corresponding to a peer given by dialog_id + * @psoc_obj: psoc object + * @mac_addr: mac addr of peer + * @dialog_id: dialog id of peer for which twt session params to be retrieved + * @params: pointer to store peer twt session parameters + * + * Return: total number of valid twt session + */ +static int +wlan_cp_stats_twt_get_single_peer_session_params( + struct wlan_objmgr_psoc *psoc_obj, + uint8_t *mac_addr, uint32_t dialog_id, + struct twt_session_stats_info *params) +{ + struct wlan_objmgr_peer *peer; + struct peer_cp_stats *peer_cp_stats_priv; + QDF_STATUS qdf_status = QDF_STATUS_E_INVAL; + int num_twt_session = 0; + + if (!psoc_obj || !params) + return num_twt_session; + + peer = wlan_objmgr_get_peer_by_mac(psoc_obj, mac_addr, + WLAN_CP_STATS_ID); + if (!peer) + return num_twt_session; + peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer); + + if (!peer_cp_stats_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + return num_twt_session; + } + + wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv); + + qdf_status = wlan_cp_stats_twt_get_peer_session_param_by_dlg_id( + peer_cp_stats_priv, + dialog_id, + params, + &num_twt_session); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + qdf_err("No TWT session for " QDF_MAC_ADDR_FMT " dialog_id %d", + QDF_MAC_ADDR_REF(mac_addr), dialog_id); + } + + wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv); + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + + return num_twt_session; +} + +int +wlan_cp_stats_twt_get_peer_session_params(struct wlan_objmgr_psoc *psoc, + struct twt_session_stats_info *params) +{ + uint8_t *mac_addr; + uint32_t dialog_id; + uint8_t vdev_id; + int num_twt_session = 0; + + if (!psoc || !params) + return num_twt_session; + + mac_addr = params[0].peer_mac.bytes; + dialog_id = params[0].dialog_id; + vdev_id = params[0].vdev_id; + + /* + * Currently for STA case, twt_get_params nl is sending only dialog_id + * and mac_addr is being filled by driver in STA peer case. + * For SAP case, twt_get_params nl is sending dialog_id and + * peer mac_addr. When twt_get_params add mac_addr and dialog_id of + * STA/SAP, we need handle unicast/multicast macaddr in + * wlan_cp_stats_twt_get_peer_session_params. + */ + if (!QDF_IS_ADDR_BROADCAST(mac_addr)) + num_twt_session = + wlan_cp_stats_twt_get_single_peer_session_params( + psoc, mac_addr, + dialog_id, + params); + else + num_twt_session = wlan_cp_stats_twt_get_all_peer_session_params( + psoc, vdev_id, + params); + return num_twt_session; +} +#endif #endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */ diff --git a/umac/cp_stats/core/src/wlan_cp_stats_obj_mgr_handler.h b/umac/cp_stats/core/src/wlan_cp_stats_obj_mgr_handler.h index 3e955c8c25..0a0f2ea09d 100644 --- a/umac/cp_stats/core/src/wlan_cp_stats_obj_mgr_handler.h +++ b/umac/cp_stats/core/src/wlan_cp_stats_obj_mgr_handler.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 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 @@ -165,6 +166,11 @@ QDF_STATUS wlan_cp_stats_send_infra_cp_req(struct wlan_objmgr_psoc *psoc, struct infra_cp_stats_cmd_info *req); +#if defined(WLAN_SUPPORT_TWT) && defined (WLAN_TWT_CONV_SUPPORTED) +int wlan_cp_stats_twt_get_peer_session_params( + struct wlan_objmgr_psoc *psoc, + struct twt_session_stats_info *params); +#endif #endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */ #endif /* QCA_SUPPORT_CP_STATS */ #endif /* __WLAN_CP_STATS_OBJ_MGR_HANDLER_H__ */ diff --git a/umac/cp_stats/dispatcher/inc/wlan_cp_stats_ucfg_api.h b/umac/cp_stats/dispatcher/inc/wlan_cp_stats_ucfg_api.h index 52cd80accf..aa598ec63e 100644 --- a/umac/cp_stats/dispatcher/inc/wlan_cp_stats_ucfg_api.h +++ b/umac/cp_stats/dispatcher/inc/wlan_cp_stats_ucfg_api.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 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 @@ -54,5 +55,11 @@ ucfg_infra_cp_stats_register_resp_cb(struct wlan_objmgr_psoc *psoc, QDF_STATUS ucfg_send_infra_cp_stats_request(struct wlan_objmgr_vdev *vdev, struct infra_cp_stats_cmd_info *req); + +#if defined(WLAN_SUPPORT_TWT) && defined (WLAN_TWT_CONV_SUPPORTED) +int ucfg_cp_stats_twt_get_peer_session_params( + struct wlan_objmgr_psoc *psoc_obj, + struct twt_session_stats_info *params); +#endif #endif /* QCA_SUPPORT_CP_STATS */ #endif /* __WLAN_CP_STATS_UCFG_API_H__ */ diff --git a/umac/cp_stats/dispatcher/src/wlan_cp_stats_ucfg_api.c b/umac/cp_stats/dispatcher/src/wlan_cp_stats_ucfg_api.c index 64de8e3f8c..8d0a69d7bb 100644 --- a/umac/cp_stats/dispatcher/src/wlan_cp_stats_ucfg_api.c +++ b/umac/cp_stats/dispatcher/src/wlan_cp_stats_ucfg_api.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 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 @@ -40,4 +41,13 @@ ucfg_send_infra_cp_stats_request(struct wlan_objmgr_vdev *vdev, { return wlan_cp_stats_send_infra_cp_req(wlan_vdev_get_psoc(vdev), req); } + +#if defined(WLAN_SUPPORT_TWT) && defined (WLAN_TWT_CONV_SUPPORTED) +int ucfg_cp_stats_twt_get_peer_session_params( + struct wlan_objmgr_psoc *psoc_obj, + struct twt_session_stats_info *params) +{ + return wlan_cp_stats_twt_get_peer_session_params(psoc_obj, params); +} +#endif #endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */