xref: /wlan-dirver/qca-wifi-host-cmn/umac/cmn_services/serialization/src/wlan_serialization_internal.c (revision 302a1d9701784af5f4797b1a9fe07ae820b51907)
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  * 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 {
91 	enum wlan_serialization_status status = WLAN_SER_CMD_DENIED_UNSPECIFIED;
92 	struct wlan_serialization_command_list *cmd_list;
93 	qdf_list_node_t *nnode;
94 	struct wlan_objmgr_pdev *pdev;
95 	struct wlan_ser_pdev_obj *ser_pdev_obj;
96 	struct wlan_serialization_pdev_queue *pdev_queue;
97 	bool active_queue;
98 
99 	/* Enqueue process
100 	 * 1) peek through command structure and see what is the command type
101 	 * 2) two main types of commands to process
102 	 *    a) SCAN
103 	 *    b) NON-SCAN
104 	 * 3) for each command there are separate command queues per pdev
105 	 * 4) pull pdev from vdev structure and get the command queue associated
106 	 *    with that pdev and try to enqueue on those queue
107 	 * 5) Thumb rule:
108 	 *    a) There could be only 1 active non-scan command at a
109 	 *       time including all total non-scan commands of all pdevs.
110 	 *
111 	 *       example: pdev1 has 1 non-scan active command and
112 	 *       pdev2 got 1 non-scan command then that command should go to
113 	 *       pdev2's pending queue
114 	 *
115 	 *    b) There could be only N number of scan commands at a time
116 	 *       including all total scan commands of all pdevs
117 	 *
118 	 *       example: Let's say N=8,
119 	 *       pdev1's vdev1 has 5 scan command, pdev2's vdev1 has 3
120 	 *       scan commands, if we get scan request on vdev2 then it will go
121 	 *       to pending queue of vdev2 as we reached max allowed scan active
122 	 *       command.
123 	 */
124 
125 	ser_enter();
126 
127 	if (!cmd) {
128 		ser_err("NULL command");
129 		goto error;
130 	}
131 
132 	if (!cmd->cmd_cb) {
133 		ser_err("no cmd_cb for cmd type:%d, id: %d",
134 			cmd->cmd_type,
135 			cmd->cmd_id);
136 		goto error;
137 	}
138 
139 	pdev = wlan_serialization_get_pdev_from_cmd(cmd);
140 	if (!pdev) {
141 		ser_err("pdev is invalid");
142 		goto error;
143 	}
144 
145 	ser_pdev_obj =
146 		wlan_objmgr_pdev_get_comp_private_obj(
147 				pdev,
148 				WLAN_UMAC_COMP_SERIALIZATION);
149 	if (!ser_pdev_obj) {
150 		ser_err("Invalid ser_pdev_obj");
151 		goto error;
152 	}
153 
154 	pdev_queue = wlan_serialization_get_pdev_queue_obj(ser_pdev_obj,
155 							   cmd->cmd_type);
156 	if (!pdev_queue) {
157 		ser_err("pdev_queue is invalid");
158 		goto error;
159 	}
160 
161 	ser_debug("enqueue cmd: type[%d] id[%d] high_priority[%d] blocking[%d]",
162 		  cmd->cmd_type,
163 		  cmd->cmd_id,
164 		  cmd->is_high_priority,
165 		  cmd->is_blocking);
166 
167 	wlan_serialization_acquire_lock(pdev_queue);
168 
169 	active_queue = wlan_serialization_is_active_cmd_allowed(cmd);
170 
171 	if (wlan_serialization_is_cmd_present_queue(cmd, active_queue)) {
172 		wlan_serialization_release_lock(pdev_queue);
173 		ser_err("duplicate command, can't enqueue");
174 		goto error;
175 	}
176 
177 	if (wlan_serialization_remove_front(
178 				&pdev_queue->cmd_pool_list,
179 				&nnode) != QDF_STATUS_SUCCESS) {
180 		wlan_serialization_release_lock(pdev_queue);
181 		ser_err("Failed to get cmd buffer from global pool");
182 		goto error;
183 	}
184 
185 	ser_debug("Global pool node: %pK", nnode);
186 
187 	cmd_list =
188 		qdf_container_of(nnode,
189 				 struct wlan_serialization_command_list,
190 				 pdev_node);
191 
192 	qdf_mem_copy(&cmd_list->cmd, cmd,
193 		     sizeof(struct wlan_serialization_command));
194 
195 	if (cmd->cmd_type < WLAN_SER_CMD_NONSCAN) {
196 		status = wlan_ser_add_scan_cmd(ser_pdev_obj,
197 					       cmd_list,
198 					       active_queue);
199 	} else {
200 		status = wlan_ser_add_non_scan_cmd(ser_pdev_obj,
201 						   cmd_list,
202 						   active_queue);
203 	}
204 
205 	if (status != WLAN_SER_CMD_PENDING && status != WLAN_SER_CMD_ACTIVE) {
206 		ser_err("Failed to add cmd to active/pending queue");
207 		qdf_mem_zero(&cmd_list->cmd,
208 			     sizeof(struct wlan_serialization_command));
209 		wlan_serialization_insert_back(
210 			&pdev_queue->cmd_pool_list,
211 			&cmd_list->pdev_node);
212 	}
213 
214 	if (WLAN_SER_CMD_ACTIVE == status) {
215 		qdf_atomic_set_bit(CMD_MARKED_FOR_ACTIVATION,
216 				   &cmd_list->cmd_in_use);
217 	}
218 
219 	wlan_serialization_release_lock(pdev_queue);
220 
221 	if (WLAN_SER_CMD_ACTIVE == status)
222 		wlan_serialization_activate_cmd(cmd_list,
223 						ser_pdev_obj);
224 
225 error:
226 	ser_exit();
227 
228 	return status;
229 }
230 
231 QDF_STATUS
232 wlan_serialization_activate_multiple_cmd(
233 		struct wlan_ser_pdev_obj *ser_pdev_obj)
234 {
235 	struct wlan_serialization_pdev_queue *pdev_queue;
236 	qdf_list_t *active_queue;
237 	QDF_STATUS peek_status = QDF_STATUS_E_FAILURE;
238 	struct wlan_serialization_command_list *active_cmd_list;
239 	uint32_t qsize;
240 	uint32_t vdev_id;
241 	qdf_list_node_t *nnode = NULL;
242 	QDF_STATUS status = QDF_STATUS_SUCCESS;
243 	struct wlan_objmgr_psoc *psoc = NULL;
244 
245 	pdev_queue = &ser_pdev_obj->pdev_q[SER_PDEV_QUEUE_COMP_NON_SCAN];
246 	active_queue = &pdev_queue->active_list;
247 
248 	qsize =  wlan_serialization_list_size(active_queue);
249 	while (qsize--) {
250 		peek_status = wlan_serialization_get_cmd_from_queue(
251 				active_queue, &nnode);
252 
253 		if (peek_status != QDF_STATUS_SUCCESS) {
254 			ser_err("can't peek cmd");
255 			break;
256 		}
257 
258 		active_cmd_list = qdf_container_of(
259 				nnode, struct wlan_serialization_command_list,
260 				pdev_node);
261 
262 		if (!qdf_atomic_test_bit(CMD_MARKED_FOR_ACTIVATION,
263 					 &active_cmd_list->cmd_in_use)) {
264 			continue;
265 		}
266 
267 		/*
268 		 * Command is already pushed to active queue.
269 		 * Now start the timer.
270 		 */
271 		psoc = wlan_vdev_get_psoc(active_cmd_list->cmd.vdev);
272 		wlan_serialization_find_and_start_timer(psoc,
273 							&active_cmd_list->cmd);
274 
275 		ser_debug("cmd cb: type[%d] id[%d] : reason: %s",
276 			  active_cmd_list->cmd.cmd_type,
277 			  active_cmd_list->cmd.cmd_id,
278 			  "WLAN_SER_CB_ACTIVATE_CMD");
279 
280 		status = active_cmd_list->cmd.cmd_cb(&active_cmd_list->cmd,
281 					    WLAN_SER_CB_ACTIVATE_CMD);
282 
283 		qdf_atomic_clear_bit(CMD_MARKED_FOR_ACTIVATION,
284 				     &active_cmd_list->cmd_in_use);
285 
286 		qdf_atomic_set_bit(CMD_IS_ACTIVE,
287 				   &active_cmd_list->cmd_in_use);
288 
289 		vdev_id = wlan_vdev_get_id(active_cmd_list->cmd.vdev);
290 		pdev_queue->vdev_active_cmd_bitmap |= (1 << vdev_id);
291 
292 		if (active_cmd_list->cmd.is_blocking)
293 			pdev_queue->blocking_cmd_active = 1;
294 
295 		if (QDF_IS_STATUS_ERROR(status))
296 			wlan_serialization_dequeue_cmd(&active_cmd_list->cmd,
297 						       true);
298 	}
299 	return status;
300 }
301 
302 QDF_STATUS wlan_serialization_activate_cmd(
303 			struct wlan_serialization_command_list *cmd_list,
304 			struct wlan_ser_pdev_obj *ser_pdev_obj)
305 {
306 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
307 	struct wlan_objmgr_psoc *psoc = NULL;
308 
309 	psoc = wlan_vdev_get_psoc(cmd_list->cmd.vdev);
310 	if (!psoc) {
311 		ser_err("invalid psoc");
312 		goto error;
313 	}
314 
315 	/*
316 	 * command is already pushed to active queue above
317 	 * now start the timer and notify requestor
318 	 */
319 	wlan_serialization_find_and_start_timer(psoc, &cmd_list->cmd);
320 	/*
321 	 * Remember that serialization module may send
322 	 * this callback in same context through which it
323 	 * received the serialization request. Due to which
324 	 * it is caller's responsibility to ensure acquiring
325 	 * and releasing its own lock appropriately.
326 	 */
327 
328 	ser_debug("cmd cb: type[%d] id[%d] : reason: %s",
329 		  cmd_list->cmd.cmd_type,
330 		  cmd_list->cmd.cmd_id,
331 		  "WLAN_SER_CB_ACTIVATE_CMD");
332 
333 	status = cmd_list->cmd.cmd_cb(&cmd_list->cmd,
334 				WLAN_SER_CB_ACTIVATE_CMD);
335 
336 	qdf_atomic_clear_bit(CMD_MARKED_FOR_ACTIVATION,
337 			     &cmd_list->cmd_in_use);
338 	qdf_atomic_set_bit(CMD_IS_ACTIVE,
339 			   &cmd_list->cmd_in_use);
340 
341 	if (QDF_IS_STATUS_ERROR(status))
342 		wlan_serialization_dequeue_cmd(&cmd_list->cmd, true);
343 
344 error:
345 	return status;
346 }
347 
348 bool
349 wlan_serialization_is_active_cmd_allowed(struct wlan_serialization_command *cmd)
350 {
351 	struct wlan_objmgr_pdev *pdev;
352 	bool active_cmd_allowed = 0;
353 
354 	pdev = wlan_serialization_get_pdev_from_cmd(cmd);
355 	if (!pdev) {
356 		ser_err("NULL pdev");
357 		goto error;
358 	}
359 
360 	if (cmd->cmd_type < WLAN_SER_CMD_NONSCAN)
361 		active_cmd_allowed =
362 			wlan_serialization_is_active_scan_cmd_allowed(cmd);
363 	else
364 		active_cmd_allowed =
365 			wlan_serialization_is_active_non_scan_cmd_allowed(cmd);
366 
367 	ser_debug("active cmd_type[%d] cmd_id[%d] allowed: %d",
368 		  cmd->cmd_type,
369 		  cmd->cmd_id,
370 		  active_cmd_allowed);
371 
372 error:
373 	return active_cmd_allowed;
374 }
375 
376 enum wlan_serialization_status
377 wlan_serialization_move_pending_to_active(
378 		enum wlan_serialization_cmd_type cmd_type,
379 		struct wlan_serialization_command_list **pcmd_list,
380 		struct wlan_ser_pdev_obj *ser_pdev_obj,
381 		struct wlan_objmgr_vdev *vdev,
382 		bool blocking_cmd_removed,
383 		bool blocking_cmd_waiting)
384 {
385 	enum wlan_serialization_status status;
386 	struct wlan_serialization_pdev_queue *pdev_queue;
387 
388 	if (cmd_type < WLAN_SER_CMD_NONSCAN) {
389 		status =
390 		wlan_ser_move_scan_pending_to_active(
391 				pcmd_list,
392 				ser_pdev_obj);
393 	} else {
394 		pdev_queue =
395 			&ser_pdev_obj->pdev_q[SER_PDEV_QUEUE_COMP_NON_SCAN];
396 
397 		if (!blocking_cmd_removed && !blocking_cmd_waiting)
398 			status =
399 			wlan_ser_move_non_scan_pending_to_active(
400 				pcmd_list,
401 				ser_pdev_obj,
402 				vdev);
403 		else
404 			status =
405 			wlan_ser_move_multiple_non_scan_pending_to_active(
406 				ser_pdev_obj);
407 	}
408 
409 	return status;
410 }
411 
412 enum wlan_serialization_cmd_status
413 wlan_serialization_dequeue_cmd(struct wlan_serialization_command *cmd,
414 			       uint8_t active_cmd)
415 {
416 	enum wlan_serialization_cmd_status status =
417 		WLAN_SER_CMD_NOT_FOUND;
418 	enum wlan_serialization_status ser_status =
419 		WLAN_SER_CMD_DENIED_UNSPECIFIED;
420 
421 	QDF_STATUS qdf_status;
422 	struct wlan_objmgr_pdev *pdev;
423 	struct wlan_objmgr_psoc *psoc;
424 	struct wlan_ser_pdev_obj *ser_pdev_obj;
425 	struct wlan_serialization_command cmd_bkup;
426 	struct wlan_serialization_command_list *cmd_list;
427 	struct wlan_serialization_command_list *pcmd_list;
428 	struct wlan_serialization_pdev_queue *pdev_queue;
429 	bool blocking_cmd_removed = 0;
430 	bool blocking_cmd_waiting = 0;
431 
432 	ser_enter();
433 
434 	if (!cmd) {
435 		ser_err("NULL command");
436 		goto error;
437 	}
438 
439 	pdev = wlan_serialization_get_pdev_from_cmd(cmd);
440 	if (!pdev) {
441 		ser_err("invalid pdev");
442 		goto error;
443 	}
444 
445 	psoc = wlan_pdev_get_psoc(pdev);
446 	if (!psoc) {
447 		ser_err("invalid psoc");
448 		goto error;
449 	}
450 
451 	ser_pdev_obj = wlan_serialization_get_pdev_obj(pdev);
452 	if (!ser_pdev_obj) {
453 		ser_err("ser_pdev_obj is empty");
454 		goto error;
455 	}
456 
457 	pdev_queue = wlan_serialization_get_pdev_queue_obj(
458 			ser_pdev_obj, cmd->cmd_type);
459 
460 	ser_debug("dequeue cmd: type[%d] id[%d] high_priority[%d] blocking[%d]",
461 		  cmd->cmd_type,
462 		  cmd->cmd_id,
463 		  cmd->is_high_priority,
464 		  cmd->is_blocking);
465 
466 	wlan_serialization_acquire_lock(pdev_queue);
467 
468 	if (cmd->cmd_type < WLAN_SER_CMD_NONSCAN)
469 		qdf_status = wlan_ser_remove_scan_cmd(
470 				ser_pdev_obj, &cmd_list, cmd, active_cmd);
471 	else {
472 		qdf_status = wlan_ser_remove_non_scan_cmd(
473 				ser_pdev_obj, &cmd_list, cmd, active_cmd);
474 	}
475 
476 	if (qdf_status != QDF_STATUS_SUCCESS) {
477 		wlan_serialization_release_lock(pdev_queue);
478 		status = WLAN_SER_CMD_NOT_FOUND;
479 		goto error;
480 	}
481 
482 	if (active_cmd) {
483 		wlan_serialization_find_and_stop_timer(psoc, &cmd_list->cmd);
484 
485 		if (cmd_list->cmd.cmd_type >= WLAN_SER_CMD_NONSCAN)
486 			blocking_cmd_removed = cmd_list->cmd.is_blocking;
487 	}
488 
489 	qdf_mem_copy(&cmd_bkup, &cmd_list->cmd,
490 		     sizeof(struct wlan_serialization_command));
491 	qdf_mem_zero(&cmd_list->cmd,
492 		     sizeof(struct wlan_serialization_command));
493 	qdf_status = wlan_serialization_insert_back(
494 			&pdev_queue->cmd_pool_list,
495 			&cmd_list->pdev_node);
496 
497 	/*
498 	 * For NON SCAN commands, the following is possible:
499 	 *
500 	 * If the remove is for non blocking command,
501 	 * and there is no blocking command waiting,
502 	 * look at vdev pending queue and
503 	 * only one command moves from pending
504 	 * to active
505 	 *
506 	 * If the remove is for blocking comamnd,
507 	 * look at the pdev queue and
508 	 * either single blocking command
509 	 * or multiple non blocking commands moves
510 	 * from pending to active
511 	 */
512 
513 	blocking_cmd_waiting = pdev_queue->blocking_cmd_waiting;
514 
515 	if (active_cmd) {
516 		ser_status = wlan_serialization_move_pending_to_active(
517 			cmd_bkup.cmd_type, &pcmd_list, ser_pdev_obj,
518 			cmd_bkup.vdev,
519 			blocking_cmd_removed,
520 			blocking_cmd_waiting);
521 	}
522 
523 	wlan_serialization_release_lock(pdev_queue);
524 
525 	/* Call cmd cb for remove request*/
526 	if (cmd_bkup.cmd_cb) {
527 		/* caller should release the memory */
528 		ser_debug("cmd cb: type[%d] id[%d]: reason: %s",
529 			  cmd_bkup.cmd_type,
530 			  cmd_bkup.cmd_id,
531 			  "WLAN_SER_CB_RELEASE_MEM_CMD");
532 		cmd_bkup.cmd_cb(&cmd_bkup,
533 				     WLAN_SER_CB_RELEASE_MEM_CMD);
534 	}
535 
536 	/*
537 	 * If the remove is for non blocking command,
538 	 * and there is no blocking command waiting,
539 	 * look at vdev pending queue and
540 	 * only one command moves from pending
541 	 * to active and gets activated
542 	 */
543 	if (WLAN_SER_CMD_ACTIVE == ser_status && !blocking_cmd_removed &&
544 	    !blocking_cmd_waiting) {
545 		ser_debug("cmd type[%d] id[%d] moved from pending to active",
546 			  pcmd_list->cmd.cmd_type,
547 			  pcmd_list->cmd.cmd_id);
548 		wlan_serialization_activate_cmd(pcmd_list,
549 						ser_pdev_obj);
550 	} else if (ser_status == WLAN_SER_CMD_ACTIVE) {
551 		/* If the remove is for blocking command
552 		 * either one or multiple commands can move
553 		 * from pending to active and gets activated
554 		 */
555 		wlan_serialization_activate_multiple_cmd(ser_pdev_obj);
556 	} else {
557 		goto exit;
558 	}
559 
560 exit:
561 	if (active_cmd)
562 		status = WLAN_SER_CMD_IN_ACTIVE_LIST;
563 	else
564 		status = WLAN_SER_CMD_IN_PENDING_LIST;
565 
566 error:
567 	ser_exit();
568 	return status;
569 }
570 
571 void wlan_serialization_generic_timer_cb(void *arg)
572 {
573 	struct wlan_serialization_timer *timer = arg;
574 	struct wlan_serialization_command *cmd = timer->cmd;
575 
576 	if (!cmd) {
577 		ser_err("command not found");
578 		QDF_ASSERT(0);
579 		return;
580 	}
581 
582 	ser_err("active cmd timeout for cmd_type[%d] vdev[%pK]",
583 		cmd->cmd_type, cmd->vdev);
584 
585 	if (cmd->cmd_cb)
586 		cmd->cmd_cb(cmd, WLAN_SER_CB_ACTIVE_CMD_TIMEOUT);
587 
588 	/*
589 	 * dequeue cmd API will cleanup and destroy the timer. If it fails to
590 	 * dequeue command then we have to destroy the timer.
591 	 */
592 	wlan_serialization_dequeue_cmd(cmd, true);
593 }
594 
595 static QDF_STATUS wlan_serialization_mc_flush_noop(struct scheduler_msg *msg)
596 {
597 	return QDF_STATUS_SUCCESS;
598 }
599 
600 static void
601 wlan_serialization_timer_cb_mc_ctx(void *arg)
602 {
603 	struct scheduler_msg msg = {0};
604 
605 	msg.type = SYS_MSG_ID_MC_TIMER;
606 	msg.reserved = SYS_MSG_COOKIE;
607 	msg.callback = wlan_serialization_generic_timer_cb;
608 	msg.bodyptr = arg;
609 	msg.bodyval = 0;
610 	msg.flush_callback = wlan_serialization_mc_flush_noop;
611 
612 	if (scheduler_post_msg(QDF_MODULE_ID_SYS, &msg) == QDF_STATUS_SUCCESS)
613 		return;
614 
615 	ser_err("Could not enqueue timer to timer queue");
616 }
617 
618 #ifdef CONFIG_MCL
619 static void wlan_serialization_timer_handler(void *arg)
620 {
621 	ser_enter();
622 
623 	wlan_serialization_timer_cb_mc_ctx(arg);
624 
625 	ser_exit();
626 }
627 #else
628 static void wlan_serialization_timer_handler(void *arg)
629 {
630 	struct wlan_serialization_timer *timer = arg;
631 	struct wlan_serialization_command *cmd = timer->cmd;
632 
633 	if (!cmd) {
634 		ser_err("command not found");
635 		QDF_ASSERT(0);
636 		return;
637 	}
638 
639 	if (cmd->cmd_type < WLAN_SER_CMD_NONSCAN)
640 		wlan_serialization_timer_cb_mc_ctx(arg);
641 	else
642 		wlan_serialization_generic_timer_cb(arg);
643 }
644 #endif
645 
646 QDF_STATUS
647 wlan_serialization_find_and_stop_timer(struct wlan_objmgr_psoc *psoc,
648 				       struct wlan_serialization_command *cmd)
649 {
650 	struct wlan_ser_psoc_obj *psoc_ser_obj;
651 	struct wlan_serialization_timer *ser_timer;
652 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
653 	int i = 0;
654 	uint32_t phy_version;
655 
656 	if (!psoc || !cmd) {
657 		ser_err("invalid param");
658 		goto error;
659 	}
660 
661 	if (cmd->cmd_timeout_duration == 0) {
662 		phy_version = wlan_psoc_get_nif_phy_version(psoc);
663 		if (wlan_is_emulation_platform(phy_version)) {
664 			ser_err("[SCAN-EMULATION]: Not performing timer funcs");
665 			status = QDF_STATUS_SUCCESS;
666 		goto exit;
667 		}
668 	}
669 
670 	psoc_ser_obj = wlan_serialization_get_psoc_obj(psoc);
671 	/*
672 	 * Here cmd_id and cmd_type are used to locate the timer being
673 	 * associated with command. For scan command, cmd_id is expected to
674 	 * be unique and For non-scan command, there should be only one active
675 	 * command per pdev
676 	 */
677 	for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) {
678 		ser_timer = &psoc_ser_obj->timers[i];
679 		if (!(ser_timer->cmd) ||
680 		    (ser_timer->cmd->cmd_id != cmd->cmd_id) ||
681 		    (ser_timer->cmd->cmd_type != cmd->cmd_type) ||
682 		    (ser_timer->cmd->vdev != cmd->vdev))
683 			continue;
684 		status = wlan_serialization_stop_timer(ser_timer);
685 		ser_debug("\n Stopping timer for cmd type:%d, id: %d",
686 			  cmd->cmd_type, cmd->cmd_id);
687 		break;
688 	}
689 
690 	if (QDF_STATUS_SUCCESS != status)
691 		ser_err("Can't find timer for cmd_type[%d]", cmd->cmd_type);
692 
693 error:
694 exit:
695 
696 	return status;
697 }
698 
699 QDF_STATUS
700 wlan_serialization_find_and_start_timer(struct wlan_objmgr_psoc *psoc,
701 					struct wlan_serialization_command *cmd)
702 {
703 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
704 	struct wlan_ser_psoc_obj *psoc_ser_obj;
705 	struct wlan_serialization_timer *ser_timer;
706 	int i = 0;
707 	uint32_t nif_phy_ver;
708 
709 	if (!psoc || !cmd) {
710 		ser_err("invalid param");
711 		goto error;
712 	}
713 
714 	nif_phy_ver = wlan_psoc_get_nif_phy_version(psoc);
715 	if ((cmd->cmd_timeout_duration == 0) &&
716 	    (wlan_is_emulation_platform(nif_phy_ver))) {
717 		ser_err("[SCAN-EMULATION]: Not performing timer functions\n");
718 		status = QDF_STATUS_SUCCESS;
719 		goto exit;
720 	}
721 
722 	psoc_ser_obj = wlan_serialization_get_psoc_obj(psoc);
723 
724 	for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) {
725 		/* Keep trying timer */
726 		ser_timer = &psoc_ser_obj->timers[i];
727 		if (ser_timer->cmd)
728 			continue;
729 
730 		/* Remember timer is pointing to command */
731 		ser_timer->cmd = cmd;
732 		qdf_timer_init(NULL,
733 			       &ser_timer->timer,
734 			       wlan_serialization_timer_handler,
735 			       ser_timer,
736 			       QDF_TIMER_TYPE_SW);
737 			       qdf_timer_mod(&ser_timer->timer,
738 					     cmd->cmd_timeout_duration);
739 
740 		ser_debug("starting timer for cmd: type[%d] id[%d] high_priority[%d] blocking[%d]",
741 			  cmd->cmd_type,
742 			  cmd->cmd_id,
743 			  cmd->is_high_priority,
744 			  cmd->is_blocking);
745 
746 		status = QDF_STATUS_SUCCESS;
747 		break;
748 	}
749 
750 error:
751 exit:
752 
753 	return status;
754 }
755 
756 enum wlan_serialization_cmd_status
757 wlan_serialization_cmd_cancel_handler(
758 		struct wlan_ser_pdev_obj *ser_obj,
759 		struct wlan_serialization_command *cmd,
760 		struct wlan_objmgr_pdev *pdev, struct wlan_objmgr_vdev *vdev,
761 		enum wlan_serialization_cmd_type cmd_type, uint8_t queue_type)
762 {
763 	enum wlan_serialization_cmd_status active_status =
764 		WLAN_SER_CMD_NOT_FOUND;
765 	enum wlan_serialization_cmd_status pending_status =
766 		WLAN_SER_CMD_NOT_FOUND;
767 	enum wlan_serialization_cmd_status status =
768 		WLAN_SER_CMD_NOT_FOUND;
769 
770 	ser_enter();
771 
772 	if (!ser_obj) {
773 		ser_err("invalid serial object");
774 		goto error;
775 	}
776 
777 	if (queue_type & WLAN_SERIALIZATION_ACTIVE_QUEUE) {
778 		if (cmd_type < WLAN_SER_CMD_NONSCAN)
779 			active_status = wlan_ser_cancel_scan_cmd(
780 					ser_obj, pdev, vdev, cmd,
781 					cmd_type, true);
782 		else
783 			active_status = wlan_ser_cancel_non_scan_cmd(
784 					ser_obj, pdev, vdev, cmd,
785 					cmd_type, true);
786 	}
787 
788 	if (queue_type & WLAN_SERIALIZATION_PENDING_QUEUE) {
789 		if (cmd_type < WLAN_SER_CMD_NONSCAN)
790 			pending_status = wlan_ser_cancel_scan_cmd(
791 					ser_obj, pdev, vdev, cmd,
792 					cmd_type, false);
793 		else
794 			pending_status = wlan_ser_cancel_non_scan_cmd(
795 					ser_obj, pdev, vdev, cmd,
796 					cmd_type, false);
797 	}
798 
799 	if (active_status == WLAN_SER_CMD_IN_ACTIVE_LIST &&
800 	    pending_status == WLAN_SER_CMD_IN_PENDING_LIST)
801 		status = WLAN_SER_CMDS_IN_ALL_LISTS;
802 	else if (active_status == WLAN_SER_CMD_IN_ACTIVE_LIST)
803 		status = active_status;
804 	else if (pending_status == WLAN_SER_CMD_IN_PENDING_LIST)
805 		status = pending_status;
806 
807 error:
808 	ser_exit();
809 	return status;
810 }
811 
812 enum wlan_serialization_cmd_status
813 wlan_serialization_find_and_cancel_cmd(
814 		struct wlan_serialization_command *cmd,
815 		enum wlan_serialization_cancel_type req_type,
816 		uint8_t queue_type)
817 {
818 	enum wlan_serialization_cmd_status status = WLAN_SER_CMD_NOT_FOUND;
819 	struct wlan_ser_pdev_obj *ser_obj = NULL;
820 	struct wlan_objmgr_pdev *pdev;
821 
822 	ser_enter();
823 
824 	if (!cmd) {
825 		ser_err("Invalid cmd");
826 		goto error;
827 	}
828 
829 	pdev = wlan_serialization_get_pdev_from_cmd(cmd);
830 	if (!pdev) {
831 		ser_err("Invalid pdev");
832 		goto error;
833 	}
834 	ser_obj = wlan_serialization_get_pdev_obj(pdev);
835 	if (!ser_obj) {
836 		ser_err("Invalid ser_obj");
837 		goto error;
838 	}
839 
840 	switch (req_type) {
841 	case WLAN_SER_CANCEL_SINGLE_SCAN:
842 		/* remove scan cmd which matches the given cmd struct */
843 		status =  wlan_serialization_cmd_cancel_handler(ser_obj,
844 								cmd,
845 								NULL,
846 								NULL,
847 								cmd->cmd_type,
848 								queue_type);
849 		break;
850 	case WLAN_SER_CANCEL_PDEV_SCANS:
851 		/* remove all scan cmds which matches the pdev object */
852 		status = wlan_serialization_cmd_cancel_handler(
853 				ser_obj,
854 				NULL,
855 				wlan_vdev_get_pdev(cmd->vdev),
856 				NULL,
857 				cmd->cmd_type,
858 				queue_type);
859 		break;
860 	case WLAN_SER_CANCEL_VDEV_SCANS:
861 		/* remove all scan cmds which matches the vdev object */
862 		status = wlan_serialization_cmd_cancel_handler(ser_obj,
863 							       NULL, NULL,
864 							       cmd->vdev,
865 							       cmd->cmd_type,
866 							       queue_type);
867 		break;
868 	case WLAN_SER_CANCEL_NON_SCAN_CMD:
869 		/* remove nonscan cmd which matches the given cmd */
870 		status = wlan_serialization_cmd_cancel_handler(ser_obj,
871 							       cmd,
872 							       NULL,
873 							       NULL,
874 							       cmd->cmd_type,
875 							       queue_type);
876 		break;
877 	case WLAN_SER_CANCEL_PDEV_NON_SCAN_CMD:
878 		/* remove all non scan cmds which matches the pdev object */
879 		status = wlan_serialization_cmd_cancel_handler(
880 				ser_obj,
881 				NULL,
882 				wlan_vdev_get_pdev(cmd->vdev),
883 				NULL,
884 				cmd->cmd_type,
885 				queue_type);
886 		break;
887 	case WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD:
888 		/* remove all non scan cmds which matches the vdev object */
889 		status = wlan_serialization_cmd_cancel_handler(ser_obj,
890 							       NULL, NULL,
891 							       cmd->vdev,
892 							       cmd->cmd_type,
893 							       queue_type);
894 		break;
895 	default:
896 		ser_err("Invalid request");
897 	}
898 
899 error:
900 	ser_exit();
901 	return status;
902 }
903