ソースを参照

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
Sridhar Selvaraj 8 年 前
コミット
dc400d2572

+ 9 - 0
Kbuild

@@ -88,6 +88,11 @@ ifeq ($(KERNEL_BUILD), 0)
 	#Flag to enable Legacy Fast Roaming3(LFR3)
 	#Flag to enable Legacy Fast Roaming3(LFR3)
 	CONFIG_QCACLD_WLAN_LFR3 := y
 	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
 	# JB kernel has CPU enablement patches, so enable
 	ifeq ($(CONFIG_ROME_IF),pci)
 	ifeq ($(CONFIG_ROME_IF),pci)
 		CONFIG_PRIMA_WLAN_11AC_HIGH_TP := y
 		CONFIG_PRIMA_WLAN_11AC_HIGH_TP := y
@@ -1325,6 +1330,10 @@ ifeq ($(CONFIG_QCACLD_WLAN_LFR2),y)
 CDEFINES += -DWLAN_FEATURE_HOST_ROAM
 CDEFINES += -DWLAN_FEATURE_HOST_ROAM
 endif
 endif
 
 
+ifeq ($(CONFIG_WLAN_POWER_DEBUGFS), y)
+CDEFINES += -DWLAN_POWER_DEBUGFS
+endif
+
 ifeq ($(BUILD_DIAG_VERSION),1)
 ifeq ($(BUILD_DIAG_VERSION),1)
 CDEFINES += -DFEATURE_WLAN_DIAG_SUPPORT
 CDEFINES += -DFEATURE_WLAN_DIAG_SUPPORT
 CDEFINES += -DFEATURE_WLAN_DIAG_SUPPORT_CSR
 CDEFINES += -DFEATURE_WLAN_DIAG_SUPPORT_CSR

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

@@ -122,6 +122,7 @@
 #define WLAN_WAIT_TIME_POWER       800
 #define WLAN_WAIT_TIME_POWER       800
 #define WLAN_WAIT_TIME_COUNTRY     1000
 #define WLAN_WAIT_TIME_COUNTRY     1000
 #define WLAN_WAIT_TIME_LINK_STATUS 800
 #define WLAN_WAIT_TIME_LINK_STATUS 800
+#define WLAN_WAIT_TIME_POWER_STATS 800
 /* Amount of time to wait for sme close session callback.
 /* Amount of time to wait for sme close session callback.
    This value should be larger than the timeout used by WDI to wait for
    This value should be larger than the timeout used by WDI to wait for
    a response from WCNSS */
    a response from WCNSS */
@@ -330,6 +331,7 @@ extern spinlock_t hdd_context_lock;
 #define LINK_STATUS_MAGIC   0x4C4B5354  /* LINKSTATUS(LNST) */
 #define LINK_STATUS_MAGIC   0x4C4B5354  /* LINKSTATUS(LNST) */
 #define TEMP_CONTEXT_MAGIC  0x74656d70   /* TEMP (temperature) */
 #define TEMP_CONTEXT_MAGIC  0x74656d70   /* TEMP (temperature) */
 #define BPF_CONTEXT_MAGIC 0x4575354    /* BPF */
 #define BPF_CONTEXT_MAGIC 0x4575354    /* BPF */
+#define POWER_STATS_MAGIC 0x14111990
 
 
 /* MAX OS Q block time value in msec
 /* MAX OS Q block time value in msec
  * Prevent from permanent stall, resume OS Q if timer expired */
  * Prevent from permanent stall, resume OS Q if timer expired */
@@ -1138,6 +1140,7 @@ struct hdd_adapter_s {
 	 */
 	 */
 	uint8_t pre_cac_chan;
 	uint8_t pre_cac_chan;
 	struct hdd_connect_pm_context connect_rpm_ctx;
 	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)
 #define WLAN_HDD_GET_STATION_CTX_PTR(pAdapter) (&(pAdapter)->sessionCtx.station)

+ 273 - 0
core/hdd/src/wlan_hdd_debugfs.c

@@ -47,6 +47,10 @@
 #define MAX_USER_COMMAND_SIZE_WOWL_PATTERN 512
 #define MAX_USER_COMMAND_SIZE_WOWL_PATTERN 512
 #define MAX_USER_COMMAND_SIZE_FRAME 4096
 #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
  * __wcnss_wowenable_write() - wow_enable debugfs handler
  * @file: debugfs file handle
  * @file: debugfs file handle
@@ -506,6 +510,241 @@ static ssize_t wcnss_patterngen_write(struct file *file,
 	return ret;
 	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
  * __wcnss_debugfs_open() - Generic debugfs open() handler
  * @inode: inode of the debugfs file
  * @inode: inode of the debugfs file
@@ -577,6 +816,37 @@ static const struct file_operations fops_patterngen = {
 	.llseek = default_llseek,
 	.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
  * hdd_debugfs_init() - Initialize debugfs interface
  * @adapter: interface adapter pointer
  * @adapter: interface adapter pointer
@@ -612,6 +882,9 @@ QDF_STATUS hdd_debugfs_init(hdd_adapter_t *adapter)
 					&fops_patterngen))
 					&fops_patterngen))
 		return QDF_STATUS_E_FAILURE;
 		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;
 	return QDF_STATUS_SUCCESS;
 }
 }
 
 

+ 22 - 0
core/mac/inc/sir_api.h

@@ -4901,6 +4901,28 @@ typedef struct {
 	uint8_t stopReq;
 	uint8_t stopReq;
 } tSirLLStatsClearReq, *tpSirLLStatsClearReq;
 } 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 {
 typedef struct {
 	uint8_t oui[WIFI_SCANNING_MAC_OUI_LENGTH];
 	uint8_t oui[WIFI_SCANNING_MAC_OUI_LENGTH];
 } tSirScanMacOui, *tpSirScanMacOui;
 } tSirScanMacOui, *tpSirScanMacOui;

