Procházet zdrojové kódy

qcacmn: WMI command/event Extended dump using qdf_debugfs APIs

Currently only 16 bytes of wmi command/event messages are logged
excluding wmi header information.

By enabling WMI_EXT_DBG whole command/event messages can be dumped
using qdf debugfs apis. This will help if it is needed to
collect whole command/event messages information.

Change-Id: I72dff1279b1145b8d2ee415db97656f457c0136f
CRs-Fixed: 2309286
Venkat Karthik Kantamneni před 6 roky
rodič
revize
f902e52618
2 změnil soubory, kde provedl 375 přidání a 1 odebrání
  1. 99 0
      wmi/inc/wmi_unified_priv.h
  2. 276 1
      wmi/src/wmi_unified.c

+ 99 - 0
wmi/inc/wmi_unified_priv.h

@@ -53,6 +53,44 @@
 
 #define WMI_UNIFIED_MAX_EVENT 0x100
 
+#ifdef WMI_EXT_DBG
+
+#define WMI_EXT_DBG_DIR			"WMI_EXT_DBG"
+#define WMI_EXT_DBG_FILE		"wmi_log"
+#define WMI_EXT_DBG_FILE_PERM		(QDF_FILE_USR_READ | \
+					 QDF_FILE_GRP_READ | \
+					 QDF_FILE_OTH_READ)
+#define WMI_EXT_DBG_QUEUE_SIZE		1024
+#define WMI_EXT_DBG_DUMP_ROW_SIZE	16
+#define WMI_EXT_DBG_DUMP_GROUP_SIZE	1
+
+/**
+ * enum WMI_MSG_TYPE - WMI message types
+ * @ WMI_MSG_TYPE_CMD - Message is of type WMI command
+ * @ WMI_MSG_TYPE_EVENT - Message is of type WMI event
+ */
+enum WMI_MSG_TYPE {
+	WMI_MSG_TYPE_CMD = 0,
+	WMI_MSG_TYPE_EVENT,
+};
+
+/**
+ * struct wmi_ext_dbg_msg - WMI command/event msg details
+ * @ node - qdf list node of wmi messages
+ * @ len - command/event message length
+ * @ ts - Time of WMI command/event handling
+ * @ WMI_MSG_TYPE - message type
+ * @ bug - command/event buffer
+ */
+struct wmi_ext_dbg_msg {
+	qdf_list_node_t node;
+	uint32_t len;
+	uint64_t ts;
+	enum WMI_MSG_TYPE type;
+	uint8_t buf[0];
+};
+#endif /*WMI_EXT_DBG */
+
 #ifdef WMI_INTERFACE_EVENT_LOGGING
 
 #ifndef WMI_EVENT_DEBUG_MAX_ENTRY
@@ -1796,6 +1834,12 @@ struct wmi_unified {
 	struct wmi_soc *soc;
 	uint16_t wmi_max_cmds;
 	struct dentry *debugfs_de[NUM_DEBUG_INFOS];
+#ifdef WMI_EXT_DBG
+	int wmi_ext_dbg_msg_queue_size;
+	qdf_list_t wmi_ext_dbg_msg_queue;
+	qdf_spinlock_t wmi_ext_dbg_msg_queue_lock;
+	qdf_dentry_t wmi_ext_dbg_dentry;
+#endif /*WMI_EXT_DBG*/
 };
 
 #define WMI_MAX_RADIOS 3
@@ -1907,4 +1951,59 @@ static inline uint32_t wmi_vdev_map_to_num_vdevs(uint32_t vdev_map)
 
 	return num_vdevs;
 }
+
+#ifdef WMI_EXT_DBG
+
+/**
+ * wmi_ext_dbg_msg_get() - Allocate memory for wmi debug msg
+ *
+ * @buflen: Length of WMI message buffer
+ *
+ * Return: Allocated msg buffer else NULL on failure.
+ */
+static inline struct wmi_ext_dbg_msg *wmi_ext_dbg_msg_get(uint32_t buflen)
+{
+	return qdf_mem_malloc(sizeof(struct wmi_ext_dbg_msg) + buflen);
+}
+
+/**
+ * wmi_ext_dbg_msg_put() - Free wmi debug msg buffer
+ *
+ * @msg: wmi message buffer to be freed
+ *
+ * Return: none
+ */
+static inline void wmi_ext_dbg_msg_put(struct wmi_ext_dbg_msg *msg)
+{
+	qdf_mem_free(msg);
+}
+
+#else
+
+static inline QDF_STATUS wmi_ext_dbg_msg_cmd_record(struct wmi_unified
+						    *wmi_handle,
+						    uint8_t *buf, uint32_t len)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS wmi_ext_dbg_msg_event_record(struct wmi_unified
+						      *wmi_handle,
+						      uint8_t *buf,
+						      uint32_t len)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS wmi_ext_dbgfs_init(struct wmi_unified *wmi_handle)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS wmi_ext_dbgfs_deinit(struct wmi_unified *wmi_handle)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+#endif /*WMI_EXT_DBG */
 #endif

