Browse Source

qcacld-3.0: Add support to query BMISS stats from fw

Currently there is no support to read bmiss stats from fw.
With this change, add support to read bmiss stats from fw.

Change-Id: I77594d05fbcd295aff4c625ba5f4f33cbc491063
CRs-Fixed: 3097304
Divyajyothi Goparaju 3 years ago
parent
commit
df5e68bdef

+ 4 - 0
Kbuild

@@ -412,6 +412,9 @@ endif
 ifeq ($(CONFIG_WLAN_DUMP_IN_PROGRESS), y)
 HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_dump_in_progress.o
 endif
+ifeq ($(CONFIG_WLAN_BMISS), y)
+HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_bmiss.o
+endif
 endif
 ifeq ($(CONFIG_WLAN_SYSFS_DP_STATS), y)
 HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_txrx_stats_console.o
@@ -3128,6 +3131,7 @@ cppflags-$(CONFIG_WLAN_SYSFS_STA_INFO) += -DWLAN_SYSFS_STA_INFO
 cppflags-$(CONFIG_WLAN_DL_MODES) += -DCONFIG_WLAN_DL_MODES
 cppflags-$(CONFIG_WLAN_THERMAL_MULTI_CLIENT_SUPPORT) += -DFEATURE_WPSS_THERMAL_MITIGATION
 cppflags-$(CONFIG_WLAN_DUMP_IN_PROGRESS) += -DCONFIG_WLAN_DUMP_IN_PROGRESS
+cppflags-$(CONFIG_WLAN_BMISS) += -DCONFIG_WLAN_BMISS
 cppflags-$(CONFIG_WLAN_SYSFS_DP_STATS) += -DWLAN_SYSFS_DP_STATS
 
 cppflags-$(CONFIG_WIFI_MONITOR_SUPPORT) += -DWIFI_MONITOR_SUPPORT

