qcacld-3.0: Add FW Profiling support

Add Profiling stats support in HOST driver to
have CPU based profiling for critical data
path functions in FW.

Change-Id: Ib6d4f0b220f622cf304536c8e538d4dc34c6434b
CRs-Fixed: 921950
diff --git a/core/hdd/inc/qc_sap_ioctl.h b/core/hdd/inc/qc_sap_ioctl.h
index 5fee04f..6983a7a 100644
--- a/core/hdd/inc/qc_sap_ioctl.h
+++ b/core/hdd/inc/qc_sap_ioctl.h
@@ -147,6 +147,7 @@
 /* Private ioctls and their sub-ioctls */
 #define QCSAP_PRIV_GET_CHAR_SET_NONE   (SIOCIWFIRSTPRIV + 13)
 #define QCSAP_GET_STATS 1
+#define QCSAP_LIST_FW_PROFILE 2
 #define QCSAP_IOCTL_CLR_STATS         (SIOCIWFIRSTPRIV+14)
 
 #define QCSAP_IOCTL_PRIV_SET_THREE_INT_GET_NONE (SIOCIWFIRSTPRIV+15)
@@ -171,6 +172,8 @@
 #define QCSAP_IOCTL_SET_FW_CRASH_INJECT 1
 #endif
 #define QCSAP_IOCTL_DUMP_DP_TRACE_LEVEL 2
+#define QCSAP_ENABLE_FW_PROFILE          3
+#define QCSAP_SET_FW_PROFILE_HIST_INTVL  4
 
 #define MAX_VAR_ARGS         7
 #define QCSAP_IOCTL_PRIV_GET_SOFTAP_LINK_SPEED (SIOCIWFIRSTPRIV + 31)
@@ -237,6 +240,8 @@
 	QCASAP_DUMP_STATS,
 	QCASAP_CLEAR_STATS,
 	QCASAP_SET_RADAR_DBG,
