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