瀏覽代碼

Merge e151bf3d8be0cfed112b1793339e1cf5d7617934 on remote branch

Change-Id: I90caabaf6d32f25f032227e30b93174de611f6b5
Linux Build Service Account 1 年之前
父節點
當前提交
28b8a138f2
共有 62 個文件被更改,包括 2706 次插入110 次删除
  1. 4 0
      Kconfig
  2. 28 0
      components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h
  3. 6 24
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c
  4. 34 0
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c
  5. 14 1
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h
  6. 4 1
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_init_deinit.c
  7. 2 2
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c
  8. 3 3
      components/mlme/dispatcher/inc/cfg_mlme_generic.h
  9. 39 1
      components/nan/core/inc/wlan_nan_api.h
  10. 55 1
      components/nan/core/src/nan_api.c
  11. 4 1
      components/nan/core/src/nan_main.c
  12. 19 1
      components/tdls/core/src/wlan_tdls_cmds_process.c
  13. 10 1
      components/tdls/dispatcher/inc/wlan_tdls_api.h
  14. 45 0
      components/tdls/dispatcher/src/wlan_tdls_api.c
  15. 7 5
      components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_fw_sync.c
  16. 17 1
      components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c
  17. 67 0
      components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_connect.c
  18. 62 1
      components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_disconnect.c
  19. 1 0
      components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h
  20. 156 4
      components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c
  21. 4 0
      configs/config_to_feature.h
  22. 1 0
      configs/pineapple_gki_kiwi-v2_defconfig
  23. 16 0
      core/cds/src/cds_api.c
  24. 2 0
      core/hdd/inc/wlan_hdd_main.h
  25. 1 1
      core/hdd/src/wlan_hdd_assoc.c
  26. 0 6
      core/hdd/src/wlan_hdd_cfg.c
  27. 82 0
      core/hdd/src/wlan_hdd_cfg80211.c
  28. 23 1
      core/hdd/src/wlan_hdd_cfg80211.h
  29. 7 1
      core/hdd/src/wlan_hdd_cm_connect.c
  30. 32 1
      core/hdd/src/wlan_hdd_cm_disconnect.c
  31. 232 1
      core/hdd/src/wlan_hdd_hostapd.c
  32. 96 1
      core/hdd/src/wlan_hdd_hostapd.h
  33. 8 0
      core/hdd/src/wlan_hdd_ioctl.c
  34. 18 0
      core/hdd/src/wlan_hdd_main.c
  35. 8 1
      core/hdd/src/wlan_hdd_nan_datapath.c
  36. 153 0
      core/hdd/src/wlan_hdd_stats.c
  37. 86 0
      core/hdd/src/wlan_hdd_stats.h
  38. 8 1
      core/hdd/src/wlan_hdd_tx_power.c
  39. 3 3
      core/mac/inc/qwlan_version.h
  40. 7 7
      core/mac/src/pe/lim/lim_ft.c
  41. 16 0
      core/mac/src/pe/lim/lim_process_assoc_req_frame.c
  42. 16 0
      core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c
  43. 10 0
      core/mac/src/pe/lim/lim_process_auth_frame.c
  44. 3 0
      core/mac/src/pe/lim/lim_process_deauth_frame.c
  45. 3 0
      core/mac/src/pe/lim/lim_process_disassoc_frame.c
  46. 12 0
      core/mac/src/pe/lim/lim_process_tdls.c
  47. 23 28
      core/mac/src/pe/lim/lim_prop_exts_utils.c
  48. 19 1
      core/mac/src/pe/lim/lim_prop_exts_utils.h
  49. 10 1
      core/mac/src/pe/lim/lim_send_frames_host_roam.c
  50. 26 0
      core/mac/src/pe/lim/lim_send_management_frames.c
  51. 1 1
      core/mac/src/pe/lim/lim_send_sme_rsp_messages.c
  52. 352 0
      core/mac/src/pe/lim/lim_utils.c
  53. 234 0
      core/mac/src/pe/lim/lim_utils.h
  54. 16 1
      core/pld/inc/pld_common.h
  55. 21 1
      core/pld/src/pld_common.c
  56. 27 1
      core/pld/src/pld_pcie.h
  57. 9 2
      core/sme/src/common/sme_api.c
  58. 5 0
      core/wma/src/wma_features.c
  59. 3 1
      core/wma/src/wma_mgmt.c
  60. 222 1
      os_if/nan/inc/os_if_nan.h
  61. 309 1
      os_if/nan/src/os_if_nan.c
  62. 5 0
      wlan_qcacld3_modules.bzl

+ 4 - 0
Kconfig

@@ -1879,6 +1879,10 @@ config DYNAMIC_DEBUG
 	bool "enable CONFIG_DYNAMIC_DEBUG"
 	default n
 
+config WLAN_CHIPSET_STATS
+	bool "enable WLAN_CHIPSET_STATS"
+	default n
+
 config DP_MLO_LINK_STATS_SUPPORT
 	bool "enable CONFIG_DP_MLO_LINK_STATS_SUPPORT"
 	default n

+ 28 - 0
components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h

@@ -367,6 +367,30 @@ QDF_STATUS
 policy_mgr_get_dfs_sta_sap_go_scc_movement(struct wlan_objmgr_psoc *psoc,
 					   bool *move_sap_go_first);
 
+ /**
+  * policy_mgr_nss_update_cb() - callback from SME confirming nss
+  * update
+  * @psoc: psoc handle
+  * @tx_status: tx completion status for updated beacon with new
+  *              nss value
+  * @vdev_id: vdev id for the specific connection
+  * @next_action: next action to happen at policy mgr after
+  *              beacon update
+  * @reason: Reason for nss update
+  * @original_vdev_id: original request hwmode change vdev id
+  * @request_id: request ID
+  *
+  * This function is the callback registered with SME at nss
+  * update request time
+  *
+  * Return: None
+  */
+
+void policy_mgr_nss_update_cb(struct wlan_objmgr_psoc *psoc,
+			      uint8_t tx_status, uint8_t vdev_id,
+			      uint8_t next_action,
+			      enum policy_mgr_conn_update_reason reason,
+			      uint32_t original_vdev_id, uint32_t request_id);
 /*
  * policy_mgr_get_connected_vdev_band_mask() - to get the connected vdev band
  * mask
@@ -2197,6 +2221,7 @@ struct policy_mgr_sme_cbacks {
  *  based on target channel frequency and concurrent connections.
  * @wlan_get_sap_acs_band: get acs band from sap config
  * @wlan_check_cc_intf_cb: get interference frequency of input SAP/GO interface
+ * @wlan_set_tx_rx_nss_cb: set NSS dynamically for STA
  */
 struct policy_mgr_hdd_cbacks {
 	QDF_STATUS (*sap_restart_chan_switch_cb)(struct wlan_objmgr_psoc *psoc,
@@ -2228,6 +2253,9 @@ struct policy_mgr_hdd_cbacks {
 	QDF_STATUS (*wlan_check_cc_intf_cb)(struct wlan_objmgr_psoc *psoc,
 					    uint8_t vdev_id,
 					    uint32_t *ch_freq);
+	QDF_STATUS (*wlan_set_tx_rx_nss_cb)(struct wlan_objmgr_psoc *psoc,
+					    uint8_t vdev_id, uint8_t tx_nss,
+					    uint8_t rx_nss);
 };
 
 /**

+ 6 - 24
components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c

@@ -4633,30 +4633,12 @@ void policy_mgr_check_scc_channel(struct wlan_objmgr_psoc *psoc,
 	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
 }
 
-/**
- * policy_mgr_nss_update_cb() - callback from SME confirming nss
- * update
- * @psoc: psoc handle
- * @tx_status: tx completion status for updated beacon with new
- *		nss value
- * @vdev_id: vdev id for the specific connection
- * @next_action: next action to happen at policy mgr after
- *		beacon update
- * @reason: Reason for nss update
- * @original_vdev_id: original request hwmode change vdev id
- * @request_id: request ID
- *
- * This function is the callback registered with SME at nss
- * update request time
- *
- * Return: None
- */
-static void policy_mgr_nss_update_cb(struct wlan_objmgr_psoc *psoc,
-		uint8_t tx_status,
-		uint8_t vdev_id,
-		uint8_t next_action,
-		enum policy_mgr_conn_update_reason reason,
-		uint32_t original_vdev_id, uint32_t request_id)
+void policy_mgr_nss_update_cb(struct wlan_objmgr_psoc *psoc,
+			      uint8_t tx_status,
+			      uint8_t vdev_id,
+			      uint8_t next_action,
+			      enum policy_mgr_conn_update_reason reason,
+			      uint32_t original_vdev_id, uint32_t request_id)
 {
 	uint32_t conn_index = 0;
 	QDF_STATUS ret;

+ 34 - 0
components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c

@@ -752,6 +752,21 @@ static void policy_mgr_get_hw_mode_params(
 	}
 }
 
+QDF_STATUS policy_mgr_update_nss_req(struct wlan_objmgr_psoc *psoc,
+				     uint8_t vdev_id, uint8_t tx_nss,
+				     uint8_t rx_nss)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+	return pm_ctx->hdd_cbacks.wlan_set_tx_rx_nss_cb(psoc, vdev_id,
+							tx_nss, rx_nss);
+}
+
 /**
  * policy_mgr_set_hw_mode_params() - sets TX-RX stream,
  * bandwidth and DBS in hw_mode_list
@@ -11290,6 +11305,25 @@ bool policy_mgr_is_sap_allowed_on_dfs_freq(struct wlan_objmgr_pdev *pdev,
 		return false;
 	}
 
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+						    vdev_id,
+						    WLAN_POLICY_MGR_ID);
+	if (!vdev) {
+		policy_mgr_err("Invalid vdev");
+		return false;
+	}
+	/* Allow the current CSA to continue if it's already started. This is
+	 * possible when SAP CSA started to move to STA channel but STA got
+	 * disconnected.
+	 */
+	if (!wlan_vdev_mlme_is_init_state(vdev) &&
+	    !wlan_vdev_is_up_active_state(vdev)) {
+		policy_mgr_debug("SAP is not yet UP: vdev %d", vdev_id);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID);
+		return true;
+	}
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID);
+
 	/*
 	 * Check if any of the concurrent STA/ML-STA link/P2P client are in
 	 * disconnecting state and disallow current SAP CSA. Concurrencies

+ 14 - 1
components/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 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
@@ -1032,6 +1032,19 @@ void policy_mgr_reg_chan_change_callback(struct wlan_objmgr_psoc *psoc,
 		struct avoid_freq_ind_data *avoid_freq_ind,
 		void *arg);
 
+/**
+ * policy_mgr_update_nss_req() - wrapper API to update nss
+ * @psoc: psoc object
+ * @vdev_id: vdev id
+ * @tx_nss: Tx nss to set
+ * @rx_nss: Rx nss to set
+ *
+ * Return: QDF_STATUS_SUCCESS
+ */
+QDF_STATUS policy_mgr_update_nss_req(struct wlan_objmgr_psoc *psoc,
+				     uint8_t vdev_id, uint8_t tx_nss,
+				     uint8_t rx_nss);
+
 /**
  * policy_mgr_nss_update() - update nss for AP vdev
  * @psoc: PSOC object information

+ 4 - 1
components/cmn_services/policy_mgr/src/wlan_policy_mgr_init_deinit.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 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
@@ -847,6 +847,8 @@ QDF_STATUS policy_mgr_register_hdd_cb(struct wlan_objmgr_psoc *psoc,
 		hdd_cbacks->wlan_get_sap_acs_band;
 	pm_ctx->hdd_cbacks.wlan_check_cc_intf_cb =
 		hdd_cbacks->wlan_check_cc_intf_cb;
+	pm_ctx->hdd_cbacks.wlan_set_tx_rx_nss_cb =
+		hdd_cbacks->wlan_set_tx_rx_nss_cb;
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -870,6 +872,7 @@ QDF_STATUS policy_mgr_deregister_hdd_cb(struct wlan_objmgr_psoc *psoc)
 	pm_ctx->hdd_cbacks.hdd_get_ap_6ghz_capable = NULL;
 	pm_ctx->hdd_cbacks.wlan_get_ap_prefer_conc_ch_params = NULL;
 	pm_ctx->hdd_cbacks.wlan_get_sap_acs_band = NULL;
+	pm_ctx->hdd_cbacks.wlan_set_tx_rx_nss_cb = NULL;
 
 	return QDF_STATUS_SUCCESS;
 }

+ 2 - 2
components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 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
@@ -1571,7 +1571,7 @@ static QDF_STATUS policy_mgr_pcl_modification_for_ll_lt_sap(
 	uint32_t pcl_list[NUM_CHANNELS], orig_len = *len;
 	uint8_t weight_list[NUM_CHANNELS];
 	uint32_t i, pcl_len = 0;
-	bool sbs_mac0_modified_pcl;
+	bool sbs_mac0_modified_pcl = false;
 
 	pm_ctx = policy_mgr_get_context(psoc);
 	if (!pm_ctx) {

+ 3 - 3
components/mlme/dispatcher/inc/cfg_mlme_generic.h

@@ -240,17 +240,17 @@ enum wlan_epcs_frame {
  * options using bitmap based on following ENUM (Name of ENUM to be added)
  * @Min: 0x0
  * @Max: 0xFFFFFFFF
- * @Default: 0x0
+ * @Default: 0x20008 - To allow MLO WPA2-PMF cap APs and WPA3-SAE w/o H2E cap
  *
  * This INI is used to control the driver candidate selection and EHT
  * connection choice based on OEM configuration. The bitmap follows the
- * implementation from this ENUM (name of the ENUM to be added)
+ * implementation from wlan_crypto_oem_eht_mlo_config enum
  */
 #define CFG_OEM_EHT_MLO_CRYPTO_BITMAP CFG_INI_UINT( \
 		"oem_eht_mlo_crypto_bitmap", \
 		0x0, \
 		0xFFFFFFFF, \
-		0x0, \
+		0x20008, \
 		CFG_VALUE_OR_DEFAULT, \
 		"OEM control to allow/disallow crypto to EHT configuration")
 

+ 39 - 1
components/nan/core/inc/wlan_nan_api.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2024 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
@@ -27,6 +27,8 @@
 #include "wlan_objmgr_peer_obj.h"
 #include "wlan_policy_mgr_public_struct.h"
 #include "qdf_status.h"
+#include <nan_public_structs.h>
+#include <wlan_cp_stats_chipset_stats.h>
 
 #ifdef WLAN_FEATURE_NAN
 
@@ -317,4 +319,40 @@ wlan_is_mlo_sta_nan_ndi_allowed(struct wlan_objmgr_psoc *psoc)
 	return false;
 }
 #endif
+
+#if defined(WLAN_FEATURE_NAN) && defined(WLAN_CHIPSET_STATS)
+/**
+ * nan_cstats_log_nan_enable_resp_evt() - Chipset stats NAN enable
+ * response event
+ *
+ * @nan_event: pointer to nan_event_params object
+ *
+ * Return: void
+ */
+void nan_cstats_log_nan_enable_resp_evt(struct nan_event_params *nan_event);
+
+/**
+ * nan_cstats_log_nan_disable_resp_evt() - Chipset stats NAN disable
+ * response event
+ *
+ * @vdev_id: vdev ID
+ * @psoc: pointer to psoc object
+ *
+ * Return: void
+ */
+void
+nan_cstats_log_nan_disable_resp_evt(uint8_t vdev_id,
+				    struct wlan_objmgr_psoc *psoc);
+#else
+static inline void
+nan_cstats_log_nan_enable_resp_evt(struct nan_event_params *nan_event)
+{
+}
+
+static inline void
+nan_cstats_log_nan_disable_resp_evt(uint8_t vdev_id,
+				    struct wlan_objmgr_psoc *psoc)
+{
+}
+#endif /* WLAN_FEATURE_NAN && WLAN_CHIPSET_STATS */
 #endif /* _WLAN_NAN_API_H_ */

+ 55 - 1
components/nan/core/src/nan_api.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 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
@@ -487,3 +487,57 @@ bool wlan_is_mlo_sta_nan_ndi_allowed(struct wlan_objmgr_psoc *psoc)
 	return psoc_nan_obj->nan_caps.mlo_sta_nan_ndi_allowed;
 }
 #endif
+
+#if defined(WLAN_FEATURE_NAN) && defined(WLAN_CHIPSET_STATS)
+void nan_cstats_log_nan_enable_resp_evt(struct nan_event_params *nan_event)
+{
+	struct cstats_nan_disc_enable_resp stat = {0};
+	struct wlan_objmgr_vdev *vdev;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(nan_event->psoc,
+						    nan_event->vdev_id,
+						    WLAN_NAN_ID);
+	if (!vdev) {
+		nan_err("Invalid vdev!");
+		return;
+	}
+
+	stat.cmn.hdr.evt_id =
+		WLAN_CHIPSET_STATS_NAN_DISCOVERY_ENABLE_RESP_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_nan_disc_enable_resp) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+
+	stat.is_enable_success = nan_event->is_nan_enable_success;
+	stat.mac_id = nan_event->mac_id;
+	stat.disc_state = nan_get_discovery_state(nan_event->psoc);
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_nan_disc_enable_resp),
+			       &stat);
+}
+
+void nan_cstats_log_nan_disable_resp_evt(uint8_t vdev_id,
+					 struct wlan_objmgr_psoc *psoc)
+{
+	struct cstats_nan_disc_disable_resp stat = {0};
+
+	stat.cmn.hdr.evt_id =
+	   WLAN_CHIPSET_STATS_NAN_DISCOVERY_DISABLE_RESP_EVENT_ID;
+	stat.cmn.hdr.length =
+		sizeof(struct cstats_nan_disc_disable_resp) -
+		sizeof(struct cstats_hdr);
+	stat.cmn.opmode = QDF_NAN_DISC_MODE;
+	stat.cmn.vdev_id = vdev_id;
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+	stat.disc_state = nan_get_discovery_state(psoc);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_nan_disc_disable_resp),
+			       &stat);
+}
+#endif /* WLAN_CHIPSET_STATS */

+ 4 - 1
components/nan/core/src/nan_main.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 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
@@ -899,6 +899,8 @@ static QDF_STATUS nan_handle_enable_rsp(struct nan_event_params *nan_event)
 		/* NAN Enable has failed, restore changes */
 		goto fail;
 	}
+
+	nan_cstats_log_nan_enable_resp_evt(nan_event);
 fail:
 	psoc_nan_obj->nan_social_ch_2g_freq = 0;
 	psoc_nan_obj->nan_social_ch_5g_freq = 0;
@@ -957,6 +959,7 @@ QDF_STATUS nan_disable_cleanup(struct wlan_objmgr_psoc *psoc)
 
 		nan_handle_emlsr_concurrency(psoc, false);
 		policy_mgr_nan_sap_post_disable_conc_check(psoc);
