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 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 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 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 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 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 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 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 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 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 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 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