qcacld-3.0: Add Host Driver support for Beacon reception stats

Implementation of Host driver support to collect per Vdev Beacon
reception  Stats from firmware and display the stats in sysfs.

	"adb shell cat /sys/class/net/wlan0/beacon_stats"
vdev id: 0
Total Beacon Count: 255
Total Beacon Miss Count: 21
Beacon Miss Bit map [0x800] [0x10000000] [0x22000400] [0x100]
[0x84000000] [0x4030002] [0x5034000] [0x28084]

Change-Id: Iadd31042320f7815a6a6f4733f5393dba93b5b3e
CRs-Fixed: 2360913
diff --git a/Kbuild b/Kbuild
index 46f95d6..4c87eaf 100644
--- a/Kbuild
+++ b/Kbuild
@@ -2048,6 +2048,7 @@
 cppflags-$(CONFIG_QCA_IBSS_SUPPORT) += -DQCA_IBSS_SUPPORT
 cppflags-$(CONFIG_WLAN_SYSFS) += -DWLAN_SYSFS
 cppflags-$(CONFIG_FEATURE_WLAN_RMC) += -DFEATURE_WLAN_RMC
+cppflags-$(CONFIG_FEATURE_BECN_STATS) += -DWLAN_FEATURE_BEACON_RECEPTION_STATS
 
 #Enable OL debug and wmi unified functions
 cppflags-$(CONFIG_ATH_PERF_PWR_OFFLOAD) += -DATH_PERF_PWR_OFFLOAD
diff --git a/configs/default_defconfig b/configs/default_defconfig
index a4efcf3..1fb7e5b 100644
--- a/configs/default_defconfig
+++ b/configs/default_defconfig
@@ -721,3 +721,5 @@
 #Enable STATE MACHINE HISTORY
 CONFIG_SM_ENG_HIST := n
 endif
+#Enable Beacon Reception Stats
+CONFIG_FEATURE_BECN_STATS := y
diff --git a/core/hdd/inc/wlan_hdd_sysfs.h b/core/hdd/inc/wlan_hdd_sysfs.h
index fead7ab..4ee128b 100644
--- a/core/hdd/inc/wlan_hdd_sysfs.h
+++ b/core/hdd/inc/wlan_hdd_sysfs.h
@@ -91,4 +91,31 @@
 {
 }
 #endif
+
+#ifdef WLAN_FEATURE_BEACON_RECEPTION_STATS
+/**
+ * hdd_sysfs_create_adapter_root_obj() - create adapter sysfs entries
+ * @adapter: HDD adapter
+ *
+ * Return: none
+ */
+void hdd_sysfs_create_adapter_root_obj(struct hdd_adapter *adapter);
+/**
+ * hdd_sysfs_destroy_adapter_root_obj() - Destroy adapter sysfs entries
+ * @adapter: HDD adapter
+ *
+ * Return: none
+ */
+void hdd_sysfs_destroy_adapter_root_obj(struct hdd_adapter *adapter);
+#else
+static inline
+void hdd_sysfs_create_adapter_root_obj(struct hdd_adapter *adapter)
+{
+}
+
+static inline
+void hdd_sysfs_destroy_adapter_root_obj(struct hdd_adapter *adapter)
+{
+}
+#endif
 #endif
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index e69147e..6ff9c89 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -4436,6 +4436,8 @@
 	qdf_spinlock_destroy(&adapter->vdev_lock);
 
 	wlan_hdd_debugfs_csr_deinit(adapter);
+	if (adapter->device_mode == QDF_STA_MODE)
+		hdd_sysfs_destroy_adapter_root_obj(adapter);
 
 	hdd_debugfs_exit(adapter);
 
@@ -5105,7 +5107,9 @@
 					WLAN_CONTROL_PATH);
 
 		hdd_nud_init_tracking(adapter);
-
+		if (adapter->device_mode == QDF_STA_MODE ||
+		    adapter->device_mode == QDF_P2P_DEVICE_MODE)
+			hdd_sysfs_create_adapter_root_obj(adapter);
 		qdf_mutex_create(&adapter->disconnection_status_lock);
 
 		break;
