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