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