1 /* 2 * Copyright (c) 2017-2018 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 { 91 enum wlan_serialization_status status = WLAN_SER_CMD_DENIED_UNSPECIFIED; 92 struct wlan_serialization_command_list *cmd_list; 93 qdf_list_node_t *nnode; 94 struct wlan_objmgr_pdev *pdev; 95 struct wlan_ser_pdev_obj *ser_pdev_obj; 96 struct wlan_serialization_pdev_queue *pdev_queue; 97 bool active_queue; 98 99 /* Enqueue process 100 * 1) peek through command structure and see what is the command type 101 * 2) two main types of commands to process 102 * a) SCAN 103 * b) NON-SCAN 104 * 3) for each command there are separate command queues per pdev 105 * 4) pull pdev from vdev structure and get the command queue associated 106 * with that pdev and try to enqueue on those queue 107 * 5) Thumb rule: 108 * a) There could be only 1 active non-scan command at a 109 * time including all total non-scan commands of all pdevs. 110 * 111 * example: pdev1 has 1 non-scan active command and 112 * pdev2 got 1 non-scan command then that command should go to 113 * pdev2's pending queue 114 * 115 * b) There could be only N number of scan commands at a time 116 * including all total scan commands of all pdevs 117 * 118 * example: Let's say N=8, 119 * pdev1's vdev1 has 5 scan command, pdev2's vdev1 has 3 120 * scan commands, if we get scan request on vdev2 then it will go 121 * to pending queue of vdev2 as we reached max allowed scan active 122 * command. 123 */ 124 125 ser_enter(); 126 127 if (!cmd) { 128 ser_err("NULL command"); 129 goto error; 130 } 131 132 if (!cmd->cmd_cb) { 133 ser_err("no cmd_cb for cmd type:%d, id: %d", 134 cmd->cmd_type, 135 cmd->cmd_id); 136 goto error; 137 } 138 139 pdev = wlan_serialization_get_pdev_from_cmd(cmd); 140 if (!pdev) { 141 ser_err("pdev is invalid"); 142 goto error; 143 } 144 145 ser_pdev_obj = 146 wlan_objmgr_pdev_get_comp_private_obj( 147 pdev, 148 WLAN_UMAC_COMP_SERIALIZATION); 149 if (!ser_pdev_obj) { 150 ser_err("Invalid ser_pdev_obj"); 151 goto error; 152 } 153 154 pdev_queue = wlan_serialization_get_pdev_queue_obj(ser_pdev_obj, 155 cmd->cmd_type); 156 if (!pdev_queue) { 157 ser_err("pdev_queue is invalid"); 158 goto error; 159 } 160 161 ser_debug("enqueue cmd: type[%d] id[%d] high_priority[%d] blocking[%d]", 162 cmd->cmd_type, 163 cmd->cmd_id, 164 cmd->is_high_priority, 165 cmd->is_blocking); 166 167 wlan_serialization_acquire_lock(&pdev_queue->pdev_queue_lock); 168 169 active_queue = wlan_serialization_is_active_cmd_allowed(cmd); 170 171 if (wlan_serialization_is_cmd_present_queue(cmd, active_queue)) { 172 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 173 ser_err("duplicate command, can't enqueue"); 174 goto error; 175 } 176 177 if (wlan_serialization_remove_front( 178 &pdev_queue->cmd_pool_list, 179 &nnode) != QDF_STATUS_SUCCESS) { 180 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 181 ser_err("Failed to get cmd buffer from global pool"); 182 goto error; 183 } 184 185 ser_debug("Global pool node: %pK", nnode); 186 187 cmd_list = 188 qdf_container_of(nnode, 189 struct wlan_serialization_command_list, 190 pdev_node); 191 192 qdf_mem_copy(&cmd_list->cmd, cmd, 193 sizeof(struct wlan_serialization_command)); 194 195 if (cmd->cmd_type < WLAN_SER_CMD_NONSCAN) { 196 status = wlan_ser_add_scan_cmd(ser_pdev_obj, 197 cmd_list, 198 active_queue); 199 } else { 200 status = wlan_ser_add_non_scan_cmd(ser_pdev_obj, 201 cmd_list, 202 active_queue); 203 } 204 205 if (status != WLAN_SER_CMD_PENDING && status != WLAN_SER_CMD_ACTIVE) { 206 ser_err("Failed to add cmd to active/pending queue"); 207 qdf_mem_zero(&cmd_list->cmd, 208 sizeof(struct wlan_serialization_command)); 209 wlan_serialization_insert_back( 210 &pdev_queue->cmd_pool_list, 211 &cmd_list->pdev_node); 212 } 213 214 if (WLAN_SER_CMD_ACTIVE == status) { 215 qdf_atomic_set_bit(CMD_MARKED_FOR_ACTIVATION, 216 &cmd_list->cmd_in_use); 217 } 218 219 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 220 221 if (WLAN_SER_CMD_ACTIVE == status) 222 wlan_serialization_activate_cmd(cmd_list, 223 ser_pdev_obj); 224 225 error: 226 ser_exit(); 227 228 return status; 229 } 230 231 QDF_STATUS 232 wlan_serialization_activate_multiple_cmd( 233 struct wlan_ser_pdev_obj *ser_pdev_obj) 234 { 235 struct wlan_serialization_pdev_queue *pdev_queue; 236 qdf_list_t *active_queue; 237 QDF_STATUS peek_status = QDF_STATUS_E_FAILURE; 238 struct wlan_serialization_command_list *active_cmd_list; 239 uint32_t qsize; 240 uint32_t vdev_id; 241 qdf_list_node_t *nnode = NULL; 242 QDF_STATUS status = QDF_STATUS_SUCCESS; 243 struct wlan_objmgr_psoc *psoc = NULL; 244 245 pdev_queue = &ser_pdev_obj->pdev_q[SER_PDEV_QUEUE_COMP_NON_SCAN]; 246 247 wlan_serialization_acquire_lock(&pdev_queue->pdev_queue_lock); 248 249 active_queue = &pdev_queue->active_list; 250 qsize = wlan_serialization_list_size(active_queue); 251 252 while (qsize--) { 253 peek_status = wlan_serialization_get_cmd_from_queue( 254 active_queue, &nnode); 255 256 if (peek_status != QDF_STATUS_SUCCESS) { 257 ser_err("can't peek cmd"); 258 break; 259 } 260 261 active_cmd_list = qdf_container_of( 262 nnode, struct wlan_serialization_command_list, 263 pdev_node); 264 265 if (!qdf_atomic_test_bit(CMD_MARKED_FOR_ACTIVATION, 266 &active_cmd_list->cmd_in_use)) { 267 continue; 268 } 269 270 qdf_atomic_clear_bit(CMD_MARKED_FOR_ACTIVATION, 271 &active_cmd_list->cmd_in_use); 272 273 qdf_atomic_set_bit(CMD_IS_ACTIVE, 274 &active_cmd_list->cmd_in_use); 275 276 vdev_id = wlan_vdev_get_id(active_cmd_list->cmd.vdev); 277 pdev_queue->vdev_active_cmd_bitmap |= (1 << vdev_id); 278 279 if (active_cmd_list->cmd.is_blocking) 280 pdev_queue->blocking_cmd_active = 1; 281 282 /* 283 * Command is already pushed to active queue. 284 * Now start the timer. 285 */ 286 psoc = wlan_vdev_get_psoc(active_cmd_list->cmd.vdev); 287 wlan_serialization_find_and_start_timer(psoc, 288 &active_cmd_list->cmd); 289 290 ser_debug("cmd cb: type[%d] id[%d] : reason: %s", 291 active_cmd_list->cmd.cmd_type, 292 active_cmd_list->cmd.cmd_id, 293 "WLAN_SER_CB_ACTIVATE_CMD"); 294 295 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 296 297 status = active_cmd_list->cmd.cmd_cb(&active_cmd_list->cmd, 298 WLAN_SER_CB_ACTIVATE_CMD); 299 300 if (QDF_IS_STATUS_ERROR(status)) 301 wlan_serialization_dequeue_cmd(&active_cmd_list->cmd, 302 true); 303 304 wlan_serialization_acquire_lock(&pdev_queue->pdev_queue_lock); 305 } 306 307 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 308 return status; 309 } 310 311 QDF_STATUS wlan_serialization_activate_cmd( 312 struct wlan_serialization_command_list *cmd_list, 313 struct wlan_ser_pdev_obj *ser_pdev_obj) 314 { 315 QDF_STATUS status = QDF_STATUS_E_FAILURE; 316 struct wlan_objmgr_psoc *psoc = NULL; 317 318 psoc = wlan_vdev_get_psoc(cmd_list->cmd.vdev); 319 if (!psoc) { 320 ser_err("invalid psoc"); 321 goto error; 322 } 323 324 /* 325 * command is already pushed to active queue above 326 * now start the timer and notify requestor 327 */ 328 wlan_serialization_find_and_start_timer(psoc, &cmd_list->cmd); 329 /* 330 * Remember that serialization module may send 331 * this callback in same context through which it 332 * received the serialization request. Due to which 333 * it is caller's responsibility to ensure acquiring 334 * and releasing its own lock appropriately. 335 */ 336 337 ser_debug("cmd cb: type[%d] id[%d] : reason: %s", 338 cmd_list->cmd.cmd_type, 339 cmd_list->cmd.cmd_id, 340 "WLAN_SER_CB_ACTIVATE_CMD"); 341 342 status = cmd_list->cmd.cmd_cb(&cmd_list->cmd, 343 WLAN_SER_CB_ACTIVATE_CMD); 344 345 qdf_atomic_clear_bit(CMD_MARKED_FOR_ACTIVATION, 346 &cmd_list->cmd_in_use); 347 qdf_atomic_set_bit(CMD_IS_ACTIVE, 348 &cmd_list->cmd_in_use); 349 350 if (QDF_IS_STATUS_ERROR(status)) 351 wlan_serialization_dequeue_cmd(&cmd_list->cmd, true); 352 353 error: 354 return status; 355 } 356 357 bool 358 wlan_serialization_is_active_cmd_allowed(struct wlan_serialization_command *cmd) 359 { 360 struct wlan_objmgr_pdev *pdev; 361 bool active_cmd_allowed = 0; 362 363 pdev = wlan_serialization_get_pdev_from_cmd(cmd); 364 if (!pdev) { 365 ser_err("NULL pdev"); 366 goto error; 367 } 368 369 if (cmd->cmd_type < WLAN_SER_CMD_NONSCAN) 370 active_cmd_allowed = 371 wlan_serialization_is_active_scan_cmd_allowed(cmd); 372 else 373 active_cmd_allowed = 374 wlan_serialization_is_active_non_scan_cmd_allowed(cmd); 375 376 ser_debug("active cmd_type[%d] cmd_id[%d] allowed: %d", 377 cmd->cmd_type, 378 cmd->cmd_id, 379 active_cmd_allowed); 380 381 error: 382 return active_cmd_allowed; 383 } 384 385 enum wlan_serialization_status 386 wlan_serialization_move_pending_to_active( 387 enum wlan_serialization_cmd_type cmd_type, 388 struct wlan_serialization_command_list **pcmd_list, 389 struct wlan_ser_pdev_obj *ser_pdev_obj, 390 struct wlan_objmgr_vdev *vdev, 391 bool blocking_cmd_removed, 392 bool blocking_cmd_waiting) 393 { 394 enum wlan_serialization_status status; 395 struct wlan_serialization_pdev_queue *pdev_queue; 396 397 if (cmd_type < WLAN_SER_CMD_NONSCAN) { 398 status = 399 wlan_ser_move_scan_pending_to_active( 400 pcmd_list, 401 ser_pdev_obj); 402 } else { 403 pdev_queue = 404 &ser_pdev_obj->pdev_q[SER_PDEV_QUEUE_COMP_NON_SCAN]; 405 406 if (!blocking_cmd_removed && !blocking_cmd_waiting) 407 status = 408 wlan_ser_move_non_scan_pending_to_active( 409 pcmd_list, 410 ser_pdev_obj, 411 vdev); 412 else 413 status = 414 wlan_ser_move_multiple_non_scan_pending_to_active( 415 ser_pdev_obj); 416 } 417 418 return status; 419 } 420 421 enum wlan_serialization_cmd_status 422 wlan_serialization_dequeue_cmd(struct wlan_serialization_command *cmd, 423 uint8_t active_cmd) 424 { 425 enum wlan_serialization_cmd_status status = 426 WLAN_SER_CMD_NOT_FOUND; 427 enum wlan_serialization_status ser_status = 428 WLAN_SER_CMD_DENIED_UNSPECIFIED; 429 430 QDF_STATUS qdf_status; 431 struct wlan_objmgr_pdev *pdev; 432 struct wlan_objmgr_psoc *psoc; 433 struct wlan_ser_pdev_obj *ser_pdev_obj; 434 struct wlan_serialization_command cmd_bkup; 435 struct wlan_serialization_command_list *cmd_list; 436 struct wlan_serialization_command_list *pcmd_list; 437 struct wlan_serialization_pdev_queue *pdev_queue; 438 bool blocking_cmd_removed = 0; 439 bool blocking_cmd_waiting = 0; 440 441 ser_enter(); 442 443 if (!cmd) { 444 ser_err("NULL command"); 445 goto error; 446 } 447 448 pdev = wlan_serialization_get_pdev_from_cmd(cmd); 449 if (!pdev) { 450 ser_err("invalid pdev"); 451 goto error; 452 } 453 454 psoc = wlan_pdev_get_psoc(pdev); 455 if (!psoc) { 456 ser_err("invalid psoc"); 457 goto error; 458 } 459 460 ser_pdev_obj = wlan_serialization_get_pdev_obj(pdev); 461 if (!ser_pdev_obj) { 462 ser_err("ser_pdev_obj is empty"); 463 goto error; 464 } 465 466 pdev_queue = wlan_serialization_get_pdev_queue_obj( 467 ser_pdev_obj, cmd->cmd_type); 468 469 ser_debug("dequeue cmd: type[%d] id[%d] high_priority[%d] blocking[%d]", 470 cmd->cmd_type, 471 cmd->cmd_id, 472 cmd->is_high_priority, 473 cmd->is_blocking); 474 475 wlan_serialization_acquire_lock(&pdev_queue->pdev_queue_lock); 476 477 if (cmd->cmd_type < WLAN_SER_CMD_NONSCAN) 478 qdf_status = wlan_ser_remove_scan_cmd( 479 ser_pdev_obj, &cmd_list, cmd, active_cmd); 480 else { 481 qdf_status = wlan_ser_remove_non_scan_cmd( 482 ser_pdev_obj, &cmd_list, cmd, active_cmd); 483 } 484 485 if (qdf_status != QDF_STATUS_SUCCESS) { 486 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 487 status = WLAN_SER_CMD_NOT_FOUND; 488 goto error; 489 } 490 491 if (active_cmd) { 492 wlan_serialization_find_and_stop_timer(psoc, &cmd_list->cmd); 493 494 if (cmd_list->cmd.cmd_type >= WLAN_SER_CMD_NONSCAN) 495 blocking_cmd_removed = cmd_list->cmd.is_blocking; 496 } 497 498 qdf_mem_copy(&cmd_bkup, &cmd_list->cmd, 499 sizeof(struct wlan_serialization_command)); 500 qdf_mem_zero(&cmd_list->cmd, 501 sizeof(struct wlan_serialization_command)); 502 qdf_status = wlan_serialization_insert_back( 503 &pdev_queue->cmd_pool_list, 504 &cmd_list->pdev_node); 505 506 /* 507 * For NON SCAN commands, the following is possible: 508 * 509 * If the remove is for non blocking command, 510 * and there is no blocking command waiting, 511 * look at vdev pending queue and 512 * only one command moves from pending 513 * to active 514 * 515 * If the remove is for blocking comamnd, 516 * look at the pdev queue and 517 * either single blocking command 518 * or multiple non blocking commands moves 519 * from pending to active 520 */ 521 522 blocking_cmd_waiting = pdev_queue->blocking_cmd_waiting; 523 524 if (active_cmd) { 525 ser_status = wlan_serialization_move_pending_to_active( 526 cmd_bkup.cmd_type, &pcmd_list, ser_pdev_obj, 527 cmd_bkup.vdev, 528 blocking_cmd_removed, 529 blocking_cmd_waiting); 530 } 531 532 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 533 534 /* Call cmd cb for remove request*/ 535 if (cmd_bkup.cmd_cb) { 536 /* caller should release the memory */ 537 ser_debug("cmd cb: type[%d] id[%d]: reason: %s", 538 cmd_bkup.cmd_type, 539 cmd_bkup.cmd_id, 540 "WLAN_SER_CB_RELEASE_MEM_CMD"); 541 cmd_bkup.cmd_cb(&cmd_bkup, 542 WLAN_SER_CB_RELEASE_MEM_CMD); 543 } 544 545 /* 546 * If the remove is for non blocking command, 547 * and there is no blocking command waiting, 548 * look at vdev pending queue and 549 * only one command moves from pending 550 * to active and gets activated 551 */ 552 if (WLAN_SER_CMD_ACTIVE == ser_status && !blocking_cmd_removed && 553 !blocking_cmd_waiting) { 554 ser_debug("cmd type[%d] id[%d] moved from pending to active", 555 pcmd_list->cmd.cmd_type, 556 pcmd_list->cmd.cmd_id); 557 wlan_serialization_activate_cmd(pcmd_list, 558 ser_pdev_obj); 559 } else if (ser_status == WLAN_SER_CMD_ACTIVE) { 560 /* If the remove is for blocking command 561 * either one or multiple commands can move 562 * from pending to active and gets activated 563 */ 564 wlan_serialization_activate_multiple_cmd(ser_pdev_obj); 565 } else { 566 goto exit; 567 } 568 569 exit: 570 if (active_cmd) 571 status = WLAN_SER_CMD_IN_ACTIVE_LIST; 572 else 573 status = WLAN_SER_CMD_IN_PENDING_LIST; 574 575 error: 576 ser_exit(); 577 return status; 578 } 579 580 void wlan_serialization_generic_timer_cb(void *arg) 581 { 582 struct wlan_serialization_timer *timer = arg; 583 struct wlan_serialization_command *cmd = timer->cmd; 584 585 if (!cmd) { 586 ser_err("command not found"); 587 QDF_ASSERT(0); 588 return; 589 } 590 591 ser_err("active cmd timeout for cmd_type[%d] vdev[%pK]", 592 cmd->cmd_type, cmd->vdev); 593 594 if (cmd->cmd_cb) 595 cmd->cmd_cb(cmd, WLAN_SER_CB_ACTIVE_CMD_TIMEOUT); 596 597 /* 598 * dequeue cmd API will cleanup and destroy the timer. If it fails to 599 * dequeue command then we have to destroy the timer. 600 */ 601 wlan_serialization_dequeue_cmd(cmd, true); 602 } 603 604 static QDF_STATUS wlan_serialization_mc_flush_noop(struct scheduler_msg *msg) 605 { 606 return QDF_STATUS_SUCCESS; 607 } 608 609 static void 610 wlan_serialization_timer_cb_mc_ctx(void *arg) 611 { 612 struct scheduler_msg msg = {0}; 613 614 msg.type = SYS_MSG_ID_MC_TIMER; 615 msg.reserved = SYS_MSG_COOKIE; 616 msg.callback = wlan_serialization_generic_timer_cb; 617 msg.bodyptr = arg; 618 msg.bodyval = 0; 619 msg.flush_callback = wlan_serialization_mc_flush_noop; 620 621 if (scheduler_post_msg(QDF_MODULE_ID_SYS, &msg) == QDF_STATUS_SUCCESS) 622 return; 623 624 ser_err("Could not enqueue timer to timer queue"); 625 } 626 627 #ifdef CONFIG_MCL 628 static void wlan_serialization_timer_handler(void *arg) 629 { 630 ser_enter(); 631 632 wlan_serialization_timer_cb_mc_ctx(arg); 633 634 ser_exit(); 635 } 636 #else 637 static void wlan_serialization_timer_handler(void *arg) 638 { 639 struct wlan_serialization_timer *timer = arg; 640 struct wlan_serialization_command *cmd = timer->cmd; 641 642 if (!cmd) { 643 ser_err("command not found"); 644 QDF_ASSERT(0); 645 return; 646 } 647 648 if (cmd->cmd_type < WLAN_SER_CMD_NONSCAN) 649 wlan_serialization_timer_cb_mc_ctx(arg); 650 else 651 wlan_serialization_generic_timer_cb(arg); 652 } 653 #endif 654 655 QDF_STATUS 656 wlan_serialization_find_and_stop_timer(struct wlan_objmgr_psoc *psoc, 657 struct wlan_serialization_command *cmd) 658 { 659 struct wlan_ser_psoc_obj *psoc_ser_obj; 660 struct wlan_serialization_timer *ser_timer; 661 QDF_STATUS status = QDF_STATUS_E_FAILURE; 662 int i = 0; 663 uint32_t phy_version; 664 665 if (!psoc || !cmd) { 666 ser_err("invalid param"); 667 goto error; 668 } 669 670 if (cmd->cmd_timeout_duration == 0) { 671 phy_version = wlan_psoc_get_nif_phy_version(psoc); 672 if (wlan_is_emulation_platform(phy_version)) { 673 ser_err("[SCAN-EMULATION]: Not performing timer funcs"); 674 status = QDF_STATUS_SUCCESS; 675 goto exit; 676 } 677 } 678 679 psoc_ser_obj = wlan_serialization_get_psoc_obj(psoc); 680 /* 681 * Here cmd_id and cmd_type are used to locate the timer being 682 * associated with command. For scan command, cmd_id is expected to 683 * be unique and For non-scan command, there should be only one active 684 * command per pdev 685 */ 686 wlan_serialization_acquire_lock(&psoc_ser_obj->timer_lock); 687 688 for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) { 689 ser_timer = &psoc_ser_obj->timers[i]; 690 if (!(ser_timer->cmd) || 691 (ser_timer->cmd->cmd_id != cmd->cmd_id) || 692 (ser_timer->cmd->cmd_type != cmd->cmd_type) || 693 (ser_timer->cmd->vdev != cmd->vdev)) 694 continue; 695 696 status = QDF_STATUS_SUCCESS; 697 break; 698 } 699 700 wlan_serialization_release_lock(&psoc_ser_obj->timer_lock); 701 702 if (QDF_IS_STATUS_SUCCESS(status)) { 703 status = wlan_serialization_stop_timer(ser_timer); 704 ser_debug("\n Stopping timer for cmd type:%d, id: %d", 705 cmd->cmd_type, cmd->cmd_id); 706 } else { 707 ser_err("Can't find timer for cmd_type[%d]", cmd->cmd_type); 708 } 709 710 711 error: 712 exit: 713 714 return status; 715 } 716 717 QDF_STATUS 718 wlan_serialization_find_and_start_timer(struct wlan_objmgr_psoc *psoc, 719 struct wlan_serialization_command *cmd) 720 { 721 QDF_STATUS status = QDF_STATUS_E_FAILURE; 722 struct wlan_ser_psoc_obj *psoc_ser_obj; 723 struct wlan_serialization_timer *ser_timer; 724 int i = 0; 725 uint32_t nif_phy_ver; 726 727 if (!psoc || !cmd) { 728 ser_err("invalid param"); 729 goto error; 730 } 731 732 nif_phy_ver = wlan_psoc_get_nif_phy_version(psoc); 733 if ((cmd->cmd_timeout_duration == 0) && 734 (wlan_is_emulation_platform(nif_phy_ver))) { 735 ser_err("[SCAN-EMULATION]: Not performing timer functions\n"); 736 status = QDF_STATUS_SUCCESS; 737 goto exit; 738 } 739 740 psoc_ser_obj = wlan_serialization_get_psoc_obj(psoc); 741 742 wlan_serialization_acquire_lock(&psoc_ser_obj->timer_lock); 743 744 for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) { 745 /* Keep trying timer */ 746 ser_timer = &psoc_ser_obj->timers[i]; 747 if (ser_timer->cmd) 748 continue; 749 750 /* Remember timer is pointing to command */ 751 ser_timer->cmd = cmd; 752 status = QDF_STATUS_SUCCESS; 753 break; 754 } 755 756 wlan_serialization_release_lock(&psoc_ser_obj->timer_lock); 757 758 if (QDF_IS_STATUS_SUCCESS(status)) { 759 qdf_timer_init(NULL, 760 &ser_timer->timer, 761 wlan_serialization_timer_handler, 762 ser_timer, 763 QDF_TIMER_TYPE_SW); 764 qdf_timer_mod(&ser_timer->timer, 765 cmd->cmd_timeout_duration); 766 767 ser_debug("starting timer for cmd: type[%d] id[%d] high_priority[%d] blocking[%d]", 768 cmd->cmd_type, 769 cmd->cmd_id, 770 cmd->is_high_priority, 771 cmd->is_blocking); 772 } 773 774 error: 775 exit: 776 777 return status; 778 } 779 780 enum wlan_serialization_cmd_status 781 wlan_serialization_cmd_cancel_handler( 782 struct wlan_ser_pdev_obj *ser_obj, 783 struct wlan_serialization_command *cmd, 784 struct wlan_objmgr_pdev *pdev, struct wlan_objmgr_vdev *vdev, 785 enum wlan_serialization_cmd_type cmd_type, uint8_t queue_type) 786 { 787 enum wlan_serialization_cmd_status active_status = 788 WLAN_SER_CMD_NOT_FOUND; 789 enum wlan_serialization_cmd_status pending_status = 790 WLAN_SER_CMD_NOT_FOUND; 791 enum wlan_serialization_cmd_status status = 792 WLAN_SER_CMD_NOT_FOUND; 793 794 ser_enter(); 795 796 if (!ser_obj) { 797 ser_err("invalid serial object"); 798 goto error; 799 } 800 801 if (queue_type & WLAN_SERIALIZATION_ACTIVE_QUEUE) { 802 if (cmd_type < WLAN_SER_CMD_NONSCAN) 803 active_status = wlan_ser_cancel_scan_cmd( 804 ser_obj, pdev, vdev, cmd, 805 cmd_type, true); 806 else 807 active_status = wlan_ser_cancel_non_scan_cmd( 808 ser_obj, pdev, vdev, cmd, 809 cmd_type, true); 810 } 811 812 if (queue_type & WLAN_SERIALIZATION_PENDING_QUEUE) { 813 if (cmd_type < WLAN_SER_CMD_NONSCAN) 814 pending_status = wlan_ser_cancel_scan_cmd( 815 ser_obj, pdev, vdev, cmd, 816 cmd_type, false); 817 else 818 pending_status = wlan_ser_cancel_non_scan_cmd( 819 ser_obj, pdev, vdev, cmd, 820 cmd_type, false); 821 } 822 823 if (active_status == WLAN_SER_CMD_IN_ACTIVE_LIST && 824 pending_status == WLAN_SER_CMD_IN_PENDING_LIST) 825 status = WLAN_SER_CMDS_IN_ALL_LISTS; 826 else if (active_status == WLAN_SER_CMD_IN_ACTIVE_LIST) 827 status = active_status; 828 else if (pending_status == WLAN_SER_CMD_IN_PENDING_LIST) 829 status = pending_status; 830 831 error: 832 ser_exit(); 833 return status; 834 } 835 836 enum wlan_serialization_cmd_status 837 wlan_serialization_find_and_cancel_cmd( 838 struct wlan_serialization_command *cmd, 839 enum wlan_serialization_cancel_type req_type, 840 uint8_t queue_type) 841 { 842 enum wlan_serialization_cmd_status status = WLAN_SER_CMD_NOT_FOUND; 843 struct wlan_ser_pdev_obj *ser_obj = NULL; 844 struct wlan_objmgr_pdev *pdev; 845 846 ser_enter(); 847 848 if (!cmd) { 849 ser_err("Invalid cmd"); 850 goto error; 851 } 852 853 pdev = wlan_serialization_get_pdev_from_cmd(cmd); 854 if (!pdev) { 855 ser_err("Invalid pdev"); 856 goto error; 857 } 858 ser_obj = wlan_serialization_get_pdev_obj(pdev); 859 if (!ser_obj) { 860 ser_err("Invalid ser_obj"); 861 goto error; 862 } 863 864 switch (req_type) { 865 case WLAN_SER_CANCEL_SINGLE_SCAN: 866 /* remove scan cmd which matches the given cmd struct */ 867 status = wlan_serialization_cmd_cancel_handler(ser_obj, 868 cmd, 869 NULL, 870 NULL, 871 cmd->cmd_type, 872 queue_type); 873 break; 874 case WLAN_SER_CANCEL_PDEV_SCANS: 875 /* remove all scan cmds which matches the pdev object */ 876 status = wlan_serialization_cmd_cancel_handler( 877 ser_obj, 878 NULL, 879 wlan_vdev_get_pdev(cmd->vdev), 880 NULL, 881 cmd->cmd_type, 882 queue_type); 883 break; 884 case WLAN_SER_CANCEL_VDEV_SCANS: 885 /* remove all scan cmds which matches the vdev object */ 886 status = wlan_serialization_cmd_cancel_handler(ser_obj, 887 NULL, NULL, 888 cmd->vdev, 889 cmd->cmd_type, 890 queue_type); 891 break; 892 case WLAN_SER_CANCEL_NON_SCAN_CMD: 893 /* remove nonscan cmd which matches the given cmd */ 894 status = wlan_serialization_cmd_cancel_handler(ser_obj, 895 cmd, 896 NULL, 897 NULL, 898 cmd->cmd_type, 899 queue_type); 900 break; 901 case WLAN_SER_CANCEL_PDEV_NON_SCAN_CMD: 902 /* remove all non scan cmds which matches the pdev object */ 903 status = wlan_serialization_cmd_cancel_handler( 904 ser_obj, 905 NULL, 906 wlan_vdev_get_pdev(cmd->vdev), 907 NULL, 908 cmd->cmd_type, 909 queue_type); 910 break; 911 case WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD: 912 /* remove all non scan cmds which matches the vdev object */ 913 status = wlan_serialization_cmd_cancel_handler(ser_obj, 914 NULL, NULL, 915 cmd->vdev, 916 cmd->cmd_type, 917 queue_type); 918 break; 919 default: 920 ser_err("Invalid request"); 921 } 922 923 error: 924 ser_exit(); 925 return status; 926 } 927