|
@@ -77,9 +77,39 @@ static QDF_STATUS scheduler_close(struct scheduler_ctx *sched_ctx)
|
|
|
/* Deinit all the queues */
|
|
|
scheduler_queues_deinit(sched_ctx);
|
|
|
|
|
|
+ qdf_timer_free(&sched_ctx->watchdog_timer);
|
|
|
+
|
|
|
return QDF_STATUS_SUCCESS;
|
|
|
}
|
|
|
|
|
|
+static inline void scheduler_watchdog_notify(struct scheduler_ctx *sched)
|
|
|
+{
|
|
|
+ char symbol[QDF_SYMBOL_LEN] = "<null>";
|
|
|
+
|
|
|
+ if (sched->watchdog_callback)
|
|
|
+ qdf_sprint_symbol(symbol, sched->watchdog_callback);
|
|
|
+
|
|
|
+ QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
|
|
|
+ "%s: Callback %s (type 0x%x) has exceeded its allotted time of %ds",
|
|
|
+ __func__, symbol, sched->watchdog_msg_type,
|
|
|
+ SCHEDULER_WATCHDOG_TIMEOUT / 1000);
|
|
|
+}
|
|
|
+
|
|
|
+#ifdef CONFIG_SLUB_DEBUG_ON
|
|
|
+static void scheduler_watchdog_bite(void *arg)
|
|
|
+{
|
|
|
+ scheduler_watchdog_notify((struct scheduler_ctx *)arg);
|
|
|
+ QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
|
|
|
+ "%s: Going down for Scheduler Watchdog Bite!", __func__);
|
|
|
+ QDF_BUG(0);
|
|
|
+}
|
|
|
+#else
|
|
|
+static void scheduler_watchdog_bite(void *arg)
|
|
|
+{
|
|
|
+ scheduler_watchdog_notify((struct scheduler_ctx *)arg);
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
static QDF_STATUS scheduler_open(struct scheduler_ctx *sched_ctx)
|
|
|
{
|
|
|
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_INFO_HIGH,
|
|
@@ -98,6 +128,12 @@ static QDF_STATUS scheduler_open(struct scheduler_ctx *sched_ctx)
|
|
|
qdf_spinlock_create(&sched_ctx->sch_thread_lock);
|
|
|
qdf_init_waitqueue_head(&sched_ctx->sch_wait_queue);
|
|
|
sched_ctx->sch_event_flag = 0;
|
|
|
+ qdf_timer_init(NULL,
|
|
|
+ &sched_ctx->watchdog_timer,
|
|
|
+ &scheduler_watchdog_bite,
|
|
|
+ sched_ctx,
|
|
|
+ QDF_TIMER_TYPE_SW);
|
|
|
+
|
|
|
/* Create the Scheduler Main Controller thread */
|
|
|
sched_ctx->sch_thread = qdf_create_thread(scheduler_thread,
|
|
|
sched_ctx, "scheduler_thread");
|