1 /* 2 * Copyright (c) 2017-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 * DOC: wlan_serialization_internal.c 20 * This file defines the functions which are called 21 * from serialization public API's and are internal 22 * to serialization. 23 */ 24 25 #include <wlan_objmgr_vdev_obj.h> 26 #include <wlan_objmgr_pdev_obj.h> 27 #include <wlan_objmgr_psoc_obj.h> 28 #include <qdf_list.h> 29 #include <qdf_status.h> 30 #include <wlan_utility.h> 31 #include "wlan_serialization_api.h" 32 #include "wlan_serialization_main_i.h" 33 #include "wlan_serialization_utils_i.h" 34 #include "wlan_serialization_non_scan_i.h" 35 #include "wlan_serialization_scan_i.h" 36 #include "wlan_serialization_internal_i.h" 37 38 bool wlan_serialization_is_cmd_present_queue( 39 struct wlan_serialization_command *cmd, 40 uint8_t is_active_queue) 41 { 42 qdf_list_t *queue; 43 bool status = false; 44 enum wlan_serialization_node node_type; 45 struct wlan_ser_pdev_obj *ser_pdev_obj; 46 struct wlan_ser_vdev_obj *ser_vdev_obj; 47 enum wlan_serialization_cmd_type cmd_type; 48 49 if (!cmd) { 50 ser_err("invalid cmd"); 51 goto error; 52 } 53 54 cmd_type = cmd->cmd_type; 55 56 ser_pdev_obj = wlan_serialization_get_pdev_obj( 57 wlan_serialization_get_pdev_from_cmd(cmd)); 58 59 if (!ser_pdev_obj) { 60 ser_err("invalid ser vdev obj"); 61 goto error; 62 } 63 64 ser_vdev_obj = wlan_serialization_get_vdev_obj( 65 wlan_serialization_get_vdev_from_cmd(cmd)); 66 if (!ser_vdev_obj) { 67 ser_err("invalid ser pdev obj"); 68 goto error; 69 } 70 71 if (cmd_type < WLAN_SER_CMD_NONSCAN) { 72 queue = wlan_serialization_get_list_from_pdev_queue( 73 ser_pdev_obj, cmd_type, is_active_queue); 74 node_type = WLAN_SER_PDEV_NODE; 75 } else { 76 queue = wlan_serialization_get_list_from_vdev_queue( 77 ser_vdev_obj, cmd_type, is_active_queue); 78 node_type = WLAN_SER_VDEV_NODE; 79 } 80 81 status = wlan_serialization_is_cmd_present_in_given_queue(queue, cmd, 82 node_type); 83 84 error: 85 return status; 86 } 87 88 enum wlan_serialization_status 89 wlan_serialization_enqueue_cmd(struct wlan_serialization_command *cmd, 90 enum ser_queue_reason ser_reason) 91 { 92 enum wlan_serialization_status status = WLAN_SER_CMD_DENIED_UNSPECIFIED; 93 struct wlan_serialization_command_list *cmd_list; 94 qdf_list_node_t *nnode; 95 struct wlan_objmgr_pdev *pdev; 96 struct wlan_ser_pdev_obj *ser_pdev_obj; 97 struct wlan_serialization_pdev_queue *pdev_queue; 98 struct wlan_ser_vdev_obj *ser_vdev_obj; 99 struct wlan_serialization_vdev_queue *vdev_queue; 100 bool active_queue; 101 102 /* Enqueue process 103 * 1) peek through command structure and see what is the command type 104 * 2) two main types of commands to process 105 * a) SCAN 106 * b) NON-SCAN 107 * 3) for each command there are separate command queues per pdev 108 * 4) pull pdev from vdev structure and get the command queue associated 109 * with that pdev and try to enqueue on those queue 110 * 5) Thumb rule: 111 * a) There could be only 1 active non-scan command at a 112 * time including all total non-scan commands of all pdevs. 113 * 114 * example: pdev1 has 1 non-scan active command and 115 * pdev2 got 1 non-scan command then that command should go to 116 * pdev2's pending queue 117 * 118 * b) There could be only N number of scan commands at a time 119 * including all total scan commands of all pdevs 120 * 121 * example: Let's say N=8, 122 * pdev1's vdev1 has 5 scan command, pdev2's vdev1 has 3 123 * scan commands, if we get scan request on vdev2 then it will go 124 * to pending queue of vdev2 as we reached max allowed scan active 125 * command. 126 */ 127 128 if (!cmd) { 129 ser_err("NULL command"); 130 goto error; 131 } 132 133 if (!cmd->cmd_cb) { 134 ser_err("no cmd_cb for cmd type:%d, id: %d", 135 cmd->cmd_type, 136 cmd->cmd_id); 137 goto error; 138 } 139 140 pdev = wlan_serialization_get_pdev_from_cmd(cmd); 141 if (!pdev) { 142 ser_err("pdev is invalid"); 143 goto error; 144 } 145 146 ser_pdev_obj = 147 wlan_objmgr_pdev_get_comp_private_obj( 148 pdev, 149 WLAN_UMAC_COMP_SERIALIZATION); 150 if (!ser_pdev_obj) { 151 ser_err("Invalid ser_pdev_obj"); 152 goto error; 153 } 154 155 pdev_queue = wlan_serialization_get_pdev_queue_obj(ser_pdev_obj, 156 cmd->cmd_type); 157 if (!pdev_queue) { 158 ser_err("pdev_queue is invalid"); 159 goto error; 160 } 161 162 wlan_serialization_acquire_lock(&pdev_queue->pdev_queue_lock); 163 164 /* Before queuing any non scan command, 165 * as part of wlan_serialization_request, 166 * we check if the vdev queues are disabled. 167 * 168 * The serialization command structure has an 169 * attribute, where after a given command is queued, 170 * we can block the vdev queues. 171 * 172 * For example, after VDEV_DOWN command is queued as 173 * part of a vdev deletion, no other commands should be queued 174 * until the deletion is complete, so with VDEV_DOWN(in case of 175 * vdev deletion) with pass the attribute to disable vdev queues 176 */ 177 if (cmd->cmd_type > WLAN_SER_CMD_SCAN && 178 ser_reason == SER_REQUEST) { 179 ser_vdev_obj = 180 wlan_serialization_get_vdev_obj( 181 wlan_serialization_get_vdev_from_cmd(cmd)); 182 183 if (!ser_vdev_obj) { 184 wlan_serialization_release_lock( 185 &pdev_queue->pdev_queue_lock); 186 goto error; 187 } 188 189 vdev_queue = 190 wlan_serialization_get_vdev_queue_obj( 191 ser_vdev_obj, 192 cmd->cmd_type); 193 194 if (!vdev_queue) { 195 wlan_serialization_release_lock( 196 &pdev_queue->pdev_queue_lock); 197 goto error; 198 } 199 200 if (vdev_queue->queue_disable) { 201 wlan_serialization_release_lock( 202 &pdev_queue->pdev_queue_lock); 203 ser_err_rl("VDEV queue is disabled, reject cmd id %d type %d", 204 cmd->cmd_id, cmd->cmd_type); 205 status = WLAN_SER_CMD_QUEUE_DISABLED; 206 goto error; 207 } 208 } 209 210 active_queue = wlan_serialization_is_active_cmd_allowed(cmd); 211 212 if (wlan_serialization_is_cmd_present_queue(cmd, active_queue)) { 213 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 214 ser_err("duplicate command, reject cmd id %d type %d", 215 cmd->cmd_id, cmd->cmd_type); 216 goto error; 217 } 218 219 if (wlan_serialization_remove_front( 220 &pdev_queue->cmd_pool_list, 221 &nnode) != QDF_STATUS_SUCCESS) { 222 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 223 ser_err("Failed to get cmd buffer from global pool cmd id %d type %d", 224 cmd->cmd_id, cmd->cmd_type); 225 status = WLAN_SER_CMD_DENIED_LIST_FULL; 226 goto error; 227 } 228 229 ser_debug("Type %d id %d high_priority %d blocking %d timeout %d allowed %d", 230 cmd->cmd_type, cmd->cmd_id, cmd->is_high_priority, 231 cmd->is_blocking, cmd->cmd_timeout_duration, active_queue); 232 233 cmd_list = 234 qdf_container_of(nnode, 235 struct wlan_serialization_command_list, 236 pdev_node); 237 238 qdf_mem_copy(&cmd_list->cmd, cmd, 239 sizeof(struct wlan_serialization_command)); 240 241 if (cmd->cmd_type < WLAN_SER_CMD_NONSCAN) { 242 status = wlan_ser_add_scan_cmd(ser_pdev_obj, 243 cmd_list, 244 active_queue); 245 } else { 246 status = wlan_ser_add_non_scan_cmd(ser_pdev_obj, 247 cmd_list, 248 active_queue); 249 } 250 251 if (status != WLAN_SER_CMD_PENDING && status != WLAN_SER_CMD_ACTIVE) { 252 qdf_mem_zero(&cmd_list->cmd, 253 sizeof(struct wlan_serialization_command)); 254 cmd_list->cmd_in_use = 0; 255 wlan_serialization_insert_back( 256 &pdev_queue->cmd_pool_list, 257 &cmd_list->pdev_node); 258 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 259 ser_err("Failed to add cmd id %d type %d to active/pending queue", 260 cmd->cmd_id, cmd->cmd_type); 261 goto error; 262 } 263 264 if (WLAN_SER_CMD_ACTIVE == status) { 265 qdf_atomic_set_bit(CMD_MARKED_FOR_ACTIVATION, 266 &cmd_list->cmd_in_use); 267 } 268 269 wlan_ser_update_cmd_history(pdev_queue, &cmd_list->cmd, 270 ser_reason, true, active_queue); 271 272 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 273 274 if (WLAN_SER_CMD_ACTIVE == status) 275 wlan_serialization_activate_cmd(cmd_list, 276 ser_pdev_obj, ser_reason); 277 278 error: 279 280 return status; 281 } 282 283 QDF_STATUS wlan_serialization_activate_cmd( 284 struct wlan_serialization_command_list *cmd_list, 285 struct wlan_ser_pdev_obj *ser_pdev_obj, 286 enum ser_queue_reason ser_reason) 287 { 288 QDF_STATUS status = QDF_STATUS_E_FAILURE; 289 struct wlan_objmgr_psoc *psoc = NULL; 290 struct wlan_serialization_pdev_queue *pdev_queue; 291 292 pdev_queue = wlan_serialization_get_pdev_queue_obj( 293 ser_pdev_obj, cmd_list->cmd.cmd_type); 294 295 psoc = wlan_vdev_get_psoc(cmd_list->cmd.vdev); 296 if (!psoc) { 297 ser_err("invalid psoc"); 298 goto error; 299 } 300 301 /* 302 * command is already pushed to active queue above 303 * now start the timer and notify requestor 304 */ 305 306 status = wlan_serialization_find_and_start_timer(psoc, &cmd_list->cmd, 307 ser_reason); 308 if (QDF_IS_STATUS_ERROR(status)) { 309 ser_err("Failed to start timer cmd type[%d] id[%d] vdev[%d]", 310 cmd_list->cmd.cmd_type, 311 cmd_list->cmd.cmd_id, 312 wlan_vdev_get_id(cmd_list->cmd.vdev)); 313 goto timer_failed; 314 } 315 316 /* 317 * Remember that serialization module may send 318 * this callback in same context through which it 319 * received the serialization request. Due to which 320 * it is caller's responsibility to ensure acquiring 321 * and releasing its own lock appropriately. 322 */ 323 324 ser_debug("Activate type %d id %d", cmd_list->cmd.cmd_type, 325 cmd_list->cmd.cmd_id); 326 327 cmd_list->cmd.activation_reason = ser_reason; 328 329 status = cmd_list->cmd.cmd_cb(&cmd_list->cmd, 330 WLAN_SER_CB_ACTIVATE_CMD); 331 timer_failed: 332 wlan_serialization_acquire_lock(&pdev_queue->pdev_queue_lock); 333 334 qdf_atomic_clear_bit(CMD_MARKED_FOR_ACTIVATION, 335 &cmd_list->cmd_in_use); 336 qdf_atomic_set_bit(CMD_IS_ACTIVE, 337 &cmd_list->cmd_in_use); 338 339 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 340 341 if (QDF_IS_STATUS_ERROR(status)) { 342 wlan_serialization_dequeue_cmd(&cmd_list->cmd, 343 SER_ACTIVATION_FAILED, 344 true); 345 return status; 346 } 347 348 /* 349 * Cmd was marked for activation and delete or cancel 350 * is received before activation completed, then the command 351 * should be immediately removed after activation 352 */ 353 if (qdf_atomic_test_bit(CMD_ACTIVE_MARKED_FOR_REMOVAL, 354 &cmd_list->cmd_in_use)) { 355 wlan_serialization_dequeue_cmd(&cmd_list->cmd, 356 SER_REMOVE, 357 true); 358 return status; 359 } 360 361 if (qdf_atomic_test_bit(CMD_ACTIVE_MARKED_FOR_CANCEL, 362 &cmd_list->cmd_in_use)) 363 wlan_serialization_cmd_cancel_handler( 364 ser_pdev_obj, &cmd_list->cmd, 365 NULL, NULL, cmd_list->cmd.cmd_type, 366 WLAN_SERIALIZATION_ACTIVE_QUEUE, 367 WLAN_SER_CMD_ATTR_NONE); 368 error: 369 return status; 370 } 371 372 bool 373 wlan_serialization_is_active_cmd_allowed(struct wlan_serialization_command *cmd) 374 { 375 struct wlan_objmgr_pdev *pdev; 376 bool active_cmd_allowed = 0; 377 378 pdev = wlan_serialization_get_pdev_from_cmd(cmd); 379 if (!pdev) { 380 ser_err("NULL pdev"); 381 goto error; 382 } 383 384 if (cmd->cmd_type < WLAN_SER_CMD_NONSCAN) 385 active_cmd_allowed = 386 (wlan_serialization_is_active_scan_cmd_allowed(cmd) && 387 wlan_serialization_is_scan_pending_queue_empty(cmd)); 388 else 389 active_cmd_allowed = 390 (wlan_serialization_is_active_non_scan_cmd_allowed(cmd) && 391 wlan_serialization_is_non_scan_pending_queue_empty(cmd)); 392 393 error: 394 return active_cmd_allowed; 395 } 396 397 enum wlan_serialization_status 398 wlan_serialization_move_pending_to_active( 399 enum wlan_serialization_cmd_type cmd_type, 400 struct wlan_ser_pdev_obj *ser_pdev_obj, 401 struct wlan_objmgr_vdev *vdev, 402 bool blocking_cmd_removed) 403 { 404 enum wlan_serialization_status status; 405 406 if (cmd_type < WLAN_SER_CMD_NONSCAN) { 407 status = 408 wlan_ser_move_scan_pending_to_active( 409 ser_pdev_obj); 410 } else { 411 status = 412 wlan_ser_move_non_scan_pending_to_active( 413 ser_pdev_obj, 414 vdev, 415 blocking_cmd_removed); 416 } 417 418 return status; 419 } 420 421 enum wlan_serialization_cmd_status 422 wlan_serialization_dequeue_cmd(struct wlan_serialization_command *cmd, 423 enum ser_queue_reason ser_reason, 424 uint8_t active_cmd) 425 { 426 enum wlan_serialization_cmd_status status = 427 WLAN_SER_CMD_NOT_FOUND; 428 enum wlan_serialization_status ser_status = 429 WLAN_SER_CMD_DENIED_UNSPECIFIED; 430 431 QDF_STATUS qdf_status; 432 struct wlan_objmgr_pdev *pdev; 433 struct wlan_objmgr_psoc *psoc; 434 struct wlan_ser_pdev_obj *ser_pdev_obj; 435 struct wlan_serialization_command cmd_bkup; 436 struct wlan_serialization_command_list *cmd_list; 437 struct wlan_serialization_pdev_queue *pdev_queue; 438 bool blocking_cmd_removed = 0; 439 440 if (!cmd) { 441 ser_err("NULL command"); 442 goto error; 443 } 444 445 pdev = wlan_serialization_get_pdev_from_cmd(cmd); 446 if (!pdev) { 447 ser_err("invalid pdev"); 448 goto error; 449 } 450 451 psoc = wlan_pdev_get_psoc(pdev); 452 if (!psoc) { 453 ser_err("invalid psoc"); 454 goto error; 455 } 456 457 ser_pdev_obj = wlan_serialization_get_pdev_obj(pdev); 458 if (!ser_pdev_obj) { 459 ser_err("ser_pdev_obj is empty"); 460 goto error; 461 } 462 463 pdev_queue = wlan_serialization_get_pdev_queue_obj( 464 ser_pdev_obj, cmd->cmd_type); 465 466 ser_debug("Type %d id %d blocking %d reason %d active %d", 467 cmd->cmd_type, cmd->cmd_id, cmd->is_blocking, 468 ser_reason, active_cmd); 469 470 wlan_serialization_acquire_lock(&pdev_queue->pdev_queue_lock); 471 472 if (cmd->cmd_type < WLAN_SER_CMD_NONSCAN) 473 qdf_status = wlan_ser_remove_scan_cmd( 474 ser_pdev_obj, &cmd_list, cmd, active_cmd); 475 else { 476 qdf_status = wlan_ser_remove_non_scan_cmd( 477 ser_pdev_obj, &cmd_list, cmd, active_cmd); 478 } 479 480 if (qdf_status == QDF_STATUS_E_PENDING) { 481 status = WLAN_SER_CMD_MARKED_FOR_ACTIVATION; 482 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 483 goto error; 484 } 485 486 if (qdf_status != QDF_STATUS_SUCCESS) { 487 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 488 status = WLAN_SER_CMD_NOT_FOUND; 489 goto error; 490 } 491 492 if (active_cmd) { 493 if (cmd_list->cmd.cmd_type >= WLAN_SER_CMD_NONSCAN) 494 blocking_cmd_removed = cmd_list->cmd.is_blocking; 495 } 496 497 if (active_cmd) 498 wlan_serialization_find_and_stop_timer( 499 psoc, &cmd_list->cmd, 500 ser_reason); 501 502 qdf_mem_copy(&cmd_bkup, &cmd_list->cmd, 503 sizeof(struct wlan_serialization_command)); 504 qdf_mem_zero(&cmd_list->cmd, 505 sizeof(struct wlan_serialization_command)); 506 cmd_list->cmd_in_use = 0; 507 qdf_status = wlan_serialization_insert_back( 508 &pdev_queue->cmd_pool_list, 509 &cmd_list->pdev_node); 510 511 wlan_ser_update_cmd_history(pdev_queue, &cmd_bkup, ser_reason, 512 false, active_cmd); 513 514 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 515 516 if (active_cmd) { 517 ser_status = wlan_serialization_move_pending_to_active( 518 cmd_bkup.cmd_type, ser_pdev_obj, 519 cmd_bkup.vdev, 520 blocking_cmd_removed); 521 } 522 523 /* Call cmd cb for remove request*/ 524 if (cmd_bkup.cmd_cb) { 525 /* caller should release the memory */ 526 ser_debug("Release memory for type %d id %d", 527 cmd_bkup.cmd_type, cmd_bkup.cmd_id); 528 cmd_bkup.cmd_cb(&cmd_bkup, WLAN_SER_CB_RELEASE_MEM_CMD); 529 } 530 531 if (active_cmd) 532 status = WLAN_SER_CMD_IN_ACTIVE_LIST; 533 else 534 status = WLAN_SER_CMD_IN_PENDING_LIST; 535 536 error: 537 return status; 538 } 539 540 static void wlan_serialization_generic_timer_cb(void *arg) 541 { 542 struct wlan_serialization_command *timeout_cmd = arg; 543 struct wlan_objmgr_vdev *vdev = NULL; 544 struct wlan_objmgr_psoc *psoc; 545 546 if (!timeout_cmd) { 547 ser_err("cmd_info not found"); 548 return; 549 } 550 551 vdev = timeout_cmd->vdev; 552 if (!vdev) { 553 ser_err("Invalid vdev"); 554 qdf_mem_free(timeout_cmd); 555 return; 556 } 557 558 psoc = wlan_vdev_get_psoc(vdev); 559 if (!psoc) { 560 ser_err("Psoc is NULL"); 561 goto free; 562 } 563 ser_err("Active cmd timeout for cmd_type[%d] vdev[%d] cmd_id[%d]", 564 timeout_cmd->cmd_type, wlan_vdev_get_id(vdev), 565 timeout_cmd->cmd_id); 566 567 /* 568 * Validate if active cmnd is still present, as actual command 569 * completion can removed it in parallel. 570 */ 571 if (!wlan_serialization_is_cmd_present_in_active_queue(psoc, 572 timeout_cmd)) { 573 ser_err("cmd_type %d vdev %d not in active queue", 574 timeout_cmd->cmd_type, wlan_vdev_get_id(vdev)); 575 goto free; 576 } 577 578 if (timeout_cmd->cmd_cb) 579 timeout_cmd->cmd_cb(timeout_cmd, 580 WLAN_SER_CB_ACTIVE_CMD_TIMEOUT); 581 /* 582 * dequeue cmd API will cleanup and destroy the timer. If it fails to 583 * dequeue command then we have to destroy the timer. 584 */ 585 wlan_serialization_dequeue_cmd(timeout_cmd, SER_TIMEOUT, true); 586 587 free: 588 wlan_objmgr_vdev_release_ref(timeout_cmd->vdev, WLAN_SERIALIZATION_ID); 589 qdf_mem_free(timeout_cmd); 590 } 591 592 static QDF_STATUS wlan_serialization_mc_flush_noop(struct scheduler_msg *msg) 593 { 594 struct wlan_serialization_command *timeout_cmd = msg->bodyptr; 595 596 wlan_objmgr_vdev_release_ref(timeout_cmd->vdev, WLAN_SERIALIZATION_ID); 597 qdf_mem_free(timeout_cmd); 598 599 return QDF_STATUS_SUCCESS; 600 } 601 602 static void 603 wlan_serialization_timer_cb_mc_ctx(struct wlan_serialization_command *cmd) 604 { 605 struct scheduler_msg msg = {0}; 606 struct wlan_serialization_command *timeout_cmd; 607 QDF_STATUS status; 608 609 msg.type = SYS_MSG_ID_MC_TIMER; 610 msg.reserved = SYS_MSG_COOKIE; 611 612 status = wlan_objmgr_vdev_try_get_ref(cmd->vdev, WLAN_SERIALIZATION_ID); 613 if (QDF_IS_STATUS_ERROR(status)) { 614 ser_err("unable to get reference for vdev %d", 615 wlan_vdev_get_id(cmd->vdev)); 616 return; 617 } 618 619 timeout_cmd = qdf_mem_malloc(sizeof(*timeout_cmd)); 620 if (!timeout_cmd) { 621 wlan_objmgr_vdev_release_ref(cmd->vdev, WLAN_SERIALIZATION_ID); 622 return; 623 } 624 625 qdf_mem_copy(timeout_cmd, cmd, sizeof(*timeout_cmd)); 626 627 /* msg.callback will explicitly cast back to qdf_mc_timer_callback_t 628 * in scheduler_timer_q_mq_handler. 629 * but in future we do not want to introduce more this kind of 630 * typecast by properly using QDF MC timer for MCC from get go in 631 * common code. 632 */ 633 msg.callback = 634 (scheduler_msg_process_fn_t)wlan_serialization_generic_timer_cb; 635 msg.bodyptr = timeout_cmd; 636 msg.bodyval = 0; 637 msg.flush_callback = wlan_serialization_mc_flush_noop; 638 639 if (scheduler_post_message(QDF_MODULE_ID_SERIALIZATION, 640 QDF_MODULE_ID_SERIALIZATION, 641 QDF_MODULE_ID_SYS, &msg) == 642 QDF_STATUS_SUCCESS) 643 return; 644 645 ser_err("Could not enqueue timer to timer queue"); 646 /* free mem and release ref on error */ 647 wlan_objmgr_vdev_release_ref(timeout_cmd->vdev, WLAN_SERIALIZATION_ID); 648 qdf_mem_free(timeout_cmd); 649 } 650 651 static void wlan_serialization_timer_handler(void *arg) 652 { 653 struct wlan_serialization_timer *timer = arg; 654 struct wlan_serialization_command *cmd = timer->cmd; 655 656 if (!cmd) { 657 ser_err("Command not found"); 658 return; 659 } 660 661 ser_err("Active cmd timeout for cmd_type %d vdev %d cmd id %d", 662 cmd->cmd_type, wlan_vdev_get_id(cmd->vdev), 663 cmd->cmd_id); 664 665 wlan_serialization_timer_cb_mc_ctx(cmd); 666 } 667 668 QDF_STATUS 669 wlan_serialization_find_and_update_timer( 670 struct wlan_objmgr_psoc *psoc, 671 struct wlan_serialization_command *cmd) 672 { 673 struct wlan_ser_psoc_obj *psoc_ser_obj; 674 struct wlan_serialization_timer *ser_timer; 675 QDF_STATUS status = QDF_STATUS_E_FAILURE; 676 int i = 0; 677 678 if (!psoc || !cmd) { 679 ser_err("invalid param"); 680 goto exit; 681 } 682 683 psoc_ser_obj = wlan_serialization_get_psoc_obj(psoc); 684 /* 685 * Here cmd_id and cmd_type are used to locate the timer being 686 * associated with command. 687 */ 688 wlan_serialization_acquire_lock(&psoc_ser_obj->timer_lock); 689 690 for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) { 691 ser_timer = &psoc_ser_obj->timers[i]; 692 if (!(ser_timer->cmd) || 693 (ser_timer->cmd->cmd_id != cmd->cmd_id) || 694 (ser_timer->cmd->cmd_type != cmd->cmd_type) || 695 (ser_timer->cmd->vdev != cmd->vdev)) 696 continue; 697 698 qdf_timer_mod(&ser_timer->timer, 699 cmd->cmd_timeout_duration); 700 status = QDF_STATUS_SUCCESS; 701 break; 702 } 703 704 wlan_serialization_release_lock(&psoc_ser_obj->timer_lock); 705 706 if (QDF_IS_STATUS_ERROR(status)) 707 ser_debug("Can't find timer for cmd_type %d", cmd->cmd_type); 708 709 exit: 710 return status; 711 } 712 713 QDF_STATUS 714 wlan_serialization_find_and_stop_timer(struct wlan_objmgr_psoc *psoc, 715 struct wlan_serialization_command *cmd, 716 enum ser_queue_reason ser_reason) 717 { 718 struct wlan_ser_psoc_obj *psoc_ser_obj; 719 struct wlan_serialization_timer *ser_timer; 720 QDF_STATUS status = QDF_STATUS_E_FAILURE; 721 int i = 0; 722 uint32_t phy_version; 723 struct wlan_objmgr_vdev *vdev; 724 725 if (!psoc || !cmd) { 726 ser_err("invalid param"); 727 goto exit; 728 } 729 730 if (cmd->cmd_timeout_duration == 0) { 731 phy_version = wlan_psoc_get_nif_phy_version(psoc); 732 if (wlan_is_emulation_platform(phy_version)) { 733 ser_err("[SCAN-EMULATION]: Not performing timer funcs"); 734 status = QDF_STATUS_SUCCESS; 735 goto exit; 736 } 737 } 738 739 psoc_ser_obj = wlan_serialization_get_psoc_obj(psoc); 740 /* 741 * Here cmd_id and cmd_type are used to locate the timer being 742 * associated with command. 743 */ 744 wlan_serialization_acquire_lock(&psoc_ser_obj->timer_lock); 745 746 for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) { 747 ser_timer = &psoc_ser_obj->timers[i]; 748 if (!(ser_timer->cmd) || 749 (ser_timer->cmd->cmd_id != cmd->cmd_id) || 750 (ser_timer->cmd->cmd_type != cmd->cmd_type) || 751 (ser_timer->cmd->vdev != cmd->vdev)) 752 continue; 753 754 vdev = ser_timer->cmd->vdev; 755 status = wlan_serialization_stop_timer(ser_timer); 756 /* 757 * Release the vdev reference when the active cmd is removed 758 * through remove/cancel request. 759 */ 760 wlan_objmgr_vdev_release_ref(vdev, WLAN_SERIALIZATION_ID); 761 762 break; 763 764 } 765 766 wlan_serialization_release_lock(&psoc_ser_obj->timer_lock); 767 768 if (QDF_IS_STATUS_ERROR(status)) 769 ser_err("Can't find timer for cmd_type %d cmd id %d", 770 cmd->cmd_type, cmd->cmd_id); 771 772 exit: 773 return status; 774 } 775 776 QDF_STATUS 777 wlan_serialization_find_and_start_timer(struct wlan_objmgr_psoc *psoc, 778 struct wlan_serialization_command *cmd, 779 enum ser_queue_reason ser_reason) 780 { 781 QDF_STATUS status = QDF_STATUS_E_FAILURE; 782 struct wlan_ser_psoc_obj *psoc_ser_obj; 783 struct wlan_serialization_timer *ser_timer; 784 int i = 0; 785 uint32_t nif_phy_ver; 786 787 if (!psoc || !cmd) { 788 ser_err("invalid param"); 789 goto error; 790 } 791 792 nif_phy_ver = wlan_psoc_get_nif_phy_version(psoc); 793 if ((cmd->cmd_timeout_duration == 0) && 794 (wlan_is_emulation_platform(nif_phy_ver))) { 795 ser_err("[SCAN-EMULATION]: Not performing timer functions\n"); 796 status = QDF_STATUS_SUCCESS; 797 goto error; 798 } 799 800 psoc_ser_obj = wlan_serialization_get_psoc_obj(psoc); 801 802 wlan_serialization_acquire_lock(&psoc_ser_obj->timer_lock); 803 804 for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) { 805 /* Keep trying timer */ 806 ser_timer = &psoc_ser_obj->timers[i]; 807 if (ser_timer->cmd) 808 continue; 809 810 /* Remember timer is pointing to command */ 811 ser_timer->cmd = cmd; 812 status = QDF_STATUS_SUCCESS; 813 814 /* 815 * Get vdev reference before starting the timer 816 * Remove the reference before removing the command 817 * in any one of the cases: 818 * 1. Active command is removed through remove/cancel request 819 * 2. Timer expiry handler is completed. 820 */ 821 822 status = wlan_objmgr_vdev_try_get_ref(ser_timer->cmd->vdev, 823 WLAN_SERIALIZATION_ID); 824 if (QDF_IS_STATUS_ERROR(status)) { 825 /* 826 * Set cmd to null so that ref release is not tried for 827 * vdev when timer is flushed. 828 */ 829 ser_timer->cmd = NULL; 830 wlan_serialization_release_lock( 831 &psoc_ser_obj->timer_lock); 832 ser_err("Unbale to get vdev reference"); 833 status = QDF_STATUS_E_FAILURE; 834 goto error; 835 } 836 break; 837 } 838 839 wlan_serialization_release_lock(&psoc_ser_obj->timer_lock); 840 841 if (QDF_IS_STATUS_SUCCESS(status)) { 842 qdf_timer_init(NULL, &ser_timer->timer, 843 wlan_serialization_timer_handler, 844 ser_timer, QDF_TIMER_TYPE_SW); 845 qdf_timer_mod(&ser_timer->timer, cmd->cmd_timeout_duration); 846 } else { 847 ser_err("Failed to start timer for cmd: type[%d] id[%d] high_priority[%d] blocking[%d]", 848 cmd->cmd_type, cmd->cmd_id, cmd->is_high_priority, 849 cmd->is_blocking); 850 } 851 852 error: 853 return status; 854 } 855 856 enum wlan_serialization_cmd_status 857 wlan_serialization_cmd_cancel_handler( 858 struct wlan_ser_pdev_obj *ser_obj, 859 struct wlan_serialization_command *cmd, 860 struct wlan_objmgr_pdev *pdev, struct wlan_objmgr_vdev *vdev, 861 enum wlan_serialization_cmd_type cmd_type, uint8_t queue_type, 862 enum wlan_ser_cmd_attr cmd_attr) 863 { 864 enum wlan_serialization_cmd_status active_status = 865 WLAN_SER_CMD_NOT_FOUND; 866 enum wlan_serialization_cmd_status pending_status = 867 WLAN_SER_CMD_NOT_FOUND; 868 enum wlan_serialization_cmd_status status = 869 WLAN_SER_CMD_NOT_FOUND; 870 871 if (!ser_obj) { 872 ser_err("invalid serial object"); 873 goto error; 874 } 875 876 if (queue_type & WLAN_SERIALIZATION_ACTIVE_QUEUE) { 877 if (cmd_type < WLAN_SER_CMD_NONSCAN) 878 active_status = wlan_ser_cancel_scan_cmd( 879 ser_obj, pdev, vdev, cmd, 880 cmd_type, true); 881 else 882 active_status = wlan_ser_cancel_non_scan_cmd( 883 ser_obj, pdev, vdev, cmd, 884 cmd_type, true, cmd_attr); 885 } 886 887 if (queue_type & WLAN_SERIALIZATION_PENDING_QUEUE) { 888 if (cmd_type < WLAN_SER_CMD_NONSCAN) 889 pending_status = wlan_ser_cancel_scan_cmd( 890 ser_obj, pdev, vdev, cmd, 891 cmd_type, false); 892 else 893 pending_status = wlan_ser_cancel_non_scan_cmd( 894 ser_obj, pdev, vdev, cmd, 895 cmd_type, false, cmd_attr); 896 } 897 898 if (active_status == WLAN_SER_CMD_IN_ACTIVE_LIST && 899 pending_status == WLAN_SER_CMD_IN_PENDING_LIST) 900 status = WLAN_SER_CMDS_IN_ALL_LISTS; 901 else if (active_status == WLAN_SER_CMD_IN_ACTIVE_LIST) 902 status = active_status; 903 else if (pending_status == WLAN_SER_CMD_IN_PENDING_LIST) 904 status = pending_status; 905 906 error: 907 return status; 908 } 909 910 enum wlan_serialization_cmd_status 911 wlan_serialization_find_and_cancel_cmd( 912 struct wlan_serialization_command *cmd, 913 enum wlan_serialization_cancel_type req_type, 914 uint8_t queue_type) 915 { 916 enum wlan_serialization_cmd_status status = WLAN_SER_CMD_NOT_FOUND; 917 struct wlan_ser_pdev_obj *ser_obj = NULL; 918 struct wlan_objmgr_pdev *pdev; 919 920 if (!cmd) { 921 ser_err("Invalid cmd"); 922 goto error; 923 } 924 925 pdev = wlan_serialization_get_pdev_from_cmd(cmd); 926 if (!pdev) { 927 ser_err("Invalid pdev"); 928 goto error; 929 } 930 ser_obj = wlan_serialization_get_pdev_obj(pdev); 931 if (!ser_obj) { 932 ser_err("Invalid ser_obj"); 933 goto error; 934 } 935 936 switch (req_type) { 937 case WLAN_SER_CANCEL_SINGLE_SCAN: 938 /* remove scan cmd which matches the given cmd struct */ 939 status = wlan_serialization_cmd_cancel_handler( 940 ser_obj, cmd, NULL, NULL, 941 WLAN_SER_CMD_SCAN, queue_type, 942 WLAN_SER_CMD_ATTR_NONE); 943 break; 944 case WLAN_SER_CANCEL_PDEV_SCANS: 945 /* remove all scan cmds which matches the pdev object */ 946 status = wlan_serialization_cmd_cancel_handler( 947 ser_obj, NULL, pdev, NULL, 948 WLAN_SER_CMD_SCAN, queue_type, 949 WLAN_SER_CMD_ATTR_NONE); 950 break; 951 case WLAN_SER_CANCEL_VDEV_SCANS: 952 case WLAN_SER_CANCEL_VDEV_HOST_SCANS: 953 /* remove all scan cmds which matches the vdev object */ 954 status = wlan_serialization_cmd_cancel_handler( 955 ser_obj, NULL, NULL, cmd->vdev, 956 WLAN_SER_CMD_SCAN, queue_type, 957 WLAN_SER_CMD_ATTR_NONE); 958 break; 959 case WLAN_SER_CANCEL_NON_SCAN_CMD: 960 /* remove nonscan cmd which matches the given cmd */ 961 status = wlan_serialization_cmd_cancel_handler( 962 ser_obj, cmd, NULL, NULL, 963 WLAN_SER_CMD_NONSCAN, queue_type, 964 WLAN_SER_CMD_ATTR_NONE); 965 break; 966 case WLAN_SER_CANCEL_PDEV_NON_SCAN_CMD: 967 /* remove all non scan cmds which matches the pdev object */ 968 status = wlan_serialization_cmd_cancel_handler( 969 ser_obj, NULL, pdev, NULL, 970 WLAN_SER_CMD_NONSCAN, queue_type, 971 WLAN_SER_CMD_ATTR_NONE); 972 break; 973 case WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD: 974 /* remove all non scan cmds which matches the vdev object */ 975 status = wlan_serialization_cmd_cancel_handler( 976 ser_obj, NULL, NULL, cmd->vdev, 977 WLAN_SER_CMD_NONSCAN, queue_type, 978 WLAN_SER_CMD_ATTR_NONE); 979 break; 980 case WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD_TYPE: 981 /* 982 * remove all non scan cmds which matches the vdev 983 * and given cmd type 984 */ 985 status = wlan_serialization_cmd_cancel_handler( 986 ser_obj, NULL, NULL, cmd->vdev, 987 cmd->cmd_type, queue_type, 988 WLAN_SER_CMD_ATTR_NONE); 989 break; 990 case WLAN_SER_CANCEL_VDEV_NON_SCAN_NB_CMD: 991 /* 992 * remove all non-blocking non-scan cmds which matches the given 993 * vdev 994 */ 995 status = wlan_serialization_cmd_cancel_handler( 996 ser_obj, NULL, NULL, cmd->vdev, 997 WLAN_SER_CMD_NONSCAN, queue_type, 998 WLAN_SER_CMD_ATTR_NONBLOCK); 999 break; 1000 default: 1001 ser_err("Invalid request"); 1002 } 1003 1004 error: 1005 1006 return status; 1007 } 1008