+	QCSAP_GET_FW_PROFILE_DATA,
+	QCSAP_START_FW_PROFILING
 };
 
 int iw_softap_get_channel_list(struct net_device *dev,
diff --git a/core/hdd/inc/wlan_hdd_wext.h b/core/hdd/inc/wlan_hdd_wext.h
index 1f78e49..7bb8606 100644
--- a/core/hdd/inc/wlan_hdd_wext.h
+++ b/core/hdd/inc/wlan_hdd_wext.h
@@ -306,6 +306,8 @@
 
 extern void hdd_wlan_get_stats(hdd_adapter_t *pAdapter, uint16_t *length,
 			       char *buffer, uint16_t buf_len);
+extern void hdd_wlan_list_fw_profile(uint16_t *length,
+			       char *buffer, uint16_t buf_len);
 
 extern int iw_set_essid(struct net_device *dev,
 			struct iw_request_info *info,
diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c
index c5b5955..ed01195 100644
--- a/core/hdd/src/wlan_hdd_hostapd.c
+++ b/core/hdd/src/wlan_hdd_hostapd.c
@@ -2032,29 +2032,36 @@
 	return ret;
 }
 
+/**
+ * iw_softap_set_two_ints_getnone() - Generic "set two integer" ioctl handler
+ * @dev: device upon which the ioctl was received
+ * @info: ioctl request information
+ * @wrqu: ioctl request data
+ * @extra: ioctl extra data
+ *
+ * Return: 0 on success, non-zero on error
+ */
 static int __iw_softap_set_two_ints_getnone(struct net_device *dev,
 					    struct iw_request_info *info,
 					    union iwreq_data *wrqu, char *extra)
 {
-	hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
-	hdd_context_t *pHddCtx;
+	hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+	int ret;
 	int *value = (int *)extra;
 	int sub_cmd = value[0];
-	int ret = 0;
+	hdd_context_t *hdd_ctx;
 
-	pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
-	ret = wlan_hdd_validate_context(pHddCtx);
-	if (ret != 0) {
-		hddLog(LOGE, FL("HDD context is not valid!"));
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	ret = wlan_hdd_validate_context(hdd_ctx);
+	if (ret != 0)
 		goto out;
-	}
 
 	switch (sub_cmd) {
 #ifdef DEBUG
 	case QCSAP_IOCTL_SET_FW_CRASH_INJECT:
 		hddLog(LOGE, "WE_SET_FW_CRASH_INJECT: %d %d",
 		       value[1], value[2]);
-		ret = wma_cli_set2_command(pAdapter->sessionId,
+		ret = wma_cli_set2_command(adapter->sessionId,
 					   GEN_PARAM_CRASH_INJECT,
 					   value[1], value[2],
 					   GEN_CMD);
@@ -2066,6 +2073,19 @@
 		if (value[1] == DUMP_DP_TRACE)
 			cdf_dp_trace_dump_all(value[2]);
 		break;
+	case QCSAP_ENABLE_FW_PROFILE:
+		hddLog(LOG1, "QCSAP_ENABLE_FW_PROFILE: %d %d",
+		       value[1], value[2]);
+		ret = wma_cli_set2_command(adapter->sessionId,
+				 WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
+					value[1], value[2], DBG_CMD);
+		break;
+	case QCSAP_SET_FW_PROFILE_HIST_INTVL:
+		hddLog(LOG1, "QCSAP_SET_FW_PROFILE_HIST_INTVL: %d %d",
+		       value[1], value[2]);
+		ret = wma_cli_set2_command(adapter->sessionId,
+					WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
+					value[1], value[2], DBG_CMD);
 	default:
 		hddLog(LOGE, FL("Invalid IOCTL command %d"), sub_cmd);
 		break;
@@ -2793,6 +2813,12 @@
 		}
 		break;
 	}
+	case QCSAP_START_FW_PROFILING:
+		hddLog(LOG1, "QCSAP_START_FW_PROFILING %d", set_value);
+		ret = wma_cli_set_command(pHostapdAdapter->sessionId,
+					WMI_WLAN_PROFILE_TRIGGER_CMDID,
+					set_value, DBG_CMD);
+		break;
 	default:
 		hddLog(LOGE, FL("Invalid setparam command %d value %d"),
 		       sub_cmd, set_value);
@@ -3007,6 +3033,12 @@
 		ret = wlan_hdd_get_temperature(pHostapdAdapter, value);
 		break;
 	}
+	case QCSAP_GET_FW_PROFILE_DATA:
+		hddLog(LOG1, "QCSAP_GET_FW_PROFILE_DATA");
+		ret = wma_cli_set_command(pHostapdAdapter->sessionId,
+				WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
+				0, DBG_CMD);
+		break;
 	default:
 		hddLog(LOGE, FL("Invalid getparam command %d"), sub_cmd);
 		ret = -EINVAL;
@@ -3415,31 +3447,44 @@
 	return ret;
 }
 