+ 276 - 1
wmi/src/wmi_unified.c

@@ -24,6 +24,9 @@
 #include "wmi_unified_priv.h"
 #include "wmi_unified_api.h"
 #include "qdf_module.h"
+#ifdef WMI_EXT_DBG
+#include "qdf_list.h"
+#endif
 
 #ifndef WMI_NON_TLV_SUPPORT
 #include "wmi_tlv_helper.h"
@@ -31,6 +34,271 @@
 
 #include <linux/debugfs.h>
 
+#ifdef WMI_EXT_DBG
+
+/**
+ * wmi_ext_dbg_msg_enqueue() - enqueue wmi message
+ *
+ * @wmi_handle: wmi handler
+ *
+ * Return: size of wmi message queue after enqueue
+ */
+static uint32_t wmi_ext_dbg_msg_enqueue(struct wmi_unified *wmi_handle,
+					struct wmi_ext_dbg_msg *msg)
+{
+	uint32_t list_size;
+
+	qdf_spinlock_acquire(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
+	qdf_list_insert_back_size(&wmi_handle->wmi_ext_dbg_msg_queue,
+				  &msg->node, &list_size);
+	qdf_spinlock_release(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
+
+	return list_size;
+}
+
+/**
+ * wmi_ext_dbg_msg_dequeue() - dequeue wmi message
+ *
+ * @wmi_handle: wmi handler
+ *
+ * Return: wmi msg on success else NULL
+ */
+static struct wmi_ext_dbg_msg *wmi_ext_dbg_msg_dequeue(struct wmi_unified
+						       *wmi_handle)
+{
+	qdf_list_node_t *list_node = NULL;
+
+	qdf_spinlock_acquire(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
+	qdf_list_remove_front(&wmi_handle->wmi_ext_dbg_msg_queue, &list_node);
+	qdf_spinlock_release(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
+
+	if (!list_node)
+		return NULL;
+
+	return qdf_container_of(list_node, struct wmi_ext_dbg_msg, node);
+}
+
+/**
+ * wmi_ext_dbg_msg_record() - record wmi messages
+ *
+ * @wmi_handle: wmi handler
+ * @buf: wmi message buffer
+ * @len: wmi message length
+ * @type: wmi message type
+ *
+ * Return: QDF_STATUS_SUCCESS on successful recording else failure.
+ */
+static QDF_STATUS wmi_ext_dbg_msg_record(struct wmi_unified *wmi_handle,
+					 uint8_t *buf, uint32_t len,
+					 enum WMI_MSG_TYPE type)
+{
+	struct wmi_ext_dbg_msg *msg;
+	uint32_t list_size;
+
+	msg = wmi_ext_dbg_msg_get(len);
+	if (!msg)
+		return QDF_STATUS_E_NOMEM;
+
+	msg->len = len;
+	msg->type = type;
+	qdf_mem_copy(msg->buf, buf, len);
+	msg->ts = qdf_get_log_timestamp();
+	list_size = wmi_ext_dbg_msg_enqueue(wmi_handle, msg);
+
+	if (list_size >= wmi_handle->wmi_ext_dbg_msg_queue_size) {
+		msg = wmi_ext_dbg_msg_dequeue(wmi_handle);
+		wmi_ext_dbg_msg_put(msg);
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * wmi_ext_dbg_msg_cmd_record() - record wmi command messages
+ *
+ * @wmi_handle: wmi handler
+ * @buf: wmi command buffer
+ * @len: wmi command message length
+ *
+ * Return: QDF_STATUS_SUCCESS on successful recording else failure.
+ */
+static QDF_STATUS wmi_ext_dbg_msg_cmd_record(struct wmi_unified *wmi_handle,
+					     uint8_t *buf, uint32_t len)
+{
+	return wmi_ext_dbg_msg_record(wmi_handle, buf, len,
+				      WMI_MSG_TYPE_CMD);
+}
+
+/**
+ * wmi_ext_dbg_msg_event_record() - record wmi event messages
+ *
+ * @wmi_handle: wmi handler
+ * @buf: wmi event buffer
+ * @len: wmi event message length
+ *
+ * Return: QDF_STATUS_SUCCESS on successful recording else failure.
+ */
+static QDF_STATUS wmi_ext_dbg_msg_event_record(struct wmi_unified *wmi_handle,
+					       uint8_t *buf, uint32_t len)
+{
+	uint32_t id;
+
+	id = WMI_GET_FIELD(buf, WMI_CMD_HDR, COMMANDID);
+	if (id != wmi_diag_event_id)
+		return wmi_ext_dbg_msg_record(wmi_handle, buf, len,
+					      WMI_MSG_TYPE_EVENT);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * wmi_ext_dbg_msg_queue_init() - create debugfs queue and associated lock
+ *
+ * @wmi_handle: wmi handler
+ *
+ * Return: none
+ */
+static void wmi_ext_dbg_msg_queue_init(struct wmi_unified *wmi_handle)
+{
+	qdf_list_create(&wmi_handle->wmi_ext_dbg_msg_queue,
+			wmi_handle->wmi_ext_dbg_msg_queue_size);
+	qdf_spinlock_create(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
+}
+
+/**
+ * wmi_ext_dbg_msg_queue_deinit() - destroy debugfs queue and associated lock
+ *
+ * @wmi_handle: wmi handler
+ *
+ * Return: none
+ */
+static void wmi_ext_dbg_msg_queue_deinit(struct wmi_unified *wmi_handle)
+{
+	qdf_list_destroy(&wmi_handle->wmi_ext_dbg_msg_queue);
+	qdf_spinlock_destroy(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
+}
+
+/**
+ * wmi_ext_dbg_msg_show() - debugfs function to display whole content of
+ * wmi command/event messages including headers.
+ *
+ * @file: qdf debugfs file handler
+ * @arg: pointer to wmi handler
+ *
+ * Return: QDF_STATUS_SUCCESS if all the messages are shown successfully,
+ * else QDF_STATUS_E_AGAIN if more data to show.
+ */
+static QDF_STATUS wmi_ext_dbg_msg_show(qdf_debugfs_file_t file, void *arg)
+{
+	struct wmi_unified *wmi_handle = (struct wmi_unified *)arg;
+	struct wmi_ext_dbg_msg *msg;
+	uint64_t secs, usecs;
+
+	msg = wmi_ext_dbg_msg_dequeue(wmi_handle);
+	if (!msg)
+		return QDF_STATUS_SUCCESS;
+
+	qdf_debugfs_printf(file, "%s: 0x%x\n",
+			   msg->type == WMI_MSG_TYPE_CMD ? "COMMAND" :
+			   "EVENT", WMI_GET_FIELD(msg->buf, WMI_CMD_HDR,
+						  COMMANDID));
+	qdf_log_timestamp_to_secs(msg->ts, &secs, &usecs);
+	qdf_debugfs_printf(file, "Time: %llu.%llu\n", secs, usecs);
+	qdf_debugfs_printf(file, "Length:%d\n", msg->len);
+	qdf_debugfs_hexdump(file, msg->buf, msg->len,
+			    WMI_EXT_DBG_DUMP_ROW_SIZE,
+			    WMI_EXT_DBG_DUMP_GROUP_SIZE);
+	qdf_debugfs_printf(file, "\n");
+
+	if (qdf_debugfs_overflow(file)) {
+		qdf_spinlock_acquire(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
+		qdf_list_insert_front(&wmi_handle->wmi_ext_dbg_msg_queue,
+				      &msg->node);
+		qdf_spinlock_release(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
+
+	} else {
+		wmi_ext_dbg_msg_put(msg);
+	}
+
+	return QDF_STATUS_E_AGAIN;
+}
+
+/**
+ * wmi_ext_dbg_msg_write() - debugfs write not supported
+ *
+ * @priv: private data
+ * @buf: received data buffer
+ * @len: length of received buffer
+ *
+ * Return: QDF_STATUS_E_NOSUPPORT.
+ */
+static QDF_STATUS wmi_ext_dbg_msg_write(void *priv, const char *buf,
+					qdf_size_t len)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+
+static struct qdf_debugfs_fops wmi_ext_dbgfs_ops = {
+	.show		= wmi_ext_dbg_msg_show,
+	.write		= wmi_ext_dbg_msg_write,
+	.priv		= NULL,
+};
+
+/**
+ * wmi_ext_debugfs_init() - init debugfs items for extended wmi dump.
+ *
+ * @wmi_handle: wmi handler
+ *
+ * Return: QDF_STATUS_SUCCESS if debugfs is initialized else
+ * QDF_STATUS_E_FAILURE
+ */
+static QDF_STATUS wmi_ext_dbgfs_init(struct wmi_unified *wmi_handle)
+{
+	qdf_dentry_t dentry;
+
+	dentry  = qdf_debugfs_create_dir(WMI_EXT_DBG_DIR, NULL);
+	if (!dentry) {
+		qdf_print("error while creating extended wmi debugfs dir");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	wmi_ext_dbgfs_ops.priv = wmi_handle;
+	if (!qdf_debugfs_create_file(WMI_EXT_DBG_FILE, WMI_EXT_DBG_FILE_PERM,
+				     dentry, &wmi_ext_dbgfs_ops)) {
+		qdf_debugfs_remove_dir(dentry);
+		qdf_print("error while creating extended wmi debugfs file");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	wmi_handle->wmi_ext_dbg_dentry = dentry;
+	wmi_handle->wmi_ext_dbg_msg_queue_size = WMI_EXT_DBG_QUEUE_SIZE;
+	wmi_ext_dbg_msg_queue_init(wmi_handle);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * wmi_ext_debugfs_deinit() - cleanup/deinit debugfs items of extended wmi dump.
+ *
+ * @wmi_handle: wmi handler
+ *
+ * Return: QDF_STATUS_SUCCESS if cleanup is successful
+ */
+static QDF_STATUS wmi_ext_dbgfs_deinit(struct wmi_unified *wmi_handle)
+{
+	struct wmi_ext_dbg_msg *msg;
+
+	while ((msg = wmi_ext_dbg_msg_dequeue(wmi_handle)))
+		wmi_ext_dbg_msg_put(msg);
+
+	wmi_ext_dbg_msg_queue_deinit(wmi_handle);
+	qdf_debugfs_remove_dir_recursive(wmi_handle->wmi_ext_dbg_dentry);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+#endif /*WMI_EXT_DBG */
+
 /* This check for CONFIG_WIN temporary added due to redeclaration compilation
 error in MCL. Error is caused due to inclusion of wmi.h in wmi_unified_api.h
 which gets included here through ol_if_athvar.h. Eventually it is expected that
@@ -1381,7 +1649,8 @@ QDF_STATUS wmi_unified_cmd_send_fl(wmi_unified_t wmi_handle, wmi_buf_t buf,
 #ifdef CONFIG_MCL
 	wmi_log_cmd_id(cmd_id, htc_tag);
 #endif
-
+	wmi_ext_dbg_msg_cmd_record(wmi_handle,
+				   qdf_nbuf_data(buf), qdf_nbuf_len(buf));
 #ifdef WMI_INTERFACE_EVENT_LOGGING
 	if (wmi_handle->log_info.wmi_logging_enable) {
 		qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock);
@@ -1796,6 +2065,9 @@ void __wmi_control_rx(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf)
 
 	id = WMI_GET_FIELD(qdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID);
 
+	wmi_ext_dbg_msg_event_record(wmi_handle, qdf_nbuf_data(evt_buf),
+				     qdf_nbuf_len(evt_buf));
+
 	if (qdf_nbuf_pull_head(evt_buf, sizeof(WMI_CMD_HDR)) == NULL)
 		goto end;
 
@@ -2175,6 +2447,8 @@ void *wmi_unified_attach(void *scn_handle,
 
 	soc->ops = wmi_handle->ops;
 	soc->wmi_pdev[0] = wmi_handle;
+	if (wmi_ext_dbgfs_init(wmi_handle) != QDF_STATUS_SUCCESS)
+		qdf_print("failed to initialize wmi extended debugfs");
 
 	return wmi_handle;
 
@@ -2198,6 +2472,7 @@ void wmi_unified_detach(struct wmi_unified *wmi_handle)
 	struct wmi_soc *soc;
 	uint8_t i;
 
+	wmi_ext_dbgfs_deinit(wmi_handle);
 	soc = wmi_handle->soc;
 	for (i = 0; i < WMI_MAX_RADIOS; i++) {
 		if (soc->wmi_pdev[i]) {