diff --git a/core/hdd/src/wlan_hdd_sysfs.c b/core/hdd/src/wlan_hdd_sysfs.c
index 35b09bf..2c8c21d 100644
--- a/core/hdd/src/wlan_hdd_sysfs.c
+++ b/core/hdd/src/wlan_hdd_sysfs.c
@@ -201,7 +201,7 @@
 					   cookie);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		hdd_err("chip power stats request failed");
-		ret_cnt = -EINVAL;
+		ret_cnt = qdf_status_to_os_return(status);
 		goto cleanup;
 	}
 
@@ -258,6 +258,154 @@
 	return ret_val;
 }
 
+#ifdef WLAN_FEATURE_BEACON_RECEPTION_STATS
+struct beacon_reception_stats_priv {
+	struct bcn_reception_stats_rsp beacon_stats;
+};
+
+static void hdd_beacon_debugstats_cb(struct bcn_reception_stats_rsp
+				     *response,
+				     void *context)
+{
+	struct osif_request *request;
+	struct beacon_reception_stats_priv *priv;
+
+	hdd_enter();
+
+	request = osif_request_get(context);
+	if (!request) {
+		hdd_err("Obsolete request");
+		return;
+	}
+
+	priv = osif_request_priv(request);
+
+	/* copy fixed-sized data */
+	priv->beacon_stats = *response;
+
+	osif_request_complete(request);
+	osif_request_put(request);
+	hdd_exit();
+}
+
+static ssize_t __show_beacon_reception_stats(struct device *dev, char *buf)
+{
+	struct net_device *netdev =
+			qdf_container_of(dev, struct net_device, dev);
+	struct hdd_adapter *adapter = (netdev_priv(netdev));
+	struct bcn_reception_stats_rsp *beacon_stats;
+	int ret_val, j;
+	void *cookie;
+	struct osif_request *request;
+	struct beacon_reception_stats_priv *priv;
+	static const struct osif_request_params params = {
+		.priv_size = sizeof(*priv),
+		.timeout_ms = WLAN_WAIT_TIME_STATS,
+	};
+	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+	QDF_STATUS status;
+
+	ret_val = wlan_hdd_validate_context(hdd_ctx);
+	if (ret_val) {
+		hdd_err("hdd ctx is invalid");
+		return ret_val;
+	}
+
+	if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
+		hdd_err("Invalid adapter or adapter has invalid magic");
+		return -EINVAL;
+	}
+
+	if (!test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) {
+		hdd_err("Interface is not enabled");
+		return -EINVAL;
+	}
+
+	if (!(adapter->device_mode == QDF_STA_MODE ||
+	      adapter->device_mode == QDF_P2P_CLIENT_MODE)) {
+		hdd_err("Beacon Reception Stats only supported in STA or P2P CLI modes!");
+		return -ENOTSUPP;
+	}
+
+	if (!hdd_adapter_is_connected_sta(adapter)) {
+		hdd_err("Adapter is not in connected state");
+		return -EINVAL;
+	}
+
+	request = osif_request_alloc(&params);
+	if (!request) {
+		hdd_err("Request allocation failure");
+		return -ENOMEM;
+	}
+	cookie = osif_request_cookie(request);
+
+	status = sme_beacon_debug_stats_req(hdd_ctx->mac_handle,
+					    adapter->session_id,
+					   hdd_beacon_debugstats_cb,
+					   cookie);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("chip power stats request failed");
+		ret_val = -EINVAL;
+		goto cleanup;
+	}
+
+	ret_val = osif_request_wait_for_response(request);
+	if (ret_val) {
+		hdd_err("Target response timed out Power stats");
+		ret_val = -ETIMEDOUT;
+		goto cleanup;
+	}
+	priv = osif_request_priv(request);
+	beacon_stats = &priv->beacon_stats;
+
+	ret_val += scnprintf(buf, PAGE_SIZE,
+			"BEACON RECEPTION STATS\n=================\n"
+			"vdev id: %u\n"
+			"Total Beacon Count: %u\n"
+			"Total Beacon Miss Count: %u\n",
+			beacon_stats->vdev_id,
+			beacon_stats->total_bcn_cnt,
+			beacon_stats->total_bmiss_cnt);
+
+	ret_val += scnprintf(buf + ret_val, PAGE_SIZE - ret_val,
+			     "Beacon Miss Bit map ");
+
+	for (j = 0; j < MAX_BCNMISS_BITMAP; j++) {
+		if ((PAGE_SIZE - ret_val) > 0) {
+			ret_val += scnprintf(buf + ret_val,
+					     PAGE_SIZE - ret_val,
+					     "[0x%x] ",
+					     beacon_stats->bmiss_bitmap[j]);
+		}
+	}
+
+	if ((PAGE_SIZE - ret_val) > 0)
+		ret_val += scnprintf(buf + ret_val,
+				     PAGE_SIZE - ret_val,
+				     "\n");
+cleanup:
+	osif_request_put(request);
+	hdd_exit();
+	return ret_val;
+}
+
+static ssize_t show_beacon_reception_stats(struct device *dev,
+					   struct device_attribute *attr,
+					   char *buf)
+{
+	ssize_t ret_val;
+
+	cds_ssr_protect(__func__);
+	ret_val = __show_beacon_reception_stats(dev, buf);
+	cds_ssr_unprotect(__func__);
+
+	return ret_val;
+}
+
+static DEVICE_ATTR(beacon_stats, 0444,
+		   show_beacon_reception_stats, NULL);
+#endif
+
 static struct kobj_attribute dr_ver_attribute =
 	__ATTR(driver_version, 0440, show_driver_version, NULL);
 static struct kobj_attribute fw_ver_attribute =
