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_non_scan.c 20 * This file defines the functions which deals with 21 * serialization non scan commands. 22 */ 23 24 #include <wlan_objmgr_psoc_obj.h> 25 #include <wlan_objmgr_pdev_obj.h> 26 #include <wlan_objmgr_vdev_obj.h> 27 #include "wlan_serialization_main_i.h" 28 #include "wlan_serialization_utils_i.h" 29 #include "wlan_serialization_non_scan_i.h" 30 31 bool 32 wlan_serialization_is_non_scan_pending_queue_empty( 33 struct wlan_serialization_command *cmd) 34 { 35 struct wlan_objmgr_vdev *vdev = NULL; 36 struct wlan_ser_vdev_obj *ser_vdev_obj = NULL; 37 struct wlan_serialization_vdev_queue *vdev_q; 38 bool status = false; 39 40 vdev = wlan_serialization_get_vdev_from_cmd(cmd); 41 42 if (!vdev) { 43 ser_err("vdev object is invalid"); 44 goto error; 45 } 46 47 ser_vdev_obj = wlan_serialization_get_vdev_obj(vdev); 48 vdev_q = &ser_vdev_obj->vdev_q[SER_VDEV_QUEUE_COMP_NON_SCAN]; 49 50 if (qdf_list_empty(&vdev_q->pending_list)) 51 status = true; 52 53 error: 54 return status; 55 } 56 57 /** 58 * wlan_serialization_is_active_nonscan_cmd_allowed() - find if cmd allowed 59 * @pdev: pointer to pdev object 60 * 61 * This API will be called to find out if non scan cmd is allowed. 62 * 63 * Return: true or false 64 */ 65 66 bool 67 wlan_serialization_is_active_non_scan_cmd_allowed( 68 struct wlan_serialization_command *cmd) 69 { 70 struct wlan_serialization_pdev_queue *pdev_queue; 71 struct wlan_ser_pdev_obj *ser_pdev_obj; 72 uint32_t vdev_active_cmd_bitmap; 73 bool blocking_cmd_active = 0; 74 uint8_t blocking_cmd_waiting = 0; 75 bool status = false; 76 uint32_t vdev_id; 77 78 ser_pdev_obj = wlan_serialization_get_pdev_obj( 79 wlan_serialization_get_pdev_from_cmd(cmd)); 80 81 pdev_queue = wlan_serialization_get_pdev_queue_obj(ser_pdev_obj, 82 cmd->cmd_type); 83 84 vdev_active_cmd_bitmap = pdev_queue->vdev_active_cmd_bitmap; 85 blocking_cmd_active = pdev_queue->blocking_cmd_active; 86 blocking_cmd_waiting = pdev_queue->blocking_cmd_waiting; 87 88 /* 89 * Command is blocking 90 */ 91 if (cmd->is_blocking) { 92 /* 93 * For blocking commands, no other 94 * commands from any vdev should be active 95 */ 96 if (vdev_active_cmd_bitmap) { 97 status = false; 98 pdev_queue->blocking_cmd_waiting++; 99 } else { 100 status = true; 101 } 102 } else { 103 /* 104 * Command is non blocking 105 * For activating non blocking commands, if there any blocking 106 * commands, waiting or active, put it to pending queue 107 */ 108 if (blocking_cmd_active || blocking_cmd_waiting) { 109 status = false; 110 } else { 111 /* 112 * For non blocking command, and no blocking commands 113 * waiting or active, check if a cmd for that vdev is active 114 * If not active, put to active else pending queue 115 */ 116 vdev_id = wlan_vdev_get_id(cmd->vdev); 117 status = vdev_active_cmd_bitmap & (1 << vdev_id) 118 ? false : true; 119 } 120 } 121 return status; 122 } 123 124 enum wlan_serialization_status wlan_ser_add_non_scan_cmd( 125 struct wlan_ser_pdev_obj *ser_pdev_obj, 126 struct wlan_serialization_command_list *cmd_list, 127 uint8_t is_cmd_for_active_queue) 128 { 129 enum wlan_serialization_status pdev_status, vdev_status; 130 enum wlan_serialization_status status = WLAN_SER_CMD_DENIED_UNSPECIFIED; 131 struct wlan_serialization_command_list *pcmd_list; 132 uint8_t vdev_id; 133 struct wlan_serialization_pdev_queue *pdev_queue; 134 135 ser_debug("add non scan cmd: type[%d] id[%d] prio[%d] blocking[%d]", 136 cmd_list->cmd.cmd_type, 137 cmd_list->cmd.cmd_id, 138 cmd_list->cmd.is_high_priority, 139 cmd_list->cmd.is_blocking); 140 141 vdev_status = wlan_serialization_add_cmd_to_vdev_queue( 142 ser_pdev_obj, cmd_list, is_cmd_for_active_queue); 143 144 if (vdev_status == WLAN_SER_CMD_DENIED_LIST_FULL) { 145 status = vdev_status; 146 goto vdev_error; 147 } 148 149 if (is_cmd_for_active_queue) { 150 if (vdev_status != WLAN_SER_CMD_ACTIVE) { 151 ser_err("Failed to add to vdev active queue"); 152 QDF_ASSERT(0); 153 goto vdev_error; 154 } 155 } else { 156 if (vdev_status != WLAN_SER_CMD_PENDING) { 157 ser_err("Failed to add to vdev pending queue"); 158 QDF_ASSERT(0); 159 goto vdev_error; 160 } 161 } 162 163 pdev_status = wlan_serialization_add_cmd_to_pdev_queue( 164 ser_pdev_obj, cmd_list, is_cmd_for_active_queue); 165 166 if (pdev_status == WLAN_SER_CMD_DENIED_LIST_FULL) { 167 status = pdev_status; 168 goto pdev_error; 169 } 170 171 if (is_cmd_for_active_queue) { 172 if (pdev_status != WLAN_SER_CMD_ACTIVE) { 173 ser_err("Failed to add to pdev active queue"); 174 QDF_ASSERT(0); 175 goto pdev_error; 176 } 177 } else { 178 if (pdev_status != WLAN_SER_CMD_PENDING) { 179 ser_err("Failed to add to pdev pending queue"); 180 QDF_ASSERT(0); 181 goto pdev_error; 182 } 183 } 184 pdev_error: 185 /* 186 * If cmd added to vdev queue, but failed while 187 * adding to pdev queue, remove cmd from vdev queue as well 188 */ 189 if (pdev_status != vdev_status) { 190 wlan_serialization_remove_cmd_from_vdev_queue( 191 ser_pdev_obj, &pcmd_list, 192 &cmd_list->cmd, 193 is_cmd_for_active_queue); 194 } else { 195 status = pdev_status; 196 } 197 198 if (is_cmd_for_active_queue) { 199 pdev_queue = wlan_serialization_get_pdev_queue_obj( 200 ser_pdev_obj, cmd_list->cmd.cmd_type); 201 vdev_id = wlan_vdev_get_id(cmd_list->cmd.vdev); 202 pdev_queue->vdev_active_cmd_bitmap |= (1 << vdev_id); 203 204 if (cmd_list->cmd.is_blocking) 205 pdev_queue->blocking_cmd_active = 1; 206 } 207 208 vdev_error: 209 return status; 210 } 211 212 enum wlan_serialization_status 213 wlan_ser_move_non_scan_pending_to_active( 214 struct wlan_ser_pdev_obj *ser_pdev_obj, 215 struct wlan_objmgr_vdev *vdev, 216 bool blocking_cmd_removed) 217 { 218 struct wlan_serialization_command_list *pending_cmd_list = NULL; 219 struct wlan_serialization_command_list *active_cmd_list; 220 struct wlan_serialization_command cmd_to_remove; 221 enum wlan_serialization_status status = WLAN_SER_CMD_DENIED_UNSPECIFIED; 222 struct wlan_serialization_pdev_queue *pdev_queue; 223 struct wlan_serialization_vdev_queue *vdev_queue; 224 225 struct wlan_ser_vdev_obj *ser_vdev_obj; 226 227 qdf_list_t *pending_queue; 228 qdf_list_node_t *pending_node = NULL; 229 QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; 230 uint32_t blocking_cmd_waiting = 0; 231 uint32_t vdev_id; 232 uint32_t qsize; 233 bool vdev_cmd_active = 0; 234 bool vdev_queue_lookup = false; 235 236 pdev_queue = &ser_pdev_obj->pdev_q[SER_PDEV_QUEUE_COMP_NON_SCAN]; 237 238 ser_vdev_obj = wlan_serialization_get_vdev_obj(vdev); 239 vdev_queue = &ser_vdev_obj->vdev_q[SER_VDEV_QUEUE_COMP_NON_SCAN]; 240 241 ser_enter(); 242 243 if (!ser_pdev_obj) { 244 ser_err("Can't find ser_pdev_obj"); 245 goto error; 246 } 247 248 wlan_serialization_acquire_lock(&pdev_queue->pdev_queue_lock); 249 250 blocking_cmd_waiting = pdev_queue->blocking_cmd_waiting; 251 252 if (!blocking_cmd_removed && !blocking_cmd_waiting) { 253 pending_queue = &vdev_queue->pending_list; 254 vdev_queue_lookup = true; 255 } else { 256 pending_queue = &pdev_queue->pending_list; 257 } 258 259 qsize = wlan_serialization_list_size(pending_queue); 260 if (!qsize) { 261 wlan_serialization_release_lock( 262 &pdev_queue->pdev_queue_lock); 263 ser_debug("Pending Queue is empty"); 264 goto error; 265 } 266 267 while (qsize--) { 268 qdf_status = wlan_serialization_get_cmd_from_queue( 269 pending_queue, &pending_node); 270 if (qdf_status != QDF_STATUS_SUCCESS) { 271 ser_err("can't peek cmd"); 272 break; 273 } 274 275 if (vdev_queue_lookup) { 276 pending_cmd_list = 277 qdf_container_of( 278 pending_node, 279 struct wlan_serialization_command_list, 280 vdev_node); 281 } else { 282 pending_cmd_list = 283 qdf_container_of( 284 pending_node, 285 struct wlan_serialization_command_list, 286 pdev_node); 287 } 288 289 if (!pending_cmd_list) { 290 wlan_serialization_release_lock( 291 &pdev_queue->pdev_queue_lock); 292 ser_debug( 293 "non scan cmd cannot move frm pendin to actv"); 294 goto error; 295 } 296 297 vdev_id = wlan_vdev_get_id(pending_cmd_list->cmd.vdev); 298 vdev_cmd_active = 299 pdev_queue->vdev_active_cmd_bitmap & 300 (1 << vdev_id); 301 302 if (!vdev_queue_lookup) { 303 if (pending_cmd_list->cmd.is_blocking && 304 pdev_queue->vdev_active_cmd_bitmap) { 305 break; 306 } 307 if (vdev_cmd_active) 308 continue; 309 } else { 310 if (vdev_cmd_active) 311 break; 312 } 313 314 qdf_mem_copy(&cmd_to_remove, &pending_cmd_list->cmd, 315 sizeof(struct wlan_serialization_command)); 316 317 qdf_status = wlan_ser_remove_non_scan_cmd(ser_pdev_obj, 318 &pending_cmd_list, 319 &cmd_to_remove, 320 false); 321 322 wlan_ser_update_cmd_history( 323 pdev_queue, &pending_cmd_list->cmd, 324 SER_PENDING_TO_ACTIVE, 325 false, false); 326 327 if (QDF_STATUS_SUCCESS != qdf_status) { 328 wlan_serialization_release_lock( 329 &pdev_queue->pdev_queue_lock); 330 ser_err("Can't remove cmd from pendingQ id-%d type-%d", 331 pending_cmd_list->cmd.cmd_id, 332 pending_cmd_list->cmd.cmd_type); 333 QDF_ASSERT(0); 334 status = WLAN_SER_CMD_DENIED_UNSPECIFIED; 335 goto error; 336 } 337 338 active_cmd_list = pending_cmd_list; 339 340 status = wlan_ser_add_non_scan_cmd( 341 ser_pdev_obj, active_cmd_list, true); 342 343 if (WLAN_SER_CMD_ACTIVE != status) { 344 wlan_serialization_release_lock( 345 &pdev_queue->pdev_queue_lock); 346 ser_err("Can't move cmd to activeQ id-%d type-%d", 347 pending_cmd_list->cmd.cmd_id, 348 pending_cmd_list->cmd.cmd_type); 349 wlan_serialization_insert_back( 350 &pdev_queue->cmd_pool_list, 351 &active_cmd_list->pdev_node); 352 status = WLAN_SER_CMD_DENIED_UNSPECIFIED; 353 QDF_ASSERT(0); 354 goto error; 355 } 356 357 wlan_ser_update_cmd_history( 358 pdev_queue, &active_cmd_list->cmd, 359 SER_PENDING_TO_ACTIVE, 360 true, true); 361 362 qdf_atomic_set_bit(CMD_MARKED_FOR_ACTIVATION, 363 &active_cmd_list->cmd_in_use); 364 365 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 366 367 wlan_serialization_activate_cmd(active_cmd_list, ser_pdev_obj, 368 SER_PENDING_TO_ACTIVE); 369 370 wlan_serialization_acquire_lock(&pdev_queue->pdev_queue_lock); 371 372 if (vdev_queue_lookup) 373 break; 374 375 pending_node = NULL; 376 377 if (active_cmd_list->cmd.is_blocking) { 378 pdev_queue->blocking_cmd_waiting--; 379 break; 380 } 381 } 382 383 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 384 error: 385 ser_exit(); 386 return status; 387 } 388 389 QDF_STATUS wlan_ser_remove_non_scan_cmd( 390 struct wlan_ser_pdev_obj *ser_pdev_obj, 391 struct wlan_serialization_command_list **pcmd_list, 392 struct wlan_serialization_command *cmd, 393 uint8_t is_active_cmd) 394 { 395 QDF_STATUS pdev_status, vdev_status; 396 QDF_STATUS status = QDF_STATUS_E_FAILURE; 397 uint32_t vdev_id; 398 bool blocking_cmd_removed = 0; 399 struct wlan_serialization_pdev_queue *pdev_queue; 400 401 ser_debug("remove non scan cmd: type[%d] id[%d] prio[%d] blocking[%d]", 402 cmd->cmd_type, 403 cmd->cmd_id, 404 cmd->is_high_priority, 405 cmd->is_blocking); 406 407 vdev_status = 408 wlan_serialization_remove_cmd_from_vdev_queue(ser_pdev_obj, 409 pcmd_list, 410 cmd, 411 is_active_cmd); 412 413 if (vdev_status != QDF_STATUS_SUCCESS) { 414 ser_err("Failed to remove cmd from vdev active/pending queue"); 415 goto error; 416 } 417 418 pdev_status = 419 wlan_serialization_remove_cmd_from_pdev_queue(ser_pdev_obj, 420 pcmd_list, 421 cmd, 422 is_active_cmd); 423 424 if (pdev_status != QDF_STATUS_SUCCESS) { 425 ser_err("Failed to remove cmd from pdev active/pending queue"); 426 goto error; 427 } 428 429 if (is_active_cmd) { 430 blocking_cmd_removed = (*pcmd_list)->cmd.is_blocking; 431 pdev_queue = wlan_serialization_get_pdev_queue_obj( 432 ser_pdev_obj, (*pcmd_list)->cmd.cmd_type); 433 434 if (blocking_cmd_removed) 435 pdev_queue->blocking_cmd_active = 0; 436 437 vdev_id = wlan_vdev_get_id(cmd->vdev); 438 pdev_queue->vdev_active_cmd_bitmap &= ~(1 << vdev_id); 439 } 440 441 status = QDF_STATUS_SUCCESS; 442 443 error: 444 return status; 445 } 446 447 enum wlan_serialization_cmd_status 448 wlan_ser_cancel_non_scan_cmd( 449 struct wlan_ser_pdev_obj *ser_pdev_obj, 450 struct wlan_objmgr_pdev *pdev, struct wlan_objmgr_vdev *vdev, 451 struct wlan_serialization_command *cmd, 452 enum wlan_serialization_cmd_type cmd_type, 453 uint8_t is_active_queue) 454 { 455 qdf_list_t *pdev_queue; 456 qdf_list_t *vdev_queue; 457 struct wlan_serialization_pdev_queue *pdev_q; 458 uint32_t qsize; 459 struct wlan_serialization_command_list *cmd_list = NULL; 460 struct wlan_serialization_command cmd_bkup; 461 qdf_list_node_t *nnode = NULL, *pnode = NULL; 462 enum wlan_serialization_cmd_status status = WLAN_SER_CMD_NOT_FOUND; 463 struct wlan_objmgr_psoc *psoc = NULL; 464 QDF_STATUS qdf_status; 465 QDF_STATUS pdev_status, vdev_status; 466 struct wlan_ser_vdev_obj *ser_vdev_obj; 467 468 ser_enter(); 469 470 pdev_q = wlan_serialization_get_pdev_queue_obj(ser_pdev_obj, cmd_type); 471 472 pdev_queue = wlan_serialization_get_list_from_pdev_queue( 473 ser_pdev_obj, cmd_type, is_active_queue); 474 475 if (pdev) 476 psoc = wlan_pdev_get_psoc(pdev); 477 else if (vdev) 478 psoc = wlan_vdev_get_psoc(vdev); 479 else if (cmd && cmd->vdev) 480 psoc = wlan_vdev_get_psoc(cmd->vdev); 481 else 482 ser_debug("Can't find psoc"); 483 484 wlan_serialization_acquire_lock(&pdev_q->pdev_queue_lock); 485 486 qsize = wlan_serialization_list_size(pdev_queue); 487 while (!wlan_serialization_list_empty(pdev_queue) && qsize--) { 488 if (wlan_serialization_get_cmd_from_queue(pdev_queue, &nnode) 489 != QDF_STATUS_SUCCESS) { 490 ser_err("can't read cmd from queue"); 491 status = WLAN_SER_CMD_NOT_FOUND; 492 break; 493 } 494 cmd_list = 495 qdf_container_of(nnode, 496 struct wlan_serialization_command_list, 497 pdev_node); 498 if (cmd && !wlan_serialization_match_cmd_id_type( 499 nnode, cmd, 500 WLAN_SER_PDEV_NODE)) { 501 pnode = nnode; 502 continue; 503 } 504 505 if (vdev && 506 !wlan_serialization_match_cmd_vdev(nnode, 507 vdev, 508 WLAN_SER_PDEV_NODE)) { 509 pnode = nnode; 510 continue; 511 } 512 513 if (pdev && 514 !wlan_serialization_match_cmd_pdev(nnode, 515 pdev, 516 WLAN_SER_PDEV_NODE)) { 517 pnode = nnode; 518 continue; 519 } 520 521 if (cmd_type > WLAN_SER_CMD_NONSCAN && vdev && 522 (!wlan_serialization_match_cmd_type(nnode, cmd_type, 523 WLAN_SER_PDEV_NODE) || 524 !wlan_serialization_match_cmd_vdev(nnode, vdev, 525 WLAN_SER_PDEV_NODE))) { 526 pnode = nnode; 527 continue; 528 } 529 530 /* 531 * active queue can't be removed directly, requester needs to 532 * wait for active command response and send remove request for 533 * active command separately 534 */ 535 if (is_active_queue) { 536 if (!psoc || !cmd_list) { 537 ser_err("psoc:0x%pK, cmd_list:0x%pK", 538 psoc, cmd_list); 539 status = WLAN_SER_CMD_NOT_FOUND; 540 break; 541 } 542 543 /* Cancel request received for a cmd in active 544 * queue which has not been activated yet, we mark 545 * it as CMD_ACTIVE_MARKED_FOR_CANCEL and remove 546 * the cmd after activation 547 */ 548 if (qdf_atomic_test_bit(CMD_MARKED_FOR_ACTIVATION, 549 &cmd_list->cmd_in_use)) { 550 qdf_atomic_set_bit(CMD_ACTIVE_MARKED_FOR_CANCEL, 551 &cmd_list->cmd_in_use); 552 status = WLAN_SER_CMD_MARKED_FOR_ACTIVATION; 553 continue; 554 } 555 556 qdf_status = wlan_serialization_find_and_stop_timer( 557 psoc, &cmd_list->cmd); 558 if (QDF_IS_STATUS_ERROR(qdf_status)) { 559 ser_err("Can't find timer for active cmd"); 560 status = WLAN_SER_CMD_NOT_FOUND; 561 /* 562 * This should not happen, as an active command 563 * should always have the timer. 564 */ 565 QDF_BUG(0); 566 break; 567 } 568 569 status = WLAN_SER_CMD_IN_ACTIVE_LIST; 570 } 571 572 qdf_mem_copy(&cmd_bkup, &cmd_list->cmd, 573 sizeof(struct wlan_serialization_command)); 574 575 pdev_status = 576 wlan_serialization_remove_node(pdev_queue, 577 &cmd_list->pdev_node); 578 579 ser_vdev_obj = wlan_serialization_get_vdev_obj( 580 cmd_list->cmd.vdev); 581 582 vdev_queue = wlan_serialization_get_list_from_vdev_queue( 583 ser_vdev_obj, cmd_type, is_active_queue); 584 585 vdev_status = 586 wlan_serialization_remove_node(vdev_queue, 587 &cmd_list->vdev_node); 588 589 if (pdev_status != QDF_STATUS_SUCCESS || 590 vdev_status != QDF_STATUS_SUCCESS) { 591 ser_err("can't remove cmd from pdev/vdev queue"); 592 status = WLAN_SER_CMD_NOT_FOUND; 593 break; 594 } 595 596 qdf_mem_zero(&cmd_list->cmd, 597 sizeof(struct wlan_serialization_command)); 598 cmd_list->cmd_in_use = 0; 599 qdf_status = wlan_serialization_insert_back( 600 &pdev_q->cmd_pool_list, 601 &cmd_list->pdev_node); 602 603 if (QDF_STATUS_SUCCESS != qdf_status) { 604 ser_err("can't remove cmd from queue"); 605 status = WLAN_SER_CMD_NOT_FOUND; 606 break; 607 } 608 nnode = pnode; 609 610 wlan_ser_update_cmd_history(pdev_q, &cmd_bkup, 611 SER_CANCEL, false, is_active_queue); 612 613 wlan_serialization_release_lock(&pdev_q->pdev_queue_lock); 614 /* 615 * call pending cmd's callback to notify that 616 * it is being removed 617 */ 618 if (cmd_bkup.cmd_cb) { 619 /* caller should now do necessary clean up */ 620 ser_debug("cmd cb: type[%d] id[%d]", 621 cmd_bkup.cmd_type, 622 cmd_bkup.cmd_id); 623 ser_debug("reason: WLAN_SER_CB_CANCEL_CMD"); 624 cmd_bkup.cmd_cb(&cmd_bkup, 625 WLAN_SER_CB_CANCEL_CMD); 626 /* caller should release the memory */ 627 ser_debug("reason: WLAN_SER_CB_RELEASE_MEM_CMD"); 628 cmd_bkup.cmd_cb(&cmd_bkup, 629 WLAN_SER_CB_RELEASE_MEM_CMD); 630 } 631 632 wlan_serialization_acquire_lock(&pdev_q->pdev_queue_lock); 633 634 if (is_active_queue) { 635 if (cmd_bkup.is_blocking) 636 pdev_q->blocking_cmd_active = 0; 637 pdev_q->vdev_active_cmd_bitmap &= 638 ~(1 << wlan_vdev_get_id(cmd_bkup.vdev)); 639 } else { 640 if (cmd_bkup.is_blocking) 641 pdev_q->blocking_cmd_waiting--; 642 643 status = WLAN_SER_CMD_IN_PENDING_LIST; 644 } 645 646 647 if (!vdev && !pdev) 648 break; 649 } 650 651 wlan_serialization_release_lock(&pdev_q->pdev_queue_lock); 652 653 ser_exit(); 654 return status; 655 } 656