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