+/**
+ * iw_get_char_setnone() - Generic "get char" private ioctl handler
+ * @dev: device upon which the ioctl was received
+ * @info: ioctl request information
+ * @wrqu: ioctl request data
+ * @extra: ioctl extra data
+ *
+ * Return: 0 on success, non-zero on error
+ */
 static int __iw_get_char_setnone(struct net_device *dev,
 				struct iw_request_info *info,
 				union iwreq_data *wrqu, char *extra)
 {
 	hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
-	CDF_STATUS status;
+	int ret;
 	int sub_cmd = wrqu->data.flags;
 	hdd_context_t *hdd_ctx;
 
 	ENTER();
 
 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
-	status = wlan_hdd_validate_context(hdd_ctx);
-	if (status != 0)
-		return status;
+	ret = wlan_hdd_validate_context(hdd_ctx);
+	if (ret != 0)
+		return ret;
 
 	switch (sub_cmd) {
 	case QCSAP_GET_STATS:
 		hdd_wlan_get_stats(adapter, &(wrqu->data.length),
 					extra, WE_MAX_STR_LEN);
 		break;
+	case QCSAP_LIST_FW_PROFILE:
+		hdd_wlan_list_fw_profile(&(wrqu->data.length),
+					extra, WE_MAX_STR_LEN);
+		break;
 	}
 
 	EXIT();
-	return status;
+	return ret;
 }
 
 static int iw_get_char_setnone(struct net_device *dev,
@@ -5465,6 +5510,10 @@
 		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
 		0, "clearStats"
 	}, {
+		QCSAP_START_FW_PROFILING,
+		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+		0, "startProfile"
+	}, {
 		QCSAP_IOCTL_GETPARAM, 0,
 		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getparam"
 	}, {
@@ -5530,6 +5579,9 @@
 		QCASAP_GET_TEMP_CMD, 0,
 		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_temp"
 	}, {
+		QCSAP_GET_FW_PROFILE_DATA, 0,
+		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getProfileData"
+	}, {
 		QCSAP_IOCTL_GET_STAWPAIE,
 		IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0,
 		"get_staWPAIE"
@@ -5572,6 +5624,10 @@
 		IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, "getStats"
 	}
 	, {
+		QCSAP_LIST_FW_PROFILE, 0,
+		IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, "listProfile"
+	}
+	, {
 		QCSAP_IOCTL_PRIV_GET_SOFTAP_LINK_SPEED,
 		IW_PRIV_TYPE_CHAR | 18,
 		IW_PRIV_TYPE_CHAR | 5, "getLinkSpeed"
@@ -5677,6 +5733,17 @@
 		0, "dump_dp_trace"
 	}
 	,
