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