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 /* 20 * DOC: contains scan manager functionality 21 */ 22 23 #include <wlan_serialization_api.h> 24 #include <wlan_scan_ucfg_api.h> 25 #include <wlan_scan_tgt_api.h> 26 #include "wlan_scan_main.h" 27 #include "wlan_scan_manager.h" 28 #include "wlan_utility.h" 29 #ifdef FEATURE_WLAN_SCAN_PNO 30 #include <host_diag_core_event.h> 31 #endif 32 33 QDF_STATUS 34 scm_scan_free_scan_request_mem(struct scan_start_request *req) 35 { 36 void *ie; 37 38 if (!req) { 39 scm_err("null request"); 40 QDF_ASSERT(0); 41 return QDF_STATUS_E_FAILURE; 42 } 43 scm_info("freed scan request: 0x%pK, scan_id: %d, requester: %d", 44 req, req->scan_req.scan_id, req->scan_req.scan_req_id); 45 /* Free vendor(extra) ie */ 46 ie = req->scan_req.extraie.ptr; 47 if (ie) { 48 req->scan_req.extraie.ptr = NULL; 49 req->scan_req.extraie.len = 0; 50 qdf_mem_free(ie); 51 } 52 53 /* Free htcap ie */ 54 ie = req->scan_req.htcap.ptr; 55 if (ie) { 56 req->scan_req.htcap.len = 0; 57 req->scan_req.htcap.ptr = NULL; 58 qdf_mem_free(ie); 59 } 60 61 /* Free vhtcap ie */ 62 ie = req->scan_req.vhtcap.ptr; 63 if (ie) { 64 req->scan_req.vhtcap.len = 0; 65 req->scan_req.vhtcap.ptr = NULL; 66 qdf_mem_free(ie); 67 } 68 /* free scan_start_request memory */ 69 qdf_mem_free(req); 70 71 return QDF_STATUS_SUCCESS; 72 } 73 74 static QDF_STATUS 75 scm_scan_get_pdev_global_event_handlers(struct scan_event_listeners *listeners, 76 struct pdev_scan_ev_handler *pdev_ev_handler) 77 { 78 uint32_t i; 79 struct cb_handler *cb_handlers = &(pdev_ev_handler->cb_handlers[0]); 80 81 for (i = 0; i < MAX_SCAN_EVENT_HANDLERS_PER_PDEV; i++, cb_handlers++) { 82 if ((cb_handlers->func) && 83 (listeners->count < MAX_SCAN_EVENT_LISTENERS)) { 84 listeners->cb[listeners->count].func = 85 cb_handlers->func; 86 listeners->cb[listeners->count].arg = 87 cb_handlers->arg; 88 listeners->count++; 89 } 90 } 91 92 return QDF_STATUS_SUCCESS; 93 } 94 95 static QDF_STATUS 96 scm_scan_get_requester_event_handler(struct scan_event_listeners *listeners, 97 struct scan_requester_info *requesters, 98 wlan_scan_requester requester_id) 99 { 100 uint32_t idx; 101 struct cb_handler *ev_handler; 102 103 idx = requester_id & WLAN_SCAN_REQUESTER_ID_PREFIX; 104 if (idx != WLAN_SCAN_REQUESTER_ID_PREFIX) 105 return QDF_STATUS_SUCCESS; 106 107 idx = requester_id & WLAN_SCAN_REQUESTER_ID_MASK; 108 if (idx < WLAN_MAX_REQUESTORS) { 109 ev_handler = &(requesters[idx].ev_handler); 110 if (ev_handler->func) { 111 if (listeners->count < MAX_SCAN_EVENT_LISTENERS) { 112 listeners->cb[listeners->count].func = 113 ev_handler->func; 114 listeners->cb[listeners->count].arg = 115 ev_handler->arg; 116 listeners->count++; 117 } 118 } 119 return QDF_STATUS_SUCCESS; 120 } else { 121 scm_err("invalid requester id"); 122 return QDF_STATUS_E_INVAL; 123 } 124 125 } 126 127 static void scm_scan_post_event(struct wlan_objmgr_vdev *vdev, 128 struct scan_event *event) 129 { 130 uint32_t i = 0; 131 struct wlan_scan_obj *scan; 132 struct pdev_scan_ev_handler *pdev_ev_handler; 133 struct cb_handler *cb_handlers; 134 struct scan_requester_info *requesters; 135 struct scan_event_listeners *listeners; 136 137 if (!vdev || !event) { 138 scm_err("vdev: 0x%pK, event: 0x%pK", vdev, event); 139 return; 140 } 141 if (!event->requester) { 142 scm_err("invalid requester id"); 143 QDF_ASSERT(0); 144 } 145 scm_info("vdev: 0x%pK, event: 0x%pK", vdev, event); 146 147 scan = wlan_vdev_get_scan_obj(vdev); 148 pdev_ev_handler = wlan_vdev_get_pdev_scan_ev_handlers(vdev); 149 cb_handlers = &(pdev_ev_handler->cb_handlers[0]); 150 requesters = scan->requesters; 151 152 scm_info("vdev: %d, type: %d, reason: %d, freq: %d, req: %d, scanid: %d", 153 event->vdev_id, event->type, event->reason, event->chan_freq, 154 event->requester, event->scan_id); 155 156 listeners = qdf_mem_malloc(sizeof(*listeners)); 157 if (!listeners) { 158 scm_warn("couldn't allocate listeners list"); 159 return; 160 } 161 162 /* initialize number of listeners */ 163 listeners->count = 0; 164 165 /* 166 * Initiator of scan request decides which all scan events 167 * he is interested in and FW will send only those scan events 168 * to host driver. 169 * All the events received by scan module will be notified 170 * to all registered handlers. 171 */ 172 173 qdf_spin_lock_bh(&scan->lock); 174 /* find all global scan event handlers on this pdev */ 175 scm_scan_get_pdev_global_event_handlers(listeners, pdev_ev_handler); 176 /* find owner who triggered this scan request */ 177 scm_scan_get_requester_event_handler(listeners, requesters, 178 event->requester); 179 qdf_spin_unlock_bh(&scan->lock); 180 181 /* notify all interested handlers */ 182 for (i = 0; i < listeners->count; i++) { 183 scm_debug("func: 0x%pK, arg: 0x%pK", 184 listeners->cb[i].func, listeners->cb[i].arg); 185 listeners->cb[i].func(vdev, event, listeners->cb[i].arg); 186 } 187 qdf_mem_free(listeners); 188 } 189 190 static QDF_STATUS 191 scm_release_serialization_command(struct wlan_objmgr_vdev *vdev, 192 uint32_t scan_id) 193 { 194 struct wlan_serialization_queued_cmd_info cmd = {0}; 195 196 cmd.requestor = WLAN_UMAC_COMP_SCAN; 197 cmd.cmd_type = WLAN_SER_CMD_SCAN; 198 cmd.cmd_id = scan_id; 199 cmd.req_type = WLAN_SER_CANCEL_SINGLE_SCAN; 200 cmd.vdev = vdev; 201 cmd.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE; 202 203 /* Inform serialization for command completion */ 204 wlan_serialization_remove_cmd(&cmd); 205 206 return QDF_STATUS_SUCCESS; 207 } 208 209 static QDF_STATUS 210 scm_post_internal_scan_complete_event(struct scan_start_request *req, 211 enum scan_completion_reason reason) 212 { 213 struct scan_event event = {0, }; 214 215 /* prepare internal scan complete event */ 216 event.type = SCAN_EVENT_TYPE_COMPLETED; 217 event.reason = reason; 218 event.chan_freq = 0; /* Invalid frequency */ 219 event.vdev_id = req->scan_req.vdev_id; 220 event.requester = req->scan_req.scan_req_id; 221 event.scan_id = req->scan_req.scan_id; 222 /* Fill scan_start_request used to trigger this scan */ 223 event.scan_start_req = req; 224 /* post scan event to registered handlers */ 225 scm_scan_post_event(req->vdev, &event); 226 227 return QDF_STATUS_SUCCESS; 228 } 229 230 static inline struct pdev_scan_info * 231 scm_scan_get_pdev_priv_info(uint8_t pdev_id, struct wlan_scan_obj *scan_obj) 232 { 233 return &scan_obj->pdev_info[pdev_id]; 234 } 235 236 static QDF_STATUS 237 scm_update_last_scan_time(struct scan_start_request *req) 238 { 239 uint8_t pdev_id; 240 struct wlan_scan_obj *scan_obj; 241 struct pdev_scan_info *pdev_scan_info; 242 243 scan_obj = wlan_vdev_get_scan_obj(req->vdev); 244 pdev_id = wlan_scan_vdev_get_pdev_id(req->vdev); 245 pdev_scan_info = scm_scan_get_pdev_priv_info(pdev_id, scan_obj); 246 /* update last scan start time */ 247 pdev_scan_info->last_scan_time = qdf_system_ticks(); 248 249 return QDF_STATUS_SUCCESS; 250 } 251 252 static QDF_STATUS 253 scm_activate_scan_request(struct scan_start_request *req) 254 { 255 QDF_STATUS status; 256 257 status = tgt_scan_start(req); 258 if (status != QDF_STATUS_SUCCESS) { 259 scm_err("tgt_scan_start failed, status: %d", status); 260 /* scan could not be started and hence 261 * we will not receive any completions. 262 * post scan cancelled 263 */ 264 scm_post_internal_scan_complete_event(req, 265 SCAN_REASON_CANCELLED); 266 return status; 267 } 268 /* save last scan start time */ 269 status = scm_update_last_scan_time(req); 270 271 return status; 272 } 273 274 static QDF_STATUS 275 scm_cancel_scan_request(struct scan_start_request *req) 276 { 277 struct scan_cancel_request cancel_req = {0, }; 278 QDF_STATUS status; 279 280 cancel_req.vdev = req->vdev; 281 cancel_req.cancel_req.scan_id = req->scan_req.scan_id; 282 cancel_req.cancel_req.requester = req->scan_req.scan_req_id; 283 cancel_req.cancel_req.req_type = WLAN_SCAN_CANCEL_SINGLE; 284 cancel_req.cancel_req.vdev_id = req->scan_req.vdev_id; 285 /* send scan cancel to fw */ 286 status = tgt_scan_cancel(&cancel_req); 287 if (status != QDF_STATUS_SUCCESS) 288 scm_err("tgt_scan_cancel failed: status: %d, scanid: %d", 289 status, req->scan_req.scan_id); 290 /* notify event handler about scan cancellation */ 291 scm_post_internal_scan_complete_event(req, SCAN_REASON_CANCELLED); 292 293 return status; 294 } 295 296 static QDF_STATUS 297 scm_scan_serialize_callback(struct wlan_serialization_command *cmd, 298 enum wlan_serialization_cb_reason reason) 299 { 300 struct scan_start_request *req; 301 QDF_STATUS status; 302 303 if (!cmd) { 304 scm_err("cmd is NULL, reason: %d", reason); 305 QDF_ASSERT(0); 306 return QDF_STATUS_E_NULL_VALUE; 307 } 308 309 if (!cmd->umac_cmd) { 310 scm_err("cmd->umac_cmd is NULL , reason: %d", reason); 311 QDF_ASSERT(0); 312 return QDF_STATUS_E_NULL_VALUE; 313 } 314 315 req = cmd->umac_cmd; 316 scm_debug("reason:%d, reqid:%d, scanid:%d, vdevid:%d, vdev:0x%pK", 317 reason, req->scan_req.scan_req_id, req->scan_req.scan_id, 318 req->scan_req.vdev_id, req->vdev); 319 320 if (!req->vdev) { 321 scm_err("NULL vdev. req:0x%pK, reason:%d\n", req, reason); 322 QDF_ASSERT(0); 323 return QDF_STATUS_E_NULL_VALUE; 324 } 325 326 switch (reason) { 327 case WLAN_SER_CB_ACTIVATE_CMD: 328 /* command moved to active list 329 * modify the params if required for concurency case. 330 */ 331 status = scm_activate_scan_request(req); 332 break; 333 334 case WLAN_SER_CB_CANCEL_CMD: 335 /* command removed from pending list. 336 * notify registered scan event handlers with 337 * status completed and reason cancelled. 338 */ 339 status = scm_post_internal_scan_complete_event(req, 340 SCAN_REASON_CANCELLED); 341 break; 342 343 case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT: 344 /* active command timed out. 345 * prepare internal scan cancel request 346 */ 347 status = scm_cancel_scan_request(req); 348 break; 349 350 case WLAN_SER_CB_RELEASE_MEM_CMD: 351 /* command successfully completed. 352 * Release vdev reference and free scan_start_request memory 353 */ 354 cmd->umac_cmd = NULL; 355 wlan_objmgr_vdev_release_ref(req->vdev, WLAN_SCAN_ID); 356 status = scm_scan_free_scan_request_mem(req); 357 break; 358 359 default: 360 /* Do nothing but logging */ 361 QDF_ASSERT(0); 362 status = QDF_STATUS_E_INVAL; 363 break; 364 } 365 366 return status; 367 } 368 369 QDF_STATUS 370 scm_scan_start_req(struct scheduler_msg *msg) 371 { 372 struct wlan_serialization_command cmd = {0, }; 373 enum wlan_serialization_status ser_cmd_status; 374 struct scan_start_request *req; 375 struct wlan_scan_obj *scan_obj; 376 QDF_STATUS status = QDF_STATUS_SUCCESS; 377 378 if (!msg) { 379 scm_err("msg received is NULL"); 380 QDF_ASSERT(0); 381 return QDF_STATUS_E_NULL_VALUE; 382 } 383 if (!msg->bodyptr) { 384 scm_err("bodyptr is NULL"); 385 QDF_ASSERT(0); 386 return QDF_STATUS_E_NULL_VALUE; 387 } 388 389 req = msg->bodyptr; 390 scan_obj = wlan_vdev_get_scan_obj(req->vdev); 391 if (!scan_obj) { 392 scm_debug("Couldn't find scan object"); 393 return QDF_STATUS_E_NULL_VALUE; 394 } 395 396 cmd.cmd_type = WLAN_SER_CMD_SCAN; 397 cmd.cmd_id = req->scan_req.scan_id; 398 cmd.cmd_cb = (wlan_serialization_cmd_callback) 399 scm_scan_serialize_callback; 400 cmd.umac_cmd = req; 401 cmd.source = WLAN_UMAC_COMP_SCAN; 402 cmd.is_high_priority = false; 403 cmd.cmd_timeout_duration = req->scan_req.max_scan_time + 404 SCAN_TIMEOUT_GRACE_PERIOD; 405 cmd.vdev = req->vdev; 406 407 if (scan_obj->disable_timeout) 408 cmd.cmd_timeout_duration = 0; 409 410 scm_info("req: 0x%pK, reqid: %d, scanid: %d, vdevid: %d", 411 req, req->scan_req.scan_req_id, req->scan_req.scan_id, 412 req->scan_req.vdev_id); 413 414 ser_cmd_status = wlan_serialization_request(&cmd); 415 scm_info("wlan_serialization_request status:%d", ser_cmd_status); 416 417 switch (ser_cmd_status) { 418 case WLAN_SER_CMD_PENDING: 419 /* command moved to pending list.Do nothing */ 420 break; 421 case WLAN_SER_CMD_ACTIVE: 422 /* command moved to active list. Do nothing */ 423 break; 424 case WLAN_SER_CMD_DENIED_LIST_FULL: 425 case WLAN_SER_CMD_DENIED_RULES_FAILED: 426 case WLAN_SER_CMD_DENIED_UNSPECIFIED: 427 /* notify registered scan event handlers 428 * about internal error 429 */ 430 scm_post_internal_scan_complete_event(req, 431 SCAN_REASON_INTERNAL_FAILURE); 432 /* cmd can't be serviced. 433 * release vdev reference and free scan_start_request memory 434 */ 435 wlan_objmgr_vdev_release_ref(req->vdev, WLAN_SCAN_ID); 436 scm_scan_free_scan_request_mem(req); 437 break; 438 default: 439 QDF_ASSERT(0); 440 status = QDF_STATUS_E_INVAL; 441 /* cmd can't be serviced. 442 * release vdev reference and free scan_start_request memory 443 */ 444 wlan_objmgr_vdev_release_ref(req->vdev, WLAN_SCAN_ID); 445 scm_scan_free_scan_request_mem(req); 446 break; 447 } 448 449 return status; 450 } 451 452 static inline enum wlan_serialization_cancel_type 453 get_serialization_cancel_type(enum scan_cancel_req_type type) 454 { 455 enum wlan_serialization_cancel_type serialization_type; 456 457 switch (type) { 458 case WLAN_SCAN_CANCEL_SINGLE: 459 serialization_type = WLAN_SER_CANCEL_SINGLE_SCAN; 460 break; 461 case WLAN_SCAN_CANCEL_VDEV_ALL: 462 serialization_type = WLAN_SER_CANCEL_VDEV_SCANS; 463 break; 464 case WLAN_SCAN_CANCEL_PDEV_ALL: 465 serialization_type = WLAN_SER_CANCEL_PDEV_SCANS; 466 break; 467 default: 468 QDF_ASSERT(0); 469 scm_warn("invalid scan_cancel_req_type: %d", type); 470 serialization_type = WLAN_SER_CANCEL_PDEV_SCANS; 471 break; 472 } 473 474 return serialization_type; 475 } 476 477 QDF_STATUS 478 scm_scan_cancel_req(struct scheduler_msg *msg) 479 { 480 struct wlan_serialization_queued_cmd_info cmd = {0,}; 481 struct wlan_serialization_command ser_cmd = {0,}; 482 enum wlan_serialization_cmd_status ser_cmd_status; 483 struct scan_cancel_request *req; 484 QDF_STATUS status = QDF_STATUS_SUCCESS; 485 486 if (!msg) { 487 scm_err("msg received is NULL"); 488 QDF_ASSERT(0); 489 return QDF_STATUS_E_NULL_VALUE; 490 } 491 if (!msg->bodyptr) { 492 scm_err("Bodyptr is NULL"); 493 QDF_ASSERT(0); 494 return QDF_STATUS_E_NULL_VALUE; 495 } 496 497 req = msg->bodyptr; 498 /* 499 * If requester wants to wait for target scan cancel event 500 * instead of internally generated cancel event, just check 501 * which queue this scan request belongs to and send scan 502 * cancel request to FW accordingly. 503 * Else generate internal scan cancel event and notify 504 * handlers and free scan request resources. 505 */ 506 if (req->wait_tgt_cancel && 507 (req->cancel_req.req_type == WLAN_SCAN_CANCEL_SINGLE)) { 508 ser_cmd.cmd_type = WLAN_SER_CMD_SCAN; 509 ser_cmd.cmd_id = req->cancel_req.scan_id; 510 ser_cmd.cmd_cb = NULL; 511 ser_cmd.umac_cmd = NULL; 512 ser_cmd.source = WLAN_UMAC_COMP_SCAN; 513 ser_cmd.is_high_priority = false; 514 ser_cmd.vdev = req->vdev; 515 if (wlan_serialization_is_cmd_present_in_active_queue(NULL, &ser_cmd)) 516 ser_cmd_status = WLAN_SER_CMD_IN_ACTIVE_LIST; 517 else if (wlan_serialization_is_cmd_present_in_pending_queue(NULL, &ser_cmd)) 518 ser_cmd_status = WLAN_SER_CMD_IN_PENDING_LIST; 519 else 520 ser_cmd_status = WLAN_SER_CMD_NOT_FOUND; 521 } else { 522 cmd.requestor = 0; 523 cmd.cmd_type = WLAN_SER_CMD_SCAN; 524 cmd.cmd_id = req->cancel_req.scan_id; 525 cmd.vdev = req->vdev; 526 cmd.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE | 527 WLAN_SERIALIZATION_PENDING_QUEUE; 528 cmd.req_type = get_serialization_cancel_type(req->cancel_req.req_type); 529 530 ser_cmd_status = wlan_serialization_cancel_request(&cmd); 531 } 532 533 scm_debug("status: %d, reqid: %d, scanid: %d, vdevid: %d, type: %d", 534 ser_cmd_status, req->cancel_req.requester, 535 req->cancel_req.scan_id, req->cancel_req.vdev_id, 536 req->cancel_req.req_type); 537 538 switch (ser_cmd_status) { 539 case WLAN_SER_CMD_IN_PENDING_LIST: 540 /* do nothing */ 541 break; 542 case WLAN_SER_CMD_IN_ACTIVE_LIST: 543 case WLAN_SER_CMDS_IN_ALL_LISTS: 544 /* send wmi scan cancel to fw */ 545 status = tgt_scan_cancel(req); 546 break; 547 case WLAN_SER_CMD_NOT_FOUND: 548 /* do nothing */ 549 break; 550 default: 551 QDF_ASSERT(0); 552 status = QDF_STATUS_E_INVAL; 553 break; 554 } 555 556 /* Release vdev reference and scan cancel request 557 * processing is complete 558 */ 559 wlan_objmgr_vdev_release_ref(req->vdev, WLAN_SCAN_ID); 560 /* Free cancel request memory */ 561 qdf_mem_free(req); 562 563 return status; 564 } 565 566 #ifdef FEATURE_WLAN_SCAN_PNO 567 static QDF_STATUS 568 scm_pno_event_handler(struct wlan_objmgr_vdev *vdev, 569 struct scan_event *event) 570 { 571 struct scan_vdev_obj *scan_vdev_obj; 572 struct wlan_scan_obj *scan_psoc_obj; 573 scan_event_handler pno_cb; 574 void *cb_arg; 575 576 scan_vdev_obj = wlan_get_vdev_scan_obj(vdev); 577 scan_psoc_obj = wlan_vdev_get_scan_obj(vdev); 578 if (!scan_vdev_obj || !scan_psoc_obj) { 579 scm_err("null scan_vdev_obj %pK scan_obj %pK", 580 scan_vdev_obj, scan_psoc_obj); 581 return QDF_STATUS_E_INVAL; 582 } 583 584 switch (event->type) { 585 case SCAN_EVENT_TYPE_NLO_COMPLETE: 586 if (!scan_vdev_obj->pno_match_evt_received) 587 return QDF_STATUS_SUCCESS; 588 qdf_wake_lock_release(&scan_psoc_obj->pno_cfg.pno_wake_lock, 589 WIFI_POWER_EVENT_WAKELOCK_PNO); 590 qdf_wake_lock_timeout_acquire( 591 &scan_psoc_obj->pno_cfg.pno_wake_lock, 592 SCAN_PNO_SCAN_COMPLETE_WAKE_LOCK_TIMEOUT); 593 scan_vdev_obj->pno_match_evt_received = false; 594 break; 595 case SCAN_EVENT_TYPE_NLO_MATCH: 596 scan_vdev_obj->pno_match_evt_received = true; 597 qdf_wake_lock_timeout_acquire( 598 &scan_psoc_obj->pno_cfg.pno_wake_lock, 599 SCAN_PNO_MATCH_WAKE_LOCK_TIMEOUT); 600 return QDF_STATUS_SUCCESS; 601 default: 602 return QDF_STATUS_E_INVAL; 603 } 604 qdf_spin_lock_bh(&scan_psoc_obj->lock); 605 pno_cb = scan_psoc_obj->pno_cfg.pno_cb.func; 606 cb_arg = scan_psoc_obj->pno_cfg.pno_cb.arg; 607 qdf_spin_unlock_bh(&scan_psoc_obj->lock); 608 609 if (pno_cb) 610 pno_cb(vdev, event, cb_arg); 611 612 return QDF_STATUS_SUCCESS; 613 } 614 #else 615 616 static QDF_STATUS 617 scm_pno_event_handler(struct wlan_objmgr_vdev *vdev, 618 struct scan_event *event) 619 { 620 return QDF_STATUS_SUCCESS; 621 } 622 #endif 623 624 /** 625 * scm_scan_update_scan_event() - update scan event 626 * @scan: scan object 627 * @event: scan event 628 * @scan_start_req: scan_start_req used for triggering scan 629 * 630 * update scan params in scan event 631 * 632 * Return: QDF_STATUS 633 */ 634 static QDF_STATUS 635 scm_scan_update_scan_event(struct wlan_scan_obj *scan, 636 struct scan_event *event, 637 struct scan_start_request *scan_start_req) 638 { 639 if (!event) 640 return QDF_STATUS_E_NULL_VALUE; 641 642 if (!scan || !scan_start_req) { 643 event->scan_start_req = NULL; 644 return QDF_STATUS_E_NULL_VALUE; 645 } 646 /* copy scan start request to pass back buffer */ 647 qdf_mem_copy(&scan->scan_start_request_buff, scan_start_req, 648 sizeof(struct scan_start_request)); 649 /* reset all pointers */ 650 scan->scan_start_request_buff.scan_req.extraie.ptr = NULL; 651 scan->scan_start_request_buff.scan_req.extraie.len = 0; 652 scan->scan_start_request_buff.scan_req.htcap.ptr = NULL; 653 scan->scan_start_request_buff.scan_req.htcap.len = 0; 654 scan->scan_start_request_buff.scan_req.vhtcap.ptr = NULL; 655 scan->scan_start_request_buff.scan_req.vhtcap.len = 0; 656 657 event->scan_start_req = &scan->scan_start_request_buff; 658 659 return QDF_STATUS_SUCCESS; 660 } 661 662 QDF_STATUS 663 scm_scan_event_handler(struct scheduler_msg *msg) 664 { 665 struct wlan_objmgr_vdev *vdev; 666 struct scan_event *event; 667 struct scan_event_info *event_info; 668 struct wlan_serialization_command cmd = {0,}; 669 struct wlan_serialization_command *queued_cmd; 670 struct scan_start_request *scan_start_req; 671 struct wlan_scan_obj *scan; 672 673 if (!msg) { 674 scm_err("NULL msg received "); 675 QDF_ASSERT(0); 676 return QDF_STATUS_E_NULL_VALUE; 677 } 678 if (!msg->bodyptr) { 679 scm_err("NULL scan event received"); 680 QDF_ASSERT(0); 681 return QDF_STATUS_E_NULL_VALUE; 682 } 683 684 event_info = msg->bodyptr; 685 vdev = event_info->vdev; 686 event = &(event_info->event); 687 688 scm_info("vdevid:%d, type:%d, reason:%d, freq:%d, reqstr:%d, scanid:%d", 689 event->vdev_id, event->type, event->reason, event->chan_freq, 690 event->requester, event->scan_id); 691 /* 692 * NLO requests are never queued, so post NLO events 693 * without checking for their presence in active queue. 694 */ 695 switch (event->type) { 696 case SCAN_EVENT_TYPE_NLO_COMPLETE: 697 case SCAN_EVENT_TYPE_NLO_MATCH: 698 scm_pno_event_handler(vdev, event); 699 goto exit; 700 default: 701 break; 702 } 703 704 cmd.cmd_type = WLAN_SER_CMD_SCAN; 705 cmd.cmd_id = event->scan_id; 706 cmd.cmd_cb = NULL; 707 cmd.umac_cmd = NULL; 708 cmd.source = WLAN_UMAC_COMP_SCAN; 709 cmd.is_high_priority = false; 710 cmd.vdev = vdev; 711 if (!wlan_serialization_is_cmd_present_in_active_queue(NULL, &cmd)) { 712 /* 713 * We received scan event for an already completed/cancelled 714 * scan request. Drop this event. 715 */ 716 scm_warn("Received scan event while request not in active queue"); 717 goto exit; 718 } 719 720 /* Fill scan_start_request used to trigger this scan */ 721 queued_cmd = wlan_serialization_get_scan_cmd_using_scan_id( 722 wlan_vdev_get_psoc(vdev), wlan_vdev_get_id(vdev), 723 event->scan_id, true); 724 725 if (!queued_cmd) { 726 scm_err("NULL queued_cmd"); 727 goto exit; 728 } 729 if (!queued_cmd->umac_cmd) { 730 scm_err("NULL umac_cmd"); 731 goto exit; 732 } 733 scan_start_req = queued_cmd->umac_cmd; 734 735 if (scan_start_req->scan_req.scan_req_id != event->requester) { 736 scm_err("req ID mismatch, scan_req_id:%d, event_req_id:%d", 737 scan_start_req->scan_req.scan_req_id, 738 event->requester); 739 goto exit; 740 } 741 742 scan = wlan_vdev_get_scan_obj(vdev); 743 if (scan) 744 scm_scan_update_scan_event(scan, event, scan_start_req); 745 746 switch (event->type) { 747 case SCAN_EVENT_TYPE_COMPLETED: 748 if (event->reason == SCAN_REASON_COMPLETED) 749 scm_11d_decide_country_code(vdev); 750 /* fall through to release the command */ 751 case SCAN_EVENT_TYPE_START_FAILED: 752 case SCAN_EVENT_TYPE_DEQUEUED: 753 scm_release_serialization_command(vdev, event->scan_id); 754 break; 755 default: 756 break; 757 } 758 759 /* Notify all interested parties */ 760 scm_scan_post_event(vdev, event); 761 762 exit: 763 /* free event info memory */ 764 qdf_mem_free(event_info); 765 wlan_objmgr_vdev_release_ref(vdev, WLAN_SCAN_ID); 766 767 return QDF_STATUS_SUCCESS; 768 } 769 770 QDF_STATUS scm_scan_event_flush_callback(struct scheduler_msg *msg) 771 { 772 struct wlan_objmgr_vdev *vdev; 773 struct scan_event_info *event_info; 774 775 if (!msg || !msg->bodyptr) { 776 scm_err("msg or msg->bodyptr is NULL"); 777 return QDF_STATUS_E_NULL_VALUE; 778 } 779 780 event_info = msg->bodyptr; 781 vdev = event_info->vdev; 782 783 /* free event info memory */ 784 qdf_mem_free(event_info); 785 wlan_objmgr_vdev_release_ref(vdev, WLAN_SCAN_ID); 786 787 return QDF_STATUS_SUCCESS; 788 } 789 790 QDF_STATUS scm_bcn_probe_flush_callback(struct scheduler_msg *msg) 791 { 792 struct scan_bcn_probe_event *bcn; 793 794 bcn = msg->bodyptr; 795 796 if (!bcn) { 797 scm_err("bcn is NULL"); 798 return QDF_STATUS_E_NULL_VALUE; 799 } 800 if (bcn->psoc) 801 wlan_objmgr_psoc_release_ref(bcn->psoc, WLAN_SCAN_ID); 802 if (bcn->rx_data) 803 qdf_mem_free(bcn->rx_data); 804 if (bcn->buf) 805 qdf_nbuf_free(bcn->buf); 806 qdf_mem_free(bcn); 807 808 return QDF_STATUS_SUCCESS; 809 } 810 811 QDF_STATUS scm_scan_start_flush_callback(struct scheduler_msg *msg) 812 { 813 struct scan_start_request *req; 814 815 if (!msg || !msg->bodyptr) { 816 scm_err("msg or msg->bodyptr is NULL"); 817 return QDF_STATUS_E_NULL_VALUE; 818 } 819 820 req = msg->bodyptr; 821 scm_post_internal_scan_complete_event(req, SCAN_REASON_CANCELLED); 822 wlan_objmgr_vdev_release_ref(req->vdev, WLAN_SCAN_ID); 823 scm_scan_free_scan_request_mem(req); 824 825 return QDF_STATUS_SUCCESS; 826 } 827 828 QDF_STATUS scm_scan_cancel_flush_callback(struct scheduler_msg *msg) 829 { 830 struct scan_cancel_request *req; 831 832 if (!msg || !msg->bodyptr) { 833 scm_err("msg or msg->bodyptr is NULL"); 834 return QDF_STATUS_E_NULL_VALUE; 835 } 836 837 req = msg->bodyptr; 838 wlan_objmgr_vdev_release_ref(req->vdev, WLAN_SCAN_ID); 839 /* Free cancel request memory */ 840 qdf_mem_free(req); 841 842 return QDF_STATUS_SUCCESS; 843 } 844