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