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