+ 37 - 3
components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- *
+ * Copyright (c) 2021 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
@@ -358,7 +358,33 @@ ucfg_mc_cp_get_big_data_fw_support(struct wlan_objmgr_psoc *psoc,
 {}
 #endif
 
-#else
+#ifdef CONFIG_WLAN_BMISS
+/**
+ * wlan_cfg80211_mc_bmiss_get_infra_cp_stats() - API to get bmiss stats
+ * @vdev: pointer to vdev object
+ * @bmiss_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_bmiss_get_infra_cp_stats(
+				struct wlan_objmgr_vdev *vdev,
+				uint8_t bmiss_peer_mac[QDF_MAC_ADDR_SIZE],
+				int *errno);
+#else /* CONFIG_WLAN_BMISS */
+static inline struct infra_cp_stats_event*
+wlan_cfg80211_mc_bmiss_get_infra_cp_stats(
+				struct wlan_objmgr_vdev *vdev,
+				uint8_t bmiss_peer_mac[QDF_MAC_ADDR_SIZE],
+				int *errno)
+{
+	return NULL;
+}
+#endif /* CONFIG_WLAN_BMISS */
+
+#else /* QCA_SUPPORT_CP_STATS */
+
 void static inline ucfg_mc_cp_stats_register_pmo_handler(void) { };
 static inline QDF_STATUS ucfg_mc_cp_stats_send_stats_request(
 				struct wlan_objmgr_vdev *vdev,
@@ -429,6 +455,14 @@ static inline void
 ucfg_mc_cp_big_data_fw_support(struct wlan_objmgr_psoc *psoc,
 			       bool *enable)
 {}
-#endif /* QCA_SUPPORT_CP_STATS */
 
+static inline struct infra_cp_stats_event*
+wlan_cfg80211_mc_bmiss_get_infra_cp_stats(
+				struct wlan_objmgr_vdev *vdev,
+				uint8_t bmiss_peer_mac[QDF_MAC_ADDR_SIZE],
+				int *errno)
+{
+	return NULL;
+}
+#endif /* QCA_SUPPORT_CP_STATS */
 #endif /* __WLAN_CP_STATS_MC_UCFG_API_H__ */

+ 1 - 0
configs/default_defconfig

@@ -332,6 +332,7 @@ endif
 	CONFIG_WLAN_THERMAL_CFG := y
 	CONFIG_WLAN_DL_MODES := y
 	CONFIG_WLAN_DUMP_IN_PROGRESS := y
+	CONFIG_WLAN_BMISS := y
 endif
 
 CONFIG_WLAN_POWER_DEBUG := y

+ 4 - 1
core/hdd/src/wlan_hdd_sysfs.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
- *
+ * Copyright (c) 2021 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
@@ -80,6 +80,7 @@
 #include <wlan_hdd_sysfs_txrx_stats_console.h>
 #include "wma_api.h"
 #include "wlan_hdd_eht.h"
+#include <wlan_hdd_sysfs_bmiss.h>
 
 #define MAX_PSOC_ID_SIZE 10
 
@@ -729,11 +730,13 @@ hdd_sysfs_create_sta_adapter_root_obj(struct hdd_adapter *adapter)
 	hdd_sysfs_range_ext_create(adapter);
 	hdd_sysfs_dl_modes_create(adapter);
 	hdd_sysfs_11be_rate_create(adapter);
+	hdd_sysfs_bmiss_create(adapter);
 }
 
 static void
 hdd_sysfs_destroy_sta_adapter_root_obj(struct hdd_adapter *adapter)
 {
+	hdd_sysfs_bmiss_destroy(adapter);
 	hdd_sysfs_11be_rate_destroy(adapter);
 	hdd_sysfs_dl_modes_destroy(adapter);
 	hdd_sysfs_range_ext_destroy(adapter);

+ 161 - 0
core/hdd/src/wlan_hdd_sysfs_bmiss.c

@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2021 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_hdd_sysfs_bmiss.c
+ *
+ * Implementation for creating sysfs file bmiss
+ */
+
+#include <wlan_hdd_includes.h>
+#include <wlan_hdd_sysfs.h>
+#include "osif_vdev_sync.h"
+#include <wlan_hdd_sysfs_bmiss.h>
+#include <wlan_hdd_stats.h>
+#include <wlan_cp_stats_mc_ucfg_api.h>
+
+static struct infra_cp_stats_event*
+wlan_hdd_get_bmiss(struct hdd_adapter *adapter)
+{
+	struct hdd_station_ctx *hdd_sta_ctx;
+	uint8_t peer_mac[QDF_MAC_ADDR_SIZE];
+	int errno;
+
+	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
+	if (!hdd_sta_ctx) {
+		hdd_debug("hdd_sta_ctx received NULL");
+		return NULL;
+	}
+	qdf_mem_copy(peer_mac, hdd_sta_ctx->conn_info.bssid.bytes,
+		     QDF_MAC_ADDR_SIZE);
+	return wlan_cfg80211_mc_bmiss_get_infra_cp_stats(adapter->vdev,
+							 peer_mac, &errno);
+}
+
+static ssize_t
+__hdd_sysfs_bmiss_show(struct net_device *net_dev, char *buf)
+{
+	struct hdd_adapter *adapter;
+	struct hdd_context *hdd_ctx;
+	struct infra_cp_stats_event *ev_ptr;
+	ssize_t ret = 0;
+	int idx = 0;
+
+	adapter = netdev_priv(net_dev);
+	if (hdd_validate_adapter(adapter))
+		return -EINVAL;
+
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	ret = wlan_hdd_validate_context(hdd_ctx);
+	if (ret)
+		return ret;
+
+	if (!wlan_hdd_validate_modules_state(hdd_ctx))
+		return -EINVAL;
+
+	ev_ptr = wlan_hdd_get_bmiss(adapter);
+	if (!ev_ptr) {
+		hdd_err_rl("GET_BMISS failed");
+		return ret;
+	}
+
+	ret = scnprintf(buf, PAGE_SIZE, "num_pre_bmiss:%u\n",
+			ev_ptr->bmiss_infra_cp_stats->num_pre_bmiss);
+	if (ret <= 0)
+		return ret;
+
+	for (idx = 0; idx < BMISS_STATS_RSSI_SAMPLES_MAX; idx++) {
+		if ((PAGE_SIZE - ret) <= 0)
+			return ret;
+
+		ret += scnprintf(
+			buf + ret, PAGE_SIZE - ret,
+			"rssi_sample%d-rssi:%d\n", idx,
+			ev_ptr->bmiss_infra_cp_stats->rssi_samples[idx].rssi);
+		if ((PAGE_SIZE - ret) <= 0)
+			return ret;
+
+		ret += scnprintf(
+			buf + ret, PAGE_SIZE - ret,
+			"rssi_sample%d-sample_time:%u\n", idx,
+			ev_ptr->bmiss_infra_cp_stats->rssi_samples[idx].sample_time);
+	}
+	if ((PAGE_SIZE - ret) <= 0)
+		return ret;
+
+	ret += scnprintf(buf + ret, PAGE_SIZE - ret,
+			 "rssi_sample_curr_index:%u\n"
+			 "num_first_bmiss:%u\n"
+			 "num_final_bmiss:%u\n"
+			 "num_null_sent_in_first_bmiss:%u\n"
+			 "num_null_failed_in_first_bmiss:%u\n"
+			 "num_null_sent_in_final_bmiss:%u\n"
+			 "num_null_failed_in_final_bmiss:%u\n"
+			 "cons_bmiss_stats.num_of_bmiss_sequences:%u\n"
+			 "cons_bmiss_stats.num_bitmask_wraparound:%u\n"
+			 "cons_bmiss_stats.num_bcn_hist_lost:%u\n",
+			 ev_ptr->bmiss_infra_cp_stats->rssi_sample_curr_index,
+			 ev_ptr->bmiss_infra_cp_stats->num_first_bmiss,
+			 ev_ptr->bmiss_infra_cp_stats->num_final_bmiss,
+			 ev_ptr->bmiss_infra_cp_stats->num_null_sent_in_first_bmiss,
+			 ev_ptr->bmiss_infra_cp_stats->num_null_failed_in_first_bmiss,
+			 ev_ptr->bmiss_infra_cp_stats->num_null_sent_in_final_bmiss,
+			 ev_ptr->bmiss_infra_cp_stats->num_null_failed_in_final_bmiss,
+			 ev_ptr->bmiss_infra_cp_stats->cons_bmiss_stats.num_of_bmiss_sequences,
+			 ev_ptr->bmiss_infra_cp_stats->cons_bmiss_stats.num_bitmask_wraparound,
+			 ev_ptr->bmiss_infra_cp_stats->cons_bmiss_stats.num_bcn_hist_lost);
+
+	qdf_mem_free(ev_ptr->bmiss_infra_cp_stats);
+	qdf_mem_free(ev_ptr);
+	return ret;
+}
+
+static ssize_t
+hdd_sysfs_bmiss_show(struct device *dev, struct device_attribute *attr,
+		     char *buf)
+{
+	struct net_device *net_dev;
+	struct osif_vdev_sync *vdev_sync;
+	ssize_t err_size;
+
+	net_dev = container_of(dev, struct net_device, dev);
+	err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync);
+	if (err_size)
+		return err_size;
+
+	err_size = __hdd_sysfs_bmiss_show(net_dev, buf);
+	osif_vdev_sync_op_stop(vdev_sync);
+	return err_size;
+}
+
+static DEVICE_ATTR(bmiss, 0440, hdd_sysfs_bmiss_show, NULL);
+
+int hdd_sysfs_bmiss_create(struct hdd_adapter *adapter)
+{
+	int error;
+
+	error = device_create_file(&adapter->dev->dev,
+				   &dev_attr_bmiss);
+	if (!error)
+		hdd_err("could not create bmiss sysfs file");
+	return error;
+}
+
+void hdd_sysfs_bmiss_destroy(struct hdd_adapter *adapter)
+{
+	device_remove_file(&adapter->dev->dev, &dev_attr_bmiss);
+}
+

+ 64 - 0
core/hdd/src/wlan_hdd_sysfs_bmiss.h

@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2021 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_hdd_sysfs_bmiss.h
+ *
+ * implementation for creating sysfs file bmiss
+ */
+
+#ifndef _WLAN_HDD_SYSFS_BMISS_H
+#define _WLAN_HDD_SYSFS_BMISS_H
+
+#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_BMISS)
+/**
+ * hdd_sysfs_bmiss_create() - API to create bmiss
+ * @adapter: pointer to adapter
+ *
+ * this file is created per adapter.
+ * file path: /sys/class/net/wlanxx/bmiss
+ * where wlanxx is adapter name
+ *
+ * usage:
+ *      cat /sys/class/net/wlanxx/bmiss
+ *
+ * Return: 0 on success and errno on failure
+ */
+int hdd_sysfs_bmiss_create(struct hdd_adapter *adapter);
+
+/**
+ * hdd_sysfs_bmiss_destroy() - API to destroy bmiss sysfs file
+ * @adapter: pointer to adapter
+ *
+ * Return: none
+ */
+void hdd_sysfs_bmiss_destroy(struct hdd_adapter *adapter);
+#else
+static inline int
+hdd_sysfs_bmiss_create(struct hdd_adapter *adapter)
+{
+	return 0;
+}
+
+static inline void
+hdd_sysfs_bmiss_destroy(struct hdd_adapter *adapter)
+{
+}
+#endif
+#endif /* #ifndef _WLAN_HDD_SYSFS_BMISS_H */
+

+ 244 - 4
os_if/cp_stats/src/wlan_cfg80211_mc_cp_stats.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved.
- *
+ * Copyright (c) 2021 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
@@ -71,6 +71,19 @@ static void wlan_cfg80211_infra_cp_stats_twt_dealloc(void *priv)
 }
 #endif /* WLAN_SUPPORT_TWT */
 
