Browse Source

qcacld-3.0: Extract Peer TWT session parameters

WMI handler is registered for twt_session_stats event.
Upon wmi event twt session parameters are extracted and
cached in peer mc_cp_stats. UMAC APIs are provided to
retrieve TWT session parameters from north bound
interface(hdd) using twt peer's mac_addr/session dialog_id

CRs-Fixed: 2730732
Change-Id: I8ce38ac6be97e844e26e03751c6d6cca981b82b4
Visweswara Tanuku 4 years ago
parent
commit
78df7f106e

+ 12 - 0
components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_defs.h

@@ -29,6 +29,14 @@
 #include "wlan_cmn.h"
 #include "qdf_event.h"
 
+#ifdef WLAN_SUPPORT_TWT
+
+#include <wmi_unified_twt_param.h>
+/* Max TWT sessions per peer (supported by fw) */
+#define TWT_PEER_MAX_SESSIONS 1
+
+#endif /* WLAN_SUPPORT_TWT */
+
 #define MAX_NUM_CHAINS              2
 
 #define MAX_MIB_STATS               1
@@ -300,6 +308,7 @@ struct peer_extd_stats {
  * @peer_macaddr: mac address
  * @extd_stats: Pointer to peer extended stats
  * @adv_stats: Pointer to peer adv (extd2) stats
+ * @twt_param: Pointer to peer twt session parameters
  */
 struct peer_mc_cp_stats {
 	uint32_t tx_rate;
@@ -308,6 +317,9 @@ struct peer_mc_cp_stats {
 	uint8_t peer_macaddr[QDF_MAC_ADDR_SIZE];
 	struct peer_extd_stats *extd_stats;
 	struct peer_adv_mc_cp_stats *adv_stats;
+#ifdef WLAN_SUPPORT_TWT
+	struct wmi_host_twt_session_stats_info twt_param[TWT_PEER_MAX_SESSIONS];
+#endif
 };
 
 /**

+ 31 - 0
components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h

@@ -31,6 +31,37 @@
 #include <wlan_objmgr_vdev_obj.h>
 #include <wlan_cp_stats_mc_defs.h>
 
+#ifdef WLAN_SUPPORT_TWT
+
+#include <wlan_objmgr_peer_obj.h>
+#include "../../core/src/wlan_cp_stats_defs.h"
+#include <qdf_event.h>
+
+/* Max TWT sessions supported */
+#define TWT_PSOC_MAX_SESSIONS TWT_PEER_MAX_SESSIONS
+
+/* Valid dialog_id 0 to (0xFF - 1) */
+#define TWT_MAX_DIALOG_ID (0xFF - 1)
+
+/* dialog_id used to get all peer's twt session parameters */
+#define TWT_GET_ALL_PEER_PARAMS_DIALOG_ID (0xFF)
+
+/**
+ * ucfg_twt_get_peer_session_params() - Retrieves peer twt session parameters
+ * corresponding to a peer by using mac_addr and dialog id
+ * If dialog_id is TWT_GET_ALL_PEER_PARAMS_DIALOG_ID retrieves twt session
+ * parameters of all peers with valid twt session
+ * @psoc_obj: psoc object
+ * @params: array pointer to store peer twt session parameters, should contain
+ * mac_addr and dialog id of a peer for which twt session stats to be retrieved
+ *
+ * Return: QDF_STATUS_SUCCESS upon success, else qdf error values
+ */
+QDF_STATUS
+ucfg_twt_get_peer_session_params(struct wlan_objmgr_psoc *psoc_obj,
+				 struct wmi_host_twt_session_stats_info *param);
+#endif /* WLAN_SUPPORT_TWT */
+
 struct psoc_cp_stats;
 struct vdev_cp_stats;
 

+ 247 - 1
components/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c

@@ -28,12 +28,258 @@
 #include <wlan_cp_stats_mc_tgt_api.h>
 #include <wlan_cp_stats_utils_api.h>
 #include "../../core/src/wlan_cp_stats_defs.h"
-#include "../../core/src/wlan_cp_stats_defs.h"
 #include "../../core/src/wlan_cp_stats_cmn_api_i.h"
 #ifdef WLAN_POWER_MANAGEMENT_OFFLOAD
 #include <wlan_pmo_obj_mgmt_api.h>
 #endif
 
+#ifdef WLAN_SUPPORT_TWT
+
+/**
+ * ucfg_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
+ * @mc_stats: 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
+ *
+ * Return: true if stats are copied for a peer with given dialog, else false
+ */
+static bool
+ucfg_twt_get_peer_session_param_by_dlg_id(struct peer_mc_cp_stats *mc_stats,
+					  uint32_t input_dialog_id,
+					  struct wmi_host_twt_session_stats_info
+					  *dest_param)
+{
+	struct wmi_host_twt_session_stats_info *src_param;
+	uint32_t event_type;
+	int i;
+
+	if (!mc_stats || !dest_param)
+		return false;
+
+	for (i = 0; i < TWT_PEER_MAX_SESSIONS; i++) {
+		event_type = mc_stats->twt_param[i].event_type;
+
+		src_param = &mc_stats->twt_param[i];
+		if ((!event_type) || (src_param->dialog_id != input_dialog_id))
+			continue;
+
+		if ((event_type == HOST_TWT_SESSION_SETUP) ||
+		    (event_type == HOST_TWT_SESSION_UPDATE)) {
+			qdf_mem_copy(dest_param, src_param, sizeof(*src_param));
+			return true;
+		}
+	}
+
+	return false;
+}
+
+/**
+ * ucfg_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: Retuns QDF_STATUS_SUCCESS upon success, else qdf error values
+ */
+static QDF_STATUS
+ucfg_twt_get_single_peer_session_params(struct wlan_objmgr_psoc *psoc_obj,
+					uint8_t *mac_addr, uint32_t dialog_id,
+					struct wmi_host_twt_session_stats_info
+					*params)
+{
+	struct wlan_objmgr_peer *peer;
+	struct peer_cp_stats *peer_cp_stats_priv;
+	struct peer_mc_cp_stats *peer_mc_stats;
+	QDF_STATUS qdf_status = QDF_STATUS_E_INVAL;
+
+	if (!psoc_obj || !params)
+		return qdf_status;
+
+	peer = wlan_objmgr_get_peer_by_mac(psoc_obj, mac_addr,
+					   WLAN_CP_STATS_ID);
+	if (!peer)
+		return qdf_status;
+
+	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 qdf_status;
+	}
+
+	wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv);
+	peer_mc_stats = peer_cp_stats_priv->peer_stats;
+
+	if (ucfg_twt_get_peer_session_param_by_dlg_id(peer_mc_stats,
+						      dialog_id, params)) {
+		qdf_status = QDF_STATUS_SUCCESS;
+	} else {
+		qdf_err("No TWT session for " QDF_MAC_ADDR_STR " dialog_id %d",
+			QDF_MAC_ADDR_ARRAY(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 qdf_status;
+}
+
+/**
+ * ucfg_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
+ucfg_twt_get_peer_session_param(struct peer_mc_cp_stats *mc_cp_stats,
+				struct wmi_host_twt_session_stats_info *params,
+				int *num_twt_sessions)
+{
+	struct wmi_host_twt_session_stats_info *twt_params;
+	QDF_STATUS qdf_status = QDF_STATUS_E_INVAL;
+	uint32_t event_type;
+	int i;
+
+	if (!mc_cp_stats || !params)
+		return qdf_status;
+
+	for (i = 0; i < TWT_PEER_MAX_SESSIONS; i++) {
+		twt_params = &mc_cp_stats->twt_param[i];
+		event_type = mc_cp_stats->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(&params[*num_twt_sessions], twt_params,
+				     sizeof(*twt_params));
+			qdf_status = QDF_STATUS_SUCCESS;
+			*num_twt_sessions += 1;
+			if (*num_twt_sessions >= TWT_PSOC_MAX_SESSIONS)
+				break;
+		}
+	}
+	return qdf_status;
+}
+
+/**
+ * ucfg_twt_get_all_peer_session_params()- Retrieves twt session parameters
+ * of all peers with valid twt session
+ * @psoc_obj: psoc object
+ * @params: array of pointer to store peer twt session parameters
+ *
+ * Return: Retuns QDF_STATUS_SUCCESS upon success, else qdf error values
+ */
+static QDF_STATUS
+ucfg_twt_get_all_peer_session_params(struct wlan_objmgr_psoc *psoc_obj,
+				     struct wmi_host_twt_session_stats_info
+				     *params)
+{
+	struct wlan_objmgr_psoc_objmgr *psoc_objmgr;
+	struct wlan_objmgr_peer *peer_obj;
+	struct wlan_peer_list *peer_list;
+	struct peer_cp_stats *cp_stats_peer_obj;
+	struct peer_mc_cp_stats *mc_cp_stats;
+	struct peer_cp_stats *peer_cp_stat_prv;
+	QDF_STATUS qdf_status = QDF_STATUS_E_INVAL;
+	qdf_list_t *obj_list;
+	int i, num_sessions = 0;
+
+	/* psoc obj lock should be taken before peer list lock */
+	wlan_psoc_obj_lock(psoc_obj);
+	psoc_objmgr = &psoc_obj->soc_objmgr;
+	/* List is empty, return */
+	if (!psoc_objmgr->wlan_peer_count) {
+		wlan_psoc_obj_unlock(psoc_obj);
+		return qdf_status;
+	}
+
+	peer_list = &psoc_objmgr->peer_list;
+	qdf_spin_lock_bh(&peer_list->peer_list_lock);
+
+	/* Iterate through peer_list to find a peer with valid twt sessions */
+	for (i = 0; i < WLAN_PEER_HASHSIZE; i++) {
+		obj_list = &peer_list->peer_hash[i];
+		peer_obj = wlan_psoc_peer_list_peek_head(obj_list);
+		while (peer_obj) {
+			cp_stats_peer_obj =
+				wlan_objmgr_peer_get_comp_private_obj
+					(peer_obj, WLAN_UMAC_COMP_CP_STATS);
+
+			mc_cp_stats = NULL;
+			if (cp_stats_peer_obj)
+				mc_cp_stats = cp_stats_peer_obj->peer_stats;
+
+			peer_cp_stat_prv =
+				wlan_cp_stats_get_peer_stats_obj(peer_obj);
+
+			if (peer_cp_stat_prv && mc_cp_stats) {
+				wlan_cp_stats_peer_obj_lock(peer_cp_stat_prv);
+				ucfg_twt_get_peer_session_param(mc_cp_stats,
+								params,
+								&num_sessions);
+				wlan_cp_stats_peer_obj_unlock(peer_cp_stat_prv);
+			}
+
+			if (num_sessions >= TWT_PSOC_MAX_SESSIONS)
+				goto done;
+			/* Get next peer */
+			peer_obj = wlan_peer_get_next_peer_of_psoc(obj_list,
+								   peer_obj);
+		}
+	}
+
+done:
+	/* If atleast one peer with valid twt session is found return success */
+	if (num_sessions)
+		qdf_status = QDF_STATUS_SUCCESS;
+	else
+		qdf_err("Unable to find a peer with twt session established");
+
+	qdf_spin_unlock_bh(&peer_list->peer_list_lock);
+	wlan_psoc_obj_unlock(psoc_obj);
+	return qdf_status;
+}
+
+QDF_STATUS
+ucfg_twt_get_peer_session_params(struct wlan_objmgr_psoc *psoc_obj,
+				 struct wmi_host_twt_session_stats_info *params)
+{
+	uint8_t *mac_addr;
+	uint32_t dialog_id;
+
+	if (!psoc_obj || !params)
+		return QDF_STATUS_E_INVAL;
+
+	mac_addr = params[0].peer_mac;
+	dialog_id = params[0].dialog_id;
+
+	/*
+	 * Currently twt_get_params nl cmd is sending only dialog_id(STA) and
+	 * mac_addr is being filled by driver in STA peer case. When
+	 * twt_get_params adds support for mac_addr and dialog_id of STA/SAP,
+	 * we need handle unicast/multicast macaddr in
+	 * ucfg_twt_get_all_peer_session_params for all active twt sessions
+	 */
+	if (dialog_id <= TWT_MAX_DIALOG_ID)
+		return ucfg_twt_get_single_peer_session_params(psoc_obj,
+							       mac_addr,
+							       dialog_id,
+							       params);
+	else if (dialog_id == TWT_GET_ALL_PEER_PARAMS_DIALOG_ID)
+		return ucfg_twt_get_all_peer_session_params(psoc_obj, params);
+
+	return QDF_STATUS_E_INVAL;
+}
+#endif /* WLAN_SUPPORT_TWT */
+
 QDF_STATUS wlan_cp_stats_psoc_cs_init(struct psoc_cp_stats *psoc_cs)
 {
 	psoc_cs->obj_stats = qdf_mem_malloc(sizeof(struct psoc_mc_cp_stats));

+ 312 - 2
components/target_if/cp_stats/src/target_if_mc_cp_stats.c

@@ -40,6 +40,274 @@
 #include <cdp_txrx_host_stats.h>
 #include <cds_api.h>
 
+#ifdef WLAN_SUPPORT_TWT
+
+#include <wmi.h>
+#include <wlan_cp_stats_mc_ucfg_api.h>
+
+/**
+ * target_if_twt_fill_peer_twt_session_params() - Fills peer twt session
+ * parameter obtained from firmware into mc_cp_stats of peer
+ * @mc_cp_stats: Pointer to Peer mc_cp stats
+ * @twt_params: twt session parameters to be copied
+ *
+ * Return: None
+ */
+static void target_if_twt_fill_peer_twt_session_params
+(
+	struct peer_mc_cp_stats *mc_cp_stats,
+	struct wmi_host_twt_session_stats_info *twt_params
+)
+{
+	uint32_t event_type;
+	int i = 0;
+
+	if (!mc_cp_stats || !twt_params)
+		return;
+
+	if ((twt_params->event_type == HOST_TWT_SESSION_UPDATE) ||
+	    (twt_params->event_type == HOST_TWT_SESSION_TEARDOWN)) {
+		/* Update for a existing session, find by dialog_id */
+		for (i = 0; i < TWT_PEER_MAX_SESSIONS; i++) {
+			if (mc_cp_stats->twt_param[i].dialog_id !=
+			    twt_params->dialog_id)
+				continue;
+			qdf_mem_copy(&mc_cp_stats->twt_param[i], twt_params,
+				     sizeof(*twt_params));
+			return;
+		}
+	} else if (twt_params->event_type == HOST_TWT_SESSION_SETUP) {
+		/* New session, fill in any existing invalid session */
+		for (i = 0; i < TWT_PEER_MAX_SESSIONS; i++) {
+			event_type = mc_cp_stats->twt_param[i].event_type;
+			if ((event_type != HOST_TWT_SESSION_SETUP) &&
+			    (event_type != HOST_TWT_SESSION_UPDATE)) {
+				qdf_mem_copy(&mc_cp_stats->twt_param[i],
+					     twt_params,
+					     sizeof(*twt_params));
+				return;
+			}
+		}
+	}
+
+	target_if_err("Unable to save twt session params with dialog id %d",
+		      twt_params->dialog_id);
+}
+
+/**
+ * target_if_obtain_mc_cp_stat_obj() - Retrieves peer mc cp stats object
+ * @peer_obj: peer object
+ *
+ * Return: mc cp stats object on success or NULL
+ */
+static struct peer_mc_cp_stats *
+target_if_obtain_mc_cp_stat_obj(struct wlan_objmgr_peer *peer_obj)
+{
+	struct peer_cp_stats *cp_stats_peer_obj;
+	struct peer_mc_cp_stats *mc_cp_stats;
+
+	cp_stats_peer_obj = wlan_objmgr_peer_get_comp_private_obj
+				(peer_obj, WLAN_UMAC_COMP_CP_STATS);
+	if (!cp_stats_peer_obj) {
+		target_if_err("cp peer stats obj err");
+		return NULL;
+	}
+
+	mc_cp_stats = cp_stats_peer_obj->peer_stats;
+	if (!mc_cp_stats) {
+		target_if_err("mc stats obj err");
+		return NULL;
+	}
+	return mc_cp_stats;
+}
+
+/**
+ * target_if_twt_session_params_event_handler() - Handles twt session stats
+ * event from firmware and store the per peer twt session parameters in
+ * mc_cp_stats
+ * @scn: scn handle
+ * @evt_buf: data buffer for event
+ * @evt_data_len: data length of event
+ *
+ * Return: 0 on success, else error values
+ */
+static int target_if_twt_session_params_event_handler(ol_scn_t scn,
+						      uint8_t *evt_buf,
+						      uint32_t evt_data_len)
+{
+	struct wlan_objmgr_psoc *psoc_obj;
+	struct wlan_objmgr_peer *peer_obj;
+	struct wmi_unified *wmi_hdl;
+	struct wmi_host_twt_session_stats_info twt_params;
+	struct wmi_twt_session_stats_event_param params = {0};
+	struct peer_mc_cp_stats *mc_cp_stats;
+	struct peer_cp_stats *peer_cp_stats_priv;
+	uint32_t expected_len;
+	int i;
+	QDF_STATUS status;
+
+	if (!scn || !evt_buf) {
+		target_if_err("scn: 0x%pK, evt_buf: 0x%pK", scn, evt_buf);
+		return -EINVAL;
+	}
+
+	psoc_obj = target_if_get_psoc_from_scn_hdl(scn);
+	if (!psoc_obj) {
+		target_if_err("psoc object is null!");
+		return -EINVAL;
+	}
+
+	wmi_hdl = get_wmi_unified_hdl_from_psoc(psoc_obj);
+	if (!wmi_hdl) {
+		target_if_err("wmi_handle is null!");
+		return -EINVAL;
+	}
+
+	status = wmi_extract_twt_session_stats_event(wmi_hdl, evt_buf, &params);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		target_if_err("Could not extract twt session stats event");
+		return qdf_status_to_os_return(status);
+	}
+
+	if (params.num_sessions > TWT_PEER_MAX_SESSIONS) {
+		target_if_err("no of twt sessions exceeded the max supported");
+		return -EINVAL;
+	}
+
+	expected_len = (sizeof(wmi_pdev_twt_session_stats_event_fixed_param) +
+			WMI_TLV_HDR_SIZE + (params.num_sessions *
+			sizeof(wmi_twt_session_stats_info)));
+
+	if (evt_data_len < expected_len) {
+		target_if_err("Got invalid len of data from FW %d expected %d",
+			      evt_data_len, expected_len);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < params.num_sessions; i++) {
+		status = wmi_extract_twt_session_stats_data(wmi_hdl, evt_buf,
+							    &params,
+							    &twt_params, i);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			target_if_err("Unable to extract twt params for idx %d",
+				      i);
+			return -EINVAL;
+		}
+
+		peer_obj = wlan_objmgr_get_peer_by_mac(psoc_obj,
+						       twt_params.peer_mac,
+						       WLAN_CP_STATS_ID);
+		if (!peer_obj) {
+			target_if_err("peer obj not found for "
+				      QDF_MAC_ADDR_STR,
+				      QDF_MAC_ADDR_ARRAY(twt_params.peer_mac));
+			continue;
+		}
+
+		peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer_obj);
+		if (!peer_cp_stats_priv) {
+			target_if_err("peer_cp_stats_priv is null");
+			continue;
+		}
+
+		mc_cp_stats = target_if_obtain_mc_cp_stat_obj(peer_obj);
+		if (!mc_cp_stats) {
+			target_if_err("Unable to retrieve mc cp stats obj for "
+				      QDF_MAC_ADDR_STR,
+				      QDF_MAC_ADDR_ARRAY(twt_params.peer_mac));
+			wlan_objmgr_peer_release_ref(peer_obj,
+						     WLAN_CP_STATS_ID);
+			continue;
+		}
+
+		wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv);
+		target_if_twt_fill_peer_twt_session_params(mc_cp_stats,
+							   &twt_params);
+		wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv);
+
+		wlan_objmgr_peer_release_ref(peer_obj, WLAN_CP_STATS_ID);
+	}
+	return 0;
+}
+
+/**
+ * target_if_twt_session_params_unregister_evt_hdlr() - Unregister the
+ * event handler registered for wmi event wmi_twt_session_stats_event_id
+ * @psoc: psoc object
+ *
+ * Return: QDF_STATUS_SUCCESS on success or QDF error values on failure
+ */
+static QDF_STATUS
+target_if_twt_session_params_unregister_evt_hdlr(struct wlan_objmgr_psoc *psoc)
+{
+	struct wmi_unified *wmi_handle;
+
+	if (!psoc) {
+		target_if_err("psoc obj in null!");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		target_if_err("wmi_handle is null!");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	wmi_unified_unregister_event_handler(wmi_handle,
+					     wmi_twt_session_stats_event_id);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * target_if_twt_session_params_register_evt_hdlr() - Register a event
+ * handler with wmi layer for wmi event wmi_twt_session_stats_event_id
+ * @psoc: psoc object
+ *
+ * Return: QDF_STATUS_SUCCESS on success or QDF error values on failure
+ */
+static QDF_STATUS
+target_if_twt_session_params_register_evt_hdlr(struct wlan_objmgr_psoc *psoc)
+{
+	int ret_val;
+	struct wmi_unified *wmi_handle;
+
+	if (!psoc) {
+		target_if_err("psoc obj in null!");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		target_if_err("wmi_handle is null!");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	ret_val = wmi_unified_register_event_handler(
+			wmi_handle,
+			wmi_twt_session_stats_event_id,
+			target_if_twt_session_params_event_handler,
+			WMI_RX_WORK_CTX);
+
+	if (ret_val)
+		target_if_err("Failed to register twt session stats event cb");
+
+	return qdf_status_from_os_return(ret_val);
+}
+#else
+static QDF_STATUS
+target_if_twt_session_params_register_evt_hdlr(struct wlan_objmgr_psoc *psoc)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS
+target_if_twt_session_params_unregister_evt_hdlr(struct wlan_objmgr_psoc *psoc)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif /* WLAN_SUPPORT_TWT */
+
 #ifdef WLAN_FEATURE_MIB_STATS
 static void target_if_cp_stats_free_mib_stats(struct stats_event *ev)
 {
@@ -725,6 +993,48 @@ static QDF_STATUS target_if_cp_stats_send_stats_req(
 					      &param);
 }
 
+/**
+ * target_if_cp_stats_unregister_handlers() - Un-registers wmi event handlers
+ * of control plane stats & twt session stats info
+ * @psoc: PSOC object
+ *
+ * Return: QDF_STATUS_SUCCESS on success or QDF error values on failure
+ */
+static QDF_STATUS
+target_if_cp_stats_unregister_handlers(struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS qdf_status;
+
+	qdf_status = target_if_twt_session_params_unregister_evt_hdlr(psoc);
+	if (qdf_status == QDF_STATUS_SUCCESS)
+		qdf_status = target_if_cp_stats_unregister_event_handler(psoc);
+
+	return qdf_status;
+}
+
+/**
+ * target_if_cp_stats_register_handlers() - Registers wmi event handlers for
+ * control plane stats & twt session stats info
+ * @psoc: PSOC object
+ *
+ * Return: QDF_STATUS_SUCCESS on success or QDF error values on failure
+ */
+static QDF_STATUS
+target_if_cp_stats_register_handlers(struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS qdf_status;
+
+	qdf_status = target_if_cp_stats_register_event_handler(psoc);
+	if (qdf_status != QDF_STATUS_SUCCESS)
+		return qdf_status;
+
+	qdf_status = target_if_twt_session_params_register_evt_hdlr(psoc);
+	if (qdf_status != QDF_STATUS_SUCCESS)
+		target_if_cp_stats_unregister_event_handler(psoc);
+
+	return qdf_status;
+}
+
 QDF_STATUS
 target_if_cp_stats_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
 {
@@ -742,9 +1052,9 @@ target_if_cp_stats_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
 	}
 
 	cp_stats_tx_ops->cp_stats_attach =
-		target_if_cp_stats_register_event_handler;
+		target_if_cp_stats_register_handlers;
 	cp_stats_tx_ops->cp_stats_detach =
-		target_if_cp_stats_unregister_event_handler;
+		target_if_cp_stats_unregister_handlers;
 	cp_stats_tx_ops->inc_wake_lock_stats =
 		target_if_cp_stats_inc_wake_lock_stats;
 	cp_stats_tx_ops->send_req_stats = target_if_cp_stats_send_stats_req;