+		nan_cstats_log_nan_disable_resp_evt(vdev_id, psoc);
 	} else {
 		/* Should not happen, NAN state can always be disabled */
 		nan_err("Cannot set NAN state to disabled!");

+ 19 - 1
components/tdls/core/src/wlan_tdls_cmds_process.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2024 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
@@ -39,6 +39,7 @@
 #include "wlan_policy_mgr_api.h"
 #include "nan_ucfg_api.h"
 #include "wlan_mlme_main.h"
+#include "wlan_policy_mgr_i.h"
 
 static uint16_t tdls_get_connected_peer_count(struct tdls_soc_priv_obj *soc_obj)
 {
@@ -2377,6 +2378,8 @@ int tdls_process_set_responder(struct tdls_set_responder_req *set_req)
 {
 	struct tdls_peer *curr_peer;
 	struct tdls_vdev_priv_obj *tdls_vdev;
+	struct wlan_objmgr_psoc *psoc;
+	QDF_STATUS status;
 
 	tdls_vdev = wlan_vdev_get_tdls_vdev_obj(set_req->vdev);
 	if (!tdls_vdev) {
@@ -2390,6 +2393,21 @@ int tdls_process_set_responder(struct tdls_set_responder_req *set_req)
 	}
 
 	curr_peer->is_responder = set_req->responder;
+
+	psoc = wlan_vdev_get_psoc(tdls_vdev->vdev);
+	if (!psoc) {
+		tdls_err("psoc not found");
+		return -EINVAL;
+	}
+
+	status = policy_mgr_update_nss_req(psoc,
+					   wlan_vdev_get_id(tdls_vdev->vdev),
+					   HW_MODE_SS_2x2, HW_MODE_SS_2x2);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("Unable to process NSS request");
+		return -EINVAL;
+	}
+
 	return 0;
 }
 

+ 10 - 1
components/tdls/dispatcher/inc/wlan_tdls_api.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2020, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2024 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
@@ -104,6 +104,15 @@ wlan_tdls_notify_sta_connect(uint8_t vdev_id,
 			     bool tdls_prohibited,
 			     struct wlan_objmgr_vdev *vdev);
 
+/**
+ * wlan_is_tdls_session_present() - Get TDLS session status
+ * @vdev: vdev pointer
+ *
+ * Return: QDF_STATUS_SUCCESS if success; other value if failed
+ */
+QDF_STATUS
+wlan_is_tdls_session_present(struct wlan_objmgr_vdev *vdev);
+
 /**
  * wlan_tdls_update_tx_pkt_cnt() - update tx pkt count
  * @vdev: tdls vdev object

+ 45 - 0
components/tdls/dispatcher/src/wlan_tdls_api.c

@@ -31,6 +31,7 @@
 #include <wlan_objmgr_cmn.h>
 #include "wlan_tdls_cfg_api.h"
 #include "wlan_policy_mgr_api.h"
+#include "wlan_mlo_mgr_sta.h"
 
 static QDF_STATUS tdls_teardown_flush_cb(struct scheduler_msg *msg)
 {
@@ -286,6 +287,50 @@ wlan_tdls_handle_sap_start(struct wlan_objmgr_psoc *psoc)
 {}
 #endif
 
+#ifdef WLAN_FEATURE_11BE_MLO
+static QDF_STATUS
+wlan_mlo_is_tdls_session_present(struct wlan_objmgr_vdev *vdev)
+{
+	uint8_t i;
+	struct wlan_mlo_dev_context *ml_dev = vdev->mlo_dev_ctx;
+
+	if (!ml_dev) {
+		tdls_err("MLO dev ctx is null");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	for (i = 0; i < ml_dev->wlan_vdev_count; i++) {
+		vdev = ml_dev->wlan_vdev_list[i];
+		if (tdls_get_connected_peer_count_from_vdev(vdev) > 0) {
+			tdls_debug("TDLS session is present");
+			return QDF_STATUS_SUCCESS;
+		}
+	}
+
+	return QDF_STATUS_E_INVAL;
+}
+#else
+static QDF_STATUS
+wlan_mlo_is_tdls_session_present(struct wlan_objmgr_vdev *vdev)
+{
+	return QDF_STATUS_E_INVAL;
+}
+#endif
+
+QDF_STATUS
+wlan_is_tdls_session_present(struct wlan_objmgr_vdev *vdev)
+{
+	if (mlo_is_mld_sta(vdev))
+		return wlan_mlo_is_tdls_session_present(vdev);
+
+	if (tdls_get_connected_peer_count_from_vdev(vdev) > 0) {
+		tdls_debug("TDLS session is present");
+		return QDF_STATUS_SUCCESS;
+	}
+
+	return QDF_STATUS_E_INVAL;
+}
+
 void wlan_tdls_notify_start_bss(struct wlan_objmgr_psoc *psoc,
 				struct wlan_objmgr_vdev *vdev)
 {

+ 7 - 5
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_fw_sync.c

@@ -113,12 +113,12 @@ QDF_STATUS cm_fw_roam_sync_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 	    cm_is_peer_preset_on_other_sta(psoc, vdev, vdev_id, event)) {
 		mlme_err("vdev %d Roam sync not handled in connecting/disconnecting state",
 			 vdev_id);
-		status = wlan_cm_roam_state_change(wlan_vdev_get_pdev(vdev),
-						   vdev_id,
-						   WLAN_ROAM_RSO_STOPPED,
-						   REASON_ROAM_SYNCH_FAILED);
+		wlan_cm_roam_state_change(wlan_vdev_get_pdev(vdev),
+					  vdev_id,
+					  WLAN_ROAM_RSO_STOPPED,
+					  REASON_ROAM_SYNCH_FAILED);
 		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
-		return status;
+		return QDF_STATUS_E_INVAL;
 	}
 	mlo_sta_stop_reconfig_timer(vdev);
 	wlan_clear_mlo_sta_link_removed_flag(vdev);
@@ -1163,6 +1163,7 @@ cm_fw_roam_sync_propagation(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 				     mlme_get_tdls_chan_switch_prohibited(vdev),
 				     mlme_get_tdls_prohibited(vdev), vdev);
 
+	wlan_cm_update_scan_mlme_info(vdev, connect_rsp);
 	cm_update_associated_ch_info(vdev, true);
 
 	status = cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_ROAM_DONE,
@@ -1181,6 +1182,7 @@ cm_fw_roam_sync_propagation(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 
 	if (wlan_vdev_mlme_is_mlo_vdev(vdev))
 		mlo_roam_copy_reassoc_rsp(vdev, connect_rsp);
+
 	mlme_debug(CM_PREFIX_FMT, CM_PREFIX_REF(vdev_id, cm_id));
 	cm_remove_cmd(cm_ctx, &cm_id);
 

+ 17 - 1
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c

@@ -3490,7 +3490,8 @@ static void cm_fill_stop_reason(struct wlan_roam_stop_config *stop_req,
 {
 	if (reason == REASON_ROAM_SYNCH_FAILED)
 		stop_req->reason = REASON_ROAM_SYNCH_FAILED;
-	else if (reason == REASON_DRIVER_DISABLED)
+	else if (reason == REASON_DRIVER_DISABLED ||
+		 reason == REASON_VDEV_RESTART_FROM_HOST)
 		stop_req->reason = REASON_ROAM_STOP_ALL;
 	else if (reason == REASON_SUPPLICANT_DISABLED_ROAMING)
 		stop_req->reason = REASON_SUPPLICANT_DISABLED_ROAMING;
@@ -4896,6 +4897,21 @@ cm_handle_mlo_rso_state_change(struct wlan_objmgr_pdev *pdev, uint8_t *vdev_id,
 		}
 	}
 
+	/*
+	 * Send RSO STOP before triggering a vdev restart on an MLO vdev
+	 * Send RSO START after CSA is completed on an MLO vdev
+	 */
+	if (wlan_vdev_mlme_is_mlo_vdev(vdev) &&
+	    mlo_check_if_all_vdev_up(vdev) &&
+	    reason == REASON_VDEV_RESTART_FROM_HOST) {
+		assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev);
+
+		*is_rso_skip = false;
+		*vdev_id = wlan_vdev_get_id(assoc_vdev);
+		mlme_debug("MLO_CSA: Send RSO on assoc vdev %d", *vdev_id);
+		goto end;
+	}
+
 	if (!wlan_vdev_mlme_get_is_mlo_link(wlan_pdev_get_psoc(pdev),
 					    *vdev_id))
 		goto end;

+ 67 - 0
components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_connect.c

@@ -45,6 +45,7 @@
 #include "wlan_mlo_link_force.h"
 #include "wlan_mlo_mgr_link_switch.h"
 #include "wlan_dp_api.h"
+#include <wlan_cp_stats_chipset_stats.h>
 
 #ifdef WLAN_FEATURE_FILS_SK
 void cm_update_hlp_info(struct wlan_objmgr_vdev *vdev,
@@ -1724,6 +1725,70 @@ cm_install_link_vdev_keys(struct wlan_objmgr_vdev *vdev)
 	mlo_defer_set_keys(vdev, link_id, false);
 }
 
+#ifdef WLAN_CHIPSET_STATS
+void cm_cp_stats_cstats_log_connect_event(struct wlan_objmgr_vdev *vdev,
+					  struct wlan_cm_connect_resp *rsp)
+{
+	struct vdev_mlme_obj *vdev_mlme;
+	struct wlan_channel *des_chan;
+	enum phy_ch_width ch_width = CH_WIDTH_20MHZ;
+	struct wlan_crypto_params *crypto_params;
+	struct cstats_sta_connect_resp stat = {0};
+
+	if (QDF_IS_STATUS_SUCCESS(rsp->connect_status)) {
+		stat.cmn.hdr.evt_id =
+			WLAN_CHIPSET_STATS_STA_CONNECT_SUCCESS_EVENT_ID;
+	} else {
+		stat.cmn.hdr.evt_id =
+			WLAN_CHIPSET_STATS_STA_CONNECT_FAIL_EVENT_ID;
+	}
+
+	wlan_mlme_get_sta_ch_width(vdev, &ch_width);
+	des_chan = wlan_vdev_mlme_get_des_chan(vdev);
+	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
+	if (!vdev_mlme) {
+		mlme_err("vdev component object is NULL");
+		return;
+	}
+
+	crypto_params = wlan_crypto_vdev_get_crypto_params(vdev);
+	if (!crypto_params) {
+		mlme_err("crypto params is null");
+		return;
+	}
+
+	cm_diag_get_auth_type(&stat.auth_type,
+			      crypto_params->authmodeset,
+			      crypto_params->key_mgmt,
+			      crypto_params->ucastcipherset);
+
+	stat.cmn.hdr.length = sizeof(struct cstats_sta_connect_resp) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+	stat.freq = rsp->freq;
+	stat.chnl_bw = cm_get_diag_ch_width(ch_width);
+	stat.dot11mode = cm_diag_dot11_mode_from_phy_mode(des_chan->ch_phymode);
+	stat.qos_capability = vdev_mlme->ext_vdev_ptr->connect_info.qos_enabled;
+	stat.encryption_type =
+			cm_get_diag_enc_type(crypto_params->ucastcipherset);
+	stat.result_code = rsp->connect_status;
+	stat.ssid_len = rsp->ssid.length;
+	qdf_mem_copy(stat.ssid, rsp->ssid.ssid, rsp->ssid.length);
+	CSTATS_MAC_COPY(stat.bssid, rsp->bssid.bytes);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_sta_connect_resp), &stat);
+}
+#else
+static inline void
+cm_cp_stats_cstats_log_connect_event(struct wlan_objmgr_vdev *vdev,
+				     struct wlan_cm_connect_resp *rsp)
+{
+}
+#endif /* WLAN_CHIPSET_STATS */
+
 QDF_STATUS
 cm_connect_complete_ind(struct wlan_objmgr_vdev *vdev,
 			struct wlan_cm_connect_resp *rsp)
@@ -1757,6 +1822,8 @@ cm_connect_complete_ind(struct wlan_objmgr_vdev *vdev,
 
 	cm_csr_connect_done_ind(vdev, rsp);
 
+	cm_cp_stats_cstats_log_connect_event(vdev, rsp);
+
 	cm_connect_info(vdev, QDF_IS_STATUS_SUCCESS(rsp->connect_status) ?
 			true : false, &rsp->bssid, &rsp->ssid,
 			rsp->freq);

+ 62 - 1
components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_disconnect.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2012-2015, 2020-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023-2024 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
@@ -37,6 +37,7 @@
 #include "wlan_t2lm_api.h"
 #include "wlan_mlo_link_force.h"
 #include <wlan_mlo_mgr_public_api.h>
+#include <wlan_cp_stats_chipset_stats.h>
 
 static void cm_abort_connect_request_timers(struct wlan_objmgr_vdev *vdev)
 {
@@ -107,6 +108,63 @@ QDF_STATUS cm_disconnect_start_ind(struct wlan_objmgr_vdev *vdev,
 	return QDF_STATUS_SUCCESS;
 }
 
+#ifdef WLAN_CHIPSET_STATS
+static void
+cm_cp_stats_cstats_disconn_req_event(struct wlan_objmgr_vdev *vdev,
+				     struct wlan_cm_vdev_discon_req *req)
+{
+	struct cstats_sta_disconnect_req stat = {0};
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_STA_DISCONNECT_REQ_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_sta_disconnect_req) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = req->req.vdev_id;
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+	stat.reason_code = req->req.reason_code;
+	stat.source = req->req.source;
+	stat.is_no_disassoc_disconnect = req->req.is_no_disassoc_disconnect;
+	CSTATS_MAC_COPY(stat.bssid, req->req.bssid.bytes);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_sta_disconnect_req), &stat);
+}
+
+static void
+cm_cp_stats_cstats_disconn_resp_event(struct wlan_objmgr_vdev *vdev,
+				      struct wlan_cm_discon_rsp *rsp)
+{
+	struct cstats_sta_disconnect_resp stat = {0};
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_STA_DISCONNECT_DONE_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_sta_disconnect_resp) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+	stat.cm_id = rsp->req.cm_id;
+	stat.reason_code = rsp->req.req.reason_code;
+	stat.source = rsp->req.req.source;
+	CSTATS_MAC_COPY(stat.bssid, rsp->req.req.bssid.bytes);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_sta_disconnect_resp),
+			       &stat);
+}
+#else
+static inline void
+cm_cp_stats_cstats_disconn_req_event(struct wlan_objmgr_vdev *vdev,
+				     struct wlan_cm_vdev_discon_req *req)
+{
+}
+
+static inline void
+cm_cp_stats_cstats_disconn_resp_event(struct wlan_objmgr_vdev *vdev,
+				      struct wlan_cm_discon_rsp *rsp)
+{
+}
+#endif /* WLAN_CHIPSET_STATS */
+
 QDF_STATUS
 cm_handle_disconnect_req(struct wlan_objmgr_vdev *vdev,
 			 struct wlan_cm_vdev_discon_req *req)
@@ -145,6 +203,7 @@ cm_handle_disconnect_req(struct wlan_objmgr_vdev *vdev,
 	discon_req = qdf_mem_malloc(sizeof(*discon_req));
 	if (!discon_req)
 		return QDF_STATUS_E_NOMEM;
+	cm_cp_stats_cstats_disconn_req_event(vdev, req);
 
 	cm_csr_handle_diconnect_req(vdev, req);
 	wlan_roam_reset_roam_params(vdev);
@@ -257,6 +316,8 @@ cm_disconnect_complete_ind(struct wlan_objmgr_vdev *vdev,
 			 CM_PREFIX_REF(vdev_id, rsp->req.cm_id));
 		return QDF_STATUS_E_INVAL;
 	}
+	cm_cp_stats_cstats_disconn_resp_event(vdev, rsp);
+
 	cm_disconnect_diag_event(vdev, rsp);
 	wlan_tdls_notify_sta_disconnect(vdev_id, false, false, vdev);
 	policy_mgr_decr_session_set_pcl(psoc, op_mode, vdev_id);

+ 1 - 0
components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h

@@ -93,6 +93,7 @@
 #define REASON_ROAM_ABORT                           53
 #define REASON_ROAM_SET_PRIMARY                     54
 #define REASON_ROAM_LINK_SWITCH_ASSOC_VDEV_CHANGE   55
+#define REASON_VDEV_RESTART_FROM_HOST               56
 
 #define FILS_MAX_KEYNAME_NAI_LENGTH WLAN_CM_FILS_MAX_KEYNAME_NAI_LENGTH
 #define WLAN_FILS_MAX_REALM_LEN WLAN_CM_FILS_MAX_REALM_LEN

+ 156 - 4
components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c

@@ -37,6 +37,7 @@
 #include "wlan_connectivity_logging.h"
 #include "target_if.h"
 #include "wlan_mlo_mgr_roam.h"
+#include <wlan_cp_stats_chipset_stats.h>
 
 /* Support for "Fast roaming" (i.e., ESE, LFR, or 802.11r.) */
 #define BG_SCAN_OCCUPIED_CHANNEL_LIST_LEN 15
@@ -260,15 +261,19 @@ QDF_STATUS wlan_cm_disable_rso(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id,
 {
 	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
 	QDF_STATUS status;
+	uint8_t disable_reason = REASON_DRIVER_DISABLED;
 
 	if (reason == REASON_DRIVER_DISABLED && requestor)
 		mlme_set_operations_bitmap(psoc, vdev_id, requestor, false);
 
+	if (reason == REASON_VDEV_RESTART_FROM_HOST)
+		disable_reason = REASON_VDEV_RESTART_FROM_HOST;
+
 	mlme_debug("ROAM_CONFIG: vdev[%d] Disable roaming - requestor:%s",
 		   vdev_id, cm_roam_get_requestor_string(requestor));
 
 	status = cm_roam_state_change(pdev, vdev_id, WLAN_ROAM_RSO_STOPPED,
-				      REASON_DRIVER_DISABLED, NULL, false);
+				      disable_reason, NULL, false);
 
 	return status;
 }
@@ -279,15 +284,19 @@ QDF_STATUS wlan_cm_enable_rso(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id,
 {
 	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
 	QDF_STATUS status;
+	uint8_t enable_reason = REASON_DRIVER_ENABLED;
 
 	if (reason == REASON_DRIVER_ENABLED && requestor)
 		mlme_set_operations_bitmap(psoc, vdev_id, requestor, true);
 
+	if (reason == REASON_VDEV_RESTART_FROM_HOST)
+		enable_reason = REASON_VDEV_RESTART_FROM_HOST;
+
 	mlme_debug("ROAM_CONFIG: vdev[%d] Enable roaming - requestor:%s",
 		   vdev_id, cm_roam_get_requestor_string(requestor));
 
 	status = cm_roam_state_change(pdev, vdev_id, WLAN_ROAM_RSO_ENABLED,
-				      REASON_DRIVER_ENABLED, NULL, false);
+				      enable_reason, NULL, false);
 
 	return status;
 }
@@ -4359,6 +4368,140 @@ wlan_cm_update_roam_stats_info(struct wlan_objmgr_psoc *psoc,
 }
 #endif
 
+#ifdef WLAN_CHIPSET_STATS
+static void
+cm_cp_stats_cstats_roam_scan_cancel(struct cstats_sta_roam_scan_cancel *stat,
+				    struct wmi_roam_trigger_abort_reason *abort)
+{
+	stat->reason_code = abort->abort_reason_code;
+	stat->data_rssi = abort->data_rssi;
+	stat->data_rssi_threshold = abort->data_rssi_threshold;
+	stat->rx_linkspeed_status = abort->rx_linkspeed_status;
+}
+
+static void
+cm_cp_stats_cstats_roam_scan_start(struct wlan_objmgr_vdev *vdev,
+				   struct wmi_roam_trigger_info *event,
+				   bool is_full_scan)
+{
+	struct cstats_sta_roam_scan_start stat = {0};
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_STA_ROAM_SCAN_START_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_sta_roam_scan_start) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+
+	stat.trigger_reason = event->trigger_reason;
+	stat.trigger_sub_reason = event->trigger_sub_reason;
+	stat.rssi = event->current_rssi;
+	stat.timestamp = event->timestamp;
+	stat.is_full_scan = is_full_scan;
+	cm_cp_stats_cstats_roam_scan_cancel(&stat.abort_roam,
+					    &event->abort_reason);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_sta_roam_scan_start),
+			       &stat);
+}
+
+static void
+cm_cp_stats_cstats_roam_scan_ap(struct cstats_sta_roam_scan_ap *stat,
+				struct wmi_roam_candidate_info *ap,
+				uint8_t num_ap)
+{
+	uint8_t i;
+
+	if (num_ap > MAX_ROAM_CANDIDATE_AP)
+		num_ap = MAX_ROAM_CANDIDATE_AP;
+
+	for (i = 0; i < num_ap; i++) {
+		CSTATS_MAC_COPY(stat->bssid, ap->bssid.bytes);
+		stat[i].total_score = ap->total_score;
+		stat[i].rssi = ap->rssi;
+		stat[i].etp = ap->etp;
+		stat[i].freq = ap->freq;
+		stat[i].cu_load = ap->cu_load;
+		stat[i].is_mlo = ap->is_mlo;
+		stat[i].type = ap->type;
+	}
+}
+
+static void cm_cp_stats_cstats_roam_scan_done(struct wlan_objmgr_vdev *vdev,
+					      struct wmi_roam_scan_data *event,
+					      bool is_full_scan)
+{
+	struct cstats_sta_roam_scan_done stat = {0};
+	uint8_t i;
+
+	if (event->num_ap >= MAX_ROAM_CANDIDATE_AP &&
+	    event->num_chan > MAX_ROAM_SCAN_CHAN)
+		return;
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_STA_ROAM_SCAN_DONE_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_sta_roam_scan_done) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+	stat.cand_ap_count = event->num_ap;
+	stat.num_scanned_freq = event->num_chan;
+	stat.timestamp = event->scan_complete_timestamp;
+
+	for (i = 0; i < event->num_chan; i++)
+		stat.scanned_freq[i] = event->chan_freq[i];
+
+	stat.is_full_scan = is_full_scan;
+	cm_cp_stats_cstats_roam_scan_ap(stat.ap, event->ap, stat.cand_ap_count);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_sta_roam_scan_done), &stat);
+}
+
+static void cm_cp_stats_cstats_roam_result(struct wlan_objmgr_vdev *vdev,
+					   struct wmi_roam_result *event)
+{
+	struct cstats_sta_roam_result stat = {0};
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_STA_ROAM_RESULT_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_sta_roam_result) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id  = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+	stat.timestamp = event->timestamp;
+	stat.status = event->status;
+	stat.fail_reason = event->fail_reason;
+	stat.roam_cancel_reason = event->roam_abort_reason;
+	CSTATS_MAC_COPY(stat.bssid, event->fail_bssid.bytes);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_sta_roam_result), &stat);
+}
+
+#else
+static inline void
+cm_cp_stats_cstats_roam_scan_start(struct wlan_objmgr_vdev *vdev,
+				   struct wmi_roam_trigger_info *event,
+				   bool is_full_scan)
+{
+}
+
+static inline void
+cm_cp_stats_cstats_roam_scan_done(struct wlan_objmgr_vdev *vdev,
+				  struct wmi_roam_scan_data *event,
+				  bool is_full_scan)
+{
+}
+
+static inline void
+cm_cp_stats_cstats_roam_result(struct wlan_objmgr_vdev *vdev,
+			       struct wmi_roam_result *event)
+{
+}
+#endif /* WLAN_CHIPSET_STATS */
+
 QDF_STATUS
 cm_roam_stats_event_handler(struct wlan_objmgr_psoc *psoc,
 			    struct roam_stats_event *stats_info)
