xref: /wlan-dirver/qca-wifi-host-cmn/umac/cmn_services/serialization/src/wlan_serialization_internal.c (revision dd4dc88b837a295134aa9869114a2efee0f4894b)
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  * DOC: wlan_serialization_internal.c
20  * This file defines the functions which are called
21  * from serialization public API's and are internal
22  * to serialization.
23  */
24 
25 #include <wlan_objmgr_vdev_obj.h>
26 #include <wlan_objmgr_pdev_obj.h>
27 #include <wlan_objmgr_psoc_obj.h>
28 #include <qdf_list.h>
29 #include <qdf_status.h>
30 #include <wlan_utility.h>
31 #include "wlan_serialization_api.h"
32 #include "wlan_serialization_main_i.h"
33 #include "wlan_serialization_utils_i.h"
34 #include "wlan_serialization_non_scan_i.h"
35 #include "wlan_serialization_scan_i.h"
36 #include "wlan_serialization_internal_i.h"
37 
38 bool wlan_serialization_is_cmd_present_queue(
39 			struct wlan_serialization_command *cmd,
40 			uint8_t is_active_queue)
41 {
42 	qdf_list_t *queue;
43 	bool status = false;
44 	enum wlan_serialization_node node_type;
45 	struct wlan_ser_pdev_obj *ser_pdev_obj;
46 	struct wlan_ser_vdev_obj *ser_vdev_obj;
47 	enum wlan_serialization_cmd_type cmd_type;
48 
49 	if (!cmd) {
50 		ser_err("invalid cmd");
51 		goto error;
52 	}
53 
54 	cmd_type = cmd->cmd_type;
55 
56 	ser_pdev_obj = wlan_serialization_get_pdev_obj(
57 			wlan_serialization_get_pdev_from_cmd(cmd));
58 
59 	if (!ser_pdev_obj) {
60 		ser_err("invalid ser vdev obj");
61 		goto error;
62 	}
63 
64 	ser_vdev_obj = wlan_serialization_get_vdev_obj(
65 			wlan_serialization_get_vdev_from_cmd(cmd));
66 	if (!ser_vdev_obj) {
67 		ser_err("invalid ser pdev obj");
68 		goto error;
69 	}
70 
71 	if (cmd_type < WLAN_SER_CMD_NONSCAN) {
72 		queue = wlan_serialization_get_list_from_pdev_queue(
73 				ser_pdev_obj, cmd_type, is_active_queue);
74 		node_type = WLAN_SER_PDEV_NODE;
75 	} else {
76 		queue = wlan_serialization_get_list_from_vdev_queue(
77 				ser_vdev_obj, cmd_type, is_active_queue);
78 		node_type = WLAN_SER_VDEV_NODE;
79 	}
80 
81 	status = wlan_serialization_is_cmd_present_in_given_queue(queue, cmd,
82 								  node_type);
83 
84 error:
85 	return status;
86 }
87 
88 enum wlan_serialization_status
89 wlan_serialization_enqueue_cmd(struct wlan_serialization_command *cmd,
90 			       enum ser_queue_reason ser_reason)
91 {
92 	enum wlan_serialization_status status = WLAN_SER_CMD_DENIED_UNSPECIFIED;
93 	struct wlan_serialization_command_list *cmd_list;
94 	qdf_list_node_t *nnode;
95 	struct wlan_objmgr_pdev *pdev;
96 	struct wlan_ser_pdev_obj *ser_pdev_obj;
97 	struct wlan_serialization_pdev_queue *pdev_queue;
98 	struct wlan_ser_vdev_obj *ser_vdev_obj;
99 	struct wlan_serialization_vdev_queue *vdev_queue;
100 	bool active_queue;
101 
102 	/* Enqueue process
103 	 * 1) peek through command structure and see what is the command type
104 	 * 2) two main types of commands to process
105 	 *    a) SCAN
106 	 *    b) NON-SCAN
107 	 * 3) for each command there are separate command queues per pdev
108 	 * 4) pull pdev from vdev structure and get the command queue associated
109 	 *    with that pdev and try to enqueue on those queue
110 	 * 5) Thumb rule:
111 	 *    a) There could be only 1 active non-scan command at a
112 	 *       time including all total non-scan commands of all pdevs.
113 	 *
114 	 *       example: pdev1 has 1 non-scan active command and
115 	 *       pdev2 got 1 non-scan command then that command should go to
116 	 *       pdev2's pending queue
117 	 *
118 	 *    b) There could be only N number of scan commands at a time
119 	 *       including all total scan commands of all pdevs
120 	 *
121 	 *       example: Let's say N=8,
122 	 *       pdev1's vdev1 has 5 scan command, pdev2's vdev1 has 3
123 	 *       scan commands, if we get scan request on vdev2 then it will go
124 	 *       to pending queue of vdev2 as we reached max allowed scan active
125 	 *       command.
126 	 */
127 
128 	ser_enter();
129 
130 	if (!cmd) {
131 		ser_err("NULL command");
132 		goto error;
133 	}
134 
135 	if (!cmd->cmd_cb) {
136 		ser_err("no cmd_cb for cmd type:%d, id: %d",
137 			cmd->cmd_type,
138 			cmd->cmd_id);
139 		goto error;
140 	}
141 
142 	pdev = wlan_serialization_get_pdev_from_cmd(cmd);
143 	if (!pdev) {
144 		ser_err("pdev is invalid");
145 		goto error;
146 	}
147 
148 	ser_pdev_obj =
149 		wlan_objmgr_pdev_get_comp_private_obj(
150 				pdev,
151 				WLAN_UMAC_COMP_SERIALIZATION);
152 	if (!ser_pdev_obj) {
153 		ser_err("Invalid ser_pdev_obj");
154 		goto error;
155 	}
156 
157 	pdev_queue = wlan_serialization_get_pdev_queue_obj(ser_pdev_obj,
158 							   cmd->cmd_type);
159 	if (!pdev_queue) {
160 		ser_err("pdev_queue is invalid");
161 		goto error;
162 	}
163 
164 	ser_debug("enqueue cmd: type[%d] id[%d] high_priority[%d] blocking[%d]",
165 		  cmd->cmd_type,
166 		  cmd->cmd_id,
167 		  cmd->is_high_priority,
168 		  cmd->is_blocking);
169 
170 	wlan_serialization_acquire_lock(&pdev_queue->pdev_queue_lock);
171 
172 	/* Before queuing any non scan command,
173 	 * as part of wlan_serialization_request,
174 	 * we check if the vdev queues are disabled.
175 	 *
176 	 * The serialization command structure has an
177 	 * attribute, where after a given command is queued,
178 	 * we can block the vdev queues.
179 	 *
180 	 * For example, after VDEV_DOWN command is queued as
181 	 * part of a vdev deletion, no other commands should be queued
182 	 * until the deletion is complete, so with VDEV_DOWN(in case of
183 	 * vdev deletion) with pass the attribute to disable vdev queues
184 	 */
185 	if (cmd->cmd_type > WLAN_SER_CMD_SCAN &&
186 	    ser_reason == SER_REQUEST) {
187 		ser_vdev_obj =
188 			wlan_serialization_get_vdev_obj(
189 				wlan_serialization_get_vdev_from_cmd(cmd));
190 
191 		if (!ser_vdev_obj) {
192 			wlan_serialization_release_lock(
193 				&pdev_queue->pdev_queue_lock);
194 			goto error;
195 		}
196 
197 		vdev_queue =
198 			wlan_serialization_get_vdev_queue_obj(
199 				ser_vdev_obj,
200 				cmd->cmd_type);
201 
202 		if (!vdev_queue) {
203 			wlan_serialization_release_lock(
204 				&pdev_queue->pdev_queue_lock);
205 			goto error;
206 		}
207 
208 		if (vdev_queue->queue_disable) {
209 			wlan_serialization_release_lock(
210 				&pdev_queue->pdev_queue_lock);
211 			ser_err("VDEV queue is disabled, ser request denied");
212 			ser_err("cmd id[%d] cmd type[%d]", cmd->cmd_id,
213 				cmd->cmd_type);
214 			status = WLAN_SER_CMD_QUEUE_DISABLED;
215 			goto error;
216 		}
217 	}
218 
219 	active_queue = wlan_serialization_is_active_cmd_allowed(cmd);
220 
221 	if (wlan_serialization_is_cmd_present_queue(cmd, active_queue)) {
222 		wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock);
223 		ser_err("duplicate command, can't enqueue");
224 		goto error;
225 	}
226 
227 	if (wlan_serialization_remove_front(
228 				&pdev_queue->cmd_pool_list,
229 				&nnode) != QDF_STATUS_SUCCESS) {
230 		wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock);
231 		ser_err("Failed to get cmd buffer from global pool");
232 		status = WLAN_SER_CMD_DENIED_LIST_FULL;
233 		goto error;
234 	}
235 
236 	ser_debug("Global pool node: %pK", nnode);
237 
238 	cmd_list =
239 		qdf_container_of(nnode,
240 				 struct wlan_serialization_command_list,
241 				 pdev_node);
242 
243 	qdf_mem_copy(&cmd_list->cmd, cmd,
244 		     sizeof(struct wlan_serialization_command));
245 
246 	if (cmd->cmd_type < WLAN_SER_CMD_NONSCAN) {
247 		status = wlan_ser_add_scan_cmd(ser_pdev_obj,
248 					       cmd_list,
249 					       active_queue);
250 	} else {
251 		status = wlan_ser_add_non_scan_cmd(ser_pdev_obj,
252 						   cmd_list,
253 						   active_queue);
254 	}
255 
256 	if (status != WLAN_SER_CMD_PENDING && status != WLAN_SER_CMD_ACTIVE) {
257 		qdf_mem_zero(&cmd_list->cmd,
258 			     sizeof(struct wlan_serialization_command));
259 		cmd_list->cmd_in_use = 0;
260 		wlan_serialization_insert_back(
261 			&pdev_queue->cmd_pool_list,
262 			&cmd_list->pdev_node);
263 		wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock);
264 		ser_err("Failed to add cmd to active/pending queue");
265 		goto error;
266 	}
267 
268 	if (WLAN_SER_CMD_ACTIVE == status) {
269 		qdf_atomic_set_bit(CMD_MARKED_FOR_ACTIVATION,
270 				   &cmd_list->cmd_in_use);
271 	}
272 
273 	wlan_ser_update_cmd_history(pdev_queue, &cmd_list->cmd,
274 				    ser_reason, true, active_queue);
275 
276 	wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock);
277 
278 	if (WLAN_SER_CMD_ACTIVE == status)
279 		wlan_serialization_activate_cmd(cmd_list,
280 						ser_pdev_obj, ser_reason);
281 
282 error:
283 	ser_exit();
284 
285 	return status;
286 }
287 
288 QDF_STATUS wlan_serialization_activate_cmd(
289 			struct wlan_serialization_command_list *cmd_list,
290 			struct wlan_ser_pdev_obj *ser_pdev_obj,
291 			enum ser_queue_reason ser_reason)
292 {
293 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
294 	struct wlan_objmgr_psoc *psoc = NULL;
295 	struct wlan_serialization_pdev_queue *pdev_queue;
296 
297 	pdev_queue = wlan_serialization_get_pdev_queue_obj(
298 			ser_pdev_obj, cmd_list->cmd.cmd_type);
299 
300 	psoc = wlan_vdev_get_psoc(cmd_list->cmd.vdev);
301 	if (!psoc) {
302 		ser_err("invalid psoc");
303 		goto error;
304 	}
305 
306 	/*
307 	 * command is already pushed to active queue above
308 	 * now start the timer and notify requestor
309 	 */
310 
311 	status = wlan_serialization_find_and_start_timer(psoc, &cmd_list->cmd,
312 							 ser_reason);
313 	if (QDF_IS_STATUS_ERROR(status)) {
314 		ser_err("Failed to start timer cmd type[%d] id[%d] vdev[%d]",
315 			cmd_list->cmd.cmd_type,
316 			cmd_list->cmd.cmd_id,
317 			wlan_vdev_get_id(cmd_list->cmd.vdev));
318 		goto timer_failed;
319 	}
320 
321 	/*
322 	 * Remember that serialization module may send
323 	 * this callback in same context through which it
324 	 * received the serialization request. Due to which
325 	 * it is caller's responsibility to ensure acquiring
326 	 * and releasing its own lock appropriately.
327 	 */
328 
329 	ser_debug("cmd cb: type[%d] id[%d] : reason: %s",
330 		  cmd_list->cmd.cmd_type,
331 		  cmd_list->cmd.cmd_id,
332 		  "WLAN_SER_CB_ACTIVATE_CMD");
333 
334 	cmd_list->cmd.activation_reason = ser_reason;
335 
336 	status = cmd_list->cmd.cmd_cb(&cmd_list->cmd,
337 				WLAN_SER_CB_ACTIVATE_CMD);
338 
339 	wlan_serialization_acquire_lock(&pdev_queue->pdev_queue_lock);
340 
341 	qdf_atomic_clear_bit(CMD_MARKED_FOR_ACTIVATION,
342 			     &cmd_list->cmd_in_use);
343 	qdf_atomic_set_bit(CMD_IS_ACTIVE,
344 			   &cmd_list->cmd_in_use);
345 
346 	wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock);
347 
348 timer_failed:
349 	if (QDF_IS_STATUS_ERROR(status)) {
350 		wlan_serialization_dequeue_cmd(&cmd_list->cmd,
351 					       SER_ACTIVATION_FAILED,
352 					       true);
353 		return status;
354 	}
355 
356 	/*
357 	 * Cmd was marked for activation and delete or cancel
358 	 * is received before activation completed, then the command
359 	 * should be immediately removed after activation
360 	 */
361 	if (qdf_atomic_test_bit(CMD_ACTIVE_MARKED_FOR_REMOVAL,
362 				&cmd_list->cmd_in_use)) {
363 		wlan_serialization_dequeue_cmd(&cmd_list->cmd,
364 					       SER_REMOVE,
365 					       true);
366 		return status;
367 	}
368 
369 	if (qdf_atomic_test_bit(CMD_ACTIVE_MARKED_FOR_CANCEL,
370 				&cmd_list->cmd_in_use))
371 		wlan_serialization_cmd_cancel_handler(
372 				ser_pdev_obj, &cmd_list->cmd,
373 				NULL, NULL, cmd_list->cmd.cmd_type,
374 				WLAN_SERIALIZATION_ACTIVE_QUEUE);
375 error:
376 	return status;
377 }
378 
379 bool
380 wlan_serialization_is_active_cmd_allowed(struct wlan_serialization_command *cmd)
381 {
382 	struct wlan_objmgr_pdev *pdev;
383 	bool active_cmd_allowed = 0;
384 
385 	pdev = wlan_serialization_get_pdev_from_cmd(cmd);
386 	if (!pdev) {
387 		ser_err("NULL pdev");
388 		goto error;
389 	}
390 
391 	if (cmd->cmd_type < WLAN_SER_CMD_NONSCAN)
392 		active_cmd_allowed =
393 		(wlan_serialization_is_active_scan_cmd_allowed(cmd) &&
394 			wlan_serialization_is_scan_pending_queue_empty(cmd));
395 	else
396 		active_cmd_allowed =
397 		(wlan_serialization_is_active_non_scan_cmd_allowed(cmd) &&
398 		 wlan_serialization_is_non_scan_pending_queue_empty(cmd));
399 
400 	ser_debug("active cmd_type[%d] cmd_id[%d] allowed: %d",
401 		  cmd->cmd_type,
402 		  cmd->cmd_id,
403 		  active_cmd_allowed);
404 
405 error:
406 	return active_cmd_allowed;
407 }
408 
409 enum wlan_serialization_status
410 wlan_serialization_move_pending_to_active(
411 		enum wlan_serialization_cmd_type cmd_type,
412 		struct wlan_ser_pdev_obj *ser_pdev_obj,
413 		struct wlan_objmgr_vdev *vdev,
414 		bool blocking_cmd_removed)
415 {
416 	enum wlan_serialization_status status;
417 
418 	if (cmd_type < WLAN_SER_CMD_NONSCAN) {
419 		status =
420 		wlan_ser_move_scan_pending_to_active(
421 				ser_pdev_obj);
422 	} else {
423 		status =
424 		wlan_ser_move_non_scan_pending_to_active(
425 				ser_pdev_obj,
426 				vdev,
427 				blocking_cmd_removed);
428 	}
429 
430 	return status;
431 }
432 
433 enum wlan_serialization_cmd_status
434 wlan_serialization_dequeue_cmd(struct wlan_serialization_command *cmd,
435 			       enum ser_queue_reason ser_reason,
436 			       uint8_t active_cmd)
437 {
438 	enum wlan_serialization_cmd_status status =
439 		WLAN_SER_CMD_NOT_FOUND;
440 	enum wlan_serialization_status ser_status =
441 		WLAN_SER_CMD_DENIED_UNSPECIFIED;
442 
443 	QDF_STATUS qdf_status;
444 	struct wlan_objmgr_pdev *pdev;
445 	struct wlan_objmgr_psoc *psoc;
446 	struct wlan_ser_pdev_obj *ser_pdev_obj;
447 	struct wlan_serialization_command cmd_bkup;
448 	struct wlan_serialization_command_list *cmd_list;
449 	struct wlan_serialization_pdev_queue *pdev_queue;
450 	bool blocking_cmd_removed = 0;
451 
452 	ser_enter();
453 
454 	if (!cmd) {
455 		ser_err("NULL command");
456 		goto error;
457 	}
458 
459 	pdev = wlan_serialization_get_pdev_from_cmd(cmd);
460 	if (!pdev) {
461 		ser_err("invalid pdev");
462 		goto error;
463 	}
464 
465 	psoc = wlan_pdev_get_psoc(pdev);
466 	if (!psoc) {
467 		ser_err("invalid psoc");
468 		goto error;
469 	}
470 
471 	ser_pdev_obj = wlan_serialization_get_pdev_obj(pdev);
472 	if (!ser_pdev_obj) {
473 		ser_err("ser_pdev_obj is empty");
474 		goto error;
475 	}
476 
477 	pdev_queue = wlan_serialization_get_pdev_queue_obj(
478 			ser_pdev_obj, cmd->cmd_type);
479 
480 	ser_debug("dequeue cmd: type[%d] id[%d] high_priority[%d] blocking[%d]",
481 		  cmd->cmd_type,
482 		  cmd->cmd_id,
483 		  cmd->is_high_priority,
484 		  cmd->is_blocking);
485 
486 	wlan_serialization_acquire_lock(&pdev_queue->pdev_queue_lock);
487 
488 	if (cmd->cmd_type < WLAN_SER_CMD_NONSCAN)
489 		qdf_status = wlan_ser_remove_scan_cmd(
490 				ser_pdev_obj, &cmd_list, cmd, active_cmd);
491 	else {
492 		qdf_status = wlan_ser_remove_non_scan_cmd(
493 				ser_pdev_obj, &cmd_list, cmd, active_cmd);
494 	}
495 
496 	if (qdf_status == QDF_STATUS_E_PENDING) {
497 		status = WLAN_SER_CMD_MARKED_FOR_ACTIVATION;
498 		wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock);
499 		goto error;
500 	}
501 
502 	if (qdf_status != QDF_STATUS_SUCCESS) {
503 		wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock);
504 		status = WLAN_SER_CMD_NOT_FOUND;
505 		goto error;
506 	}
507 
508 	if (active_cmd) {
509 		if (cmd_list->cmd.cmd_type >= WLAN_SER_CMD_NONSCAN)
510 			blocking_cmd_removed = cmd_list->cmd.is_blocking;
511 	}
512 
513 	if (active_cmd)
514 		wlan_serialization_find_and_stop_timer(
515 				psoc, &cmd_list->cmd,
516 				ser_reason);
517 
518 	qdf_mem_copy(&cmd_bkup, &cmd_list->cmd,
519 		     sizeof(struct wlan_serialization_command));
520 	qdf_mem_zero(&cmd_list->cmd,
521 		     sizeof(struct wlan_serialization_command));
522 	cmd_list->cmd_in_use = 0;
523 	qdf_status = wlan_serialization_insert_back(
524 			&pdev_queue->cmd_pool_list,
525 			&cmd_list->pdev_node);
526 
527 	wlan_ser_update_cmd_history(pdev_queue, &cmd_bkup, ser_reason,
528 				    false, active_cmd);
529 
530 	wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock);
531 
532 	/* Call cmd cb for remove request*/
533 	if (cmd_bkup.cmd_cb) {
534 		/* caller should release the memory */
535 		ser_debug("cmd cb: type[%d] id[%d]: reason: %s",
536 			  cmd_bkup.cmd_type,
537 			  cmd_bkup.cmd_id,
538 			  "WLAN_SER_CB_RELEASE_MEM_CMD");
539 		cmd_bkup.cmd_cb(&cmd_bkup,
540 				     WLAN_SER_CB_RELEASE_MEM_CMD);
541 	}
542 
543 	if (active_cmd) {
544 		ser_status = wlan_serialization_move_pending_to_active(
545 			cmd_bkup.cmd_type, ser_pdev_obj,
546 			cmd_bkup.vdev,
547 			blocking_cmd_removed);
548 	}
549 
550 	if (active_cmd)
551 		status = WLAN_SER_CMD_IN_ACTIVE_LIST;
552 	else
553 		status = WLAN_SER_CMD_IN_PENDING_LIST;
554 
555 error:
556 	ser_exit();
557 	return status;
558 }
559 
560 void wlan_serialization_generic_timer_cb(void *arg)
561 {
562 	struct wlan_serialization_timer *timer = arg;
563 	struct wlan_serialization_command *cmd = timer->cmd;
564 	struct wlan_objmgr_vdev *vdev = NULL;
565 
566 
567 	if (!cmd) {
568 		ser_err("Command not found");
569 		return;
570 	}
571 
572 	vdev = cmd->vdev;
573 	if (!vdev) {
574 		ser_err("Invalid vdev");
575 		return;
576 	}
577 
578 	ser_err("active cmd timeout for cmd_type[%d] vdev[%d]",
579 		cmd->cmd_type, wlan_vdev_get_id(cmd->vdev));
580 
581 	if (cmd->cmd_cb)
582 		cmd->cmd_cb(cmd, WLAN_SER_CB_ACTIVE_CMD_TIMEOUT);
583 
584 	/*
585 	 * dequeue cmd API will cleanup and destroy the timer. If it fails to
586 	 * dequeue command then we have to destroy the timer.
587 	 */
588 	wlan_serialization_dequeue_cmd(cmd, SER_TIMEOUT, true);
589 
590 	/* Release the ref taken before the timer was started */
591 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SERIALIZATION_ID);
592 }
593 
594 static QDF_STATUS wlan_serialization_mc_flush_noop(struct scheduler_msg *msg)
595 {
596 	return QDF_STATUS_SUCCESS;
597 }
598 
599 static void
600 wlan_serialization_timer_cb_mc_ctx(void *arg)
601 {
602 	struct scheduler_msg msg = {0};
603 
604 	msg.type = SYS_MSG_ID_MC_TIMER;
605 	msg.reserved = SYS_MSG_COOKIE;
606 	msg.callback = wlan_serialization_generic_timer_cb;
607 	msg.bodyptr = arg;
608 	msg.bodyval = 0;
609 	msg.flush_callback = wlan_serialization_mc_flush_noop;
610 
611 	if (scheduler_post_message(QDF_MODULE_ID_SERIALIZATION,
612 				   QDF_MODULE_ID_SERIALIZATION,
613 				   QDF_MODULE_ID_SYS, &msg) ==
614 							QDF_STATUS_SUCCESS)
615 		return;
616 
617 	ser_err("Could not enqueue timer to timer queue");
618 }
619 
620 static void wlan_serialization_timer_handler(void *arg)
621 {
622 	struct wlan_serialization_timer *timer = arg;
623 	struct wlan_serialization_command *cmd = timer->cmd;
624 
625 	if (!cmd) {
626 		ser_err("Command not found");
627 		return;
628 	}
629 
630 	ser_err("active cmd timeout for cmd_type[%d] vdev[%d]",
631 		cmd->cmd_type, wlan_vdev_get_id(cmd->vdev));
632 
633 	wlan_serialization_timer_cb_mc_ctx(arg);
634 
635 }
636 
637 QDF_STATUS
638 wlan_serialization_find_and_update_timer(
639 		struct wlan_objmgr_psoc *psoc,
640 		struct wlan_serialization_command *cmd)
641 {
642 	struct wlan_ser_psoc_obj *psoc_ser_obj;
643 	struct wlan_serialization_timer *ser_timer;
644 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
645 	int i = 0;
646 
647 	if (!psoc || !cmd) {
648 		ser_err("invalid param");
649 		goto exit;
650 	}
651 
652 	psoc_ser_obj = wlan_serialization_get_psoc_obj(psoc);
653 	/*
654 	 * Here cmd_id and cmd_type are used to locate the timer being
655 	 * associated with command.
656 	 */
657 	wlan_serialization_acquire_lock(&psoc_ser_obj->timer_lock);
658 
659 	for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) {
660 		ser_timer = &psoc_ser_obj->timers[i];
661 		if (!(ser_timer->cmd) ||
662 		    (ser_timer->cmd->cmd_id != cmd->cmd_id) ||
663 		    (ser_timer->cmd->cmd_type != cmd->cmd_type) ||
664 		    (ser_timer->cmd->vdev != cmd->vdev))
665 			continue;
666 
667 		qdf_timer_mod(&ser_timer->timer,
668 			      cmd->cmd_timeout_duration);
669 		status = QDF_STATUS_SUCCESS;
670 		break;
671 	}
672 
673 	wlan_serialization_release_lock(&psoc_ser_obj->timer_lock);
674 
675 	if (QDF_IS_STATUS_SUCCESS(status))
676 		ser_debug("Updated the timer for cmd type:%d, id: %d",
677 			  cmd->cmd_type, cmd->cmd_id);
678 	else
679 		ser_debug("Can't find timer for cmd_type[%d]", cmd->cmd_type);
680 
681 exit:
682 	return status;
683 }
684 
685 QDF_STATUS
686 wlan_serialization_find_and_stop_timer(struct wlan_objmgr_psoc *psoc,
687 				       struct wlan_serialization_command *cmd,
688 				       enum ser_queue_reason ser_reason)
689 {
690 	struct wlan_ser_psoc_obj *psoc_ser_obj;
691 	struct wlan_serialization_timer *ser_timer;
692 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
693 	int i = 0;
694 	uint32_t phy_version;
695 	struct wlan_objmgr_vdev *vdev;
696 
697 	if (!psoc || !cmd) {
698 		ser_err("invalid param");
699 		goto exit;
700 	}
701 
702 	if (cmd->cmd_timeout_duration == 0) {
703 		phy_version = wlan_psoc_get_nif_phy_version(psoc);
704 		if (wlan_is_emulation_platform(phy_version)) {
705 			ser_err("[SCAN-EMULATION]: Not performing timer funcs");
706 			status = QDF_STATUS_SUCCESS;
707 		goto exit;
708 		}
709 	}
710 
711 	psoc_ser_obj = wlan_serialization_get_psoc_obj(psoc);
712 	/*
713 	 * Here cmd_id and cmd_type are used to locate the timer being
714 	 * associated with command.
715 	 */
716 	wlan_serialization_acquire_lock(&psoc_ser_obj->timer_lock);
717 
718 	for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) {
719 		ser_timer = &psoc_ser_obj->timers[i];
720 		if (!(ser_timer->cmd) ||
721 		    (ser_timer->cmd->cmd_id != cmd->cmd_id) ||
722 		    (ser_timer->cmd->cmd_type != cmd->cmd_type) ||
723 		    (ser_timer->cmd->vdev != cmd->vdev))
724 			continue;
725 
726 		vdev = ser_timer->cmd->vdev;
727 		status = wlan_serialization_stop_timer(ser_timer);
728 		/*
729 		 * Release the vdev reference when the active cmd is removed
730 		 * through remove/cancel request.
731 		 *
732 		 * In case the command removal is because of timer expiry,
733 		 * the vdev is released when the timer handler completes.
734 		 */
735 		if (vdev && ser_reason != SER_TIMEOUT)
736 			wlan_objmgr_vdev_release_ref(
737 					vdev, WLAN_SERIALIZATION_ID);
738 
739 		break;
740 
741 	}
742 
743 	wlan_serialization_release_lock(&psoc_ser_obj->timer_lock);
744 
745 	if (QDF_IS_STATUS_SUCCESS(status))
746 		ser_debug("Stopped timer for cmd_type %d cmd id %d",
747 			  cmd->cmd_type, cmd->cmd_id);
748 	else
749 		ser_err("Can't find timer for cmd_type %d cmd id %d",
750 			cmd->cmd_type, cmd->cmd_id);
751 
752 exit:
753 	return status;
754 }
755 
756 QDF_STATUS
757 wlan_serialization_find_and_start_timer(struct wlan_objmgr_psoc *psoc,
758 					struct wlan_serialization_command *cmd,
759 					enum ser_queue_reason ser_reason)
760 {
761 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
762 	struct wlan_ser_psoc_obj *psoc_ser_obj;
763 	struct wlan_serialization_timer *ser_timer;
764 	int i = 0;
765 	uint32_t nif_phy_ver;
766 
767 	if (!psoc || !cmd) {
768 		ser_err("invalid param");
769 		goto error;
770 	}
771 
772 	nif_phy_ver = wlan_psoc_get_nif_phy_version(psoc);
773 	if ((cmd->cmd_timeout_duration == 0) &&
774 	    (wlan_is_emulation_platform(nif_phy_ver))) {
775 		ser_err("[SCAN-EMULATION]: Not performing timer functions\n");
776 		status = QDF_STATUS_SUCCESS;
777 		goto exit;
778 	}
779 
780 	psoc_ser_obj = wlan_serialization_get_psoc_obj(psoc);
781 
782 	wlan_serialization_acquire_lock(&psoc_ser_obj->timer_lock);
783 
784 	for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) {
785 		/* Keep trying timer */
786 		ser_timer = &psoc_ser_obj->timers[i];
787 		if (ser_timer->cmd)
788 			continue;
789 
790 		/* Remember timer is pointing to command */
791 		ser_timer->cmd = cmd;
792 		status = QDF_STATUS_SUCCESS;
793 
794 		/*
795 		 * Get vdev reference before starting the timer
796 		 * Remove the reference before removing the command
797 		 * in any one of the cases:
798 		 * 1. Active command is removed through remove/cancel request
799 		 * 2. Timer expiry handler is completed.
800 		 */
801 
802 		status = wlan_objmgr_vdev_try_get_ref(ser_timer->cmd->vdev,
803 						      WLAN_SERIALIZATION_ID);
804 		if (QDF_IS_STATUS_ERROR(status)) {
805 			wlan_serialization_release_lock(
806 					&psoc_ser_obj->timer_lock);
807 			ser_err("Unbale to get vdev reference");
808 			status = QDF_STATUS_E_FAILURE;
809 			goto error;
810 		}
811 		break;
812 	}
813 
814 	wlan_serialization_release_lock(&psoc_ser_obj->timer_lock);
815 
816 	if (QDF_IS_STATUS_SUCCESS(status)) {
817 		qdf_timer_init(NULL,
818 			       &ser_timer->timer,
819 			       wlan_serialization_timer_handler,
820 			       ser_timer,
821 			       QDF_TIMER_TYPE_SW);
822 			       qdf_timer_mod(&ser_timer->timer,
823 			       cmd->cmd_timeout_duration);
824 
825 		ser_debug("Started timer for cmd: type[%d] id[%d] high_priority[%d] blocking[%d]",
826 			  cmd->cmd_type,
827 			  cmd->cmd_id,
828 			  cmd->is_high_priority,
829 			  cmd->is_blocking);
830 	} else {
831 		ser_err("Failed to start timer for cmd: type[%d] id[%d] high_priority[%d] blocking[%d]",
832 			  cmd->cmd_type,
833 			  cmd->cmd_id,
834 			  cmd->is_high_priority,
835 			  cmd->is_blocking);
836 	}
837 
838 error:
839 exit:
840 	return status;
841 }
842 
843 enum wlan_serialization_cmd_status
844 wlan_serialization_cmd_cancel_handler(
845 		struct wlan_ser_pdev_obj *ser_obj,
846 		struct wlan_serialization_command *cmd,
847 		struct wlan_objmgr_pdev *pdev, struct wlan_objmgr_vdev *vdev,
848 		enum wlan_serialization_cmd_type cmd_type, uint8_t queue_type)
849 {
850 	enum wlan_serialization_cmd_status active_status =
851 		WLAN_SER_CMD_NOT_FOUND;
852 	enum wlan_serialization_cmd_status pending_status =
853 		WLAN_SER_CMD_NOT_FOUND;
854 	enum wlan_serialization_cmd_status status =
855 		WLAN_SER_CMD_NOT_FOUND;
856 
857 	ser_enter();
858 
859 	if (!ser_obj) {
860 		ser_err("invalid serial object");
861 		goto error;
862 	}
863 
864 	if (queue_type & WLAN_SERIALIZATION_ACTIVE_QUEUE) {
865 		if (cmd_type < WLAN_SER_CMD_NONSCAN)
866 			active_status = wlan_ser_cancel_scan_cmd(
867 					ser_obj, pdev, vdev, cmd,
868 					cmd_type, true);
869 		else
870 			active_status = wlan_ser_cancel_non_scan_cmd(
871 					ser_obj, pdev, vdev, cmd,
872 					cmd_type, true);
873 	}
874 
875 	if (queue_type & WLAN_SERIALIZATION_PENDING_QUEUE) {
876 		if (cmd_type < WLAN_SER_CMD_NONSCAN)
877 			pending_status = wlan_ser_cancel_scan_cmd(
878 					ser_obj, pdev, vdev, cmd,
879 					cmd_type, false);
880 		else
881 			pending_status = wlan_ser_cancel_non_scan_cmd(
882 					ser_obj, pdev, vdev, cmd,
883 					cmd_type, false);
884 	}
885 
886 	if (active_status == WLAN_SER_CMD_IN_ACTIVE_LIST &&
887 	    pending_status == WLAN_SER_CMD_IN_PENDING_LIST)
888 		status = WLAN_SER_CMDS_IN_ALL_LISTS;
889 	else if (active_status == WLAN_SER_CMD_IN_ACTIVE_LIST)
890 		status = active_status;
891 	else if (pending_status == WLAN_SER_CMD_IN_PENDING_LIST)
892 		status = pending_status;
893 
894 error:
895 	ser_exit();
896 	return status;
897 }
898 
899 enum wlan_serialization_cmd_status
900 wlan_serialization_find_and_cancel_cmd(
901 		struct wlan_serialization_command *cmd,
902 		enum wlan_serialization_cancel_type req_type,
903 		uint8_t queue_type)
904 {
905 	enum wlan_serialization_cmd_status status = WLAN_SER_CMD_NOT_FOUND;
906 	struct wlan_ser_pdev_obj *ser_obj = NULL;
907 	struct wlan_objmgr_pdev *pdev;
908 
909 	ser_enter();
910 
911 	if (!cmd) {
912 		ser_err("Invalid cmd");
913 		goto error;
914 	}
915 
916 	pdev = wlan_serialization_get_pdev_from_cmd(cmd);
917 	if (!pdev) {
918 		ser_err("Invalid pdev");
919 		goto error;
920 	}
921 	ser_obj = wlan_serialization_get_pdev_obj(pdev);
922 	if (!ser_obj) {
923 		ser_err("Invalid ser_obj");
924 		goto error;
925 	}
926 
927 	switch (req_type) {
928 	case WLAN_SER_CANCEL_SINGLE_SCAN:
929 		/* remove scan cmd which matches the given cmd struct */
930 		status = wlan_serialization_cmd_cancel_handler(
931 				ser_obj, cmd, NULL, NULL,
932 				WLAN_SER_CMD_SCAN, queue_type);
933 		break;
934 	case WLAN_SER_CANCEL_PDEV_SCANS:
935 		/* remove all scan cmds which matches the pdev object */
936 		status = wlan_serialization_cmd_cancel_handler(
937 				ser_obj, NULL, pdev, NULL,
938 				WLAN_SER_CMD_SCAN, queue_type);
939 		break;
940 	case WLAN_SER_CANCEL_VDEV_SCANS:
941 		/* remove all scan cmds which matches the vdev object */
942 		status = wlan_serialization_cmd_cancel_handler(
943 				ser_obj, NULL, NULL, cmd->vdev,
944 				WLAN_SER_CMD_SCAN, queue_type);
945 		break;
946 	case WLAN_SER_CANCEL_NON_SCAN_CMD:
947 		/* remove nonscan cmd which matches the given cmd */
948 		status = wlan_serialization_cmd_cancel_handler(
949 				ser_obj, cmd, NULL, NULL,
950 				WLAN_SER_CMD_NONSCAN, queue_type);
951 		break;
952 	case WLAN_SER_CANCEL_PDEV_NON_SCAN_CMD:
953 		/* remove all non scan cmds which matches the pdev object */
954 		status = wlan_serialization_cmd_cancel_handler(
955 				ser_obj, NULL, pdev, NULL,
956 				WLAN_SER_CMD_NONSCAN, queue_type);
957 		break;
958 	case WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD:
959 		/* remove all non scan cmds which matches the vdev object */
960 		status = wlan_serialization_cmd_cancel_handler(
961 				ser_obj, NULL, NULL, cmd->vdev,
962 				WLAN_SER_CMD_NONSCAN, queue_type);
963 		break;
964 	case WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD_TYPE:
965 		/*
966 		 * remove all non scan cmds which matches the vdev
967 		 * and given cmd type
968 		 */
969 		status = wlan_serialization_cmd_cancel_handler(
970 				ser_obj, NULL, NULL, cmd->vdev,
971 				cmd->cmd_type, queue_type);
972 		break;
973 	default:
974 		ser_err("Invalid request");
975 	}
976 
977 error:
978 	ser_exit();
979 	return status;
980 }
981