+#ifdef CONFIG_WLAN_BMISS
+static void wlan_cfg80211_infra_cp_stats_bmiss_dealloc(void *priv)
+{
+	struct infra_cp_stats_event *stats = priv;
+
+	qdf_mem_free(stats->bmiss_infra_cp_stats);
+	stats->bmiss_infra_cp_stats = NULL;
+}
+#else /* CONFIG_WLAN_BMISS */
+static void wlan_cfg80211_infra_cp_stats_bmiss_dealloc(void *priv)
+{
+}
+#endif /* CONFIG_WLAN_BMISS */
 /**
  * wlan_cfg80211_mc_infra_cp_stats_dealloc() - callback to free priv
  * allocations for infra cp stats
@@ -88,6 +101,7 @@ void wlan_cfg80211_mc_infra_cp_stats_dealloc(void *priv)
 		return;
 	}
 	wlan_cfg80211_infra_cp_stats_twt_dealloc(priv);
+	wlan_cfg80211_infra_cp_stats_bmiss_dealloc(priv);
 }
 #endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */
 
@@ -636,6 +650,19 @@ wlan_cfg80211_mc_infra_cp_free_twt_stats(struct infra_cp_stats_event *stats)
 }
 #endif /* WLAN_SUPPORT_TWT */
 
