Browse Source

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
Rajasekaran Kalidoss 4 years ago
parent
commit
744ae542a0

+ 4 - 1
Kbuild

@@ -1940,7 +1940,9 @@ CP_STATS_OBJS := $(CP_MC_STATS_COMPONENT_SRC)/wlan_cp_stats_mc_tgt_api.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		\
-		 $(WLAN_COMMON_ROOT)/target_if/cp_stats/src/target_if_cp_stats.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
 
 ###### DCS ######
@@ -2668,6 +2670,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_CP_STATS) += -DWLAN_SUPPORT_LEGACY_CP_STATS_HANDLERS

+ 5 - 1
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 <wmi_unified_twt_param.h>

+ 20 - 3
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
  */

+ 26 - 3
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
@@ -221,7 +235,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
@@ -250,10 +263,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
  */

+ 62 - 0
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 <wlan_cp_stats_mc_ucfg_api.h>
 #include <wlan_cp_stats_utils_api.h>
 #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 */
+
 #ifdef WLAN_FEATURE_MEDIUM_ASSESS
 static void
 tgt_mc_cp_stats_extract_congestion_stats(struct wlan_objmgr_psoc *psoc,
@@ -1079,6 +1127,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)
 {

+ 243 - 1
core/hdd/src/wlan_hdd_twt.c

@@ -75,6 +75,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] = {
@@ -1366,6 +1371,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
@@ -2352,7 +2376,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;
@@ -2415,6 +2438,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
@@ -2549,6 +2787,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;

+ 250 - 0
os_if/cp_stats/src/wlan_cfg80211_mc_cp_stats.c

@@ -23,6 +23,7 @@
  */
 
 #include <wlan_cfg80211.h>
+#include <wlan_cp_stats_ucfg_api.h>
 #include <wlan_cp_stats_mc_defs.h>
 #include <wlan_cp_stats_mc_ucfg_api.h>
 #include <wlan_cfg80211_mc_cp_stats.h>
@@ -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(&params);
+	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)