+ 2 - 0
core/mac/src/include/sir_params.h

@@ -640,6 +640,8 @@ typedef struct sSirMbMsgP2p {
 #define SIR_HAL_SHORT_RETRY_LIMIT_CNT       (SIR_HAL_ITC_MSG_TYPES_BEGIN + 365)
 #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_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_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)
 #define SIR_HAL_MSG_TYPES_END                (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF)
 
 
 /* CFG message types */
 /* CFG message types */

+ 5 - 0
core/sme/inc/sme_api.h

@@ -1358,4 +1358,9 @@ QDF_STATUS sme_update_sta_inactivity_timeout(tHalHandle hal_handle,
  */
  */
 QDF_STATUS sme_set_lost_link_info_cb(tHalHandle hal,
 QDF_STATUS sme_set_lost_link_info_cb(tHalHandle hal,
 		void (*cb)(void *, struct sir_lost_link_info *));
 		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 ) */
 #endif /* #if !defined( __SME_API_H ) */

+ 6 - 0
core/sme/inc/sme_internal.h

@@ -183,6 +183,12 @@ typedef struct tagSmeStruct {
 	void (*pLinkLayerStatsIndCallback)(void *callbackContext,
 	void (*pLinkLayerStatsIndCallback)(void *callbackContext,
 			int indType, void *pRsp);
 			int indType, void *pRsp);
 #endif /* WLAN_FEATURE_LINK_LAYER_STATS */
 #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
 #ifdef FEATURE_WLAN_AUTO_SHUTDOWN
 	void (*pAutoShutdownNotificationCb)(void);
 	void (*pAutoShutdownNotificationCb)(void);
 #endif
 #endif

+ 40 - 0
core/sme/src/common/sme_api.c

@@ -14362,6 +14362,46 @@ QDF_STATUS sme_reset_link_layer_stats_ind_cb(tHalHandle h_hal)
 
 
 #endif /* WLAN_FEATURE_LINK_LAYER_STATS */
 #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
  * sme_fw_mem_dump_register_cb() - Register fw memory dump callback
  *
  *

+ 2 - 0
core/wma/inc/wma_internal.h

@@ -1231,4 +1231,6 @@ static inline int wma_encrypt_decrypt_msg_handler(void *handle, uint8_t *data,
  */
  */
 void wma_lost_link_info_handler(tp_wma_handle wma, uint32_t vdev_id,
 void wma_lost_link_info_handler(tp_wma_handle wma, uint32_t vdev_id,
 				int32_t rssi);
 				int32_t rssi);
+int wma_unified_power_debug_stats_event_handler(void *handle,
+			uint8_t *cmd_param_info, uint32_t len);
 #endif
 #endif

+ 2 - 0
core/wma/inc/wma_types.h

@@ -477,6 +477,8 @@
 #define WMA_UPDATE_WEP_DEFAULT_KEY           SIR_HAL_UPDATE_WEP_DEFAULT_KEY
 #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_SEND_FREQ_RANGE_CONTROL_IND      SIR_HAL_SEND_FREQ_RANGE_CONTROL_IND
 #define WMA_ENCRYPT_DECRYPT_MSG              SIR_HAL_ENCRYPT_DECRYPT_MSG
 #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 */
 /* Bit 6 will be used to control BD rate for Management frames */
 #define HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME 0x40
 #define HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME 0x40
 
 

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

@@ -8516,3 +8516,87 @@ int wma_encrypt_decrypt_msg_handler(void *handle, uint8_t *data,
 	return 0;
 	return 0;
 }
 }
 #endif
 #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

+ 69 - 1
core/wma/src/wma_main.c

@@ -2164,6 +2164,15 @@ QDF_STATUS wma_open(struct wlan_objmgr_psoc *psoc, void *cds_context,
 					   WMI_UPDATE_STATS_EVENTID,
 					   WMI_UPDATE_STATS_EVENTID,
 					   wma_stats_event_handler,
 					   wma_stats_event_handler,
 					   WMA_RX_SERIALIZER_CTX);
 					   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 */
 	/* register for linkspeed response event */
 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
 					   WMI_PEER_ESTIMATED_LINKSPEED_EVENTID,
 					   WMI_PEER_ESTIMATED_LINKSPEED_EVENTID,
@@ -6081,6 +6090,62 @@ void wma_update_sta_inactivity_timeout(tp_wma_handle wma,
 			max_unresponsive_time);
 			max_unresponsive_time);
 }
 }
 
 
+/**
+ * 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.
  * wma_mc_process_msg() - process wma messages and call appropriate function.
  * @cds_context: cds context
  * @cds_context: cds context
@@ -6915,8 +6980,11 @@ QDF_STATUS wma_mc_process_msg(void *cds_context, cds_msg_t *msg)
 		wma_update_short_retry_limit(wma_handle, msg->bodyptr);
 		wma_update_short_retry_limit(wma_handle, msg->bodyptr);
 		qdf_mem_free(msg->bodyptr);
 		qdf_mem_free(msg->bodyptr);
 		break;
 		break;
+	case SIR_HAL_POWER_DEBUG_STATS_REQ:
+		wma_process_power_debug_stats_req(wma_handle);
+		break;
 	default:
 	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 */
 		/* Do Nothing? MSG Body should be freed at here */
 		if (NULL != msg->bodyptr) {
 		if (NULL != msg->bodyptr) {
 			qdf_mem_free(msg->bodyptr);
 			qdf_mem_free(msg->bodyptr);