+#ifdef CONFIG_WLAN_BMISS
+static void
+wlan_cfg80211_mc_infra_cp_free_bmiss_stats(struct infra_cp_stats_event *stats)
+{
+	qdf_mem_free(stats->bmiss_infra_cp_stats);
+	qdf_mem_free(stats);
+}
+#else /* CONFIG_WLAN_BMISS */
+static void
+wlan_cfg80211_mc_infra_cp_free_bmiss_stats(struct infra_cp_stats_event *stats)
+{
+}
+#endif/* CONFIG_WLAN_BMISS */
 static inline void
 wlan_cfg80211_mc_infra_cp_stats_free_stats_event(
 					struct infra_cp_stats_event *stats)
@@ -643,6 +670,7 @@ wlan_cfg80211_mc_infra_cp_stats_free_stats_event(
 	if (!stats)
 		return;
 	wlan_cfg80211_mc_infra_cp_free_twt_stats(stats);
+	wlan_cfg80211_mc_infra_cp_free_bmiss_stats(stats);
 	qdf_mem_free(stats);
 }
 
@@ -1428,11 +1456,8 @@ wlan_cfg80211_mc_cp_stats_get_peer_stats(struct wlan_objmgr_vdev *vdev,
 	out->peer_adv_stats = priv->peer_adv_stats;
 	priv->peer_adv_stats = NULL;
 	osif_request_put(request);
-
 	osif_debug("Exit");
-
 	return out;
-
 get_peer_stats_fail:
 	osif_request_put(request);
 	wlan_cfg80211_mc_cp_stats_free_stats_event(out);
@@ -1469,3 +1494,218 @@ wlan_cfg80211_mc_cp_stats_free_big_data_stats_event(
 	qdf_mem_free(stats);
 }
 #endif
+
+#ifdef CONFIG_WLAN_BMISS
+static void get_bmiss_infra_cp_stats(struct infra_cp_stats_event *ev,
+				     struct infra_cp_stats_event *priv)
+
+{
+	int idx = 0;
+
+	if (!ev || !ev->bmiss_infra_cp_stats) {
+		osif_err("got bmiss_infra_cp_stats as NULL");
+		return;
+	}
+	priv->bmiss_infra_cp_stats->num_pre_bmiss =
+					ev->bmiss_infra_cp_stats->num_pre_bmiss;
+	for (idx = 0; idx < BMISS_STATS_RSSI_SAMPLES_MAX; idx++) {
+		priv->bmiss_infra_cp_stats->rssi_samples[idx].rssi =
+			ev->bmiss_infra_cp_stats->rssi_samples[idx].rssi;
+		priv->bmiss_infra_cp_stats->rssi_samples[idx].sample_time =
+			ev->bmiss_infra_cp_stats->rssi_samples[idx].sample_time;
+	}
+	priv->bmiss_infra_cp_stats->rssi_sample_curr_index =
+			ev->bmiss_infra_cp_stats->rssi_sample_curr_index;
+	priv->bmiss_infra_cp_stats->num_first_bmiss =
+			ev->bmiss_infra_cp_stats->num_first_bmiss;
+	priv->bmiss_infra_cp_stats->num_final_bmiss =
+			ev->bmiss_infra_cp_stats->num_final_bmiss;
+	priv->bmiss_infra_cp_stats->num_null_sent_in_first_bmiss =
+		ev->bmiss_infra_cp_stats->num_null_sent_in_first_bmiss;
+	priv->bmiss_infra_cp_stats->num_null_failed_in_first_bmiss =
+		ev->bmiss_infra_cp_stats->num_null_failed_in_first_bmiss;
+	priv->bmiss_infra_cp_stats->num_null_sent_in_final_bmiss =
+		ev->bmiss_infra_cp_stats->num_null_sent_in_final_bmiss;
+	priv->bmiss_infra_cp_stats->num_null_failed_in_final_bmiss =
+		ev->bmiss_infra_cp_stats->num_null_failed_in_final_bmiss;
+	priv->bmiss_infra_cp_stats->cons_bmiss_stats.num_of_bmiss_sequences =
+	ev->bmiss_infra_cp_stats->cons_bmiss_stats.num_of_bmiss_sequences;
+	priv->bmiss_infra_cp_stats->cons_bmiss_stats.num_bitmask_wraparound =
+	ev->bmiss_infra_cp_stats->cons_bmiss_stats.num_bitmask_wraparound;
+	priv->bmiss_infra_cp_stats->cons_bmiss_stats.num_bcn_hist_lost =
+	ev->bmiss_infra_cp_stats->cons_bmiss_stats.num_bcn_hist_lost;
+}
+
+/**
+ * infra_cp_stats_bmiss_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_bmiss_response_cb(struct infra_cp_stats_event *ev,
+				      void *cookie)
+{
+	struct infra_cp_stats_event *priv;
+	struct osif_request *request;
+
+	osif_debug("Enter");
+
+	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_bmiss_infra_cp_stats(ev, priv);
+
+	osif_request_complete(request);
+	osif_request_put(request);
+}
+
+#define MAX_BMISS_STAT_VDEV_ENTRIES 1
+#define MAX_BMISS_STAT_MAC_ADDR_ENTRIES 1
+
+struct infra_cp_stats_event *
+wlan_cfg80211_mc_bmiss_get_infra_cp_stats(struct wlan_objmgr_vdev *vdev,
+					  uint8_t *bmiss_peer_mac, int *errno)
+{
+	void *cookie;
+	int idx = 0;
+	QDF_STATUS status;
+	struct infra_cp_stats_event *priv, *out;
+	struct bmiss_infra_cp_stats_event *bmiss_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->bmiss_infra_cp_stats =
+			qdf_mem_malloc(sizeof(*out->bmiss_infra_cp_stats));
+	if (!out->bmiss_infra_cp_stats) {
+		qdf_mem_free(out);
+		*errno = -ENOMEM;
+		return NULL;
+	}
+
+	request = osif_request_alloc(&params);
+	if (!request) {
+		qdf_mem_free(out->bmiss_infra_cp_stats);
+		qdf_mem_free(out);
+		*errno = -ENOMEM;
+		return NULL;
+	}
+
+	cookie = osif_request_cookie(request);
+	priv = osif_request_priv(request);
+
+	priv->bmiss_infra_cp_stats =
+			qdf_mem_malloc(sizeof(*priv->bmiss_infra_cp_stats));
+	if (!priv->bmiss_infra_cp_stats) {
+		qdf_mem_free(out->bmiss_infra_cp_stats);
+		qdf_mem_free(out);
+		*errno = -ENOMEM;
+		return NULL;
+	}
+	bmiss_event = priv->bmiss_infra_cp_stats;
+	info.request_cookie = cookie;
+	info.stats_id = TYPE_REQ_CTRL_PATH_BMISS_STAT;
+	info.action = ACTION_REQ_CTRL_PATH_STAT_GET;
+	info.infra_cp_stats_resp_cb = infra_cp_stats_bmiss_response_cb;
+	info.num_pdev_ids = 0;
+	info.num_vdev_ids = MAX_BMISS_STAT_VDEV_ENTRIES;
+	info.vdev_id[0] = wlan_vdev_get_id(vdev);
+	info.num_mac_addr_list = MAX_TWT_STAT_MAC_ADDR_ENTRIES;
+	info.num_pdev_ids = 0;
+
+	qdf_mem_copy(&info.peer_mac_addr[0], bmiss_peer_mac, QDF_MAC_ADDR_SIZE);
+	peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_CP_STATS_ID);
+	if (!peer) {
+		osif_err("peer is null");
+		*errno = -EINVAL;
+		goto get_bmiss_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_bmiss_stats_fail;
+	}
+
+	status = ucfg_send_infra_cp_stats_request(vdev, &info);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		osif_err("Failed to send bmiss stats request status: %d",
+			 status);
+		*errno = qdf_status_to_os_return(status);
+		goto get_bmiss_stats_fail;
+	}
+
+	*errno = osif_request_wait_for_response(request);
+	if (*errno) {
+		osif_err("wait failed or timed out ret: %d", *errno);
+		goto get_bmiss_stats_fail;
+	}
+
+	out->request_id = priv->request_id;
+	out->bmiss_infra_cp_stats->num_pre_bmiss = bmiss_event->num_pre_bmiss;
+	out->bmiss_infra_cp_stats->num_pre_bmiss =
+					bmiss_event->num_pre_bmiss;
+	for (idx = 0; idx < BMISS_STATS_RSSI_SAMPLES_MAX; idx++) {
+		out->bmiss_infra_cp_stats->rssi_samples[idx].rssi =
+			bmiss_event->rssi_samples[idx].rssi;
+		out->bmiss_infra_cp_stats->rssi_samples[idx].sample_time =
+			bmiss_event->rssi_samples[idx].sample_time;
+	}
+	out->bmiss_infra_cp_stats->rssi_sample_curr_index =
+					bmiss_event->rssi_sample_curr_index;
+	out->bmiss_infra_cp_stats->num_first_bmiss =
+					bmiss_event->num_first_bmiss;
+	out->bmiss_infra_cp_stats->num_null_sent_in_first_bmiss =
+				bmiss_event->num_null_sent_in_first_bmiss;
+	out->bmiss_infra_cp_stats->num_null_failed_in_first_bmiss =
+				bmiss_event->num_null_failed_in_first_bmiss;
+	out->bmiss_infra_cp_stats->num_null_sent_in_final_bmiss =
+				bmiss_event->num_null_sent_in_final_bmiss;
+	out->bmiss_infra_cp_stats->num_null_failed_in_final_bmiss =
+				bmiss_event->num_null_failed_in_final_bmiss;
+	out->bmiss_infra_cp_stats->cons_bmiss_stats.num_of_bmiss_sequences =
+			bmiss_event->cons_bmiss_stats.num_of_bmiss_sequences;
+	out->bmiss_infra_cp_stats->cons_bmiss_stats.num_bitmask_wraparound =
+			bmiss_event->cons_bmiss_stats.num_bitmask_wraparound;
+	out->bmiss_infra_cp_stats->cons_bmiss_stats.num_bcn_hist_lost =
+			bmiss_event->cons_bmiss_stats.num_bcn_hist_lost;
+
+	qdf_mem_copy(&out->bmiss_infra_cp_stats->peer_macaddr, bmiss_peer_mac,
+		     QDF_MAC_ADDR_SIZE);
+	osif_request_put(request);
+	osif_debug("Exit");
+	return out;
+get_bmiss_stats_fail:
+	osif_request_put(request);
+	wlan_cfg80211_mc_infra_cp_stats_free_stats_event(out);
+	osif_debug("Exit");
+	return NULL;
+}
+#endif /* CONFIG_WLAN_BMISS */
+