Przeglądaj źródła

qcacld-3.0: Dump driver information

qcacld-2.0 to qcacld-3.0 propagation

Dump state information of HDD, SME, PE and WMA layers
into a buffer. Contents of this buffer will be copied
into user space using proc entry /proc/debugdriver/
driverdump.

Change-Id: Ifbb102e440d7df20defa1a397964cb9b55082bf9
CRs-Fixed: 955357
Padma, Santhosh Kumar 8 lat temu
rodzic
commit
9aba02f52c

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

@@ -101,6 +101,7 @@ v_CONTEXT_t cds_init(void)
 #if defined(TRACE_RECORD)
 	qdf_trace_init();
 #endif
+	qdf_register_debugcb_init();
 
 	cds_ssr_protect_init();
 

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

@@ -1469,6 +1469,8 @@ struct hdd_context_s {
 	bool memdump_in_progress;
 	bool memdump_init_done;
 #endif /* WLAN_FEATURE_MEMDUMP */
+	uint16_t driver_dump_size;
+	uint8_t *driver_dump_mem;
 
 	bool connection_in_progress;
 	qdf_spinlock_t connection_status_lock;

+ 18 - 0
core/hdd/inc/wlan_hdd_memdump.h

@@ -37,6 +37,10 @@
 
 #include "wlan_hdd_main.h"
 
+/* Assigned size of driver memory dump is 4096 bytes */
+#define DRIVER_MEM_DUMP_SIZE    4096
+
+
 #ifdef WLAN_FEATURE_MEMDUMP
 /**
  * enum qca_wlan_vendor_attr_memory_dump - values for memory dump attributes
@@ -72,6 +76,10 @@ int wlan_hdd_cfg80211_get_fw_mem_dump(struct wiphy *wiphy,
 				      struct wireless_dev *wdev,
 				      const void *data, int data_len);
 void wlan_hdd_cfg80211_fw_mem_dump_cb(void *ctx, struct fw_dump_rsp *dump_rsp);
+
+int hdd_driver_memdump_init(void);
+void hdd_driver_memdump_deinit(void);
+
 #else
 static inline int memdump_init(void)
 {
@@ -95,6 +103,16 @@ static inline void wlan_hdd_cfg80211_fw_mem_dump_cb(void *ctx,
 						    *dump_rsp)
 {
 }
+
+static inline int hdd_driver_memdump_init(void)
+{
+	return -ENOTSUPP;
+}
+
+static inline void hdd_driver_memdump_deinit(void)
+{
+}
+
 #endif
 
 #endif /* if !defined(WLAN_HDD_MEMDUMP_H)*/

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

@@ -4795,6 +4795,7 @@ void __hdd_wlan_exit(void)
 	hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
 
 	memdump_deinit();
+	hdd_driver_memdump_deinit();
 
 	/* Do all the cleanup before deregistering the driver */
 	hdd_wlan_exit(hdd_ctx);
@@ -7723,6 +7724,79 @@ static void hdd_iface_change_callback(void *priv)
 	EXIT();
 }
 
