1 /* 2 * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <scheduler_api.h> 20 #include <scheduler_core.h> 21 #include <qdf_atomic.h> 22 #include <qdf_module.h> 23 #include <qdf_platform.h> 24 25 QDF_STATUS scheduler_disable(void) 26 { 27 struct scheduler_ctx *sched_ctx; 28 29 sched_debug("Disabling Scheduler"); 30 31 sched_ctx = scheduler_get_context(); 32 QDF_BUG(sched_ctx); 33 if (!sched_ctx) 34 return QDF_STATUS_E_INVAL; 35 36 if (!sched_ctx->sch_thread) { 37 sched_debug("Scheduler already disabled"); 38 return QDF_STATUS_SUCCESS; 39 } 40 41 /* send shutdown signal to scheduler thread */ 42 qdf_atomic_set_bit(MC_SHUTDOWN_EVENT_MASK, &sched_ctx->sch_event_flag); 43 qdf_atomic_set_bit(MC_POST_EVENT_MASK, &sched_ctx->sch_event_flag); 44 qdf_wake_up_interruptible(&sched_ctx->sch_wait_queue); 45 46 /* wait for scheduler thread to shutdown */ 47 qdf_wait_single_event(&sched_ctx->sch_shutdown, 0); 48 sched_ctx->sch_thread = NULL; 49 50 /* flush any unprocessed scheduler messages */ 51 scheduler_queues_flush(sched_ctx); 52 53 return QDF_STATUS_SUCCESS; 54 } 55 56 static inline void scheduler_watchdog_notify(struct scheduler_ctx *sched) 57 { 58 char symbol[QDF_SYMBOL_LEN]; 59 60 if (sched->watchdog_callback) 61 qdf_sprint_symbol(symbol, sched->watchdog_callback); 62 63 sched_fatal("Callback %s (type 0x%x) exceeded its allotted time of %ds", 64 sched->watchdog_callback ? symbol : "<null>", 65 sched->watchdog_msg_type, 66 sched->timeout / 1000); 67 } 68 69 static void scheduler_watchdog_timeout(void *arg) 70 { 71 struct scheduler_ctx *sched = arg; 72 73 if (qdf_is_recovering()) { 74 sched_debug("Recovery is in progress ignore timeout"); 75 return; 76 } 77 78 scheduler_watchdog_notify(sched); 79 if (sched->sch_thread) 80 qdf_print_thread_trace(sched->sch_thread); 81 82 /* avoid crashing during shutdown */ 83 if (qdf_atomic_test_bit(MC_SHUTDOWN_EVENT_MASK, &sched->sch_event_flag)) 84 return; 85 86 SCHED_DEBUG_PANIC("Going down for Scheduler Watchdog Bite!"); 87 } 88 89 QDF_STATUS scheduler_enable(void) 90 { 91 struct scheduler_ctx *sched_ctx; 92 93 sched_debug("Enabling Scheduler"); 94 95 sched_ctx = scheduler_get_context(); 96 QDF_BUG(sched_ctx); 97 if (!sched_ctx) 98 return QDF_STATUS_E_INVAL; 99 100 qdf_atomic_clear_bit(MC_SHUTDOWN_EVENT_MASK, 101 &sched_ctx->sch_event_flag); 102 qdf_atomic_clear_bit(MC_POST_EVENT_MASK, 103 &sched_ctx->sch_event_flag); 104 105 /* create the scheduler thread */ 106 sched_ctx->sch_thread = qdf_create_thread(scheduler_thread, sched_ctx, 107 "scheduler_thread"); 108 if (!sched_ctx->sch_thread) { 109 sched_fatal("Failed to create scheduler thread"); 110 return QDF_STATUS_E_RESOURCES; 111 } 112 113 sched_debug("Scheduler thread created"); 114 115 /* wait for the scheduler thread to startup */ 116 qdf_wake_up_process(sched_ctx->sch_thread); 117 qdf_wait_single_event(&sched_ctx->sch_start_event, 0); 118 119 sched_debug("Scheduler thread started"); 120 121 return QDF_STATUS_SUCCESS; 122 } 123 124 QDF_STATUS scheduler_init(void) 125 { 126 QDF_STATUS status; 127 struct scheduler_ctx *sched_ctx; 128 129 sched_debug("Initializing Scheduler"); 130 131 status = scheduler_create_ctx(); 132 if (QDF_IS_STATUS_ERROR(status)) { 133 sched_fatal("Failed to create context; status:%d", status); 134 return status; 135 } 136 137 sched_ctx = scheduler_get_context(); 138 QDF_BUG(sched_ctx); 139 if (!sched_ctx) { 140 status = QDF_STATUS_E_FAILURE; 141 goto ctx_destroy; 142 } 143 144 status = scheduler_queues_init(sched_ctx); 145 if (QDF_IS_STATUS_ERROR(status)) { 146 sched_fatal("Failed to init queues; status:%d", status); 147 goto ctx_destroy; 148 } 149 150 status = qdf_event_create(&sched_ctx->sch_start_event); 151 if (QDF_IS_STATUS_ERROR(status)) { 152 sched_fatal("Failed to create start event; status:%d", status); 153 goto queues_deinit; 154 } 155 156 status = qdf_event_create(&sched_ctx->sch_shutdown); 157 if (QDF_IS_STATUS_ERROR(status)) { 158 sched_fatal("Failed to create shutdown event; status:%d", 159 status); 160 goto start_event_destroy; 161 } 162 163 status = qdf_event_create(&sched_ctx->resume_sch_event); 164 if (QDF_IS_STATUS_ERROR(status)) { 165 sched_fatal("Failed to create resume event; status:%d", status); 166 goto shutdown_event_destroy; 167 } 168 169 qdf_spinlock_create(&sched_ctx->sch_thread_lock); 170 qdf_init_waitqueue_head(&sched_ctx->sch_wait_queue); 171 sched_ctx->sch_event_flag = 0; 172 sched_ctx->timeout = SCHEDULER_WATCHDOG_TIMEOUT; 173 qdf_timer_init(NULL, 174 &sched_ctx->watchdog_timer, 175 &scheduler_watchdog_timeout, 176 sched_ctx, 177 QDF_TIMER_TYPE_SW); 178 179 qdf_register_mc_timer_callback(scheduler_mc_timer_callback); 180 181 return QDF_STATUS_SUCCESS; 182 183 shutdown_event_destroy: 184 qdf_event_destroy(&sched_ctx->sch_shutdown); 185 186 start_event_destroy: 187 qdf_event_destroy(&sched_ctx->sch_start_event); 188 189 queues_deinit: 190 scheduler_queues_deinit(sched_ctx); 191 192 ctx_destroy: 193 scheduler_destroy_ctx(); 194 195 return status; 196 } 197 198 QDF_STATUS scheduler_deinit(void) 199 { 200 QDF_STATUS status; 201 struct scheduler_ctx *sched_ctx; 202 203 sched_debug("Deinitializing Scheduler"); 204 205 sched_ctx = scheduler_get_context(); 206 QDF_BUG(sched_ctx); 207 if (!sched_ctx) 208 return QDF_STATUS_E_INVAL; 209 210 qdf_timer_free(&sched_ctx->watchdog_timer); 211 qdf_spinlock_destroy(&sched_ctx->sch_thread_lock); 212 qdf_event_destroy(&sched_ctx->resume_sch_event); 213 qdf_event_destroy(&sched_ctx->sch_shutdown); 214 qdf_event_destroy(&sched_ctx->sch_start_event); 215 216 status = scheduler_queues_deinit(sched_ctx); 217 if (QDF_IS_STATUS_ERROR(status)) 218 sched_err("Failed to deinit queues; status:%d", status); 219 220 status = scheduler_destroy_ctx(); 221 if (QDF_IS_STATUS_ERROR(status)) 222 sched_err("Failed to destroy context; status:%d", status); 223 224 return QDF_STATUS_SUCCESS; 225 } 226 227 QDF_STATUS scheduler_post_msg_by_priority(uint32_t qid, 228 struct scheduler_msg *msg, 229 bool is_high_priority) 230 { 231 uint8_t qidx; 232 struct scheduler_mq_type *target_mq; 233 struct scheduler_msg *queue_msg; 234 struct scheduler_ctx *sched_ctx; 235 uint16_t src_id; 236 uint16_t dest_id; 237 uint16_t que_id; 238 239 QDF_BUG(msg); 240 if (!msg) 241 return QDF_STATUS_E_INVAL; 242 243 sched_ctx = scheduler_get_context(); 244 QDF_BUG(sched_ctx); 245 if (!sched_ctx) 246 return QDF_STATUS_E_INVAL; 247 248 if (!sched_ctx->sch_thread) { 249 sched_err("Cannot post message; scheduler thread is stopped"); 250 return QDF_STATUS_E_FAILURE; 251 } 252 253 if (msg->reserved != 0 && msg->reserved != SYS_MSG_COOKIE) { 254 QDF_DEBUG_PANIC("Scheduler messages must be initialized"); 255 return QDF_STATUS_E_FAILURE; 256 } 257 258 dest_id = scheduler_get_dest_id(qid); 259 src_id = scheduler_get_src_id(qid); 260 que_id = scheduler_get_que_id(qid); 261 262 if (que_id >= QDF_MODULE_ID_MAX || src_id >= QDF_MODULE_ID_MAX || 263 dest_id >= QDF_MODULE_ID_MAX) { 264 sched_err("Src_id/Dest_id invalid, cannot post message"); 265 return QDF_STATUS_E_FAILURE; 266 } 267 /* Target_If is a special message queue in phase 3 convergence beacause 268 * its used by both legacy WMA and as well as new UMAC components which 269 * directly populate callback handlers in message body. 270 * 1) WMA legacy messages should not have callback 271 * 2) New target_if message needs to have valid callback 272 * Clear callback handler for legacy WMA messages such that in case 273 * if someone is sending legacy WMA message from stack which has 274 * uninitialized callback then its handled properly. Also change 275 * legacy WMA message queue id to target_if queue such that its always 276 * handled in right order. 277 */ 278 if (QDF_MODULE_ID_WMA == que_id) { 279 msg->callback = NULL; 280 /* change legacy WMA message id to new target_if mq id */ 281 que_id = QDF_MODULE_ID_TARGET_IF; 282 } 283 qdf_mtrace(src_id, dest_id, msg->type, 0xFF, 0); 284 285 qidx = sched_ctx->queue_ctx.scheduler_msg_qid_to_qidx[que_id]; 286 if (qidx >= SCHEDULER_NUMBER_OF_MSG_QUEUE) { 287 sched_err("Scheduler is deinitialized ignore msg"); 288 return QDF_STATUS_E_FAILURE; 289 } 290 291 if (!sched_ctx->queue_ctx.scheduler_msg_process_fn[qidx]) { 292 QDF_DEBUG_PANIC("callback not registered for qid[%d]", que_id); 293 return QDF_STATUS_E_FAILURE; 294 } 295 296 target_mq = &(sched_ctx->queue_ctx.sch_msg_q[qidx]); 297 298 queue_msg = scheduler_core_msg_dup(msg); 299 if (!queue_msg) 300 return QDF_STATUS_E_NOMEM; 301 302 if (is_high_priority) 303 scheduler_mq_put_front(target_mq, queue_msg); 304 else 305 scheduler_mq_put(target_mq, queue_msg); 306 307 qdf_atomic_set_bit(MC_POST_EVENT_MASK, &sched_ctx->sch_event_flag); 308 qdf_wake_up_interruptible(&sched_ctx->sch_wait_queue); 309 310 return QDF_STATUS_SUCCESS; 311 } 312 313 QDF_STATUS scheduler_register_module(QDF_MODULE_ID qid, 314 scheduler_msg_process_fn_t callback) 315 { 316 struct scheduler_mq_ctx *ctx; 317 struct scheduler_ctx *sched_ctx = scheduler_get_context(); 318 319 sched_enter(); 320 321 QDF_BUG(sched_ctx); 322 if (!sched_ctx) 323 return QDF_STATUS_E_FAILURE; 324 325 if (sched_ctx->sch_last_qidx >= SCHEDULER_NUMBER_OF_MSG_QUEUE) { 326 sched_err("Already registered max %d no of message queues", 327 SCHEDULER_NUMBER_OF_MSG_QUEUE); 328 return QDF_STATUS_E_FAILURE; 329 } 330 331 ctx = &sched_ctx->queue_ctx; 332 ctx->scheduler_msg_qid_to_qidx[qid] = sched_ctx->sch_last_qidx; 333 ctx->sch_msg_q[sched_ctx->sch_last_qidx].qid = qid; 334 ctx->scheduler_msg_process_fn[sched_ctx->sch_last_qidx] = callback; 335 sched_ctx->sch_last_qidx++; 336 337 sched_exit(); 338 339 return QDF_STATUS_SUCCESS; 340 } 341 342 QDF_STATUS scheduler_deregister_module(QDF_MODULE_ID qid) 343 { 344 struct scheduler_mq_ctx *ctx; 345 struct scheduler_ctx *sched_ctx = scheduler_get_context(); 346 uint8_t qidx; 347 348 sched_enter(); 349 350 QDF_BUG(sched_ctx); 351 if (!sched_ctx) 352 return QDF_STATUS_E_FAILURE; 353 354 ctx = &sched_ctx->queue_ctx; 355 qidx = ctx->scheduler_msg_qid_to_qidx[qid]; 356 ctx->scheduler_msg_process_fn[qidx] = NULL; 357 sched_ctx->sch_last_qidx--; 358 ctx->scheduler_msg_qid_to_qidx[qidx] = SCHEDULER_NUMBER_OF_MSG_QUEUE; 359 360 sched_exit(); 361 362 return QDF_STATUS_SUCCESS; 363 } 364 365 void scheduler_resume(void) 366 { 367 struct scheduler_ctx *sched_ctx = scheduler_get_context(); 368 369 if (sched_ctx) 370 qdf_event_set(&sched_ctx->resume_sch_event); 371 } 372 373 void scheduler_register_hdd_suspend_callback(hdd_suspend_callback callback) 374 { 375 struct scheduler_ctx *sched_ctx = scheduler_get_context(); 376 377 if (sched_ctx) 378 sched_ctx->hdd_callback = callback; 379 } 380 void scheduler_wake_up_controller_thread(void) 381 { 382 struct scheduler_ctx *sched_ctx = scheduler_get_context(); 383 384 if (sched_ctx) 385 qdf_wake_up_interruptible(&sched_ctx->sch_wait_queue); 386 } 387 void scheduler_set_event_mask(uint32_t event_mask) 388 { 389 struct scheduler_ctx *sched_ctx = scheduler_get_context(); 390 391 if (sched_ctx) 392 qdf_atomic_set_bit(event_mask, &sched_ctx->sch_event_flag); 393 } 394 395 void scheduler_clear_event_mask(uint32_t event_mask) 396 { 397 struct scheduler_ctx *sched_ctx = scheduler_get_context(); 398 399 if (sched_ctx) 400 qdf_atomic_clear_bit(event_mask, &sched_ctx->sch_event_flag); 401 } 402 403 QDF_STATUS scheduler_target_if_mq_handler(struct scheduler_msg *msg) 404 { 405 QDF_STATUS status; 406 struct scheduler_ctx *sched_ctx = scheduler_get_context(); 407 QDF_STATUS (*target_if_msg_handler)(struct scheduler_msg *); 408 409 QDF_BUG(msg); 410 if (!msg) 411 return QDF_STATUS_E_FAILURE; 412 413 QDF_BUG(sched_ctx); 414 if (!sched_ctx) 415 return QDF_STATUS_E_FAILURE; 416 417 target_if_msg_handler = msg->callback; 418 419 /* Target_If is a special message queue in phase 3 convergence beacause 420 * its used by both legacy WMA and as well as new UMAC components. New 421 * UMAC components directly pass their message handlers as callback in 422 * message body. 423 * 1) All Legacy WMA messages do not contain message callback so invoke 424 * registered legacy WMA handler. Scheduler message posting APIs 425 * makes sure legacy WMA messages do not have callbacks. 426 * 2) For new messages which have valid callbacks invoke their callbacks 427 * directly. 428 */ 429 if (!target_if_msg_handler) 430 status = sched_ctx->legacy_wma_handler(msg); 431 else 432 status = target_if_msg_handler(msg); 433 434 return status; 435 } 436 437 QDF_STATUS scheduler_os_if_mq_handler(struct scheduler_msg *msg) 438 { 439 QDF_STATUS (*os_if_msg_handler)(struct scheduler_msg *); 440 441 QDF_BUG(msg); 442 if (!msg) 443 return QDF_STATUS_E_FAILURE; 444 445 os_if_msg_handler = msg->callback; 446 447 QDF_BUG(os_if_msg_handler); 448 if (!os_if_msg_handler) 449 return QDF_STATUS_E_FAILURE; 450 451 os_if_msg_handler(msg); 452 453 return QDF_STATUS_SUCCESS; 454 } 455 456 QDF_STATUS scheduler_timer_q_mq_handler(struct scheduler_msg *msg) 457 { 458 struct scheduler_ctx *sched_ctx = scheduler_get_context(); 459 qdf_mc_timer_callback_t timer_callback; 460 461 QDF_BUG(msg); 462 if (!msg) 463 return QDF_STATUS_E_FAILURE; 464 465 QDF_BUG(sched_ctx); 466 if (!sched_ctx) 467 return QDF_STATUS_E_FAILURE; 468 469 /* legacy sys message handler? */ 470 if (msg->reserved != SYS_MSG_COOKIE || msg->type != SYS_MSG_ID_MC_TIMER) 471 return sched_ctx->legacy_sys_handler(msg); 472 473 /* scheduler_msg_process_fn_t and qdf_mc_timer_callback_t have 474 * different parameters and return type 475 */ 476 timer_callback = (qdf_mc_timer_callback_t)msg->callback; 477 QDF_BUG(timer_callback); 478 if (!timer_callback) 479 return QDF_STATUS_E_FAILURE; 480 481 timer_callback(msg->bodyptr); 482 483 return QDF_STATUS_SUCCESS; 484 } 485 486 QDF_STATUS scheduler_mlme_mq_handler(struct scheduler_msg *msg) 487 { 488 scheduler_msg_process_fn_t mlme_msg_handler; 489 490 QDF_BUG(msg); 491 if (!msg) 492 return QDF_STATUS_E_FAILURE; 493 494 mlme_msg_handler = msg->callback; 495 496 QDF_BUG(mlme_msg_handler); 497 if (!mlme_msg_handler) 498 return QDF_STATUS_E_FAILURE; 499 500 mlme_msg_handler(msg); 501 502 return QDF_STATUS_SUCCESS; 503 } 504 505 QDF_STATUS scheduler_scan_mq_handler(struct scheduler_msg *msg) 506 { 507 QDF_STATUS (*scan_q_msg_handler)(struct scheduler_msg *); 508 509 QDF_BUG(msg); 510 if (!msg) 511 return QDF_STATUS_E_FAILURE; 512 513 scan_q_msg_handler = msg->callback; 514 515 QDF_BUG(scan_q_msg_handler); 516 if (!scan_q_msg_handler) 517 return QDF_STATUS_E_FAILURE; 518 519 scan_q_msg_handler(msg); 520 521 return QDF_STATUS_SUCCESS; 522 } 523 524 void scheduler_set_watchdog_timeout(uint32_t timeout) 525 { 526 struct scheduler_ctx *sched_ctx = scheduler_get_context(); 527 528 QDF_BUG(sched_ctx); 529 if (!sched_ctx) 530 return; 531 532 sched_ctx->timeout = timeout; 533 } 534 535 QDF_STATUS scheduler_register_wma_legacy_handler(scheduler_msg_process_fn_t 536 wma_callback) 537 { 538 struct scheduler_ctx *sched_ctx = scheduler_get_context(); 539 540 QDF_BUG(sched_ctx); 541 if (!sched_ctx) 542 return QDF_STATUS_E_FAILURE; 543 544 sched_ctx->legacy_wma_handler = wma_callback; 545 546 return QDF_STATUS_SUCCESS; 547 } 548 549 QDF_STATUS scheduler_register_sys_legacy_handler(scheduler_msg_process_fn_t 550 sys_callback) 551 { 552 struct scheduler_ctx *sched_ctx = scheduler_get_context(); 553 554 QDF_BUG(sched_ctx); 555 if (!sched_ctx) 556 return QDF_STATUS_E_FAILURE; 557 558 sched_ctx->legacy_sys_handler = sys_callback; 559 560 return QDF_STATUS_SUCCESS; 561 } 562 563 QDF_STATUS scheduler_deregister_wma_legacy_handler(void) 564 { 565 struct scheduler_ctx *sched_ctx = scheduler_get_context(); 566 567 QDF_BUG(sched_ctx); 568 if (!sched_ctx) 569 return QDF_STATUS_E_FAILURE; 570 571 sched_ctx->legacy_wma_handler = NULL; 572 573 return QDF_STATUS_SUCCESS; 574 } 575 576 QDF_STATUS scheduler_deregister_sys_legacy_handler(void) 577 { 578 struct scheduler_ctx *sched_ctx = scheduler_get_context(); 579 580 QDF_BUG(sched_ctx); 581 if (!sched_ctx) 582 return QDF_STATUS_E_FAILURE; 583 584 sched_ctx->legacy_sys_handler = NULL; 585 586 return QDF_STATUS_SUCCESS; 587 } 588 589 static QDF_STATUS scheduler_msg_flush_noop(struct scheduler_msg *msg) 590 { 591 return QDF_STATUS_SUCCESS; 592 } 593 594 void scheduler_mc_timer_callback(qdf_mc_timer_t *timer) 595 { 596 struct scheduler_msg msg = {0}; 597 QDF_STATUS status; 598 599 qdf_mc_timer_callback_t callback = NULL; 600 void *user_data = NULL; 601 QDF_TIMER_TYPE type = QDF_TIMER_TYPE_SW; 602 603 QDF_BUG(timer); 604 if (!timer) 605 return; 606 607 qdf_spin_lock_irqsave(&timer->platform_info.spinlock); 608 609 switch (timer->state) { 610 case QDF_TIMER_STATE_STARTING: 611 /* we are in this state because someone just started the timer, 612 * MC timer got started and expired, but the time content have 613 * not been updated this is a rare race condition! 614 */ 615 timer->state = QDF_TIMER_STATE_STOPPED; 616 status = QDF_STATUS_E_ALREADY; 617 break; 618 619 case QDF_TIMER_STATE_STOPPED: 620 status = QDF_STATUS_E_ALREADY; 621 break; 622 623 case QDF_TIMER_STATE_UNUSED: 624 status = QDF_STATUS_E_EXISTS; 625 break; 626 627 case QDF_TIMER_STATE_RUNNING: 628 /* need to go to stop state here because the call-back function 629 * may restart timer (to emulate periodic timer) 630 */ 631 timer->state = QDF_TIMER_STATE_STOPPED; 632 /* copy the relevant timer information to local variables; 633 * once we exits from this critical section, the timer content 634 * may be modified by other tasks 635 */ 636 callback = timer->callback; 637 user_data = timer->user_data; 638 type = timer->type; 639 status = QDF_STATUS_SUCCESS; 640 break; 641 642 default: 643 QDF_ASSERT(0); 644 status = QDF_STATUS_E_FAULT; 645 break; 646 } 647 648 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); 649 650 if (QDF_IS_STATUS_ERROR(status)) { 651 sched_debug("MC timer fired but is not running; skip callback"); 652 return; 653 } 654 655 qdf_try_allowing_sleep(type); 656 657 QDF_BUG(callback); 658 if (!callback) 659 return; 660 661 /* serialize to scheduler controller thread */ 662 msg.type = SYS_MSG_ID_MC_TIMER; 663 msg.reserved = SYS_MSG_COOKIE; 664 msg.callback = (scheduler_msg_process_fn_t)callback; 665 msg.bodyptr = user_data; 666 msg.bodyval = 0; 667 668 /* bodyptr points to user data, do not free it during msg flush */ 669 msg.flush_callback = scheduler_msg_flush_noop; 670 671 status = scheduler_post_message(QDF_MODULE_ID_SCHEDULER, 672 QDF_MODULE_ID_SCHEDULER, 673 QDF_MODULE_ID_SYS, &msg); 674 if (QDF_IS_STATUS_ERROR(status)) 675 sched_err("Could not enqueue timer to timer queue"); 676 } 677 678 QDF_STATUS scheduler_get_queue_size(QDF_MODULE_ID qid, uint32_t *size) 679 { 680 uint8_t qidx; 681 struct scheduler_mq_type *target_mq; 682 struct scheduler_ctx *sched_ctx; 683 684 sched_ctx = scheduler_get_context(); 685 if (!sched_ctx) 686 return QDF_STATUS_E_INVAL; 687 688 /* WMA also uses the target_if queue, so replace the QID */ 689 if (QDF_MODULE_ID_WMA == qid) 690 qid = QDF_MODULE_ID_TARGET_IF; 691 692 qidx = sched_ctx->queue_ctx.scheduler_msg_qid_to_qidx[qid]; 693 if (qidx >= SCHEDULER_NUMBER_OF_MSG_QUEUE) { 694 sched_err("Scheduler is deinitialized"); 695 return QDF_STATUS_E_FAILURE; 696 } 697 698 target_mq = &(sched_ctx->queue_ctx.sch_msg_q[qidx]); 699 700 *size = qdf_list_size(&target_mq->mq_list); 701 702 return QDF_STATUS_SUCCESS; 703 } 704 705 QDF_STATUS scheduler_post_message_debug(QDF_MODULE_ID src_id, 706 QDF_MODULE_ID dest_id, 707 QDF_MODULE_ID que_id, 708 struct scheduler_msg *msg, 709 int line, 710 const char *func) 711 { 712 QDF_STATUS status; 713 714 status = scheduler_post_msg(scheduler_get_qid(src_id, dest_id, que_id), 715 msg); 716 717 if (QDF_IS_STATUS_ERROR(status)) 718 sched_err("couldn't post from %d to %d - called from %d, %s", 719 src_id, dest_id, line, func); 720 721 return status; 722 } 723 724 qdf_export_symbol(scheduler_post_message_debug); 725