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 static void 206 wlan_mlme_cancel_pending_csa_restart(struct wlan_objmgr_pdev *pdev, 207 void *object, void *arg) 208 { 209 struct wlan_objmgr_vdev *vdev = object; 210 bool *csa_restart_pending = arg; 211 struct wlan_serialization_command cmd = {0}; 212 uint8_t vdev_id = wlan_vdev_get_id(vdev); 213 214 cmd.vdev = vdev; 215 cmd.cmd_id = vdev_id; 216 cmd.cmd_type = WLAN_SER_CMD_PDEV_CSA_RESTART; 217 if (wlan_serialization_is_cmd_present_in_pending_queue(NULL, &cmd)) { 218 mlme_debug("Cmd already exist in the pending queue vdev:%u", 219 vdev_id); 220 *csa_restart_pending = true; 221 } 222 223 wlan_vdev_mlme_ser_cancel_request( 224 vdev, 225 WLAN_SER_CMD_PDEV_CSA_RESTART, 226 WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD_TYPE); 227 } 228 229 static void 230 wlan_mlme_check_pdev_restart(struct wlan_objmgr_pdev *pdev, 231 void *object, void *arg) 232 { 233 struct wlan_objmgr_vdev *vdev = object; 234 bool *pdev_restart_pending = arg; 235 struct wlan_serialization_command cmd = {0}; 236 uint8_t vdev_id = wlan_vdev_get_id(vdev); 237 238 cmd.vdev = vdev; 239 cmd.cmd_id = vdev_id; 240 cmd.cmd_type = WLAN_SER_CMD_PDEV_RESTART; 241 if (wlan_serialization_is_cmd_present_in_active_queue(NULL, &cmd)) { 242 mlme_debug("Pdev restart already in the active queue vdev:%u", 243 vdev_id); 244 *pdev_restart_pending = true; 245 } 246 } 247 248 enum wlan_serialization_status 249 wlan_vdev_mlme_ser_pdev_csa_restart(struct wlan_serialization_command *cmd) 250 { 251 struct wlan_objmgr_pdev *pdev; 252 bool csa_restart_pending = false; 253 bool pdev_restart_pending = false; 254 enum wlan_serialization_status ret; 255 256 if (!cmd || !cmd->vdev) { 257 mlme_err("Null input"); 258 return WLAN_SER_CMD_DENIED_UNSPECIFIED; 259 } 260 261 if (!wlan_ser_is_vdev_queue_enabled(cmd->vdev)) 262 return WLAN_SER_CMD_QUEUE_DISABLED; 263 264 /* 265 * Serialization command filtering logic 266 * a. Cancel any existing PDEV CSA restart cmd in the pending queue 267 * b. If there exists PDEV RESTART command in the active queue 268 * then deny this request 269 * c. If PDEV CSA RESTART cmd already existed in pending queue 270 * then enqueue and return already exists 271 * d. Else enqueue this PDEV CSA RESTART cmd 272 */ 273 pdev = wlan_vdev_get_pdev(cmd->vdev); 274 wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, 275 wlan_mlme_cancel_pending_csa_restart, 276 &csa_restart_pending, 0, 277 WLAN_MLME_SER_IF_ID); 278 279 wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, 280 wlan_mlme_check_pdev_restart, 281 &pdev_restart_pending, 0, 282 WLAN_MLME_SER_IF_ID); 283 284 if (pdev_restart_pending) 285 return WLAN_SER_CMD_DENIED_UNSPECIFIED; 286 287 ret = wlan_serialization_request(cmd); 288 289 if (csa_restart_pending && ret == WLAN_SER_CMD_PENDING) 290 return WLAN_SER_CMD_ALREADY_EXISTS; 291 292 return ret; 293 } 294 295 void 296 wlan_vdev_mlme_ser_remove_request(struct wlan_objmgr_vdev *vdev, 297 uint32_t cmd_id, 298 enum wlan_serialization_cmd_type cmd_type) 299 { 300 struct wlan_serialization_queued_cmd_info cmd = {0}; 301 302 mlme_debug("Vdev:%d remove cmd:%d", wlan_vdev_get_id(vdev), cmd_type); 303 304 cmd.vdev = vdev; 305 cmd.cmd_id = cmd_id; 306 cmd.cmd_type = cmd_type; 307 cmd.requestor = WLAN_UMAC_COMP_MLME; 308 cmd.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD; 309 cmd.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE; 310 311 /* Inform serialization for command completion */ 312 wlan_serialization_remove_cmd(&cmd); 313 } 314 315 void 316 wlan_vdev_mlme_ser_cancel_request(struct wlan_objmgr_vdev *vdev, 317 enum wlan_serialization_cmd_type cmd_type, 318 enum wlan_serialization_cancel_type req_type) 319 { 320 struct wlan_serialization_queued_cmd_info cmd = {0}; 321 322 cmd.vdev = vdev; 323 cmd.cmd_type = cmd_type; 324 cmd.req_type = req_type; 325 cmd.requestor = WLAN_UMAC_COMP_MLME; 326 cmd.queue_type = WLAN_SERIALIZATION_PENDING_QUEUE; 327 328 wlan_serialization_cancel_request(&cmd); 329 } 330 331 void 332 mlme_ser_inc_act_cmd_timeout(struct wlan_serialization_command *cmd) 333 { 334 mlme_debug("Increase timeout of cmd type:%d", cmd->cmd_type); 335 wlan_serialization_update_timer(cmd); 336 } 337