qcacmn: Rename control path scheduler from sch to scheduler

Legacy protocol engine already has a module name 'sch' rename
control path scheduler from sch to scheduler to avoid naming
conflict with protocol sch.

Change-Id: I94ce9aa5037aa75319aaad2287116462444c03f4
CRs-Fixed: 1105115
This commit is contained in:
Rajeev Kumar 2016-12-24 18:59:55 -08:00 • committed by qcabuildsw
commit cd39549564
4 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,557 @@
/*
* Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#include <scheduler_api.h>
#include <scheduler_core.h>
static void scheduler_flush_mqs(struct scheduler_ctx *sched_ctx)
{
int i;
/* Here each of the MC thread MQ shall be drained and returned to the
* Core. Before returning a wrapper to the Core, the Scheduler message
* shall be freed first
*/
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_INFO,
("Flushing scheduler message queue"));
if (!sched_ctx) {
QDF_ASSERT(0);
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: sched_ctx is NULL", __func__);
return;
}
for (i = 0; i < SCHEDULER_NUMBER_OF_MSG_QUEUE; i++)
scheduler_cleanup_queues(sched_ctx, i);
}
static QDF_STATUS scheduler_close(struct scheduler_ctx *sched_ctx)
{
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_INFO_HIGH,
"%s: invoked", __func__);
if (!sched_ctx) {
QDF_ASSERT(0);
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: sched_ctx == NULL", __func__);
return QDF_STATUS_E_FAILURE;
}
/* shut down scheduler thread */
qdf_set_bit(MC_SHUTDOWN_EVENT_MASK, &sched_ctx->sch_event_flag);
qdf_set_bit(MC_POST_EVENT_MASK, &sched_ctx->sch_event_flag);
qdf_wake_up_interruptible(&sched_ctx->sch_wait_queue);
/* Wait for MC to exit */
qdf_wait_single_event(&sched_ctx->sch_shutdown, 0);
sched_ctx->sch_thread = 0;
/* Clean up message queues of MC thread */
scheduler_flush_mqs(sched_ctx);
/* Deinit all the queues */
scheduler_queues_deinit(sched_ctx);
return QDF_STATUS_SUCCESS;
}
static QDF_STATUS scheduler_open(struct scheduler_ctx *sched_ctx)
{
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_INFO_HIGH,
"%s: Opening the QDF Scheduler", __func__);
/* Sanity checks */
if (!sched_ctx) {
QDF_ASSERT(0);
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: Null params being passed", __func__);
return QDF_STATUS_E_FAILURE;
}
/* Initialize the helper events and event queues */
qdf_event_create(&sched_ctx->sch_start_event);
qdf_event_create(&sched_ctx->sch_shutdown);
qdf_event_create(&sched_ctx->resume_sch_event);
qdf_spinlock_create(&sched_ctx->sch_thread_lock);
qdf_init_waitqueue_head(&sched_ctx->sch_wait_queue);
sched_ctx->sch_event_flag = 0;
/* Create the Scheduler Main Controller thread */
sched_ctx->sch_thread = qdf_create_thread(scheduler_thread,
sched_ctx, "scheduler_thread");
if (IS_ERR(sched_ctx->sch_thread)) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_FATAL,
"%s: Could not Create QDF Main Thread Controller",
__func__);
scheduler_queues_deinit(sched_ctx);
return QDF_STATUS_E_RESOURCES;
}
/* start the thread here */
qdf_wake_up_process(sched_ctx->sch_thread);
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: QDF Main Controller thread Created", __func__);
/*
* Now make sure all threads have started before we exit.
* Each thread should normally ACK back when it starts.
*/
qdf_wait_single_event(&sched_ctx->sch_start_event, 0);
/* We're good now: Let's get the ball rolling!!! */
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: Scheduler thread has started", __func__);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS scheduler_init(void)
{
QDF_STATUS status = QDF_STATUS_SUCCESS;
struct scheduler_ctx *sched_ctx;
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_INFO_HIGH,
FL("Opening Scheduler"));
status = scheduler_create_ctx();
if (QDF_STATUS_SUCCESS != status) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
FL("can't create scheduler ctx"));
return status;
}
sched_ctx = scheduler_get_context();
status = scheduler_queues_init(sched_ctx);
if (QDF_STATUS_SUCCESS != status) {
QDF_ASSERT(0);
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
FL("Queue init failed"));
scheduler_destroy_ctx();
return status;
}
status = scheduler_open(sched_ctx);
if (!QDF_IS_STATUS_SUCCESS(status)) {
/* Critical Error ... Cannot proceed further */
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_FATAL,
"Failed to open QDF Scheduler");
QDF_ASSERT(0);
scheduler_queues_deinit(sched_ctx);
scheduler_destroy_ctx();
}
qdf_register_mc_timer_callback(scheduler_mc_timer_callback);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS scheduler_deinit(void)
{
QDF_STATUS status = QDF_STATUS_SUCCESS;
struct scheduler_ctx *sched_ctx = scheduler_get_context();
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_INFO_HIGH,
FL("Closing Scheduler"));
status = scheduler_close(sched_ctx);
if (QDF_STATUS_SUCCESS != status) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
FL("Scheduler close failed"));
return status;
}
return scheduler_destroy_ctx();
}
QDF_STATUS scheduler_post_msg_by_priority(QDF_MODULE_ID qid,
struct scheduler_msg *pMsg, bool is_high_priority)
{
uint8_t qidx;
struct scheduler_mq_type *target_mq = NULL;
struct scheduler_msg_wrapper *msg_wrapper = NULL;
struct scheduler_ctx *sched_ctx = scheduler_get_context();
if (!sched_ctx || !pMsg) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: Null params or global sch context is null",
__func__);
QDF_ASSERT(0);
return QDF_STATUS_E_FAILURE;
}
/* Target_If is a special message queue in phase 3 convergence beacause
* its used by both legacy WMA and as well as new UMAC components which
* directly populate callback handlers in message body.
* 1) WMA legacy messages should not have callback
* 2) New target_if message needs to have valid callback
* Clear callback handler for legacy WMA messages such that in case
* if someone is sending legacy WMA message from stack which has
* uninitialized callback then its handled properly. Also change
* legacy WMA message queue id to target_if queue such that its always
* handled in right order.
*/
if (QDF_MODULE_ID_WMA == qid) {
pMsg->callback = NULL;
/* change legacy WMA message id to new target_if mq id */
qid = QDF_MODULE_ID_TARGET_IF;
}
qidx = sched_ctx->queue_ctx.scheduler_msg_qid_to_qidx[qid];
if (qidx >= SCHEDULER_NUMBER_OF_MSG_QUEUE) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
FL("Scheduler is deinitialized ignore msg"));
return QDF_STATUS_E_FAILURE;
}
if (!sched_ctx->queue_ctx.scheduler_msg_process_fn[qidx]) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
FL("callback not registered for qid[%d]"), qid);
QDF_ASSERT(0);
return QDF_STATUS_E_FAILURE;
}
target_mq = &(sched_ctx->queue_ctx.sch_msg_q[qidx]);
QDF_ASSERT(target_mq);
if (target_mq == NULL) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: target_mq == NULL", __func__);
return QDF_STATUS_E_FAILURE;
}
/* Try and get a free Msg wrapper */
msg_wrapper = scheduler_mq_get(&sched_ctx->queue_ctx.free_msg_q);
if (NULL == msg_wrapper) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
FL("message wrapper empty"));
return QDF_STATUS_E_RESOURCES;
}
/* Copy the message now */
qdf_mem_copy((void *)msg_wrapper->msg_buf,
(void *)pMsg, sizeof(struct scheduler_msg));
if (is_high_priority)
scheduler_mq_put_front(target_mq, msg_wrapper);
else
scheduler_mq_put(target_mq, msg_wrapper);
qdf_set_bit(MC_POST_EVENT_MASK, &sched_ctx->sch_event_flag);
qdf_wake_up_interruptible(&sched_ctx->sch_wait_queue);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS scheduler_register_module(QDF_MODULE_ID qid,
scheduler_msg_process_fn_t callback)
{
struct scheduler_mq_ctx *ctx;
struct scheduler_ctx *sched_ctx = scheduler_get_context();
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_INFO,
FL("Enter"));
if (!sched_ctx) {
QDF_ASSERT(0);
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
FL("sched_ctx is NULL"));
return QDF_STATUS_E_FAILURE;
}
if (sched_ctx->sch_last_qidx >= SCHEDULER_NUMBER_OF_MSG_QUEUE) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER,
QDF_TRACE_LEVEL_ERROR,
FL("Already registered max %d no of message queues"),
SCHEDULER_NUMBER_OF_MSG_QUEUE);
return QDF_STATUS_E_FAILURE;
}
ctx = &sched_ctx->queue_ctx;
ctx->scheduler_msg_qid_to_qidx[qid] = sched_ctx->sch_last_qidx;
ctx->sch_msg_q[sched_ctx->sch_last_qidx].qid = qid;
ctx->scheduler_msg_process_fn[sched_ctx->sch_last_qidx] = callback;
sched_ctx->sch_last_qidx++;
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_INFO,
FL("Exit"));
return QDF_STATUS_SUCCESS;
}
QDF_STATUS scheduler_deregister_module(QDF_MODULE_ID qid)
{
struct scheduler_mq_ctx *ctx;
struct scheduler_ctx *sched_ctx = scheduler_get_context();
uint8_t qidx;
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_INFO,
FL("Enter"));
if (!sched_ctx) {
QDF_ASSERT(0);
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
FL("sched_ctx is NULL"));
return QDF_STATUS_E_FAILURE;
}
ctx = &sched_ctx->queue_ctx;
qidx = ctx->scheduler_msg_qid_to_qidx[qid];
ctx->scheduler_msg_process_fn[qidx] = NULL;
ctx->scheduler_msg_qid_to_qidx[qidx] = SCHEDULER_NUMBER_OF_MSG_QUEUE;
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_INFO,
FL("Exit"));
return QDF_STATUS_SUCCESS;
}
void scheduler_resume(void)
{
struct scheduler_ctx *sched_ctx = scheduler_get_context();
if (sched_ctx)
qdf_event_set(&sched_ctx->resume_sch_event);
}
void scheduler_register_hdd_suspend_callback(hdd_suspend_callback callback)
{
struct scheduler_ctx *sched_ctx = scheduler_get_context();
if (sched_ctx)
sched_ctx->hdd_callback = callback;
}
void scheduler_wake_up_controller_thread(void)
{
struct scheduler_ctx *sched_ctx = scheduler_get_context();
if (sched_ctx)
qdf_wake_up_interruptible(&sched_ctx->sch_wait_queue);
}
void scheduler_set_event_mask(uint32_t event_mask)
{
struct scheduler_ctx *sched_ctx = scheduler_get_context();
if (sched_ctx)
qdf_set_bit(event_mask, &sched_ctx->sch_event_flag);
}
void scheduler_clear_event_mask(uint32_t event_mask)
{
struct scheduler_ctx *sched_ctx = scheduler_get_context();
if (sched_ctx)
qdf_clear_bit(event_mask, &sched_ctx->sch_event_flag);
}
QDF_STATUS scheduler_target_if_mq_handler(struct scheduler_msg *msg)
{
QDF_STATUS status;
struct scheduler_ctx *sched_ctx = scheduler_get_context();
QDF_STATUS (*target_if_msg_handler)(struct scheduler_msg *);
if (NULL == msg || NULL == sched_ctx) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER,
QDF_TRACE_LEVEL_ERROR, FL("msg %p sch %p"),
msg, sched_ctx);
return QDF_STATUS_E_FAILURE;
}
target_if_msg_handler = msg->callback;
/* Target_If is a special message queue in phase 3 convergence beacause
* its used by both legacy WMA and as well as new UMAC components. New
* UMAC components directly pass their message handlers as callback in
* message body.
* 1) All Legacy WMA messages do not contain message callback so invoke
* registered legacy WMA handler. Scheduler message posting APIs
* makes sure legacy WMA messages do not have callbacks.
* 2) For new messages which have valid callbacks invoke their callbacks
* directly.
*/
if (NULL == target_if_msg_handler)
status = sched_ctx->legacy_wma_handler(msg);
else
status = target_if_msg_handler(msg);
return status;
}
QDF_STATUS scheduler_os_if_mq_handler(struct scheduler_msg *msg)
{
QDF_STATUS (*os_if_msg_handler)(struct scheduler_msg *);
if (NULL == msg) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER,
QDF_TRACE_LEVEL_ERROR, FL("Msg is NULL"));
return QDF_STATUS_E_FAILURE;
}
os_if_msg_handler = msg->callback;
if (NULL == os_if_msg_handler) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER,
QDF_TRACE_LEVEL_ERROR, FL("Msg callback is NULL"));
QDF_ASSERT(0);
return QDF_STATUS_E_FAILURE;
}
os_if_msg_handler(msg);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS scheduler_timer_q_mq_handler(struct scheduler_msg *msg)
{
QDF_STATUS status;
struct scheduler_ctx *sched_ctx = scheduler_get_context();
qdf_mc_timer_callback_t timer_q_msg_handler;
if (NULL == msg || NULL == sched_ctx) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER,
QDF_TRACE_LEVEL_ERROR, FL("msg %p sch %p"),
msg, sched_ctx);
return QDF_STATUS_E_FAILURE;
}
timer_q_msg_handler = msg->callback;
/* Timer message handler */
if (SYS_MSG_COOKIE == msg->reserved &&
SYS_MSG_ID_MC_TIMER == msg->type) {
if (timer_q_msg_handler) {
status = QDF_STATUS_SUCCESS;
timer_q_msg_handler(msg->bodyptr);
} else {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER,
QDF_TRACE_LEVEL_ERROR, FL("Timer cb is null"));
status = QDF_STATUS_E_FAILURE;
}
return status;
} else {
/* Legacy sys message handler */
status = sched_ctx->legacy_sys_handler(msg);
return status;
}
}
QDF_STATUS scheduler_register_wma_legacy_handler(scheduler_msg_process_fn_t
wma_callback)
{
struct scheduler_ctx *sched_ctx = scheduler_get_context();
if (NULL == sched_ctx) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER,
QDF_TRACE_LEVEL_ERROR, FL("scheduler context is null"));
return QDF_STATUS_E_FAILURE;
}
sched_ctx->legacy_wma_handler = wma_callback;
return QDF_STATUS_SUCCESS;
}
QDF_STATUS scheduler_register_sys_legacy_handler(scheduler_msg_process_fn_t
sys_callback)
{
struct scheduler_ctx *sched_ctx = scheduler_get_context();
if (NULL == sched_ctx) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER,
QDF_TRACE_LEVEL_ERROR, FL("scheduler context is null"));
return QDF_STATUS_E_FAILURE;
}
sched_ctx->legacy_sys_handler = sys_callback;
return QDF_STATUS_SUCCESS;
}
void scheduler_mc_timer_callback(unsigned long data)
{
qdf_mc_timer_t *timer = (qdf_mc_timer_t *)data;
struct scheduler_msg msg;
QDF_STATUS status;
qdf_mc_timer_callback_t callback = NULL;
void *user_data = NULL;
QDF_TIMER_TYPE type = QDF_TIMER_TYPE_SW;
QDF_ASSERT(timer);
if (timer == NULL) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s Null pointer passed in!", __func__);
return;
}
qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
switch (timer->state) {
case QDF_TIMER_STATE_STARTING:
/* we are in this state because someone just started the timer,
* MC timer got started and expired, but the time content have
* not been updated this is a rare race condition!
*/
timer->state = QDF_TIMER_STATE_STOPPED;
status = QDF_STATUS_E_ALREADY;
break;
case QDF_TIMER_STATE_STOPPED:
status = QDF_STATUS_E_ALREADY;
break;
case QDF_TIMER_STATE_UNUSED:
status = QDF_STATUS_E_EXISTS;
break;
case QDF_TIMER_STATE_RUNNING:
/* need to go to stop state here because the call-back function
* may restart timer (to emulate periodic timer)
*/
timer->state = QDF_TIMER_STATE_STOPPED;
/* copy the relevant timer information to local variables;
* once we exits from this critical section, the timer content
* may be modified by other tasks
*/
callback = timer->callback;
user_data = timer->user_data;
type = timer->type;
status = QDF_STATUS_SUCCESS;
break;
default:
QDF_ASSERT(0);
status = QDF_STATUS_E_FAULT;
break;
}
qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
if (QDF_STATUS_SUCCESS != status) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"TIMER callback called in a wrong state=%d",
timer->state);
return;
}
qdf_try_allowing_sleep(type);
if (callback == NULL) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: No TIMER callback, Couldn't enqueue timer to any queue",
__func__);
QDF_ASSERT(0);
return;
}
/* serialize to scheduler controller thread */
msg.type = SYS_MSG_ID_MC_TIMER;
msg.reserved = SYS_MSG_COOKIE;
msg.callback = callback;
msg.bodyptr = user_data;
msg.bodyval = 0;
if (scheduler_post_msg(QDF_MODULE_ID_SYS, &msg) == QDF_STATUS_SUCCESS)
return;
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: Could not enqueue timer to timer queue", __func__);
}

