qcacld-3.0: Add Host Driver support for Chip Power stats debugfs

Implementation of Host driver support to collect chip power stats
from firmware and display the stats in
    "adb shell cat /sys/kernel/debug/wlan0/power_stats".

Change-Id: I19595ebf5a6870a0ee4d3cc2ff47d18eb24d213c
CRs-Fixed: 1045057
diff --git a/Kbuild b/Kbuild
index 881f82d..546c750 100644
--- a/Kbuild
+++ b/Kbuild
@@ -88,6 +88,11 @@
 	#Flag to enable Legacy Fast Roaming3(LFR3)
 	CONFIG_QCACLD_WLAN_LFR3 := y
 
+	#Enable Power debugfs feature only if debug_fs is enabled
+	ifeq ($(CONFIG_DEBUG_FS), y)
+	CONFIG_WLAN_POWER_DEBUGFS := y
+	endif
+
 	# JB kernel has CPU enablement patches, so enable
 	ifeq ($(CONFIG_ROME_IF),pci)
 		CONFIG_PRIMA_WLAN_11AC_HIGH_TP := y
@@ -1325,6 +1330,10 @@
 CDEFINES += -DWLAN_FEATURE_HOST_ROAM
 endif
 
+ifeq ($(CONFIG_WLAN_POWER_DEBUGFS), y)
+CDEFINES += -DWLAN_POWER_DEBUGFS
+endif
+
 ifeq ($(BUILD_DIAG_VERSION),1)
 CDEFINES += -DFEATURE_WLAN_DIAG_SUPPORT
 CDEFINES += -DFEATURE_WLAN_DIAG_SUPPORT_CSR
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h
index 18cdee5..27cba28 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -122,6 +122,7 @@
 #define WLAN_WAIT_TIME_POWER       800
 #define WLAN_WAIT_TIME_COUNTRY     1000
 #define WLAN_WAIT_TIME_LINK_STATUS 800
+#define WLAN_WAIT_TIME_POWER_STATS 800
 /* Amount of time to wait for sme close session callback.
    This value should be larger than the timeout used by WDI to wait for
    a response from WCNSS */
@@ -330,6 +331,7 @@
 #define LINK_STATUS_MAGIC   0x4C4B5354  /* LINKSTATUS(LNST) */
 #define TEMP_CONTEXT_MAGIC  0x74656d70   /* TEMP (temperature) */
 #define BPF_CONTEXT_MAGIC 0x4575354    /* BPF */
+#define POWER_STATS_MAGIC 0x14111990
 
 /* MAX OS Q block time value in msec
  * Prevent from permanent stall, resume OS Q if timer expired */
@@ -1138,6 +1140,7 @@
 	 */
 	uint8_t pre_cac_chan;
 	struct hdd_connect_pm_context connect_rpm_ctx;
+	struct power_stats_response *chip_power_stats;
 };
 
 #define WLAN_HDD_GET_STATION_CTX_PTR(pAdapter) (&(pAdapter)->sessionCtx.station)
diff --git a/core/hdd/src/wlan_hdd_debugfs.c b/core/hdd/src/wlan_hdd_debugfs.c
index e5652b4..ce21d64 100644
--- a/core/hdd/src/wlan_hdd_debugfs.c
+++ b/core/hdd/src/wlan_hdd_debugfs.c
@@ -47,6 +47,10 @@
 #define MAX_USER_COMMAND_SIZE_WOWL_PATTERN 512
 #define MAX_USER_COMMAND_SIZE_FRAME 4096
 
