1 /* 2 * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /** 21 * DOC: wlan_serialization_scan.c 22 * This file defines the functions which deals with 23 * serialization scan commands. 24 */ 25 26 #include "wlan_serialization_utils_i.h" 27 #include "wlan_serialization_main_i.h" 28 #include "wlan_serialization_api.h" 29 #include "wlan_serialization_scan_i.h" 30 #include <wlan_objmgr_vdev_obj.h> 31 #include <wlan_objmgr_pdev_obj.h> 32 #include <qdf_mc_timer.h> 33 #include <wlan_utility.h> 34 35 void 36 wlan_serialization_active_scan_cmd_count_handler(struct wlan_objmgr_psoc *psoc, 37 void *obj, void *arg) 38 { 39 struct wlan_objmgr_pdev *pdev = obj; 40 struct wlan_ser_pdev_obj *ser_pdev_obj; 41 struct wlan_serialization_pdev_queue *pdev_q; 42 uint32_t *count = arg; 43 44 if (!pdev) { 45 ser_err("invalid pdev"); 46 return; 47 } 48 49 ser_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj( 50 pdev, WLAN_UMAC_COMP_SERIALIZATION); 51 52 pdev_q = &ser_pdev_obj->pdev_q[SER_PDEV_QUEUE_COMP_SCAN]; 53 *count += wlan_serialization_list_size(&pdev_q->active_list); 54 } 55 56 bool 57 wlan_serialization_is_scan_pending_queue_empty( 58 struct wlan_serialization_command *cmd) 59 { 60 struct wlan_objmgr_pdev *pdev; 61 struct wlan_ser_pdev_obj *ser_pdev_obj = NULL; 62 struct wlan_serialization_pdev_queue *pdev_q; 63 bool status = false; 64 65 pdev = wlan_serialization_get_pdev_from_cmd(cmd); 66 ser_pdev_obj = wlan_serialization_get_pdev_obj(pdev); 67 68 pdev_q = &ser_pdev_obj->pdev_q[SER_PDEV_QUEUE_COMP_SCAN]; 69 70 if (qdf_list_empty(&pdev_q->pending_list)) 71 status = true; 72 73 return status; 74 } 75 76 bool 77 wlan_serialization_is_active_scan_cmd_allowed( 78 struct wlan_serialization_command *cmd) 79 { 80 uint32_t count = 0; 81 struct wlan_objmgr_pdev *pdev = NULL; 82 struct wlan_objmgr_psoc *psoc; 83 bool status = false; 84 85 pdev = wlan_serialization_get_pdev_from_cmd(cmd); 86 if (!pdev) { 87 ser_err("invalid pdev"); 88 goto error; 89 } 90 91 psoc = wlan_pdev_get_psoc(pdev); 92 if (!psoc) { 93 ser_err("invalid psoc"); 94 goto error; 95 } 96 97 wlan_objmgr_iterate_obj_list( 98 psoc, WLAN_PDEV_OP, 99 wlan_serialization_active_scan_cmd_count_handler, 100 &count, 1, WLAN_SERIALIZATION_ID); 101 if (count < ucfg_scan_get_max_active_scans(psoc)) 102 status = true; 103 104 error: 105 return status; 106 } 107 108 bool wlan_ser_match_cmd_scan_id( 109 qdf_list_node_t *nnode, 110 struct wlan_serialization_command **cmd, 111 uint16_t scan_id, struct wlan_objmgr_vdev *vdev) 112 { 113 struct wlan_serialization_command_list *cmd_list = NULL; 114 bool match_found = false; 115 116 cmd_list = qdf_container_of(nnode, 117 struct wlan_serialization_command_list, 118 pdev_node); 119 if ((cmd_list->cmd.cmd_id == scan_id) && 120 (cmd_list->cmd.vdev == vdev)) { 121 *cmd = &cmd_list->cmd; 122 match_found = true; 123 }; 124 125 ser_debug("match found: %d", match_found); 126 127 return match_found; 128 } 129 130 enum wlan_serialization_status 131 wlan_ser_add_scan_cmd( 132 struct wlan_ser_pdev_obj *ser_pdev_obj, 133 struct wlan_serialization_command_list *cmd_list, 134 uint8_t is_cmd_for_active_queue) 135 { 136 enum wlan_serialization_status status; 137 138 status = wlan_serialization_add_cmd_to_pdev_queue( 139 ser_pdev_obj, cmd_list, 140 is_cmd_for_active_queue); 141 142 return status; 143 } 144 145 QDF_STATUS 146 wlan_ser_remove_scan_cmd( 147 struct wlan_ser_pdev_obj *ser_pdev_obj, 148 struct wlan_serialization_command_list **pcmd_list, 149 struct wlan_serialization_command *cmd, 150 uint8_t is_active_cmd) 151 { 152 QDF_STATUS status; 153 154 status = wlan_serialization_remove_cmd_from_pdev_queue( 155 ser_pdev_obj, pcmd_list, cmd, is_active_cmd); 156 157 return status; 158 } 159 160 enum wlan_serialization_cmd_status 161 wlan_ser_cancel_scan_cmd( 162 struct wlan_ser_pdev_obj *ser_obj, 163 struct wlan_objmgr_pdev *pdev, struct wlan_objmgr_vdev *vdev, 164 struct wlan_serialization_command *cmd, 165 enum wlan_serialization_cmd_type cmd_type, 166 uint8_t is_active_queue) 167 { 168 qdf_list_t *queue; 169 struct wlan_serialization_pdev_queue *pdev_q; 170 uint32_t qsize; 171 struct wlan_serialization_command_list *cmd_list = NULL; 172 struct wlan_serialization_command cmd_bkup; 173 qdf_list_node_t *nnode = NULL, *pnode = NULL; 174 enum wlan_serialization_cmd_status status = WLAN_SER_CMD_NOT_FOUND; 175 struct wlan_objmgr_psoc *psoc = NULL; 176 QDF_STATUS qdf_status; 177 178 pdev_q = &ser_obj->pdev_q[SER_PDEV_QUEUE_COMP_SCAN]; 179 180 if (is_active_queue) 181 queue = &pdev_q->active_list; 182 else 183 queue = &pdev_q->pending_list; 184 185 if (pdev) 186 psoc = wlan_pdev_get_psoc(pdev); 187 else if (vdev) 188 psoc = wlan_vdev_get_psoc(vdev); 189 else if (cmd && cmd->vdev) 190 psoc = wlan_vdev_get_psoc(cmd->vdev); 191 else 192 ser_debug("Can't find psoc"); 193 194 wlan_serialization_acquire_lock(&pdev_q->pdev_queue_lock); 195 196 qsize = wlan_serialization_list_size(queue); 197 while (!wlan_serialization_list_empty(queue) && qsize--) { 198 if (wlan_serialization_get_cmd_from_queue( 199 queue, &nnode) != QDF_STATUS_SUCCESS) { 200 ser_err("can't read cmd from queue"); 201 status = WLAN_SER_CMD_NOT_FOUND; 202 break; 203 } 204 cmd_list = 205 qdf_container_of(nnode, 206 struct wlan_serialization_command_list, 207 pdev_node); 208 209 if (cmd && 210 !(wlan_serialization_match_cmd_id_type(nnode, cmd, 211 WLAN_SER_PDEV_NODE) && 212 wlan_serialization_match_cmd_vdev(nnode, cmd->vdev, 213 WLAN_SER_PDEV_NODE))) { 214 pnode = nnode; 215 continue; 216 } 217 if (vdev && 218 !wlan_serialization_match_cmd_vdev(nnode, 219 vdev, 220 WLAN_SER_PDEV_NODE)) { 221 pnode = nnode; 222 continue; 223 } 224 225 if (pdev && 226 !wlan_serialization_match_cmd_pdev(nnode, 227 pdev, 228 WLAN_SER_PDEV_NODE)) { 229 pnode = nnode; 230 continue; 231 } 232 233 /* 234 * active queue can't be removed directly, requester needs to 235 * wait for active command response and send remove request for 236 * active command separately 237 */ 238 if (is_active_queue) { 239 if (!psoc || !cmd_list) { 240 ser_err("psoc:0x%pK, cmd_list:0x%pK", 241 psoc, cmd_list); 242 status = WLAN_SER_CMD_NOT_FOUND; 243 break; 244 } 245 246 /* Cancel request received for a cmd in active 247 * queue which has not been activated yet, we mark 248 * it as CMD_ACTIVE_MARKED_FOR_CANCEL and remove 249 * the cmd after activation 250 */ 251 if (qdf_atomic_test_bit(CMD_MARKED_FOR_ACTIVATION, 252 &cmd_list->cmd_in_use)) { 253 qdf_atomic_set_bit(CMD_ACTIVE_MARKED_FOR_CANCEL, 254 &cmd_list->cmd_in_use); 255 status = WLAN_SER_CMD_MARKED_FOR_ACTIVATION; 256 continue; 257 } 258 259 qdf_status = wlan_serialization_find_and_stop_timer( 260 psoc, &cmd_list->cmd, 261 SER_CANCEL); 262 if (QDF_IS_STATUS_ERROR(qdf_status)) { 263 ser_err("Can't fix timer for active cmd"); 264 status = WLAN_SER_CMD_NOT_FOUND; 265 /* 266 * This should not happen, as an active command 267 * should always have the timer. 268 */ 269 QDF_BUG(0); 270 break; 271 } 272 273 status = WLAN_SER_CMD_IN_ACTIVE_LIST; 274 } 275 276 qdf_mem_copy(&cmd_bkup, &cmd_list->cmd, 277 sizeof(struct wlan_serialization_command)); 278 279 qdf_status = 280 wlan_serialization_remove_node(queue, 281 &cmd_list->pdev_node); 282 283 if (qdf_status != QDF_STATUS_SUCCESS) { 284 ser_err("can't remove cmd from pdev queue"); 285 status = WLAN_SER_CMD_NOT_FOUND; 286 break; 287 } 288 289 qdf_mem_zero(&cmd_list->cmd, 290 sizeof(struct wlan_serialization_command)); 291 cmd_list->cmd_in_use = 0; 292 qdf_status = wlan_serialization_insert_back( 293 &pdev_q->cmd_pool_list, 294 &cmd_list->pdev_node); 295 296 if (QDF_STATUS_SUCCESS != qdf_status) { 297 ser_err("can't remove cmd from queue"); 298 status = WLAN_SER_CMD_NOT_FOUND; 299 break; 300 } 301 nnode = pnode; 302 303 wlan_ser_update_cmd_history(pdev_q, &cmd_bkup, 304 SER_CANCEL, false, is_active_queue); 305 306 wlan_serialization_release_lock(&pdev_q->pdev_queue_lock); 307 /* 308 * call pending cmd's callback to notify that 309 * it is being removed 310 */ 311 if (cmd_bkup.cmd_cb) { 312 ser_debug("Cancel command: type %d id %d vdev %d and Release memory", 313 cmd_bkup.cmd_type, cmd_bkup.cmd_id, 314 wlan_vdev_get_id(cmd_bkup.vdev)); 315 cmd_bkup.cmd_cb(&cmd_bkup, WLAN_SER_CB_CANCEL_CMD); 316 cmd_bkup.cmd_cb(&cmd_bkup, WLAN_SER_CB_RELEASE_MEM_CMD); 317 } 318 319 wlan_serialization_acquire_lock(&pdev_q->pdev_queue_lock); 320 321 if (!is_active_queue) 322 status = WLAN_SER_CMD_IN_PENDING_LIST; 323 } 324 325 wlan_serialization_release_lock(&pdev_q->pdev_queue_lock); 326 327 return status; 328 } 329 330 enum wlan_serialization_status wlan_ser_move_scan_pending_to_active( 331 struct wlan_ser_pdev_obj *ser_pdev_obj) 332 { 333 struct wlan_serialization_command_list *pending_cmd_list = NULL; 334 struct wlan_serialization_command_list *active_cmd_list; 335 struct wlan_serialization_command cmd_to_remove; 336 enum wlan_serialization_status status = WLAN_SER_CMD_DENIED_UNSPECIFIED; 337 QDF_STATUS qdf_status; 338 struct wlan_serialization_pdev_queue *pdev_queue; 339 qdf_list_t *pending_queue; 340 qdf_list_node_t *pending_node = NULL; 341 342 pdev_queue = &ser_pdev_obj->pdev_q[SER_PDEV_QUEUE_COMP_SCAN]; 343 344 if (!ser_pdev_obj) { 345 ser_err("Can't find ser_pdev_obj"); 346 goto error; 347 } 348 349 wlan_serialization_acquire_lock(&pdev_queue->pdev_queue_lock); 350 351 pending_queue = &pdev_queue->pending_list; 352 353 if (wlan_serialization_list_empty(pending_queue)) { 354 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 355 goto error; 356 } 357 358 qdf_status = wlan_serialization_peek_front(pending_queue, 359 &pending_node); 360 if (QDF_STATUS_SUCCESS != qdf_status) { 361 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 362 ser_err("can't read from pending queue"); 363 goto error; 364 } 365 366 pending_cmd_list = 367 qdf_container_of(pending_node, 368 struct wlan_serialization_command_list, 369 pdev_node); 370 371 if (!pending_cmd_list) { 372 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 373 goto error; 374 } 375 376 qdf_mem_copy(&cmd_to_remove, &pending_cmd_list->cmd, 377 sizeof(struct wlan_serialization_command)); 378 379 if (!wlan_serialization_is_active_scan_cmd_allowed(&cmd_to_remove)) { 380 ser_debug("active scan command not allowed"); 381 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 382 goto error; 383 } 384 385 qdf_status = 386 wlan_ser_remove_scan_cmd(ser_pdev_obj, 387 &pending_cmd_list, 388 &cmd_to_remove, false); 389 390 wlan_ser_update_cmd_history(pdev_queue, &pending_cmd_list->cmd, 391 SER_PENDING_TO_ACTIVE, 392 false, false); 393 394 if (QDF_STATUS_SUCCESS != qdf_status) { 395 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 396 ser_err("Can't remove from pendingQ id %d type %d", 397 pending_cmd_list->cmd.cmd_id, 398 pending_cmd_list->cmd.cmd_type); 399 QDF_ASSERT(0); 400 status = WLAN_SER_CMD_DENIED_UNSPECIFIED; 401 goto error; 402 } 403 404 active_cmd_list = pending_cmd_list; 405 406 status = wlan_ser_add_scan_cmd(ser_pdev_obj, 407 active_cmd_list, true); 408 409 if (WLAN_SER_CMD_ACTIVE != status) { 410 wlan_serialization_insert_back( 411 &pdev_queue->cmd_pool_list, 412 &active_cmd_list->pdev_node); 413 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 414 status = WLAN_SER_CMD_DENIED_UNSPECIFIED; 415 ser_err("Can't add cmd to activeQ id-%d type-%d", 416 active_cmd_list->cmd.cmd_id, 417 active_cmd_list->cmd.cmd_type); 418 QDF_ASSERT(0); 419 goto error; 420 } 421 422 qdf_atomic_set_bit(CMD_MARKED_FOR_ACTIVATION, 423 &active_cmd_list->cmd_in_use); 424 425 wlan_ser_update_cmd_history(pdev_queue, &active_cmd_list->cmd, 426 SER_PENDING_TO_ACTIVE, 427 true, true); 428 429 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock); 430 431 wlan_serialization_activate_cmd(active_cmd_list, ser_pdev_obj, 432 SER_PENDING_TO_ACTIVE); 433 error: 434 return status; 435 } 436