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 86 ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc); 87 if (!ser_pdev_obj) { 88 serialization_err("invalid ser_pdev_obj"); 89 return 0; 90 } 91 92 if (is_cmd_from_active_scan_queue) 93 queue = &ser_pdev_obj->active_scan_list; 94 else 95 queue = &ser_pdev_obj->active_list; 96 97 return qdf_list_size(queue); 98 } 99 100 uint32_t wlan_serialization_get_pending_list_count( 101 struct wlan_objmgr_psoc *psoc, 102 uint8_t is_cmd_from_pending_scan_queue) 103 { 104 struct wlan_serialization_pdev_priv_obj *ser_pdev_obj; 105 qdf_list_t *queue; 106 107 ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc); 108 if (!ser_pdev_obj) { 109 serialization_err("invalid ser_pdev_obj"); 110 return 0; 111 } 112 113 if (is_cmd_from_pending_scan_queue) 114 queue = &ser_pdev_obj->pending_scan_list; 115 else 116 queue = &ser_pdev_obj->pending_list; 117 118 return qdf_list_size(queue); 119 } 120 121 struct wlan_serialization_command* 122 wlan_serialization_peek_head_active_cmd_using_psoc( 123 struct wlan_objmgr_psoc *psoc, 124 uint8_t is_cmd_from_active_scan_queue) 125 { 126 struct wlan_serialization_pdev_priv_obj *ser_pdev_obj; 127 struct wlan_serialization_command_list *cmd_list = NULL; 128 struct wlan_serialization_command *cmd = NULL; 129 qdf_list_node_t *nnode = NULL; 130 qdf_list_t *queue; 131 132 ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc); 133 if (!ser_pdev_obj) { 134 serialization_err("invalid ser_pdev_obj"); 135 return 0; 136 } 137 138 if (is_cmd_from_active_scan_queue) 139 queue = &ser_pdev_obj->active_scan_list; 140 else 141 queue = &ser_pdev_obj->active_list; 142 if (!qdf_list_size(queue)) { 143 serialization_err("Empty Queue"); 144 return NULL; 145 } 146 147 if (QDF_STATUS_SUCCESS != wlan_serialization_get_cmd_from_queue(queue, 148 &nnode)) { 149 serialization_err("Can't get command from queue"); 150 return NULL; 151 } 152 153 cmd_list = qdf_container_of(nnode, 154 struct wlan_serialization_command_list, node); 155 serialization_debug("cmd_type[%d]", cmd_list->cmd.cmd_type); 156 cmd = &cmd_list->cmd; 157 158 return cmd; 159 } 160 161 struct wlan_serialization_command* 162 wlan_serialization_peek_head_pending_cmd_using_psoc( 163 struct wlan_objmgr_psoc *psoc, 164 uint8_t is_cmd_from_pending_scan_queue) 165 { 166 struct wlan_serialization_pdev_priv_obj *ser_pdev_obj; 167 struct wlan_serialization_command_list *cmd_list = NULL; 168 struct wlan_serialization_command *cmd = NULL; 169 qdf_list_node_t *nnode = NULL; 170 qdf_list_t *queue; 171 172 ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc); 173 if (!ser_pdev_obj) { 174 serialization_err("invalid ser_pdev_obj"); 175 return 0; 176 } 177 178 if (is_cmd_from_pending_scan_queue) 179 queue = &ser_pdev_obj->pending_scan_list; 180 else 181 queue = &ser_pdev_obj->pending_list; 182 if (!qdf_list_size(queue)) { 183 serialization_err("Empty Queue"); 184 return NULL; 185 } 186 187 if (QDF_STATUS_SUCCESS != wlan_serialization_get_cmd_from_queue(queue, 188 &nnode)) { 189 serialization_err("Can't get command from queue"); 190 return NULL; 191 } 192 cmd_list = qdf_container_of(nnode, 193 struct wlan_serialization_command_list, node); 194 serialization_debug("cmd_type[%d] matched", cmd_list->cmd.cmd_type); 195 cmd = &cmd_list->cmd; 196 197 return cmd; 198 } 199 200 static struct wlan_serialization_command* 201 wlan_serialization_get_list_next_node(qdf_list_t *queue, 202 struct wlan_serialization_command *cmd) 203 { 204 struct wlan_serialization_command_list *cmd_list = NULL; 205 qdf_list_node_t *pnode = NULL, *nnode = NULL; 206 bool found = false; 207 uint32_t i = 0; 208 QDF_STATUS status; 209 210 if (!qdf_list_empty(queue)) { 211 i = qdf_list_size(queue); 212 while (i--) { 213 if (!cmd_list) 214 status = qdf_list_peek_front(queue, &nnode); 215 else 216 status = qdf_list_peek_next(queue, pnode, 217 &nnode); 218 219 if ((status != QDF_STATUS_SUCCESS) || found) 220 break; 221 222 pnode = nnode; 223 cmd_list = qdf_container_of(nnode, 224 struct wlan_serialization_command_list, 225 node); 226 if ((cmd_list->cmd.cmd_id == cmd->cmd_id) && 227 (cmd_list->cmd.cmd_type == cmd->cmd_type) && 228 (cmd_list->cmd.vdev == cmd->vdev)) { 229 found = true; 230 } 231 nnode = NULL; 232 } 233 } 234 if (nnode && found) { 235 cmd_list = qdf_container_of(nnode, 236 struct wlan_serialization_command_list, node); 237 return &cmd_list->cmd; 238 } else if (!found) { 239 serialization_err("Can't locate next command"); 240 return NULL; 241 } else { 242 serialization_debug("next node is empty, so fine"); 243 return NULL; 244 } 245 } 246 247 struct wlan_serialization_command* 248 wlan_serialization_get_active_list_next_node_using_psoc( 249 struct wlan_objmgr_psoc *psoc, 250 struct wlan_serialization_command *prev_cmd, 251 uint8_t is_cmd_for_active_scan_queue) 252 { 253 struct wlan_serialization_pdev_priv_obj *ser_pdev_obj; 254 qdf_list_t *queue; 255 256 if (!prev_cmd) { 257 serialization_err("invalid prev_cmd"); 258 return NULL; 259 } 260 261 ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc); 262 if (!ser_pdev_obj) { 263 serialization_err("invalid ser_pdev_obj"); 264 return 0; 265 } 266 267 if (is_cmd_for_active_scan_queue) 268 queue = &ser_pdev_obj->active_scan_list; 269 else 270 queue = &ser_pdev_obj->active_list; 271 if (!qdf_list_size(queue)) { 272 serialization_err("Empty Queue"); 273 return NULL; 274 } 275 276 return wlan_serialization_get_list_next_node(queue, prev_cmd); 277 } 278 279 struct wlan_serialization_command* 280 wlan_serialization_get_pending_list_next_node_using_psoc( 281 struct wlan_objmgr_psoc *psoc, 282 struct wlan_serialization_command *prev_cmd, 283 uint8_t is_cmd_for_pending_scan_queue) 284 { 285 struct wlan_serialization_pdev_priv_obj *ser_pdev_obj; 286 qdf_list_t *queue; 287 288 if (!prev_cmd) { 289 serialization_err("invalid prev_cmd"); 290 return NULL; 291 } 292 293 ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc); 294 if (!ser_pdev_obj) { 295 serialization_err("invalid ser_pdev_obj"); 296 return 0; 297 } 298 299 if (is_cmd_for_pending_scan_queue) 300 queue = &ser_pdev_obj->pending_scan_list; 301 else 302 queue = &ser_pdev_obj->pending_list; 303 if (!qdf_list_size(queue)) { 304 serialization_err("Empty Queue"); 305 return NULL; 306 } 307 308 return wlan_serialization_get_list_next_node(queue, prev_cmd); 309 } 310 311 void wlan_serialization_legacy_init_callback(void) 312 { 313 ser_legacy_cb.serialization_purge_cmd_list = 314 wlan_serialization_purge_cmd_list; 315 } 316 317 void wlan_serialization_purge_cmd_list_by_vdev_id(struct wlan_objmgr_psoc *psoc, 318 uint8_t vdev_id, bool purge_scan_active_queue, 319 bool purge_scan_pending_queue, 320 bool purge_nonscan_active_queue, 321 bool purge_nonscan_pending_queue, 322 bool purge_all_queues) 323 { 324 struct wlan_objmgr_vdev *vdev; 325 326 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 327 WLAN_SERIALIZATION_ID); 328 if (!vdev) { 329 serialization_err("Invalid vdev"); 330 return; 331 } 332 wlan_serialization_purge_cmd_list(psoc, vdev, purge_scan_active_queue, 333 purge_scan_pending_queue, 334 purge_nonscan_active_queue, 335 purge_nonscan_pending_queue, 336 purge_all_queues); 337 wlan_objmgr_vdev_release_ref(vdev, WLAN_SERIALIZATION_ID); 338 } 339 340 void wlan_serialization_purge_cmd_list(struct wlan_objmgr_psoc *psoc, 341 struct wlan_objmgr_vdev *vdev, 342 bool purge_scan_active_queue, 343 bool purge_scan_pending_queue, 344 bool purge_nonscan_active_queue, 345 bool purge_nonscan_pending_queue, 346 bool purge_all_queues) 347 { 348 struct wlan_serialization_timer *ser_timer; 349 struct wlan_serialization_psoc_priv_obj *psoc_ser_obj; 350 struct wlan_serialization_pdev_priv_obj *ser_pdev_obj; 351 struct wlan_objmgr_pdev *pdev = NULL; 352 uint32_t i = 0; 353 354 if (!psoc) { 355 serialization_err("Invalid psoc"); 356 return; 357 } 358 ser_pdev_obj = wlan_serialization_get_pdev_priv_obj_using_psoc(psoc); 359 if (!ser_pdev_obj) { 360 serialization_err("Invalid ser_pdev_obj"); 361 return; 362 } 363 psoc_ser_obj = wlan_serialization_get_psoc_priv_obj(psoc); 364 if (!psoc_ser_obj) { 365 serialization_err("Invalid psoc_ser_obj"); 366 return; 367 } 368 pdev = wlan_serialization_get_first_pdev(psoc); 369 if (!pdev) { 370 serialization_err("Invalid pdev"); 371 return; 372 } 373 for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) { 374 ser_timer = &psoc_ser_obj->timers[i]; 375 if (!ser_timer->cmd) 376 continue; 377 if (vdev && (vdev != ser_timer->cmd->vdev)) 378 continue; 379 /* 380 * if request is to purge active scan then don't de-activate 381 * non-scan cmds. If request is to purge all queues then 382 * de-activate all the timers. 383 */ 384 if (!purge_all_queues && purge_scan_active_queue && 385 (ser_timer->cmd->cmd_type >= WLAN_SER_CMD_NONSCAN)) 386 continue; 387 /* 388 * if request is to purge active nonscan then don't de-activate 389 * scan cmds. If request is to purge all queues then 390 * de-activate all the timers. 391 */ 392 if (!purge_all_queues && purge_nonscan_active_queue && 393 (ser_timer->cmd->cmd_type < WLAN_SER_CMD_NONSCAN)) 394 continue; 395 396 if (QDF_STATUS_SUCCESS != 397 wlan_serialization_find_and_stop_timer(psoc, 398 ser_timer->cmd)) 399 serialization_err("some error in stopping timer"); 400 } 401 if (purge_all_queues || purge_scan_active_queue) { 402 /* sending active queue as pending queue to leverage the API */ 403 wlan_serialization_remove_all_cmd_from_queue( 404 &ser_pdev_obj->active_scan_list, ser_pdev_obj, 405 pdev, vdev, NULL, false); 406 } 407 if (purge_all_queues || purge_scan_pending_queue) { 408 wlan_serialization_remove_all_cmd_from_queue( 409 &ser_pdev_obj->pending_scan_list, ser_pdev_obj, 410 pdev, vdev, NULL, false); 411 } 412 if (purge_all_queues || purge_nonscan_active_queue) { 413 /* sending active queue as pending queue to leverage the API */ 414 wlan_serialization_remove_all_cmd_from_queue( 415 &ser_pdev_obj->active_list, ser_pdev_obj, 416 pdev, vdev, NULL, false); 417 } 418 if (purge_all_queues || purge_nonscan_pending_queue) { 419 wlan_serialization_remove_all_cmd_from_queue( 420 &ser_pdev_obj->pending_list, ser_pdev_obj, 421 pdev, vdev, NULL, false); 422 } 423 wlan_objmgr_pdev_release_ref(pdev, WLAN_SERIALIZATION_ID); 424 425 return; 426 } 427