xref: /wlan-dirver/qca-wifi-host-cmn/umac/scan/core/src/wlan_scan_manager.c (revision 92d87f51612f6c3b2285266215edee8911647c2f)
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