@@ -4384,6 +4527,9 @@ cm_roam_stats_event_handler(struct wlan_objmgr_psoc *psoc,
 				stats_info->scan[i].present &&
 				stats_info->scan[i].type;
 
+			cm_cp_stats_cstats_roam_scan_start
+				(vdev, &stats_info->trigger[i], is_full_scan);
+
 			if (stats_info->trigger[i].trigger_reason ==
 			    ROAM_TRIGGER_REASON_BTM) {
 				cm_roam_handle_btm_stats(psoc, stats_info, i,
@@ -4398,20 +4544,26 @@ cm_roam_stats_event_handler(struct wlan_objmgr_psoc *psoc,
 					&stats_info->scan[i],
 					stats_info->vdev_id, is_full_scan);
 
-			if (stats_info->scan[i].present)
+			if (stats_info->scan[i].present) {
 				cm_roam_stats_print_scan_info(
 					psoc, &stats_info->scan[i],
 					stats_info->vdev_id,
 					stats_info->trigger[i].trigger_reason,
 					stats_info->trigger[i].timestamp);
+				cm_cp_stats_cstats_roam_scan_done
+				     (vdev, &stats_info->scan[i], is_full_scan);
+			}
 		}
 
-		if (stats_info->result[i].present)
+		if (stats_info->result[i].present) {
 			cm_roam_stats_print_roam_result(psoc,
 							&stats_info->trigger[i],
 							&stats_info->result[i],
 							&stats_info->scan[i],
 							stats_info->vdev_id);
+			cm_cp_stats_cstats_roam_result
+					       (vdev, &stats_info->result[i]);
+		}
 
 		if (stats_info->frame_stats[i].num_frame)
 			cm_roam_print_frame_info(psoc,

+ 4 - 0
configs/config_to_feature.h

@@ -2064,6 +2064,10 @@
 #define FEATURE_MULTICAST_HOST_FW_MSGS (1)
 #endif
 
+#ifdef CONFIG_WLAN_CHIPSET_STATS
+#define WLAN_CHIPSET_STATS (1)
+#endif
+
 #ifdef CONFIG_ENABLE_SMMU_S1_TRANSLATION
 #define ENABLE_SMMU_S1_TRANSLATION (1)
 #endif

+ 1 - 0
configs/pineapple_gki_kiwi-v2_defconfig

@@ -398,3 +398,4 @@ CONFIG_WLAN_MULTI_CHIP_SUPPORT=y
 CONFIG_WLAN_FEATURE_LL_LT_SAP=y
 CONFIG_DP_RX_MSDU_DONE_FAIL_HISTORY=y
 CONFIG_DP_RX_PEEK_MSDU_DONE_WAR=y
+CONFIG_WLAN_CHIPSET_STATS=y

+ 16 - 0
core/cds/src/cds_api.c

@@ -243,6 +243,20 @@ static QDF_STATUS cds_wmi_send_recv_qmi(void *buf, uint32_t len, void * cb_ctx,
 	return QDF_STATUS_SUCCESS;
 }
 
+static QDF_STATUS cds_qmi_indication(void *cb_ctx, qdf_qmi_ind_cb qmi_ind_cb)
+{
+	qdf_device_t qdf_ctx;
+
+	qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
+	if (!qdf_ctx)
+		return QDF_STATUS_E_INVAL;
+
+	if (pld_qmi_indication(qdf_ctx->dev, cb_ctx, qmi_ind_cb))
+		return QDF_STATUS_E_INVAL;
+
+	return QDF_STATUS_SUCCESS;
+}
+
 /**
  * cds_update_recovery_reason() - update the recovery reason code
  * @recovery_reason: recovery reason
@@ -332,6 +346,7 @@ QDF_STATUS cds_init(void)
 	qdf_register_drv_connected_callback(cds_is_drv_connected);
 	qdf_register_drv_supported_callback(cds_is_drv_supported);
 	qdf_register_wmi_send_recv_qmi_callback(cds_wmi_send_recv_qmi);
+	qdf_register_qmi_indication_callback(cds_qmi_indication);
 	qdf_register_recovery_reason_update(cds_update_recovery_reason);
 	qdf_register_get_bus_reg_dump(pld_get_bus_reg_dump);
 
@@ -365,6 +380,7 @@ void cds_deinit(void)
 	qdf_register_is_driver_state_module_stop_callback(NULL);
 	qdf_register_self_recovery_callback(NULL);
 	qdf_register_wmi_send_recv_qmi_callback(NULL);
+	qdf_register_qmi_indication_callback(NULL);
 
 	gp_cds_context->qdf_ctx = NULL;
 	qdf_mem_zero(&g_qdf_ctx, sizeof(g_qdf_ctx));

+ 2 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -1296,6 +1296,7 @@ struct wlan_hdd_tx_power {
  * @tx_power: Structure to hold connection tx Power info
  * @tx_latency_cfg: configuration for per-link transmit latency statistics
  * @link_state_cached_timestamp: link state cached timestamp
+ * @keep_alive_interval: user configured STA keep alive interval
  */
 struct hdd_adapter {
 	uint32_t magic;
@@ -1493,6 +1494,7 @@ struct hdd_adapter {
 #ifdef WLAN_FEATURE_11BE_MLO
 	qdf_time_t link_state_cached_timestamp;
 #endif
+	uint16_t keep_alive_interval;
 };
 
 #define WLAN_HDD_GET_STATION_CTX_PTR(link_info) (&(link_info)->session.station)

+ 1 - 1
core/hdd/src/wlan_hdd_assoc.c

@@ -2388,7 +2388,7 @@ hdd_roam_channel_switch_handler(struct wlan_hdd_link_info *link_info,
 	/* Enable Roaming on STA interface which was disabled before CSA */
 	if (adapter->device_mode == QDF_STA_MODE)
 		sme_start_roaming(mac_handle, link_info->vdev_id,
-				  REASON_DRIVER_ENABLED,
+				  REASON_VDEV_RESTART_FROM_HOST,
 				  RSO_CHANNEL_SWITCH);
 
 	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);

+ 0 - 6
core/hdd/src/wlan_hdd_cfg.c

@@ -1143,12 +1143,6 @@ static QDF_STATUS hdd_set_nss_params(struct wlan_hdd_link_info *link_info,
 				      link_info->vdev_id)))
 		return QDF_STATUS_E_FAILURE;
 
-	/* Check TDLS status and update antenna mode */
-	if ((adapter->device_mode == QDF_STA_MODE ||
-	     adapter->device_mode == QDF_P2P_CLIENT_MODE) &&
-	     policy_mgr_is_sta_active_connection_exists(hdd_ctx->psoc))
-		wlan_hdd_tdls_antenna_switch(link_info, rx_nss);
-
 	return QDF_STATUS_SUCCESS;
 }
 

+ 82 - 0
core/hdd/src/wlan_hdd_cfg80211.c

@@ -8646,6 +8646,8 @@ const struct nla_policy wlan_hdd_wifi_config_policy[
 	[QCA_WLAN_VENDOR_ATTR_CONFIG_COEX_TRAFFIC_SHAPING_MODE] = {
 		.type = NLA_U8},
 	[QCA_WLAN_VENDOR_ATTR_CONFIG_BTM_SUPPORT] = {.type = NLA_U8},
+	[QCA_WLAN_VENDOR_ATTR_CONFIG_KEEP_ALIVE_INTERVAL] = {
+		.type = NLA_U16},
 };
 
 #define WLAN_MAX_LINK_ID 15
@@ -11767,6 +11769,81 @@ hdd_set_coex_traffic_shaping_mode(struct wlan_hdd_link_info *link_info,
 	return ret;
 }
 
+#define STA_KEEPALIVE_INTERVAL_MAX 60
+#define STA_KEEPALIVE_INTERVAL_MIN 5
+
+int hdd_vdev_send_sta_keep_alive_interval(
+				struct wlan_hdd_link_info *link_info,
+				struct hdd_context *hdd_ctx,
+				uint16_t keep_alive_interval)
+{
+	struct keep_alive_req request;
+
+	qdf_mem_zero(&request, sizeof(request));
+
+	request.timePeriod = keep_alive_interval;
+	request.packetType = WLAN_KEEP_ALIVE_NULL_PKT;
+
+	if (QDF_STATUS_SUCCESS !=
+	    sme_set_keep_alive(hdd_ctx->mac_handle, link_info->vdev_id,
+			       &request)) {
+		hdd_err("Failure to execute Keep Alive");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void wlan_hdd_save_sta_keep_alive_interval(struct hdd_adapter *adapter,
+					   uint16_t keep_alive_interval)
+{
+	adapter->keep_alive_interval = keep_alive_interval;
+}
+
+/**
+ * hdd_vdev_set_sta_keep_alive_interval() - Set sta keep alive interval
+ * @link_info: Link info pointer.
+ * @attr: NL attribute pointer.
+ *
+ * Return: 0 on success, negative on failure.
+ */
+static int hdd_vdev_set_sta_keep_alive_interval(
+				struct wlan_hdd_link_info *link_info,
+				const struct nlattr *attr)
+{
+	struct hdd_adapter *adapter = link_info->adapter;
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	enum QDF_OPMODE device_mode = link_info->adapter->device_mode;
+	uint16_t keep_alive_interval;
+
+	keep_alive_interval = nla_get_u16(attr);
+	if (keep_alive_interval > STA_KEEPALIVE_INTERVAL_MAX ||
+	    keep_alive_interval < STA_KEEPALIVE_INTERVAL_MIN) {
+		hdd_err("Sta keep alive period: %d is out of range",
+			keep_alive_interval);
+		return -EINVAL;
+	}
+
+	hdd_debug("sta keep alive interval = %u", keep_alive_interval);
+
+	if (device_mode != QDF_STA_MODE) {
+		hdd_debug("This command is not supported for %s device mode",
+			  device_mode_to_string(device_mode));
+		return -EINVAL;
+	}
+
+	if (!hdd_is_vdev_in_conn_state(link_info)) {
+		hdd_debug("Vdev (id %d) not in connected/started state, cannot accept command",
+			  link_info->vdev_id);
+		return -EINVAL;
+	}
+
+	wlan_hdd_save_sta_keep_alive_interval(adapter, keep_alive_interval);
+
+	return hdd_vdev_send_sta_keep_alive_interval(link_info, hdd_ctx,
+						     keep_alive_interval);
+}
+
 #ifdef WLAN_FEATURE_11BE_MLO
 static int hdd_test_config_emlsr_mode(struct hdd_context *hdd_ctx,
 				      bool cfg_val)
@@ -12472,6 +12549,8 @@ static const struct independent_setters independent_setters[] = {
 	 hdd_set_coex_traffic_shaping_mode},
 	{QCA_WLAN_VENDOR_ATTR_CONFIG_BTM_SUPPORT,
 	 hdd_set_btm_support_config},
+	{QCA_WLAN_VENDOR_ATTR_CONFIG_KEEP_ALIVE_INTERVAL,
+	 hdd_vdev_set_sta_keep_alive_interval},
 };
 
 #ifdef WLAN_FEATURE_ELNA
@@ -15154,6 +15233,9 @@ static int __wlan_hdd_cfg80211_wifi_logger_get_ring_data(struct wiphy *wiphy,
 			hdd_err("Failed to trigger bug report");
 			return -EINVAL;
 		}
+
+		wlan_set_chipset_stats_bit();
+
 		status = wlan_logging_wait_for_flush_log_completion();
 		if (!QDF_IS_STATUS_SUCCESS(status)) {
 			hdd_err("wait for flush log timed out");

+ 23 - 1
core/hdd/src/wlan_hdd_cfg80211.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 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
@@ -1165,4 +1165,26 @@ wlan_hdd_ml_sap_get_peer(struct wlan_objmgr_vdev *vdev,
 	return NULL;
 }
 #endif /* WLAN_FEATURE_11BE_MLO && CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT */
+
+/**
+ * hdd_vdev_send_sta_keep_alive_interval - Send sta keep alive interval to fw
+ * @link_info: Link info pointer.
+ * @hdd_ctx: HDD context pointer
+ * @keep_alive_interval: STA keep alive interval
+ *
+ * Return: 0 on success, negative on failure
+ */
+int hdd_vdev_send_sta_keep_alive_interval(struct wlan_hdd_link_info *link_info,
+					  struct hdd_context *hdd_ctx,
+					  uint16_t keep_alive_interval);
+
+/**
+ * wlan_hdd_save_sta_keep_alive_interval() - Save STA keep alive interval
+ * @adapter: HDD adapter pointer
+ * @sta_alive_interval: STA keep alive interval
+ *
+ * Return: None.
+ */
+void wlan_hdd_save_sta_keep_alive_interval(struct hdd_adapter *adapter,
+					   uint16_t sta_alive_interval);
 #endif

+ 7 - 1
core/hdd/src/wlan_hdd_cm_connect.c

@@ -1795,8 +1795,14 @@ hdd_cm_connect_success_pre_user_update(struct wlan_objmgr_vdev *vdev,
 		link_info->vdev_id, QDF_TRACE_DEFAULT_PDEV_ID,
 		QDF_PROTO_TYPE_MGMT, QDF_PROTO_MGMT_ASSOC));
 
-	if (is_roam)
+	if (is_roam) {
 		ucfg_dp_nud_indicate_roam(vdev);
+
+		if (adapter->keep_alive_interval)
+			hdd_vdev_send_sta_keep_alive_interval(link_info,
+						hdd_ctx,
+						adapter->keep_alive_interval);
+	}
 	 /* hdd_objmgr_set_peer_mlme_auth_state */
 }
 

+ 32 - 1
core/hdd/src/wlan_hdd_cm_disconnect.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2024 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
@@ -165,6 +165,36 @@ __hdd_cm_disconnect_handler_pre_user_update(struct wlan_hdd_link_info *link_info
 	hdd_place_marker(adapter, "DISCONNECTED", NULL);
 }
 
+/**
+ * hdd_reset_sta_keep_alive_interval() - Reset STA keep alive interval
+ * @link_info: Link info pointer.
+ * @hdd_ctx: HDD context pointer.
+ *
+ * Return: None.
+ */
+static void
+hdd_reset_sta_keep_alive_interval(struct wlan_hdd_link_info *link_info,
+				  struct hdd_context *hdd_ctx)
+{
+	enum QDF_OPMODE device_mode = link_info->adapter->device_mode;
+	uint32_t keep_alive_interval;
+
+	if (!link_info->adapter->keep_alive_interval)
+		return;
+
+	if (device_mode != QDF_STA_MODE) {
+		hdd_debug("Not supported for device mode %s = ",
+			  device_mode_to_string(device_mode));
+		return;
+	}
+
+	wlan_hdd_save_sta_keep_alive_interval(link_info->adapter, 0);
+	ucfg_mlme_get_sta_keep_alive_period(hdd_ctx->psoc,
+					    &keep_alive_interval);
+	hdd_vdev_send_sta_keep_alive_interval(link_info, hdd_ctx,
+					      keep_alive_interval);
+}
+
 void
 __hdd_cm_disconnect_handler_post_user_update(struct wlan_hdd_link_info *link_info,
 					     struct wlan_objmgr_vdev *vdev,
@@ -250,6 +280,7 @@ __hdd_cm_disconnect_handler_post_user_update(struct wlan_hdd_link_info *link_inf
 
 	ucfg_dp_nud_reset_tracking(vdev);
 	hdd_reset_limit_off_chan(adapter);
+	hdd_reset_sta_keep_alive_interval(link_info, hdd_ctx);
 
 	hdd_cm_print_bss_info(sta_ctx);
 }

+ 232 - 1
core/hdd/src/wlan_hdd_hostapd.c

@@ -2245,6 +2245,8 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
 			      ap_ctx->operating_chan_freq,
 			      sap_config->ch_params.ch_width);
 
+		hdd_cp_stats_cstats_sap_go_start_event(link_info, sap_event);
+
 		sap_config->ch_params = ap_ctx->sap_context->ch_params;
 		sap_config->sec_ch_freq = ap_ctx->sap_context->sec_ch_freq;
 
@@ -2435,6 +2437,7 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
 		hdd_debug("BSS stop status = %s",
 		       sap_event->sapevt.sapStopBssCompleteEvent.
 		       status ? "eSAP_STATUS_FAILURE" : "eSAP_STATUS_SUCCESS");
+		hdd_cp_stats_cstats_sap_go_stop_event(link_info, sap_event);
 
 		hdd_hostapd_channel_allow_suspend(adapter,
 						  ap_ctx->operating_chan_freq,
@@ -2484,6 +2487,10 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
 					    &dfs_info,
 					    sizeof(struct wlan_dfs_info));
 		hdd_ctx->dev_dfs_cac_status = DFS_CAC_IN_PROGRESS;
+
+		hdd_cp_stats_cstats_log_sap_go_dfs_event(link_info,
+							 eSAP_DFS_CAC_START);
+
 		if (QDF_STATUS_SUCCESS !=
 			hdd_send_radar_event(hdd_ctx, eSAP_DFS_CAC_START,
 				dfs_info, &adapter->wdev)) {
@@ -2504,6 +2511,8 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
 		 * space applications are waiting on CAC end for their state
 		 * management.
 		 */
+		hdd_cp_stats_cstats_log_sap_go_dfs_event
+					(link_info, eSAP_DFS_CAC_INTERRUPTED);
 		if (QDF_STATUS_SUCCESS !=
 			hdd_send_radar_event(hdd_ctx, eSAP_DFS_CAC_END,
 				dfs_info, &adapter->wdev)) {
@@ -2531,6 +2540,9 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
 			hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID);
 		}
 
+		hdd_cp_stats_cstats_log_sap_go_dfs_event(link_info,
+							 eSAP_DFS_CAC_END);
+
 		hdd_ctx->dev_dfs_cac_status = DFS_CAC_ALREADY_DONE;
 		if (QDF_STATUS_SUCCESS !=
 			hdd_send_radar_event(hdd_ctx, eSAP_DFS_CAC_END,
@@ -2548,6 +2560,8 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
 	{
 		int i;
 
+		hdd_cp_stats_cstats_log_sap_go_dfs_event(link_info,
+							 eSAP_DFS_RADAR_DETECT);
 		hdd_dfs_indicate_radar(hdd_ctx);
 		wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
 					WLAN_SVC_DFS_RADAR_DETECT_IND,
@@ -2641,7 +2655,8 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
 	case eSAP_STA_ASSOC_EVENT:
 	case eSAP_STA_REASSOC_EVENT:
 		event = &sap_event->sapevt.sapStationAssocReassocCompleteEvent;
-
+		hdd_cp_stats_cstats_log_sap_go_sta_assoc_reassoc_event
+							 (link_info, sap_event);
 		/* Reset scan reject params on assoc */
 		hdd_init_scan_reject_params(hdd_ctx);
 		if (eSAP_STATUS_FAILURE == event->status) {
@@ -2834,6 +2849,10 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
 			      QDF_MAC_ADDR_REF(wrqu.addr.sa_data));
 		hdd_place_marker(adapter, "CLIENT DISASSOCIATED FROM SAP",
 				 wrqu.addr.sa_data);
+
+		hdd_cp_stats_cstats_log_sap_go_sta_disassoc_event(link_info,
+								  sap_event);
+
 		qdf_status = qdf_event_set(&hostapd_state->qdf_sta_disassoc_event);
 		if (!QDF_IS_STATUS_SUCCESS(qdf_status))
 			hdd_err("Station Deauth event Set failed");
@@ -8456,3 +8475,215 @@ bool hdd_sap_is_acs_in_progress(struct wlan_objmgr_vdev *vdev)
 	return in_progress;
 }
 #endif
+
+#ifdef WLAN_CHIPSET_STATS
+void
+hdd_cp_stats_cstats_sap_go_start_event(struct wlan_hdd_link_info *link_info,
+				       struct sap_event *sap_event)
+{
+	struct sap_config *sap_config;
+	struct hdd_ap_ctx *ap_ctx;
+	struct wlan_objmgr_vdev *vdev;
+	struct cstats_sap_go_start stat = {0};
+
+	ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info);
+
+	sap_config = &ap_ctx->sap_config;
+
+	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_HDD_ID_OBJ_MGR);
+	if (!vdev) {
+		hdd_err("vdev is NULL");
+		return;
+	}
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_SAP_GO_START_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_sap_go_start) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id =
+			sap_event->sapevt.sapStartBssCompleteEvent.sessionId;
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+
+	stat.status = sap_event->sapevt.sapStartBssCompleteEvent.status;
+	stat.operating_chan_freq =
+		sap_event->sapevt.sapStartBssCompleteEvent.operating_chan_freq;
+	stat.ch_width = sap_event->sapevt.sapStartBssCompleteEvent.ch_width;
+	stat.staId = sap_event->sapevt.sapStartBssCompleteEvent.staId;
+
+	stat.ssid_len = sap_config->SSIDinfo.ssid.length;
+	qdf_mem_copy(stat.ssid, sap_config->SSIDinfo.ssid.ssId,
+		     sap_config->SSIDinfo.ssid.length);
+	CSTATS_MAC_COPY(stat.bssid, sap_config->self_macaddr.bytes);
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_sap_go_start), &stat);
+}
+
+void hdd_cp_stats_cstats_sap_go_stop_event(struct wlan_hdd_link_info *link_info,
+					   struct sap_event *sap_event)
+{
+	struct sap_config *sap_config;
+	struct hdd_ap_ctx *ap_ctx;
+	struct wlan_objmgr_vdev *vdev;
+	struct cstats_sap_go_stop stat = {0};
+
+	ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info);
+
+	sap_config = &ap_ctx->sap_config;
+
+	vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_HDD_ID_OBJ_MGR);
+	if (!vdev) {
+		hdd_err("vdev is NULL");
+		return;
+	}
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_SAP_GO_STOP_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_sap_go_stop) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+	stat.status = sap_event->sapevt.sapStopBssCompleteEvent.status;
+	CSTATS_MAC_COPY(stat.bssid, sap_config->self_macaddr.bytes);
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_sap_go_stop), &stat);
+}
+
+void
+hdd_cp_stats_cstats_log_sap_go_sta_disassoc_event(struct wlan_hdd_link_info *li,
+						  struct sap_event *sap_evt)
+{
+	struct sap_config *sap_config;
+	struct hdd_ap_ctx *ap_ctx;
+	struct wlan_objmgr_vdev *vdev;
+	tSap_StationDisassocCompleteEvent *disassoc_comp;
+	struct cstats_sap_go_sta_disassoc stat = {0};
+
+	ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(li);
+
+	sap_config = &ap_ctx->sap_config;
+
+	vdev = hdd_objmgr_get_vdev_by_user(li, WLAN_HDD_ID_OBJ_MGR);
+	if (!vdev) {
+		hdd_err("vdev is NULL");
+		return;
+	}
+
+	disassoc_comp = &sap_evt->sapevt.sapStationDisassocCompleteEvent;
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_SAP_GO_STA_DISASSOC_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_sap_go_sta_disassoc) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+
+	stat.sta_id = disassoc_comp->staId;
+	stat.status = disassoc_comp->status;
+	stat.status_code = disassoc_comp->status_code;
+	stat.reason = disassoc_comp->reason;
+	stat.reason_code = disassoc_comp->reason_code;
+	CSTATS_MAC_COPY(stat.bssid, sap_config->self_macaddr.bytes);
+	CSTATS_MAC_COPY(stat.sta_mac, disassoc_comp->staMac.bytes);
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_sap_go_sta_disassoc),
+			       &stat);
+}
+
+void hdd_cp_stats_cstats_log_sap_go_sta_assoc_reassoc_event(
+		struct wlan_hdd_link_info *li, struct sap_event *sap_evt)
+{
+	struct sap_config *sap_config;
+	struct hdd_ap_ctx *ap_ctx;
+	struct wlan_objmgr_vdev *vdev;
+	tSap_StationAssocReassocCompleteEvent *event;
+	struct cstats_sap_go_sta_assoc_reassoc stat = {0};
+
+	ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(li);
+
+	sap_config = &ap_ctx->sap_config;
+
+	vdev = hdd_objmgr_get_vdev_by_user(li, WLAN_HDD_ID_OBJ_MGR);
+	if (!vdev) {
+		hdd_err("vdev is NULL");
+		return;
+	}
+
+	event = &sap_evt->sapevt.sapStationAssocReassocCompleteEvent;
+
+	stat.cmn.hdr.evt_id =
+			WLAN_CHIPSET_STATS_SAP_GO_STA_ASSOC_REASSOC_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_sap_go_sta_assoc_reassoc) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR);
+
+	stat.sta_id = event->staId;
+	stat.status = event->status;
+	stat.status_code = event->status_code;
+	CSTATS_MAC_COPY(stat.sta_mac, event->staMac.bytes);
+	CSTATS_MAC_COPY(stat.bssid, sap_config->self_macaddr.bytes);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_sap_go_sta_assoc_reassoc),
+			       &stat);
+}
+
+void hdd_cp_stats_cstats_log_sap_go_dfs_event(struct wlan_hdd_link_info *li,
+					      eSapHddEvent event_id)
+{
+	struct sap_config *sap_config;
+	struct hdd_ap_ctx *ap_ctx;
+	struct wlan_objmgr_vdev *vdev;
+	struct cstats_sap_go_dfs_evt stat = {0};
+
+	ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(li);
+
+	sap_config = &ap_ctx->sap_config;
+
+	vdev = hdd_objmgr_get_vdev_by_user(li, WLAN_HDD_ID_OBJ_MGR);
+	if (!vdev) {
+		hdd_err("vdev is NULL");
+		return;
+	}
+
+	if (event_id == eSAP_DFS_CAC_START) {
+		stat.cmn.hdr.evt_id =
+				   WLAN_CHIPSET_STATS_SAP_GO_CAC_START_EVENT_ID;
+	} else if (event_id == eSAP_DFS_CAC_END) {
+		stat.cmn.hdr.evt_id =
+				     WLAN_CHIPSET_STATS_SAP_GO_CAC_END_EVENT_ID;
+	} else if (event_id == eSAP_DFS_RADAR_DETECT) {
+		stat.cmn.hdr.evt_id =
+			      WLAN_CHIPSET_STATS_SAP_GO_RADAR_DETECTED_EVENT_ID;
+	} else if (event_id == eSAP_DFS_CAC_INTERRUPTED) {
+		stat.cmn.hdr.evt_id =
+			     WLAN_CHIPSET_STATS_SAP_GO_CAC_INTERRUPTED_EVENT_ID;
+	} else {
+		hdd_err("Invalid Event");
+		hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR);
+		return;
+	}
+
+	stat.cmn.hdr.length = sizeof(struct cstats_sap_go_dfs_evt) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+
+	CSTATS_MAC_COPY(stat.bssid, sap_config->self_macaddr.bytes);
+	stat.freq = ap_ctx->operating_chan_freq;
+	wlan_reg_get_cc_and_src(wlan_vdev_get_psoc(vdev), stat.cc);
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_sap_go_dfs_evt), &stat);
+}
+#endif /* WLAN_CHIPSET_STATS */

