1 /* 2 * Copyright (c) 2017-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 * 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 /* Call cmd cb for remove request*/ 517 if (cmd_bkup.cmd_cb) { 518 /* caller should release the memory */ 519 ser_debug("Release memory for type %d id %d", 520 cmd_bkup.cmd_type, cmd_bkup.cmd_id); 521 cmd_bkup.cmd_cb(&cmd_bkup, 522 WLAN_SER_CB_RELEASE_MEM_CMD); 523 } 524 525 if (active_cmd) { 526 ser_status = wlan_serialization_move_pending_to_active( 527 cmd_bkup.cmd_type, ser_pdev_obj, 528 cmd_bkup.vdev, 529 blocking_cmd_removed); 530 } 531 532 if (active_cmd) 533 status = WLAN_SER_CMD_IN_ACTIVE_LIST; 534 else 535 status = WLAN_SER_CMD_IN_PENDING_LIST; 536 537 error: 538 return status; 539 } 540 541 void wlan_serialization_generic_timer_cb(void *arg) 542 { 543 struct wlan_serialization_timer *timer = arg; 544 struct wlan_serialization_command *cmd = timer->cmd; 545 struct wlan_objmgr_vdev *vdev = NULL; 546 enum wlan_serialization_cmd_status status; 547 548 549 if (!cmd) { 550 ser_err("Command not found"); 551 return; 552 } 553 554 vdev = cmd->vdev; 555 if (!vdev) { 556 ser_err("Invalid vdev"); 557 return; 558 } 559 560 ser_err("Active cmd timeout for cmd_type[%d] vdev[%d]", 561 cmd->cmd_type, wlan_vdev_get_id(cmd->vdev)); 562 563 if (cmd->cmd_cb) 564 cmd->cmd_cb(cmd, WLAN_SER_CB_ACTIVE_CMD_TIMEOUT); 565 566 /* 567 * dequeue cmd API will cleanup and destroy the timer. If it fails to 568 * dequeue command then we have to destroy the timer. 569 */ 570 status = wlan_serialization_dequeue_cmd(cmd, SER_TIMEOUT, true); 571 572 /* Release the ref taken before the timer was started */ 573 if (status == WLAN_SER_CMD_IN_ACTIVE_LIST) 574 wlan_objmgr_vdev_release_ref(vdev, WLAN_SERIALIZATION_ID); 575 } 576 577 static QDF_STATUS wlan_serialization_mc_flush_noop(struct scheduler_msg *msg) 578 { 579 return QDF_STATUS_SUCCESS; 580 } 581 582 static void 583 wlan_serialization_timer_cb_mc_ctx(void *arg) 584 { 585 struct scheduler_msg msg = {0}; 586 587 msg.type = SYS_MSG_ID_MC_TIMER; 588 msg.reserved = SYS_MSG_COOKIE; 589 590 /* msg.callback will explicitly cast back to qdf_mc_timer_callback_t 591 * in scheduler_timer_q_mq_handler. 592 * but in future we do not want to introduce more this kind of 593 * typecast by properly using QDF MC timer for MCC from get go in 594 * common code. 595 */ 596 msg.callback = 597 (scheduler_msg_process_fn_t)wlan_serialization_generic_timer_cb; 598 msg.bodyptr = arg; 599 msg.bodyval = 0; 600 msg.flush_callback = wlan_serialization_mc_flush_noop; 601 602 if (scheduler_post_message(QDF_MODULE_ID_SERIALIZATION, 603 QDF_MODULE_ID_SERIALIZATION, 604 QDF_MODULE_ID_SYS, &msg) == 605 QDF_STATUS_SUCCESS) 606 return; 607 608 ser_err("Could not enqueue timer to timer queue"); 609 } 610 611 static void wlan_serialization_timer_handler(void *arg) 612 { 613 struct wlan_serialization_timer *timer = arg; 614 struct wlan_serialization_command *cmd = timer->cmd; 615 616 if (!cmd) { 617 ser_err("Command not found"); 618 return; 619 } 620 621 ser_err("Active cmd timeout for cmd_type %d vdev %d", 622 cmd->cmd_type, wlan_vdev_get_id(cmd->vdev)); 623 624 wlan_serialization_timer_cb_mc_ctx(arg); 625 626 } 627 628 QDF_STATUS 629 wlan_serialization_find_and_update_timer( 630 struct wlan_objmgr_psoc *psoc, 631 struct wlan_serialization_command *cmd) 632 { 633 struct wlan_ser_psoc_obj *psoc_ser_obj; 634 struct wlan_serialization_timer *ser_timer; 635 QDF_STATUS status = QDF_STATUS_E_FAILURE; 636 int i = 0; 637 638 if (!psoc || !cmd) { 639 ser_err("invalid param"); 640 goto exit; 641 } 642 643 psoc_ser_obj = wlan_serialization_get_psoc_obj(psoc); 644 /* 645 * Here cmd_id and cmd_type are used to locate the timer being 646 * associated with command. 647 */ 648 wlan_serialization_acquire_lock(&psoc_ser_obj->timer_lock); 649 650 for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) { 651 ser_timer = &psoc_ser_obj->timers[i]; 652 if (!(ser_timer->cmd) || 653 (ser_timer->cmd->cmd_id != cmd->cmd_id) || 654 (ser_timer->cmd->cmd_type != cmd->cmd_type) || 655 (ser_timer->cmd->vdev != cmd->vdev)) 656 continue; 657 658 qdf_timer_mod(&ser_timer->timer, 659 cmd->cmd_timeout_duration); 660 status = QDF_STATUS_SUCCESS; 661 break; 662 } 663 664 wlan_serialization_release_lock(&psoc_ser_obj->timer_lock); 665 666 if (QDF_IS_STATUS_ERROR(status)) 667 ser_debug("Can't find timer for cmd_type %d", cmd->cmd_type); 668 669 exit: 670 return status; 671 } 672 673 QDF_STATUS 674 wlan_serialization_find_and_stop_timer(struct wlan_objmgr_psoc *psoc, 675 struct wlan_serialization_command *cmd, 676 enum ser_queue_reason ser_reason) 677 { 678 struct wlan_ser_psoc_obj *psoc_ser_obj; 679 struct wlan_serialization_timer *ser_timer; 680 QDF_STATUS status = QDF_STATUS_E_FAILURE; 681 int i = 0; 682 uint32_t phy_version; 683 struct wlan_objmgr_vdev *vdev; 684 685 if (!psoc || !cmd) { 686 ser_err("invalid param"); 687 goto exit; 688 } 689 690 if (cmd->cmd_timeout_duration == 0) { 691 phy_version = wlan_psoc_get_nif_phy_version(psoc); 692 if (wlan_is_emulation_platform(phy_version)) { 693 ser_err("[SCAN-EMULATION]: Not performing timer funcs"); 694 status = QDF_STATUS_SUCCESS; 695 goto exit; 696 } 697 } 698 699 psoc_ser_obj = wlan_serialization_get_psoc_obj(psoc); 700 /* 701 * Here cmd_id and cmd_type are used to locate the timer being 702 * associated with command. 703 */ 704 wlan_serialization_acquire_lock(&psoc_ser_obj->timer_lock); 705 706 for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) { 707 ser_timer = &psoc_ser_obj->timers[i]; 708 if (!(ser_timer->cmd) || 709 (ser_timer->cmd->cmd_id != cmd->cmd_id) || 710 (ser_timer->cmd->cmd_type != cmd->cmd_type) || 711 (ser_timer->cmd->vdev != cmd->vdev)) 712 continue; 713 714 vdev = ser_timer->cmd->vdev; 715 status = wlan_serialization_stop_timer(ser_timer); 716 /* 717 * Release the vdev reference when the active cmd is removed 718 * through remove/cancel request. 719 * 720 * In case the command removal is because of timer expiry, 721 * the vdev is released when the timer handler completes. 722 */ 723 if (vdev && ser_reason != SER_TIMEOUT) 724 wlan_objmgr_vdev_release_ref( 725 vdev, WLAN_SERIALIZATION_ID); 726 727 break; 728 729 } 730 731 wlan_serialization_release_lock(&psoc_ser_obj->timer_lock); 732 733 if (QDF_IS_STATUS_ERROR(status)) 734 ser_err("Can't find timer for cmd_type %d cmd id %d", 735 cmd->cmd_type, cmd->cmd_id); 736 737 exit: 738 return status; 739 } 740 741 QDF_STATUS 742 wlan_serialization_find_and_start_timer(struct wlan_objmgr_psoc *psoc, 743 struct wlan_serialization_command *cmd, 744 enum ser_queue_reason ser_reason) 745 { 746 QDF_STATUS status = QDF_STATUS_E_FAILURE; 747 struct wlan_ser_psoc_obj *psoc_ser_obj; 748 struct wlan_serialization_timer *ser_timer; 749 int i = 0; 750 uint32_t nif_phy_ver; 751 752 if (!psoc || !cmd) { 753 ser_err("invalid param"); 754 goto error; 755 } 756 757 nif_phy_ver = wlan_psoc_get_nif_phy_version(psoc); 758 if ((cmd->cmd_timeout_duration == 0) && 759 (wlan_is_emulation_platform(nif_phy_ver))) { 760 ser_err("[SCAN-EMULATION]: Not performing timer functions\n"); 761 status = QDF_STATUS_SUCCESS; 762 goto error; 763 } 764 765 psoc_ser_obj = wlan_serialization_get_psoc_obj(psoc); 766 767 wlan_serialization_acquire_lock(&psoc_ser_obj->timer_lock); 768 769 for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) { 770 /* Keep trying timer */ 771 ser_timer = &psoc_ser_obj->timers[i]; 772 if (ser_timer->cmd) 773 continue; 774 775 /* Remember timer is pointing to command */ 776 ser_timer->cmd = cmd; 777 status = QDF_STATUS_SUCCESS; 778 779 /* 780 * Get vdev reference before starting the timer 781 * Remove the reference before removing the command 782 * in any one of the cases: 783 * 1. Active command is removed through remove/cancel request 784 * 2. Timer expiry handler is completed. 785 */ 786 787 status = wlan_objmgr_vdev_try_get_ref(ser_timer->cmd->vdev, 788 WLAN_SERIALIZATION_ID); 789 if (QDF_IS_STATUS_ERROR(status)) { 790 /* 791 * Set cmd to null so that ref release is not tried for 792 * vdev when timer is flushed. 793 */ 794 ser_timer->cmd = NULL; 795 wlan_serialization_release_lock( 796 &psoc_ser_obj->timer_lock); 797 ser_err("Unbale to get vdev reference"); 798 status = QDF_STATUS_E_FAILURE; 799 goto error; 800 } 801 break; 802 } 803 804 wlan_serialization_release_lock(&psoc_ser_obj->timer_lock); 805 806 if (QDF_IS_STATUS_SUCCESS(status)) { 807 qdf_timer_init(NULL, &ser_timer->timer, 808 wlan_serialization_timer_handler, 809 ser_timer, QDF_TIMER_TYPE_SW); 810 qdf_timer_mod(&ser_timer->timer, cmd->cmd_timeout_duration); 811 } else { 812 ser_err("Failed to start timer for cmd: type[%d] id[%d] high_priority[%d] blocking[%d]", 813 cmd->cmd_type, cmd->cmd_id, cmd->is_high_priority, 814 cmd->is_blocking); 815 } 816 817 error: 818 return status; 819 } 820 821 enum wlan_serialization_cmd_status 822 wlan_serialization_cmd_cancel_handler( 823 struct wlan_ser_pdev_obj *ser_obj, 824 struct wlan_serialization_command *cmd, 825 struct wlan_objmgr_pdev *pdev, struct wlan_objmgr_vdev *vdev, 826 enum wlan_serialization_cmd_type cmd_type, uint8_t queue_type, 827 enum wlan_ser_cmd_attr cmd_attr) 828 { 829 enum wlan_serialization_cmd_status active_status = 830 WLAN_SER_CMD_NOT_FOUND; 831 enum wlan_serialization_cmd_status pending_status = 832 WLAN_SER_CMD_NOT_FOUND; 833 enum wlan_serialization_cmd_status status = 834 WLAN_SER_CMD_NOT_FOUND; 835 836 if (!ser_obj) { 837 ser_err("invalid serial object"); 838 goto error; 839 } 840 841 if (queue_type & WLAN_SERIALIZATION_ACTIVE_QUEUE) { 842 if (cmd_type < WLAN_SER_CMD_NONSCAN) 843 active_status = wlan_ser_cancel_scan_cmd( 844 ser_obj, pdev, vdev, cmd, 845 cmd_type, true); 846 else 847 active_status = wlan_ser_cancel_non_scan_cmd( 848 ser_obj, pdev, vdev, cmd, 849 cmd_type, true, cmd_attr); 850 } 851 852 if (queue_type & WLAN_SERIALIZATION_PENDING_QUEUE) { 853 if (cmd_type < WLAN_SER_CMD_NONSCAN) 854 pending_status = wlan_ser_cancel_scan_cmd( 855 ser_obj, pdev, vdev, cmd, 856 cmd_type, false); 857 else 858 pending_status = wlan_ser_cancel_non_scan_cmd( 859 ser_obj, pdev, vdev, cmd, 860 cmd_type, false, cmd_attr); 861 } 862 863 if (active_status == WLAN_SER_CMD_IN_ACTIVE_LIST && 864 pending_status == WLAN_SER_CMD_IN_PENDING_LIST) 865 status = WLAN_SER_CMDS_IN_ALL_LISTS; 866 else if (active_status == WLAN_SER_CMD_IN_ACTIVE_LIST) 867 status = active_status; 868 else if (pending_status == WLAN_SER_CMD_IN_PENDING_LIST) 869 status = pending_status; 870 871 error: 872 return status; 873 } 874 875 enum wlan_serialization_cmd_status 876 wlan_serialization_find_and_cancel_cmd( 877 struct wlan_serialization_command *cmd, 878 enum wlan_serialization_cancel_type req_type, 879 uint8_t queue_type) 880 { 881 enum wlan_serialization_cmd_status status = WLAN_SER_CMD_NOT_FOUND; 882 struct wlan_ser_pdev_obj *ser_obj = NULL; 883 struct wlan_objmgr_pdev *pdev; 884 885 if (!cmd) { 886 ser_err("Invalid cmd"); 887 goto error; 888 } 889 890 pdev = wlan_serialization_get_pdev_from_cmd(cmd); 891 if (!pdev) { 892 ser_err("Invalid pdev"); 893 goto error; 894 } 895 ser_obj = wlan_serialization_get_pdev_obj(pdev); 896 if (!ser_obj) { 897 ser_err("Invalid ser_obj"); 898 goto error; 899 } 900 901 switch (req_type) { 902 case WLAN_SER_CANCEL_SINGLE_SCAN: 903 /* remove scan cmd which matches the given cmd struct */ 904 status = wlan_serialization_cmd_cancel_handler( 905 ser_obj, cmd, NULL, NULL, 906 WLAN_SER_CMD_SCAN, queue_type, 907 WLAN_SER_CMD_ATTR_NONE); 908 break; 909 case WLAN_SER_CANCEL_PDEV_SCANS: 910 /* remove all scan cmds which matches the pdev object */ 911 status = wlan_serialization_cmd_cancel_handler( 912 ser_obj, NULL, pdev, NULL, 913 WLAN_SER_CMD_SCAN, queue_type, 914 WLAN_SER_CMD_ATTR_NONE); 915 break; 916 case WLAN_SER_CANCEL_VDEV_SCANS: 917 case WLAN_SER_CANCEL_VDEV_HOST_SCANS: 918 /* remove all scan cmds which matches the vdev object */ 919 status = wlan_serialization_cmd_cancel_handler( 920 ser_obj, NULL, NULL, cmd->vdev, 921 WLAN_SER_CMD_SCAN, queue_type, 922 WLAN_SER_CMD_ATTR_NONE); 923 break; 924 case WLAN_SER_CANCEL_NON_SCAN_CMD: 925 /* remove nonscan cmd which matches the given cmd */ 926 status = wlan_serialization_cmd_cancel_handler( 927 ser_obj, cmd, NULL, NULL, 928 WLAN_SER_CMD_NONSCAN, queue_type, 929 WLAN_SER_CMD_ATTR_NONE); 930 break; 931 case WLAN_SER_CANCEL_PDEV_NON_SCAN_CMD: 932 /* remove all non scan cmds which matches the pdev object */ 933 status = wlan_serialization_cmd_cancel_handler( 934 ser_obj, NULL, pdev, NULL, 935 WLAN_SER_CMD_NONSCAN, queue_type, 936 WLAN_SER_CMD_ATTR_NONE); 937 break; 938 case WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD: 939 /* remove all non scan cmds which matches the vdev object */ 940 status = wlan_serialization_cmd_cancel_handler( 941 ser_obj, NULL, NULL, cmd->vdev, 942 WLAN_SER_CMD_NONSCAN, queue_type, 943 WLAN_SER_CMD_ATTR_NONE); 944 break; 945 case WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD_TYPE: 946 /* 947 * remove all non scan cmds which matches the vdev 948 * and given cmd type 949 */ 950 status = wlan_serialization_cmd_cancel_handler( 951 ser_obj, NULL, NULL, cmd->vdev, 952 cmd->cmd_type, queue_type, 953 WLAN_SER_CMD_ATTR_NONE); 954 break; 955 case WLAN_SER_CANCEL_VDEV_NON_SCAN_NB_CMD: 956 /* 957 * remove all non-blocking non-scan cmds which matches the given 958 * vdev 959 */ 960 status = wlan_serialization_cmd_cancel_handler( 961 ser_obj, NULL, NULL, cmd->vdev, 962 WLAN_SER_CMD_NONSCAN, queue_type, 963 WLAN_SER_CMD_ATTR_NONBLOCK); 964 break; 965 default: 966 ser_err("Invalid request"); 967 } 968 969 error: 970 971 return status; 972 } 973