+	{
+		QCSAP_ENABLE_FW_PROFILE,
+		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2,
+		0, "enableProfile"
+	}
+	,
+	{
+		QCSAP_SET_FW_PROFILE_HIST_INTVL,
+		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2,
+		0, "set_hist_intvl"
+	}
 };
 
 static const iw_handler hostapd_private[] = {
diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c
index 4e68ecb..047131f 100644
--- a/core/hdd/src/wlan_hdd_wext.c
+++ b/core/hdd/src/wlan_hdd_wext.c
@@ -213,6 +213,8 @@
 #define WE_SET_CTS_CBW                        84
 #define WE_DUMP_STATS                         85
 #define WE_CLEAR_STATS                        86
+/* Private sub ioctl for starting/stopping the profiling */
+#define WE_START_FW_PROFILE                      87
 
 /* Private ioctls and their sub-ioctls */
 #define WLAN_PRIV_SET_NONE_GET_INT    (SIOCIWFIRSTPRIV + 1)
@@ -314,6 +316,7 @@
 #define WE_GET_OEM_DATA_CAP  13
 #endif
 #define WE_GET_SNR           14
+#define WE_LIST_FW_PROFILE      15
 
 /* Private ioctls and their sub-ioctls */
 #define WLAN_PRIV_SET_NONE_GET_NONE   (SIOCIWFIRSTPRIV + 6)
@@ -328,6 +331,7 @@
 #define WE_DUMP_PCIE_LOG           16
 #endif
 #define WE_GET_RECOVERY_STAT       17
+#define WE_GET_FW_PROFILE_DATA        18
 
 /* Private ioctls and their sub-ioctls */
 #define WLAN_PRIV_SET_VAR_INT_GET_NONE   (SIOCIWFIRSTPRIV + 7)
@@ -424,6 +428,9 @@
 #endif
 #define WE_DUMP_DP_TRACE_LEVEL    3
 #define DUMP_DP_TRACE       0
+/* Private sub ioctl for enabling and setting histogram interval of profiling */
+#define WE_ENABLE_FW_PROFILE    4
+#define WE_SET_FW_PROFILE_HIST_INTVL    5
 
 /* (SIOCIWFIRSTPRIV + 29) is currently unused */
 
@@ -648,6 +655,41 @@
 }
 
 /**
+ * hdd_wlan_list_fw_profile() - Get fw profiling points
+ * @length:   Size of the data copied
+ * @buffer:   Pointer to char buffer.
+ * @buf_len:  Length of the char buffer.
+ *
+ * This function called when the "iwpriv wlan0 listProfile" command is given.
+ * It is used to get the supported profiling points in FW.
+ *
+ * Return - none
+ */
+void hdd_wlan_list_fw_profile(uint16_t *length,
+			char *buffer, uint16_t buf_len)
+{
+	uint32_t len = 0;
+
+	len = scnprintf(buffer, buf_len,
+		    "PROF_CPU_IDLE: %u\n"
+		    "PROF_PPDU_PROC: %u\n"
+		    "PROF_PPDU_POST: %u\n"
+		    "PROF_HTT_TX_INPUT: %u\n"
+		    "PROF_MSDU_ENQ: %u\n"
+		    "PROF_PPDU_POST_HAL: %u\n"
+		    "PROF_COMPUTE_TX_TIME: %u\n",
+		    PROF_CPU_IDLE,
+		    PROF_PPDU_PROC,
+		    PROF_PPDU_POST,
+		    PROF_HTT_TX_INPUT,
+		    PROF_MSDU_ENQ,
+		    PROF_PPDU_POST_HAL,
+		    PROF_COMPUTE_TX_TIME);
+
+	*length = len + 1;
+}
+
+/**
  * hdd_wlan_dump_stats() - display dump Stats
  * @adapter: adapter handle
  * @value: value from user
@@ -6072,6 +6114,14 @@
 		sme_set_scan_disable(WLAN_HDD_GET_HAL_CTX(pAdapter), set_value);
 		break;
 	}
+	case WE_START_FW_PROFILE:
+	{
+		hddLog(LOG1, "WE_START_FW_PROFILE %d", set_value);
+		ret = wma_cli_set_command(pAdapter->sessionId,
+					WMI_WLAN_PROFILE_TRIGGER_CMDID,
+					set_value, DBG_CMD);
+		break;
+	}
 	default:
 	{
 		hddLog(LOGE, "%s: Invalid sub command %d", __func__,
@@ -6896,6 +6946,11 @@
 		break;
 	}
 
+	case WE_LIST_FW_PROFILE:
+		hdd_wlan_list_fw_profile(&(wrqu->data.length),
+					extra, WE_MAX_STR_LEN);
+		break;
+
 	/* The case prints the current state of the HDD, SME, CSR, PE,
 	 * TL it can be extended for WDI Global State as well.  And
 	 * currently it only checks P2P_CLIENT adapter.  P2P_DEVICE
@@ -7409,6 +7464,12 @@
 		break;
 	}
 
+	case WE_GET_FW_PROFILE_DATA:
+		ret = wma_cli_set_command(pAdapter->sessionId,
+				WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
+				0, DBG_CMD);
+		break;
+
 	case WE_SET_REASSOC_TRIGGER:
 	{
 		hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
@@ -9431,6 +9492,20 @@
 					   value[1], value[2], GEN_CMD);
 		break;
 #endif
+	case WE_ENABLE_FW_PROFILE:
+		hddLog(LOGE, "WE_ENABLE_FW_PROFILE: %d %d",
+		       value[1], value[2]);
+		ret = wma_cli_set2_command(pAdapter->sessionId,
+				 WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
+					value[1], value[2], DBG_CMD);
+		break;
+	case WE_SET_FW_PROFILE_HIST_INTVL:
+		hddLog(LOGE, "WE_SET_FW_PROFILE_HIST_INTVL: %d %d",
+		       value[1], value[2]);
+		ret = wma_cli_set2_command(pAdapter->sessionId,
+					WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
+					value[1], value[2], DBG_CMD);
+		break;
 	case WE_SET_DUAL_MAC_FW_MODE_CONFIG:
 		hdd_debug("Ioctl to set dual fw mode config");
 		if (hdd_ctx->config->dual_mac_feature_disable) {
@@ -9986,6 +10061,10 @@
 	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
 	 0, "clearStats"},
 
+	{WE_START_FW_PROFILE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 0, "startProfile"},
+
 	{WLAN_PRIV_SET_NONE_GET_INT,
 	 0,
 	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
@@ -10322,6 +10401,10 @@
 	 0,
 	 IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN,
 	 "getStats"},
+	{WE_LIST_FW_PROFILE,
+	 0,
+	 IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN,
+	 "listProfile"},
 	{WE_GET_STATES,
 	 0,
 	 IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN,
@@ -10388,12 +10471,17 @@
 	 0,
 	 0,
 	 "getRecoverStat"},
-	{
-		WE_SET_REASSOC_TRIGGER,
-		0,
-		0,
-		"reassoc"
-	},
+
+	{WE_GET_FW_PROFILE_DATA,
+	 0,
+	 0,
+	 "getProfileData"},
+
+	{WE_SET_REASSOC_TRIGGER,
+	0,
+	0,
+	"reassoc"},
+
 	{WE_DUMP_AGC_START,
 	 0,
 	 0,
@@ -10608,6 +10696,14 @@
 	 0, "crash_inject"}
 	,
 #endif
+	{WE_ENABLE_FW_PROFILE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2,
+	 0, "enableProfile"}
+	,
+	{WE_SET_FW_PROFILE_HIST_INTVL,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2,
+	 0, "set_hist_intvl"}
+	,
 	{WE_SET_DUAL_MAC_FW_MODE_CONFIG,
 	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2,
 	 0, "set_fw_mode_cfg"}
diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h
index f15e518..b72d9fc 100644
--- a/core/wma/inc/wma.h
+++ b/core/wma/inc/wma.h
@@ -1631,6 +1631,28 @@
 };
 
 /**
+ * enum profile_id_t - Firmware profiling index
+ * @PROF_CPU_IDLE: cpu idle profile
+ * @PROF_PPDU_PROC: ppdu processing profile
+ * @PROF_PPDU_POST: ppdu post profile
+ * @PROF_HTT_TX_INPUT: htt tx input profile
+ * @PROF_MSDU_ENQ: msdu enqueue profile
+ * @PROF_PPDU_POST_HAL: ppdu post profile
+ * @PROF_COMPUTE_TX_TIME: tx time profile
+ * @PROF_MAX_ID: max profile index
+ */
+enum profile_id_t {
+	PROF_CPU_IDLE,
+	PROF_PPDU_PROC,
+	PROF_PPDU_POST,
+	PROF_HTT_TX_INPUT,
+	PROF_MSDU_ENQ,
+	PROF_PPDU_POST_HAL,
+	PROF_COMPUTE_TX_TIME,
+	PROF_MAX_ID,
+};
+
+/**
  * struct p2p_ie - P2P IE structural definition.
  * @p2p_id: p2p id
  * @p2p_len: p2p length
diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h
index c455e12..d927a76 100644
--- a/core/wma/inc/wma_internal.h
+++ b/core/wma/inc/wma_internal.h
@@ -868,6 +868,12 @@
 						uint32_t value);
 #endif
 
+int wma_profile_data_report_event_handler(void *handle, uint8_t *event_buf,
+				       uint32_t len);
+
+int32_t wmi_unified_fw_profiling_cmd(wmi_unified_t wmi_handle,
+				uint32_t cmd, uint32_t value1, uint32_t value2);
+
 void wma_wow_tx_complete(void *wma);
 
 int wmi_unified_nat_keepalive_enable(tp_wma_handle wma, uint8_t vdev_id);
diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c
index d7f54aa..c1e7df5 100644
--- a/core/wma/src/wma_features.c
+++ b/core/wma/src/wma_features.c
@@ -1025,6 +1025,137 @@
 }
 #endif /* FEATURE_GREEN_AP */
 
