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