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