+/**
+ * wmi_unified_fw_profiling_cmd() - send FW profiling cmd to WLAN FW
+ * @wma: wma handle
+ * @cmd: Profiling command index
+ * @value1: parameter1 value
+ * @value2: parameter2 value
+ *
+ * Return: 0 for success else error code
+ */
+int32_t wmi_unified_fw_profiling_cmd(wmi_unified_t wmi_handle,
+			uint32_t cmd, uint32_t value1, uint32_t value2)
+{
+	wmi_buf_t buf;
+	int32_t len = 0;
+	int ret;
+	wmi_wlan_profile_trigger_cmd_fixed_param *prof_trig_cmd;
+	wmi_wlan_profile_set_hist_intvl_cmd_fixed_param *hist_intvl_cmd;
+	wmi_wlan_profile_enable_profile_id_cmd_fixed_param *profile_enable_cmd;
+	wmi_wlan_profile_get_prof_data_cmd_fixed_param *profile_getdata_cmd;
+
+	switch (cmd) {
+	case WMI_WLAN_PROFILE_TRIGGER_CMDID:
+		len = sizeof(wmi_wlan_profile_trigger_cmd_fixed_param);
+		buf = wmi_buf_alloc(wmi_handle, len);
+		if (!buf) {
+			WMA_LOGP("%s: wmi_buf_alloc Failed", __func__);
+			return -ENOMEM;
+		}
+		prof_trig_cmd =
+			(wmi_wlan_profile_trigger_cmd_fixed_param *)
+				wmi_buf_data(buf);
+		WMITLV_SET_HDR(&prof_trig_cmd->tlv_header,
+			      WMITLV_TAG_STRUC_wmi_wlan_profile_trigger_cmd_fixed_param,
+			      WMITLV_GET_STRUCT_TLVLEN
+			      (wmi_wlan_profile_trigger_cmd_fixed_param));
+		prof_trig_cmd->enable = value1;
+		ret = wmi_unified_cmd_send(wmi_handle, buf, len,
+				WMI_WLAN_PROFILE_TRIGGER_CMDID);
+		if (ret) {
+			WMA_LOGE("PROFILE_TRIGGER cmd Failed with value %d",
+					value1);
+			cdf_nbuf_free(buf);
+			return ret;
+		}
+		break;
+
+	case WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID:
+		len = sizeof(wmi_wlan_profile_get_prof_data_cmd_fixed_param);
+		buf = wmi_buf_alloc(wmi_handle, len);
+		if (!buf) {
+			WMA_LOGP("%s: wmi_buf_alloc Failed", __func__);
+			return -ENOMEM;
+		}
+		profile_getdata_cmd =
+			(wmi_wlan_profile_get_prof_data_cmd_fixed_param *)
+				wmi_buf_data(buf);
+		WMITLV_SET_HDR(&profile_getdata_cmd->tlv_header,
+			      WMITLV_TAG_STRUC_wmi_wlan_profile_get_prof_data_cmd_fixed_param,
+			      WMITLV_GET_STRUCT_TLVLEN
+			      (wmi_wlan_profile_get_prof_data_cmd_fixed_param));
+		ret = wmi_unified_cmd_send(wmi_handle, buf, len,
+				WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID);
+		if (ret) {
+			WMA_LOGE("PROFILE_DATA cmd Failed for id %d value %d",
+					value1, value2);
+			cdf_nbuf_free(buf);
+			return ret;
+		}
+		break;
+
+	case WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID:
+		len = sizeof(wmi_wlan_profile_set_hist_intvl_cmd_fixed_param);
+		buf = wmi_buf_alloc(wmi_handle, len);
+		if (!buf) {
+			WMA_LOGP("%s: wmi_buf_alloc Failed", __func__);
+			return -ENOMEM;
+		}
+		hist_intvl_cmd =
+			(wmi_wlan_profile_set_hist_intvl_cmd_fixed_param *)
+				wmi_buf_data(buf);
+		WMITLV_SET_HDR(&hist_intvl_cmd->tlv_header,
+			      WMITLV_TAG_STRUC_wmi_wlan_profile_set_hist_intvl_cmd_fixed_param,
+			      WMITLV_GET_STRUCT_TLVLEN
+			      (wmi_wlan_profile_set_hist_intvl_cmd_fixed_param));
+		hist_intvl_cmd->profile_id = value1;
+		hist_intvl_cmd->value = value2;
+		ret = wmi_unified_cmd_send(wmi_handle, buf, len,
+				WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID);
+		if (ret) {
+			WMA_LOGE("HIST_INTVL cmd Failed for id %d value %d",
+					value1, value2);
+			cdf_nbuf_free(buf);
+			return ret;
+		}
+		break;
+
+	case WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID:
+		len =
+		sizeof(wmi_wlan_profile_enable_profile_id_cmd_fixed_param);
+		buf = wmi_buf_alloc(wmi_handle, len);
+		if (!buf) {
+			WMA_LOGP("%s: wmi_buf_alloc Failed", __func__);
+			return -ENOMEM;
+		}
+		profile_enable_cmd =
+			(wmi_wlan_profile_enable_profile_id_cmd_fixed_param *)
+				wmi_buf_data(buf);
+		WMITLV_SET_HDR(&profile_enable_cmd->tlv_header,
+			      WMITLV_TAG_STRUC_wmi_wlan_profile_enable_profile_id_cmd_fixed_param,
+			      WMITLV_GET_STRUCT_TLVLEN
+			      (wmi_wlan_profile_enable_profile_id_cmd_fixed_param));
+		profile_enable_cmd->profile_id = value1;
+		profile_enable_cmd->enable = value2;
+		ret = wmi_unified_cmd_send(wmi_handle, buf, len,
+				WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID);
+		if (ret) {
+			WMA_LOGE("enable cmd Failed for id %d value %d",
+					value1, value2);
+			cdf_nbuf_free(buf);
+			return ret;
+		}
+		break;
+
+	default:
+		WMA_LOGD("%s: invalid profiling command", __func__);
+		break;
+	}
+
+	return 0;
+}
+
 #ifdef FEATURE_WLAN_LPHB
 /**
  * wma_lphb_handler() - send LPHB indication to SME
diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c
index c2eafde..e9c6bd9 100644
--- a/core/wma/src/wma_main.c
+++ b/core/wma/src/wma_main.c
@@ -955,6 +955,52 @@
 				WMA_LOGE("dbglog_report_enable failed ret %d",
 					 ret);
 			break;
+		case WMI_WLAN_PROFILE_TRIGGER_CMDID:
+			ret = wmi_unified_fw_profiling_cmd(wma->wmi_handle,
+					 WMI_WLAN_PROFILE_TRIGGER_CMDID,
+					 privcmd->param_value, 0);
+			if (ret)
+				WMA_LOGE("Profile cmd failed for %d ret %d",
+					WMI_WLAN_PROFILE_TRIGGER_CMDID, ret);
+			break;
+		case WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID:
+			ret = wmi_unified_fw_profiling_cmd(wma->wmi_handle,
+				  WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
+				  privcmd->param_value,
+				  privcmd->param_sec_value);
+			if (ret)
+				WMA_LOGE("Profile cmd failed for %d ret %d",
+				   WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
+				   ret);
+			break;
+		case WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID:
+			ret = wmi_unified_fw_profiling_cmd(wma->wmi_handle,
+					 WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
+					 privcmd->param_value,
+					 privcmd->param_sec_value);
+			if (ret)
+				WMA_LOGE("Profile cmd failed for %d ret %d",
+					WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
+					ret);
+			break;
+		case WMI_WLAN_PROFILE_LIST_PROFILE_ID_CMDID:
+			ret = wmi_unified_fw_profiling_cmd(wma->wmi_handle,
+					 WMI_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
+					 0, 0);
+			if (ret)
+				WMA_LOGE("Profile cmd failed for %d ret %d",
+					WMI_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
+					ret);
+			break;
+		case WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID:
+			ret = wmi_unified_fw_profiling_cmd(wma->wmi_handle,
+					WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
+					0, 0);
+			if (ret)
+				WMA_LOGE("Profile cmd failed for %d ret %d",
+				   WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
+				   ret);
+			break;
 #ifdef FEATURE_GREEN_AP
 		case WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID:
 			/* Set the Green AP */
