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: This file contains green ap north bound interface definitions 22 */ 23 #include <wlan_green_ap_api.h> 24 #include <../../core/src/wlan_green_ap_main_i.h> 25 #include <wlan_objmgr_global_obj.h> 26 #include "cfg_green_ap_params.h" 27 #include "cfg_ucfg_api.h" 28 29 QDF_STATUS wlan_green_ap_get_capab( 30 struct wlan_objmgr_pdev *pdev) 31 { 32 struct wlan_lmac_if_green_ap_tx_ops *green_ap_tx_ops; 33 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 34 35 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(pdev, 36 WLAN_UMAC_COMP_GREEN_AP); 37 38 if (!green_ap_ctx) { 39 green_ap_err("green ap context obtained is NULL"); 40 return QDF_STATUS_E_FAILURE; 41 } 42 43 44 green_ap_tx_ops = wlan_psoc_get_green_ap_tx_ops(green_ap_ctx); 45 if (!green_ap_tx_ops) { 46 green_ap_err("green ap tx ops obtained are NULL"); 47 return QDF_STATUS_E_EXISTS; 48 } 49 50 if (green_ap_tx_ops->get_capab) 51 return green_ap_tx_ops->get_capab(pdev); 52 53 return QDF_STATUS_SUCCESS; 54 } 55 56 /** 57 * wlan_green_ap_pdev_obj_create_notification() - called from objmgr when pdev 58 * is created 59 * @pdev: pdev context 60 * @arg: argument 61 * 62 * This function gets called from object manager when pdev is being created and 63 * creates green ap context and attach it to objmgr. 64 * 65 * Return: QDF_STATUS_SUCCESS - in case of success 66 */ 67 static QDF_STATUS wlan_green_ap_pdev_obj_create_notification( 68 struct wlan_objmgr_pdev *pdev, void *arg) 69 { 70 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 71 QDF_STATUS status = QDF_STATUS_SUCCESS; 72 73 if (!pdev) { 74 green_ap_err("pdev context passed is NULL"); 75 return QDF_STATUS_E_INVAL; 76 } 77 78 green_ap_ctx = qdf_mem_malloc(sizeof(*green_ap_ctx)); 79 if (!green_ap_ctx) 80 return QDF_STATUS_E_NOMEM; 81 82 green_ap_ctx->ps_state = WLAN_GREEN_AP_PS_IDLE_STATE; 83 green_ap_ctx->ps_event = WLAN_GREEN_AP_PS_WAIT_EVENT; 84 green_ap_ctx->ps_mode = WLAN_GREEN_AP_MODE_NO_STA; 85 green_ap_ctx->num_nodes = 0; 86 green_ap_ctx->num_nodes_multistream = 0; 87 green_ap_ctx->ps_on_time = WLAN_GREEN_AP_PS_ON_TIME; 88 green_ap_ctx->ps_trans_time = WLAN_GREEN_AP_PS_TRANS_TIME; 89 90 green_ap_ctx->pdev = pdev; 91 92 qdf_timer_init(NULL, &green_ap_ctx->ps_timer, 93 wlan_green_ap_timer_fn, 94 pdev, QDF_TIMER_TYPE_WAKE_APPS); 95 96 qdf_spinlock_create(&green_ap_ctx->lock); 97 if (wlan_objmgr_pdev_component_obj_attach(pdev, 98 WLAN_UMAC_COMP_GREEN_AP, 99 green_ap_ctx, QDF_STATUS_SUCCESS) 100 != QDF_STATUS_SUCCESS) { 101 green_ap_err("Failed to attach green ap ctx in pdev ctx"); 102 status = QDF_STATUS_E_FAILURE; 103 goto err_pdev_attach; 104 } 105 106 green_ap_info("Green AP creation successful, green ap ctx: %pK, pdev: %pK", 107 green_ap_ctx, pdev); 108 109 return QDF_STATUS_SUCCESS; 110 111 err_pdev_attach: 112 qdf_spinlock_destroy(&green_ap_ctx->lock); 113 qdf_timer_free(&green_ap_ctx->ps_timer); 114 qdf_mem_free(green_ap_ctx); 115 return status; 116 } 117 118 /** 119 * wlan_green_ap_pdev_obj_destroy_notification() - called from objmgr when 120 * pdev is destroyed 121 * @pdev: pdev context 122 * @arg: argument 123 * 124 * This function gets called from object manager when pdev is being destroyed 125 * and deletes green ap context and detach it from objmgr. 126 * 127 * Return: QDF_STATUS_SUCCESS - in case of success 128 */ 129 static QDF_STATUS wlan_green_ap_pdev_obj_destroy_notification( 130 struct wlan_objmgr_pdev *pdev, void *arg) 131 { 132 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 133 134 if (!pdev) { 135 green_ap_err("pdev context passed is NULL"); 136 return QDF_STATUS_E_INVAL; 137 } 138 139 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 140 pdev, WLAN_UMAC_COMP_GREEN_AP); 141 if (!green_ap_ctx) { 142 green_ap_err("green ap context is already NULL"); 143 return QDF_STATUS_E_FAILURE; 144 } 145 146 green_ap_info("Deleting green ap pdev obj, green ap ctx: %pK, pdev: %pK", 147 green_ap_ctx, pdev); 148 149 if (wlan_objmgr_pdev_component_obj_detach(pdev, 150 WLAN_UMAC_COMP_GREEN_AP, green_ap_ctx) != 151 QDF_STATUS_SUCCESS) { 152 green_ap_err("Failed to detach green ap ctx in psoc ctx"); 153 return QDF_STATUS_E_FAILURE; 154 } 155 156 qdf_timer_free(&green_ap_ctx->ps_timer); 157 qdf_spinlock_destroy(&green_ap_ctx->lock); 158 159 qdf_mem_free(green_ap_ctx); 160 green_ap_info("green ap deletion successful"); 161 162 return QDF_STATUS_SUCCESS; 163 } 164 165 QDF_STATUS wlan_green_ap_init(void) 166 { 167 QDF_STATUS status = QDF_STATUS_SUCCESS; 168 169 status = wlan_objmgr_register_pdev_create_handler( 170 WLAN_UMAC_COMP_GREEN_AP, 171 wlan_green_ap_pdev_obj_create_notification, 172 NULL); 173 if (status != QDF_STATUS_SUCCESS) { 174 green_ap_err("Failed to register green ap obj create handler"); 175 goto err_pdev_create; 176 } 177 178 status = wlan_objmgr_register_pdev_destroy_handler( 179 WLAN_UMAC_COMP_GREEN_AP, 180 wlan_green_ap_pdev_obj_destroy_notification, 181 NULL); 182 if (status != QDF_STATUS_SUCCESS) { 183 green_ap_err("Failed to register green ap obj destroy handler"); 184 goto err_pdev_delete; 185 } 186 187 green_ap_info("Successfully registered create and destroy handlers with objmgr"); 188 return QDF_STATUS_SUCCESS; 189 190 err_pdev_delete: 191 wlan_objmgr_unregister_pdev_create_handler( 192 WLAN_UMAC_COMP_GREEN_AP, 193 wlan_green_ap_pdev_obj_create_notification, 194 NULL); 195 err_pdev_create: 196 return status; 197 } 198 199 QDF_STATUS wlan_green_ap_deinit(void) 200 { 201 if (wlan_objmgr_unregister_pdev_create_handler( 202 WLAN_UMAC_COMP_GREEN_AP, 203 wlan_green_ap_pdev_obj_create_notification, 204 NULL) 205 != QDF_STATUS_SUCCESS) { 206 return QDF_STATUS_E_FAILURE; 207 } 208 209 if (wlan_objmgr_unregister_pdev_destroy_handler( 210 WLAN_UMAC_COMP_GREEN_AP, 211 wlan_green_ap_pdev_obj_destroy_notification, 212 NULL) 213 != QDF_STATUS_SUCCESS) { 214 return QDF_STATUS_E_FAILURE; 215 } 216 217 green_ap_info("Successfully unregistered create and destroy handlers with objmgr"); 218 return QDF_STATUS_SUCCESS; 219 } 220 221 QDF_STATUS wlan_green_ap_pdev_open(struct wlan_objmgr_pdev *pdev) 222 { 223 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 224 struct wlan_objmgr_psoc *psoc; 225 226 if (!pdev) { 227 green_ap_err("pdev is NULL"); 228 return QDF_STATUS_E_INVAL; 229 } 230 231 psoc = wlan_pdev_get_psoc(pdev); 232 233 if (!psoc) { 234 green_ap_err("psoc is NULL"); 235 return QDF_STATUS_E_INVAL; 236 } 237 238 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 239 pdev, WLAN_UMAC_COMP_GREEN_AP); 240 if (!green_ap_ctx) { 241 green_ap_err("green ap context obtained is NULL"); 242 return QDF_STATUS_E_FAILURE; 243 } 244 245 qdf_spin_lock_bh(&green_ap_ctx->lock); 246 green_ap_ctx->ps_enable = cfg_get(psoc, 247 CFG_ENABLE_GREEN_AP_FEATURE); 248 green_ap_ctx->egap_params.host_enable_egap = cfg_get(psoc, 249 CFG_ENABLE_EGAP_FEATURE); 250 green_ap_ctx->egap_params.egap_inactivity_time = cfg_get(psoc, 251 CFG_EGAP_INACT_TIME_FEATURE); 252 green_ap_ctx->egap_params.egap_wait_time = cfg_get(psoc, 253 CFG_EGAP_WAIT_TIME_FEATURE); 254 green_ap_ctx->egap_params.egap_feature_flags = cfg_get(psoc, 255 CFG_EGAP_FLAGS_FEATURE); 256 257 qdf_spin_unlock_bh(&green_ap_ctx->lock); 258 259 return QDF_STATUS_SUCCESS; 260 } 261 262 QDF_STATUS wlan_green_ap_start(struct wlan_objmgr_pdev *pdev) 263 { 264 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 265 266 if (!pdev) { 267 green_ap_err("pdev context passed is NULL"); 268 return QDF_STATUS_E_INVAL; 269 } 270 271 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 272 pdev, WLAN_UMAC_COMP_GREEN_AP); 273 if (!green_ap_ctx) { 274 green_ap_err("green ap context obtained is NULL"); 275 return QDF_STATUS_E_FAILURE; 276 } 277 278 green_ap_debug("Green AP start received"); 279 280 /* Make sure the start function does not get called 2 times */ 281 qdf_spin_lock_bh(&green_ap_ctx->lock); 282 283 if (wlan_is_egap_enabled(green_ap_ctx)) { 284 qdf_spin_unlock_bh(&green_ap_ctx->lock); 285 green_ap_debug("enhanced green ap support is enabled"); 286 return QDF_STATUS_SUCCESS; 287 } 288 289 if (green_ap_ctx->ps_state == WLAN_GREEN_AP_PS_IDLE_STATE) { 290 if (green_ap_ctx->ps_enable) { 291 qdf_spin_unlock_bh(&green_ap_ctx->lock); 292 return wlan_green_ap_state_mc(green_ap_ctx, 293 WLAN_GREEN_AP_PS_START_EVENT); 294 } 295 } 296 297 qdf_spin_unlock_bh(&green_ap_ctx->lock); 298 return QDF_STATUS_E_ALREADY; 299 } 300 301 QDF_STATUS wlan_green_ap_stop(struct wlan_objmgr_pdev *pdev) 302 { 303 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 304 305 if (!pdev) { 306 green_ap_err("pdev context passed is NULL"); 307 return QDF_STATUS_E_INVAL; 308 } 309 310 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 311 pdev, WLAN_UMAC_COMP_GREEN_AP); 312 if (!green_ap_ctx) { 313 green_ap_err("green ap context obtained is NULL"); 314 return QDF_STATUS_E_FAILURE; 315 } 316 317 green_ap_debug("Green AP stop received"); 318 319 qdf_spin_lock_bh(&green_ap_ctx->lock); 320 if (wlan_is_egap_enabled(green_ap_ctx)) { 321 qdf_spin_unlock_bh(&green_ap_ctx->lock); 322 green_ap_debug("enhanced green ap support is enabled"); 323 return QDF_STATUS_SUCCESS; 324 } 325 326 /* Delete the timer just to be sure */ 327 qdf_timer_stop(&green_ap_ctx->ps_timer); 328 329 /* Disable the power save */ 330 green_ap_ctx->ps_enable = WLAN_GREEN_AP_PS_DISABLE; 331 332 qdf_spin_unlock_bh(&green_ap_ctx->lock); 333 return wlan_green_ap_state_mc(green_ap_ctx, 334 WLAN_GREEN_AP_PS_STOP_EVENT); 335 } 336 337 QDF_STATUS wlan_green_ap_add_sta(struct wlan_objmgr_pdev *pdev) 338 { 339 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 340 341 if (!pdev) { 342 green_ap_err("pdev context passed is NULL"); 343 return QDF_STATUS_E_INVAL; 344 } 345 346 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 347 pdev, WLAN_UMAC_COMP_GREEN_AP); 348 if (!green_ap_ctx) { 349 green_ap_err("green ap context obtained is NULL"); 350 return QDF_STATUS_E_FAILURE; 351 } 352 353 green_ap_debug("Green AP add sta received"); 354 355 qdf_spin_lock_bh(&green_ap_ctx->lock); 356 if (wlan_is_egap_enabled(green_ap_ctx)) { 357 qdf_spin_unlock_bh(&green_ap_ctx->lock); 358 green_ap_debug("enhanced green ap support is enabled"); 359 return QDF_STATUS_SUCCESS; 360 } 361 qdf_spin_unlock_bh(&green_ap_ctx->lock); 362 363 return wlan_green_ap_state_mc(green_ap_ctx, 364 WLAN_GREEN_AP_ADD_STA_EVENT); 365 } 366 367 QDF_STATUS wlan_green_ap_add_multistream_sta(struct wlan_objmgr_pdev *pdev) 368 { 369 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 370 371 if (!pdev) { 372 green_ap_err("pdev context passed is NULL"); 373 return QDF_STATUS_E_INVAL; 374 } 375 376 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 377 pdev, WLAN_UMAC_COMP_GREEN_AP); 378 if (!green_ap_ctx) { 379 green_ap_err("green ap context obtained is NULL"); 380 return QDF_STATUS_E_FAILURE; 381 } 382 383 green_ap_debug("Green AP add multistream sta received"); 384 385 qdf_spin_lock_bh(&green_ap_ctx->lock); 386 if (wlan_is_egap_enabled(green_ap_ctx)) { 387 qdf_spin_unlock_bh(&green_ap_ctx->lock); 388 green_ap_debug("enhanced green ap support is enabled"); 389 return QDF_STATUS_SUCCESS; 390 } 391 qdf_spin_unlock_bh(&green_ap_ctx->lock); 392 393 return wlan_green_ap_state_mc(green_ap_ctx, 394 WLAN_GREEN_AP_ADD_MULTISTREAM_STA_EVENT); 395 } 396 397 QDF_STATUS wlan_green_ap_del_sta(struct wlan_objmgr_pdev *pdev) 398 { 399 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 400 401 if (!pdev) { 402 green_ap_err("pdev context passed is NULL"); 403 return QDF_STATUS_E_INVAL; 404 } 405 406 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 407 pdev, WLAN_UMAC_COMP_GREEN_AP); 408 if (!green_ap_ctx) { 409 green_ap_err("green ap context obtained is NULL"); 410 return QDF_STATUS_E_FAILURE; 411 } 412 413 green_ap_debug("Green AP del sta received"); 414 415 qdf_spin_lock_bh(&green_ap_ctx->lock); 416 if (wlan_is_egap_enabled(green_ap_ctx)) { 417 qdf_spin_unlock_bh(&green_ap_ctx->lock); 418 green_ap_debug("enhanced green ap support is enabled"); 419 return QDF_STATUS_SUCCESS; 420 } 421 qdf_spin_unlock_bh(&green_ap_ctx->lock); 422 423 return wlan_green_ap_state_mc(green_ap_ctx, 424 WLAN_GREEN_AP_DEL_STA_EVENT); 425 } 426 427 QDF_STATUS wlan_green_ap_del_multistream_sta(struct wlan_objmgr_pdev *pdev) 428 { 429 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 430 431 if (!pdev) { 432 green_ap_err("pdev context passed is NULL"); 433 return QDF_STATUS_E_INVAL; 434 } 435 436 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 437 pdev, WLAN_UMAC_COMP_GREEN_AP); 438 if (!green_ap_ctx) { 439 green_ap_err("green ap context obtained is NULL"); 440 return QDF_STATUS_E_FAILURE; 441 } 442 443 green_ap_debug("Green AP del multistream sta received"); 444 445 qdf_spin_lock_bh(&green_ap_ctx->lock); 446 if (wlan_is_egap_enabled(green_ap_ctx)) { 447 qdf_spin_unlock_bh(&green_ap_ctx->lock); 448 green_ap_info("enhanced green ap support is enabled"); 449 return QDF_STATUS_SUCCESS; 450 } 451 qdf_spin_unlock_bh(&green_ap_ctx->lock); 452 453 return wlan_green_ap_state_mc(green_ap_ctx, 454 WLAN_GREEN_AP_DEL_MULTISTREAM_STA_EVENT); 455 } 456 457 bool wlan_green_ap_is_ps_enabled(struct wlan_objmgr_pdev *pdev) 458 { 459 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 460 461 if (!pdev) { 462 green_ap_err("pdev context passed is NULL"); 463 return QDF_STATUS_E_INVAL; 464 } 465 466 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 467 pdev, WLAN_UMAC_COMP_GREEN_AP); 468 if (!green_ap_ctx) { 469 green_ap_err("green ap context obtained is NULL"); 470 return QDF_STATUS_E_FAILURE; 471 } 472 473 if ((green_ap_ctx->ps_state == WLAN_GREEN_AP_PS_ON_STATE) && 474 (green_ap_ctx->ps_enable)) 475 return true; 476 477 return false; 478 479 } 480 481 void wlan_green_ap_suspend_handle(struct wlan_objmgr_pdev *pdev) 482 { 483 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 484 485 if (!pdev) { 486 green_ap_err("pdev context passed is NULL"); 487 return; 488 } 489 490 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 491 pdev, WLAN_UMAC_COMP_GREEN_AP); 492 493 if (!green_ap_ctx) { 494 green_ap_err("green ap context obtained is NULL"); 495 return; 496 } 497 498 wlan_green_ap_stop(pdev); 499 500 green_ap_ctx->ps_enable = WLAN_GREEN_AP_PS_SUSPEND; 501 } 502 503 bool wlan_green_ap_is_ps_waiting(struct wlan_objmgr_pdev *pdev) 504 { 505 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 506 507 if (!pdev) { 508 green_ap_err("pdev context passed is NULL"); 509 return QDF_STATUS_E_INVAL; 510 } 511 512 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 513 pdev, WLAN_UMAC_COMP_GREEN_AP); 514 if (!green_ap_ctx) { 515 green_ap_err("green ap context obtained is NULL"); 516 return QDF_STATUS_E_FAILURE; 517 } 518 519 if ((green_ap_ctx->ps_state == WLAN_GREEN_AP_PS_WAIT_STATE) && 520 (green_ap_ctx->ps_enable)) { 521 return true; 522 } 523 524 return false; 525 } 526