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 
86 	ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc);
87 	if (!ser_pdev_obj) {
88 		serialization_err("invalid ser_pdev_obj");
89 		return 0;
90 	}
91 
92 	if (is_cmd_from_active_scan_queue)
93 		queue = &ser_pdev_obj->active_scan_list;
94 	else
95 		queue = &ser_pdev_obj->active_list;
96 
97 	return qdf_list_size(queue);
98 }
99 
100 uint32_t wlan_serialization_get_pending_list_count(
101 				struct wlan_objmgr_psoc *psoc,
102 				uint8_t is_cmd_from_pending_scan_queue)
103 {
104 	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
105 	qdf_list_t *queue;
106 
107 	ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc);
108 	if (!ser_pdev_obj) {
109 		serialization_err("invalid ser_pdev_obj");
110 		return 0;
111 	}
112 
113 	if (is_cmd_from_pending_scan_queue)
114 		queue = &ser_pdev_obj->pending_scan_list;
115 	else
116 		queue = &ser_pdev_obj->pending_list;
117 
118 	return qdf_list_size(queue);
119 }
120 
121 struct wlan_serialization_command*
122 wlan_serialization_peek_head_active_cmd_using_psoc(
123 			struct wlan_objmgr_psoc *psoc,
124 			uint8_t is_cmd_from_active_scan_queue)
125 {
126 	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
127 	struct wlan_serialization_command_list *cmd_list = NULL;
128 	struct wlan_serialization_command *cmd = NULL;
129 	qdf_list_node_t *nnode = NULL;
130 	qdf_list_t *queue;
131 
132 	ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc);
133 	if (!ser_pdev_obj) {
134 		serialization_err("invalid ser_pdev_obj");
135 		return 0;
136 	}
137 
138 	if (is_cmd_from_active_scan_queue)
139 		queue = &ser_pdev_obj->active_scan_list;
140 	else
141 		queue = &ser_pdev_obj->active_list;
142 	if (!qdf_list_size(queue)) {
143 		serialization_err("Empty Queue");
144 		return NULL;
145 	}
146 
147 	if (QDF_STATUS_SUCCESS != wlan_serialization_get_cmd_from_queue(queue,
148 						&nnode)) {
149 		serialization_err("Can't get command from queue");
150 		return NULL;
151 	}
152 
153 	cmd_list = qdf_container_of(nnode,
154 			struct wlan_serialization_command_list, node);
155 	serialization_debug("cmd_type[%d]", cmd_list->cmd.cmd_type);
156 	cmd = &cmd_list->cmd;
157 
158 	return cmd;
159 }
160 
161 struct wlan_serialization_command*
162 wlan_serialization_peek_head_pending_cmd_using_psoc(
163 			struct wlan_objmgr_psoc *psoc,
164 			uint8_t is_cmd_from_pending_scan_queue)
165 {
166 	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
167 	struct wlan_serialization_command_list *cmd_list = NULL;
168 	struct wlan_serialization_command *cmd = NULL;
169 	qdf_list_node_t *nnode = NULL;
170 	qdf_list_t *queue;
171 
172 	ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc);
173 	if (!ser_pdev_obj) {
174 		serialization_err("invalid ser_pdev_obj");
175 		return 0;
176 	}
177 
178 	if (is_cmd_from_pending_scan_queue)
179 		queue = &ser_pdev_obj->pending_scan_list;
180 	else
181 		queue = &ser_pdev_obj->pending_list;
182 	if (!qdf_list_size(queue)) {
183 		serialization_err("Empty Queue");
184 		return NULL;
185 	}
186 
187 	if (QDF_STATUS_SUCCESS != wlan_serialization_get_cmd_from_queue(queue,
188 							&nnode)) {
189 		serialization_err("Can't get command from queue");
190 		return NULL;
191 	}
192 	cmd_list = qdf_container_of(nnode,
193 			struct wlan_serialization_command_list, node);
194 	serialization_debug("cmd_type[%d] matched", cmd_list->cmd.cmd_type);
195 	cmd = &cmd_list->cmd;
196 
197 	return cmd;
198 }
199 
200 static struct wlan_serialization_command*
201 wlan_serialization_get_list_next_node(qdf_list_t *queue,
202 				struct wlan_serialization_command *cmd)
203 {
204 	struct wlan_serialization_command_list *cmd_list = NULL;
205 	qdf_list_node_t *pnode = NULL, *nnode = NULL;
206 	bool found = false;
207 	uint32_t i = 0;
208 	QDF_STATUS status;
209 
210 	if (!qdf_list_empty(queue)) {
211 		i = qdf_list_size(queue);
212 		while (i--) {
213 			if (!cmd_list)
214 				status = qdf_list_peek_front(queue, &nnode);
215 			else
216 				status = qdf_list_peek_next(queue, pnode,
217 							&nnode);
218 
219 			if ((status != QDF_STATUS_SUCCESS) || found)
220 				break;
221 
222 			pnode = nnode;
223 			cmd_list = qdf_container_of(nnode,
224 					struct wlan_serialization_command_list,
225 					node);
226 			if ((cmd_list->cmd.cmd_id == cmd->cmd_id) &&
227 				(cmd_list->cmd.cmd_type == cmd->cmd_type) &&
228 					(cmd_list->cmd.vdev == cmd->vdev)) {
229 				found = true;
230 			}
231 			nnode = NULL;
232 		}
233 	}
234 	if (nnode && found) {
235 		cmd_list = qdf_container_of(nnode,
236 				struct wlan_serialization_command_list, node);
237 		return &cmd_list->cmd;
238 	} else if (!found) {
239 		serialization_err("Can't locate next command");
240 		return NULL;
241 	} else {
242 		serialization_debug("next node is empty, so fine");
243 		return NULL;
244 	}
245 }
246 
247 struct wlan_serialization_command*
248 wlan_serialization_get_active_list_next_node_using_psoc(
249 			struct wlan_objmgr_psoc *psoc,
250 			struct wlan_serialization_command *prev_cmd,
251 			uint8_t is_cmd_for_active_scan_queue)
252 {
253 	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
254 	qdf_list_t *queue;
255 
256 	if (!prev_cmd) {
257 		serialization_err("invalid prev_cmd");
258 		return NULL;
259 	}
260 
261 	ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc);
262 	if (!ser_pdev_obj) {
263 		serialization_err("invalid ser_pdev_obj");
264 		return 0;
265 	}
266 
267 	if (is_cmd_for_active_scan_queue)
268 		queue = &ser_pdev_obj->active_scan_list;
269 	else
270 		queue = &ser_pdev_obj->active_list;
271 	if (!qdf_list_size(queue)) {
272 		serialization_err("Empty Queue");
273 		return NULL;
274 	}
275 
276 	return wlan_serialization_get_list_next_node(queue, prev_cmd);
277 }
278 
279 struct wlan_serialization_command*
280 wlan_serialization_get_pending_list_next_node_using_psoc(
281 			struct wlan_objmgr_psoc *psoc,
282 			struct wlan_serialization_command *prev_cmd,
283 			uint8_t is_cmd_for_pending_scan_queue)
284 {
285 	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
286 	qdf_list_t *queue;
287 
288 	if (!prev_cmd) {
289 		serialization_err("invalid prev_cmd");
290 		return NULL;
291 	}
292 
293 	ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc);
294 	if (!ser_pdev_obj) {
295 		serialization_err("invalid ser_pdev_obj");
296 		return 0;
297 	}
298 
299 	if (is_cmd_for_pending_scan_queue)
300 		queue = &ser_pdev_obj->pending_scan_list;
301 	else
302 		queue = &ser_pdev_obj->pending_list;
303 	if (!qdf_list_size(queue)) {
304 		serialization_err("Empty Queue");
305 		return NULL;
306 	}
307 
308 	return wlan_serialization_get_list_next_node(queue, prev_cmd);
309 }
310 
311 void wlan_serialization_legacy_init_callback(void)
312 {
313 	ser_legacy_cb.serialization_purge_cmd_list =
314 			wlan_serialization_purge_cmd_list;
315 }
316 
317 void wlan_serialization_purge_cmd_list_by_vdev_id(struct wlan_objmgr_psoc *psoc,
318 			uint8_t vdev_id, bool purge_scan_active_queue,
319 			bool purge_scan_pending_queue,
320 			bool purge_nonscan_active_queue,
321 			bool purge_nonscan_pending_queue,
322 			bool purge_all_queues)
323 {
324 	struct wlan_objmgr_vdev *vdev;
325 
326 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
327 			WLAN_SERIALIZATION_ID);
328 	if (!vdev) {
329 		serialization_err("Invalid vdev");
330 		return;
331 	}
332 	wlan_serialization_purge_cmd_list(psoc, vdev, purge_scan_active_queue,
333 				purge_scan_pending_queue,
334 				purge_nonscan_active_queue,
335 				purge_nonscan_pending_queue,
336 				purge_all_queues);
337 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SERIALIZATION_ID);
338 }
339 
340 void wlan_serialization_purge_cmd_list(struct wlan_objmgr_psoc *psoc,
341 		struct wlan_objmgr_vdev *vdev,
342 		bool purge_scan_active_queue,
343 		bool purge_scan_pending_queue,
344 		bool purge_nonscan_active_queue,
345 		bool purge_nonscan_pending_queue,
346 		bool purge_all_queues)
347 {
348 	struct wlan_serialization_timer *ser_timer;
349 	struct wlan_serialization_psoc_priv_obj *psoc_ser_obj;
350 	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
351 	struct wlan_objmgr_pdev *pdev = NULL;
352 	uint32_t i = 0;
353 
354 	if (!psoc) {
355 		serialization_err("Invalid psoc");
356 		return;
357 	}
358 	ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc);
359 	if (!ser_pdev_obj) {
360 		serialization_err("Invalid ser_pdev_obj");
361 		return;
362 	}
363 	psoc_ser_obj = wlan_serialization_get_psoc_priv_obj(psoc);
364 	if (!psoc_ser_obj) {
365 		serialization_err("Invalid psoc_ser_obj");
366 		return;
367 	}
368 	pdev = wlan_serialization_get_first_pdev(psoc);
369 	if (!pdev) {
370 		serialization_err("Invalid pdev");
371 		return;
372 	}
373 	for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) {
374 		ser_timer = &psoc_ser_obj->timers[i];
375 		if (!ser_timer->cmd)
376 			continue;
377 		if (vdev && (vdev != ser_timer->cmd->vdev))
378 			continue;
379 		/*
380 		 * if request is to purge active scan then don't de-activate
381 		 * non-scan cmds. If request is to purge all queues then
382 		 * de-activate all the timers.
383 		 */
384 		if (!purge_all_queues && purge_scan_active_queue &&
385 			     (ser_timer->cmd->cmd_type >= WLAN_SER_CMD_NONSCAN))
386 			continue;
387 		/*
388 		 * if request is to purge active nonscan then don't de-activate
389 		 * scan cmds. If request is to purge all queues then
390 		 * de-activate all the timers.
391 		 */
392 		if (!purge_all_queues && purge_nonscan_active_queue &&
393 			     (ser_timer->cmd->cmd_type < WLAN_SER_CMD_NONSCAN))
394 			continue;
395 
396 		if (QDF_STATUS_SUCCESS !=
397 				wlan_serialization_find_and_stop_timer(psoc,
398 							ser_timer->cmd))
399 			serialization_err("some error in stopping timer");
400 	}
401 	if (purge_all_queues || purge_scan_active_queue) {
402 		/* sending active queue as pending queue to leverage the API */
403 		wlan_serialization_remove_all_cmd_from_queue(
404 			&ser_pdev_obj->active_scan_list, ser_pdev_obj,
405 			pdev, vdev, NULL, false);
406 	}
407 	if (purge_all_queues || purge_scan_pending_queue) {
408 		wlan_serialization_remove_all_cmd_from_queue(
409 			&ser_pdev_obj->pending_scan_list, ser_pdev_obj,
410 			pdev, vdev, NULL, false);
411 	}
412 	if (purge_all_queues || purge_nonscan_active_queue) {
413 		/* sending active queue as pending queue to leverage the API */
414 		wlan_serialization_remove_all_cmd_from_queue(
415 			&ser_pdev_obj->active_list, ser_pdev_obj,
416 			pdev, vdev, NULL, false);
417 	}
418 	if (purge_all_queues || purge_nonscan_pending_queue) {
419 		wlan_serialization_remove_all_cmd_from_queue(
420 			&ser_pdev_obj->pending_list, ser_pdev_obj,
421 			pdev, vdev, NULL, false);
422 	}
423 	wlan_objmgr_pdev_release_ref(pdev, WLAN_SERIALIZATION_ID);
424 
425 	return;
426 }
427