View file

@ -0,0 +1,445 @@
/*
* Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#include <scheduler_core.h>
static struct scheduler_ctx *gp_sched_ctx;
QDF_STATUS scheduler_create_ctx(void)
{
if (gp_sched_ctx) {
QDF_ASSERT(0);
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
FL("there is a already gp_sched_ctx mem allocated"));
return QDF_STATUS_E_FAILURE;
}
gp_sched_ctx = qdf_mem_malloc(sizeof(struct scheduler_ctx));
if (!gp_sched_ctx) {
QDF_ASSERT(0);
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
FL("gp_sched_ctx can't alloc mememory"));
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}
QDF_STATUS scheduler_destroy_ctx(void)
{
if (gp_sched_ctx)
qdf_mem_free(gp_sched_ctx);
gp_sched_ctx = NULL;
return QDF_STATUS_SUCCESS;
}
struct scheduler_ctx *scheduler_get_context(void)
{
return gp_sched_ctx;
}
static QDF_STATUS scheduler_all_queues_init(
struct scheduler_ctx *sched_ctx)
{
QDF_STATUS status = QDF_STATUS_SUCCESS;
int i;
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR, FL("enter"));
if (!sched_ctx) {
QDF_ASSERT(0);
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: Null params being passed", __func__);
return QDF_STATUS_E_FAILURE;
}
status = scheduler_mq_init(&sched_ctx->queue_ctx.free_msg_q);
if (QDF_STATUS_SUCCESS != status)
return status;
QDF_TRACE(QDF_MODULE_ID_SCHEDULER,
QDF_TRACE_LEVEL_ERROR, FL("free msg queue init complete"));
/* Initialize all message queues */
for (i = 0; i < SCHEDULER_NUMBER_OF_MSG_QUEUE; i++) {
status = scheduler_mq_init(
&sched_ctx->queue_ctx.sch_msg_q[i]);
if (QDF_STATUS_SUCCESS != status)
return status;
}
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR, FL("exit"));
return status;
}
static QDF_STATUS scheduler_all_queues_deinit(
struct scheduler_ctx *sched_ctx)
{
QDF_STATUS status = QDF_STATUS_SUCCESS;
int i;
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR, FL("enter"));
if (!sched_ctx) {
QDF_ASSERT(0);
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: Null params being passed", __func__);
return QDF_STATUS_E_FAILURE;
}
scheduler_mq_deinit(&sched_ctx->queue_ctx.free_msg_q);
QDF_TRACE(QDF_MODULE_ID_SCHEDULER,
QDF_TRACE_LEVEL_ERROR, FL("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]);
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR, FL("exit"));
return status;
}
QDF_STATUS scheduler_mq_init(struct scheduler_mq_type *msg_q)
{
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR, FL("Enter"));
if (msg_q == NULL) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: NULL pointer passed", __func__);
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);
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR, FL("Exit"));
return QDF_STATUS_SUCCESS;
}
void scheduler_mq_deinit(struct scheduler_mq_type *msg_q)
{
if (msg_q == NULL) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: NULL pointer passed", __func__);
return;
}
}
void scheduler_mq_put(struct scheduler_mq_type *msg_q,
struct scheduler_msg_wrapper *msg_wrapper)
{
if (msg_q == NULL || msg_wrapper == NULL) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: NULL pointer passed", __func__);
return;
}
qdf_spin_lock_irqsave(&msg_q->mq_lock);
qdf_list_insert_back(&msg_q->mq_list, &msg_wrapper->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)
{
if ((msg_q == NULL) || (msg_wrapper == NULL)) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: NULL pointer passed", __func__);
return;
}
qdf_spin_lock_irqsave(&msg_q->mq_lock);
qdf_list_insert_front(&msg_q->mq_list, &msg_wrapper->msg_node);
qdf_spin_unlock_irqrestore(&msg_q->mq_lock);
}
struct scheduler_msg_wrapper *scheduler_mq_get(struct scheduler_mq_type *msg_q)
{
qdf_list_node_t *listptr;
struct scheduler_msg_wrapper *msg_wrapper = NULL;
if (msg_q == NULL) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: NULL pointer passed", __func__);
return NULL;
}
qdf_spin_lock_irqsave(&msg_q->mq_lock);
if (qdf_list_empty(&msg_q->mq_list)) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_WARN,
"%s: Scheduler Message Queue is empty", __func__);
} 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);
}
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 = false;
if (msg_q == NULL) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: NULL pointer passed", __func__);
return QDF_STATUS_E_FAILURE;
}
qdf_spin_lock_irqsave(&msg_q->mq_lock);
is_empty = qdf_list_empty(&msg_q->mq_list) ? true : false;
qdf_spin_unlock_irqrestore(&msg_q->mq_lock);
return is_empty;
}
QDF_STATUS scheduler_queues_deinit(struct scheduler_ctx *sched_ctx)
{
return scheduler_all_queues_deinit(sched_ctx);
}
QDF_STATUS scheduler_queues_init(struct scheduler_ctx *sched_ctx)
{
QDF_STATUS status = QDF_STATUS_E_FAILURE;
int i;
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR, FL("Enter"));
if (!sched_ctx) {
QDF_ASSERT(0);
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: Null params being passed", __func__);
return QDF_STATUS_E_FAILURE;
}
status = scheduler_all_queues_init(sched_ctx);
if (QDF_STATUS_SUCCESS != status) {
scheduler_all_queues_deinit(sched_ctx);
QDF_ASSERT(0);
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_FATAL,
FL("Failed to initialize the msg queues"));
return status;
}
QDF_TRACE(QDF_MODULE_ID_SCHEDULER,
QDF_TRACE_LEVEL_ERROR, FL("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]));
}
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR, FL("Exit"));
return status;
}
static void scheduler_core_return_msg(struct scheduler_ctx *sch_ctx,
struct scheduler_msg_wrapper *msg_wrapper)
{
if (!sch_ctx) {
QDF_ASSERT(0);
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: gp_cds_context != p_cds_context", __func__);
return;
}
QDF_ASSERT(NULL != msg_wrapper);
if (msg_wrapper == NULL) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
FL("msg_wrapper == NULL in function"));
return;
}
/*
* 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);
}
static void scheduler_thread_process_queues(struct scheduler_ctx *sch_ctx,
bool *shutdown)
{
int i;
QDF_STATUS vStatus = QDF_STATUS_E_FAILURE;
struct scheduler_msg_wrapper *pMsgWrapper = NULL;
if (!sch_ctx) {
QDF_ASSERT(0);
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
FL("sch_ctx null"));
return;
}
/* start with highest priority queue : timer queue at index 0 */
i = 0;
while (i < SCHEDULER_NUMBER_OF_MSG_QUEUE) {
/* Check if MC needs to shutdown */
if (qdf_test_bit(MC_SHUTDOWN_EVENT_MASK,
&sch_ctx->sch_event_flag)) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER,
QDF_TRACE_LEVEL_ERROR,
"%s: scheduler thread signaled to shutdown",
__func__);
*shutdown = true;
/* Check for any Suspend Indication */
if (qdf_test_and_clear_bit(MC_SUSPEND_EVENT_MASK,
&sch_ctx->sch_event_flag)) {
/* Unblock anyone waiting on suspend */
if (gp_sched_ctx->hdd_callback)
gp_sched_ctx->hdd_callback();
}
break;
}
if (scheduler_is_mq_empty(&sch_ctx->queue_ctx.sch_msg_q[i])) {
/* check next queue */
i++;
continue;
}
pMsgWrapper =
scheduler_mq_get(&sch_ctx->queue_ctx.sch_msg_q[i]);
if (pMsgWrapper == NULL) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER,
QDF_TRACE_LEVEL_ERROR,
"%s: pMsgWrapper is NULL", __func__);
QDF_ASSERT(0);
return;
}
if (sch_ctx->queue_ctx.scheduler_msg_process_fn[i]) {
vStatus = sch_ctx->queue_ctx.
scheduler_msg_process_fn[i](
pMsgWrapper->msg_buf);
if (QDF_IS_STATUS_ERROR(vStatus)) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER,
QDF_TRACE_LEVEL_ERROR,
FL("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, pMsgWrapper);
}
/* start again with highest priority queue at index 0 */
i = 0;
continue;
}
/* Check for any Suspend Indication */
if (qdf_test_and_clear_bit(MC_SUSPEND_EVENT_MASK,
&sch_ctx->sch_event_flag)) {
qdf_spin_lock(&sch_ctx->sch_thread_lock);
qdf_event_reset(&sch_ctx->resume_sch_event);
/* controller thread suspend completion callback */
if (gp_sched_ctx->hdd_callback)
gp_sched_ctx->hdd_callback();
qdf_spin_unlock(&sch_ctx->sch_thread_lock);
/* Wait for resume indication */
qdf_wait_single_event(&sch_ctx->resume_sch_event, 0);
}
return; /* Nothing to process wait on wait queue */
}
int scheduler_thread(void *arg)
{
struct scheduler_ctx *sch_ctx = (struct scheduler_ctx *)arg;
int retWaitStatus = 0;
bool shutdown = false;
if (arg == NULL) {
QDF_ASSERT(0);
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: Bad Args passed", __func__);
return 0;
}
qdf_set_user_nice(current, -2);
/* Ack back to the context from which the main controller thread
* has been created
*/
qdf_event_set(&sch_ctx->sch_start_event);
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: scheduler_thread %d (%s) starting up", __func__, current->pid,
current->comm);
while (!shutdown) {
/* This implements the execution model algorithm */
retWaitStatus = qdf_wait_queue_interruptible(
sch_ctx->sch_wait_queue,
qdf_test_bit(MC_POST_EVENT_MASK,
&sch_ctx->sch_event_flag) ||
qdf_test_bit(MC_SUSPEND_EVENT_MASK,
&sch_ctx->sch_event_flag));
if (retWaitStatus == -ERESTARTSYS) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: wait_event_interruptible returned -ERESTARTSYS",
__func__);
QDF_BUG(0);
}
qdf_clear_bit(MC_POST_EVENT_MASK, &sch_ctx->sch_event_flag);
scheduler_thread_process_queues(sch_ctx, &shutdown);
}
/* If we get here the MC thread must exit */
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: Scheduler thread exiting!!!!", __func__);
qdf_event_set(&sch_ctx->sch_shutdown);
qdf_exit_thread(QDF_STATUS_SUCCESS);
return 0;
}
void scheduler_cleanup_queues(struct scheduler_ctx *sch_ctx, int idx)
{
struct scheduler_msg_wrapper *msg_wrapper = NULL;
if (!sch_ctx) {
QDF_ASSERT(0);
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_ERROR,
"%s: Null params being passed", __func__);
return;
}
while ((msg_wrapper =
scheduler_mq_get(&sch_ctx->queue_ctx.sch_msg_q[idx]))) {
if (msg_wrapper->msg_buf != NULL) {
QDF_TRACE(QDF_MODULE_ID_SCHEDULER, QDF_TRACE_LEVEL_INFO,
"%s: Freeing MC WMA MSG message type %d",
__func__, msg_wrapper->msg_buf->type);
if (msg_wrapper->msg_buf->bodyptr)
qdf_mem_free(
(void *)msg_wrapper->msg_buf->bodyptr);
msg_wrapper->msg_buf->bodyptr = NULL;
msg_wrapper->msg_buf->bodyval = 0;
msg_wrapper->msg_buf->type = 0;
}
scheduler_core_return_msg(sch_ctx, msg_wrapper);
}
}