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