+ 96 - 1
core/hdd/src/wlan_hdd_hostapd.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2024 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
@@ -504,4 +504,99 @@ bool hdd_sap_is_acs_in_progress(struct wlan_objmgr_vdev *vdev)
 	return false;
 }
 #endif
+
+#ifdef WLAN_CHIPSET_STATS
+/*
+ * hdd_cp_stats_cstats_sap_go_start_event() - chipset stats for sap/go start
+ * event
+ *
+ * @link_info: pointer to link_info object
+ * @sap_event: pointer to sap_event object
+ *
+ * Return : void
+ */
+void
+hdd_cp_stats_cstats_sap_go_start_event(struct wlan_hdd_link_info *link_info,
+				       struct sap_event *sap_event);
+
+/**
+ * hdd_cp_stats_cstats_sap_go_stop_event() - chipset stats for sap/go stop event
+ *
+ * @link_info: pointer to link_info object
+ * @sap_event: pointer to sap_event object
+ *
+ * Return : void
+ */
+void
+hdd_cp_stats_cstats_sap_go_stop_event(struct wlan_hdd_link_info *link_info,
+				      struct sap_event *sap_event);
+
+/**
+ * hdd_cp_stats_cstats_log_sap_go_sta_disassoc_event() - chipset stats for
+ * sap/go STA disconnect event
+ *
+ * @li: pointer to link_info object
+ * @sap_evt: pointer to sap_event object
+ *
+ * Return : void
+ */
+void
+hdd_cp_stats_cstats_log_sap_go_sta_disassoc_event(struct wlan_hdd_link_info *li,
+						  struct sap_event *sap_evt);
+
+/**
+ * hdd_cp_stats_cstats_log_sap_go_sta_assoc_reassoc_event() - chipset stats for
+ * sap/go STA assoc event
+ *
+ * @li: pointer to link_info object
+ * @sap_evt: pointer to sap_event object
+ *
+ * Return : void
+ */
+void
+hdd_cp_stats_cstats_log_sap_go_sta_assoc_reassoc_event
+		     (struct wlan_hdd_link_info *li, struct sap_event *sap_evt);
+
+/**
+ * hdd_cp_stats_cstats_log_sap_go_dfs_event() - chipset stats for
+ * sap/go dfs event
+ *
+ * @li: pointer to link_info object
+ * @event_id: eSapHddEvent event
+ *
+ * Return : void
+ */
+void hdd_cp_stats_cstats_log_sap_go_dfs_event(struct wlan_hdd_link_info *li,
+					      eSapHddEvent event_id);
+#else
+static inline void
+hdd_cp_stats_cstats_sap_go_start_event(struct wlan_hdd_link_info *link_info,
+				       struct sap_event *sap_event)
+{
+}
+
+static inline void
+hdd_cp_stats_cstats_sap_go_stop_event(struct wlan_hdd_link_info *link_info,
+				      struct sap_event *sap_event)
+{
+}
+
+static inline void
+hdd_cp_stats_cstats_log_sap_go_sta_disassoc_event(struct wlan_hdd_link_info *li,
+						  struct sap_event *sap_evt)
+{
+}
+
+static inline void
+hdd_cp_stats_cstats_log_sap_go_sta_assoc_reassoc_event
+		     (struct wlan_hdd_link_info *li, struct sap_event *sap_evt)
+{
+}
+
+static inline void
+hdd_cp_stats_cstats_log_sap_go_dfs_event(struct wlan_hdd_link_info *li,
+					 eSapHddEvent event_id)
+{
+}
+#endif /* WLAN_CHIPSET_STATS */
 #endif /* end #if !defined(WLAN_HDD_HOSTAPD_H) */

+ 8 - 0
core/hdd/src/wlan_hdd_ioctl.c

@@ -50,6 +50,7 @@
 #include "wlan_reg_ucfg_api.h"
 #include "qdf_func_tracker.h"
 #include "wlan_cm_roam_ucfg_api.h"
+#include "wlan_tdls_api.h"
 
 #if defined(LINUX_QCMBR)
 #define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13)
@@ -6063,6 +6064,13 @@ int hdd_set_antenna_mode(struct wlan_hdd_link_info *link_info, int mode)
 		.timeout_ms = SME_POLICY_MGR_CMD_TIMEOUT,
 	};
 
+	if (QDF_STATUS_SUCCESS ==
+	    wlan_is_tdls_session_present(link_info->vdev)) {
+		hdd_debug("TDLS session exists");
+		ret = -EINVAL;
+		goto exit;
+	}
+
 	switch (mode) {
 	case HDD_ANTENNA_MODE_1X1:
 		params.num_rx_chains = 1;

+ 18 - 0
core/hdd/src/wlan_hdd_main.c

@@ -4072,6 +4072,21 @@ static bool hdd_is_cac_in_progress(void)
 	return (hdd_ctx->dev_dfs_cac_status == DFS_CAC_IN_PROGRESS);
 }
 
+static QDF_STATUS
+wlan_hdd_set_tx_rx_nss_cb(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
+			  uint8_t tx_nss, uint8_t rx_nss)
+{
+	struct wlan_hdd_link_info *link_info;
+
+	link_info = wlan_hdd_get_link_info_from_vdev(psoc, vdev_id);
+	if (!link_info) {
+		hdd_err("Invalid vdev %d", vdev_id);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return hdd_update_nss(link_info, tx_nss, rx_nss);
+}
+
 static void hdd_register_policy_manager_callback(
 			struct wlan_objmgr_psoc *psoc)
 {
@@ -4099,6 +4114,7 @@ static void hdd_register_policy_manager_callback(
 	hdd_cbacks.wlan_get_sap_acs_band =
 			wlan_get_sap_acs_band;
 	hdd_cbacks.wlan_check_cc_intf_cb = wlan_hdd_check_cc_intf_cb;
+	hdd_cbacks.wlan_set_tx_rx_nss_cb = wlan_hdd_set_tx_rx_nss_cb;
 
 	if (QDF_STATUS_SUCCESS !=
 	    policy_mgr_register_hdd_cb(psoc, &hdd_cbacks)) {
@@ -19572,6 +19588,8 @@ static QDF_STATUS hdd_component_init(void)
 	if (QDF_IS_STATUS_ERROR(status))
 		goto afc_deinit;
 
+	hdd_register_cstats_ops();
+
 	return QDF_STATUS_SUCCESS;
 
 afc_deinit:

+ 8 - 1
core/hdd/src/wlan_hdd_nan_datapath.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 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
@@ -46,6 +46,7 @@
 #include "wlan_fwol_ucfg_api.h"
 #include "wlan_dp_ucfg_api.h"
 #include "wlan_hdd_sysfs.h"
+#include "wlan_hdd_stats.h"
 
 /**
  * hdd_nan_datapath_target_config() - Configure NAN datapath features
@@ -848,6 +849,8 @@ int hdd_ndi_start(const char *iface_name, uint16_t transaction_id)
 		ret = -EINVAL;
 		goto err_handler;
 	}
+
+	hdd_cstats_log_ndi_create_req_evt(vdev, transaction_id);
 	/*
 	 * Create transaction id is required to be saved since the firmware
 	 * does not honor the transaction id for create request
@@ -938,7 +941,9 @@ int hdd_ndi_delete(uint8_t vdev_id, const char *iface_name,
 
 	os_if_nan_set_ndp_delete_transaction_id(vdev, transaction_id);
 	os_if_nan_set_ndi_state(vdev, NAN_DATA_NDI_DELETING_STATE);
+	hdd_cstats_log_ndi_delete_req_evt(vdev, transaction_id);
 	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_NAN_ID);
+
 	/* Delete the interface */
 	adapter->is_virtual_iface = true;
 	ret = hdd_delete_ndi_intf(hdd_ctx->wiphy, &adapter->wdev);
@@ -1039,6 +1044,8 @@ hdd_ndi_drv_ndi_create_rsp_handler(uint8_t vdev_id,
 			ndi_rsp->reason /* create_reason */);
 	}
 
+	hdd_cstats_log_ndi_create_resp_evt(link_info, ndi_rsp);
+
 	hdd_save_peer(sta_ctx, &bc_mac_addr);
 	qdf_copy_macaddr(&roam_info->bssid, &bc_mac_addr);
 	hdd_roam_register_sta(link_info,

+ 153 - 0
core/hdd/src/wlan_hdd_stats.c

@@ -49,6 +49,16 @@
 #include "wlan_hdd_eht.h"
 #include "wlan_dp_ucfg_api.h"
 #include "wlan_cm_roam_ucfg_api.h"
+#include <wlan_cp_stats_chipset_stats.h>
+#include <wlan_cp_stats_ucfg_api.h>
+#ifdef CNSS_GENL
+#ifdef CONFIG_CNSS_OUT_OF_TREE
+#include "cnss_nl.h"
+#else
+#include <net/cnss_nl.h>
+#endif
+#endif
+#include "wlan_nan_api.h"
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS)
 #define HDD_INFO_SIGNAL                 STATION_INFO_SIGNAL
@@ -11549,3 +11559,146 @@ QDF_STATUS hdd_tx_latency_register_cb(void *soc)
 						     hdd_tx_latency_stats_cb);
 }
 #endif
+
+#ifdef WLAN_CHIPSET_STATS
+#ifdef CNSS_GENL
+static int nl_srv_bcast_cstats(struct sk_buff *skb)
+{
+	return nl_srv_bcast(skb, CLD80211_MCGRP_HOST_LOGS, ANI_NL_MSG_LOG);
+}
+#else
+static int nl_srv_bcast_cstats(struct sk_buff *skb)
+{
+	return nl_srv_bcast(skb);
+}
+#endif
+
+int hdd_cstats_send_data_to_userspace(char *buff, unsigned int len,
+				      enum cstats_types type)
+{
+	struct sk_buff *skb = NULL;
+	struct nlmsghdr *nlh;
+	tAniNlHdr *wnl;
+	static int nlmsg_seq;
+	int tot_msg_len;
+	int ret = -1;
+
+	if (type == CSTATS_HOST_TYPE) {
+		*(unsigned short *)(buff) = ANI_NL_MSG_CSTATS_HOST_LOG_TYPE;
+		*(unsigned short *)(buff + 2) = len - sizeof(tAniHdr);
+	} else if (type == CSTATS_FW_TYPE) {
+		*(unsigned short *)(buff) = ANI_NL_MSG_CSTATS_FW_LOG_TYPE;
+		*(unsigned short *)(buff + 2) = len - sizeof(tAniHdr);
+	}
+
+	skb = dev_alloc_skb(MAX_CSTATS_NODE_LENGTH);
+	if (!skb) {
+		qdf_err("dev_alloc_skb() failed");
+		return -ENOMEM;
+	}
+
+	tot_msg_len = NLMSG_SPACE(len + sizeof(wnl->radio));
+
+	nlh = nlmsg_put(skb, 0, nlmsg_seq++,
+			ANI_NL_MSG_LOG,
+			len + sizeof(wnl->radio), NLM_F_REQUEST);
+	if (!nlh) {
+		qdf_err("nlmsg_put() failed for msg size[%d]", tot_msg_len);
+		dev_kfree_skb(skb);
+		return -EINVAL;
+	}
+
+	wnl = (tAniNlHdr *)nlh;
+	wnl->radio = 0;
+
+	memcpy(nlmsg_data(nlh) + sizeof(wnl->radio), buff, len);
+
+	ret = nl_srv_bcast_cstats(skb);
+	if (ret < 0)
+		qdf_err("Send Failed %d", ret);
+
+	return ret;
+}
+
+struct cstats_tx_rx_ops cstats_ops = {
+	.cstats_send_data_to_usr = hdd_cstats_send_data_to_userspace,
+};
+
+void hdd_register_cstats_ops(void)
+{
+	ucfg_cp_stats_cstats_register_tx_rx_ops(&cstats_ops);
+}
+
+void
+hdd_cstats_log_ndi_delete_req_evt(struct wlan_objmgr_vdev *vdev,
+				  uint16_t transaction_id)
+{
+	struct cstats_nan_ndi_delete_req stat = {0};
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDI_DELETE_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_nan_ndi_delete_req) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+	stat.transaction_id = transaction_id;
+
+	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndi_delete_req), &stat);
+}
+
+void
+hdd_cstats_log_ndi_create_resp_evt(struct wlan_hdd_link_info *li,
+				   struct nan_datapath_inf_create_rsp *ndi_rsp)
+{
+	struct cstats_nan_ndi_create_resp stat = {0};
+	struct wlan_objmgr_vdev *vdev;
+	struct nan_vdev_priv_obj *priv_obj;
+
+	vdev = hdd_objmgr_get_vdev_by_user(li, WLAN_OSIF_NAN_ID);
+	if (!vdev) {
+		hdd_err("vdev is NULL");
+		return;
+	}
+
+	priv_obj = nan_get_vdev_priv_obj(vdev);
+	if (!priv_obj) {
+		hdd_err("priv_obj is null");
+		return;
+	}
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDI_CREATE_RESP_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_nan_ndi_create_resp) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+	stat.status = ndi_rsp->status;
+	stat.reason = ndi_rsp->reason;
+	qdf_spin_lock_bh(&priv_obj->lock);
+	stat.transaction_id = priv_obj->ndp_create_transaction_id;
+	qdf_spin_unlock_bh(&priv_obj->lock);
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_NAN_ID);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndi_create_resp),
+			       &stat);
+}
+
+void hdd_cstats_log_ndi_create_req_evt(struct wlan_objmgr_vdev *vdev,
+				       uint16_t transaction_id)
+{
+	struct cstats_nan_ndi_create_req stat = {0};
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDI_CREATE_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_nan_ndi_create_req) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+	stat.transaction_id = transaction_id;
+
+	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndi_create_req), &stat);
+}
+#endif /* WLAN_CHIPSET_STATS */