+/**
+ * hdd_state_info_dump() - prints state information of hdd layer
+ * @buf: buffer pointer
+ * @size: size of buffer to be filled
+ *
+ * This function is used to dump state information of hdd layer
+ *
+ * Return: None
+ */
+static void hdd_state_info_dump(char **buf_ptr, uint16_t *size)
+{
+	hdd_context_t *hdd_ctx;
+	hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
+	QDF_STATUS status;
+	hdd_station_ctx_t *hdd_sta_ctx;
+	hdd_adapter_t *adapter;
+	uint16_t len = 0;
+	char *buf = *buf_ptr;
+
+	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+	if (!hdd_ctx) {
+		hdd_err("Failed to get hdd context ");
+		return;
+	}
+
+	hdd_notice("size of buffer: %d", *size);
+
+	len += scnprintf(buf + len, *size - len,
+		"\n isWiphySuspended %d", hdd_ctx->isWiphySuspended);
+	len += scnprintf(buf + len, *size - len,
+		"\n isMcThreadSuspended %d",
+		hdd_ctx->isMcThreadSuspended);
+
+	status = hdd_get_front_adapter(hdd_ctx, &adapter_node);
+
+	while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
+		adapter = adapter_node->pAdapter;
+		if (adapter->dev)
+			len += scnprintf(buf + len, *size - len,
+				"\n device name: %s", adapter->dev->name);
+			len += scnprintf(buf + len, *size - len,
+				"\n device_mode: %d", adapter->device_mode);
+		switch (adapter->device_mode) {
+		case QDF_STA_MODE:
+		case QDF_P2P_CLIENT_MODE:
+			hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
+			len += scnprintf(buf + len, *size - len,
+				"\n connState: %d",
+				hdd_sta_ctx->conn_info.connState);
+			break;
+
+		default:
+			break;
+		}
+		status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next);
+		adapter_node = next;
+	}
+
+	*size -= len;
+	*buf_ptr += len;
+}
+
+/**
+ * hdd_register_debug_callback() - registration function for hdd layer
+ * to print hdd state information
+ *
+ * Return: None
+ */
+static void hdd_register_debug_callback(void)
+{
+	qdf_register_debug_callback(QDF_MODULE_ID_HDD, &hdd_state_info_dump);
+}
+
 /**
  * hdd_wlan_startup() - HDD init function
  * @dev:	Pointer to the underlying device
@@ -7854,6 +7928,7 @@ int hdd_wlan_startup(struct device *dev)
 
 	memdump_init();
 	hdd_encrypt_decrypt_init(hdd_ctx);
+	hdd_driver_memdump_init();
 
 	if (hdd_ctx->config->fIsImpsEnabled)
 		hdd_set_idle_ps_config(hdd_ctx, true);
@@ -8804,6 +8879,7 @@ int hdd_init(void)
 	}
 
 	hdd_trace_init();
+	hdd_register_debug_callback();
 
 err_out:
 	return ret;

+ 234 - 0
core/hdd/src/wlan_hdd_memdump.c

@@ -630,3 +630,237 @@ void memdump_deinit(void)
 	if (!QDF_IS_STATUS_SUCCESS(qdf_status))
 		hdd_err("Failed to deallocate timer");
 }
+
+#ifdef MULTI_IF_NAME
+#define PROCFS_DRIVER_DUMP_DIR "debugdriver" MULTI_IF_NAME
+#else
+#define PROCFS_DRIVER_DUMP_DIR "debugdriver"
+#endif
+#define PROCFS_DRIVER_DUMP_NAME "driverdump"
+#define PROCFS_DRIVER_DUMP_PERM 0444
+
+static struct proc_dir_entry *proc_file_driver, *proc_dir_driver;
+
+/**
+ * hdd_driver_mem_cleanup() - Frees memory allocated for
+ * driver dump
+ *
+ * This function unallocates driver dump memory.
+ *
+ * Return: None
+ */
+static void hdd_driver_mem_cleanup(void)
+{
+	hdd_context_t *hdd_ctx;
+
+	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+	if (!hdd_ctx) {
+		hdd_err("Invalid HDD context");
+		return;
+	}
+
+	if (hdd_ctx->driver_dump_mem) {
+		qdf_mem_free(hdd_ctx->driver_dump_mem);
+		hdd_ctx->driver_dump_mem = NULL;
+	}
+}
+
+
+/**
+ * hdd_driver_memdump_read() - perform read operation in driver
+ * memory dump proc file
+ * @file  - handle for the proc file.
+ * @buf   - pointer to user space buffer.
+ * @count - number of bytes to be read.
+ * @pos   - offset in the from buffer.
+ *
+ * This function performs read operation for the driver memory dump proc file.
+ *
+ * Return: number of bytes read on success, error code otherwise.
+ */
+static ssize_t hdd_driver_memdump_read(struct file *file, char __user *buf,
+					size_t count, loff_t *pos)
+{
+	int status;
+	QDF_STATUS qdf_status;
+	hdd_context_t *hdd_ctx;
+	size_t no_of_bytes_read = 0;
+
+	hdd_ctx = memdump_get_file_data(file);
+
+	hdd_notice("Read req for size:%zu pos:%llu", count, *pos);
+	status = wlan_hdd_validate_context(hdd_ctx);
+	if (status != 0)
+		return -EINVAL;
+
+	if (*pos < 0) {
+		hdd_err("Invalid start offset for memdump read");
+		return -EINVAL;
+	} else if (!count || (hdd_ctx->driver_dump_size &&
+				(*pos >= hdd_ctx->driver_dump_size))) {
+		hdd_err("No more data to copy");
+		return 0;
+	} else if ((*pos == 0) || (hdd_ctx->driver_dump_mem == NULL)) {
+		/*
+		 * Allocate memory for Driver memory dump.
+		 */
+		if (!hdd_ctx->driver_dump_mem) {
+			hdd_ctx->driver_dump_mem =
+				qdf_mem_malloc(DRIVER_MEM_DUMP_SIZE);
+			if (!hdd_ctx->driver_dump_mem) {
+				hdd_err("qdf_mem_malloc failed");
+				return -ENOMEM;
+			}
+		}
+
+		qdf_status = qdf_state_info_dump_all(hdd_ctx->driver_dump_mem,
+						DRIVER_MEM_DUMP_SIZE,
+						&hdd_ctx->driver_dump_size);
+		/*
+		 * If qdf_status is QDF_STATUS_E_NOMEM, then memory allocated is
+		 * insufficient to dump driver information. This print can give
+		 * information to allocate more memory if more information from
+		 * each layer is added in future.
+		 */
+		if (qdf_status != QDF_STATUS_SUCCESS)
+			hdd_err("Error in dump driver information, status %d",
+				qdf_status);
+		hdd_notice("driver_dump_size: %d",
+					hdd_ctx->driver_dump_size);
+	}
+
+	if (count > hdd_ctx->driver_dump_size - *pos)
+		no_of_bytes_read = hdd_ctx->driver_dump_size - *pos;
+	else
+		no_of_bytes_read = count;
+
+	if (copy_to_user(buf, hdd_ctx->driver_dump_mem + *pos,
+					no_of_bytes_read)) {
+		hdd_err("copy to user space failed");
+		return -EFAULT;
+	}
+
+	/* offset(pos) should be updated here based on the copy done */
+	*pos += no_of_bytes_read;
+
+	/* Entire driver memory dump copy completed */
+	if (*pos >= hdd_ctx->driver_dump_size)
+		hdd_driver_mem_cleanup();
+
+	return no_of_bytes_read;
+}
+
+
+/**
+ * struct driver_dump_fops - file operations for driver dump feature
+ * @read - read function for driver dump operation.
+ *
+ * This structure initialize the file operation handle for memory
+ * dump feature
+ */
+static const struct file_operations driver_dump_fops = {
+read: hdd_driver_memdump_read
+};
+
+/**
+ * hdd_driver_memdump_procfs_init() - Initialize procfs for driver memory dump
+ *
+ * This function create file under proc file system to be used later for
+ * processing driver memory dump
+ *
+ * Return:   0 on success, error code otherwise.
+ */
+static int hdd_driver_memdump_procfs_init(void)
+{
+	hdd_context_t *hdd_ctx;
+
+	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+	if (!hdd_ctx) {
+		hdd_err("Invalid HDD context");
+		return -EINVAL;
+	}
+
+	proc_dir_driver = proc_mkdir(PROCFS_DRIVER_DUMP_DIR, NULL);
+	if (proc_dir_driver == NULL) {
+		pr_debug("Error: Could not initialize /proc/%s\n",
+			 PROCFS_DRIVER_DUMP_DIR);
+		return -ENOMEM;
+	}
+
+	proc_file_driver = proc_create_data(PROCFS_DRIVER_DUMP_NAME,
+				     PROCFS_DRIVER_DUMP_PERM, proc_dir_driver,
+				     &driver_dump_fops, hdd_ctx);
+	if (proc_file_driver == NULL) {
+		remove_proc_entry(PROCFS_DRIVER_DUMP_NAME, proc_dir_driver);
+		pr_debug("Error: Could not initialize /proc/%s\n",
+			  PROCFS_DRIVER_DUMP_NAME);
+		return -ENOMEM;
+	}
+
+	pr_debug("/proc/%s/%s created\n", PROCFS_DRIVER_DUMP_DIR,
+		 PROCFS_DRIVER_DUMP_NAME);
+	return 0;
+}
+
+/**
+ * hdd_driver_memdump_procfs_remove() - Remove file/dir under procfs
+ * for driver memory dump
+ *
+ * This function removes file/dir under proc file system that was
+ * processing driver memory dump
+ *
+ * Return:  None
+ */
+static void hdd_driver_memdump_procfs_remove(void)
+{
+	remove_proc_entry(PROCFS_DRIVER_DUMP_NAME, proc_dir_driver);
+	pr_debug("/proc/%s/%s removed\n", PROCFS_DRIVER_DUMP_DIR,
+					  PROCFS_DRIVER_DUMP_NAME);
+	remove_proc_entry(PROCFS_DRIVER_DUMP_DIR, NULL);
+	pr_debug("/proc/%s removed\n", PROCFS_DRIVER_DUMP_DIR);
+}
+
+/**
+ * hdd_driver_memdump_init() - Intialization function for driver
+ * memory dump feature
+ *
+ * This function creates proc file for driver memdump feature
+ *
+ * Return - 0 on success, error otherwise
+ */
+int hdd_driver_memdump_init(void)
+{
+	int status;
+
+	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
+		hdd_err("Not initializing memdump in FTM mode");
+		return -EINVAL;
+	}
+
+	status = hdd_driver_memdump_procfs_init();
+	if (status) {
+		hdd_err("Failed to create proc file");
+		return status;
+	}
+
+	return 0;
+}
+
+/**
+ * hdd_driver_memdump_deinit() - De initialize driver memdump feature
+ *
+ * This function removes proc file created for driver memdump feature.
+ *
+ * Return: None
+ */
+void hdd_driver_memdump_deinit(void)
+{
+	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
+		hdd_err("Not deinitializing memdump in FTM mode");
+		return;
+	}
+
+	hdd_driver_memdump_procfs_remove();
+
+	hdd_driver_mem_cleanup();
+}