@@ -375,3 +523,33 @@
 		driver_kobject = NULL;
 	}
 }
+
+#ifdef WLAN_FEATURE_BEACON_RECEPTION_STATS
+static int hdd_sysfs_create_bcn_reception_interface(struct hdd_adapter
+						     *adapter)
+{
+	int error;
+
+	error = device_create_file(&adapter->dev->dev, &dev_attr_beacon_stats);
+	if (error)
+		hdd_err("could not create beacon stats sysfs file");
+
+	return error;
+}
+
+void hdd_sysfs_create_adapter_root_obj(struct hdd_adapter *adapter)
+{
+	hdd_sysfs_create_bcn_reception_interface(adapter);
+}
+
+static void hdd_sysfs_destroy_bcn_reception_interface(struct hdd_adapter
+						      *adapter)
+{
+	device_remove_file(&adapter->dev->dev, &dev_attr_beacon_stats);
+}
+
+void hdd_sysfs_destroy_adapter_root_obj(struct hdd_adapter *adapter)
+{
+	hdd_sysfs_destroy_bcn_reception_interface(adapter);
+}
+#endif
diff --git a/core/mac/inc/ani_global.h b/core/mac/inc/ani_global.h
index 4a4b0cb..d5565a5 100644
--- a/core/mac/inc/ani_global.h
+++ b/core/mac/inc/ani_global.h
@@ -882,6 +882,7 @@
 	tDot11fIEhe_cap he_cap_5g;
 #endif
 	bool obss_scan_offload;
+	bool bcn_reception_stats;
 };
 
 #ifdef FEATURE_WLAN_TDLS
diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h
index 78ad6cd..208ef60 100644
--- a/core/mac/inc/sir_api.h
+++ b/core/mac/inc/sir_api.h
@@ -3912,6 +3912,26 @@
 };
 #endif
 