+ 86 - 0
core/hdd/src/wlan_hdd_stats.h

@@ -31,6 +31,7 @@
 #ifdef WLAN_FEATURE_11BE_MLO
 #include "wlan_mlo_mgr_cmn.h"
 #endif
+#include <wlan_cp_stats_chipset_stats.h>
 
 #define INVALID_MCS_IDX 255
 
@@ -808,4 +809,89 @@ hdd_tx_latency_record_ingress_ts(struct hdd_adapter *adapter,
 #define FEATURE_TX_LATENCY_STATS_COMMANDS
 #define FEATURE_TX_LATENCY_STATS_EVENTS
 #endif
+
+#ifdef WLAN_CHIPSET_STATS
+/**
+ * hdd_cstats_send_data_to_userspace() - Send chipsset stats to userspace
+ *
+ * @buff: Buffer to be sent
+ * @len: length of the buffer
+ * @type: Chipset stats type
+ *
+ * Return: 0 on success -ve value on error
+ */
+int hdd_cstats_send_data_to_userspace(char *buff, unsigned int len,
+				      enum cstats_types type);
+
+/**
+ * hdd_register_cstats_ops() - Register chipset stats ops
+ *
+ * Return: void
+ */
+void hdd_register_cstats_ops(void);
+
+/**
+ * hdd_cstats_log_ndi_delete_req_evt() - Chipset stats for ndi delete
+ *
+ * @vdev: pointer to vdev object
+ * @transaction_id: transaction ID
+ *
+ * Return : void
+ */
+void hdd_cstats_log_ndi_delete_req_evt(struct wlan_objmgr_vdev *vdev,
+				       uint16_t transaction_id);
+
+/**
+ * hdd_cstats_log_ndi_create_resp_evt() - Chipset stats for ndi create
+ * response
+ * @li: pointer link_info object
+ * @ndi_rsp: pointer to nan_datapath_inf_create_rsp object
+ *
+ * Return : void
+ */
+void
+hdd_cstats_log_ndi_create_resp_evt(struct wlan_hdd_link_info *li,
+				   struct nan_datapath_inf_create_rsp *ndi_rsp);
+
+/**
+ * hdd_cstats_log_ndi_create_req_evt() - Chipset stats for ndi create
+ * request
+ *
+ * @vdev: pointer vdve object
+ * @transaction_id : Transaction ID
+ *
+ * Return : void
+ */
+void hdd_cstats_log_ndi_create_req_evt(struct wlan_objmgr_vdev *vdev,
+				       uint16_t transaction_id);
+#else
+static inline void hdd_register_cstats_ops(void)
+{
+}
+
+static inline int
+hdd_cstats_send_data_to_userspace(char *buff, unsigned int len,
+				  enum cstats_types type)
+{
+	return 0;
+}
+
+static inline void
+hdd_cstats_log_ndi_delete_req_evt(struct wlan_objmgr_vdev *vdev,
+				  uint16_t transaction_id)
+{
+}
+
+static inline void
+hdd_cstats_log_ndi_create_resp_evt(struct wlan_hdd_link_info *li,
+				   struct nan_datapath_inf_create_rsp *ndi_rsp)
+{
+}
+
+static inline void
+hdd_cstats_log_ndi_create_req_evt(struct wlan_objmgr_vdev *vdev,
+				  uint16_t transaction_id)
+{
+}
+#endif /* WLAN_CHIPSET_STATS */
 #endif /* end #if !defined(WLAN_HDD_STATS_H) */

+ 8 - 1
core/hdd/src/wlan_hdd_tx_power.c

@@ -345,7 +345,10 @@ next_link:
 
 	for (i = 0; i < num_of_links; i++) {
 		tpc_attr = nla_nest_start(reply_skb, i);
-
+		if (!tpc_attr) {
+			hdd_err("tpc_attr null, %d", i);
+			continue;
+		}
 		if (nla_put(reply_skb, QCA_WLAN_VENDOR_ATTR_TPC_BSSID,
 			    QDF_MAC_ADDR_SIZE, &link_bssid[i])) {
 			hdd_err("failed to put mac_addr");
@@ -402,6 +405,10 @@ next_link:
 		}
 		for (j = 0; j < reg_tpc_info[i].num_pwr_levels; j++) {
 			tpc_level = nla_nest_start(reply_skb, j);
+			if (!tpc_level) {
+				hdd_err("tpc_level null. level %d", j);
+				continue;
+			}
 			chan_power_info = &reg_tpc_info[i].chan_power_info[j];
 
 			attr_id = QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL_FREQUENCY;

+ 3 - 3
core/mac/inc/qwlan_version.h

@@ -32,9 +32,9 @@
 #define QWLAN_VERSION_MAJOR            5
 #define QWLAN_VERSION_MINOR            2
 #define QWLAN_VERSION_PATCH            1
-#define QWLAN_VERSION_EXTRA            "N"
-#define QWLAN_VERSION_BUILD            89
+#define QWLAN_VERSION_EXTRA            ""
+#define QWLAN_VERSION_BUILD            90
 
-#define QWLAN_VERSIONSTR               "5.2.1.89N"
+#define QWLAN_VERSIONSTR               "5.2.1.90"
 
 #endif /* QWLAN_VERSION_H */

+ 7 - 7
core/mac/src/pe/lim/lim_ft.c

@@ -393,7 +393,7 @@ static uint8_t lim_convert_phymode_to_dot11mode(enum wlan_phymode phymode)
 
 /**
  * lim_calculate_dot11_mode() - calculate dot11 mode.
- * @mac_context: mac context
+ * @mac_ctx: mac context
  * @bcn: beacon structure
  * @band: reg_wifi_band
  *
@@ -515,7 +515,7 @@ static void lim_fill_dot11mode(struct mac_context *mac_ctx,
 #if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD)
 /**
  * lim_fill_session_power_info() - to fill power info in session
- * @mac_ctx: pointer to mac ctx
+ * @mac: pointer to mac ctx
  * @pbssDescription: Pointer to pbssDescription
  * @ft_session: Pointer to FT session
  * @pe_session: Pointer to PE session
@@ -727,7 +727,7 @@ lim_fill_ft_session(struct mac_context *mac,
 	if (ft_session->htRecommendedTxWidthSet) {
 		ft_session->ch_width = CH_WIDTH_40MHZ;
 		if (ft_session->vhtCapabilityPresentInBeacon &&
-				pBeaconStruct->VHTOperation.chanWidth) {
+		    pBeaconStruct->VHTOperation.chanWidth) {
 			ft_session->ch_width =
 				pBeaconStruct->VHTOperation.chanWidth + 1;
 			ft_session->ch_center_freq_seg0 =
@@ -735,13 +735,13 @@ lim_fill_ft_session(struct mac_context *mac,
 			ft_session->ch_center_freq_seg1 =
 			pBeaconStruct->VHTOperation.chan_center_freq_seg1;
 		} else if (ft_session->vhtCapabilityPresentInBeacon &&
-			   pBeaconStruct->vendor_vht_ie.VHTOperation.chanWidth){
+			   pBeaconStruct->vendor_vht_ie.VHTOperation.chanWidth) {
 			ft_session->ch_width =
-			pBeaconStruct->vendor_vht_ie.VHTOperation.chanWidth + 1;
+				pBeaconStruct->vendor_vht_ie.VHTOperation.chanWidth + 1;
 			ft_session->ch_center_freq_seg0 =
-		pBeaconStruct->vendor_vht_ie.VHTOperation.chan_center_freq_seg0;
+				pBeaconStruct->vendor_vht_ie.VHTOperation.chan_center_freq_seg0;
 			ft_session->ch_center_freq_seg1 =
-		pBeaconStruct->vendor_vht_ie.VHTOperation.chan_center_freq_seg1;
+				pBeaconStruct->vendor_vht_ie.VHTOperation.chan_center_freq_seg1;
 
 		} else {
 			if (pBeaconStruct->HTInfo.secondaryChannelOffset ==

+ 16 - 0
core/mac/src/pe/lim/lim_process_assoc_req_frame.c

@@ -2863,6 +2863,22 @@ void lim_process_assoc_req_frame(struct mac_context *mac_ctx,
 	lim_proc_assoc_req_frm_cmn(mac_ctx, sub_type, session, hdr->sa,
 				   assoc_req, 0);
 
+	if (sub_type == LIM_ASSOC) {
+		lim_cp_stats_cstats_log_assoc_req_evt
+			(session, CSTATS_DIR_RX, hdr->bssId, hdr->sa,
+			 assoc_req->ssId.length, assoc_req->ssId.ssId,
+			 assoc_req->HTCaps.present, assoc_req->VHTCaps.present,
+			 assoc_req->he_cap.present, assoc_req->eht_cap.present,
+			 false);
+	} else if (sub_type == LIM_REASSOC) {
+		lim_cp_stats_cstats_log_assoc_req_evt
+			(session, CSTATS_DIR_RX, hdr->bssId, hdr->sa,
+			 assoc_req->ssId.length, assoc_req->ssId.ssId,
+			 assoc_req->HTCaps.present, assoc_req->VHTCaps.present,
+			 assoc_req->he_cap.present, assoc_req->eht_cap.present,
+			 true);
+	}
+
 	return;
 error:
 	if (assoc_req) {

+ 16 - 0
core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c

@@ -1269,6 +1269,22 @@ lim_process_assoc_rsp_frame(struct mac_context *mac_ctx, uint8_t *rx_pkt_info,
 		return;
 	}
 
+	if (subtype == LIM_REASSOC) {
+		lim_cp_stats_cstats_log_assoc_resp_evt
+			(session_entry, CSTATS_DIR_RX, assoc_rsp->status_code,
+			 assoc_rsp->aid, hdr->bssId, hdr->da,
+			 assoc_rsp->HTCaps.present,
+			 assoc_rsp->VHTCaps.present, assoc_rsp->he_cap.present,
+			 assoc_rsp->eht_op.present, true);
+	} else if (subtype == LIM_ASSOC) {
+		lim_cp_stats_cstats_log_assoc_resp_evt
+			(session_entry, CSTATS_DIR_RX, assoc_rsp->status_code,
+			 assoc_rsp->aid, hdr->bssId, hdr->da,
+			 assoc_rsp->HTCaps.present,
+			 assoc_rsp->VHTCaps.present, assoc_rsp->he_cap.present,
+			 assoc_rsp->eht_op.present, false);
+	}
+
 	if (subtype != LIM_REASSOC) {
 		aid = assoc_rsp->aid & 0x3FFF;
 		wlan_connectivity_mgmt_event(mac_ctx->psoc,

+ 10 - 0
core/mac/src/pe/lim/lim_process_auth_frame.c

@@ -856,6 +856,10 @@ static void lim_process_sae_auth_frame(struct mac_context *mac_ctx,
 				auth_algo, sae_auth_seq, sae_auth_seq, 0,
 				WLAN_AUTH_RESP);
 
+		lim_cp_stats_cstats_log_auth_evt(pe_session, CSTATS_DIR_RX,
+						 auth_algo, sae_auth_seq,
+						 sae_status_code);
+
 		status = lim_update_link_to_mld_address(mac_ctx,
 							pe_session->vdev,
 							mac_hdr);
@@ -2115,6 +2119,12 @@ lim_process_auth_frame(struct mac_context *mac_ctx, uint8_t *rx_pkt_info,
 				     auth_alg, 0,
 				     rx_auth_frm_body->authTransactionSeqNumber,
 				     0, WLAN_AUTH_RESP);
+
+	lim_cp_stats_cstats_log_auth_evt
+			(pe_session, CSTATS_DIR_RX, auth_alg,
+			 rx_auth_frm_body->authTransactionSeqNumber,
+			 rx_auth_frm_body->authStatusCode);
+
 	switch (rx_auth_frm_body->authTransactionSeqNumber) {
 	case SIR_MAC_AUTH_FRAME_1:
 		lim_process_auth_frame_type1(mac_ctx,

+ 3 - 0
core/mac/src/pe/lim/lim_process_deauth_frame.c

@@ -165,6 +165,9 @@ lim_process_deauth_frame(struct mac_context *mac, uint8_t *pRxPacketInfo,
 	lim_diag_event_report(mac, WLAN_PE_DIAG_DEAUTH_FRAME_EVENT,
 		pe_session, 0, reasonCode);
 
+	lim_cp_stats_cstats_log_deauth_evt(pe_session, CSTATS_DIR_RX,
+					   reasonCode);
+
 	if (lim_check_disassoc_deauth_ack_pending(mac, (uint8_t *) pHdr->sa)) {
 		pe_debug("Ignore the Deauth received, while waiting for ack of "
 			"disassoc/deauth");

+ 3 - 0
core/mac/src/pe/lim/lim_process_disassoc_frame.c

@@ -162,6 +162,9 @@ lim_process_disassoc_frame(struct mac_context *mac, uint8_t *pRxPacketInfo,
 	lim_diag_event_report(mac, WLAN_PE_DIAG_DISASSOC_FRAME_EVENT,
 		pe_session, 0, reasonCode);
 
+	lim_cp_stats_cstats_log_disassoc_evt(pe_session, CSTATS_DIR_RX,
+					     reasonCode);
+
 	/**
 	 * Extract 'associated' context for STA, if any.
 	 * This is maintained by DPH and created by LIM.

+ 12 - 0
core/mac/src/pe/lim/lim_process_tdls.c

@@ -802,6 +802,8 @@ static QDF_STATUS lim_send_tdls_dis_req_frame(struct mac_context *mac,
 		nPayload += mlo_ie_len;
 	}
 
+	lim_cp_stats_cstats_log_disc_req_evt(tdls_dis_req, pe_session);
+
 	qdf_mem_free(tdls_dis_req);
 
 #ifndef NO_PAD_TDLS_MIN_8023_SIZE
@@ -1837,6 +1839,8 @@ static QDF_STATUS lim_send_tdls_dis_rsp_frame(struct mac_context *mac,
 		nPayload += mlo_ie_len;
 	}
 
+	lim_cp_stats_cstats_log_disc_resp_evt(tdls_dis_rsp, pe_session);
+
 	qdf_mem_free(tdls_dis_rsp);
 
 	if (0 != addIeLen) {
@@ -2250,6 +2254,8 @@ QDF_STATUS lim_send_tdls_link_setup_req_frame(struct mac_context *mac,
 			status);
 	}
 
+	lim_cp_stats_cstats_log_setup_req_evt(tdls_setup_req, pe_session);
+
 	qdf_mem_free(tdls_setup_req);
 
 	/* Copy the additional IE. */
@@ -2471,6 +2477,8 @@ QDF_STATUS lim_send_tdls_teardown_frame(struct mac_context *mac,
 			status);
 	}
 
+	lim_cp_stats_cstats_log_tear_down_evt(teardown, pe_session);
+
 	qdf_mem_free(teardown);
 
 	if (addIeLen != 0) {
@@ -2779,6 +2787,8 @@ lim_send_tdls_setup_rsp_frame(struct mac_context *mac,
 			status);
 	}
 
+	lim_cp_stats_cstats_log_setup_resp_evt(setup_rsp, pe_session);
+
 	qdf_mem_free(setup_rsp);
 
 	/* Copy the additional IE. */
@@ -3022,6 +3032,8 @@ QDF_STATUS lim_send_tdls_link_setup_cnf_frame(struct mac_context *mac,
 			status);
 	}
 
+	lim_cp_stats_cstats_log_setup_confirm_evt(setup_cnf, pe_session);
+
 	qdf_mem_free(setup_cnf);
 
 	/* Copy the additional IE. */

+ 23 - 28
core/mac/src/pe/lim/lim_prop_exts_utils.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2024 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
@@ -339,8 +339,8 @@ void lim_update_he_mcs_12_13_map(struct wlan_objmgr_psoc *psoc,
 #endif
 
 #ifdef WLAN_FEATURE_11BE
-static void lim_extract_eht_op(struct pe_session *session,
-			       tSirProbeRespBeacon *beacon_struct)
+void lim_extract_eht_op(struct pe_session *session,
+			tSirProbeRespBeacon *beacon_struct)
 {
 	uint32_t max_eht_bw;
 
@@ -405,11 +405,6 @@ void lim_update_eht_bw_cap_mcs(struct pe_session *session,
 			session->eht_config.num_sounding_dim_320mhz = 0;
 	}
 }
-#else
-static void lim_extract_eht_op(struct pe_session *session,
-			       tSirProbeRespBeacon *beacon_struct)
-{
-}
 #endif
 
 #ifdef WLAN_FEATURE_11BE_MLO
@@ -598,6 +593,7 @@ void lim_extract_ap_capability(struct mac_context *mac_ctx, uint8_t *p_ie,
 	uint8_t channel = 0;
 	uint8_t sta_prefer_80mhz_over_160mhz;
 	struct mlme_vht_capabilities_info *mlme_vht_cap;
+	QDF_STATUS status;
 
 	beacon_struct = qdf_mem_malloc(sizeof(tSirProbeRespBeacon));
 	if (!beacon_struct)
@@ -608,8 +604,9 @@ void lim_extract_ap_capability(struct mac_context *mac_ctx, uint8_t *p_ie,
 	sta_prefer_80mhz_over_160mhz =
 		session->mac_ctx->mlme_cfg->sta.sta_prefer_80mhz_over_160mhz;
 
-	if (sir_parse_beacon_ie(mac_ctx, beacon_struct, p_ie,
-		(uint32_t) ie_len) != QDF_STATUS_SUCCESS) {
+	status = sir_parse_beacon_ie(mac_ctx, beacon_struct, p_ie,
+				     (uint32_t)ie_len);
+	if (QDF_IS_STATUS_ERROR(status)) {
 		pe_err("sir_parse_beacon_ie failed to parse beacon");
 		qdf_mem_free(beacon_struct);
 		return;
@@ -620,9 +617,10 @@ void lim_extract_ap_capability(struct mac_context *mac_ctx, uint8_t *p_ie,
 	    beacon_struct->wmeEdcaPresent ||
 	    beacon_struct->HTCaps.present)
 		LIM_BSS_CAPS_SET(WME, *qos_cap);
-	if (LIM_BSS_CAPS_GET(WME, *qos_cap)
-			&& beacon_struct->wsmCapablePresent)
+
+	if (LIM_BSS_CAPS_GET(WME, *qos_cap) && beacon_struct->wsmCapablePresent)
 		LIM_BSS_CAPS_SET(WSM, *qos_cap);
+
 	if (beacon_struct->HTCaps.present)
 		mac_ctx->lim.htCapabilityPresentInBeacon = 1;
 	else
@@ -630,10 +628,10 @@ void lim_extract_ap_capability(struct mac_context *mac_ctx, uint8_t *p_ie,
 
 	vht_op = &beacon_struct->VHTOperation;
 	vht_caps = &beacon_struct->VHTCaps;
-	if (IS_BSS_VHT_CAPABLE(beacon_struct->VHTCaps) &&
-			vht_op->present &&
-			session->vhtCapability) {
+	if (IS_BSS_VHT_CAPABLE(beacon_struct->VHTCaps) && vht_op->present &&
+	    session->vhtCapability) {
 		session->vhtCapabilityPresentInBeacon = 1;
+
 		if (((beacon_struct->Vendor1IEPresent &&
 		      beacon_struct->vendor_vht_ie.present &&
 		      beacon_struct->Vendor3IEPresent)) &&
@@ -647,7 +645,7 @@ void lim_extract_ap_capability(struct mac_context *mac_ctx, uint8_t *p_ie,
 	}
 
 	if (session->vhtCapabilityPresentInBeacon == 1 &&
-			!session->htSupportedChannelWidthSet) {
+	    !session->htSupportedChannelWidthSet) {
 		if (!mac_ctx->mlme_cfg->vht_caps.vht_cap_info.enable_txbf_20mhz)
 			session->vht_config.su_beam_formee = 0;
 
@@ -658,8 +656,7 @@ void lim_extract_ap_capability(struct mac_context *mac_ctx, uint8_t *p_ie,
 					mac_ctx, session,
 					beacon_struct->chan_freq);
 
-	} else if (session->vhtCapabilityPresentInBeacon &&
-			vht_op->chanWidth) {
+	} else if (session->vhtCapabilityPresentInBeacon && vht_op->chanWidth) {
 		/* If VHT is supported min 80 MHz support is must */
 		ap_bcon_ch_width = vht_op->chanWidth;
 		if (vht_caps->vht_extended_nss_bw_cap) {
@@ -707,8 +704,7 @@ void lim_extract_ap_capability(struct mac_context *mac_ctx, uint8_t *p_ie,
 				vht_ch_wd =
 					WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ;
 			else
-				vht_ch_wd =
-					WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ;
+				vht_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ;
 		}
 		/*
 		 * If the supported channel width is greater than 80MHz and
@@ -774,12 +770,11 @@ void lim_extract_ap_capability(struct mac_context *mac_ctx, uint8_t *p_ie,
 		session->ap_ch_width = session->ch_width;
 	}
 
-	if (session->vhtCapability &&
-		session->vhtCapabilityPresentInBeacon &&
-		beacon_struct->ext_cap.present) {
+	if (session->vhtCapability && session->vhtCapabilityPresentInBeacon &&
+	    beacon_struct->ext_cap.present) {
 		ext_cap = (struct s_ext_cap *)beacon_struct->ext_cap.bytes;
 		session->gLimOperatingMode.present =
-			ext_cap->oper_mode_notification;
+					ext_cap->oper_mode_notification;
 		if (ext_cap->oper_mode_notification) {
 			uint8_t self_nss = 0;
 
@@ -798,13 +793,12 @@ void lim_extract_ap_capability(struct mac_context *mac_ctx, uint8_t *p_ie,
 			 *  WFA CERT test scenario.
 			 */
 			if (ext_cap->beacon_protection_enable &&
-			    (session->opmode == QDF_STA_MODE) &&
-			    (!session->nss_forced_1x1) &&
+			    session->opmode == QDF_STA_MODE &&
+			    !session->nss_forced_1x1 &&
 			     lim_get_nss_supported_by_ap(
 					&beacon_struct->VHTCaps,
 					&beacon_struct->HTCaps,
-					&beacon_struct->he_cap) ==
-						 NSS_1x1_MODE)
+					&beacon_struct->he_cap) == NSS_1x1_MODE)
 				session->gLimOperatingMode.rxNSS = self_nss - 1;
 			else
 				session->gLimOperatingMode.rxNSS =
@@ -813,6 +807,7 @@ void lim_extract_ap_capability(struct mac_context *mac_ctx, uint8_t *p_ie,
 			pe_err("AP does not support op_mode rx");
 		}
 	}
+
 	lim_check_is_he_mcs_valid(session, beacon_struct);
 	lim_check_peer_ldpc_and_update(session, beacon_struct);
 	lim_extract_he_op(session, beacon_struct);

+ 19 - 1
core/mac/src/pe/lim/lim_prop_exts_utils.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2011-2014, 2016, 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022, 2024 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
@@ -57,6 +57,24 @@ lim_extract_ap_capability(struct mac_context *mac_ctx, uint8_t *p_ie,
 			  int8_t *local_constraint, struct pe_session *session,
 			  bool *is_pwr_constraint);
 
+#ifdef WLAN_FEATURE_11BE
+/**
+ * lim_extract_eht_op() - Extract EHT operation IE into session
+ * @session: Pointer to pe_session
+ * @beacon_struct: Pointer to extracted beacon/probe response of the
+ * AP
+ *
+ * Return: None
+ */
+void lim_extract_eht_op(struct pe_session *session,
+			tSirProbeRespBeacon *beacon_struct);
+#else
+static inline void
+lim_extract_eht_op(struct pe_session *session,
+		   tSirProbeRespBeacon *beacon_struct)
+{}
+#endif
+
 ePhyChanBondState lim_get_htcb_state(ePhyChanBondState aniCBMode);
 
 /**

+ 10 - 1
core/mac/src/pe/lim/lim_send_frames_host_roam.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2024 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
@@ -897,6 +897,15 @@ void lim_send_reassoc_req_mgmt_frame(struct mac_context *mac,
 		pe_warn("warning packing a Re-AssocReq: (0x%08x)", nStatus);
 	}
 
+	lim_cp_stats_cstats_log_assoc_req_evt(pe_session, CSTATS_DIR_TX,
+					      pMacHdr->bssId, pMacHdr->sa,
+					      frm->SSID.num_ssid,
+					      frm->SSID.ssid,
+					      frm->HTCaps.present,
+					      frm->VHTCaps.present,
+					      frm->he_cap.present,
+					      frm->eht_cap.present, true);
+
 	pe_debug("*** Sending Re-Association Request length: %d" "to", nBytes);
 
 	if (pe_session->assoc_req) {

+ 26 - 0
core/mac/src/pe/lim/lim_send_management_frames.c

@@ -1921,6 +1921,13 @@ lim_send_assoc_rsp_mgmt_frame(struct mac_context *mac_ctx,
 		      frm.vendor_vht_ie.present, frm.he_cap.present,
 		      frm.eht_cap.present);
 
+	lim_cp_stats_cstats_log_assoc_resp_evt(pe_session, CSTATS_DIR_TX,
+					       status_code, aid, mac_hdr->bssId,
+					       mac_hdr->da, frm.HTCaps.present,
+					       frm.VHTCaps.present,
+					       frm.he_cap.present,
+					       frm.eht_cap.present, false);
+
 	if (!wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq) ||
 	    pe_session->opmode == QDF_P2P_CLIENT_MODE ||
 	    pe_session->opmode == QDF_P2P_GO_MODE)
@@ -2174,6 +2181,9 @@ static void wlan_send_tx_complete_event(struct mac_context *mac, qdf_nbuf_t buf,
 					mac_hdr, params->vdev_id, status,
 					qdf_tx_complete, mac->lim.bss_rssi,
 					algo, type, seq, 0, WLAN_AUTH_REQ);
+			lim_cp_stats_cstats_log_auth_evt(pe_session,
+							 CSTATS_DIR_TX, algo,
+							 seq, status);
 			return;
 		}
 
@@ -3061,6 +3071,16 @@ lim_send_assoc_req_mgmt_frame(struct mac_context *mac_ctx,
 		     pe_session->vdev_id, QDF_MAC_ADDR_REF(pe_session->bssId),
 		     mac_ctx->mgmtSeqNum);
 
+	lim_cp_stats_cstats_log_assoc_req_evt(pe_session, CSTATS_DIR_TX,
+					      pe_session->bssId,
+					      mac_hdr->sa,
+					      frm->SSID.num_ssid,
+					      frm->SSID.ssid,
+					      frm->HTCaps.present,
+					      frm->VHTCaps.present,
+					      frm->he_cap.present,
+					      frm->eht_cap.present, false);
+
 	min_rid = lim_get_min_session_txrate(pe_session, NULL);
 	lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_ASSOC_START_EVENT,
 			      pe_session, QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS);
@@ -4360,6 +4380,9 @@ lim_send_disassoc_mgmt_frame(struct mac_context *mac,
 					     mac->lim.bss_rssi, 0, 0, 0, 0,
 					     WLAN_DISASSOC_TX);
 
+		lim_cp_stats_cstats_log_disassoc_evt(pe_session, CSTATS_DIR_TX,
+						     nReason);
+
 		/* Queue Disassociation frame in high priority WQ */
 		qdf_status = wma_tx_frame(mac, pPacket, (uint16_t) nBytes,
 					TXRX_FRM_802_11_MGMT,
@@ -4623,6 +4646,9 @@ lim_send_deauth_mgmt_frame(struct mac_context *mac,
 					     mac->lim.bss_rssi, 0, 0, 0, 0,
 					     WLAN_DEAUTH_TX);
 
+		lim_cp_stats_cstats_log_deauth_evt(pe_session, CSTATS_DIR_TX,
+						   nReason);
+
 		/* Queue Disassociation frame in high priority WQ */
 		qdf_status =
 			wma_tx_frame(mac, pPacket, (uint16_t) nBytes,

+ 1 - 1
core/mac/src/pe/lim/lim_send_sme_rsp_messages.c

@@ -2345,7 +2345,7 @@ void lim_handle_sta_csa_param(struct mac_context *mac_ctx,
 	if (mac_ctx->lim.stop_roaming_callback)
 		mac_ctx->lim.stop_roaming_callback(MAC_HANDLE(mac_ctx),
 						   session_entry->smeSessionId,
-						   REASON_DRIVER_DISABLED,
+						   REASON_VDEV_RESTART_FROM_HOST,
 						   RSO_CHANNEL_SWITCH);
 
 	if (mlo_is_any_link_disconnecting(session_entry->vdev)) {

+ 352 - 0
core/mac/src/pe/lim/lim_utils.c

@@ -11849,3 +11849,355 @@ rel_vdev:
 		}
 	}
 }
+
+#ifdef WLAN_CHIPSET_STATS
+void lim_cp_stats_cstats_log_assoc_resp_evt(struct pe_session *session_entry,
+					    enum cstats_dir dir,
+					    uint16_t status_code, uint16_t aid,
+					    uint8_t *bssid, uint8_t *da,
+					    bool is_ht, bool is_vht,
+					    bool is_he, bool is_eht,
+					    bool is_reassoc)
+{
+	struct cstats_assoc_resp_mgmt_frm stat = {0};
+
+	if (is_reassoc) {
+		stat.cmn.hdr.evt_id =
+				WLAN_CHIPSET_STATS_MGMT_REASSOC_RESP_EVENT_ID;
+	} else {
+		stat.cmn.hdr.evt_id =
+			WLAN_CHIPSET_STATS_MGMT_ASSOC_RESP_EVENT_ID;
+	}
+
+	stat.cmn.hdr.length = sizeof(struct cstats_assoc_resp_mgmt_frm) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.vdev_id = session_entry->vdev_id;
+	stat.cmn.opmode = session_entry->opmode;
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+
+	stat.direction = dir;
+	stat.status_code = status_code;
+	stat.aid = aid;
+
+	if (is_ht)
+		CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HT);
+
+	if (is_vht)
+		CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_VHT);
+
+	if (is_he)
+		CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HE);
+
+	if (is_eht)
+		CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_EHT);
+
+	CSTATS_MAC_COPY(stat.bssid, bssid);
+	CSTATS_MAC_COPY(stat.dest_mac, da);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_assoc_resp_mgmt_frm),
+			       &stat);
+}
+
+void
+lim_cp_stats_cstats_log_auth_evt(struct pe_session *pe_session,
+				 enum cstats_dir dir, uint16_t algo,
+				 uint16_t seq, uint16_t status)
+{
+	struct cstats_auth_mgmt_frm stat = {0};
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_MGMT_AUTH_EVENT_ID;
+	stat.cmn.hdr.length =
+		sizeof(struct cstats_auth_mgmt_frm) -
+		sizeof(struct cstats_hdr);
+	stat.cmn.opmode = pe_session->opmode;
+	stat.cmn.vdev_id = pe_session->vdev_id;
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+
+	stat.direction = dir;
+	stat.auth_algo = algo;
+	stat.auth_seq_num = seq;
+	stat.status = status;
+
+	wlan_cstats_host_stats(sizeof(struct cstats_auth_mgmt_frm), &stat);
+}
+
+void lim_cp_stats_cstats_log_deauth_evt(struct pe_session *pe_session,
+					enum cstats_dir dir,
+					uint16_t reasonCode)
+{
+	struct cstats_deauth_mgmt_frm stat = {0};
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_MGMT_DEAUTH_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_deauth_mgmt_frm) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = pe_session->opmode;
+	stat.cmn.vdev_id = pe_session->vdev_id;
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+
+	stat.reason = reasonCode;
+	stat.direction = dir;
+
+	wlan_cstats_host_stats(sizeof(struct cstats_deauth_mgmt_frm), &stat);
+}
+
+void lim_cp_stats_cstats_log_disassoc_evt(struct pe_session *pe_session,
+					  enum cstats_dir dir,
+					  uint16_t reasonCode)
+{
+	struct cstats_disassoc_mgmt_frm stat = {0};
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_MGMT_DISASSOC_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_disassoc_mgmt_frm) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = pe_session->opmode;
+	stat.cmn.vdev_id = pe_session->vdev_id;
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+
+	stat.reason = reasonCode;
+	stat.direction = dir;
+
+	wlan_cstats_host_stats(sizeof(struct cstats_disassoc_mgmt_frm), &stat);
+}
+
+void lim_cp_stats_cstats_log_assoc_req_evt(struct pe_session *pe_session,
+					   enum cstats_dir dir,
+					   uint8_t *bssid, uint8_t *sa,
+					   uint8_t ssid_len, uint8_t *ssid,
+					   bool is_ht, bool is_vht, bool is_he,
+					   bool is_eht, bool is_reassoc)
+{
+	struct cstats_assoc_req_mgmt_frm stat = {0};
+
+	if (is_reassoc) {
+		stat.cmn.hdr.evt_id =
+				WLAN_CHIPSET_STATS_MGMT_REASSOC_REQ_EVENT_ID;
+	} else {
+		stat.cmn.hdr.evt_id =
+				WLAN_CHIPSET_STATS_MGMT_ASSOC_REQ_EVENT_ID;
+	}
+
+	stat.cmn.hdr.length = sizeof(struct cstats_assoc_req_mgmt_frm) -
+			      sizeof(struct cstats_hdr);
+
+	stat.cmn.opmode = pe_session->opmode;
+	stat.cmn.vdev_id = pe_session->vdev_id;
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+
+	stat.freq = pe_session->curr_op_freq;
+	stat.ssid_len = ssid_len;
+	qdf_mem_copy(stat.ssid, ssid, ssid_len);
+
+	stat.direction = dir;
+	CSTATS_MAC_COPY(stat.bssid, bssid);
+	CSTATS_MAC_COPY(stat.sa, sa);
+
+	if (is_ht)
+		CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HT);
+
+	if (is_vht)
+		CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_VHT);
+
+	if (is_he)
+		CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HE);
+
+	if (is_eht)
+		CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_EHT);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_assoc_req_mgmt_frm), &stat);
+}
+
+void lim_cp_stats_cstats_log_disc_req_evt(tDot11fTDLSDisReq *frm,
+					  struct pe_session *pe_session)
+{
+	struct cstats_tdls_disc_req stat = {0};
+
+	stat.cmn.hdr.evt_id =
+			WLAN_CHIPSET_STATS_STA_TDLS_DISCOVERY_REQ_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_tdls_disc_req) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = pe_session->opmode;
+	stat.cmn.vdev_id = pe_session->vdev_id;
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.act_category = frm->Category.category;
+	stat.act = frm->Action.action;
+	stat.dt = frm->DialogToken.token;
+	stat.direction = CSTATS_DIR_TX;
+
+	CSTATS_MAC_COPY(stat.init_sta_addr, frm->LinkIdentifier.InitStaAddr);
+	CSTATS_MAC_COPY(stat.bssid, frm->LinkIdentifier.bssid);
+	CSTATS_MAC_COPY(stat.resp_sta_addr, frm->LinkIdentifier.RespStaAddr);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_tdls_disc_req), &stat);
+}
+
+void lim_cp_stats_cstats_log_disc_resp_evt(tDot11fTDLSDisRsp *frm,
+					   struct pe_session *pe_session)
+{
+	struct cstats_tdls_disc_resp stat = {0};
+
+	stat.cmn.hdr.evt_id =
+			WLAN_CHIPSET_STATS_STA_TDLS_DISCOVERY_RESP_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_tdls_disc_resp) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = pe_session->opmode;
+	stat.cmn.vdev_id = pe_session->vdev_id;
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+
+	stat.act_category = frm->Category.category;
+	stat.act = frm->Action.action;
+	stat.dt = frm->DialogToken.token;
+	stat.direction = CSTATS_DIR_TX;
+
+	if (frm->HTCaps.present)
+		CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HT);
+
+	if (frm->VHTCaps.present)
+		CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_VHT);
+
+	if (frm->he_cap.present)
+		CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HE);
+
+	CSTATS_MAC_COPY(stat.init_sta_addr, frm->LinkIdentifier.InitStaAddr);
+	CSTATS_MAC_COPY(stat.bssid, frm->LinkIdentifier.bssid);
+	CSTATS_MAC_COPY(stat.resp_sta_addr, frm->LinkIdentifier.RespStaAddr);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_tdls_disc_resp), &stat);
+}
+
+void lim_cp_stats_cstats_log_setup_req_evt(tDot11fTDLSSetupReq *frm,
+					   struct pe_session *pe_session)
+{
+	struct cstats_tdls_setup_req stat = {0};
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_STA_TDLS_SETUP_REQ_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_tdls_setup_req) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = pe_session->opmode;
+	stat.cmn.vdev_id = pe_session->vdev_id;
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+
+	stat.act_category = frm->Category.category;
+	stat.act = frm->Action.action;
+	stat.dt = frm->DialogToken.token;
+	stat.direction = CSTATS_DIR_TX;
+
+	if (frm->HTCaps.present)
+		CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HT);
+
+	if (frm->VHTCaps.present)
+		CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_VHT);
+
+	if (frm->he_cap.present)
+		CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HE);
+
+	CSTATS_MAC_COPY(stat.init_sta_addr, frm->LinkIdentifier.InitStaAddr);
+	CSTATS_MAC_COPY(stat.bssid, frm->LinkIdentifier.bssid);
+	CSTATS_MAC_COPY(stat.resp_sta_addr, frm->LinkIdentifier.RespStaAddr);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_tdls_setup_req), &stat);
+}
+
+void
+lim_cp_stats_cstats_log_setup_resp_evt(tDot11fTDLSSetupRsp *frm,
+				       struct pe_session *pe_session)
+{
+	struct cstats_tdls_setup_resp stat = {0};
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_STA_TDLS_SETUP_RESP_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_tdls_setup_resp) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = pe_session->opmode;
+	stat.cmn.vdev_id = pe_session->vdev_id;
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+
+	stat.act_category = frm->Category.category;
+	stat.act = frm->Action.action;
+	stat.dt = frm->DialogToken.token;
+	stat.direction = CSTATS_DIR_TX;
+
+	if (frm->HTCaps.present)
+		CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HT);
+
+	if (frm->VHTCaps.present)
+		CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_VHT);
+
+	if (frm->he_cap.present)
+		CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HE);
+
+	stat.status = frm->Status.status;
+
+	CSTATS_MAC_COPY(stat.init_sta_addr, frm->LinkIdentifier.InitStaAddr);
+	CSTATS_MAC_COPY(stat.bssid, frm->LinkIdentifier.bssid);
+	CSTATS_MAC_COPY(stat.resp_sta_addr, frm->LinkIdentifier.RespStaAddr);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_tdls_setup_resp), &stat);
+}
+
+void
+lim_cp_stats_cstats_log_setup_confirm_evt(tDot11fTDLSSetupCnf *frm,
+					  struct pe_session *pe_session)
+{
+	struct cstats_tdls_setup_confirm stat = {0};
+
+	stat.cmn.hdr.evt_id =
+			     WLAN_CHIPSET_STATS_STA_TDLS_SETUP_CONFIRM_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_tdls_setup_confirm) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = pe_session->opmode;
+	stat.cmn.vdev_id = pe_session->vdev_id;
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+
+	stat.act_category = frm->Category.category;
+	stat.act = frm->Action.action;
+	stat.dt = frm->DialogToken.token;
+	stat.direction = CSTATS_DIR_TX;
+
+	if (frm->HTInfo.present)
+		CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HT);
+
+	if (frm->VHTOperation.present)
+		CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_VHT);
+
+	if (frm->he_op.present)
+		CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HE);
+
+	stat.status = frm->Status.status;
+
+	CSTATS_MAC_COPY(stat.init_sta_addr, frm->LinkIdentifier.InitStaAddr);
+	CSTATS_MAC_COPY(stat.bssid, frm->LinkIdentifier.bssid);
+	CSTATS_MAC_COPY(stat.resp_sta_addr, frm->LinkIdentifier.RespStaAddr);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_tdls_setup_confirm), &stat);
+}
+
+void
+lim_cp_stats_cstats_log_tear_down_evt(tDot11fTDLSTeardown *frm,
+				      struct pe_session *pe_session)
+{
+	struct cstats_tdls_tear_down stat = {0};
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_STA_TDLS_TEARDOWN_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_tdls_setup_confirm) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = pe_session->opmode;
+	stat.cmn.vdev_id = pe_session->vdev_id;
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+
+	stat.act_category = frm->Category.category;
+	stat.act = frm->Action.action;
+	stat.direction = CSTATS_DIR_TX;
+
+	stat.reason = frm->Reason.code;
+
+	CSTATS_MAC_COPY(stat.init_sta_addr, frm->LinkIdentifier.InitStaAddr);
+	CSTATS_MAC_COPY(stat.bssid, frm->LinkIdentifier.bssid);
+	CSTATS_MAC_COPY(stat.resp_sta_addr, frm->LinkIdentifier.RespStaAddr);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_tdls_tear_down), &stat);
+}
+#endif /* WLAN_CHIPSET_STATS */

