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