xref: /wlan-dirver/qca-wifi-host-cmn/umac/cmn_services/serialization/src/wlan_serialization_non_scan.c (revision 27d564647e9b50e713c60b0d7e5ea2a9b0a3ae74)
1 /*
2  * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 /**
19  * DOC: wlan_serialization_non_scan.c
20  * This file defines the functions which deals with
21  * serialization non scan commands.
22  */
23 
24 #include <wlan_objmgr_psoc_obj.h>
25 #include <wlan_objmgr_pdev_obj.h>
26 #include <wlan_objmgr_vdev_obj.h>
27 #include "wlan_serialization_main_i.h"
28 #include "wlan_serialization_utils_i.h"
29 #include "wlan_serialization_non_scan_i.h"
30 
31 /**
32  * wlan_serialization_is_active_nonscan_cmd_allowed() - find if cmd allowed
33  * @pdev: pointer to pdev object
34  *
35  * This API will be called to find out if non scan cmd is allowed.
36  *
37  * Return: true or false
38  */
39 bool
40 wlan_serialization_is_active_non_scan_cmd_allowed(
41 		struct wlan_serialization_command *cmd)
42 {
43 	struct wlan_serialization_pdev_queue *pdev_queue;
44 	struct wlan_ser_pdev_obj *ser_pdev_obj;
45 	uint32_t vdev_active_cmd_bitmap;
46 	bool blocking_cmd_active = 0;
47 	uint8_t blocking_cmd_waiting = 0;
48 	bool status = false;
49 	uint32_t vdev_id;
50 
51 	ser_pdev_obj = wlan_serialization_get_pdev_obj(
52 			wlan_serialization_get_pdev_from_cmd(cmd));
53 
54 	pdev_queue = wlan_serialization_get_pdev_queue_obj(ser_pdev_obj,
55 							   cmd->cmd_type);
56 
57 	vdev_active_cmd_bitmap = pdev_queue->vdev_active_cmd_bitmap;
58 	blocking_cmd_active = pdev_queue->blocking_cmd_active;
59 	blocking_cmd_waiting = pdev_queue->blocking_cmd_waiting;
60 
61 	/*
62 	 * Command is blocking
63 	 */
64 	if (cmd->is_blocking) {
65 		/*
66 		 * For blocking commands, no other
67 		 * commands from any vdev should be active
68 		 */
69 		if (vdev_active_cmd_bitmap) {
70 			status = false;
71 			pdev_queue->blocking_cmd_waiting++;
72 		} else {
73 			status = true;
74 		}
75 	} else {
76 		/*
77 		 * Command is non blocking
78 		 * For activating non blocking commands, if there any blocking
79 		 * commands, waiting or active, put it to pending queue
80 		 */
81 		if (blocking_cmd_active || blocking_cmd_waiting) {
82 			status = false;
83 		} else {
84 		/*
85 		 * For non blocking command, and no blocking commands
86 		 * waiting or active, check if a cmd for that vdev is active
87 		 * If not active, put to active else pending queue
88 		 */
89 			vdev_id = wlan_vdev_get_id(cmd->vdev);
90 			status = vdev_active_cmd_bitmap & (1 << vdev_id)
91 						? false : true;
92 		}
93 	}
94 	return status;
95 }
96 
97 enum wlan_serialization_status wlan_ser_add_non_scan_cmd(
98 		struct wlan_ser_pdev_obj *ser_pdev_obj,
99 		struct wlan_serialization_command_list *cmd_list,
100 		uint8_t is_cmd_for_active_queue)
101 {
102 	enum wlan_serialization_status pdev_status, vdev_status;
103 	enum wlan_serialization_status status = WLAN_SER_CMD_DENIED_UNSPECIFIED;
104 	struct wlan_serialization_command_list *pcmd_list;
105 	uint8_t vdev_id;
106 	struct wlan_serialization_pdev_queue *pdev_queue;
107 
108 	ser_debug("add non scan cmd: type[%d] id[%d] prio[%d] blocking[%d]",
109 		  cmd_list->cmd.cmd_type,
110 		  cmd_list->cmd.cmd_id,
111 		  cmd_list->cmd.is_high_priority,
112 		  cmd_list->cmd.is_blocking);
113 
114 	vdev_status = wlan_serialization_add_cmd_to_vdev_queue(
115 			ser_pdev_obj, cmd_list, is_cmd_for_active_queue);
116 
117 	if (vdev_status == WLAN_SER_CMD_DENIED_LIST_FULL) {
118 		status = vdev_status;
119 		goto vdev_error;
120 	}
121 
122 	if (is_cmd_for_active_queue) {
123 		if (vdev_status != WLAN_SER_CMD_ACTIVE) {
124 			ser_err("Failed to add to vdev active queue");
125 			QDF_ASSERT(0);
126 			goto vdev_error;
127 		}
128 	} else {
129 		if (vdev_status != WLAN_SER_CMD_PENDING) {
130 			ser_err("Failed to add to vdev pending queue");
131 			QDF_ASSERT(0);
132 			goto vdev_error;
133 		}
134 	}
135 
136 	pdev_status = wlan_serialization_add_cmd_to_pdev_queue(
137 			ser_pdev_obj, cmd_list, is_cmd_for_active_queue);
138 
139 	if (pdev_status == WLAN_SER_CMD_DENIED_LIST_FULL) {
140 		status = pdev_status;
141 		goto pdev_error;
142 	}
143 
144 	if (is_cmd_for_active_queue) {
145 		if (pdev_status != WLAN_SER_CMD_ACTIVE) {
146 			ser_err("Failed to add to pdev active queue");
147 			QDF_ASSERT(0);
148 			goto pdev_error;
149 		}
150 	} else {
151 		if (pdev_status != WLAN_SER_CMD_PENDING) {
152 			ser_err("Failed to add to pdev pending queue");
153 			QDF_ASSERT(0);
154 			goto pdev_error;
155 		}
156 	}
157 pdev_error:
158 	/*
159 	 * If cmd added to vdev queue, but failed while
160 	 * adding to pdev queue, remove cmd from vdev queue as well
161 	 */
162 	if (pdev_status != vdev_status) {
163 		wlan_serialization_remove_cmd_from_vdev_queue(
164 			ser_pdev_obj, &pcmd_list,
165 			&cmd_list->cmd,
166 			is_cmd_for_active_queue);
167 	} else {
168 		status = pdev_status;
169 	}
170 
171 	if (is_cmd_for_active_queue) {
172 		pdev_queue = wlan_serialization_get_pdev_queue_obj(
173 				ser_pdev_obj, cmd_list->cmd.cmd_type);
174 		vdev_id = wlan_vdev_get_id(cmd_list->cmd.vdev);
175 		pdev_queue->vdev_active_cmd_bitmap |= (1 << vdev_id);
176 
177 		if (cmd_list->cmd.is_blocking)
178 			pdev_queue->blocking_cmd_active = 1;
179 	}
180 
181 vdev_error:
182 	return status;
183 }
184 
185 enum wlan_serialization_status
186 wlan_ser_move_non_scan_pending_to_active(
187 		struct wlan_ser_pdev_obj *ser_pdev_obj,
188 		struct wlan_objmgr_vdev *vdev,
189 		bool blocking_cmd_removed)
190 {
191 	struct wlan_serialization_command_list *pending_cmd_list = NULL;
192 	struct wlan_serialization_command_list *active_cmd_list;
193 	struct wlan_serialization_command cmd_to_remove;
194 	enum wlan_serialization_status status = WLAN_SER_CMD_DENIED_UNSPECIFIED;
195 	struct wlan_serialization_pdev_queue *pdev_queue;
196 	struct wlan_serialization_vdev_queue *vdev_queue;
197 
198 	struct wlan_ser_vdev_obj *ser_vdev_obj;
199 
200 	qdf_list_t *pending_queue;
201 	qdf_list_node_t *pending_node = NULL;
202 	QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
203 	uint32_t blocking_cmd_waiting = 0;
204 	uint32_t vdev_id;
205 	uint32_t qsize;
206 	bool vdev_cmd_active = 0;
207 	bool vdev_queue_lookup = false;
208 
209 	pdev_queue = &ser_pdev_obj->pdev_q[SER_PDEV_QUEUE_COMP_NON_SCAN];
210 
211 	ser_vdev_obj = wlan_serialization_get_vdev_obj(vdev);
212 	vdev_queue = &ser_vdev_obj->vdev_q[SER_VDEV_QUEUE_COMP_NON_SCAN];
213 
214 	ser_enter();
215 
216 	if (!ser_pdev_obj) {
217 		ser_err("Can't find ser_pdev_obj");
218 		goto error;
219 	}
220 
221 	wlan_serialization_acquire_lock(&pdev_queue->pdev_queue_lock);
222 
223 	blocking_cmd_waiting = pdev_queue->blocking_cmd_waiting;
224 
225 	if (!blocking_cmd_removed && !blocking_cmd_waiting) {
226 		pending_queue = &vdev_queue->pending_list;
227 		vdev_queue_lookup = true;
228 	} else {
229 		pending_queue = &pdev_queue->pending_list;
230 	}
231 
232 	qsize =  wlan_serialization_list_size(pending_queue);
233 	if (!qsize) {
234 		wlan_serialization_release_lock(
235 			&pdev_queue->pdev_queue_lock);
236 		ser_err("Pending Queue is empty");
237 		goto error;
238 	}
239 
240 	while (qsize--) {
241 		qdf_status = wlan_serialization_get_cmd_from_queue(
242 				pending_queue, &pending_node);
243 		if (qdf_status != QDF_STATUS_SUCCESS) {
244 			ser_err("can't peek cmd");
245 			break;
246 		}
247 
248 		if (vdev_queue_lookup) {
249 			pending_cmd_list =
250 				qdf_container_of(
251 				pending_node,
252 				struct wlan_serialization_command_list,
253 				vdev_node);
254 		} else {
255 			pending_cmd_list =
256 				qdf_container_of(
257 				pending_node,
258 				struct wlan_serialization_command_list,
259 				pdev_node);
260 		}
261 
262 		if (!pending_cmd_list) {
263 			wlan_serialization_release_lock(
264 				&pdev_queue->pdev_queue_lock);
265 			ser_debug(
266 				"non scan cmd cannot move frm pendin to actv");
267 			goto error;
268 		}
269 
270 		if (!vdev_queue_lookup) {
271 			if (pending_cmd_list->cmd.is_blocking &&
272 			    pdev_queue->vdev_active_cmd_bitmap) {
273 				break;
274 			}
275 
276 			vdev_id = wlan_vdev_get_id(pending_cmd_list->cmd.vdev);
277 			vdev_cmd_active =
278 				pdev_queue->vdev_active_cmd_bitmap &
279 				(1 << vdev_id);
280 			if (vdev_cmd_active)
281 				continue;
282 		}
283 
284 		qdf_mem_copy(&cmd_to_remove, &pending_cmd_list->cmd,
285 			     sizeof(struct wlan_serialization_command));
286 
287 		qdf_status = wlan_ser_remove_non_scan_cmd(ser_pdev_obj,
288 							  &pending_cmd_list,
289 							  &cmd_to_remove,
290 							  false);
291 
292 		if (QDF_STATUS_SUCCESS != qdf_status) {
293 			wlan_serialization_release_lock(
294 					&pdev_queue->pdev_queue_lock);
295 			ser_err("Can't remove cmd from pendingQ id-%d type-%d",
296 				pending_cmd_list->cmd.cmd_id,
297 				pending_cmd_list->cmd.cmd_type);
298 			QDF_ASSERT(0);
299 			status = WLAN_SER_CMD_DENIED_UNSPECIFIED;
300 			goto error;
301 		}
302 
303 		active_cmd_list = pending_cmd_list;
304 
305 		status = wlan_ser_add_non_scan_cmd(
306 				ser_pdev_obj, active_cmd_list, true);
307 
308 		if (WLAN_SER_CMD_ACTIVE != status) {
309 			wlan_serialization_release_lock(
310 					&pdev_queue->pdev_queue_lock);
311 			ser_err("Can't move cmd to activeQ id-%d type-%d",
312 				pending_cmd_list->cmd.cmd_id,
313 				pending_cmd_list->cmd.cmd_type);
314 			wlan_serialization_insert_back(
315 				&pdev_queue->cmd_pool_list,
316 				&active_cmd_list->pdev_node);
317 			status = WLAN_SER_CMD_DENIED_UNSPECIFIED;
318 			goto error;
319 		}
320 
321 		qdf_atomic_set_bit(CMD_MARKED_FOR_ACTIVATION,
322 				   &active_cmd_list->cmd_in_use);
323 
324 		wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock);
325 
326 		wlan_serialization_activate_cmd(active_cmd_list, ser_pdev_obj);
327 
328 		wlan_serialization_acquire_lock(&pdev_queue->pdev_queue_lock);
329 
330 		if (vdev_queue_lookup)
331 			break;
332 
333 		pending_node = NULL;
334 
335 		if (active_cmd_list->cmd.is_blocking) {
336 			pdev_queue->blocking_cmd_waiting--;
337 			break;
338 		}
339 	}
340 
341 	wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock);
342 error:
343 	ser_exit();
344 	return status;
345 }
346 
347 QDF_STATUS wlan_ser_remove_non_scan_cmd(
348 		struct wlan_ser_pdev_obj *ser_pdev_obj,
349 		struct wlan_serialization_command_list **pcmd_list,
350 		struct wlan_serialization_command *cmd,
351 		uint8_t is_active_cmd)
352 {
353 	QDF_STATUS pdev_status, vdev_status;
354 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
355 	uint32_t vdev_id;
356 	bool blocking_cmd_removed = 0;
357 	struct wlan_serialization_pdev_queue *pdev_queue;
358 
359 	ser_debug("remove non scan cmd: type[%d] id[%d] prio[%d] blocking[%d]",
360 		  cmd->cmd_type,
361 		  cmd->cmd_id,
362 		  cmd->is_high_priority,
363 		  cmd->is_blocking);
364 
365 	vdev_status =
366 		wlan_serialization_remove_cmd_from_vdev_queue(ser_pdev_obj,
367 							      pcmd_list,
368 							      cmd,
369 							      is_active_cmd);
370 
371 	if (vdev_status != QDF_STATUS_SUCCESS) {
372 		ser_err("Failed to remove cmd from vdev active/pending queue");
373 		goto error;
374 	}
375 
376 	pdev_status =
377 		wlan_serialization_remove_cmd_from_pdev_queue(ser_pdev_obj,
378 							      pcmd_list,
379 							      cmd,
380 							      is_active_cmd);
381 
382 	if (pdev_status != QDF_STATUS_SUCCESS) {
383 		ser_err("Failed to remove cmd from pdev active/pending queue");
384 		goto error;
385 	}
386 
387 	if (is_active_cmd) {
388 		blocking_cmd_removed = (*pcmd_list)->cmd.is_blocking;
389 		pdev_queue = wlan_serialization_get_pdev_queue_obj(
390 				ser_pdev_obj, (*pcmd_list)->cmd.cmd_type);
391 
392 		if (blocking_cmd_removed)
393 			pdev_queue->blocking_cmd_active = 0;
394 
395 		vdev_id = wlan_vdev_get_id(cmd->vdev);
396 		pdev_queue->vdev_active_cmd_bitmap &= ~(1 << vdev_id);
397 	}
398 
399 	status = QDF_STATUS_SUCCESS;
400 
401 error:
402 	return status;
403 }
404 
405 enum wlan_serialization_cmd_status
406 wlan_ser_cancel_non_scan_cmd(
407 		struct wlan_ser_pdev_obj *ser_pdev_obj,
408 		struct wlan_objmgr_pdev *pdev, struct wlan_objmgr_vdev *vdev,
409 		struct wlan_serialization_command *cmd,
410 		enum wlan_serialization_cmd_type cmd_type,
411 		uint8_t is_active_queue)
412 {
413 	qdf_list_t *pdev_queue;
414 	qdf_list_t *vdev_queue;
415 	struct wlan_serialization_pdev_queue *pdev_q;
416 	uint32_t qsize;
417 	struct wlan_serialization_command_list *cmd_list = NULL;
418 	struct wlan_serialization_command cmd_bkup;
419 	qdf_list_node_t *nnode = NULL, *pnode = NULL;
420 	enum wlan_serialization_cmd_status status = WLAN_SER_CMD_NOT_FOUND;
421 	struct wlan_objmgr_psoc *psoc = NULL;
422 	QDF_STATUS qdf_status;
423 	QDF_STATUS pdev_status, vdev_status;
424 	struct wlan_ser_vdev_obj *ser_vdev_obj;
425 
426 	ser_enter();
427 
428 	pdev_q = wlan_serialization_get_pdev_queue_obj(ser_pdev_obj, cmd_type);
429 
430 	pdev_queue = wlan_serialization_get_list_from_pdev_queue(
431 			ser_pdev_obj, cmd_type, is_active_queue);
432 
433 	if (pdev)
434 		psoc = wlan_pdev_get_psoc(pdev);
435 	else if (vdev)
436 		psoc = wlan_vdev_get_psoc(vdev);
437 	else if (cmd && cmd->vdev)
438 		psoc = wlan_vdev_get_psoc(cmd->vdev);
439 	else
440 		ser_debug("Can't find psoc");
441 
442 	wlan_serialization_acquire_lock(&pdev_q->pdev_queue_lock);
443 
444 	qsize = wlan_serialization_list_size(pdev_queue);
445 	while (!wlan_serialization_list_empty(pdev_queue) && qsize--) {
446 		if (wlan_serialization_get_cmd_from_queue(pdev_queue, &nnode)
447 		    != QDF_STATUS_SUCCESS) {
448 			ser_err("can't read cmd from queue");
449 			status = WLAN_SER_CMD_NOT_FOUND;
450 			break;
451 		}
452 		cmd_list =
453 			qdf_container_of(nnode,
454 					 struct wlan_serialization_command_list,
455 					 pdev_node);
456 		if (cmd && !wlan_serialization_match_cmd_id_type(
457 							nnode, cmd,
458 							WLAN_SER_PDEV_NODE)) {
459 			pnode = nnode;
460 			continue;
461 		}
462 
463 		if (vdev &&
464 		    !wlan_serialization_match_cmd_vdev(nnode,
465 						      vdev,
466 						      WLAN_SER_PDEV_NODE)) {
467 			pnode = nnode;
468 			continue;
469 		}
470 
471 		if (pdev &&
472 		    !wlan_serialization_match_cmd_pdev(nnode,
473 						       pdev,
474 						       WLAN_SER_PDEV_NODE)) {
475 			pnode = nnode;
476 			continue;
477 		}
478 
479 		/*
480 		 * active queue can't be removed directly, requester needs to
481 		 * wait for active command response and send remove request for
482 		 * active command separately
483 		 */
484 		if (is_active_queue) {
485 			if (!psoc || !cmd_list) {
486 				ser_err("psoc:0x%pK, cmd_list:0x%pK",
487 					psoc, cmd_list);
488 				status = WLAN_SER_CMD_NOT_FOUND;
489 				break;
490 			}
491 
492 			/* Cancel request received for a cmd in active
493 			 * queue which has not been activated yet, we
494 			 * should assert here
495 			 */
496 			if (qdf_atomic_test_bit(CMD_MARKED_FOR_ACTIVATION,
497 						&cmd_list->cmd_in_use)) {
498 				wlan_serialization_release_lock(
499 						&pdev_q->pdev_queue_lock);
500 				status = WLAN_SER_CMD_MARKED_FOR_ACTIVATION;
501 				goto error;
502 			}
503 
504 			qdf_status = wlan_serialization_find_and_stop_timer(
505 							psoc, &cmd_list->cmd);
506 			if (QDF_STATUS_SUCCESS != qdf_status) {
507 				ser_err("Can't fix timer for active cmd");
508 				status = WLAN_SER_CMD_NOT_FOUND;
509 				break;
510 			}
511 			status = WLAN_SER_CMD_IN_ACTIVE_LIST;
512 		}
513 
514 		qdf_mem_copy(&cmd_bkup, &cmd_list->cmd,
515 			     sizeof(struct wlan_serialization_command));
516 
517 		pdev_status =
518 			wlan_serialization_remove_node(pdev_queue,
519 						       &cmd_list->pdev_node);
520 
521 		ser_vdev_obj = wlan_serialization_get_vdev_obj(
522 					cmd_list->cmd.vdev);
523 
524 		vdev_queue = wlan_serialization_get_list_from_vdev_queue(
525 			ser_vdev_obj, cmd_type, is_active_queue);
526 
527 		vdev_status =
528 			wlan_serialization_remove_node(vdev_queue,
529 						       &cmd_list->vdev_node);
530 
531 		if (pdev_status != QDF_STATUS_SUCCESS ||
532 		    vdev_status != QDF_STATUS_SUCCESS) {
533 			ser_err("can't remove cmd from pdev/vdev queue");
534 			status = WLAN_SER_CMD_NOT_FOUND;
535 			break;
536 		}
537 
538 		qdf_mem_zero(&cmd_list->cmd,
539 			     sizeof(struct wlan_serialization_command));
540 
541 		qdf_status = wlan_serialization_insert_back(
542 			&pdev_q->cmd_pool_list,
543 			&cmd_list->pdev_node);
544 
545 		if (QDF_STATUS_SUCCESS != qdf_status) {
546 			ser_err("can't remove cmd from queue");
547 			status = WLAN_SER_CMD_NOT_FOUND;
548 			break;
549 		}
550 		nnode = pnode;
551 
552 		wlan_serialization_release_lock(&pdev_q->pdev_queue_lock);
553 		/*
554 		 * call pending cmd's callback to notify that
555 		 * it is being removed
556 		 */
557 		if (cmd_bkup.cmd_cb) {
558 			/* caller should now do necessary clean up */
559 			ser_debug("cmd cb: type[%d] id[%d]",
560 				  cmd_bkup.cmd_type,
561 				  cmd_bkup.cmd_id);
562 			ser_debug("reason: WLAN_SER_CB_CANCEL_CMD");
563 			cmd_bkup.cmd_cb(&cmd_bkup,
564 					WLAN_SER_CB_CANCEL_CMD);
565 			/* caller should release the memory */
566 			ser_debug("reason: WLAN_SER_CB_RELEASE_MEM_CMD");
567 			cmd_bkup.cmd_cb(&cmd_bkup,
568 					WLAN_SER_CB_RELEASE_MEM_CMD);
569 		}
570 
571 		wlan_serialization_acquire_lock(&pdev_q->pdev_queue_lock);
572 
573 		if (is_active_queue) {
574 			if (cmd_bkup.is_blocking)
575 				pdev_q->blocking_cmd_active = 0;
576 			pdev_q->vdev_active_cmd_bitmap &=
577 				 ~(1 << wlan_vdev_get_id(cmd_bkup.vdev));
578 		} else {
579 			if (cmd_bkup.is_blocking)
580 				pdev_q->blocking_cmd_waiting--;
581 
582 			status = WLAN_SER_CMD_IN_PENDING_LIST;
583 		}
584 
585 
586 		if (!vdev && !pdev)
587 			break;
588 	}
589 
590 	wlan_serialization_release_lock(&pdev_q->pdev_queue_lock);
591 
592 error:
593 	ser_exit();
594 	return status;
595 }
596