+ 234 - 0
core/mac/src/pe/lim/lim_utils.h

@@ -39,6 +39,7 @@
 #include "include/wlan_vdev_mlme.h"
 #include "wlan_mlme_vdev_mgr_interface.h"
 #include "wlan_qct_sys.h"
+#include <wlan_cp_stats_chipset_stats.h>
 
 #define LIM_QOS_AP_SUPPORTS_UAPSD         0x80
 
@@ -3401,4 +3402,237 @@ uint32_t lim_cmp_ssid(tSirMacSSid *ssid, struct pe_session *pe_session);
 void
 lim_configure_fd_for_existing_6ghz_sap(struct pe_session *session,
 				       bool is_sap_starting);
+
+#ifdef WLAN_CHIPSET_STATS
+/**
+ * lim_cp_stats_cstats_log_assoc_resp_evt() - Log chipset stats for assoc resp
+ *
+ * @session_entry: pointer to session object
+ * @dir: Direction
+ * @status_code: assoc/reassoc status
+ * @aid: association identifier
+ * @bssid: bssid
+ * @da: destination address
+ * @is_ht: is HT
+ * @is_vht: is VHT
+ * @is_he: is HE
+ * @is_eht: is EHT
+ * @is_reassoc: is reassoc frame
+ *
+ * Return : void
+ */
+void lim_cp_stats_cstats_log_assoc_resp_evt(struct pe_session *session_entry,
+					    enum cstats_dir dir,
+					    uint16_t status_code, uint16_t aid,
+					    uint8_t *bssid, uint8_t *da,
+					    bool is_ht, bool is_vht, bool is_he,
+					    bool is_eht, bool is_reassoc);
+
+/**
+ * lim_cp_stats_cstats_log_auth_evt() - Log chipset stats for auth frames
+ *
+ * @pe_session: pointer to session object
+ * @dir: direction
+ * @algo: auth algorithm
+ * @seq: auth sequence
+ * @status: Status
+ *
+ * Return : void
+ */
+void lim_cp_stats_cstats_log_auth_evt(struct pe_session *pe_session,
+				      enum cstats_dir dir, uint16_t algo,
+				      uint16_t seq, uint16_t status);
+
+/**
+ * lim_cp_stats_cstats_log_deauth_evt() - Log chipset stats for deauth frames
+ *
+ * @pe_session: pointer to session object
+ * @dir: direction
+ * @reasonCode: reason code
+ *
+ * Return : void
+ */
+void lim_cp_stats_cstats_log_deauth_evt(struct pe_session *pe_session,
+					enum cstats_dir dir,
+					uint16_t reasonCode);
+
+/**
+ * lim_cp_stats_cstats_log_disassoc_evt() - Log chipset stats for disassoc frm
+ *
+ * @pe_session: pointer to session object
+ * @dir: direction
+ * @reasonCode: reason code
+ *
+ * Return : void
+ */
+void lim_cp_stats_cstats_log_disassoc_evt(struct pe_session *pe_session,
+					  enum cstats_dir dir,
+					  uint16_t reasonCode);
+
+/**
+ * lim_cp_stats_cstats_log_assoc_req_evt() - Log chipset stats for assoc req frm
+ *
+ * @pe_session: pointer to session object
+ * @dir: Direction
+ * @bssid: bssid
+ * @sa: source addr
+ * @ssid_len: ssid length
+ * @ssid: ssid
+ * @is_ht: is HT
+ * @is_vht: is VHT
+ * @is_he: is HE
+ * @is_eht: is EHT
+ * @is_reassoc: is reassociation request
+ *
+ * Return : void
+ */
+void lim_cp_stats_cstats_log_assoc_req_evt(struct pe_session *pe_session,
+					   enum cstats_dir dir, uint8_t *bssid,
+					   uint8_t *sa, uint8_t ssid_len,
+					   uint8_t *ssid, bool is_ht,
+					   bool is_vht, bool is_he,
+					   bool is_eht, bool is_reassoc);
+
+/**
+ * lim_cp_stats_cstats_log_disc_req_evt() : chipset stats for TDLS disc req
+ *
+ * @frm: pointer to tDot11fTDLSDisReq
+ * @pe_session: pointer to session object
+ *
+ * Return: void
+ */
+void lim_cp_stats_cstats_log_disc_req_evt(tDot11fTDLSDisReq *frm,
+					  struct pe_session *pe_session);
+
+/**
+ * lim_cp_stats_cstats_log_disc_resp_evt() : chipset stats for TDLS disc resp
+ *
+ * @frm: pointer to tDot11fTDLSDisRsp
+ * @pe_session: pointer to session object
+ *
+ * Return: void
+ */
+void lim_cp_stats_cstats_log_disc_resp_evt(tDot11fTDLSDisRsp *frm,
+					   struct pe_session *pe_session);
+
+/**
+ * lim_cp_stats_cstats_log_setup_req_evt() : chipset stats for TDLS setup req
+ *
+ * @frm: pointer to tDot11fTDLSSetupReq
+ * @pe_session: pointer to session object
+ *
+ * Return: void
+ */
+void lim_cp_stats_cstats_log_setup_req_evt(tDot11fTDLSSetupReq *frm,
+					   struct pe_session *pe_session);
+
+/**
+ * lim_cp_stats_cstats_log_setup_resp_evt() : chipset stats for TDLS setup resp
+ *
+ * @frm: pointer to tDot11fTDLSSetupRsp
+ * @pe_session: pointer to session object
+ *
+ * Return: void
+ */
+void lim_cp_stats_cstats_log_setup_resp_evt(tDot11fTDLSSetupRsp *frm,
+					    struct pe_session *pe_session);
+
+/**
+ * lim_cp_stats_cstats_log_setup_confirm_evt() : chipset stats for TDLS setup
+ * confirm
+ *
+ * @frm: pointer to tDot11fTDLSSetupCnf
+ * @pe_session: pointer to session object
+ *
+ * Return: void
+ */
+void lim_cp_stats_cstats_log_setup_confirm_evt(tDot11fTDLSSetupCnf *frm,
+					       struct pe_session *pe_session);
+
+/**
+ * lim_cp_stats_cstats_log_tear_down_evt() : chipset stats for TDLS teardown
+ *
+ * @frm: pointer to tDot11fTDLSSetupCnf
+ * @pe_session: pointer to session object
+ *
+ * Return: void
+ */
+void lim_cp_stats_cstats_log_tear_down_evt(tDot11fTDLSTeardown *frm,
+					   struct pe_session *pe_session);
+#else
+static inline void
+lim_cp_stats_cstats_log_assoc_resp_evt(struct pe_session *session_entry,
+				       enum cstats_dir dir,
+				       uint16_t status_code, uint16_t aid,
+				       uint8_t *bssid, uint8_t *da,
+				       bool is_ht, bool is_vht, bool is_he,
+				       bool is_eht, bool is_reassoc)
+{
+}
+
+static inline void
+lim_cp_stats_cstats_log_auth_evt(struct pe_session *pe_session,
+				 enum cstats_dir dir, uint16_t algo,
+				 uint16_t seq, uint16_t status)
+{
+}
+
+static inline void
+lim_cp_stats_cstats_log_deauth_evt(struct pe_session *pe_session,
+				   enum cstats_dir dir, uint16_t reasonCode)
+{
+}
+
+static inline void
+lim_cp_stats_cstats_log_disassoc_evt(struct pe_session *pe_session,
+				     enum cstats_dir dir, uint16_t reasonCode)
+{
+}
+
+static inline void
+lim_cp_stats_cstats_log_assoc_req_evt(struct pe_session *pe_session,
+				      enum cstats_dir dir, uint8_t *bssid,
+				      uint8_t *sa, uint8_t ssid_len,
+				      uint8_t *ssid, bool is_ht,
+				      bool is_vht, bool is_he,
+				      bool is_eht, bool is_reassoc)
+{
+}
+
+static inline void
+lim_cp_stats_cstats_log_disc_req_evt(tDot11fTDLSDisReq *frm,
+				     struct pe_session *pe_session)
+{
+}
+
+static inline void
+lim_cp_stats_cstats_log_disc_resp_evt(tDot11fTDLSDisRsp *frm,
+				      struct pe_session *pe_session)
+{
+}
+
+static inline void
+lim_cp_stats_cstats_log_setup_req_evt(tDot11fTDLSSetupReq *frm,
+				      struct pe_session *pe_session)
+{
+}
+
+static inline void
+lim_cp_stats_cstats_log_setup_resp_evt(tDot11fTDLSSetupRsp *frm,
+				       struct pe_session *pe_session)
+{
+}
+
+static inline void
+lim_cp_stats_cstats_log_setup_confirm_evt(tDot11fTDLSSetupCnf *frm,
+					  struct pe_session *pe_session)
+{
+}
+
+static inline void
+lim_cp_stats_cstats_log_tear_down_evt(tDot11fTDLSTeardown *frm,
+				      struct pe_session *pe_session)
+{
+}
+#endif /* WLAN_CHIPSET_STATS */
 #endif /* __LIM_UTILS_H */