+ 59 - 0
core/mac/src/pe/lim/lim_api.c

@@ -681,6 +681,63 @@ void lim_cleanup(tpAniSirGlobal pMac)
 
 } /*** end lim_cleanup() ***/
 
+/**
+ * lim_state_info_dump() - print state information of lim layer
+ * @buf: buffer pointer
+ * @size: size of buffer to be filled
+ *
+ * This function is used to print state information of lim layer
+ *
+ * Return: None
+ */
+static void lim_state_info_dump(char **buf_ptr, uint16_t *size)
+{
+	tHalHandle hal;
+	tpAniSirGlobal mac;
+	uint16_t len = 0;
+	char *buf = *buf_ptr;
+
+	hal = cds_get_context(QDF_MODULE_ID_PE);
+	if (hal == NULL) {
+		QDF_ASSERT(0);
+		return;
+	}
+
+	mac = PMAC_STRUCT(hal);
+
+	lim_log(mac, LOG1, FL("size of buffer: %d"), *size);
+
+	len += qdf_scnprintf(buf + len, *size - len,
+		"\n SmeState: %d", mac->lim.gLimSmeState);
+	len += qdf_scnprintf(buf + len, *size - len,
+		"\n PrevSmeState: %d", mac->lim.gLimPrevSmeState);
+	len += qdf_scnprintf(buf + len, *size - len,
+		"\n MlmState: %d", mac->lim.gLimMlmState);
+	len += qdf_scnprintf(buf + len, *size - len,
+		"\n PrevMlmState: %d", mac->lim.gLimPrevMlmState);
+	len += qdf_scnprintf(buf + len, *size - len,
+		"\n SystemInScanLearnMode: %d",
+		mac->lim.gLimSystemInScanLearnMode);
+	len += qdf_scnprintf(buf + len, *size - len,
+		"\n ProcessDefdMsgs: %d", mac->lim.gLimProcessDefdMsgs);
+	len += qdf_scnprintf(buf + len, *size - len,
+		"\n gLimHalScanState: %d", mac->lim.gLimHalScanState);
+
+	*size -= len;
+	*buf_ptr += len;
+}
+
+/**
+ * lim_register_debug_callback() - registration function for lim layer
+ * to print lim state information
+ *
+ * Return: None
+ */
+static void lim_register_debug_callback(void)
+{
+	qdf_register_debug_callback(QDF_MODULE_ID_PE, &lim_state_info_dump);
+}
+
 /** -------------------------------------------------------------
    \fn pe_open
    \brief will be called in Open sequence from mac_open
@@ -746,6 +803,8 @@ tSirRetStatus pe_open(tpAniSirGlobal pMac, struct cds_config_info *cds_cfg)
 #ifdef LIM_TRACE_RECORD
 	MTRACE(lim_trace_init(pMac));
 #endif
+	lim_register_debug_callback();
+
 	return status; /* status here will be eSIR_SUCCESS */
 
 pe_open_lock_fail:

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

