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_api.c 20 * This file provides an interface for the external components 21 * to utilize the services provided by the serialization 22 * component. 23 */ 24 25 /* Include files */ 26 #include "wlan_objmgr_psoc_obj.h" 27 #include "wlan_objmgr_pdev_obj.h" 28 #include "wlan_objmgr_vdev_obj.h" 29 #include "wlan_serialization_main_i.h" 30 #include "wlan_serialization_utils_i.h" 31 32 bool wlan_serialization_is_cmd_present_in_pending_queue( 33 struct wlan_objmgr_psoc *psoc, 34 struct wlan_serialization_command *cmd) 35 { 36 if (!cmd) { 37 serialization_err("invalid cmd"); 38 return false; 39 } 40 return wlan_serialization_is_cmd_present_queue(cmd, false); 41 } 42 43 bool wlan_serialization_is_cmd_present_in_active_queue( 44 struct wlan_objmgr_psoc *psoc, 45 struct wlan_serialization_command *cmd) 46 { 47 if (!cmd) { 48 serialization_err("invalid cmd"); 49 return false; 50 } 51 return wlan_serialization_is_cmd_present_queue(cmd, true); 52 } 53 54 QDF_STATUS 55 wlan_serialization_register_apply_rules_cb(struct wlan_objmgr_psoc *psoc, 56 enum wlan_serialization_cmd_type cmd_type, 57 wlan_serialization_apply_rules_cb cb) 58 { 59 struct wlan_serialization_psoc_priv_obj *ser_soc_obj; 60 QDF_STATUS status; 61 62 status = wlan_serialization_validate_cmdtype(cmd_type); 63 if (status != QDF_STATUS_SUCCESS) { 64 serialization_err("invalid cmd_type %d", 65 cmd_type); 66 return status; 67 } 68 ser_soc_obj = wlan_serialization_get_psoc_priv_obj(psoc); 69 if (!ser_soc_obj) { 70 serialization_err("invalid ser_soc_obj"); 71 return QDF_STATUS_E_FAILURE; 72 } 73 ser_soc_obj->apply_rules_cb[cmd_type] = cb; 74 75 return QDF_STATUS_SUCCESS; 76 } 77 78 QDF_STATUS 79 wlan_serialization_deregister_apply_rules_cb(struct wlan_objmgr_psoc *psoc, 80 enum wlan_serialization_cmd_type cmd_type) 81 { 82 struct wlan_serialization_psoc_priv_obj *ser_soc_obj; 83 QDF_STATUS status; 84 85 status = wlan_serialization_validate_cmdtype(cmd_type); 86 if (status != QDF_STATUS_SUCCESS) { 87 serialization_err("invalid cmd_type %d", 88 cmd_type); 89 return status; 90 } 91 ser_soc_obj = wlan_serialization_get_psoc_priv_obj(psoc); 92 if (!ser_soc_obj) { 93 serialization_err("invalid ser_soc_obj"); 94 return QDF_STATUS_E_FAILURE; 95 } 96 ser_soc_obj->apply_rules_cb[cmd_type] = NULL; 97 98 return QDF_STATUS_SUCCESS; 99 } 100 101 QDF_STATUS 102 wlan_serialization_register_comp_info_cb(struct wlan_objmgr_psoc *psoc, 103 enum wlan_umac_comp_id comp_id, 104 enum wlan_serialization_cmd_type cmd_type, 105 wlan_serialization_comp_info_cb cb) 106 { 107 struct wlan_serialization_psoc_priv_obj *ser_soc_obj; 108 QDF_STATUS status; 109 110 status = wlan_serialization_validate_cmd(comp_id, cmd_type); 111 if (status != QDF_STATUS_SUCCESS) { 112 serialization_err("invalid comp_id %d or cmd_type %d", 113 comp_id, cmd_type); 114 return status; 115 } 116 ser_soc_obj = wlan_serialization_get_psoc_priv_obj(psoc); 117 if (!ser_soc_obj) { 118 serialization_err("invalid ser_soc_obj"); 119 return QDF_STATUS_E_FAILURE; 120 } 121 ser_soc_obj->comp_info_cb[cmd_type][comp_id] = cb; 122 123 return QDF_STATUS_SUCCESS; 124 } 125 126 QDF_STATUS 127 wlan_serialization_deregister_comp_info_cb(struct wlan_objmgr_psoc *psoc, 128 enum wlan_umac_comp_id comp_id, 129 enum wlan_serialization_cmd_type cmd_type) 130 { 131 struct wlan_serialization_psoc_priv_obj *ser_soc_obj; 132 QDF_STATUS status; 133 134 status = wlan_serialization_validate_cmd(comp_id, cmd_type); 135 if (status != QDF_STATUS_SUCCESS) { 136 serialization_err("invalid comp_id %d or cmd_type %d", 137 comp_id, cmd_type); 138 return status; 139 } 140 ser_soc_obj = wlan_serialization_get_psoc_priv_obj(psoc); 141 if (!ser_soc_obj) { 142 serialization_err("invalid ser_soc_obj"); 143 return QDF_STATUS_E_FAILURE; 144 } 145 ser_soc_obj->comp_info_cb[cmd_type][comp_id] = NULL; 146 147 return QDF_STATUS_SUCCESS; 148 } 149 150 enum wlan_serialization_cmd_status 151 wlan_serialization_non_scan_cmd_status(struct wlan_objmgr_pdev *pdev, 152 enum wlan_serialization_cmd_type cmd_id) 153 { 154 serialization_enter(); 155 156 return WLAN_SER_CMD_NOT_FOUND; 157 } 158 159 enum wlan_serialization_cmd_status 160 wlan_serialization_cancel_request( 161 struct wlan_serialization_queued_cmd_info *req) 162 { 163 QDF_STATUS status; 164 165 serialization_enter(); 166 if (!req) { 167 serialization_err("given request is empty"); 168 return WLAN_SER_CMD_NOT_FOUND; 169 } 170 status = wlan_serialization_validate_cmd(req->requestor, req->cmd_type); 171 if (status != QDF_STATUS_SUCCESS) { 172 serialization_err("req is not valid"); 173 return WLAN_SER_CMD_NOT_FOUND; 174 } 175 176 return wlan_serialization_find_and_cancel_cmd(req); 177 } 178 179 void wlan_serialization_remove_cmd( 180 struct wlan_serialization_queued_cmd_info *cmd) 181 { 182 QDF_STATUS status; 183 184 serialization_enter(); 185 if (!cmd) { 186 serialization_err("given request is empty"); 187 QDF_ASSERT(0); 188 return; 189 } 190 status = wlan_serialization_validate_cmd(cmd->requestor, cmd->cmd_type); 191 if (status != QDF_STATUS_SUCCESS) { 192 serialization_err("cmd is not valid"); 193 QDF_ASSERT(0); 194 return; 195 } 196 wlan_serialization_find_and_remove_cmd(cmd); 197 198 return; 199 } 200 201 enum wlan_serialization_status 202 wlan_serialization_request(struct wlan_serialization_command *cmd) 203 { 204 bool is_active_cmd_allowed; 205 QDF_STATUS status; 206 enum wlan_serialization_status serialization_status; 207 uint8_t comp_id; 208 struct wlan_serialization_psoc_priv_obj *ser_soc_obj; 209 union wlan_serialization_rules_info info; 210 struct wlan_serialization_pdev_priv_obj *ser_pdev_obj = NULL; 211 struct wlan_objmgr_pdev *pdev = NULL; 212 struct wlan_serialization_command_list *cmd_list = NULL; 213 214 serialization_enter(); 215 if (!cmd) { 216 serialization_err("serialization cmd is null"); 217 return WLAN_SER_CMD_DENIED_UNSPECIFIED; 218 } 219 status = wlan_serialization_validate_cmd(cmd->source, cmd->cmd_type); 220 if (status != QDF_STATUS_SUCCESS) { 221 serialization_err("cmd is not valid"); 222 return WLAN_SER_CMD_DENIED_UNSPECIFIED; 223 } 224 225 ser_soc_obj = wlan_serialization_get_psoc_obj(cmd); 226 if (!ser_soc_obj) { 227 serialization_err("ser_soc_obj is invalid"); 228 return WLAN_SER_CMD_DENIED_UNSPECIFIED; 229 } 230 231 pdev = wlan_serialization_get_pdev_from_cmd(cmd); 232 if (!pdev) { 233 serialization_err("pdev is invalid"); 234 return WLAN_SER_CMD_DENIED_UNSPECIFIED; 235 } 236 237 ser_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev, 238 WLAN_UMAC_COMP_SERIALIZATION); 239 if (!ser_pdev_obj) { 240 serialization_err("Invalid ser_pdev_obj"); 241 return WLAN_SER_CMD_DENIED_UNSPECIFIED; 242 } 243 /* 244 * Get Component Info callback by calling 245 * each registered module 246 */ 247 for (comp_id = 0; comp_id < WLAN_UMAC_COMP_ID_MAX; comp_id++) { 248 if (!ser_soc_obj->comp_info_cb[cmd->cmd_type][comp_id]) 249 continue; 250 (ser_soc_obj->comp_info_cb[cmd->cmd_type][comp_id])(cmd->vdev, 251 &info); 252 if (!ser_soc_obj->apply_rules_cb[cmd->cmd_type]) 253 continue; 254 if (!ser_soc_obj->apply_rules_cb[cmd->cmd_type](&info, comp_id)) 255 return WLAN_SER_CMD_DENIED_RULES_FAILED; 256 } 257 258 is_active_cmd_allowed = wlan_serialization_is_active_cmd_allowed(cmd); 259 serialization_status = wlan_serialization_enqueue_cmd( 260 cmd, is_active_cmd_allowed, &cmd_list); 261 if (WLAN_SER_CMD_ACTIVE == serialization_status) 262 wlan_serialization_activate_cmd(cmd_list, ser_pdev_obj); 263 264 return serialization_status; 265 } 266 267 enum wlan_serialization_cmd_status 268 wlan_serialization_vdev_scan_status(struct wlan_objmgr_vdev *vdev) 269 { 270 bool cmd_in_active, cmd_in_pending; 271 struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); 272 struct wlan_serialization_pdev_priv_obj *ser_pdev_obj = 273 wlan_serialization_get_pdev_priv_obj(pdev); 274 275 cmd_in_active = 276 wlan_serialization_is_cmd_in_vdev_list( 277 vdev, &ser_pdev_obj->active_scan_list); 278 279 cmd_in_pending = 280 wlan_serialization_is_cmd_in_vdev_list( 281 vdev, &ser_pdev_obj->pending_scan_list); 282 283 return wlan_serialization_is_cmd_in_active_pending( 284 cmd_in_active, cmd_in_pending); 285 } 286 287 void wlan_serialization_flush_cmd( 288 struct wlan_serialization_queued_cmd_info *cmd) 289 { 290 serialization_enter(); 291 if (!cmd) { 292 serialization_err("cmd is null, can't flush"); 293 return; 294 } 295 /* TODO: discuss and fill this API later */ 296 297 return; 298 } 299 300 enum wlan_serialization_cmd_status 301 wlan_serialization_pdev_scan_status(struct wlan_objmgr_pdev *pdev) 302 { 303 bool cmd_in_active, cmd_in_pending; 304 struct wlan_serialization_pdev_priv_obj *ser_pdev_obj = 305 wlan_serialization_get_pdev_priv_obj(pdev); 306 307 cmd_in_active = !qdf_list_empty(&ser_pdev_obj->active_scan_list); 308 cmd_in_pending = !qdf_list_empty(&ser_pdev_obj->pending_scan_list); 309 310 return wlan_serialization_is_cmd_in_active_pending( 311 cmd_in_active, cmd_in_pending); 312 } 313 314 struct wlan_serialization_command* 315 wlan_serialization_get_scan_cmd_using_scan_id( 316 struct wlan_objmgr_psoc *psoc, 317 uint8_t vdev_id, uint16_t scan_id, 318 uint8_t is_scan_cmd_from_active_queue) 319 { 320 uint32_t qlen; 321 struct wlan_objmgr_vdev *vdev; 322 struct wlan_objmgr_pdev *pdev; 323 struct wlan_serialization_pdev_priv_obj *ser_pdev_obj; 324 struct wlan_serialization_command *cmd = NULL; 325 qdf_list_node_t *nnode = NULL; 326 qdf_list_t *queue; 327 328 if (!psoc) { 329 serialization_err("invalid psoc"); 330 return cmd; 331 } 332 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 333 WLAN_SERIALIZATION_ID); 334 if (!vdev) { 335 serialization_err("invalid vdev"); 336 return cmd; 337 } 338 339 pdev = wlan_vdev_get_pdev(vdev); 340 if (!pdev) { 341 serialization_err("invalid pdev"); 342 goto release_vdev_ref; 343 } 344 345 ser_pdev_obj = wlan_serialization_get_pdev_priv_obj(pdev); 346 if (!ser_pdev_obj) { 347 serialization_err("invalid ser_pdev_obj"); 348 goto release_vdev_ref; 349 } 350 if (is_scan_cmd_from_active_queue) 351 queue = &ser_pdev_obj->active_scan_list; 352 else 353 queue = &ser_pdev_obj->pending_scan_list; 354 qlen = wlan_serialization_list_size(queue, ser_pdev_obj); 355 while (qlen--) { 356 if (QDF_STATUS_SUCCESS != wlan_serialization_get_cmd_from_queue( 357 queue, &nnode, ser_pdev_obj)) { 358 serialization_debug("Node not found"); 359 break; 360 } 361 if (wlan_serialization_match_cmd_scan_id(nnode, &cmd, scan_id, 362 vdev, ser_pdev_obj)) { 363 serialization_debug("Cmd matched with the scan_id"); 364 break; 365 } 366 } 367 release_vdev_ref: 368 wlan_objmgr_vdev_release_ref(vdev, WLAN_SERIALIZATION_ID); 369 370 return cmd; 371 } 372 373 void *wlan_serialization_get_active_cmd(struct wlan_objmgr_psoc *psoc, 374 uint8_t vdev_id, 375 enum wlan_serialization_cmd_type cmd_type) 376 { 377 uint32_t qlen; 378 struct wlan_objmgr_vdev *vdev; 379 struct wlan_objmgr_pdev *pdev; 380 struct wlan_serialization_pdev_priv_obj *ser_pdev_obj; 381 struct wlan_serialization_command_list *cmd_list = NULL; 382 void *umac_cmd = NULL; 383 qdf_list_node_t *nnode = NULL; 384 qdf_list_t *queue; 385 386 if (!psoc) { 387 serialization_err("invalid psoc"); 388 return umac_cmd; 389 } 390 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 391 WLAN_SERIALIZATION_ID); 392 if (!vdev) { 393 serialization_err("invalid vdev"); 394 return umac_cmd; 395 } 396 397 pdev = wlan_vdev_get_pdev(vdev); 398 if (!pdev) { 399 serialization_err("invalid pdev"); 400 goto release_vdev_ref; 401 } 402 403 ser_pdev_obj = wlan_serialization_get_pdev_priv_obj(pdev); 404 if (!ser_pdev_obj) { 405 serialization_err("invalid ser_pdev_obj"); 406 goto release_vdev_ref; 407 } 408 409 queue = &ser_pdev_obj->active_list; 410 411 qlen = qdf_list_size(queue); 412 if (!qlen) { 413 serialization_err("Empty Queue"); 414 goto release_vdev_ref; 415 } 416 while (qlen--) { 417 if (QDF_STATUS_SUCCESS != wlan_serialization_get_cmd_from_queue( 418 queue, &nnode, 419 ser_pdev_obj)) { 420 serialization_err("unsuccessful attempt"); 421 break; 422 } 423 cmd_list = qdf_container_of(nnode, 424 struct wlan_serialization_command_list, 425 node); 426 if (cmd_list->cmd.cmd_type == cmd_type && 427 cmd_list->cmd.vdev == vdev) { 428 serialization_debug("cmd_type[%d] matched", cmd_type); 429 umac_cmd = cmd_list->cmd.umac_cmd; 430 break; 431 } 432 } 433 release_vdev_ref: 434 wlan_objmgr_vdev_release_ref(vdev, WLAN_SERIALIZATION_ID); 435 436 return umac_cmd; 437 } 438