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