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
This commit is contained in:
Govind Singh
2017-11-21 10:53:40 +05:30
committed by snandini
parent e0c9f6699f
commit 11c7f8b00e
4 changed files with 38 additions and 5 deletions

View File

@@ -81,4 +81,10 @@ int qdf_wake_up_process(qdf_thread_t *thread);
*/ */
void qdf_print_thread_trace(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 */ #endif /* __QDF_THREADS_H */

View File

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

View File

@@ -48,6 +48,7 @@
#ifdef DFS_COMPONENT_ENABLE #ifdef DFS_COMPONENT_ENABLE
#include <wlan_dfs_public_struct.h> #include <wlan_dfs_public_struct.h>
#endif #endif
#include <qdf_threads.h>
#define WMI_UNIFIED_MAX_EVENT 0x100 #define WMI_UNIFIED_MAX_EVENT 0x100
#define WMI_MAX_CMDS 1024 #define WMI_MAX_CMDS 1024
@@ -175,6 +176,18 @@ struct fwdebug {
}; };
#endif /* WLAN_OPEN_SOURCE */ #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 { struct wmi_ops {
QDF_STATUS (*send_vdev_create_cmd)(wmi_unified_t wmi_handle, QDF_STATUS (*send_vdev_create_cmd)(wmi_unified_t wmi_handle,
uint8_t macaddr[IEEE80211_ADDR_LEN], uint8_t macaddr[IEEE80211_ADDR_LEN],

View File

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