+ 16 - 1
core/pld/inc/pld_common.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 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
@@ -1638,6 +1638,21 @@ int pld_qmi_send(struct device *dev, int type, void *cmd,
 		 int cmd_len, void *cb_ctx,
 		 int (*cb)(void *ctx, void *event, int event_len));
 
+/**
+ * pld_qmi_indication() - Send data request over QMI
+ * @dev: device pointer
+ * @cb_ctx: context pointer if any to pass back in callback
+ * @cb: callback pointer to pass response back
+ *
+ * This API can be used to register for QMI events.
+ *
+ * Return: 0 if registration is successful
+ *         Non zero failure code for errors
+ */
+int pld_qmi_indication(struct device *dev, void *cb_ctx,
+		       int (*cb)(void *ctx, uint16_t type,
+				 void *event, int event_len));
+
 /**
  * pld_is_fw_dump_skipped() - get fw dump skipped status.
  * @dev: device

+ 21 - 1
core/pld/src/pld_common.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 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
@@ -2323,6 +2323,26 @@ int pld_qmi_send(struct device *dev, int type, void *cmd,
 	}
 }
 
+int pld_qmi_indication(struct device *dev, void *cb_ctx,
+		       int (*cb)(void *ctx, uint16_t type,
+				 void *event, int event_len))
+{
+	enum pld_bus_type bus_type = pld_get_bus_type(dev);
+
+	switch (bus_type) {
+	case PLD_BUS_TYPE_PCIE:
+		return pld_pcie_register_qmi_ind(dev, cb_ctx, cb);
+	case PLD_BUS_TYPE_SNOC:
+	case PLD_BUS_TYPE_SDIO:
+	case PLD_BUS_TYPE_USB:
+	case PLD_BUS_TYPE_IPCI:
+		return -EINVAL;
+	default:
+		pr_err("Invalid device type %d\n", bus_type);
+		return -EINVAL;
+	}
+}
+
 bool pld_is_fw_dump_skipped(struct device *dev)
 {
 	bool ret = false;

+ 27 - 1
core/pld/src/pld_pcie.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2024 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
@@ -451,6 +451,14 @@ pld_pcie_qmi_send(struct device *dev, int type, void *cmd,
 	return -EINVAL;
 }
 
+static inline int
+pld_pcie_register_qmi_ind(struct device *dev, void *cb_ctx,
+			  int (*cb)(void *ctx, uint16_t type,
+				    void *event, int event_len))
+{
+	return -EINVAL;
+}
+
 static inline int pld_pcie_get_user_msi_assignment(struct device *dev,
 						   char *user_name,
 						   int *num_vectors,
@@ -623,6 +631,24 @@ pld_pcie_qmi_send(struct device *dev, int type, void *cmd,
 	return cnss_qmi_send(dev, type, cmd, cmd_len, cb_ctx, cb);
 }
 
+#ifdef WLAN_CHIPSET_STATS
+static inline int
+pld_pcie_register_qmi_ind(struct device *dev, void *cb_ctx,
+			  int (*cb)(void *ctx, uint16_t type,
+				    void *event, int event_len))
+{
+	return cnss_register_driver_async_data_cb(dev, cb_ctx, cb);
+}
+#else
+static inline int
+pld_pcie_register_qmi_ind(struct device *dev, void *cb_ctx,
+			  int (*cb)(void *ctx, uint16_t type,
+				    void *event, int event_len))
+{
+	return 0;
+}
+#endif
+
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0))
 static inline void *pld_pcie_smmu_get_domain(struct device *dev)
 {

+ 9 - 2
core/sme/src/common/sme_api.c

@@ -89,6 +89,7 @@
 #include "wlan_policy_mgr_ll_sap.h"
 #include "wlan_vdev_mgr_ucfg_api.h"
 #include "wlan_vdev_mlme_main.h"
+#include "wlan_tdls_api.h"
 
 static QDF_STATUS init_sme_cmd_list(struct mac_context *mac);
 
@@ -4780,7 +4781,7 @@ sme_nss_chains_update(mac_handle_t mac_handle,
 		      uint8_t vdev_id)
 {
 	struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle);
-	QDF_STATUS status;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
 	struct wlan_mlme_nss_chains *dynamic_cfg;
 	struct wlan_objmgr_vdev *vdev =
 		       wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc,
@@ -4798,7 +4799,13 @@ sme_nss_chains_update(mac_handle_t mac_handle,
 	if (ll_lt_sap_vdev_id != WLAN_INVALID_VDEV_ID) {
 		sme_info_rl("LL_LT_SAP vdev %d present, chainmask config not allowed",
 			    ll_lt_sap_vdev_id);
-		return QDF_STATUS_E_FAILURE;
+		goto release_ref;
+	}
+
+	if (QDF_STATUS_SUCCESS == wlan_is_tdls_session_present(vdev)) {
+		sme_debug("TDLS session exists");
+		status = QDF_STATUS_E_FAILURE;
+		goto release_ref;
 	}
 
 	status = sme_acquire_global_lock(&mac_ctx->sme);

+ 5 - 0
core/wma/src/wma_features.c

@@ -3231,6 +3231,11 @@ static QDF_STATUS wma_wow_pagefault_action_cb(void *buf)
 {
 	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
 
+	if (!mac) {
+		wma_err("NULL mac ptr");
+		return QDF_STATUS_E_INVAL;
+	}
+
 	return mac->sme.pagefault_action_cb(buf, WLAN_WMA_PF_APPS_NOTIFY_BUF_LEN);
 }
 

+ 3 - 1
core/wma/src/wma_mgmt.c

@@ -873,7 +873,9 @@ void wma_set_sta_keep_alive(tp_wma_handle wma, uint8_t vdev_id,
 	params.timeperiod = timeperiod;
 	if (intr) {
 		if (intr->bss_max_idle_period) {
-			params.timeperiod = intr->bss_max_idle_period;
+			if (intr->bss_max_idle_period < timeperiod)
+				params.timeperiod = intr->bss_max_idle_period;
+
 			if (method == WMI_KEEP_ALIVE_NULL_PKT)
 				params.method = WMI_KEEP_ALIVE_MGMT_FRAME;
 		}

+ 222 - 1
os_if/nan/inc/os_if_nan.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022,2024 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
@@ -29,6 +29,7 @@
 #include "nan_public_structs.h"
 #include "nan_ucfg_api.h"
 #include "qca_vendor.h"
+#include <wlan_cp_stats_chipset_stats.h>
 
 /* QCA_NL80211_VENDOR_SUBCMD_NAN_EXT policy */
 extern const struct nla_policy nan_attr_policy[
@@ -184,4 +185,224 @@ static inline void os_if_nan_post_ndi_delete_rsp(struct wlan_objmgr_psoc *psoc,
 
 #endif /* WLAN_FEATURE_NAN */
 
+#if defined(WLAN_FEATURE_NAN) && defined(WLAN_CHIPSET_STATS)
+/**
+ * os_if_cstats_log_ndp_initiator_req_evt() - Chipset stats for ndp
+ * initiator request
+ *
+ * @req : pointer to nan_datapath_initiator_req
+ *
+ * Return : void
+ */
+void
+os_if_cstats_log_ndp_initiator_req_evt(struct nan_datapath_initiator_req *req);
+
+/**
+ * os_if_cstats_log_ndp_responder_req_evt() - Chipset stats for ndp
+ * responder request
+ *
+ * @vdev : pointer to vdev object
+ * @req : pointer to nan_datapath_responder_req
+ *
+ * Return : void
+ */
+void
+os_if_cstats_log_ndp_responder_req_evt(struct wlan_objmgr_vdev *vdev,
+				       struct nan_datapath_responder_req *req);
+
+/**
+ * os_if_cstats_log_ndp_end_req_evt() - Chipset stats for ndp end
+ * request event
+ *
+ * @vdev : pointer to vdev object
+ * @rq : pointer to nan_datapath_end_req
+ *
+ * Return : void
+ */
+void os_if_cstats_log_ndp_end_req_evt(struct wlan_objmgr_vdev *vdev,
+				      struct nan_datapath_end_req *rq);
+
+/**
+ * os_if_cstats_log_ndp_initiator_resp_evt() - Chipset stats for ndp
+ * initiator request event
+ *
+ * @vdev : pointer to vdev object
+ * @rsp : pointer to nan_datapath_end_req
+ *
+ * Return : void
+ */
+void
+os_if_cstats_log_ndp_initiator_resp_evt(struct wlan_objmgr_vdev *vdev,
+					struct nan_datapath_initiator_rsp *rsp);
+
+/**
+ * os_if_cstats_log_ndp_responder_resp_evt() - Chipset stats for ndp
+ * responder response event
+ *
+ * @vdev : pointer to vdev object
+ * @rsp : pointer to nan_datapath_responder_rsp
+ *
+ * Return : void
+ */
+void
+os_if_cstats_log_ndp_responder_resp_evt(struct wlan_objmgr_vdev *vdev,
+					struct nan_datapath_responder_rsp *rsp);
+
+/**
+ * os_if_cstats_log_ndp_indication_evt() - Chipset stats for ndp
+ * indication event
+ *
+ * @vdev : pointer to vdev object
+ * @evt : pointer to nan_datapath_indication_event object
+ *
+ * Return : void
+ */
+void
+os_if_cstats_log_ndp_indication_evt(struct wlan_objmgr_vdev *vdev,
+				    struct nan_datapath_indication_event *evt);
+
+/**
+ * os_if_cstats_log_ndp_confirm_evt() - Chipset stats for ndp
+ * confirm event
+ *
+ * @vdev : pointer to vdev object
+ * @nc : pointer to nan_datapath_confirm_event
+ *
+ * Return : void
+ */
+void os_if_cstats_log_ndp_confirm_evt(struct wlan_objmgr_vdev *vdev,
+				      struct nan_datapath_confirm_event *nc);
+
+/**
+ * os_if_cstats_log_ndp_end_rsp_evt() - Chipset stats for ndp
+ * end response event
+ *
+ * @vdev : pointer to vdev object
+ * @rsp : pointer to nan_datapath_end_rsp_event object
+ *
+ * Return : void
+ */
+void os_if_cstats_log_ndp_end_rsp_evt(struct wlan_objmgr_vdev *vdev,
+				      struct nan_datapath_end_rsp_event *rsp);
+
+/**
+ * os_if_cstats_log_ndp_new_peer_evt() - Chipset stats for ndp
+ * new peer event
+ *
+ * @vdev : pointer to vdev object
+ * @peer_ind : pointer to nan_datapath_peer_ind object
+ *
+ * Return : void
+ */
+void os_if_cstats_log_ndp_new_peer_evt(struct wlan_objmgr_vdev *vdev,
+				       struct nan_datapath_peer_ind *peer_ind);
+
+/**
+ * os_if_cstats_log_ndi_delete_resp_evt() - Chipset stats for ndi
+ * delete response event
+ *
+ * @vdev : pointer to vdev object
+ * @rsp : pointer to nan_datapath_inf_delete_rsp object
+ *
+ * Return : void
+ */
+void
+os_if_cstats_log_ndi_delete_resp_evt(struct wlan_objmgr_vdev *vdev,
+				     struct nan_datapath_inf_delete_rsp *rsp);
+
+/**
+ * os_if_cstats_log_nan_disc_enable_req_evt() - Chipset stats for nan
+ * discovery enable request
+ *
+ * @vdev_id : pointer to vdev object
+ * @nan_req : pointer to nan_enable_req object
+ *
+ * Return : void
+ */
+void os_if_cstats_log_nan_disc_enable_req_evt(uint8_t vdev_id,
+					      struct nan_enable_req *nan_req);
+
+/**
+ * os_if_cstats_log_disable_nan_disc_evt() - Chipset stats for nan
+ * discovery disable event
+ *
+ * @pdev : pointer to pdev object
+ * @vdev_id : vdev ID
+ *
+ * Return : void
+ */
+void os_if_cstats_log_disable_nan_disc_evt(struct wlan_objmgr_pdev *pdev,
+					   uint8_t vdev_id);
+#else
+static inline void
+os_if_cstats_log_ndp_initiator_req_evt(struct nan_datapath_initiator_req *req)
+{
+}
+
+static inline void
+os_if_cstats_log_ndp_responder_req_evt(struct wlan_objmgr_vdev *vdev,
+				       struct nan_datapath_responder_req *req)
+{
+}
+
+static inline void
+os_if_cstats_log_ndp_end_req_evt(struct wlan_objmgr_vdev *vdev,
+				 struct nan_datapath_end_req *rq)
+{
+}
+
+static inline void
+os_if_cstats_log_ndp_initiator_resp_evt(struct wlan_objmgr_vdev *vdev,
+					struct nan_datapath_initiator_rsp *rsp)
+{
+}
+
+static inline void
+os_if_cstats_log_ndp_responder_resp_evt(struct wlan_objmgr_vdev *vdev,
+					struct nan_datapath_responder_rsp *rsp)
+{
+}
+
+static inline void
+os_if_cstats_log_ndp_indication_evt(struct wlan_objmgr_vdev *vdev,
+				    struct nan_datapath_indication_event *event)
+{
+}
+
+static inline void
+os_if_cstats_log_ndp_confirm_evt(struct wlan_objmgr_vdev *vdev,
+				 struct nan_datapath_confirm_event *nc)
+{
+}
+
+static inline void
+os_if_cstats_log_ndp_end_rsp_evt(struct wlan_objmgr_vdev *vdev,
+				 struct nan_datapath_end_rsp_event *rsp)
+{
+}
+
+static inline void
+os_if_cstats_log_ndp_new_peer_evt(struct wlan_objmgr_vdev *vdev,
+				  struct nan_datapath_peer_ind *peer_ind)
+{
+}
+
+static inline void
+os_if_cstats_log_ndi_delete_resp_evt(struct wlan_objmgr_vdev *vdev,
+				     struct nan_datapath_inf_delete_rsp *rsp)
+{
+}
+
+static inline void
+os_if_cstats_log_nan_disc_enable_req_evt(uint8_t vdev_id,
+					 struct nan_enable_req *nan_req)
+{
+}
+
+static inline void
+os_if_cstats_log_disable_nan_disc_evt(struct wlan_objmgr_pdev *pdev,
+				      uint8_t vdev_id)
+{
+}
+#endif /* WLAN_CHIPSET_STATS */
 #endif

+ 309 - 1
os_if/nan/src/os_if_nan.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 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
@@ -833,6 +833,9 @@ static int __os_if_nan_process_ndp_initiator_req(struct wlan_objmgr_psoc *psoc,
 	}
 
 	req.vdev = nan_vdev;
+
+	os_if_cstats_log_ndp_initiator_req_evt(&req);
+
 	status = ucfg_nan_req_processor(nan_vdev, &req, NDP_INITIATOR_REQ);
 	ret = qdf_status_to_os_return(status);
 initiator_req_failed:
@@ -1023,6 +1026,8 @@ static int __os_if_nan_process_ndp_responder_req(struct wlan_objmgr_psoc *psoc,
 		goto responder_req_failed;
 	}
 
+	os_if_cstats_log_ndp_responder_req_evt(nan_vdev, &req);
+
 	osif_debug("vdev_id: %d, transaction_id: %d, ndp_rsp %d, ndp_instance_id: %d, ndp_app_info_len: %d, csid: %d",
 		   wlan_vdev_get_id(nan_vdev), req.transaction_id, req.ndp_rsp,
 		   req.ndp_instance_id, req.ndp_info.ndp_app_info_len,
@@ -1110,6 +1115,9 @@ static int __os_if_nan_process_ndp_end_req(struct wlan_objmgr_psoc *psoc,
 	}
 
 	req.vdev = nan_vdev;
+
+	os_if_cstats_log_ndp_end_req_evt(nan_vdev, &req);
+
 	status = ucfg_nan_req_processor(nan_vdev, &req, NDP_END_REQ);
 	ret = qdf_status_to_os_return(status);
 	if (ret)
@@ -1309,6 +1317,8 @@ static void os_if_ndp_initiator_rsp_handler(struct wlan_objmgr_vdev *vdev,
 			rsp->reason))
 		goto ndp_initiator_rsp_nla_failed;
 
+	os_if_cstats_log_ndp_initiator_resp_evt(vdev, rsp);
+
 	osif_debug("NDP Initiator rsp sent, tid:%d, instance id:%d, status:%d, reason: %d",
 		   rsp->transaction_id, rsp->ndp_instance_id, rsp->status,
 		   rsp->reason);
@@ -1391,6 +1401,8 @@ static void os_if_ndp_responder_rsp_handler(struct wlan_objmgr_vdev *vdev,
 	   rsp->reason))
 		goto ndp_responder_rsp_nla_failed;
 
+	os_if_cstats_log_ndp_responder_resp_evt(vdev, rsp);
+
 	wlan_cfg80211_vendor_event(vendor_event, GFP_ATOMIC);
 	return;
 ndp_responder_rsp_nla_failed:
@@ -1599,6 +1611,8 @@ static void os_if_ndp_indication_handler(struct wlan_objmgr_vdev *vdev,
 			goto ndp_indication_nla_failed;
 	}
 
+	os_if_cstats_log_ndp_indication_evt(vdev, event);
+
 	wlan_cfg80211_vendor_event(vendor_event, GFP_ATOMIC);
 	return;
 ndp_indication_nla_failed:
@@ -1807,6 +1821,9 @@ os_if_ndp_confirm_ind_handler(struct wlan_objmgr_vdev *vdev,
 			goto ndp_confirm_nla_failed;
 
 	wlan_cfg80211_vendor_event(vendor_event, GFP_ATOMIC);
+
+	os_if_cstats_log_ndp_confirm_evt(vdev, ndp_confirm);
+
 	osif_debug("NDP confim sent, ndp instance id: %d, peer addr: "QDF_MAC_ADDR_FMT" rsp_code: %d, reason_code: %d",
 		   ndp_confirm->ndp_instance_id,
 		   QDF_MAC_ADDR_REF(ndp_confirm->peer_ndi_mac_addr.bytes),
@@ -1889,6 +1906,8 @@ static void os_if_ndp_end_rsp_handler(struct wlan_objmgr_vdev *vdev,
 			rsp->transaction_id))
 		goto ndp_end_rsp_nla_failed;
 
+	os_if_cstats_log_ndp_end_rsp_evt(vdev, rsp);
+
 	osif_debug("NDP End rsp sent, transaction id: %u, status: %u, reason: %u",
 		   rsp->transaction_id, rsp->status, rsp->reason);
 	wlan_cfg80211_vendor_event(vendor_event, GFP_ATOMIC);
@@ -2006,6 +2025,8 @@ static void os_if_new_peer_ind_handler(struct wlan_objmgr_vdev *vdev,
 		return;
 	}
 
+	os_if_cstats_log_ndp_new_peer_evt(vdev, peer_ind);
+
 	osif_debug("vdev_id: %d, peer_mac: "QDF_MAC_ADDR_FMT,
 		   vdev_id, QDF_MAC_ADDR_REF(peer_ind->peer_mac_addr.bytes));
 	ret = cb_obj.new_peer_ind(vdev_id, peer_ind->sta_id,
@@ -2254,6 +2275,8 @@ static void os_if_ndp_iface_delete_rsp_handler(struct wlan_objmgr_psoc *psoc,
 		osif_debug("NDI BSS stop failed with reason %d",
 			   ndi_rsp->reason);
 
+	os_if_cstats_log_ndi_delete_resp_evt(vdev, ndi_rsp);
+
 	ucfg_nan_set_ndi_delete_rsp_reason(vdev, ndi_rsp->reason);
 	ucfg_nan_set_ndi_delete_rsp_status(vdev, ndi_rsp->status);
 	cb_obj.drv_ndi_delete_rsp_handler(vdev_id);
@@ -2896,9 +2919,294 @@ int os_if_process_nan_req(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id,
 	case QCA_WLAN_NAN_EXT_SUBCMD_TYPE_ENABLE_REQ:
 		return os_if_process_nan_enable_req(pdev, tb, vdev_id);
 	case QCA_WLAN_NAN_EXT_SUBCMD_TYPE_DISABLE_REQ:
+		os_if_cstats_log_disable_nan_disc_evt(pdev, vdev_id);
 		return os_if_process_nan_disable_req(psoc, tb);
 	default:
 		osif_err("Unrecognized NAN subcmd type(%d)", nan_subcmd);
 		return -EINVAL;
 	}
 }
+
+#ifdef WLAN_CHIPSET_STATS
+void
+os_if_cstats_log_ndp_initiator_req_evt(struct nan_datapath_initiator_req *req)
+{
+	struct cstats_nan_ndp_initiator_req stat = {0};
+	struct wlan_objmgr_vdev *vdev;
+
+	vdev = req->vdev;
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDP_INITIATOR_REQ_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_nan_ndp_initiator_req) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+
+	stat.transaction_id = req->transaction_id;
+	stat.channel = req->channel;
+	stat.channel_cfg = req->channel_cfg;
+	stat.service_instance_id = req->service_instance_id;
+	CSTATS_MAC_COPY(stat.self_ndi_mac_addr, req->self_ndi_mac_addr.bytes);
+	CSTATS_MAC_COPY(stat.peer_discovery_mac_addr,
+			req->peer_discovery_mac_addr.bytes);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndp_initiator_req),
+			       &stat);
+}
+
+void
+os_if_cstats_log_ndp_responder_req_evt(struct wlan_objmgr_vdev *vdev,
+				       struct nan_datapath_responder_req *req)
+{
+	struct cstats_nan_ndp_responder_req stat = {0};
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDP_RESPONDER_REQ_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_nan_ndp_responder_req) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+	stat.transaction_id = req->transaction_id;
+	stat.ndp_instance_id = req->ndp_instance_id;
+	stat.ndp_rsp = req->ndp_rsp;
+	stat.ncs_sk_type = req->ncs_sk_type;
+
+	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndp_responder_req),
+			       &stat);
+}
+
+void os_if_cstats_log_ndp_end_req_evt(struct wlan_objmgr_vdev *vdev,
+				      struct nan_datapath_end_req *rq)
+{
+	struct cstats_nan_ndp_end_req stat = {0};
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDP_END_REQ_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_nan_ndp_end_req) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+	stat.transaction_id = rq->transaction_id;
+	stat.num_ndp_instances = rq->num_ndp_instances;
+
+	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndp_end_req), &stat);
+}
+
+void
+os_if_cstats_log_ndp_initiator_resp_evt(struct wlan_objmgr_vdev *vdev,
+					struct nan_datapath_initiator_rsp *rsp)
+{
+	struct cstats_nan_ndp_initiator_resp stat = {0};
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDP_INITIATOR_RSP_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_nan_ndp_initiator_resp) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+	stat.status = rsp->status;
+	stat.reason = rsp->reason;
+	stat.transaction_id = rsp->transaction_id;
+	stat.service_instance_id = rsp->ndp_instance_id;
+
+	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndp_initiator_resp),
+			       &stat);
+}
+
+void
+os_if_cstats_log_ndp_responder_resp_evt(struct wlan_objmgr_vdev *vdev,
+					struct nan_datapath_responder_rsp *rsp)
+{
+	struct cstats_nan_ndp_responder_resp stat = {0};
+
+	stat.cmn.hdr.evt_id =
+		WLAN_CHIPSET_STATS_NAN_NDP_RESPONDER_RESP_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_tdls_disc_req) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+	stat.status = rsp->status;
+	stat.reason = rsp->reason;
+	stat.transaction_id = rsp->transaction_id;
+
+	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndp_responder_resp),
+			       &stat);
+}
+
+void
+os_if_cstats_log_ndp_indication_evt(struct wlan_objmgr_vdev *vdev,
+				    struct nan_datapath_indication_event *evt)
+{
+	struct cstats_nan_ndp_ind stat = {0};
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDP_INDICATION_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_nan_ndp_ind) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+	stat.ndp_instance_id = evt->ndp_instance_id;
+	stat.service_instance_id = evt->service_instance_id;
+	CSTATS_MAC_COPY(stat.peer_mac, evt->peer_mac_addr.bytes);
+	CSTATS_MAC_COPY(stat.peer_discovery_mac_addr,
+			evt->peer_discovery_mac_addr.bytes);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndp_ind), &stat);
+}
+
+void
+os_if_cstats_log_ndp_confirm_evt(struct wlan_objmgr_vdev *vdev,
+				 struct nan_datapath_confirm_event *nc)
+{
+	struct cstats_nan_ndp_confirm_ind stat = {0};
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDP_CONFIRM_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_nan_ndp_confirm_ind) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+	stat.instance_id = nc->ndp_instance_id;
+	stat.rsp_code = nc->rsp_code;
+	stat.reason_code = nc->reason_code;
+	CSTATS_MAC_COPY(stat.peer_addr, nc->peer_ndi_mac_addr.bytes);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndp_confirm_ind),
+			       &stat);
+}
+
+void
+os_if_cstats_log_ndp_end_rsp_evt(struct wlan_objmgr_vdev *vdev,
+				 struct nan_datapath_end_rsp_event *rsp)
+{
+	struct cstats_nan_ndp_end_resp stat = {0};
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDP_END_RESP_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_nan_ndp_end_resp) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+	stat.status = rsp->status;
+	stat.reason = rsp->reason;
+	stat.transaction_id = rsp->transaction_id;
+
+	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndp_end_resp), &stat);
+}
+
+void
+os_if_cstats_log_ndp_new_peer_evt(struct wlan_objmgr_vdev *vdev,
+				  struct nan_datapath_peer_ind *peer_ind)
+{
+	struct cstats_nan_ndp_new_peer_ind stat = {0};
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDP_NEW_PEER_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_nan_ndp_new_peer_ind) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+	stat.sta_id = peer_ind->sta_id;
+	CSTATS_MAC_COPY(stat.peer_mac, peer_ind->peer_mac_addr.bytes);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndp_new_peer_ind),
+			       &stat);
+}
+
+void
+os_if_cstats_log_ndi_delete_resp_evt(struct wlan_objmgr_vdev *vdev,
+				     struct nan_datapath_inf_delete_rsp *rsp)
+{
+	struct cstats_nan_ndi_delete_resp stat = {0};
+
+	stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDI_DELETE_RESP_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_nan_ndi_delete_resp) -
+			      sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+
+	stat.status = rsp->status;
+	stat.reason = rsp->reason;
+	stat.transaction_id = ucfg_nan_get_ndp_delete_transaction_id(vdev);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_nan_ndi_delete_resp),
+			       &stat);
+}
+
+void os_if_cstats_log_nan_disc_enable_req_evt(uint8_t vdev_id,
+					      struct nan_enable_req *nan_req)
+{
+	struct cstats_nan_disc_enable stat = {0};
+	struct wlan_objmgr_vdev *vdev;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_pdev(nan_req->pdev,
+						    vdev_id, WLAN_NAN_ID);
+	if (!vdev) {
+		osif_err("vdev is null");
+		return;
+	}
+
+	stat.cmn.hdr.evt_id =
+		WLAN_CHIPSET_STATS_NAN_DISCOVERY_ENABLE_REQ_EVENT_ID;
+	stat.cmn.hdr.length =
+			sizeof(struct cstats_nan_disc_enable) -
+			sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+	stat.social_chan_2g_freq = nan_req->social_chan_2g_freq;
+	stat.social_chan_5g_freq = nan_req->social_chan_5g_freq;
+	stat.rtt_cap = nan_req->params.rtt_cap;
+	stat.disable_6g_nan = nan_req->params.disable_6g_nan;
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_nan_disc_enable), &stat);
+}
+
+void
+os_if_cstats_log_disable_nan_disc_evt(struct wlan_objmgr_pdev *pdev,
+				      uint8_t vdev_id)
+{
+	struct cstats_nan_disc_disable_req stat = {0};
+	struct wlan_objmgr_vdev *vdev = NULL;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, WLAN_NAN_ID);
+	if (!vdev) {
+		osif_err("vdev is null");
+		return;
+	}
+
+	stat.cmn.hdr.evt_id =
+		WLAN_CHIPSET_STATS_NAN_DISCOVERY_DISABLE_REQ_EVENT_ID;
+	stat.cmn.hdr.length = sizeof(struct cstats_nan_disc_disable_req) -
+			  sizeof(struct cstats_hdr);
+	stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev);
+	stat.cmn.vdev_id = wlan_vdev_get_id(vdev);
+	stat.cmn.timestamp_us = qdf_get_time_of_the_day_us();
+	stat.cmn.time_tick = qdf_get_log_timestamp();
+
+	stat.disable_2g_discovery = 1;
+	stat.disable_5g_discovery = 1;
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID);
+
+	wlan_cstats_host_stats(sizeof(struct cstats_nan_disc_disable_req),
+			       &stat);
+}
+#endif /* WLAN_CHIPSET_STATS */
+

+ 5 - 0
wlan_qcacld3_modules.bzl

@@ -727,6 +727,11 @@ _conditional_srcs = {
             "os_if/cp_stats/src/wlan_cfg80211_mc_cp_stats.c",
         ],
     },
+    "CONFIG_WLAN_CHIPSET_STATS": {
+        True: [
+            "cmn/umac/cp_stats/core/src/wlan_cp_stats_chipset_stats.c",
+        ],
+    },
     "CONFIG_QCA_TARGET_IF_MLME": {
 	True: [
 	    "components/target_if/mlme/src/target_if_mlme.c",