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