xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlme/mlme_utils/wlan_vdev_mlme_ser_if.c (revision 11f5a63a6cbdda84849a730de22f0a71e635d58c)
1 /*
2  * Copyright (c) 2018-2019 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 void
272 wlan_vdev_mlme_ser_remove_request(struct wlan_objmgr_vdev *vdev,
273 				  uint32_t cmd_id,
274 				  enum wlan_serialization_cmd_type cmd_type)
275 {
276 	struct wlan_serialization_queued_cmd_info cmd = {0};
277 
278 	mlme_debug("Vdev:%d remove cmd:%d", wlan_vdev_get_id(vdev), cmd_type);
279 
280 	cmd.vdev = vdev;
281 	cmd.cmd_id = cmd_id;
282 	cmd.cmd_type = cmd_type;
283 	cmd.requestor = WLAN_UMAC_COMP_MLME;
284 	cmd.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD;
285 	cmd.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE;
286 
287 	/* Inform serialization for command completion */
288 	wlan_serialization_remove_cmd(&cmd);
289 }
290 
291 void
292 wlan_vdev_mlme_ser_cancel_request(struct wlan_objmgr_vdev *vdev,
293 				  enum wlan_serialization_cmd_type cmd_type,
294 				  enum wlan_serialization_cancel_type req_type)
295 {
296 	struct wlan_serialization_queued_cmd_info cmd = {0};
297 
298 	cmd.vdev = vdev;
299 	cmd.cmd_type = cmd_type;
300 	cmd.req_type = req_type;
301 	cmd.requestor = WLAN_UMAC_COMP_MLME;
302 	cmd.queue_type = WLAN_SERIALIZATION_PENDING_QUEUE;
303 
304 	wlan_serialization_cancel_request(&cmd);
305 }
306 
307 void
308 mlme_ser_inc_act_cmd_timeout(struct wlan_serialization_command *cmd)
309 {
310 	mlme_debug("Increase timeout of cmd type:%d", cmd->cmd_type);
311 	wlan_serialization_update_timer(cmd);
312 }
313