Browse Source

qcacmn: Dump WMI work queue stack for watchdog bite

In the event of an WMI work queue watchdog bite, dump the stack
trace to aid in debugging.

Change-Id: I7f3df5a56904748fb80afb1aef1aed90d20fbbc0
CRs-Fixed: 2145913
Govind Singh 7 years ago
parent
commit
11c7f8b00e
4 changed files with 38 additions and 5 deletions
  1. 6 0
      qdf/inc/qdf_threads.h
  2. 6 0
      qdf/linux/src/qdf_threads.c
  3. 13 0
      wmi/inc/wmi_unified_priv.h
  4. 13 5
      wmi/src/wmi_unified.c

+ 6 - 0
qdf/inc/qdf_threads.h

@@ -81,4 +81,10 @@ int qdf_wake_up_process(qdf_thread_t *thread);
  */
 void qdf_print_thread_trace(qdf_thread_t *thread);
 
+/**
+ * qdf_get_current_task() - get current task struct
+ *
+ * Return: pointer to task struct
+ */
+qdf_thread_t *qdf_get_current_task(void);
 #endif /* __QDF_THREADS_H */

+ 6 - 0
qdf/linux/src/qdf_threads.c

@@ -45,6 +45,7 @@
 #include <linux/export.h>
 #include <linux/kthread.h>
 #include <linux/stacktrace.h>
+#include <qdf_defer.h>
 
 /* Function declarations and documenation */
 
@@ -154,3 +155,8 @@ void qdf_print_thread_trace(qdf_thread_t *thread) { }
 #endif /* KERNEL_VERSION(4, 14, 0) */
 EXPORT_SYMBOL(qdf_print_thread_trace);
 
+qdf_thread_t *qdf_get_current_task(void)
+{
+	return current;
+}
+EXPORT_SYMBOL(qdf_get_current_task);

+ 13 - 0
wmi/inc/wmi_unified_priv.h

@@ -48,6 +48,7 @@
 #ifdef DFS_COMPONENT_ENABLE
 #include <wlan_dfs_public_struct.h>
 #endif
+#include <qdf_threads.h>
 
 #define WMI_UNIFIED_MAX_EVENT 0x100
 #define WMI_MAX_CMDS 1024
@@ -175,6 +176,18 @@ struct fwdebug {
 };
 #endif /* WLAN_OPEN_SOURCE */
 
+/**
+ * struct wmi_wq_dbg_info - WMI WQ debug info
+ * @ wd_msg_type_id - wmi event id
+ * @ wmi_wq - WMI workqueue struct
+ * @ task - WMI workqueue task struct
+ */
+struct wmi_wq_dbg_info {
+	uint16_t wd_msg_type_id;
+	qdf_workqueue_t *wmi_wq;
+	qdf_thread_t *task;
+};
+
 struct wmi_ops {
 QDF_STATUS (*send_vdev_create_cmd)(wmi_unified_t wmi_handle,
 				 uint8_t macaddr[IEEE80211_ADDR_LEN],

+ 13 - 5
wmi/src/wmi_unified.c

@@ -1883,7 +1883,11 @@ static inline void wmi_workqueue_watchdog_warn(uint16_t msg_type_id)
 #ifdef CONFIG_SLUB_DEBUG_ON
 static void wmi_workqueue_watchdog_bite(void *arg)
 {
-	wmi_workqueue_watchdog_warn(*(uint16_t *)arg);
+	struct wmi_wq_dbg_info *info = arg;
+
+	wmi_workqueue_watchdog_warn(info->wd_msg_type_id);
+	qdf_print_thread_trace(info->task);
+
 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
 		  "%s: Going down for WMI WQ Watchdog Bite!", __func__);
 	QDF_BUG(0);
@@ -1891,7 +1895,9 @@ static void wmi_workqueue_watchdog_bite(void *arg)
 #else
 static inline void wmi_workqueue_watchdog_bite(void *arg)
 {
-	wmi_workqueue_watchdog_warn(*(uint16_t *)arg);
+	struct wmi_wq_dbg_info *info = arg;
+
+	wmi_workqueue_watchdog_warn(info->wd_msg_type_id);
 }
 #endif
 
@@ -1908,18 +1914,20 @@ static void wmi_rx_event_work(void *arg)
 	wmi_buf_t buf;
 	struct wmi_unified *wmi = arg;
 	qdf_timer_t wd_timer;
-	uint16_t wd_msg_type_id;
+	struct wmi_wq_dbg_info info;
 
 	/* initialize WMI workqueue watchdog timer */
 	qdf_timer_init(NULL, &wd_timer, &wmi_workqueue_watchdog_bite,
-			&wd_msg_type_id, QDF_TIMER_TYPE_SW);
+			&info, QDF_TIMER_TYPE_SW);
 	qdf_spin_lock_bh(&wmi->eventq_lock);
 	buf = qdf_nbuf_queue_remove(&wmi->event_queue);
 	qdf_spin_unlock_bh(&wmi->eventq_lock);
 	while (buf) {
 		qdf_timer_start(&wd_timer, WMI_WQ_WD_TIMEOUT);
-		wd_msg_type_id =
+		info.wd_msg_type_id =
 		   WMI_GET_FIELD(qdf_nbuf_data(buf), WMI_CMD_HDR, COMMANDID);
+		info.wmi_wq = wmi->wmi_rx_work_queue;
+		info.task = qdf_get_current_task();
 		__wmi_control_rx(wmi, buf);
 		qdf_timer_stop(&wd_timer);
 		qdf_spin_lock_bh(&wmi->eventq_lock);