+#ifdef WLAN_FEATURE_BEACON_RECEPTION_STATS
+#define MAX_BCNMISS_BITMAP 8
+/**
+ * struct bcn_reception_stats_rsp - beacon stats response
+ * @total_bcn_cnt: total beacon count (tbtt instances)
+ * @total_bmiss_cnt: Total beacon miss count in last 255 beacons, max 255
+ * @bmiss_bitmap: This bitmap indicates the status of the last 255 beacons.
+ * If a bit is set, that means the corresponding beacon was missed.
+ * Bit 0 of bmiss_bitmap[0] represents the most recent beacon.
+ * The total_bcn_cnt field indicates how many bits within bmiss_bitmap
+ * are valid.
+ */
+struct bcn_reception_stats_rsp {
+	uint32_t vdev_id;
+	uint32_t total_bcn_cnt;
+	uint32_t total_bmiss_cnt;
+	uint32_t bmiss_bitmap[MAX_BCNMISS_BITMAP];
+};
+#endif
+
 /**
  * struct lfr_firmware_status - LFR status in firmware
  * @is_disabled: Is LFR disabled in FW
diff --git a/core/mac/src/include/sir_params.h b/core/mac/src/include/sir_params.h
index e4453f4..1393550 100644
--- a/core/mac/src/include/sir_params.h
+++ b/core/mac/src/include/sir_params.h
@@ -695,6 +695,7 @@
 #define SIR_HAL_SEND_AP_VDEV_UP             (SIR_HAL_ITC_MSG_TYPES_BEGIN + 400)
 #define SIR_HAL_SEND_BCN_RSP                (SIR_HAL_ITC_MSG_TYPES_BEGIN + 401)
 #define SIR_HAL_CFG_VENDOR_ACTION_TB_PPDU   (SIR_HAL_ITC_MSG_TYPES_BEGIN + 402)
+#define SIR_HAL_BEACON_DEBUG_STATS_REQ       (SIR_HAL_ITC_MSG_TYPES_BEGIN + 403)
 #define SIR_HAL_MSG_TYPES_END               (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF)
 
 /* CFG message types */
diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h
index 684cffa..0e519fb 100644
--- a/core/sme/inc/sme_api.h
+++ b/core/sme/inc/sme_api.h
@@ -1966,6 +1966,22 @@
 		void *power_stats_context);
 #endif
 