+#ifdef WLAN_POWER_DEBUGFS
+#define POWER_DEBUGFS_BUFFER_MAX_LEN 4096
+#endif
+
 /**
  * __wcnss_wowenable_write() - wow_enable debugfs handler
  * @file: debugfs file handle
@@ -506,6 +510,241 @@
 	return ret;
 }
 
+#ifdef WLAN_POWER_DEBUGFS
+/**
+ * hdd_power_debugstats_cb() - callback routine for Power stats debugs
+ * @response: Pointer to Power stats response
+ * @context: Pointer to statsContext
+ *
+ * Return: None
+ */
+static void hdd_power_debugstats_cb(struct power_stats_response *response,
+							void *context)
+{
+	struct statsContext *stats_context;
+	struct power_stats_response *power_stats;
+	hdd_adapter_t *adapter;
+	uint32_t power_stats_len;
+	uint32_t stats_registers_len;
+
+	ENTER();
+	if (!context) {
+		hdd_err("context is NULL");
+		return;
+	}
+
+	stats_context = (struct statsContext *)context;
+
+	spin_lock(&hdd_context_lock);
+	adapter = stats_context->pAdapter;
+	if ((POWER_STATS_MAGIC != stats_context->magic) ||
+		(!adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
+		spin_unlock(&hdd_context_lock);
+		hdd_err("Invalid context, adapter [%p] magic [%08x]",
+				adapter, stats_context->magic);
+		return;
+	}
+
+	stats_context->magic = 0;
+	stats_registers_len = (sizeof(response->debug_registers[0]) *
+					response->num_debug_register);
+	power_stats_len = stats_registers_len + sizeof(*power_stats);
+	adapter->chip_power_stats = qdf_mem_malloc(power_stats_len);
+	if (!adapter->chip_power_stats) {
+		hdd_err("Power stats memory alloc fails!");
+		goto exit_stats_cb;
+	}
+
+	power_stats = adapter->chip_power_stats;
+	power_stats->cumulative_sleep_time_ms
+		= response->cumulative_sleep_time_ms;
+	power_stats->cumulative_total_on_time_ms
+		= response->cumulative_total_on_time_ms;
+	power_stats->deep_sleep_enter_counter
+		= response->deep_sleep_enter_counter;
+	power_stats->last_deep_sleep_enter_tstamp_ms
+		= response->last_deep_sleep_enter_tstamp_ms;
+	power_stats->debug_register_fmt
+		= response->debug_register_fmt;
+	power_stats->num_debug_register
+		= response->num_debug_register;
+
+	power_stats->debug_registers = (uint32_t *)(power_stats + 1);
+
+	qdf_mem_copy(power_stats->debug_registers,
+		response->debug_registers, stats_registers_len);
+
+exit_stats_cb:
+	complete(&stats_context->completion);
+	spin_unlock(&hdd_context_lock);
+	EXIT();
+}
+
+/**
+ * __wlan_hdd_read_power_debugfs() - API to collect Chip power stats from FW
+ * @file: file pointer
+ * @buf: buffer
+ * @count: count
+ * @pos: position pointer
+ *
+ * Return: Number of bytes read on success, error number otherwise
+ */
+static ssize_t __wlan_hdd_read_power_debugfs(struct file *file,
+		char __user *buf,
+		size_t count, loff_t *pos)
+{
+	hdd_adapter_t *adapter;
+	hdd_context_t *hdd_ctx;
+	static struct statsContext context;
+	struct power_stats_response *chip_power_stats;
+	ssize_t ret_cnt = 0;
+	int rc = 0, j;
+	unsigned int len = 0;
+	char *power_debugfs_buf;
+
+	ENTER();
+	adapter = (hdd_adapter_t *)file->private_data;
+	if ((!adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
+		hdd_err("Invalid adapter or adapter has invalid magic");
+		return -EINVAL;
+	}
+
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	ret_cnt = wlan_hdd_validate_context(hdd_ctx);
+	if (0 != ret_cnt)
+		return ret_cnt;
+
+	if (adapter->chip_power_stats)
+		qdf_mem_free(adapter->chip_power_stats);
+
+	adapter->chip_power_stats = NULL;
+	context.pAdapter = adapter;
+	context.magic = POWER_STATS_MAGIC;
+
+	init_completion(&context.completion);
+
+	if (QDF_STATUS_SUCCESS !=
+			sme_power_debug_stats_req(hdd_ctx->hHal,
+				hdd_power_debugstats_cb,
+				&context)) {
+		hdd_err("chip power stats request failed");
+		return -EINVAL;
+	}
+
+	rc = wait_for_completion_timeout(&context.completion,
+			msecs_to_jiffies(WLAN_WAIT_TIME_POWER_STATS));
+	if (!rc) {
+		hdd_err("Target response timed out Power stats");
+		/* Invalidate the Stats context magic */
+		spin_lock(&hdd_context_lock);
+		context.magic = 0;
+		spin_unlock(&hdd_context_lock);
+		return -ETIMEDOUT;
+	}
+
+	chip_power_stats = adapter->chip_power_stats;
+	if (!chip_power_stats) {
+		hdd_err("Power stats retrieval fails!");
+		return -EINVAL;
+	}
+
+	power_debugfs_buf = qdf_mem_malloc(POWER_DEBUGFS_BUFFER_MAX_LEN);
+	if (!power_debugfs_buf) {
+		hdd_err("Power stats buffer alloc fails!");
+		qdf_mem_free(chip_power_stats);
+		adapter->chip_power_stats = NULL;
+		return -EINVAL;
+	}
+
+	len += scnprintf(power_debugfs_buf, POWER_DEBUGFS_BUFFER_MAX_LEN,
+			"POWER DEBUG STATS\n=================\n"
+			"cumulative_sleep_time_ms: %d\n"
+			"cumulative_total_on_time_ms: %d\n"
+			"deep_sleep_enter_counter: %d\n"
+			"last_deep_sleep_enter_tstamp_ms: %d\n"
+			"debug_register_fmt: %d\n"
+			"num_debug_register: %d\n",
+			chip_power_stats->cumulative_sleep_time_ms,
+			chip_power_stats->cumulative_total_on_time_ms,
+			chip_power_stats->deep_sleep_enter_counter,
+			chip_power_stats->last_deep_sleep_enter_tstamp_ms,
+			chip_power_stats->debug_register_fmt,
+			chip_power_stats->num_debug_register);
+
+	for (j = 0; j < chip_power_stats->num_debug_register; j++) {
+		if ((POWER_DEBUGFS_BUFFER_MAX_LEN - len) > 0)
+			len += scnprintf(power_debugfs_buf + len,
+					POWER_DEBUGFS_BUFFER_MAX_LEN - len,
+					"debug_registers[%d]: 0x%x\n", j,
+					chip_power_stats->debug_registers[j]);
+		else
+			j = chip_power_stats->num_debug_register;
+	}
+
+	qdf_mem_free(chip_power_stats);
+	adapter->chip_power_stats = NULL;
+
+	ret_cnt = simple_read_from_buffer(buf, count, pos,
+			power_debugfs_buf, len);
+	qdf_mem_free(power_debugfs_buf);
+	return ret_cnt;
+}
+
+/**
+ * wlan_hdd_read_power_debugfs() - SSR wrapper function to read power debugfs
+ * @file: file pointer
+ * @buf: buffer
+ * @count: count
+ * @pos: position pointer
+ *
+ * Return: Number of bytes read on success, error number otherwise
+ */
+static ssize_t wlan_hdd_read_power_debugfs(struct file *file,
+		char __user *buf,
+		size_t count, loff_t *pos)
+{
+	int ret;
+
+	cds_ssr_protect(__func__);
+	ret = __wlan_hdd_read_power_debugfs(file, buf, count, pos);
+	cds_ssr_unprotect(__func__);
+
+	return ret;
+}
+
+/**
+ * __wlan_hdd_open_power_debugfs() - Function to save private on open
+ * @inode: Pointer to inode structure
+ * @file: file pointer
+ *
+ * Return: zero
+ */
+static int __wlan_hdd_open_power_debugfs(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+
+/**
+ * wlan_hdd_open_power_debugfs() - SSR wrapper function to save private on open
+ * @inode: Pointer to inode structure
+ * @file: file pointer
+ *
+ * Return: zero
+ */
+static int wlan_hdd_open_power_debugfs(struct inode *inode, struct file *file)
+{
+	int ret;
+
+	cds_ssr_protect(__func__);
+	ret = __wlan_hdd_open_power_debugfs(inode, file);
+	cds_ssr_unprotect(__func__);
+
+	return ret;
+}
+#endif
+
 /**
  * __wcnss_debugfs_open() - Generic debugfs open() handler
  * @inode: inode of the debugfs file
@@ -577,6 +816,37 @@
 	.llseek = default_llseek,
 };
 
+#ifdef WLAN_POWER_DEBUGFS
+static const struct file_operations fops_powerdebugs = {
+	.read = wlan_hdd_read_power_debugfs,
+	.open = wlan_hdd_open_power_debugfs,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+/**
+ * wlan_hdd_create_power_stats_file() - API to create power stats file
+ * @adapter: interface adapter pointer
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS wlan_hdd_create_power_stats_file(hdd_adapter_t *adapter)
+{
+	if (!debugfs_create_file("power_stats", S_IRUSR | S_IRGRP | S_IROTH,
+				adapter->debugfs_phy, adapter,
+				&fops_powerdebugs))
+		return QDF_STATUS_E_FAILURE;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+#else
+static QDF_STATUS wlan_hdd_create_power_stats_file(hdd_adapter_t *adapter)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 /**
  * hdd_debugfs_init() - Initialize debugfs interface
  * @adapter: interface adapter pointer
@@ -612,6 +882,9 @@
 					&fops_patterngen))
 		return QDF_STATUS_E_FAILURE;
 
+	if (QDF_STATUS_SUCCESS != wlan_hdd_create_power_stats_file(adapter))
+		return QDF_STATUS_E_FAILURE;
+
 	return QDF_STATUS_SUCCESS;
 }
 
diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h
index 970dbd7..ba18cd3 100644
--- a/core/mac/inc/sir_api.h
+++ b/core/mac/inc/sir_api.h
@@ -4901,6 +4901,28 @@
 	uint8_t stopReq;
 } tSirLLStatsClearReq, *tpSirLLStatsClearReq;
 
+#ifdef WLAN_POWER_DEBUGFS
+/**
+ * struct power_stats_response - Power stats response
+ * @cumulative_sleep_time_ms: cumulative sleep time in ms
+ * @cumulative_total_on_time_ms: total awake time in ms
+ * @deep_sleep_enter_counter: deep sleep enter counter
+ * @last_deep_sleep_enter_tstamp_ms: last deep sleep enter timestamp
+ * @debug_register_fmt: debug registers format
+ * @num_debug_register: number of debug registers
+ * @debug_registers: Pointer to the debug registers buffer
+ */
+struct power_stats_response {
+	uint32_t cumulative_sleep_time_ms;
+	uint32_t cumulative_total_on_time_ms;
+	uint32_t deep_sleep_enter_counter;
+	uint32_t last_deep_sleep_enter_tstamp_ms;
+	uint32_t debug_register_fmt;
+	uint32_t num_debug_register;
+	uint32_t *debug_registers;
+};
+#endif
+
 typedef struct {
 	uint8_t oui[WIFI_SCANNING_MAC_OUI_LENGTH];
 } tSirScanMacOui, *tpSirScanMacOui;
diff --git a/core/mac/src/include/sir_params.h b/core/mac/src/include/sir_params.h
index 3fe1af3..e91e6ca 100644
--- a/core/mac/src/include/sir_params.h
+++ b/core/mac/src/include/sir_params.h
@@ -640,6 +640,8 @@
 #define SIR_HAL_SHORT_RETRY_LIMIT_CNT       (SIR_HAL_ITC_MSG_TYPES_BEGIN + 365)
 #define SIR_HAL_LONG_RETRY_LIMIT_CNT        (SIR_HAL_ITC_MSG_TYPES_BEGIN + 366)
 #define SIR_HAL_UPDATE_TX_FAIL_CNT_TH       (SIR_HAL_ITC_MSG_TYPES_BEGIN + 367)
+#define SIR_HAL_POWER_DEBUG_STATS_REQ       (SIR_HAL_ITC_MSG_TYPES_BEGIN + 368)
+
 #define SIR_HAL_MSG_TYPES_END                (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF)
 
 /* CFG message types */
diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h
index ae21183..6f7afab 100644
--- a/core/sme/inc/sme_api.h
+++ b/core/sme/inc/sme_api.h
@@ -1358,4 +1358,9 @@
  */
 QDF_STATUS sme_set_lost_link_info_cb(tHalHandle hal,
 		void (*cb)(void *, struct sir_lost_link_info *));
+#ifdef WLAN_POWER_DEBUGFS
+QDF_STATUS sme_power_debug_stats_req(tHalHandle hal, void (*callback_fn)
+				(struct  power_stats_response *response,
+				void *context), void *power_stats_context);
+#endif
 #endif /* #if !defined( __SME_API_H ) */
diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h
index dfc972d..b443404 100644
--- a/core/sme/inc/sme_internal.h
+++ b/core/sme/inc/sme_internal.h
@@ -183,6 +183,12 @@
 	void (*pLinkLayerStatsIndCallback)(void *callbackContext,
 			int indType, void *pRsp);
 #endif /* WLAN_FEATURE_LINK_LAYER_STATS */
+
+#ifdef WLAN_POWER_DEBUGFS
+	void *power_debug_stats_context;
+	void (*power_stats_resp_callback)(struct power_stats_response *rsp,
+						void *callback_context);
+#endif
 #ifdef FEATURE_WLAN_AUTO_SHUTDOWN
 	void (*pAutoShutdownNotificationCb)(void);
 #endif
diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c
index 1564ff1..0b100ad 100644
--- a/core/sme/src/common/sme_api.c
+++ b/core/sme/src/common/sme_api.c
@@ -14362,6 +14362,46 @@
 
 #endif /* WLAN_FEATURE_LINK_LAYER_STATS */
 
+#ifdef WLAN_POWER_DEBUGFS
+/**
+ * sme_power_debug_stats_req() - SME API to collect Power debug stats
+ * @callback_fn: Pointer to the callback function for Power stats event
+ * @power_stats_context: Pointer to context
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS sme_power_debug_stats_req(tHalHandle hal, void (*callback_fn)
+				(struct power_stats_response *response,
+				void *context), void *power_stats_context)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal);
+	cds_msg_t msg;
+
+	status = sme_acquire_global_lock(&mac_ctx->sme);
+	if (QDF_IS_STATUS_SUCCESS(status)) {
+		if (!callback_fn) {
+			sms_log(mac_ctx, LOGE,
+				FL("Indication callback did not registered"));
+			sme_release_global_lock(&mac_ctx->sme);
+			return QDF_STATUS_E_FAILURE;
+		}
+
+		mac_ctx->sme.power_debug_stats_context = power_stats_context;
+		mac_ctx->sme.power_stats_resp_callback = callback_fn;
+		msg.bodyptr = NULL;
+		msg.type = WMA_POWER_DEBUG_STATS_REQ;
+		status = cds_mq_post_message(QDF_MODULE_ID_WMA, &msg);
+		if (!QDF_IS_STATUS_SUCCESS(status)) {
+			sms_log(mac_ctx, LOGE,
+				FL("not able to post WDA_POWER_DEBUG_STATS_REQ"));
+		}
+		sme_release_global_lock(&mac_ctx->sme);
+	}
+	return status;
+}
+#endif
+
 /**
  * sme_fw_mem_dump_register_cb() - Register fw memory dump callback
  *
diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h
index feb5c18..3354115 100644
--- a/core/wma/inc/wma_internal.h
+++ b/core/wma/inc/wma_internal.h
@@ -1231,4 +1231,6 @@
  */
 void wma_lost_link_info_handler(tp_wma_handle wma, uint32_t vdev_id,
 				int32_t rssi);
+int wma_unified_power_debug_stats_event_handler(void *handle,
+			uint8_t *cmd_param_info, uint32_t len);
 #endif
diff --git a/core/wma/inc/wma_types.h b/core/wma/inc/wma_types.h
index ab7e09f..d850a8b 100644
--- a/core/wma/inc/wma_types.h
+++ b/core/wma/inc/wma_types.h
@@ -477,6 +477,8 @@
 #define WMA_UPDATE_WEP_DEFAULT_KEY           SIR_HAL_UPDATE_WEP_DEFAULT_KEY
 #define WMA_SEND_FREQ_RANGE_CONTROL_IND      SIR_HAL_SEND_FREQ_RANGE_CONTROL_IND
 #define WMA_ENCRYPT_DECRYPT_MSG              SIR_HAL_ENCRYPT_DECRYPT_MSG
+#define WMA_POWER_DEBUG_STATS_REQ            SIR_HAL_POWER_DEBUG_STATS_REQ
+
 /* Bit 6 will be used to control BD rate for Management frames */
 #define HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME 0x40
 
diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c
index d893fff..a9323d2 100644
--- a/core/wma/src/wma_features.c
+++ b/core/wma/src/wma_features.c
@@ -8516,3 +8516,87 @@
 	return 0;
 }
 #endif
+
+/**
+ * wma_unified_power_debug_stats_event_handler() - WMA handler function to
+ * handle Power stats event from firmware
+ * @handle: Pointer to wma handle
+ * @cmd_param_info: Pointer to Power stats event TLV
+ * @len: Length of the cmd_param_info
+ *
+ * Return: 0 on success, error number otherwise
+ */
+#ifdef WLAN_POWER_DEBUGFS
+int wma_unified_power_debug_stats_event_handler(void *handle,
+			uint8_t *cmd_param_info, uint32_t len)
+{
+	WMI_PDEV_CHIP_POWER_STATS_EVENTID_param_tlvs *param_tlvs;
+	struct power_stats_response *power_stats_results;
+	wmi_pdev_chip_power_stats_event_fixed_param *param_buf;
+	uint32_t power_stats_len, stats_registers_len, *debug_registers;
+
+	tpAniSirGlobal mac = (tpAniSirGlobal)cds_get_context(QDF_MODULE_ID_PE);
+	param_tlvs =
+		(WMI_PDEV_CHIP_POWER_STATS_EVENTID_param_tlvs *) cmd_param_info;
+
+	param_buf = (wmi_pdev_chip_power_stats_event_fixed_param *)
+		param_tlvs->fixed_param;
+	if (!mac || !mac->sme.power_stats_resp_callback) {
+		WMA_LOGD("%s: NULL mac ptr or HDD callback is null", __func__);
+		return -EINVAL;
+	}
+
+	if (!param_buf) {
+		WMA_LOGD("%s: NULL power stats event fixed param", __func__);
+		return -EINVAL;
+	}
+
+	debug_registers = param_tlvs->debug_registers;
+	stats_registers_len =
+		(sizeof(uint32_t) * param_buf->num_debug_register);
+	power_stats_len = stats_registers_len + sizeof(*power_stats_results);
+	power_stats_results = qdf_mem_malloc(power_stats_len);
+	if (!power_stats_results) {
+		WMA_LOGD("%s: could not allocate mem for power stats results",
+				__func__);
+		return -ENOMEM;
+	}
+	WMA_LOGD("Cumulative sleep time %d cumulative total on time %d deep sleep enter counter %d last deep sleep enter tstamp ts %d debug registers fmt %d num debug register %d",
+			param_buf->cumulative_sleep_time_ms,
+			param_buf->cumulative_total_on_time_ms,
+			param_buf->deep_sleep_enter_counter,
+			param_buf->last_deep_sleep_enter_tstamp_ms,
+			param_buf->debug_register_fmt,
+			param_buf->num_debug_register);
+
+	power_stats_results->cumulative_sleep_time_ms
+		= param_buf->cumulative_sleep_time_ms;
+	power_stats_results->cumulative_total_on_time_ms
+		= param_buf->cumulative_total_on_time_ms;
+	power_stats_results->deep_sleep_enter_counter
+		= param_buf->deep_sleep_enter_counter;
+	power_stats_results->last_deep_sleep_enter_tstamp_ms
+		= param_buf->last_deep_sleep_enter_tstamp_ms;
+	power_stats_results->debug_register_fmt
+		= param_buf->debug_register_fmt;
+	power_stats_results->num_debug_register
+		= param_buf->num_debug_register;
+
+	power_stats_results->debug_registers
+		= (uint32_t *)(power_stats_results + 1);
+
+	qdf_mem_copy(power_stats_results->debug_registers,
+			debug_registers, stats_registers_len);
+
+	mac->sme.power_stats_resp_callback(power_stats_results,
+			mac->sme.power_debug_stats_context);
+	qdf_mem_free(power_stats_results);
+	return 0;
+}
+#else
+int wma_unified_power_debug_stats_event_handler(void *handle,
+		uint8_t *cmd_param_info, uint32_t len)
+{
+	return 0;
+}
+#endif
diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c
index b106d38..1d8fc77 100644
--- a/core/wma/src/wma_main.c
+++ b/core/wma/src/wma_main.c
@@ -2164,6 +2164,15 @@
 					   WMI_UPDATE_STATS_EVENTID,
 					   wma_stats_event_handler,
 					   WMA_RX_SERIALIZER_CTX);
+
+#ifdef WLAN_POWER_DEBUGFS
+	/* register for Chip Power stats event */
+	wmi_unified_register_event_handler(wma_handle->wmi_handle,
+				WMI_PDEV_CHIP_POWER_STATS_EVENTID,
+				wma_unified_power_debug_stats_event_handler,
+				WMA_RX_SERIALIZER_CTX);
+#endif
+
 	/* register for linkspeed response event */
 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
 					   WMI_PEER_ESTIMATED_LINKSPEED_EVENTID,
@@ -6082,6 +6091,62 @@
 }
 
 /**
+ * wma_process_power_debug_stats_req() - Process the Chip Power stats collect
+ * request and pass the Power stats request to Fw
+ * @wma_handle: WMA handle
+ *
+ * Return: QDF_STATUS
+ */
+#ifdef WLAN_POWER_DEBUGFS
+static QDF_STATUS wma_process_power_debug_stats_req(tp_wma_handle wma_handle)
+{
+	wmi_pdev_get_chip_power_stats_cmd_fixed_param *cmd;
+	int32_t len;
+	wmi_buf_t buf;
+	uint8_t *buf_ptr;
+	int ret;
+
+	if (!wma_handle) {
+		WMA_LOGE("%s: input pointer is NULL", __func__);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	len = sizeof(*cmd);
+	buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
+	if (!buf) {
+		WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	buf_ptr = (u_int8_t *) wmi_buf_data(buf);
+	cmd = (wmi_pdev_get_chip_power_stats_cmd_fixed_param *) buf_ptr;
+
+	WMITLV_SET_HDR(&cmd->tlv_header,
+		WMITLV_TAG_STRUC_wmi_get_chip_power_stats_cmd_fixed_param,
+		WMITLV_GET_STRUCT_TLVLEN(
+			wmi_pdev_get_chip_power_stats_cmd_fixed_param));
+	cmd->pdev_id = 0;
+
+	WMA_LOGD("POWER_DEBUG_STATS - Get Request Params; Pdev id - %d",
+			cmd->pdev_id);
+	ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
+			WMI_PDEV_GET_CHIP_POWER_STATS_CMDID);
+	if (ret) {
+		WMA_LOGE("%s: Failed to send power debug stats request",
+				__func__);
+		wmi_buf_free(buf);
+		return QDF_STATUS_E_FAILURE;
+	}
+	return QDF_STATUS_SUCCESS;
+}
+#else
+static QDF_STATUS wma_process_power_debug_stats_req(tp_wma_handle wma_handle)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
+/**
  * wma_mc_process_msg() - process wma messages and call appropriate function.
  * @cds_context: cds context
  * @msg: message
@@ -6915,8 +6980,11 @@
 		wma_update_short_retry_limit(wma_handle, msg->bodyptr);
 		qdf_mem_free(msg->bodyptr);
 		break;
+	case SIR_HAL_POWER_DEBUG_STATS_REQ:
+		wma_process_power_debug_stats_req(wma_handle);
+		break;
 	default:
-		WMA_LOGD("unknow msg type %x", msg->type);
+		WMA_LOGD("unknown msg type %x", msg->type);
 		/* Do Nothing? MSG Body should be freed at here */
 		if (NULL != msg->bodyptr) {
 			qdf_mem_free(msg->bodyptr);