1 /* 2 * Copyright (c) 2017-2018 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 * DOC: wlan_serialization_legacy_api.c 20 * This file provides prototypes of the routines needed for the 21 * legacy mcl serialization to utilize the services provided by the 22 * serialization component. 23 */ 24 25 #include "wlan_serialization_legacy_api.h" 26 #include "wlan_serialization_main_i.h" 27 #include "wlan_serialization_utils_i.h" 28 #include "wlan_objmgr_vdev_obj.h" 29 30 extern struct serialization_legacy_callback ser_legacy_cb; 31 32 static struct wlan_objmgr_pdev *wlan_serialization_get_first_pdev( 33 struct wlan_objmgr_psoc *psoc) 34 { 35 struct wlan_objmgr_pdev *pdev; 36 uint8_t i = 0; 37 38 if (!psoc) { 39 serialization_err("invalid psoc"); 40 return NULL; 41 } 42 for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) { 43 pdev = wlan_objmgr_get_pdev_by_id(psoc, i, 44 WLAN_SERIALIZATION_ID); 45 if (pdev != NULL) 46 break; 47 } 48 49 return pdev; 50 } 51 52 static struct wlan_serialization_pdev_priv_obj * 53 wlan_serialization_get_pdev_priv_obj_using_psoc(struct wlan_objmgr_psoc *psoc) 54 { 55 struct wlan_objmgr_pdev *pdev = NULL; 56 struct wlan_serialization_pdev_priv_obj *ser_pdev_obj; 57 58 if (!psoc) { 59 serialization_err("invalid psoc"); 60 return NULL; 61 } 62 63 pdev = wlan_serialization_get_first_pdev(psoc); 64 if (!pdev) { 65 serialization_err("invalid pdev"); 66 return NULL; 67 } 68 69 ser_pdev_obj = wlan_serialization_get_pdev_priv_obj(pdev); 70 wlan_objmgr_pdev_release_ref(pdev, WLAN_SERIALIZATION_ID); 71 if (!ser_pdev_obj) { 72 serialization_err("invalid ser_pdev_obj"); 73 return NULL; 74 } 75 76 return ser_pdev_obj; 77 } 78 79 uint32_t wlan_serialization_get_active_list_count( 80 struct wlan_objmgr_psoc *psoc, 81 uint8_t is_cmd_from_active_scan_queue) 82 { 83 struct wlan_serialization_pdev_priv_obj *ser_pdev_obj; 84 qdf_list_t *queue; 85 uint32_t count; 86 87 ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc); 88 if (!ser_pdev_obj) { 89 serialization_err("invalid ser_pdev_obj"); 90 return 0; 91 } 92 93 wlan_serialization_acquire_lock(ser_pdev_obj); 94 if (is_cmd_from_active_scan_queue) 95 queue = &ser_pdev_obj->active_scan_list; 96 else 97 queue = &ser_pdev_obj->active_list; 98 99 count = qdf_list_size(queue); 100 wlan_serialization_release_lock(ser_pdev_obj); 101 102 return count; 103 } 104 105 uint32_t wlan_serialization_get_pending_list_count( 106 struct wlan_objmgr_psoc *psoc, 107 uint8_t is_cmd_from_pending_scan_queue) 108 { 109 struct wlan_serialization_pdev_priv_obj *ser_pdev_obj; 110 qdf_list_t *queue; 111 uint32_t count = 0; 112 113 ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc); 114 if (!ser_pdev_obj) { 115 serialization_err("invalid ser_pdev_obj"); 116 return 0; 117 } 118 119 wlan_serialization_acquire_lock(ser_pdev_obj); 120 if (is_cmd_from_pending_scan_queue) 121 queue = &ser_pdev_obj->pending_scan_list; 122 else 123 queue = &ser_pdev_obj->pending_list; 124 125 count = qdf_list_size(queue); 126 wlan_serialization_release_lock(ser_pdev_obj); 127 128 return count; 129 } 130 131 struct wlan_serialization_command* 132 wlan_serialization_peek_head_active_cmd_using_psoc( 133 struct wlan_objmgr_psoc *psoc, 134 uint8_t is_cmd_from_active_scan_queue) 135 { 136 struct wlan_serialization_pdev_priv_obj *ser_pdev_obj; 137 struct wlan_serialization_command_list *cmd_list = NULL; 138 struct wlan_serialization_command *cmd = NULL; 139 qdf_list_node_t *nnode = NULL; 140 qdf_list_t *queue; 141 142 ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc); 143 if (!ser_pdev_obj) { 144 serialization_err("invalid ser_pdev_obj"); 145 return NULL; 146 } 147 148 if (is_cmd_from_active_scan_queue) 149 queue = &ser_pdev_obj->active_scan_list; 150 else 151 queue = &ser_pdev_obj->active_list; 152 if (wlan_serialization_list_empty(queue, ser_pdev_obj)) { 153 serialization_err("Empty Queue"); 154 goto end; 155 } 156 157 if (QDF_STATUS_SUCCESS != wlan_serialization_get_cmd_from_queue(queue, 158 &nnode, ser_pdev_obj)) { 159 serialization_err("Can't get command from queue"); 160 goto end; 161 } 162 163 cmd_list = qdf_container_of(nnode, 164 struct wlan_serialization_command_list, node); 165 cmd = &cmd_list->cmd; 166 serialization_debug("cmd_type[%d], cmd_id[%d]", 167 cmd_list->cmd.cmd_type, cmd_list->cmd.cmd_id); 168 169 end: 170 return cmd; 171 } 172 173 struct wlan_serialization_command* 174 wlan_serialization_peek_head_pending_cmd_using_psoc( 175 struct wlan_objmgr_psoc *psoc, 176 uint8_t is_cmd_from_pending_scan_queue) 177 { 178 struct wlan_serialization_pdev_priv_obj *ser_pdev_obj; 179 struct wlan_serialization_command_list *cmd_list = NULL; 180 struct wlan_serialization_command *cmd = NULL; 181 qdf_list_node_t *nnode = NULL; 182 qdf_list_t *queue; 183 184 ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc); 185 if (!ser_pdev_obj) { 186 serialization_err("invalid ser_pdev_obj"); 187 return NULL; 188 } 189 if (is_cmd_from_pending_scan_queue) 190 queue = &ser_pdev_obj->pending_scan_list; 191 else 192 queue = &ser_pdev_obj->pending_list; 193 if (wlan_serialization_list_empty(queue, ser_pdev_obj)) { 194 serialization_err("Empty Queue"); 195 goto end; 196 } 197 198 if (QDF_STATUS_SUCCESS != wlan_serialization_get_cmd_from_queue(queue, 199 &nnode, ser_pdev_obj)) { 200 serialization_err("Can't get command from queue"); 201 goto end; 202 } 203 cmd_list = qdf_container_of(nnode, 204 struct wlan_serialization_command_list, node); 205 cmd = &cmd_list->cmd; 206 serialization_debug("cmd_type[%d] cmd_id[%d]matched", 207 cmd_list->cmd.cmd_type, cmd_list->cmd.cmd_id); 208 209 end: 210 return cmd; 211 } 212 213 static struct wlan_serialization_command* 214 wlan_serialization_get_list_next_node(qdf_list_t *queue, 215 struct wlan_serialization_command *cmd, 216 struct wlan_serialization_pdev_priv_obj *ser_pdev_obj) 217 { 218 struct wlan_serialization_command_list *cmd_list = NULL; 219 qdf_list_node_t *pnode = NULL, *nnode = NULL; 220 bool found = false; 221 uint32_t i = 0; 222 QDF_STATUS status; 223 struct wlan_serialization_command *ret_cmd = NULL; 224 225 i = wlan_serialization_list_size(queue, ser_pdev_obj); 226 if (i == 0) { 227 serialization_err("Empty Queue"); 228 return NULL; 229 } 230 while (i--) { 231 if (!cmd_list) 232 status = wlan_serialization_peek_front(queue, &nnode, 233 ser_pdev_obj); 234 else 235 status = wlan_serialization_peek_next(queue, pnode, 236 &nnode, 237 ser_pdev_obj); 238 239 if ((status != QDF_STATUS_SUCCESS) || found) 240 break; 241 242 pnode = nnode; 243 cmd_list = qdf_container_of( 244 nnode, 245 struct wlan_serialization_command_list, 246 node); 247 if (wlan_serialization_match_cmd_id_type(nnode, cmd, 248 ser_pdev_obj) && 249 wlan_serialization_match_cmd_vdev(nnode, 250 cmd->vdev)) { 251 found = true; 252 } 253 nnode = NULL; 254 } 255 if (nnode && found) { 256 cmd_list = qdf_container_of(nnode, 257 struct wlan_serialization_command_list, node); 258 ret_cmd = &cmd_list->cmd; 259 } 260 if (!found) { 261 serialization_err("Can't locate next command"); 262 return NULL; 263 } 264 if (!nnode) { 265 serialization_debug("next node is empty, so fine"); 266 return NULL; 267 } 268 269 return ret_cmd; 270 } 271 272 struct wlan_serialization_command* 273 wlan_serialization_get_active_list_next_node_using_psoc( 274 struct wlan_objmgr_psoc *psoc, 275 struct wlan_serialization_command *prev_cmd, 276 uint8_t is_cmd_for_active_scan_queue) 277 { 278 struct wlan_serialization_pdev_priv_obj *ser_pdev_obj; 279 qdf_list_t *queue; 280 281 if (!prev_cmd) { 282 serialization_err("invalid prev_cmd"); 283 return NULL; 284 } 285 286 ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc); 287 if (!ser_pdev_obj) { 288 serialization_err("invalid ser_pdev_obj"); 289 return NULL; 290 } 291 292 if (is_cmd_for_active_scan_queue) 293 queue = &ser_pdev_obj->active_scan_list; 294 else 295 queue = &ser_pdev_obj->active_list; 296 297 return wlan_serialization_get_list_next_node(queue, prev_cmd, 298 ser_pdev_obj); 299 } 300 301 struct wlan_serialization_command* 302 wlan_serialization_get_pending_list_next_node_using_psoc( 303 struct wlan_objmgr_psoc *psoc, 304 struct wlan_serialization_command *prev_cmd, 305 uint8_t is_cmd_for_pending_scan_queue) 306 { 307 struct wlan_serialization_pdev_priv_obj *ser_pdev_obj; 308 qdf_list_t *queue; 309 310 if (!prev_cmd) { 311 serialization_err("invalid prev_cmd"); 312 return NULL; 313 } 314 315 ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc); 316 if (!ser_pdev_obj) { 317 serialization_err("invalid ser_pdev_obj"); 318 return NULL; 319 } 320 if (is_cmd_for_pending_scan_queue) 321 queue = &ser_pdev_obj->pending_scan_list; 322 else 323 queue = &ser_pdev_obj->pending_list; 324 325 return wlan_serialization_get_list_next_node(queue, prev_cmd, 326 ser_pdev_obj); 327 } 328 329 void wlan_serialization_legacy_init_callback(void) 330 { 331 ser_legacy_cb.serialization_purge_cmd_list = 332 wlan_serialization_purge_cmd_list; 333 } 334 335 void wlan_serialization_purge_cmd_list_by_vdev_id(struct wlan_objmgr_psoc *psoc, 336 uint8_t vdev_id, bool purge_scan_active_queue, 337 bool purge_scan_pending_queue, 338 bool purge_nonscan_active_queue, 339 bool purge_nonscan_pending_queue, 340 bool purge_all_queues) 341 { 342 struct wlan_objmgr_vdev *vdev; 343 344 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 345 WLAN_SERIALIZATION_ID); 346 if (!vdev) { 347 serialization_err("Invalid vdev"); 348 return; 349 } 350 wlan_serialization_purge_cmd_list(psoc, vdev, purge_scan_active_queue, 351 purge_scan_pending_queue, 352 purge_nonscan_active_queue, 353 purge_nonscan_pending_queue, 354 purge_all_queues); 355 wlan_objmgr_vdev_release_ref(vdev, WLAN_SERIALIZATION_ID); 356 } 357 358 void wlan_serialization_purge_cmd_list(struct wlan_objmgr_psoc *psoc, 359 struct wlan_objmgr_vdev *vdev, 360 bool purge_scan_active_queue, 361 bool purge_scan_pending_queue, 362 bool purge_nonscan_active_queue, 363 bool purge_nonscan_pending_queue, 364 bool purge_all_queues) 365 { 366 struct wlan_serialization_timer *ser_timer; 367 struct wlan_serialization_psoc_priv_obj *psoc_ser_obj; 368 struct wlan_serialization_pdev_priv_obj *ser_pdev_obj; 369 struct wlan_objmgr_pdev *pdev = NULL; 370 uint32_t i = 0; 371 372 if (!psoc) { 373 serialization_err("Invalid psoc"); 374 return; 375 } 376 ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc); 377 if (!ser_pdev_obj) { 378 serialization_err("Invalid ser_pdev_obj"); 379 return; 380 } 381 psoc_ser_obj = wlan_serialization_get_psoc_priv_obj(psoc); 382 if (!psoc_ser_obj) { 383 serialization_err("Invalid psoc_ser_obj"); 384 return; 385 } 386 pdev = wlan_serialization_get_first_pdev(psoc); 387 if (!pdev) { 388 serialization_err("Invalid pdev"); 389 return; 390 } 391 for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) { 392 ser_timer = &psoc_ser_obj->timers[i]; 393 if (!ser_timer->cmd) 394 continue; 395 if (vdev && (vdev != ser_timer->cmd->vdev)) 396 continue; 397 /* 398 * if request is to purge active scan then don't de-activate 399 * non-scan cmds. If request is to purge all queues then 400 * de-activate all the timers. 401 */ 402 if (!purge_all_queues && purge_scan_active_queue && 403 (ser_timer->cmd->cmd_type >= WLAN_SER_CMD_NONSCAN)) 404 continue; 405 /* 406 * if request is to purge active nonscan then don't de-activate 407 * scan cmds. If request is to purge all queues then 408 * de-activate all the timers. 409 */ 410 if (!purge_all_queues && purge_nonscan_active_queue && 411 (ser_timer->cmd->cmd_type < WLAN_SER_CMD_NONSCAN)) 412 continue; 413 414 if (QDF_STATUS_SUCCESS != 415 wlan_serialization_find_and_stop_timer(psoc, 416 ser_timer->cmd)) 417 serialization_err("some error in stopping timer"); 418 } 419 if (purge_all_queues || purge_scan_active_queue) { 420 /* sending active queue as pending queue to leverage the API */ 421 wlan_serialization_remove_all_cmd_from_queue( 422 &ser_pdev_obj->active_scan_list, ser_pdev_obj, 423 pdev, vdev, NULL, false); 424 } 425 if (purge_all_queues || purge_scan_pending_queue) { 426 wlan_serialization_remove_all_cmd_from_queue( 427 &ser_pdev_obj->pending_scan_list, ser_pdev_obj, 428 pdev, vdev, NULL, false); 429 } 430 if (purge_all_queues || purge_nonscan_active_queue) { 431 /* sending active queue as pending queue to leverage the API */ 432 wlan_serialization_remove_all_cmd_from_queue( 433 &ser_pdev_obj->active_list, ser_pdev_obj, 434 pdev, vdev, NULL, false); 435 } 436 if (purge_all_queues || purge_nonscan_pending_queue) { 437 wlan_serialization_remove_all_cmd_from_queue( 438 &ser_pdev_obj->pending_list, ser_pdev_obj, 439 pdev, vdev, NULL, false); 440 } 441 wlan_objmgr_pdev_release_ref(pdev, WLAN_SERIALIZATION_ID); 442 443 return; 444 } 445