+#ifdef WLAN_FEATURE_BEACON_RECEPTION_STATS
+/**
+ * sme_beacon_debug_stats_req() - SME API to collect beacon debug stats
+ * @vdev_id: Vdev id on which stats is being requested
+ * @callback_fn: Pointer to the callback function for beacon stats event
+ * @beacon_stats_context: Pointer to context
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS sme_beacon_debug_stats_req(
+		mac_handle_t mac_handle, uint32_t vdev_id,
+		void (*callback_fn)(struct bcn_reception_stats_rsp
+				    *response, void *context),
+		void *beacon_stats_context);
+#endif
+
 /**
  * sme_get_sar_power_limits() - get SAR limits
  * @mac_handle: Opaque handle to the global MAC context
diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h
index e0c35db..0653709 100644
--- a/core/sme/inc/sme_internal.h
+++ b/core/sme/inc/sme_internal.h
@@ -262,6 +262,11 @@
 	void (*power_stats_resp_callback)(struct power_stats_response *rsp,
 						void *callback_context);
 #endif
+#ifdef WLAN_FEATURE_BEACON_RECEPTION_STATS
+	void *beacon_stats_context;
+	void (*beacon_stats_resp_callback)(struct bcn_reception_stats_rsp *rsp,
+					   void *callback_context);
+#endif
 #ifdef FEATURE_WLAN_AUTO_SHUTDOWN
 	void (*pAutoShutdownNotificationCb)(void);
 #endif
diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c
index fa3520d..5ea52dd 100644
--- a/core/sme/src/common/sme_api.c
+++ b/core/sme/src/common/sme_api.c
@@ -11904,6 +11904,56 @@
 }
 #endif
 
+#ifdef WLAN_FEATURE_BEACON_RECEPTION_STATS
+QDF_STATUS sme_beacon_debug_stats_req(
+		mac_handle_t mac_handle, uint32_t vdev_id,
+		void (*callback_fn)(struct bcn_reception_stats_rsp
+				    *response, void *context),
+		void *beacon_stats_context)
+{
+	QDF_STATUS status;
+	struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle);
+	uint32_t *val;
+	struct scheduler_msg msg = {0};
+
+	status = sme_acquire_global_lock(&mac_ctx->sme);
+	if (QDF_IS_STATUS_SUCCESS(status)) {
+		if (!callback_fn) {
+			sme_err("Indication callback did not registered");
+			sme_release_global_lock(&mac_ctx->sme);
+			return QDF_STATUS_E_FAILURE;
+		}
+
+		if (!mac_ctx->bcn_reception_stats) {
+			sme_err("Beacon Reception stats not supported by FW");
+			sme_release_global_lock(&mac_ctx->sme);
+			return QDF_STATUS_E_NOSUPPORT;
+		}
+
+		val = qdf_mem_malloc(sizeof(*val));
+		if (!val) {
+			sme_release_global_lock(&mac_ctx->sme);
+			return QDF_STATUS_E_NOMEM;
+		}
+
+		*val = vdev_id;
+		mac_ctx->sme.beacon_stats_context = beacon_stats_context;
+		mac_ctx->sme.beacon_stats_resp_callback = callback_fn;
+		msg.bodyptr = val;
+		msg.type = WMA_BEACON_DEBUG_STATS_REQ;
+		status = scheduler_post_message(QDF_MODULE_ID_SME,
+						QDF_MODULE_ID_WMA,
+						QDF_MODULE_ID_WMA, &msg);
+		if (!QDF_IS_STATUS_SUCCESS(status)) {
+			sme_err("not able to post WMA_BEACON_DEBUG_STATS_REQ");
+			qdf_mem_free(val);
+		}
+		sme_release_global_lock(&mac_ctx->sme);
+	}
+	return status;
+}
+#endif
+
 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
 /**
  * sme_update_roam_key_mgmt_offload_enabled() - enable/disable key mgmt offload
@@ -13794,6 +13844,7 @@
 	sme_debug("pmf_offload: %d fils_roam support %d 11k_offload %d",
 		  mac_ctx->pmf_offload, mac_ctx->is_fils_roaming_supported,
 		  mac_ctx->is_11k_offload_supported);
+	mac_ctx->bcn_reception_stats = cfg->bcn_reception_stats;
 }
 
 /**
diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h
index b94e3dd..a0324c4 100644
--- a/core/wma/inc/wma_internal.h
+++ b/core/wma/inc/wma_internal.h
@@ -1285,6 +1285,17 @@
 				int32_t rssi);
 int wma_unified_power_debug_stats_event_handler(void *handle,
 			uint8_t *cmd_param_info, uint32_t len);
+/**
+ * wma_unified_beacon_debug_stats_event_handler() - collect beacon debug stats
+ * @handle: WMA handle
+ * @cmd_param_info: data from event
+ * @len: length
+ *
+ * Return: 0 for success or error code
+ */
+int wma_unified_beacon_debug_stats_event_handler(void *handle,
+						 uint8_t *cmd_param_info,
+						 uint32_t len);
 
 #ifdef FEATURE_WLAN_DIAG_SUPPORT
 /**
diff --git a/core/wma/inc/wma_tgt_cfg.h b/core/wma/inc/wma_tgt_cfg.h
index f5b4218..9d809e0 100644
--- a/core/wma/inc/wma_tgt_cfg.h
+++ b/core/wma/inc/wma_tgt_cfg.h
@@ -41,6 +41,7 @@
  * @is_fw_mawc_capable: Motion Aided Wireless Connectivity feature
  * @twt_requestor: TWT requestor capability
  * @twt_responder: TWT responder capability
+ * @bcn_reception_stats: Beacon Reception stats capability
  */
 struct wma_tgt_services {
 	uint32_t sta_power_save;
@@ -72,6 +73,7 @@
 	bool twt_requestor;
 	bool twt_responder;
 	bool obss_scan_offload;
+	bool bcn_reception_stats;
 };
 
 /**
diff --git a/core/wma/inc/wma_types.h b/core/wma/inc/wma_types.h
index a8b9d45..f340455 100644
--- a/core/wma/inc/wma_types.h
+++ b/core/wma/inc/wma_types.h
@@ -435,6 +435,7 @@
 #define WMA_UPDATE_WEP_DEFAULT_KEY           SIR_HAL_UPDATE_WEP_DEFAULT_KEY
 #define WMA_SEND_FREQ_RANGE_CONTROL_IND      SIR_HAL_SEND_FREQ_RANGE_CONTROL_IND
 #define WMA_POWER_DEBUG_STATS_REQ            SIR_HAL_POWER_DEBUG_STATS_REQ
+#define WMA_BEACON_DEBUG_STATS_REQ           SIR_HAL_BEACON_DEBUG_STATS_REQ
 #define WMA_GET_RCPI_REQ                     SIR_HAL_GET_RCPI_REQ
 
 #define WMA_SET_DBS_SCAN_SEL_CONF_PARAMS     SIR_HAL_SET_DBS_SCAN_SEL_PARAMS
diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c
index 31373b3..2fd8da6 100644
--- a/core/wma/src/wma_features.c
+++ b/core/wma/src/wma_features.c
@@ -5376,6 +5376,66 @@
 	return 0;
 }
 #endif
+#ifdef WLAN_FEATURE_BEACON_RECEPTION_STATS
+int wma_unified_beacon_debug_stats_event_handler(void *handle,
+						 uint8_t *cmd_param_info,
+						 uint32_t len)
+{
+	WMI_VDEV_BCN_RECEPTION_STATS_EVENTID_param_tlvs *param_tlvs;
+	struct bcn_reception_stats_rsp *bcn_reception_stats;
+	wmi_vdev_bcn_recv_stats_fixed_param *param_buf;
+	struct mac_context *mac =
+			(struct mac_context *)cds_get_context(QDF_MODULE_ID_PE);
+
+	param_tlvs =
+	   (WMI_VDEV_BCN_RECEPTION_STATS_EVENTID_param_tlvs *)cmd_param_info;
+	if (!param_tlvs) {
+		WMA_LOGA("%s: Invalid stats event", __func__);
+		return -EINVAL;
+	}
+
+	param_buf = (wmi_vdev_bcn_recv_stats_fixed_param *)
+		param_tlvs->fixed_param;
+	if (!param_buf || !mac || !mac->sme.beacon_stats_resp_callback) {
+		WMA_LOGD("%s: NULL mac ptr or HDD callback is null", __func__);
+		return -EINVAL;
+	}
+
+	if (!param_buf) {
+		WMA_LOGD("%s: NULL beacon stats event fixed param", __func__);
+		return -EINVAL;
+	}
+
+	bcn_reception_stats = qdf_mem_malloc(sizeof(*bcn_reception_stats));
+	if (!bcn_reception_stats)
+		return -ENOMEM;
+
+	bcn_reception_stats->total_bcn_cnt = param_buf->total_bcn_cnt;
+	bcn_reception_stats->total_bmiss_cnt = param_buf->total_bmiss_cnt;
+	bcn_reception_stats->vdev_id = param_buf->vdev_id;
+
+	WMA_LOGD("Total beacon count %d total beacon miss count %d vdev_id %d",
+		 param_buf->total_bcn_cnt,
+		 param_buf->total_bmiss_cnt,
+		 param_buf->vdev_id);
+
+	qdf_mem_copy(bcn_reception_stats->bmiss_bitmap,
+		     param_buf->bmiss_bitmap,
+		     MAX_BCNMISS_BITMAP * sizeof(uint32_t));
+
+	mac->sme.beacon_stats_resp_callback(bcn_reception_stats,
+			mac->sme.beacon_stats_context);
+	qdf_mem_free(bcn_reception_stats);
+	return 0;
+}
+#else
+int wma_unified_beacon_debug_stats_event_handler(void *handle,
+						 uint8_t *cmd_param_info,
+						  uint32_t len)
+{
+	return 0;
+}
+#endif
 
 int wma_chan_info_event_handler(void *handle, uint8_t *event_buf,
 				uint32_t len)
diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c
index 5049548..a10fc9b 100644
--- a/core/wma/src/wma_main.c
+++ b/core/wma/src/wma_main.c
@@ -3471,6 +3471,13 @@
 				wma_unified_power_debug_stats_event_handler,
 				WMA_RX_SERIALIZER_CTX);
 #endif
+#ifdef WLAN_FEATURE_BEACON_RECEPTION_STATS
+	/* register for beacon stats event */
+	wmi_unified_register_event_handler(wma_handle->wmi_handle,
+				wmi_vdev_bcn_reception_stats_event_id,
+				wma_unified_beacon_debug_stats_event_handler,
+				WMA_RX_SERIALIZER_CTX);
+#endif
 
 	/* register for linkspeed response event */
 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
