xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlme/mlme_utils/wlan_vdev_mlme_ser_if.c (revision f28396d060cff5c6519f883cb28ae0116ce479f1)
1 /*
2  * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /**
18  * @file wlan_vdev_mlme_ser.c
19  * This file contains the APIs to support interface between vdev_mlme and
20  * serialization module
21  */
22 
23 #include <qdf_types.h>
24 #include <qdf_status.h>
25 #include <qdf_mem.h>
26 #include <wlan_serialization_api.h>
27 #include <wlan_objmgr_vdev_obj.h>
28 #include <wlan_cmn.h>
29 #include <wlan_mlme_dbg.h>
30 #include <include/wlan_mlme_cmn.h>
31 #include <wlan_vdev_mlme_api.h>
32 #include <wlan_vdev_mlme_ser_if.h>
33 
34 enum wlan_serialization_status
35 wlan_vdev_mlme_ser_start_bss(struct wlan_serialization_command *cmd)
36 {
37 	struct vdev_mlme_obj *vdev_mlme;
38 
39 	if (!cmd || !cmd->vdev) {
40 		mlme_err("Null input");
41 		return WLAN_SER_CMD_DENIED_UNSPECIFIED;
42 	}
43 
44 	if (!wlan_ser_is_vdev_queue_enabled(cmd->vdev))
45 		return WLAN_SER_CMD_QUEUE_DISABLED;
46 	/*
47 	 * Serialization command filtering logic
48 	 * a. Cancel any existing start bss cmd in the pending queue
49 	 * b. If there is an start bss cmd in active queue and
50 	 * there is no stop bss cmd in pending queue,
51 	 * then explicitly enqueue a stop bss cmd to avoid back to
52 	 * back execution of UP cmd.
53 	 * c. Enqueue the new start bss cmd with serialization
54 	 */
55 	wlan_vdev_mlme_ser_cancel_request(
56 			cmd->vdev,
57 			WLAN_SER_CMD_VDEV_START_BSS,
58 			WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD_TYPE);
59 
60 	if (wlan_serialization_is_cmd_present_in_active_queue(NULL, cmd)) {
61 		vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(cmd->vdev);
62 		if (mlme_vdev_enqueue_exp_ser_cmd(vdev_mlme,
63 						  WLAN_SER_CMD_VDEV_STOP_BSS)) {
64 			mlme_err("Unable to add the exception cmd request");
65 			return WLAN_SER_CMD_DENIED_UNSPECIFIED;
66 		}
67 	}
68 
69 	return wlan_serialization_request(cmd);
70 }
71 
72 enum wlan_serialization_status
73 wlan_vdev_mlme_ser_stop_bss(struct wlan_serialization_command *cmd)
74 {
75 	uint8_t stop_cmd_pending;
76 	uint8_t ret;
77 
78 	if (!cmd || !cmd->vdev) {
79 		mlme_err("Null input");
80 		return WLAN_SER_CMD_DENIED_UNSPECIFIED;
81 	}
82 
83 	if (!wlan_ser_is_vdev_queue_enabled(cmd->vdev))
84 		return WLAN_SER_CMD_QUEUE_DISABLED;
85 	/*
86 	 * Serialization command filtering logic
87 	 * a. Cancel any existing start/stop/restart command in the pending
88 	 *  queue.
89 	 * b. If there is a stop cmd in active queue then return
90 	 * c. Else enqueue the cmd
91 	 * d. If stop cmd already existed in pending queue then return with
92 	 *  already exists else return the enqueued return value.
93 	 */
94 	stop_cmd_pending =
95 		wlan_serialization_is_cmd_present_in_pending_queue(NULL, cmd);
96 	wlan_vdev_mlme_ser_cancel_request(cmd->vdev,
97 					  WLAN_SER_CMD_NONSCAN,
98 					  WLAN_SER_CANCEL_VDEV_NON_SCAN_NB_CMD);
99 
100 	if (wlan_serialization_is_cmd_present_in_active_queue(NULL, cmd)) {
101 		mlme_debug("Cmd already exist in the active queue");
102 		return WLAN_SER_CMD_DENIED_UNSPECIFIED;
103 	}
104 
105 	ret = wlan_serialization_request(cmd);
106 
107 	if (stop_cmd_pending && ret == WLAN_SER_CMD_PENDING)
108 		return WLAN_SER_CMD_ALREADY_EXISTS;
109 	else
110 		return ret;
111 }
112 
113 enum wlan_serialization_status
114 wlan_vdev_mlme_ser_vdev_restart(struct wlan_serialization_command *cmd)
115 {
116 	if (!cmd || !cmd->vdev) {
117 		mlme_err("Null input");
118 		return WLAN_SER_CMD_DENIED_UNSPECIFIED;
119 	}
120 
121 	if (!wlan_ser_is_vdev_queue_enabled(cmd->vdev))
122 		return WLAN_SER_CMD_QUEUE_DISABLED;
123 	/*
124 	 * Serialization command filtering logic
125 	 * a. If there exists START or PDEV/VDEV restart command in the pending
126 	 * queue then ignore this new vdev restart request.
127 	 * b. Else enqueue the new VDEV RESTART cmd
128 	 */
129 	cmd->cmd_type = WLAN_SER_CMD_VDEV_START_BSS;
130 	if (wlan_serialization_is_cmd_present_in_pending_queue(NULL, cmd)) {
131 		mlme_debug("Start cmd already in the pending queue");
132 		return WLAN_SER_CMD_ALREADY_EXISTS;
133 	}
134 
135 	cmd->cmd_type = WLAN_SER_CMD_PDEV_RESTART;
136 	if (wlan_serialization_is_cmd_present_in_pending_queue(NULL, cmd)) {
137 		mlme_debug("Pdev restart already in the pending queue");
138 		return WLAN_SER_CMD_ALREADY_EXISTS;
139 	}
140 
141 	cmd->cmd_type = WLAN_SER_CMD_VDEV_RESTART;
142 	if (wlan_serialization_is_cmd_present_in_pending_queue(NULL, cmd)) {
143 		mlme_debug("Vdev restart already in the pending queue");
144 		return WLAN_SER_CMD_ALREADY_EXISTS;
145 	}
146 
147 	return wlan_serialization_request(cmd);
148 }
149 
150 void wlan_mlme_restart_pdev_iter_cb(struct wlan_objmgr_pdev *pdev,
151 				    void *object, void *arg)
152 {
153 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
154 	uint8_t *pdev_restart_pending = (uint8_t *)arg;
155 	struct wlan_serialization_command cmd = {0};
156 	uint8_t vdev_id = wlan_vdev_get_id(vdev);
157 
158 	cmd.vdev = vdev;
159 	cmd.cmd_id = vdev_id;
160 	cmd.cmd_type = WLAN_SER_CMD_PDEV_RESTART;
161 	/*
162 	 * Serialization command filtering logic
163 	 * a. Cancel any existing VDEV restart cmd in the pending queue
164 	 * b. If Pdev restart already exist in pending queue then return else
165 	 * enqueue the new PDEV RESTART cmd
166 	 */
167 	wlan_vdev_mlme_ser_cancel_request(
168 			vdev,
169 			WLAN_SER_CMD_VDEV_RESTART,
170 			WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD_TYPE);
171 
172 	if (wlan_serialization_is_cmd_present_in_pending_queue(NULL, &cmd)) {
173 		mlme_debug("Cmd already exist in the pending queue vdev:%u",
174 			   vdev_id);
175 		*pdev_restart_pending = 1;
176 	}
177 }
178 
179 enum wlan_serialization_status
180 wlan_vdev_mlme_ser_pdev_restart(struct wlan_serialization_command *cmd)
181 {
182 	struct wlan_objmgr_pdev *pdev;
183 	uint8_t pdev_restart_in_pending = 0;
184 
185 	if (!cmd || !cmd->vdev) {
186 		mlme_err("Null input");
187 		return WLAN_SER_CMD_DENIED_UNSPECIFIED;
188 	}
189 
190 	if (!wlan_ser_is_vdev_queue_enabled(cmd->vdev))
191 		return WLAN_SER_CMD_QUEUE_DISABLED;
192 
193 	pdev = wlan_vdev_get_pdev(cmd->vdev);
194 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
195 					  wlan_mlme_restart_pdev_iter_cb,
196 					  &pdev_restart_in_pending, 0,
197 					  WLAN_MLME_SER_IF_ID);
198 
199 	if (pdev_restart_in_pending)
200 		return WLAN_SER_CMD_ALREADY_EXISTS;
201 
202 	return wlan_serialization_request(cmd);
203 }
204 
205 enum wlan_serialization_status
206 wlan_vdev_mlme_ser_connect(struct wlan_serialization_command *cmd)
207 {
208 	struct vdev_mlme_obj *vdev_mlme;
209 
210 	if (!cmd || !cmd->vdev) {
211 		mlme_err("Null input");
212 		return WLAN_SER_CMD_DENIED_UNSPECIFIED;
213 	}
214 
215 	if (!wlan_ser_is_vdev_queue_enabled(cmd->vdev))
216 		return WLAN_SER_CMD_QUEUE_DISABLED;
217 	/*
218 	 * Serialization command filtering logic
219 	 * a. Cancel any existing CONNECT cmd in the pending queue
220 	 * b. If there is an CONNECT cmd in active queue and there is no
221 	 * DISCONNECT cmd in pending queue, then explicitly enqueue a
222 	 * DISCONNECT cmd to avoid back to back execution of CONNECT cmd.
223 	 * c. Enqueue the new CONNECT cmd to the pending queue
224 	 */
225 	wlan_vdev_mlme_ser_cancel_request(
226 			cmd->vdev,
227 			WLAN_SER_CMD_VDEV_CONNECT,
228 			WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD_TYPE);
229 
230 	if (wlan_serialization_is_cmd_present_in_active_queue(NULL, cmd)) {
231 		vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(cmd->vdev);
232 		if (mlme_vdev_enqueue_exp_ser_cmd(vdev_mlme,
233 					WLAN_SER_CMD_VDEV_DISCONNECT)) {
234 			mlme_err("Unable to add the exception cmd request");
235 			return WLAN_SER_CMD_DENIED_UNSPECIFIED;
236 		}
237 	}
238 
239 	return wlan_serialization_request(cmd);
240 }
241 
242 enum wlan_serialization_status
243 wlan_vdev_mlme_ser_disconnect(struct wlan_serialization_command *cmd)
244 {
245 	if (!cmd || !cmd->vdev) {
246 		mlme_err("Null input");
247 		return WLAN_SER_CMD_DENIED_UNSPECIFIED;
248 	}
249 
250 	if (!wlan_ser_is_vdev_queue_enabled(cmd->vdev))
251 		return WLAN_SER_CMD_QUEUE_DISABLED;
252 	/*
253 	 * Serialization command filtering logic
254 	 * a.Cancel any existing non-blocking non-scan command in the
255 	 * pending queue
256 	 * b.If there is a DISCONNECT cmd in active queue then return
257 	 * c.Else enqueue the DISCONNECT cmd
258 	 */
259 	wlan_vdev_mlme_ser_cancel_request(cmd->vdev,
260 					  WLAN_SER_CMD_NONSCAN,
261 					  WLAN_SER_CANCEL_VDEV_NON_SCAN_NB_CMD);
262 
263 	if (wlan_serialization_is_cmd_present_in_active_queue(NULL, cmd)) {
264 		mlme_debug("Cmd already exist in the active queue");
265 		return WLAN_SER_CMD_DENIED_UNSPECIFIED;
266 	}
267 
268 	return wlan_serialization_request(cmd);
269 }
270 
271 static void
272 wlan_mlme_cancel_pending_csa_restart(struct wlan_objmgr_pdev *pdev,
273 				     void *object, void *arg)
274 {
275 	struct wlan_objmgr_vdev *vdev = object;
276 	bool *csa_restart_pending = arg;
277 	struct wlan_serialization_command cmd = {0};
278 	uint8_t vdev_id = wlan_vdev_get_id(vdev);
279 
280 	cmd.vdev = vdev;
281 	cmd.cmd_id = vdev_id;
282 	cmd.cmd_type = WLAN_SER_CMD_PDEV_CSA_RESTART;
283 	if (wlan_serialization_is_cmd_present_in_pending_queue(NULL, &cmd)) {
284 		mlme_debug("Cmd already exist in the pending queue vdev:%u",
285 			   vdev_id);
286 		*csa_restart_pending = true;
287 	}
288 
289 	wlan_vdev_mlme_ser_cancel_request(
290 			vdev,
291 			WLAN_SER_CMD_PDEV_CSA_RESTART,
292 			WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD_TYPE);
293 }
294 
295 static void
296 wlan_mlme_check_pdev_restart(struct wlan_objmgr_pdev *pdev,
297 			     void *object, void *arg)
298 {
299 	struct wlan_objmgr_vdev *vdev = object;
300 	bool *pdev_restart_pending  = arg;
301 	struct wlan_serialization_command cmd = {0};
302 	uint8_t vdev_id = wlan_vdev_get_id(vdev);
303 
304 	cmd.vdev = vdev;
305 	cmd.cmd_id = vdev_id;
306 	cmd.cmd_type = WLAN_SER_CMD_PDEV_RESTART;
307 	if (wlan_serialization_is_cmd_present_in_active_queue(NULL, &cmd)) {
308 		mlme_debug("Pdev restart already in the active queue vdev:%u",
309 			   vdev_id);
310 		*pdev_restart_pending = true;
311 	}
312 }
313 
314 enum wlan_serialization_status
315 wlan_vdev_mlme_ser_pdev_csa_restart(struct wlan_serialization_command *cmd)
316 {
317 	struct wlan_objmgr_pdev *pdev;
318 	bool csa_restart_pending = false;
319 	bool pdev_restart_pending = false;
320 	enum wlan_serialization_status ret;
321 
322 	if (!cmd || !cmd->vdev) {
323 		mlme_err("Null input");
324 		return WLAN_SER_CMD_DENIED_UNSPECIFIED;
325 	}
326 
327 	if (!wlan_ser_is_vdev_queue_enabled(cmd->vdev))
328 		return WLAN_SER_CMD_QUEUE_DISABLED;
329 
330 	/*
331 	 * Serialization command filtering logic
332 	 * a. Cancel any existing PDEV CSA restart cmd in the pending queue
333 	 * b. If there exists PDEV RESTART command in the active queue
334 	 *    then deny this request
335 	 * c. If PDEV CSA RESTART cmd already existed in pending queue
336 	 *    then enqueue and return already exists
337 	 * d. Else enqueue this PDEV CSA RESTART cmd
338 	 */
339 	pdev = wlan_vdev_get_pdev(cmd->vdev);
340 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
341 					  wlan_mlme_cancel_pending_csa_restart,
342 					  &csa_restart_pending, 0,
343 					  WLAN_MLME_SER_IF_ID);
344 
345 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
346 					  wlan_mlme_check_pdev_restart,
347 					  &pdev_restart_pending, 0,
348 					  WLAN_MLME_SER_IF_ID);
349 
350 	if (pdev_restart_pending)
351 		return WLAN_SER_CMD_DENIED_UNSPECIFIED;
352 
353 	ret = wlan_serialization_request(cmd);
354 
355 	if (csa_restart_pending && ret == WLAN_SER_CMD_PENDING)
356 		return WLAN_SER_CMD_ALREADY_EXISTS;
357 
358 	return ret;
359 }
360 
361 void
362 wlan_vdev_mlme_ser_remove_request(struct wlan_objmgr_vdev *vdev,
363 				  uint32_t cmd_id,
364 				  enum wlan_serialization_cmd_type cmd_type)
365 {
366 	struct wlan_serialization_queued_cmd_info cmd = {0};
367 
368 	mlme_debug("Vdev:%d remove cmd:%d", wlan_vdev_get_id(vdev), cmd_type);
369 
370 	cmd.vdev = vdev;
371 	cmd.cmd_id = cmd_id;
372 	cmd.cmd_type = cmd_type;
373 	cmd.requestor = WLAN_UMAC_COMP_MLME;
374 	cmd.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD;
375 	cmd.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE;
376 
377 	/* Inform serialization for command completion */
378 	wlan_serialization_remove_cmd(&cmd);
379 }
380 
381 void
382 wlan_vdev_mlme_ser_cancel_request(struct wlan_objmgr_vdev *vdev,
383 				  enum wlan_serialization_cmd_type cmd_type,
384 				  enum wlan_serialization_cancel_type req_type)
385 {
386 	struct wlan_serialization_queued_cmd_info cmd = {0};
387 
388 	cmd.vdev = vdev;
389 	cmd.cmd_type = cmd_type;
390 	cmd.req_type = req_type;
391 	cmd.requestor = WLAN_UMAC_COMP_MLME;
392 	cmd.queue_type = WLAN_SERIALIZATION_PENDING_QUEUE;
393 
394 	wlan_serialization_cancel_request(&cmd);
395 }
396 
397 void
398 mlme_ser_inc_act_cmd_timeout(struct wlan_serialization_command *cmd)
399 {
400 	mlme_debug("Increase timeout of cmd type:%d", cmd->cmd_type);
401 	wlan_serialization_update_timer(cmd);
402 }
403