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