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