@@ -1073,6 +1073,104 @@ bool sme_command_pending(tpAniSirGlobal pMac)
 					 LL_ACCESS_NOLOCK);
 }
 
+/**
+ * sme_get_sessionid_from_activelist() - gets session id
+ * @mac: mac context
+ *
+ * This function is used to get session id from sme command
+ * active list
+ *
+ * Return: returns session id
+ */
+uint32_t sme_get_sessionid_from_activelist(tpAniSirGlobal mac)
+{
+	tListElem *entry;
+	tSmeCmd *command;
+	uint32_t session_id = CSR_SESSION_ID_INVALID;
+
+	entry = csr_ll_peek_head(&mac->sme.smeCmdActiveList, LL_ACCESS_LOCK);
+	if (entry) {
+		command = GET_BASE_ADDR(entry, tSmeCmd, Link);
+		session_id = command->sessionId;
+	}
+
+	return session_id;
+}
+
+/**
+ * sme_state_info_dump() - prints state information of sme layer
+ * @buf: buffer pointer
+ * @size: size of buffer to be filled
+ *
+ * This function is used to dump state information of sme layer
+ *
+ * Return: None
+ */
+static void sme_state_info_dump(char **buf_ptr, uint16_t *size)
+{
+	uint32_t session_id, active_session_id;
+	tHalHandle hal;
+	tpAniSirGlobal mac;
+	uint16_t len = 0;
+	char *buf = *buf_ptr;
+	eCsrConnectState connect_state;
+
+	hal = cds_get_context(QDF_MODULE_ID_SME);
+	if (hal == NULL) {
+		QDF_ASSERT(0);
+		return;
+	}
+
+	mac = PMAC_STRUCT(hal);
+	sms_log(mac, LOG1, FL("size of buffer: %d"), *size);
+
+	active_session_id = sme_get_sessionid_from_activelist(mac);
+	if (active_session_id != CSR_SESSION_ID_INVALID) {
+		len += qdf_scnprintf(buf + len, *size - len,
+			"\n active command sessionid %d", active_session_id);
+	}
+
+	for (session_id = 0; session_id < CSR_ROAM_SESSION_MAX; session_id++) {
+		if (CSR_IS_SESSION_VALID(mac, session_id)) {
+			connect_state =
+				mac->roam.roamSession[session_id].connectState;
+			if ((eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED ==
+			     connect_state)
+			    || (eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED ==
+				connect_state)) {
+				len += qdf_scnprintf(buf + len, *size - len,
+					"\n NeighborRoamState: %d",
+					mac->roam.neighborRoamInfo[session_id].
+						neighborRoamState);
+				len += qdf_scnprintf(buf + len, *size - len,
+					"\n RoamState: %d", mac->roam.
+						curState[session_id]);
+				len += qdf_scnprintf(buf + len, *size - len,
+					"\n RoamSubState: %d", mac->roam.
+						curSubState[session_id]);
+				len += qdf_scnprintf(buf + len, *size - len,
+					"\n ConnectState: %d",
+					connect_state);
+			}
+		}
+	}
+
+	*size -= len;
+	*buf_ptr += len;
+}
+
+/**
+ * sme_register_debug_callback() - registration function sme layer
+ * to print sme state information
+ *
+ * Return: None
+ */
+static void sme_register_debug_callback(void)
+{
+	qdf_register_debug_callback(QDF_MODULE_ID_SME, &sme_state_info_dump);
+}
+
+
 /* Global APIs */
 
 /**
@@ -1134,6 +1232,7 @@ QDF_STATUS sme_open(tHalHandle hHal)
 	}
 	sme_p2p_open(pMac);
 	sme_trace_init(pMac);
+	sme_register_debug_callback();
 	return status;
 }
 

+ 142 - 0
core/wma/src/wma_main.c

@@ -1672,6 +1672,146 @@ static void wma_init_max_no_of_peers(tp_wma_handle wma_handle,
 
 struct wma_version_info g_wmi_version_info;
 
+/**
+ * wma_state_info_dump() - prints state information of wma layer
+ * @buf: buffer pointer
+ * @size: size of buffer to be filled
+ *
+ * This function is used to dump state information of wma layer
+ *
+ * Return: None
+ */
+static void wma_state_info_dump(char **buf_ptr, uint16_t *size)
+{
+	tp_wma_handle wma_handle;
+	uint16_t len = 0;
+	char *buf = *buf_ptr;
+	struct wma_txrx_node *iface;
+	uint8_t vdev_id;
+
+	wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
+	if (!wma_handle) {
+		WMA_LOGE("%s: WMA context is invald!", __func__);
+		return;
+	}
+
+	WMA_LOGI("%s: size of buffer: %d", __func__, *size);
+
+	len += qdf_scnprintf(buf + len, *size - len,
+		"\n wow_pno_match_wake_up_count %d",
+		wma_handle->wow_pno_match_wake_up_count);
+	len += qdf_scnprintf(buf + len, *size - len,
+		"\n wow_pno_complete_wake_up_count %d",
+		wma_handle->wow_pno_complete_wake_up_count);
+	len += qdf_scnprintf(buf + len, *size - len,
+		"\n wow_gscan_wake_up_count %d",
+		wma_handle->wow_gscan_wake_up_count);
+	len += qdf_scnprintf(buf + len, *size - len,
+		"\n wow_low_rssi_wake_up_count %d",
+		wma_handle->wow_low_rssi_wake_up_count);
+	len += qdf_scnprintf(buf + len, *size - len,
+		"\n wow_rssi_breach_wake_up_count %d",
+		wma_handle->wow_rssi_breach_wake_up_count);
+	len += qdf_scnprintf(buf + len, *size - len,
+		"\n wow_ucast_wake_up_count %d",
+		wma_handle->wow_ucast_wake_up_count);
+	len += qdf_scnprintf(buf + len, *size - len,
+		"\n wow_bcast_wake_up_count %d",
+		wma_handle->wow_bcast_wake_up_count);
+	len += qdf_scnprintf(buf + len, *size - len,
+		"\n wow_ipv4_mcast_wake_up_count %d",
+		wma_handle->wow_ipv4_mcast_wake_up_count);
+	len += qdf_scnprintf(buf + len, *size - len,
+		"\n wow_ipv6_mcast_ra_stats %d",
+		wma_handle->wow_ipv6_mcast_ra_stats);
+	len += qdf_scnprintf(buf + len, *size - len,
+		"\n wow_ipv6_mcast_ns_stats %d",
+		wma_handle->wow_ipv6_mcast_ns_stats);
+	len += qdf_scnprintf(buf + len, *size - len,
+		"\n wow_ipv6_mcast_na_stats %d",
+		wma_handle->wow_ipv6_mcast_na_stats);
+
+	for (vdev_id = 0; vdev_id < wma_handle->max_bssid; vdev_id++) {
+		if (!wma_handle->interfaces[vdev_id].handle)
+			continue;
+
+		iface = &wma_handle->interfaces[vdev_id];
+
+		len += qdf_scnprintf(buf + len, *size - len,
+			"\n vdev_id %d",
+			vdev_id);
+		len += qdf_scnprintf(buf + len, *size - len,
+			"\n conn_state %d",
+			iface->conn_state);
+		len += qdf_scnprintf(buf + len, *size - len,
+			"\n dtimPeriod %d",
+			iface->dtimPeriod);
+		len += qdf_scnprintf(buf + len, *size - len,
+			"\n chanmode %d",
+			iface->chanmode);
+		len += qdf_scnprintf(buf + len, *size - len,
+			"\n vht_capable %d",
+			iface->vht_capable);
+		len += qdf_scnprintf(buf + len, *size - len,
+			"\n ht_capable %d",
+			iface->ht_capable);
+		len += qdf_scnprintf(buf + len, *size - len,
+			"\n chan_width %d",
+			iface->chan_width);
+		len += qdf_scnprintf(buf + len, *size - len,
+			"\n vdev_active %d",
+			iface->vdev_active);
+		len += qdf_scnprintf(buf + len, *size - len,
+			"\n vdev_up %d",
+			iface->vdev_up);
+		len += qdf_scnprintf(buf + len, *size - len,
+			"\n aid %d",
+			iface->aid);
+		len += qdf_scnprintf(buf + len, *size - len,
+			"\n rate_flags %d",
+			iface->rate_flags);
+		len += qdf_scnprintf(buf + len, *size - len,
+			"\n nss %d",
+			iface->nss);
+		len += qdf_scnprintf(buf + len, *size - len,
+			"\n tx_power %d",
+			iface->tx_power);
+		len += qdf_scnprintf(buf + len, *size - len,
+			"\n max_tx_power %d",
+			iface->max_tx_power);
+		len += qdf_scnprintf(buf + len, *size - len,
+			"\n nwType %d",
+			iface->nwType);
+		len += qdf_scnprintf(buf + len, *size - len,
+			"\n tx_streams %d",
+			iface->tx_streams);
+		len += qdf_scnprintf(buf + len, *size - len,
+			"\n rx_streams %d",
+			iface->rx_streams);
+		len += qdf_scnprintf(buf + len, *size - len,
+			"\n chain_mask %d",
+			iface->chain_mask);
+		len += qdf_scnprintf(buf + len, *size - len,
+			"\n nss_2g %d",
+			iface->nss_2g);
+		len += qdf_scnprintf(buf + len, *size - len,
+			"\n nss_5g %d",
+			iface->nss_5g);
+	}
+
+	*size -= len;
+	*buf_ptr += len;
+}
+
+/**
+ * wma_register_debug_callback() - registration function for wma layer
+ * to print wma state information
+ */
+static void wma_register_debug_callback(void)
+{
+	qdf_register_debug_callback(QDF_MODULE_ID_WMA, &wma_state_info_dump);
+}
+
 /**
  * wma_open() - Allocate wma context and initialize it.
  * @cds_context:  cds context
@@ -2157,6 +2297,8 @@ QDF_STATUS wma_open(void *cds_context,
 				wma_encrypt_decrypt_msg_handler,
 				WMA_RX_SERIALIZER_CTX);
 	wma_ndp_register_all_event_handlers(wma_handle);
+	wma_register_debug_callback();
+
 	return QDF_STATUS_SUCCESS;
 
 err_dbglog_init: