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_mem.h"
|
||||||
#include "qdf_status.h"
|
#include "qdf_status.h"
|
||||||
#include "qdf_str.h"
|
#include "qdf_str.h"
|
||||||
|
#include "qdf_timer.h"
|
||||||
#include "__wlan_dsc.h"
|
#include "__wlan_dsc.h"
|
||||||
|
|
||||||
#ifdef WLAN_DSC_DEBUG
|
#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
|
* __dsc_dbg_ops_init() - initialize debug ops data structures
|
||||||
* @ops: the ops container to initialize
|
* @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)
|
static QDF_STATUS __dsc_dbg_ops_insert(struct dsc_ops *ops, const char *func)
|
||||||
{
|
{
|
||||||
|
QDF_STATUS status;
|
||||||
struct dsc_op *op;
|
struct dsc_op *op;
|
||||||
|
|
||||||
op = qdf_mem_malloc(sizeof(*op));
|
op = qdf_mem_malloc(sizeof(*op));
|
||||||
if (!op)
|
if (!op)
|
||||||
return QDF_STATUS_E_NOMEM;
|
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;
|
op->func = func;
|
||||||
|
|
||||||
|
qdf_timer_start(&op->timeout_timer, DSC_OP_TIMEOUT_MS);
|
||||||
qdf_list_insert_back(&ops->list, &op->node);
|
qdf_list_insert_back(&ops->list, &op->node);
|
||||||
|
|
||||||
return QDF_STATUS_SUCCESS;
|
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 */
|
/* this is safe because we cease iteration */
|
||||||
qdf_list_remove_node(&ops->list, &op->node);
|
qdf_list_remove_node(&ops->list, &op->node);
|
||||||
|
|
||||||
|
qdf_timer_stop(&op->timeout_timer);
|
||||||
|
qdf_timer_free(&op->timeout_timer);
|
||||||
qdf_mem_free(op);
|
qdf_mem_free(op);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
#include "qdf_event.h"
|
#include "qdf_event.h"
|
||||||
#include "qdf_list.h"
|
#include "qdf_list.h"
|
||||||
#include "qdf_trace.h"
|
#include "qdf_trace.h"
|
||||||
|
#include "qdf_timer.h"
|
||||||
#include "qdf_types.h"
|
#include "qdf_types.h"
|
||||||
#include "wlan_dsc.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
|
#ifdef WLAN_DSC_DEBUG
|
||||||
#define DSC_TRANS_TIMEOUT 120000 /* 2 minutes */
|
#define DSC_TRANS_TIMEOUT 120000 /* 2 minutes */
|
||||||
|
#define DSC_OP_TIMEOUT_MS (1 * 60 * 1000) /* 1 minute */
|
||||||
#else
|
#else
|
||||||
#define DSC_TRANS_TIMEOUT 0 /* no timeout */
|
#define DSC_TRANS_TIMEOUT 0 /* no timeout */
|
||||||
#endif
|
#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
|
* struct dsc_op - list node for operation tracking information
|
||||||
* @node: list node
|
* @node: list node
|
||||||
|
* @timeout_timer: a timer used to detect operation timeouts
|
||||||
* @func: name of the function the operation was started from
|
* @func: name of the function the operation was started from
|
||||||
*/
|
*/
|
||||||
struct dsc_op {
|
struct dsc_op {
|
||||||
qdf_list_node_t node;
|
qdf_list_node_t node;
|
||||||
|
qdf_timer_t timeout_timer;
|
||||||
const char *func;
|
const char *func;
|
||||||
};
|
};
|
||||||
#endif /* WLAN_DSC_DEBUG */
|
#endif /* WLAN_DSC_DEBUG */
|
||||||
|
Reference in New Issue
Block a user