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 /** 20 * DOC: wlan_serialization_api.c 21 * This file provides an interface for the external components 22 * to utilize the services provided by the serialization 23 * component. 24 */ 25 26 #include <wlan_objmgr_psoc_obj.h> 27 #include <wlan_objmgr_pdev_obj.h> 28 #include <wlan_objmgr_vdev_obj.h> 29 #include "wlan_serialization_main_i.h" 30 #include "wlan_serialization_utils_i.h" 31 #include "wlan_serialization_queue_i.h" 32 #include "wlan_serialization_scan_i.h" 33 #include "wlan_serialization_internal_i.h" 34 35 bool wlan_serialization_is_cmd_present_in_pending_queue( 36 struct wlan_objmgr_psoc *psoc, 37 struct wlan_serialization_command *cmd) 38 { 39 bool status = false; 40 41 if (!cmd) { 42 ser_err("invalid cmd"); 43 goto error; 44 } 45 46 status = wlan_serialization_is_cmd_present_queue(cmd, false); 47 48 error: 49 return status; 50 } 51 52 bool wlan_serialization_is_cmd_present_in_active_queue( 53 struct wlan_objmgr_psoc *psoc, 54 struct wlan_serialization_command *cmd) 55 { 56 bool status; 57 58 if (!cmd) { 59 ser_err("invalid cmd"); 60 status = false; 61 goto error; 62 } 63 64 status = wlan_serialization_is_cmd_present_queue(cmd, true); 65 66 ser_debug("Cmd type:%d id:%d present: %d", 67 cmd->cmd_type, cmd->cmd_id, status); 68 69 error: 70 return status; 71 } 72 73 QDF_STATUS 74 wlan_serialization_register_apply_rules_cb( 75 struct wlan_objmgr_psoc *psoc, 76 enum wlan_serialization_cmd_type cmd_type, 77 wlan_serialization_apply_rules_cb cb) 78 { 79 struct wlan_ser_psoc_obj *ser_soc_obj; 80 QDF_STATUS status; 81 82 status = wlan_serialization_validate_cmdtype(cmd_type); 83 if (QDF_IS_STATUS_ERROR(status)) { 84 ser_err("invalid cmd_type %d", cmd_type); 85 goto error; 86 } 87 88 ser_soc_obj = wlan_serialization_get_psoc_obj(psoc); 89 if (!ser_soc_obj) { 90 ser_err("invalid ser_soc_obj"); 91 status = QDF_STATUS_E_FAILURE; 92 goto error; 93 } 94 95 ser_soc_obj->apply_rules_cb[cmd_type] = cb; 96 status = QDF_STATUS_SUCCESS; 97 98 error: 99 return status; 100 } 101 102 QDF_STATUS 103 wlan_serialization_deregister_apply_rules_cb( 104 struct wlan_objmgr_psoc *psoc, 105 enum wlan_serialization_cmd_type cmd_type) 106 { 107 struct wlan_ser_psoc_obj *ser_soc_obj; 108 QDF_STATUS status; 109 110 status = wlan_serialization_validate_cmdtype(cmd_type); 111 if (QDF_IS_STATUS_ERROR(status)) { 112 ser_err("invalid cmd_type %d", cmd_type); 113 goto error; 114 } 115 ser_soc_obj = wlan_serialization_get_psoc_obj(psoc); 116 if (!ser_soc_obj) { 117 ser_err("invalid ser_soc_obj"); 118 status = QDF_STATUS_E_FAILURE; 119 goto error; 120 } 121 ser_soc_obj->apply_rules_cb[cmd_type] = NULL; 122 status = QDF_STATUS_SUCCESS; 123 124 error: 125 return status; 126 } 127 128 QDF_STATUS 129 wlan_serialization_register_comp_info_cb( 130 struct wlan_objmgr_psoc *psoc, 131 enum wlan_umac_comp_id comp_id, 132 enum wlan_serialization_cmd_type cmd_type, 133 wlan_serialization_comp_info_cb cb) 134 { 135 struct wlan_ser_psoc_obj *ser_soc_obj; 136 QDF_STATUS status; 137 138 status = wlan_serialization_validate_cmd(comp_id, cmd_type); 139 if (QDF_IS_STATUS_ERROR(status)) { 140 ser_err("invalid comp_id %d or cmd_type %d", 141 comp_id, cmd_type); 142 goto error; 143 } 144 ser_soc_obj = wlan_serialization_get_psoc_obj(psoc); 145 if (!ser_soc_obj) { 146 ser_err("invalid ser_soc_obj"); 147 status = QDF_STATUS_E_FAILURE; 148 goto error; 149 } 150 ser_soc_obj->comp_info_cb[cmd_type][comp_id] = cb; 151 status = QDF_STATUS_SUCCESS; 152 153 error: 154 return status; 155 } 156 157 QDF_STATUS 158 wlan_serialization_deregister_comp_info_cb(struct wlan_objmgr_psoc *psoc, 159 enum wlan_umac_comp_id comp_id, 160 enum wlan_serialization_cmd_type cmd_type) 161 { 162 struct wlan_ser_psoc_obj *ser_soc_obj; 163 QDF_STATUS status; 164 165 status = wlan_serialization_validate_cmd(comp_id, cmd_type); 166 if (QDF_IS_STATUS_ERROR(status)) { 167 ser_err("invalid comp_id %d or cmd_type %d", 168 comp_id, cmd_type); 169 goto error; 170 } 171 ser_soc_obj = wlan_serialization_get_psoc_obj(psoc); 172 if (!ser_soc_obj) { 173 ser_err("invalid ser_soc_obj"); 174 status = QDF_STATUS_E_FAILURE; 175 goto error; 176 } 177 ser_soc_obj->comp_info_cb[cmd_type][comp_id] = NULL; 178 status = QDF_STATUS_SUCCESS; 179 180 error: 181 return status; 182 } 183 184 enum wlan_serialization_cmd_status 185 wlan_serialization_non_scan_cmd_status( 186 struct wlan_objmgr_pdev *pdev, 187 enum wlan_serialization_cmd_type cmd_type) 188 { 189 bool cmd_in_active = 0; 190 bool cmd_in_pending = 0; 191 struct wlan_ser_pdev_obj *ser_pdev_obj = 192 wlan_serialization_get_pdev_obj(pdev); 193 enum wlan_serialization_cmd_status cmd_status = WLAN_SER_CMD_NOT_FOUND; 194 struct wlan_serialization_pdev_queue *pdev_q; 195 qdf_list_node_t *node = NULL; 196 qdf_list_t *queue = NULL; 197 198 ser_enter(); 199 200 pdev_q = &ser_pdev_obj->pdev_q[SER_PDEV_QUEUE_COMP_NON_SCAN]; 201 202 /* Look in the pdev non scan active queue */ 203 queue = &pdev_q->active_list; 204 205 wlan_serialization_acquire_lock(&pdev_q->pdev_queue_lock); 206 207 node = wlan_serialization_find_cmd( 208 queue, WLAN_SER_MATCH_CMD_TYPE, 209 NULL, cmd_type, NULL, NULL, WLAN_SER_PDEV_NODE); 210 211 if (node) 212 cmd_in_active = true; 213 214 node = NULL; 215 216 /* Look in the pdev non scan pending queue */ 217 queue = &pdev_q->pending_list; 218 219 node = wlan_serialization_find_cmd( 220 queue, WLAN_SER_MATCH_CMD_TYPE, 221 NULL, cmd_type, NULL, NULL, WLAN_SER_PDEV_NODE); 222 223 if (node) 224 cmd_in_pending = true; 225 226 cmd_status = wlan_serialization_is_cmd_in_active_pending( 227 cmd_in_active, cmd_in_pending); 228 229 wlan_serialization_release_lock(&pdev_q->pdev_queue_lock); 230 231 ser_exit(); 232 return cmd_status; 233 } 234 235 enum wlan_serialization_cmd_status 236 wlan_serialization_cancel_request( 237 struct wlan_serialization_queued_cmd_info *req) 238 { 239 QDF_STATUS status; 240 enum wlan_serialization_cmd_status cmd_status; 241 242 struct wlan_serialization_command cmd; 243 struct wlan_objmgr_pdev *pdev; 244 struct wlan_ser_pdev_obj *ser_pdev_obj; 245 struct wlan_serialization_pdev_queue *pdev_queue; 246 247 ser_enter(); 248 249 if (!req) { 250 ser_err("given request is empty"); 251 cmd_status = WLAN_SER_CMD_NOT_FOUND; 252 goto error; 253 } 254 255 status = wlan_serialization_validate_cmd(req->requestor, req->cmd_type); 256 if (QDF_IS_STATUS_ERROR(status)) { 257 ser_err("req is not valid"); 258 cmd_status = WLAN_SER_CMD_NOT_FOUND; 259 goto error; 260 } 261 262 cmd.cmd_type = req->cmd_type; 263 cmd.cmd_id = req->cmd_id; 264 cmd.source = req->requestor; 265 cmd.vdev = req->vdev; 266 267 pdev = wlan_serialization_get_pdev_from_cmd(&cmd); 268 if (!pdev) { 269 ser_err("pdev is invalid"); 270 cmd_status = WLAN_SER_CMD_NOT_FOUND; 271 goto error; 272 } 273 274 ser_pdev_obj = wlan_serialization_get_pdev_obj(pdev); 275 276 pdev_queue = wlan_serialization_get_pdev_queue_obj(ser_pdev_obj, 277 cmd.cmd_type); 278 279 if (!pdev_queue) { 280 ser_err("pdev_queue is invalid"); 281 cmd_status = WLAN_SER_CMD_NOT_FOUND; 282 goto error; 283 } 284 285 cmd_status = wlan_serialization_find_and_cancel_cmd( 286 &cmd, req->req_type, req->queue_type); 287 288 error: 289 ser_exit(); 290 return cmd_status; 291 } 292 293 void wlan_serialization_remove_cmd( 294 struct wlan_serialization_queued_cmd_info *cmd_info) 295 { 296 QDF_STATUS status; 297 struct wlan_serialization_command cmd = {0}; 298 299 ser_enter(); 300 301 if (!cmd_info) { 302 ser_err("given request is empty"); 303 QDF_ASSERT(0); 304 return; 305 } 306 status = wlan_serialization_validate_cmd(cmd_info->requestor, 307 cmd_info->cmd_type); 308 if (QDF_IS_STATUS_ERROR(status)) { 309 ser_err("cmd is not valid"); 310 QDF_ASSERT(0); 311 goto error; 312 } 313 314 cmd.cmd_type = cmd_info->cmd_type; 315 cmd.cmd_id = cmd_info->cmd_id; 316 cmd.source = cmd_info->requestor; 317 cmd.vdev = cmd_info->vdev; 318 319 if (wlan_serialization_dequeue_cmd(&cmd, SER_REMOVE, true) != 320 WLAN_SER_CMD_IN_ACTIVE_LIST) { 321 ser_err("Can't dequeue requested cmd_id[%d] type[%d]", 322 cmd.cmd_id, cmd.cmd_type); 323 } 324 325 error: 326 ser_exit(); 327 } 328 329 enum wlan_serialization_status 330 wlan_serialization_request(struct wlan_serialization_command *cmd) 331 { 332 QDF_STATUS status; 333 enum wlan_serialization_status serialization_status; 334 uint8_t comp_id; 335 struct wlan_ser_psoc_obj *ser_soc_obj; 336 union wlan_serialization_rules_info info; 337 struct wlan_objmgr_psoc *psoc; 338 339 ser_enter(); 340 341 serialization_status = WLAN_SER_CMD_DENIED_UNSPECIFIED; 342 343 if (!cmd) { 344 ser_err("serialization cmd is null"); 345 goto error; 346 } 347 status = wlan_serialization_validate_cmd(cmd->source, cmd->cmd_type); 348 if (QDF_IS_STATUS_ERROR(status)) { 349 ser_err("cmd is not valid"); 350 goto error; 351 } 352 353 psoc = wlan_serialization_get_psoc_from_cmd(cmd); 354 if (!psoc) { 355 ser_err("psoc _obj is invalid"); 356 return WLAN_SER_CMD_DENIED_UNSPECIFIED; 357 } 358 ser_soc_obj = wlan_serialization_get_psoc_obj(psoc); 359 360 if (!ser_soc_obj) { 361 ser_err("ser_soc_obj is invalid"); 362 return WLAN_SER_CMD_DENIED_UNSPECIFIED; 363 } 364 365 /* 366 * Get Component Info callback by calling 367 * each registered module 368 */ 369 for (comp_id = 0; comp_id < WLAN_UMAC_COMP_ID_MAX; comp_id++) { 370 if (!ser_soc_obj->comp_info_cb[cmd->cmd_type][comp_id]) 371 continue; 372 ser_soc_obj->comp_info_cb[cmd->cmd_type][comp_id](cmd->vdev, 373 &info); 374 if (!ser_soc_obj->apply_rules_cb[cmd->cmd_type]) 375 continue; 376 if (!ser_soc_obj->apply_rules_cb[cmd->cmd_type](&info, comp_id)) 377 return WLAN_SER_CMD_DENIED_RULES_FAILED; 378 } 379 380 serialization_status = wlan_serialization_enqueue_cmd(cmd, SER_REQUEST); 381 382 error: 383 ser_exit(); 384 return serialization_status; 385 } 386 387 QDF_STATUS 388 wlan_serialization_update_timer(struct wlan_serialization_command *cmd) 389 { 390 QDF_STATUS status = QDF_STATUS_E_FAILURE; 391 struct wlan_objmgr_pdev *pdev; 392 struct wlan_objmgr_psoc *psoc; 393 394 if (!cmd) { 395 ser_err("NULL command"); 396 goto error; 397 } 398 399 pdev = wlan_serialization_get_pdev_from_cmd(cmd); 400 if (!pdev) { 401 ser_err("invalid pdev"); 402 goto error; 403 } 404 405 psoc = wlan_pdev_get_psoc(pdev); 406 if (!psoc) { 407 ser_err("invalid psoc"); 408 goto error; 409 } 410 411 status = wlan_serialization_find_and_update_timer(psoc, cmd); 412 413 error: 414 return status; 415 } 416 417 enum wlan_serialization_cmd_status 418 wlan_serialization_vdev_scan_status(struct wlan_objmgr_vdev *vdev) 419 { 420 bool cmd_in_active = 0, cmd_in_pending = 0; 421 struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); 422 struct wlan_ser_pdev_obj *ser_pdev_obj = 423 wlan_serialization_get_pdev_obj(pdev); 424 struct wlan_serialization_pdev_queue *pdev_q; 425 enum wlan_serialization_cmd_status status; 426 427 ser_enter(); 428 429 pdev_q = &ser_pdev_obj->pdev_q[SER_PDEV_QUEUE_COMP_SCAN]; 430 431 wlan_serialization_acquire_lock(&pdev_q->pdev_queue_lock); 432 433 cmd_in_active = 434 wlan_serialization_is_cmd_in_vdev_list( 435 vdev, &pdev_q->active_list, WLAN_SER_PDEV_NODE); 436 437 cmd_in_pending = 438 wlan_serialization_is_cmd_in_vdev_list( 439 vdev, &pdev_q->pending_list, WLAN_SER_PDEV_NODE); 440 441 status = wlan_serialization_is_cmd_in_active_pending( 442 cmd_in_active, cmd_in_pending); 443 444 wlan_serialization_release_lock(&pdev_q->pdev_queue_lock); 445 ser_exit(); 446 447 return status; 448 } 449 450 void wlan_serialization_flush_cmd( 451 struct wlan_serialization_queued_cmd_info *cmd) 452 { 453 ser_enter(); 454 455 if (!cmd) { 456 ser_err("cmd is null, can't flush"); 457 goto error; 458 } 459 460 error: 461 ser_exit(); 462 } 463 464 enum wlan_serialization_cmd_status 465 wlan_serialization_pdev_scan_status(struct wlan_objmgr_pdev *pdev) 466 { 467 bool cmd_in_active, cmd_in_pending; 468 struct wlan_ser_pdev_obj *ser_pdev_obj = 469 wlan_serialization_get_pdev_obj(pdev); 470 struct wlan_serialization_pdev_queue *pdev_q; 471 enum wlan_serialization_cmd_status status; 472 473 pdev_q = &ser_pdev_obj->pdev_q[SER_PDEV_QUEUE_COMP_SCAN]; 474 475 wlan_serialization_acquire_lock(&pdev_q->pdev_queue_lock); 476 477 cmd_in_active = !qdf_list_empty(&pdev_q->active_list); 478 cmd_in_pending = !qdf_list_empty(&pdev_q->pending_list); 479 480 status = wlan_serialization_is_cmd_in_active_pending( 481 cmd_in_active, cmd_in_pending); 482 483 wlan_serialization_release_lock(&pdev_q->pdev_queue_lock); 484 485 return status; 486 } 487 488 struct wlan_serialization_command* 489 wlan_serialization_get_scan_cmd_using_scan_id( 490 struct wlan_objmgr_psoc *psoc, 491 uint8_t vdev_id, uint16_t scan_id, 492 uint8_t is_scan_cmd_from_active_queue) 493 { 494 struct wlan_objmgr_vdev *vdev; 495 struct wlan_objmgr_pdev *pdev; 496 struct wlan_ser_pdev_obj *ser_pdev_obj; 497 struct wlan_serialization_command cmd = {0}; 498 struct wlan_serialization_command *pcmd = NULL; 499 struct wlan_serialization_command_list *cmd_list; 500 qdf_list_node_t *node = NULL; 501 qdf_list_t *queue; 502 struct wlan_serialization_pdev_queue *pdev_q; 503 504 if (!psoc) { 505 ser_err("invalid psoc"); 506 goto error; 507 } 508 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 509 WLAN_SERIALIZATION_ID); 510 if (!vdev) { 511 ser_err("invalid vdev"); 512 goto error; 513 } 514 515 pdev = wlan_vdev_get_pdev(vdev); 516 if (!pdev) { 517 ser_err("invalid pdev"); 518 goto release_vdev_ref; 519 } 520 521 ser_pdev_obj = wlan_serialization_get_pdev_obj(pdev); 522 if (!ser_pdev_obj) { 523 ser_err("invalid ser_pdev_obj"); 524 goto release_vdev_ref; 525 } 526 527 pdev_q = &ser_pdev_obj->pdev_q[SER_PDEV_QUEUE_COMP_SCAN]; 528 529 wlan_serialization_acquire_lock(&pdev_q->pdev_queue_lock); 530 531 if (is_scan_cmd_from_active_queue) 532 queue = &pdev_q->active_list; 533 else 534 queue = &pdev_q->pending_list; 535 536 cmd.cmd_type = WLAN_SER_CMD_SCAN; 537 cmd.cmd_id = scan_id; 538 cmd.vdev = vdev; 539 540 node = wlan_serialization_find_cmd( 541 queue, WLAN_SER_MATCH_CMD_ID_VDEV, 542 &cmd, 0, NULL, vdev, WLAN_SER_PDEV_NODE); 543 544 if (node) { 545 cmd_list = qdf_container_of( 546 node, 547 struct wlan_serialization_command_list, 548 pdev_node); 549 550 pcmd = &cmd_list->cmd; 551 } 552 553 wlan_serialization_release_lock(&pdev_q->pdev_queue_lock); 554 555 release_vdev_ref: 556 wlan_objmgr_vdev_release_ref(vdev, WLAN_SERIALIZATION_ID); 557 error: 558 return pcmd; 559 } 560 561 void *wlan_serialization_get_active_cmd( 562 struct wlan_objmgr_psoc *psoc, 563 uint8_t vdev_id, 564 enum wlan_serialization_cmd_type cmd_type) 565 { 566 struct wlan_objmgr_vdev *vdev; 567 struct wlan_objmgr_pdev *pdev; 568 struct wlan_ser_pdev_obj *ser_pdev_obj; 569 struct wlan_serialization_command_list *cmd_list = NULL; 570 void *umac_cmd = NULL; 571 qdf_list_node_t *node = NULL; 572 qdf_list_t *queue; 573 struct wlan_serialization_pdev_queue *pdev_q; 574 575 ser_enter(); 576 577 if (!psoc) { 578 ser_err("invalid psoc"); 579 goto error; 580 } 581 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 582 WLAN_SERIALIZATION_ID); 583 if (!vdev) { 584 ser_err("invalid vdev"); 585 goto error; 586 } 587 588 pdev = wlan_vdev_get_pdev(vdev); 589 if (!pdev) { 590 ser_err("invalid pdev"); 591 goto release_vdev_ref; 592 } 593 594 ser_pdev_obj = wlan_serialization_get_pdev_obj(pdev); 595 if (!ser_pdev_obj) { 596 ser_err("invalid ser_pdev_obj"); 597 goto release_vdev_ref; 598 } 599 600 pdev_q = wlan_serialization_get_pdev_queue_obj(ser_pdev_obj, cmd_type); 601 602 wlan_serialization_acquire_lock(&pdev_q->pdev_queue_lock); 603 604 queue = &pdev_q->active_list; 605 606 node = wlan_serialization_find_cmd( 607 queue, WLAN_SER_MATCH_CMD_TYPE_VDEV, 608 NULL, cmd_type, NULL, vdev, WLAN_SER_PDEV_NODE); 609 610 if (node) { 611 cmd_list = qdf_container_of( 612 node, 613 struct wlan_serialization_command_list, 614 pdev_node); 615 616 umac_cmd = cmd_list->cmd.umac_cmd; 617 } 618 619 wlan_serialization_release_lock(&pdev_q->pdev_queue_lock); 620 621 release_vdev_ref: 622 wlan_objmgr_vdev_release_ref(vdev, WLAN_SERIALIZATION_ID); 623 error: 624 ser_exit(); 625 return umac_cmd; 626 } 627 628 enum wlan_serialization_cmd_type 629 wlan_serialization_get_vdev_active_cmd_type(struct wlan_objmgr_vdev *vdev) 630 { 631 enum wlan_serialization_cmd_type cmd_type = WLAN_SER_CMD_MAX; 632 struct wlan_ser_pdev_obj *ser_pdev_obj; 633 struct wlan_ser_vdev_obj *ser_vdev_obj; 634 struct wlan_serialization_pdev_queue *pdev_queue; 635 struct wlan_serialization_vdev_queue *vdev_queue; 636 struct wlan_serialization_command_list *cmd_list = NULL; 637 qdf_list_node_t *node; 638 639 ser_pdev_obj = wlan_serialization_get_pdev_obj( 640 wlan_vdev_get_pdev(vdev)); 641 642 if (!ser_pdev_obj) { 643 ser_err("invalid ser_pdev_obj"); 644 goto error; 645 } 646 pdev_queue = wlan_serialization_get_pdev_queue_obj( 647 ser_pdev_obj, cmd_type); 648 649 ser_vdev_obj = wlan_serialization_get_vdev_obj(vdev); 650 if (!ser_vdev_obj) { 651 ser_err("invalid ser_vdev_obj"); 652 goto error; 653 } 654 vdev_queue = wlan_serialization_get_vdev_queue_obj( 655 ser_vdev_obj, WLAN_SER_CMD_NONSCAN); 656 657 wlan_serialization_acquire_lock(&pdev_queue->pdev_queue_lock); 658 659 if (wlan_serialization_peek_front( 660 &vdev_queue->active_list, &node) == QDF_STATUS_SUCCESS) { 661 cmd_list = qdf_container_of( 662 node, 663 struct wlan_serialization_command_list, 664 vdev_node); 665 666 cmd_type = cmd_list->cmd.cmd_type; 667 } 668 669 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 670 671 error: 672 return cmd_type; 673 } 674