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
This commit is contained in:
@@ -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;
|
||||
|
@@ -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 */
|
||||
|
Reference in New Issue
Block a user