From 39e01d0812918fab42719b8a80f8c01a1bd0fc32 Mon Sep 17 00:00:00 2001 From: Dustin Brown Date: Thu, 4 Oct 2018 13:32:50 -0700 Subject: [PATCH] qcacld-3.0: Add operation timeout detection to DSC In order to catch and debug long running or stuck operations, add a watchdog timer to Driver Synchronization Core (DSC) operation start/stop call pairs. If the timer expires, panic the driver for offline debugging. Change-Id: If93914178622b993fb09c7330fded2e9bc1c25d1 CRs-Fixed: 2328591 --- components/dsc/src/__wlan_dsc.c | 23 +++++++++++++++++++++++ components/dsc/src/__wlan_dsc.h | 4 ++++ 2 files changed, 27 insertions(+) diff --git a/components/dsc/src/__wlan_dsc.c b/components/dsc/src/__wlan_dsc.c index 25aad7846a68..e71b499b75f3 100644 --- a/components/dsc/src/__wlan_dsc.c +++ b/components/dsc/src/__wlan_dsc.c @@ -20,9 +20,18 @@ #include "qdf_mem.h" #include "qdf_status.h" #include "qdf_str.h" +#include "qdf_timer.h" #include "__wlan_dsc.h" #ifdef WLAN_DSC_DEBUG +static void __dsc_dbg_op_timeout(void *opaque_op) +{ + struct dsc_op *op = opaque_op; + + QDF_DEBUG_PANIC("Operation '%s' exceeded %ums", + op->func, DSC_OP_TIMEOUT_MS); +} + /** * __dsc_dbg_ops_init() - initialize debug ops data structures * @ops: the ops container to initialize @@ -54,17 +63,29 @@ static inline void __dsc_dbg_ops_deinit(struct dsc_ops *ops) */ static QDF_STATUS __dsc_dbg_ops_insert(struct dsc_ops *ops, const char *func) { + QDF_STATUS status; struct dsc_op *op; op = qdf_mem_malloc(sizeof(*op)); if (!op) return QDF_STATUS_E_NOMEM; + status = qdf_timer_init(NULL, &op->timeout_timer, __dsc_dbg_op_timeout, + op, QDF_TIMER_TYPE_SW); + if (QDF_IS_STATUS_ERROR(status)) + goto free_op; + op->func = func; + qdf_timer_start(&op->timeout_timer, DSC_OP_TIMEOUT_MS); qdf_list_insert_back(&ops->list, &op->node); return QDF_STATUS_SUCCESS; + +free_op: + qdf_mem_free(op); + + return status; } /** @@ -86,6 +107,8 @@ static void __dsc_dbg_ops_remove(struct dsc_ops *ops, const char *func) /* this is safe because we cease iteration */ qdf_list_remove_node(&ops->list, &op->node); + qdf_timer_stop(&op->timeout_timer); + qdf_timer_free(&op->timeout_timer); qdf_mem_free(op); return; diff --git a/components/dsc/src/__wlan_dsc.h b/components/dsc/src/__wlan_dsc.h index 103413d0d4ea..40ff29752e6b 100644 --- a/components/dsc/src/__wlan_dsc.h +++ b/components/dsc/src/__wlan_dsc.h @@ -26,6 +26,7 @@ #include "qdf_event.h" #include "qdf_list.h" #include "qdf_trace.h" +#include "qdf_timer.h" #include "qdf_types.h" #include "wlan_dsc.h" @@ -55,6 +56,7 @@ static inline bool __dsc_assert(const bool cond, const char *cond_str, #ifdef WLAN_DSC_DEBUG #define DSC_TRANS_TIMEOUT 120000 /* 2 minutes */ +#define DSC_OP_TIMEOUT_MS (1 * 60 * 1000) /* 1 minute */ #else #define DSC_TRANS_TIMEOUT 0 /* no timeout */ #endif @@ -63,10 +65,12 @@ static inline bool __dsc_assert(const bool cond, const char *cond_str, /** * struct dsc_op - list node for operation tracking information * @node: list node + * @timeout_timer: a timer used to detect operation timeouts * @func: name of the function the operation was started from */ struct dsc_op { qdf_list_node_t node; + qdf_timer_t timeout_timer; const char *func; }; #endif /* WLAN_DSC_DEBUG */