@@ -4996,6 +5003,8 @@
 		cfg->twt_responder = true;
 	if (wmi_service_enabled(wmi_handle, wmi_service_obss_scan))
 		cfg->obss_scan_offload = true;
+	if (wmi_service_enabled(wmi_handle, wmi_service_beacon_reception_stats))
+		cfg->bcn_reception_stats = true;
 }
 
 /**
@@ -7498,6 +7507,55 @@
 	return QDF_STATUS_SUCCESS;
 }
 #endif
+#ifdef WLAN_FEATURE_BEACON_RECEPTION_STATS
+static QDF_STATUS wma_process_beacon_debug_stats_req(tp_wma_handle wma_handle,
+						     uint32_t *vdev_id)
+{
+	wmi_vdev_get_bcn_recv_stats_cmd_fixed_param *cmd;
+	int32_t len;
+	wmi_buf_t buf;
+	uint8_t *buf_ptr;
+	int ret;
+
+	WMA_LOGD("%s: Enter", __func__);
+	if (!wma_handle) {
+		WMA_LOGE("%s: input pointer is NULL", __func__);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	len = sizeof(*cmd);
+	buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
+	if (!buf)
+		return QDF_STATUS_E_NOMEM;
+
+	buf_ptr = (u_int8_t *)wmi_buf_data(buf);
+	cmd = (wmi_vdev_get_bcn_recv_stats_cmd_fixed_param *)buf_ptr;
+
+	WMITLV_SET_HDR(&cmd->tlv_header,
+		WMITLV_TAG_STRUC_wmi_get_bcn_recv_stats_fixed_param,
+		WMITLV_GET_STRUCT_TLVLEN(
+			wmi_vdev_get_bcn_recv_stats_cmd_fixed_param));
+	cmd->vdev_id = *vdev_id;
+
+	WMA_LOGD("BEACON_DEBUG_STATS - Get Request Params; vdev id - %d",
+		 cmd->vdev_id);
+	ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
+				   WMI_VDEV_GET_BCN_RECEPTION_STATS_CMDID);
+	if (ret) {
+		wmi_buf_free(buf);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	WMA_LOGD("%s: Exit", __func__);
+	return QDF_STATUS_SUCCESS;
+}
+#else
+static QDF_STATUS wma_process_beacon_debug_stats_req(tp_wma_handle wma_handle,
+						     uint32_t *vdev_id)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
 
 /**
  * wma_set_arp_req_stats() - process set arp stats request command to fw
@@ -8573,6 +8631,10 @@
 	case SIR_HAL_POWER_DEBUG_STATS_REQ:
 		wma_process_power_debug_stats_req(wma_handle);
 		break;
+	case WMA_BEACON_DEBUG_STATS_REQ:
+		wma_process_beacon_debug_stats_req(wma_handle, msg->bodyptr);
+		qdf_mem_free(msg->bodyptr);
+		break;
 	case WMA_GET_RCPI_REQ:
 		wma_get_rcpi_req(wma_handle,
 				 (struct sme_rcpi_req *)msg->bodyptr);