|
@@ -18,12 +18,21 @@
|
|
|
|
|
|
#include <scheduler_core.h>
|
|
|
#include <qdf_atomic.h>
|
|
|
+#include "qdf_flex_mem.h"
|
|
|
|
|
|
static struct scheduler_ctx g_sched_ctx;
|
|
|
static struct scheduler_ctx *gp_sched_ctx;
|
|
|
|
|
|
+#ifndef WLAN_SCHED_REDUCTION_LIMIT
|
|
|
+#define WLAN_SCHED_REDUCTION_LIMIT 0
|
|
|
+#endif
|
|
|
+
|
|
|
+DEFINE_QDF_FLEX_MEM_POOL(sched_pool, sizeof(struct scheduler_msg),
|
|
|
+ WLAN_SCHED_REDUCTION_LIMIT);
|
|
|
+
|
|
|
QDF_STATUS scheduler_create_ctx(void)
|
|
|
{
|
|
|
+ qdf_flex_mem_init(&sched_pool);
|
|
|
gp_sched_ctx = &g_sched_ctx;
|
|
|
|
|
|
return QDF_STATUS_SUCCESS;
|
|
@@ -32,15 +41,41 @@ QDF_STATUS scheduler_create_ctx(void)
|
|
|
QDF_STATUS scheduler_destroy_ctx(void)
|
|
|
{
|
|
|
gp_sched_ctx = NULL;
|
|
|
+ qdf_flex_mem_deinit(&sched_pool);
|
|
|
|
|
|
return QDF_STATUS_SUCCESS;
|
|
|
}
|
|
|
|
|
|
struct scheduler_ctx *scheduler_get_context(void)
|
|
|
{
|
|
|
+ QDF_BUG(gp_sched_ctx);
|
|
|
+
|
|
|
return gp_sched_ctx;
|
|
|
}
|
|
|
|
|
|
+static QDF_STATUS scheduler_mq_init(struct scheduler_mq_type *msg_q)
|
|
|
+{
|
|
|
+ sched_enter();
|
|
|
+
|
|
|
+ qdf_spinlock_create(&msg_q->mq_lock);
|
|
|
+ qdf_list_create(&msg_q->mq_list, SCHEDULER_CORE_MAX_MESSAGES);
|
|
|
+
|
|
|
+ sched_exit();
|
|
|
+
|
|
|
+ return QDF_STATUS_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+static void scheduler_mq_deinit(struct scheduler_mq_type *msg_q)
|
|
|
+{
|
|
|
+ sched_enter();
|
|
|
+
|
|
|
+ qdf_list_destroy(&msg_q->mq_list);
|
|
|
+ qdf_spinlock_destroy(&msg_q->mq_lock);
|
|
|
+
|
|
|
+ sched_exit();
|
|
|
+}
|
|
|
+
|
|
|
+static qdf_atomic_t __sched_queue_depth;
|
|
|
|
|
|
static QDF_STATUS scheduler_all_queues_init(struct scheduler_ctx *sched_ctx)
|
|
|
{
|
|
@@ -55,11 +90,7 @@ static QDF_STATUS scheduler_all_queues_init(struct scheduler_ctx *sched_ctx)
|
|
|
return QDF_STATUS_E_FAILURE;
|
|
|
}
|
|
|
|
|
|
- status = scheduler_mq_init(&sched_ctx->queue_ctx.free_msg_q);
|
|
|
- if (QDF_STATUS_SUCCESS != status)
|
|
|
- return status;
|
|
|
-
|
|
|
- sched_debug("free msg queue init complete");
|
|
|
+ qdf_atomic_set(&__sched_queue_depth, 0);
|
|
|
|
|
|
/* Initialize all message queues */
|
|
|
for (i = 0; i < SCHEDULER_NUMBER_OF_MSG_QUEUE; i++) {
|
|
@@ -78,7 +109,6 @@ static QDF_STATUS scheduler_all_queues_init(struct scheduler_ctx *sched_ctx)
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
static QDF_STATUS scheduler_all_queues_deinit(struct scheduler_ctx *sched_ctx)
|
|
|
{
|
|
|
int i;
|
|
@@ -91,10 +121,6 @@ static QDF_STATUS scheduler_all_queues_deinit(struct scheduler_ctx *sched_ctx)
|
|
|
return QDF_STATUS_E_FAILURE;
|
|
|
}
|
|
|
|
|
|
- scheduler_mq_deinit(&sched_ctx->queue_ctx.free_msg_q);
|
|
|
-
|
|
|
- sched_debug("free msg queue inited");
|
|
|
-
|
|
|
/* De-Initialize all message queues */
|
|
|
for (i = 0; i < SCHEDULER_NUMBER_OF_MSG_QUEUE; i++)
|
|
|
scheduler_mq_deinit(&sched_ctx->queue_ctx.sch_msg_q[i]);
|
|
@@ -109,108 +135,35 @@ static QDF_STATUS scheduler_all_queues_deinit(struct scheduler_ctx *sched_ctx)
|
|
|
return QDF_STATUS_SUCCESS;
|
|
|
}
|
|
|
|
|
|
-QDF_STATUS scheduler_mq_init(struct scheduler_mq_type *msg_q)
|
|
|
-{
|
|
|
- sched_enter();
|
|
|
-
|
|
|
- if (!msg_q) {
|
|
|
- sched_err("msg_q is null");
|
|
|
- return QDF_STATUS_E_FAILURE;
|
|
|
- }
|
|
|
-
|
|
|
- /* Now initialize the lock */
|
|
|
- qdf_spinlock_create(&msg_q->mq_lock);
|
|
|
-
|
|
|
- /* Now initialize the List data structure */
|
|
|
- qdf_list_create(&msg_q->mq_list, SCHEDULER_CORE_MAX_MESSAGES);
|
|
|
-
|
|
|
- sched_exit();
|
|
|
-
|
|
|
- return QDF_STATUS_SUCCESS;
|
|
|
-}
|
|
|
-
|
|
|
-void scheduler_mq_deinit(struct scheduler_mq_type *msg_q)
|
|
|
-{
|
|
|
- if (!msg_q)
|
|
|
- sched_err("msg_q is null");
|
|
|
-}
|
|
|
-
|
|
|
void scheduler_mq_put(struct scheduler_mq_type *msg_q,
|
|
|
- struct scheduler_msg_wrapper *msg_wrapper)
|
|
|
+ struct scheduler_msg *msg)
|
|
|
{
|
|
|
- if (!msg_q) {
|
|
|
- sched_err("msg_q is null");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (!msg_wrapper) {
|
|
|
- sched_err("msg_wrapper is null");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
qdf_spin_lock_irqsave(&msg_q->mq_lock);
|
|
|
- qdf_list_insert_back(&msg_q->mq_list, &msg_wrapper->msg_node);
|
|
|
+ qdf_list_insert_back(&msg_q->mq_list, &msg->node);
|
|
|
qdf_spin_unlock_irqrestore(&msg_q->mq_lock);
|
|
|
}
|
|
|
|
|
|
void scheduler_mq_put_front(struct scheduler_mq_type *msg_q,
|
|
|
- struct scheduler_msg_wrapper *msg_wrapper)
|
|
|
+ struct scheduler_msg *msg)
|
|
|
{
|
|
|
- if (!msg_q) {
|
|
|
- sched_err("msg_q is null");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (!msg_wrapper) {
|
|
|
- sched_err("msg_wrapper is null");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
qdf_spin_lock_irqsave(&msg_q->mq_lock);
|
|
|
- qdf_list_insert_front(&msg_q->mq_list, &msg_wrapper->msg_node);
|
|
|
+ qdf_list_insert_front(&msg_q->mq_list, &msg->node);
|
|
|
qdf_spin_unlock_irqrestore(&msg_q->mq_lock);
|
|
|
}
|
|
|
|
|
|
-struct scheduler_msg_wrapper *scheduler_mq_get(struct scheduler_mq_type *msg_q)
|
|
|
+struct scheduler_msg *scheduler_mq_get(struct scheduler_mq_type *msg_q)
|
|
|
{
|
|
|
- qdf_list_node_t *listptr;
|
|
|
- struct scheduler_msg_wrapper *msg_wrapper = NULL;
|
|
|
-
|
|
|
- if (!msg_q) {
|
|
|
- sched_err("msg_q is null");
|
|
|
- return NULL;
|
|
|
- }
|
|
|
+ QDF_STATUS status;
|
|
|
+ qdf_list_node_t *node;
|
|
|
|
|
|
qdf_spin_lock_irqsave(&msg_q->mq_lock);
|
|
|
- if (qdf_list_empty(&msg_q->mq_list)) {
|
|
|
- sched_warn("Scheduler Message Queue is empty");
|
|
|
- } else {
|
|
|
- listptr = msg_q->mq_list.anchor.next;
|
|
|
- msg_wrapper = (struct scheduler_msg_wrapper *)
|
|
|
- qdf_container_of(listptr,
|
|
|
- struct scheduler_msg_wrapper,
|
|
|
- msg_node);
|
|
|
- qdf_list_remove_node(&msg_q->mq_list, listptr);
|
|
|
- }
|
|
|
+ status = qdf_list_remove_front(&msg_q->mq_list, &node);
|
|
|
qdf_spin_unlock_irqrestore(&msg_q->mq_lock);
|
|
|
|
|
|
- return msg_wrapper;
|
|
|
-}
|
|
|
-
|
|
|
-bool scheduler_is_mq_empty(struct scheduler_mq_type *msg_q)
|
|
|
-{
|
|
|
- bool is_empty;
|
|
|
-
|
|
|
- if (!msg_q) {
|
|
|
- sched_err("msg_q is null");
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- qdf_spin_lock_irqsave(&msg_q->mq_lock);
|
|
|
- is_empty = qdf_list_empty(&msg_q->mq_list);
|
|
|
- qdf_spin_unlock_irqrestore(&msg_q->mq_lock);
|
|
|
+ if (QDF_IS_STATUS_ERROR(status))
|
|
|
+ return NULL;
|
|
|
|
|
|
- return is_empty;
|
|
|
+ return qdf_container_of(node, struct scheduler_msg, node);
|
|
|
}
|
|
|
|
|
|
QDF_STATUS scheduler_queues_deinit(struct scheduler_ctx *sched_ctx)
|
|
@@ -221,7 +174,6 @@ QDF_STATUS scheduler_queues_deinit(struct scheduler_ctx *sched_ctx)
|
|
|
QDF_STATUS scheduler_queues_init(struct scheduler_ctx *sched_ctx)
|
|
|
{
|
|
|
QDF_STATUS status;
|
|
|
- int i;
|
|
|
|
|
|
sched_enter();
|
|
|
|
|
@@ -232,7 +184,7 @@ QDF_STATUS scheduler_queues_init(struct scheduler_ctx *sched_ctx)
|
|
|
}
|
|
|
|
|
|
status = scheduler_all_queues_init(sched_ctx);
|
|
|
- if (QDF_STATUS_SUCCESS != status) {
|
|
|
+ if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
scheduler_all_queues_deinit(sched_ctx);
|
|
|
sched_err("Failed to initialize the msg queues");
|
|
|
return status;
|
|
@@ -240,40 +192,43 @@ QDF_STATUS scheduler_queues_init(struct scheduler_ctx *sched_ctx)
|
|
|
|
|
|
sched_debug("Queue init passed");
|
|
|
|
|
|
- for (i = 0; i < SCHEDULER_CORE_MAX_MESSAGES; i++) {
|
|
|
- (sched_ctx->queue_ctx.msg_wrappers[i]).msg_buf =
|
|
|
- &(sched_ctx->queue_ctx.msg_buffers[i]);
|
|
|
- qdf_init_list_head(
|
|
|
- &sched_ctx->queue_ctx.msg_wrappers[i].msg_node);
|
|
|
- scheduler_mq_put(&sched_ctx->queue_ctx.free_msg_q,
|
|
|
- &(sched_ctx->queue_ctx.msg_wrappers[i]));
|
|
|
- }
|
|
|
-
|
|
|
sched_exit();
|
|
|
|
|
|
return QDF_STATUS_SUCCESS;
|
|
|
}
|
|
|
|
|
|
-static void scheduler_core_return_msg(struct scheduler_ctx *sch_ctx,
|
|
|
- struct scheduler_msg_wrapper *msg_wrapper)
|
|
|
+struct scheduler_msg *scheduler_core_msg_dup(struct scheduler_msg *msg)
|
|
|
{
|
|
|
- if (!sch_ctx) {
|
|
|
- sched_err("sch_ctx is null");
|
|
|
- QDF_DEBUG_PANIC();
|
|
|
- return;
|
|
|
- }
|
|
|
+ struct scheduler_msg *dup;
|
|
|
|
|
|
- QDF_ASSERT(msg_wrapper);
|
|
|
- if (!msg_wrapper) {
|
|
|
- sched_err("msg_wrapper is null");
|
|
|
- return;
|
|
|
+ if (qdf_atomic_inc_return(&__sched_queue_depth) >
|
|
|
+ SCHEDULER_CORE_MAX_MESSAGES)
|
|
|
+ goto buffer_full;
|
|
|
+
|
|
|
+ dup = qdf_flex_mem_alloc(&sched_pool);
|
|
|
+ if (!dup) {
|
|
|
+ sched_err("out of memory");
|
|
|
+ goto dec_queue_count;
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- * Return the message on the free message queue
|
|
|
- */
|
|
|
- qdf_init_list_head(&msg_wrapper->msg_node);
|
|
|
- scheduler_mq_put(&sch_ctx->queue_ctx.free_msg_q, msg_wrapper);
|
|
|
+ qdf_mem_copy(dup, msg, sizeof(*dup));
|
|
|
+
|
|
|
+ return dup;
|
|
|
+
|
|
|
+buffer_full:
|
|
|
+ sched_err("Scheduler buffer is full");
|
|
|
+ QDF_DEBUG_PANIC();
|
|
|
+
|
|
|
+dec_queue_count:
|
|
|
+ qdf_atomic_dec(&__sched_queue_depth);
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+void scheduler_core_msg_free(struct scheduler_msg *msg)
|
|
|
+{
|
|
|
+ qdf_flex_mem_free(&sched_pool, msg);
|
|
|
+ qdf_atomic_dec(&__sched_queue_depth);
|
|
|
}
|
|
|
|
|
|
static void scheduler_thread_process_queues(struct scheduler_ctx *sch_ctx,
|
|
@@ -281,7 +236,7 @@ static void scheduler_thread_process_queues(struct scheduler_ctx *sch_ctx,
|
|
|
{
|
|
|
int i;
|
|
|
QDF_STATUS status;
|
|
|
- struct scheduler_msg_wrapper *msg_wrapper;
|
|
|
+ struct scheduler_msg *msg;
|
|
|
|
|
|
if (!sch_ctx) {
|
|
|
sched_err("sch_ctx is null");
|
|
@@ -309,23 +264,14 @@ static void scheduler_thread_process_queues(struct scheduler_ctx *sch_ctx,
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- if (scheduler_is_mq_empty(&sch_ctx->queue_ctx.sch_msg_q[i])) {
|
|
|
+ msg = scheduler_mq_get(&sch_ctx->queue_ctx.sch_msg_q[i]);
|
|
|
+ if (!msg) {
|
|
|
/* check next queue */
|
|
|
i++;
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- msg_wrapper =
|
|
|
- scheduler_mq_get(&sch_ctx->queue_ctx.sch_msg_q[i]);
|
|
|
- if (!msg_wrapper) {
|
|
|
- sched_err("msg_wrapper is NULL");
|
|
|
- QDF_ASSERT(0);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
if (sch_ctx->queue_ctx.scheduler_msg_process_fn[i]) {
|
|
|
- struct scheduler_msg *msg = msg_wrapper->msg_buf;
|
|
|
-
|
|
|
sch_ctx->watchdog_msg_type = msg->type;
|
|
|
sch_ctx->watchdog_callback = msg->callback;
|
|
|
qdf_timer_start(&sch_ctx->watchdog_timer,
|
|
@@ -338,14 +284,11 @@ static void scheduler_thread_process_queues(struct scheduler_ctx *sch_ctx,
|
|
|
sched_err("Failed processing Qid[%d] message",
|
|
|
sch_ctx->queue_ctx.sch_msg_q[i].qid);
|
|
|
|
|
|
- /* return message to the Core */
|
|
|
- scheduler_core_return_msg(sch_ctx, msg_wrapper);
|
|
|
+ scheduler_core_msg_free(msg);
|
|
|
}
|
|
|
|
|
|
/* start again with highest priority queue at index 0 */
|
|
|
i = 0;
|
|
|
-
|
|
|
- continue;
|
|
|
}
|
|
|
|
|
|
/* Check for any Suspend Indication */
|
|
@@ -410,47 +353,39 @@ int scheduler_thread(void *arg)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-void scheduler_cleanup_queues(struct scheduler_ctx *sch_ctx, int idx)
|
|
|
+static void scheduler_flush_single_queue(struct scheduler_mq_type *mq)
|
|
|
{
|
|
|
- struct scheduler_msg_wrapper *msg_wrapper;
|
|
|
- QDF_STATUS (*scheduler_flush_callback) (struct scheduler_msg *);
|
|
|
+ struct scheduler_msg *msg;
|
|
|
+ QDF_STATUS (*flush_cb)(struct scheduler_msg *);
|
|
|
+
|
|
|
+ while ((msg = scheduler_mq_get(mq))) {
|
|
|
+ if (msg->flush_callback) {
|
|
|
+ sched_info("Calling flush callback; type: %x",
|
|
|
+ msg->type);
|
|
|
+ flush_cb = msg->flush_callback;
|
|
|
+ flush_cb(msg);
|
|
|
+ } else if (msg->bodyptr) {
|
|
|
+ sched_info("Freeing scheduler msg bodyptr; type: %x",
|
|
|
+ msg->type);
|
|
|
+ qdf_mem_free(msg->bodyptr);
|
|
|
+ }
|
|
|
|
|
|
- if (!sch_ctx) {
|
|
|
- sched_err("sch_ctx is null");
|
|
|
- QDF_DEBUG_PANIC();
|
|
|
- return;
|
|
|
+ scheduler_core_msg_free(msg);
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- while ((msg_wrapper =
|
|
|
- scheduler_mq_get(&sch_ctx->queue_ctx.sch_msg_q[idx]))) {
|
|
|
- if (msg_wrapper->msg_buf) {
|
|
|
- if ((QDF_MODULE_ID_SYS ==
|
|
|
- sch_ctx->queue_ctx.sch_msg_q[idx].qid) &&
|
|
|
- (SYS_MSG_ID_MC_TIMER ==
|
|
|
- msg_wrapper->msg_buf->type)) {
|
|
|
- sched_debug("Timer is freed by each module, not here");
|
|
|
- continue;
|
|
|
- }
|
|
|
- sched_info("Freeing MC MSG message type %d, module id:%d",
|
|
|
- msg_wrapper->msg_buf->type,
|
|
|
- sch_ctx->queue_ctx.sch_msg_q[idx].qid);
|
|
|
- if (msg_wrapper->msg_buf->flush_callback) {
|
|
|
- sched_debug("Flush callback called for type-%x",
|
|
|
- msg_wrapper->msg_buf->type);
|
|
|
- scheduler_flush_callback =
|
|
|
- msg_wrapper->msg_buf->flush_callback;
|
|
|
- scheduler_flush_callback(msg_wrapper->msg_buf);
|
|
|
- } else if (msg_wrapper->msg_buf->bodyptr) {
|
|
|
- sched_debug("noflush cb given for type-%x",
|
|
|
- msg_wrapper->msg_buf->type);
|
|
|
- qdf_mem_free(msg_wrapper->msg_buf->bodyptr);
|
|
|
- }
|
|
|
+void scheduler_queues_flush(struct scheduler_ctx *sched_ctx)
|
|
|
+{
|
|
|
+ struct scheduler_mq_type *mq;
|
|
|
+ int i;
|
|
|
|
|
|
- msg_wrapper->msg_buf->bodyptr = NULL;
|
|
|
- msg_wrapper->msg_buf->bodyval = 0;
|
|
|
- msg_wrapper->msg_buf->type = 0;
|
|
|
- }
|
|
|
+ sched_info("Flushing scheduler message queues");
|
|
|
|
|
|
- scheduler_core_return_msg(sch_ctx, msg_wrapper);
|
|
|
+ for (i = 0; i < SCHEDULER_NUMBER_OF_MSG_QUEUE; i++) {
|
|
|
+ mq = &sched_ctx->queue_ctx.sch_msg_q[i];
|
|
|
+ scheduler_flush_single_queue(mq);
|
|
|
}
|
|
|
+
|
|
|
+ qdf_flex_mem_release(&sched_pool);
|
|
|
}
|
|
|
+
|