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_legacy_api.c
20  * This file provides prototypes of the routines needed for the
21  * legacy mcl serialization to utilize the services provided by the
22  * serialization component.
23  */
24 
25 #include "wlan_serialization_legacy_api.h"
26 #include "wlan_serialization_main_i.h"
27 #include "wlan_serialization_utils_i.h"
28 #include "wlan_objmgr_vdev_obj.h"
29 
30 extern struct serialization_legacy_callback ser_legacy_cb;
31 
32 static struct wlan_objmgr_pdev *wlan_serialization_get_first_pdev(
33 			struct wlan_objmgr_psoc *psoc)
34 {
35 	struct wlan_objmgr_pdev *pdev;
36 	uint8_t i = 0;
37 
38 	if (!psoc) {
39 		serialization_err("invalid psoc");
40 		return NULL;
41 	}
42 	for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) {
43 		pdev = wlan_objmgr_get_pdev_by_id(psoc, i,
44 					WLAN_SERIALIZATION_ID);
45 		if (pdev != NULL)
46 			break;
47 	}
48 
49 	return pdev;
50 }
51 
52 static struct wlan_serialization_pdev_priv_obj *
53 wlan_serialization_get_pdev_priv_obj_using_psoc(struct wlan_objmgr_psoc *psoc)
54 {
55 	struct wlan_objmgr_pdev *pdev = NULL;
56 	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
57 
58 	if (!psoc) {
59 		serialization_err("invalid psoc");
60 		return NULL;
61 	}
62 
63 	pdev = wlan_serialization_get_first_pdev(psoc);
64 	if (!pdev) {
65 		serialization_err("invalid pdev");
66 		return NULL;
67 	}
68 
69 	ser_pdev_obj = wlan_serialization_get_pdev_priv_obj(pdev);
70 	wlan_objmgr_pdev_release_ref(pdev, WLAN_SERIALIZATION_ID);
71 	if (!ser_pdev_obj) {
72 		serialization_err("invalid ser_pdev_obj");
73 		return NULL;
74 	}
75 
76 	return ser_pdev_obj;
77 }
78 
79 uint32_t wlan_serialization_get_active_list_count(
80 			struct wlan_objmgr_psoc *psoc,
81 			uint8_t is_cmd_from_active_scan_queue)
82 {
83 	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
84 	qdf_list_t *queue;
85 	uint32_t count;
86 
87 	ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc);
88 	if (!ser_pdev_obj) {
89 		serialization_err("invalid ser_pdev_obj");
90 		return 0;
91 	}
92 
93 	wlan_serialization_acquire_lock(ser_pdev_obj);
94 	if (is_cmd_from_active_scan_queue)
95 		queue = &ser_pdev_obj->active_scan_list;
96 	else
97 		queue = &ser_pdev_obj->active_list;
98 
99 	count = qdf_list_size(queue);
100 	wlan_serialization_release_lock(ser_pdev_obj);
101 
102 	return count;
103 }
104 
105 uint32_t wlan_serialization_get_pending_list_count(
106 				struct wlan_objmgr_psoc *psoc,
107 				uint8_t is_cmd_from_pending_scan_queue)
108 {
109 	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
110 	qdf_list_t *queue;
111 	uint32_t count = 0;
112 
113 	ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc);
114 	if (!ser_pdev_obj) {
115 		serialization_err("invalid ser_pdev_obj");
116 		return 0;
117 	}
118 
119 	wlan_serialization_acquire_lock(ser_pdev_obj);
120 	if (is_cmd_from_pending_scan_queue)
121 		queue = &ser_pdev_obj->pending_scan_list;
122 	else
123 		queue = &ser_pdev_obj->pending_list;
124 
125 	count = qdf_list_size(queue);
126 	wlan_serialization_release_lock(ser_pdev_obj);
127 
128 	return count;
129 }
130 
131 struct wlan_serialization_command*
132 wlan_serialization_peek_head_active_cmd_using_psoc(
133 			struct wlan_objmgr_psoc *psoc,
134 			uint8_t is_cmd_from_active_scan_queue)
135 {
136 	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
137 	struct wlan_serialization_command_list *cmd_list = NULL;
138 	struct wlan_serialization_command *cmd = NULL;
139 	qdf_list_node_t *nnode = NULL;
140 	qdf_list_t *queue;
141 
142 	ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc);
143 	if (!ser_pdev_obj) {
144 		serialization_err("invalid ser_pdev_obj");
145 		return NULL;
146 	}
147 
148 	if (is_cmd_from_active_scan_queue)
149 		queue = &ser_pdev_obj->active_scan_list;
150 	else
151 		queue = &ser_pdev_obj->active_list;
152 	if (wlan_serialization_list_empty(queue, ser_pdev_obj)) {
153 		serialization_err("Empty Queue");
154 		goto end;
155 	}
156 
157 	if (QDF_STATUS_SUCCESS != wlan_serialization_get_cmd_from_queue(queue,
158 						&nnode, ser_pdev_obj)) {
159 		serialization_err("Can't get command from queue");
160 		goto end;
161 	}
162 
163 	cmd_list = qdf_container_of(nnode,
164 			struct wlan_serialization_command_list, node);
165 	cmd = &cmd_list->cmd;
166 	serialization_debug("cmd_type[%d], cmd_id[%d]",
167 			    cmd_list->cmd.cmd_type, cmd_list->cmd.cmd_id);
168 
169 end:
170 	return cmd;
171 }
172 
173 struct wlan_serialization_command*
174 wlan_serialization_peek_head_pending_cmd_using_psoc(
175 			struct wlan_objmgr_psoc *psoc,
176 			uint8_t is_cmd_from_pending_scan_queue)
177 {
178 	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
179 	struct wlan_serialization_command_list *cmd_list = NULL;
180 	struct wlan_serialization_command *cmd = NULL;
181 	qdf_list_node_t *nnode = NULL;
182 	qdf_list_t *queue;
183 
184 	ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc);
185 	if (!ser_pdev_obj) {
186 		serialization_err("invalid ser_pdev_obj");
187 		return NULL;
188 	}
189 	if (is_cmd_from_pending_scan_queue)
190 		queue = &ser_pdev_obj->pending_scan_list;
191 	else
192 		queue = &ser_pdev_obj->pending_list;
193 	if (wlan_serialization_list_empty(queue, ser_pdev_obj)) {
194 		serialization_err("Empty Queue");
195 		goto end;
196 	}
197 
198 	if (QDF_STATUS_SUCCESS != wlan_serialization_get_cmd_from_queue(queue,
199 							&nnode, ser_pdev_obj)) {
200 		serialization_err("Can't get command from queue");
201 		goto end;
202 	}
203 	cmd_list = qdf_container_of(nnode,
204 			struct wlan_serialization_command_list, node);
205 	cmd = &cmd_list->cmd;
206 	serialization_debug("cmd_type[%d] cmd_id[%d]matched",
207 			    cmd_list->cmd.cmd_type, cmd_list->cmd.cmd_id);
208 
209 end:
210 	return cmd;
211 }
212 
213 static struct wlan_serialization_command*
214 wlan_serialization_get_list_next_node(qdf_list_t *queue,
215 			struct wlan_serialization_command *cmd,
216 			struct wlan_serialization_pdev_priv_obj *ser_pdev_obj)
217 {
218 	struct wlan_serialization_command_list *cmd_list = NULL;
219 	qdf_list_node_t *pnode = NULL, *nnode = NULL;
220 	bool found = false;
221 	uint32_t i = 0;
222 	QDF_STATUS status;
223 	struct wlan_serialization_command *ret_cmd = NULL;
224 
225 	i = wlan_serialization_list_size(queue, ser_pdev_obj);
226 	if (i == 0) {
227 		serialization_err("Empty Queue");
228 		return NULL;
229 	}
230 	while (i--) {
231 		if (!cmd_list)
232 			status = wlan_serialization_peek_front(queue, &nnode,
233 							       ser_pdev_obj);
234 		else
235 			status = wlan_serialization_peek_next(queue, pnode,
236 							      &nnode,
237 							      ser_pdev_obj);
238 
239 		if ((status != QDF_STATUS_SUCCESS) || found)
240 			break;
241 
242 		pnode = nnode;
243 		cmd_list = qdf_container_of(
244 					nnode,
245 					struct wlan_serialization_command_list,
246 					node);
247 		if (wlan_serialization_match_cmd_id_type(nnode, cmd,
248 							 ser_pdev_obj) &&
249 				wlan_serialization_match_cmd_vdev(nnode,
250 								  cmd->vdev)) {
251 			found = true;
252 		}
253 		nnode = NULL;
254 	}
255 	if (nnode && found) {
256 		cmd_list = qdf_container_of(nnode,
257 				struct wlan_serialization_command_list, node);
258 		ret_cmd = &cmd_list->cmd;
259 	}
260 	if (!found) {
261 		serialization_err("Can't locate next command");
262 		return NULL;
263 	}
264 	if (!nnode) {
265 		serialization_debug("next node is empty, so fine");
266 		return NULL;
267 	}
268 
269 	return ret_cmd;
270 }
271 
272 struct wlan_serialization_command*
273 wlan_serialization_get_active_list_next_node_using_psoc(
274 			struct wlan_objmgr_psoc *psoc,
275 			struct wlan_serialization_command *prev_cmd,
276 			uint8_t is_cmd_for_active_scan_queue)
277 {
278 	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
279 	qdf_list_t *queue;
280 
281 	if (!prev_cmd) {
282 		serialization_err("invalid prev_cmd");
283 		return NULL;
284 	}
285 
286 	ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc);
287 	if (!ser_pdev_obj) {
288 		serialization_err("invalid ser_pdev_obj");
289 		return NULL;
290 	}
291 
292 	if (is_cmd_for_active_scan_queue)
293 		queue = &ser_pdev_obj->active_scan_list;
294 	else
295 		queue = &ser_pdev_obj->active_list;
296 
297 	return wlan_serialization_get_list_next_node(queue, prev_cmd,
298 						     ser_pdev_obj);
299 }
300 
301 struct wlan_serialization_command*
302 wlan_serialization_get_pending_list_next_node_using_psoc(
303 			struct wlan_objmgr_psoc *psoc,
304 			struct wlan_serialization_command *prev_cmd,
305 			uint8_t is_cmd_for_pending_scan_queue)
306 {
307 	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
308 	qdf_list_t *queue;
309 
310 	if (!prev_cmd) {
311 		serialization_err("invalid prev_cmd");
312 		return NULL;
313 	}
314 
315 	ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc);
316 	if (!ser_pdev_obj) {
317 		serialization_err("invalid ser_pdev_obj");
318 		return NULL;
319 	}
320 	if (is_cmd_for_pending_scan_queue)
321 		queue = &ser_pdev_obj->pending_scan_list;
322 	else
323 		queue = &ser_pdev_obj->pending_list;
324 
325 	return wlan_serialization_get_list_next_node(queue, prev_cmd,
326 						     ser_pdev_obj);
327 }
328 
329 void wlan_serialization_legacy_init_callback(void)
330 {
331 	ser_legacy_cb.serialization_purge_cmd_list =
332 			wlan_serialization_purge_cmd_list;
333 }
334 
335 void wlan_serialization_purge_cmd_list_by_vdev_id(struct wlan_objmgr_psoc *psoc,
336 			uint8_t vdev_id, bool purge_scan_active_queue,
337 			bool purge_scan_pending_queue,
338 			bool purge_nonscan_active_queue,
339 			bool purge_nonscan_pending_queue,
340 			bool purge_all_queues)
341 {
342 	struct wlan_objmgr_vdev *vdev;
343 
344 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
345 			WLAN_SERIALIZATION_ID);
346 	if (!vdev) {
347 		serialization_err("Invalid vdev");
348 		return;
349 	}
350 	wlan_serialization_purge_cmd_list(psoc, vdev, purge_scan_active_queue,
351 				purge_scan_pending_queue,
352 				purge_nonscan_active_queue,
353 				purge_nonscan_pending_queue,
354 				purge_all_queues);
355 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SERIALIZATION_ID);
356 }
357 
358 void wlan_serialization_purge_cmd_list(struct wlan_objmgr_psoc *psoc,
359 		struct wlan_objmgr_vdev *vdev,
360 		bool purge_scan_active_queue,
361 		bool purge_scan_pending_queue,
362 		bool purge_nonscan_active_queue,
363 		bool purge_nonscan_pending_queue,
364 		bool purge_all_queues)
365 {
366 	struct wlan_serialization_timer *ser_timer;
367 	struct wlan_serialization_psoc_priv_obj *psoc_ser_obj;
368 	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
369 	struct wlan_objmgr_pdev *pdev = NULL;
370 	uint32_t i = 0;
371 
372 	if (!psoc) {
373 		serialization_err("Invalid psoc");
374 		return;
375 	}
376 	ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc);
377 	if (!ser_pdev_obj) {
378 		serialization_err("Invalid ser_pdev_obj");
379 		return;
380 	}
381 	psoc_ser_obj = wlan_serialization_get_psoc_priv_obj(psoc);
382 	if (!psoc_ser_obj) {
383 		serialization_err("Invalid psoc_ser_obj");
384 		return;
385 	}
386 	pdev = wlan_serialization_get_first_pdev(psoc);
387 	if (!pdev) {
388 		serialization_err("Invalid pdev");
389 		return;
390 	}
391 	for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) {
392 		ser_timer = &psoc_ser_obj->timers[i];
393 		if (!ser_timer->cmd)
394 			continue;
395 		if (vdev && (vdev != ser_timer->cmd->vdev))
396 			continue;
397 		/*
398 		 * if request is to purge active scan then don't de-activate
399 		 * non-scan cmds. If request is to purge all queues then
400 		 * de-activate all the timers.
401 		 */
402 		if (!purge_all_queues && purge_scan_active_queue &&
403 			     (ser_timer->cmd->cmd_type >= WLAN_SER_CMD_NONSCAN))
404 			continue;
405 		/*
406 		 * if request is to purge active nonscan then don't de-activate
407 		 * scan cmds. If request is to purge all queues then
408 		 * de-activate all the timers.
409 		 */
410 		if (!purge_all_queues && purge_nonscan_active_queue &&
411 			     (ser_timer->cmd->cmd_type < WLAN_SER_CMD_NONSCAN))
412 			continue;
413 
414 		if (QDF_STATUS_SUCCESS !=
415 				wlan_serialization_find_and_stop_timer(psoc,
416 							ser_timer->cmd))
417 			serialization_err("some error in stopping timer");
418 	}
419 	if (purge_all_queues || purge_scan_active_queue) {
420 		/* sending active queue as pending queue to leverage the API */
421 		wlan_serialization_remove_all_cmd_from_queue(
422 			&ser_pdev_obj->active_scan_list, ser_pdev_obj,
423 			pdev, vdev, NULL, false);
424 	}
425 	if (purge_all_queues || purge_scan_pending_queue) {
426 		wlan_serialization_remove_all_cmd_from_queue(
427 			&ser_pdev_obj->pending_scan_list, ser_pdev_obj,
428 			pdev, vdev, NULL, false);
429 	}
430 	if (purge_all_queues || purge_nonscan_active_queue) {
431 		/* sending active queue as pending queue to leverage the API */
432 		wlan_serialization_remove_all_cmd_from_queue(
433 			&ser_pdev_obj->active_list, ser_pdev_obj,
434 			pdev, vdev, NULL, false);
435 	}
436 	if (purge_all_queues || purge_nonscan_pending_queue) {
437 		wlan_serialization_remove_all_cmd_from_queue(
438 			&ser_pdev_obj->pending_list, ser_pdev_obj,
439 			pdev, vdev, NULL, false);
440 	}
441 	wlan_objmgr_pdev_release_ref(pdev, WLAN_SERIALIZATION_ID);
442 
443 	return;
444 }
445