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