diff --git a/wmi/src/wmi_unified.c b/wmi/src/wmi_unified.c index f9d9bb6b9d..3fc290ba53 100644 --- a/wmi/src/wmi_unified.c +++ b/wmi/src/wmi_unified.c @@ -2473,6 +2473,30 @@ end: } +#define WMI_WQ_WD_TIMEOUT (10 * 1000) /* 10s */ + +static inline void wmi_workqueue_watchdog_warn(uint16_t msg_type_id) +{ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Message type %x has exceeded its alloted time of %ds", + __func__, msg_type_id, WMI_WQ_WD_TIMEOUT / 1000); +} + +#ifdef CONFIG_SLUB_DEBUG_ON +static void wmi_workqueue_watchdog_bite(void *arg) +{ + wmi_workqueue_watchdog_warn(*(uint16_t *)arg); + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Going down for WMI WQ Watchdog Bite!", __func__); + QDF_BUG(0); +} +#else +static inline void wmi_workqueue_watchdog_bite(void *arg) +{ + wmi_workqueue_watchdog_warn(*(uint16_t *)arg); +} +#endif + /** * wmi_rx_event_work() - process rx event in rx work queue context * @arg: opaque pointer to wmi handle @@ -2485,16 +2509,26 @@ 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; + /* initialize WMI workqueue watchdog timer */ + qdf_timer_init(NULL, &wd_timer, &wmi_workqueue_watchdog_bite, + &wd_msg_type_id, 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 = + WMI_GET_FIELD(qdf_nbuf_data(buf), WMI_CMD_HDR, COMMANDID); __wmi_control_rx(wmi, buf); + qdf_timer_stop(&wd_timer); qdf_spin_lock_bh(&wmi->eventq_lock); buf = qdf_nbuf_queue_remove(&wmi->event_queue); qdf_spin_unlock_bh(&wmi->eventq_lock); } + qdf_timer_free(&wd_timer); } #ifdef FEATURE_RUNTIME_PM