xref: /wlan-dirver/qca-wifi-host-cmn/umac/cmn_services/serialization/src/wlan_serialization_internal.c (revision 11f5a63a6cbdda84849a730de22f0a71e635d58c)
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 timer_failed:
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 	if (QDF_IS_STATUS_ERROR(status)) {
349 		wlan_serialization_dequeue_cmd(&cmd_list->cmd,
350 					       SER_ACTIVATION_FAILED,
351 					       true);
352 		return status;
353 	}
354 
355 	/*
356 	 * Cmd was marked for activation and delete or cancel
357 	 * is received before activation completed, then the command
358 	 * should be immediately removed after activation
359 	 */
360 	if (qdf_atomic_test_bit(CMD_ACTIVE_MARKED_FOR_REMOVAL,
361 				&cmd_list->cmd_in_use)) {
362 		wlan_serialization_dequeue_cmd(&cmd_list->cmd,
363 					       SER_REMOVE,
364 					       true);
365 		return status;
366 	}
367 
368 	if (qdf_atomic_test_bit(CMD_ACTIVE_MARKED_FOR_CANCEL,
369 				&cmd_list->cmd_in_use))
370 		wlan_serialization_cmd_cancel_handler(
371 				ser_pdev_obj, &cmd_list->cmd,
372 				NULL, NULL, cmd_list->cmd.cmd_type,
373 				WLAN_SERIALIZATION_ACTIVE_QUEUE,
374 				WLAN_SER_CMD_ATTR_NONE);
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 	enum wlan_serialization_cmd_status status;
566 
567 
568 	if (!cmd) {
569 		ser_err("Command not found");
570 		return;
571 	}
572 
573 	vdev = cmd->vdev;
574 	if (!vdev) {
575 		ser_err("Invalid vdev");
576 		return;
577 	}
578 
579 	ser_err("active cmd timeout for cmd_type[%d] vdev[%d]",
580 		cmd->cmd_type, wlan_vdev_get_id(cmd->vdev));
581 
582 	if (cmd->cmd_cb)
583 		cmd->cmd_cb(cmd, WLAN_SER_CB_ACTIVE_CMD_TIMEOUT);
584 
585 	/*
586 	 * dequeue cmd API will cleanup and destroy the timer. If it fails to
587 	 * dequeue command then we have to destroy the timer.
588 	 */
589 	status = wlan_serialization_dequeue_cmd(cmd, SER_TIMEOUT, true);
590 
591 	/* Release the ref taken before the timer was started */
592 	if (status == WLAN_SER_CMD_IN_ACTIVE_LIST)
593 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SERIALIZATION_ID);
594 }
595 
596 static QDF_STATUS wlan_serialization_mc_flush_noop(struct scheduler_msg *msg)
597 {
598 	return QDF_STATUS_SUCCESS;
599 }
600 
601 static void
602 wlan_serialization_timer_cb_mc_ctx(void *arg)
603 {
604 	struct scheduler_msg msg = {0};
605 
606 	msg.type = SYS_MSG_ID_MC_TIMER;
607 	msg.reserved = SYS_MSG_COOKIE;
608 	msg.callback = wlan_serialization_generic_timer_cb;
609 	msg.bodyptr = arg;
610 	msg.bodyval = 0;
611 	msg.flush_callback = wlan_serialization_mc_flush_noop;
612 
613 	if (scheduler_post_message(QDF_MODULE_ID_SERIALIZATION,
614 				   QDF_MODULE_ID_SERIALIZATION,
615 				   QDF_MODULE_ID_SYS, &msg) ==
616 							QDF_STATUS_SUCCESS)
617 		return;
618 
619 	ser_err("Could not enqueue timer to timer queue");
620 }
621 
622 static void wlan_serialization_timer_handler(void *arg)
623 {
624 	struct wlan_serialization_timer *timer = arg;
625 	struct wlan_serialization_command *cmd = timer->cmd;
626 
627 	if (!cmd) {
628 		ser_err("Command not found");
629 		return;
630 	}
631 
632 	ser_err("active cmd timeout for cmd_type[%d] vdev[%d]",
633 		cmd->cmd_type, wlan_vdev_get_id(cmd->vdev));
634 
635 	wlan_serialization_timer_cb_mc_ctx(arg);
636 
637 }
638 
639 QDF_STATUS
640 wlan_serialization_find_and_update_timer(
641 		struct wlan_objmgr_psoc *psoc,
642 		struct wlan_serialization_command *cmd)
643 {
644 	struct wlan_ser_psoc_obj *psoc_ser_obj;
645 	struct wlan_serialization_timer *ser_timer;
646 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
647 	int i = 0;
648 
649 	if (!psoc || !cmd) {
650 		ser_err("invalid param");
651 		goto exit;
652 	}
653 
654 	psoc_ser_obj = wlan_serialization_get_psoc_obj(psoc);
655 	/*
656 	 * Here cmd_id and cmd_type are used to locate the timer being
657 	 * associated with command.
658 	 */
659 	wlan_serialization_acquire_lock(&psoc_ser_obj->timer_lock);
660 
661 	for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) {
662 		ser_timer = &psoc_ser_obj->timers[i];
663 		if (!(ser_timer->cmd) ||
664 		    (ser_timer->cmd->cmd_id != cmd->cmd_id) ||
665 		    (ser_timer->cmd->cmd_type != cmd->cmd_type) ||
666 		    (ser_timer->cmd->vdev != cmd->vdev))
667 			continue;
668 
669 		qdf_timer_mod(&ser_timer->timer,
670 			      cmd->cmd_timeout_duration);
671 		status = QDF_STATUS_SUCCESS;
672 		break;
673 	}
674 
675 	wlan_serialization_release_lock(&psoc_ser_obj->timer_lock);
676 
677 	if (QDF_IS_STATUS_SUCCESS(status))
678 		ser_debug("Updated the timer for cmd type:%d, id: %d",
679 			  cmd->cmd_type, cmd->cmd_id);
680 	else
681 		ser_debug("Can't find timer for cmd_type[%d]", cmd->cmd_type);
682 
683 exit:
684 	return status;
685 }
686 
687 QDF_STATUS
688 wlan_serialization_find_and_stop_timer(struct wlan_objmgr_psoc *psoc,
689 				       struct wlan_serialization_command *cmd,
690 				       enum ser_queue_reason ser_reason)
691 {
692 	struct wlan_ser_psoc_obj *psoc_ser_obj;
693 	struct wlan_serialization_timer *ser_timer;
694 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
695 	int i = 0;
696 	uint32_t phy_version;
697 	struct wlan_objmgr_vdev *vdev;
698 
699 	if (!psoc || !cmd) {
700 		ser_err("invalid param");
701 		goto exit;
702 	}
703 
704 	if (cmd->cmd_timeout_duration == 0) {
705 		phy_version = wlan_psoc_get_nif_phy_version(psoc);
706 		if (wlan_is_emulation_platform(phy_version)) {
707 			ser_err("[SCAN-EMULATION]: Not performing timer funcs");
708 			status = QDF_STATUS_SUCCESS;
709 		goto exit;
710 		}
711 	}
712 
713 	psoc_ser_obj = wlan_serialization_get_psoc_obj(psoc);
714 	/*
715 	 * Here cmd_id and cmd_type are used to locate the timer being
716 	 * associated with command.
717 	 */
718 	wlan_serialization_acquire_lock(&psoc_ser_obj->timer_lock);
719 
720 	for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) {
721 		ser_timer = &psoc_ser_obj->timers[i];
722 		if (!(ser_timer->cmd) ||
723 		    (ser_timer->cmd->cmd_id != cmd->cmd_id) ||
724 		    (ser_timer->cmd->cmd_type != cmd->cmd_type) ||
725 		    (ser_timer->cmd->vdev != cmd->vdev))
726 			continue;
727 
728 		vdev = ser_timer->cmd->vdev;
729 		status = wlan_serialization_stop_timer(ser_timer);
730 		/*
731 		 * Release the vdev reference when the active cmd is removed
732 		 * through remove/cancel request.
733 		 *
734 		 * In case the command removal is because of timer expiry,
735 		 * the vdev is released when the timer handler completes.
736 		 */
737 		if (vdev && ser_reason != SER_TIMEOUT)
738 			wlan_objmgr_vdev_release_ref(
739 					vdev, WLAN_SERIALIZATION_ID);
740 
741 		break;
742 
743 	}
744 
745 	wlan_serialization_release_lock(&psoc_ser_obj->timer_lock);
746 
747 	if (QDF_IS_STATUS_SUCCESS(status))
748 		ser_debug("Stopped timer for cmd_type %d cmd id %d",
749 			  cmd->cmd_type, cmd->cmd_id);
750 	else
751 		ser_err("Can't find timer for cmd_type %d cmd id %d",
752 			cmd->cmd_type, cmd->cmd_id);
753 
754 exit:
755 	return status;
756 }
757 
758 QDF_STATUS
759 wlan_serialization_find_and_start_timer(struct wlan_objmgr_psoc *psoc,
760 					struct wlan_serialization_command *cmd,
761 					enum ser_queue_reason ser_reason)
762 {
763 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
764 	struct wlan_ser_psoc_obj *psoc_ser_obj;
765 	struct wlan_serialization_timer *ser_timer;
766 	int i = 0;
767 	uint32_t nif_phy_ver;
768 
769 	if (!psoc || !cmd) {
770 		ser_err("invalid param");
771 		goto error;
772 	}
773 
774 	nif_phy_ver = wlan_psoc_get_nif_phy_version(psoc);
775 	if ((cmd->cmd_timeout_duration == 0) &&
776 	    (wlan_is_emulation_platform(nif_phy_ver))) {
777 		ser_err("[SCAN-EMULATION]: Not performing timer functions\n");
778 		status = QDF_STATUS_SUCCESS;
779 		goto exit;
780 	}
781 
782 	psoc_ser_obj = wlan_serialization_get_psoc_obj(psoc);
783 
784 	wlan_serialization_acquire_lock(&psoc_ser_obj->timer_lock);
785 
786 	for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) {
787 		/* Keep trying timer */
788 		ser_timer = &psoc_ser_obj->timers[i];
789 		if (ser_timer->cmd)
790 			continue;
791 
792 		/* Remember timer is pointing to command */
793 		ser_timer->cmd = cmd;
794 		status = QDF_STATUS_SUCCESS;
795 
796 		/*
797 		 * Get vdev reference before starting the timer
798 		 * Remove the reference before removing the command
799 		 * in any one of the cases:
800 		 * 1. Active command is removed through remove/cancel request
801 		 * 2. Timer expiry handler is completed.
802 		 */
803 
804 		status = wlan_objmgr_vdev_try_get_ref(ser_timer->cmd->vdev,
805 						      WLAN_SERIALIZATION_ID);
806 		if (QDF_IS_STATUS_ERROR(status)) {
807 			/*
808 			 * Set cmd to null so that ref release is not tried for
809 			 * vdev when timer is flushed.
810 			 */
811 			ser_timer->cmd = NULL;
812 			wlan_serialization_release_lock(
813 					&psoc_ser_obj->timer_lock);
814 			ser_err("Unbale to get vdev reference");
815 			status = QDF_STATUS_E_FAILURE;
816 			goto error;
817 		}
818 		break;
819 	}
820 
821 	wlan_serialization_release_lock(&psoc_ser_obj->timer_lock);
822 
823 	if (QDF_IS_STATUS_SUCCESS(status)) {
824 		qdf_timer_init(NULL,
825 			       &ser_timer->timer,
826 			       wlan_serialization_timer_handler,
827 			       ser_timer,
828 			       QDF_TIMER_TYPE_SW);
829 			       qdf_timer_mod(&ser_timer->timer,
830 			       cmd->cmd_timeout_duration);
831 
832 		ser_debug("Started timer for cmd: type[%d] id[%d] high_priority[%d] blocking[%d]",
833 			  cmd->cmd_type,
834 			  cmd->cmd_id,
835 			  cmd->is_high_priority,
836 			  cmd->is_blocking);
837 	} else {
838 		ser_err("Failed to start timer for cmd: type[%d] id[%d] high_priority[%d] blocking[%d]",
839 			  cmd->cmd_type,
840 			  cmd->cmd_id,
841 			  cmd->is_high_priority,
842 			  cmd->is_blocking);
843 	}
844 
845 error:
846 exit:
847 	return status;
848 }
849 
850 enum wlan_serialization_cmd_status
851 wlan_serialization_cmd_cancel_handler(
852 		struct wlan_ser_pdev_obj *ser_obj,
853 		struct wlan_serialization_command *cmd,
854 		struct wlan_objmgr_pdev *pdev, struct wlan_objmgr_vdev *vdev,
855 		enum wlan_serialization_cmd_type cmd_type, uint8_t queue_type,
856 		enum wlan_ser_cmd_attr cmd_attr)
857 {
858 	enum wlan_serialization_cmd_status active_status =
859 		WLAN_SER_CMD_NOT_FOUND;
860 	enum wlan_serialization_cmd_status pending_status =
861 		WLAN_SER_CMD_NOT_FOUND;
862 	enum wlan_serialization_cmd_status status =
863 		WLAN_SER_CMD_NOT_FOUND;
864 
865 	ser_enter();
866 
867 	if (!ser_obj) {
868 		ser_err("invalid serial object");
869 		goto error;
870 	}
871 
872 	if (queue_type & WLAN_SERIALIZATION_ACTIVE_QUEUE) {
873 		if (cmd_type < WLAN_SER_CMD_NONSCAN)
874 			active_status = wlan_ser_cancel_scan_cmd(
875 					ser_obj, pdev, vdev, cmd,
876 					cmd_type, true);
877 		else
878 			active_status = wlan_ser_cancel_non_scan_cmd(
879 					ser_obj, pdev, vdev, cmd,
880 					cmd_type, true, cmd_attr);
881 	}
882 
883 	if (queue_type & WLAN_SERIALIZATION_PENDING_QUEUE) {
884 		if (cmd_type < WLAN_SER_CMD_NONSCAN)
885 			pending_status = wlan_ser_cancel_scan_cmd(
886 					ser_obj, pdev, vdev, cmd,
887 					cmd_type, false);
888 		else
889 			pending_status = wlan_ser_cancel_non_scan_cmd(
890 					ser_obj, pdev, vdev, cmd,
891 					cmd_type, false, cmd_attr);
892 	}
893 
894 	if (active_status == WLAN_SER_CMD_IN_ACTIVE_LIST &&
895 	    pending_status == WLAN_SER_CMD_IN_PENDING_LIST)
896 		status = WLAN_SER_CMDS_IN_ALL_LISTS;
897 	else if (active_status == WLAN_SER_CMD_IN_ACTIVE_LIST)
898 		status = active_status;
899 	else if (pending_status == WLAN_SER_CMD_IN_PENDING_LIST)
900 		status = pending_status;
901 
902 error:
903 	ser_exit();
904 	return status;
905 }
906 
907 enum wlan_serialization_cmd_status
908 wlan_serialization_find_and_cancel_cmd(
909 		struct wlan_serialization_command *cmd,
910 		enum wlan_serialization_cancel_type req_type,
911 		uint8_t queue_type)
912 {
913 	enum wlan_serialization_cmd_status status = WLAN_SER_CMD_NOT_FOUND;
914 	struct wlan_ser_pdev_obj *ser_obj = NULL;
915 	struct wlan_objmgr_pdev *pdev;
916 
917 	ser_enter();
918 
919 	if (!cmd) {
920 		ser_err("Invalid cmd");
921 		goto error;
922 	}
923 
924 	pdev = wlan_serialization_get_pdev_from_cmd(cmd);
925 	if (!pdev) {
926 		ser_err("Invalid pdev");
927 		goto error;
928 	}
929 	ser_obj = wlan_serialization_get_pdev_obj(pdev);
930 	if (!ser_obj) {
931 		ser_err("Invalid ser_obj");
932 		goto error;
933 	}
934 
935 	switch (req_type) {
936 	case WLAN_SER_CANCEL_SINGLE_SCAN:
937 		/* remove scan cmd which matches the given cmd struct */
938 		status = wlan_serialization_cmd_cancel_handler(
939 				ser_obj, cmd, NULL, NULL,
940 				WLAN_SER_CMD_SCAN, queue_type,
941 				WLAN_SER_CMD_ATTR_NONE);
942 		break;
943 	case WLAN_SER_CANCEL_PDEV_SCANS:
944 		/* remove all scan cmds which matches the pdev object */
945 		status = wlan_serialization_cmd_cancel_handler(
946 				ser_obj, NULL, pdev, NULL,
947 				WLAN_SER_CMD_SCAN, queue_type,
948 				WLAN_SER_CMD_ATTR_NONE);
949 		break;
950 	case WLAN_SER_CANCEL_VDEV_SCANS:
951 		/* remove all scan cmds which matches the vdev object */
952 		status = wlan_serialization_cmd_cancel_handler(
953 				ser_obj, NULL, NULL, cmd->vdev,
954 				WLAN_SER_CMD_SCAN, queue_type,
955 				WLAN_SER_CMD_ATTR_NONE);
956 		break;
957 	case WLAN_SER_CANCEL_NON_SCAN_CMD:
958 		/* remove nonscan cmd which matches the given cmd */
959 		status = wlan_serialization_cmd_cancel_handler(
960 				ser_obj, cmd, NULL, NULL,
961 				WLAN_SER_CMD_NONSCAN, queue_type,
962 				WLAN_SER_CMD_ATTR_NONE);
963 		break;
964 	case WLAN_SER_CANCEL_PDEV_NON_SCAN_CMD:
965 		/* remove all non scan cmds which matches the pdev object */
966 		status = wlan_serialization_cmd_cancel_handler(
967 				ser_obj, NULL, pdev, NULL,
968 				WLAN_SER_CMD_NONSCAN, queue_type,
969 				WLAN_SER_CMD_ATTR_NONE);
970 		break;
971 	case WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD:
972 		/* remove all non scan cmds which matches the vdev object */
973 		status = wlan_serialization_cmd_cancel_handler(
974 				ser_obj, NULL, NULL, cmd->vdev,
975 				WLAN_SER_CMD_NONSCAN, queue_type,
976 				WLAN_SER_CMD_ATTR_NONE);
977 		break;
978 	case WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD_TYPE:
979 		/*
980 		 * remove all non scan cmds which matches the vdev
981 		 * and given cmd type
982 		 */
983 		status = wlan_serialization_cmd_cancel_handler(
984 				ser_obj, NULL, NULL, cmd->vdev,
985 				cmd->cmd_type, queue_type,
986 				WLAN_SER_CMD_ATTR_NONE);
987 		break;
988 	case WLAN_SER_CANCEL_VDEV_NON_SCAN_NB_CMD:
989 		/*
990 		 * remove all non-blocking non-scan cmds which matches the given
991 		 * vdev
992 		 */
993 		status = wlan_serialization_cmd_cancel_handler(
994 				ser_obj, NULL, NULL, cmd->vdev,
995 				WLAN_SER_CMD_NONSCAN, queue_type,
996 				WLAN_SER_CMD_ATTR_NONBLOCK);
997 		break;
998 	default:
999 		ser_err("Invalid request");
1000 	}
1001 
1002 error:
1003 	ser_exit();
1004 	return status;
1005 }
1006