@@ -1640,6 +1686,10 @@
 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
 					   WMI_DEBUG_PRINT_EVENTID,
 					   wma_unified_debug_print_event_handler);
+	/* Register profiling event Handler */
+	wmi_unified_register_event_handler(wma_handle->wmi_handle,
+					WMI_WLAN_PROFILE_DATA_EVENTID,
+					wma_profile_data_report_event_handler);
 
 	wma_handle->tgt_cfg_update_cb = tgt_cfg_cb;
 	wma_handle->dfs_radar_indication_cb = radar_ind_cb;
diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c
index fd34f80..a8f81d5 100644
--- a/core/wma/src/wma_utils.c
+++ b/core/wma/src/wma_utils.c
@@ -381,6 +381,78 @@
 }
 #endif /* WLAN_FEATURE_STATS_EXT */
 
+/**
+ * wma_profile_data_report_event_handler() - fw profiling handler
+ * @handle:     wma handle
+ * @event_buf:  event buffer received from fw
+ * @len:        length of data
+ *
+ * Return: 0 for success or error code
+ */
+int wma_profile_data_report_event_handler(void *handle, uint8_t *event_buf,
+				uint32_t len)
+{
+	WMI_WLAN_PROFILE_DATA_EVENTID_param_tlvs *param_buf;
+	wmi_wlan_profile_ctx_t *profile_ctx;
+	wmi_wlan_profile_t *profile_data;
+	uint32_t i = 0;
+	uint32_t entries;
+	uint8_t *buf_ptr;
+	param_buf = (WMI_WLAN_PROFILE_DATA_EVENTID_param_tlvs *) event_buf;
+
+	if (!param_buf) {
+		WMA_LOGE("%s: Invalid profile data event buf", __func__);
+		return -EINVAL;
+	}
+	profile_ctx = param_buf->profile_ctx;
+	buf_ptr = (uint8_t *)profile_ctx;
+	buf_ptr = buf_ptr + sizeof(wmi_wlan_profile_ctx_t) + WMI_TLV_HDR_SIZE;
+	profile_data = (wmi_wlan_profile_t *) buf_ptr;
+	entries = profile_ctx->bin_count;
+	CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR,
+				"Profile data stats\n");
+	CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR,
+		"TOT: %d\n"
+		"tx_msdu_cnt: %d\n"
+		"tx_mpdu_cnt: %d\n"
+		"tx_ppdu_cnt: %d\n"
+		"rx_msdu_cnt: %d\n"
+		"rx_mpdu_cnt: %d\n"
+		"bin_count: %d\n",
+		profile_ctx->tot,
+		profile_ctx->tx_msdu_cnt,
+		profile_ctx->tx_mpdu_cnt,
+		profile_ctx->tx_ppdu_cnt,
+		profile_ctx->rx_msdu_cnt,
+		profile_ctx->rx_mpdu_cnt,
+		profile_ctx->bin_count);
+
+	for (i = 0; i < entries; i++) {
+		if (i == WMI_WLAN_PROFILE_MAX_BIN_CNT)
+			break;
+		CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR,
+			"Profile ID: %d\n"
+			"Profile Count: %d\n"
+			"Profile TOT: %d\n"
+			"Profile Min: %d\n"
+			"Profile Max: %d\n"
+			"Profile hist_intvl: %d\n"
+			"Profile hist[0]: %d\n"
+			"Profile hist[1]: %d\n"
+			"Profile hist[2]: %d\n",
+			profile_data[i].id,
+			profile_data[i].cnt,
+			profile_data[i].tot,
+			profile_data[i].min,
+			profile_data[i].max,
+			profile_data[i].hist_intvl,
+			profile_data[i].hist[0],
+			profile_data[i].hist[1],
+			profile_data[i].hist[2]);
+	}
+
+	return 0;
+}
 
 #ifdef WLAN_FEATURE_LINK_LAYER_STATS