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 #ifdef WLAN_SUPPORT_GAP_LL_PS_MODE 222 /** 223 * wlan_green_ap_set_bcn_mult() - API to set Green AP beacon 224 * multiplier 225 * @pdev: Pdev pointer 226 * 227 */ 228 static void wlan_green_ap_set_bcn_mult(struct wlan_objmgr_pdev *pdev) 229 { 230 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 231 struct wlan_objmgr_psoc *psoc; 232 233 psoc = wlan_pdev_get_psoc(pdev); 234 235 if (!psoc) { 236 green_ap_err("psoc is NULL"); 237 return; 238 } 239 240 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 241 pdev, WLAN_UMAC_COMP_GREEN_AP); 242 if (!green_ap_ctx) { 243 green_ap_err("green ap context obtained is NULL"); 244 return; 245 } 246 247 green_ap_ctx->bcn_mult = cfg_get(psoc, 248 CFG_GAP_LL_PS_LOW_BEACON_MULT); 249 } 250 251 /** 252 * wlan_green_ap_init_cmd_count() - Initialize command count. 253 * @green_ap_ctx: green ap ctx 254 */ 255 static void wlan_green_ap_init_cmd_count(struct wlan_pdev_green_ap_ctx *green_ap_ctx) 256 { 257 /* Disable cookie id will from 0,2,6,..*/ 258 qdf_atomic_init(&green_ap_ctx->ps_dis_cmd_cnt); 259 /* Enable cookie id will be from 1,3,5,..*/ 260 qdf_atomic_set(&green_ap_ctx->ps_en_cmd_cnt, 1); 261 } 262 #else 263 static inline void wlan_green_ap_set_bcn_mult(struct wlan_objmgr_pdev *pdev) 264 { 265 } 266 267 static inline 268 void wlan_green_ap_init_cmd_count(struct wlan_pdev_green_ap_ctx *green_ap_ctx) 269 { 270 } 271 #endif 272 273 QDF_STATUS wlan_green_ap_pdev_open(struct wlan_objmgr_pdev *pdev) 274 { 275 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 276 struct wlan_objmgr_psoc *psoc; 277 278 if (!pdev) { 279 green_ap_err("pdev is NULL"); 280 return QDF_STATUS_E_INVAL; 281 } 282 283 psoc = wlan_pdev_get_psoc(pdev); 284 285 if (!psoc) { 286 green_ap_err("psoc is NULL"); 287 return QDF_STATUS_E_INVAL; 288 } 289 290 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 291 pdev, WLAN_UMAC_COMP_GREEN_AP); 292 if (!green_ap_ctx) { 293 green_ap_err("green ap context obtained is NULL"); 294 return QDF_STATUS_E_FAILURE; 295 } 296 297 qdf_spin_lock_bh(&green_ap_ctx->lock); 298 green_ap_ctx->ps_enable = cfg_get(psoc, 299 CFG_ENABLE_GREEN_AP_FEATURE); 300 green_ap_ctx->egap_params.host_enable_egap = cfg_get(psoc, 301 CFG_ENABLE_EGAP_FEATURE); 302 green_ap_ctx->egap_params.egap_inactivity_time = cfg_get(psoc, 303 CFG_EGAP_INACT_TIME_FEATURE); 304 green_ap_ctx->egap_params.egap_wait_time = cfg_get(psoc, 305 CFG_EGAP_WAIT_TIME_FEATURE); 306 green_ap_ctx->egap_params.egap_feature_flags = cfg_get(psoc, 307 CFG_EGAP_FLAGS_FEATURE); 308 309 wlan_green_ap_set_bcn_mult(pdev); 310 311 wlan_green_ap_init_cmd_count(green_ap_ctx); 312 313 qdf_spin_unlock_bh(&green_ap_ctx->lock); 314 315 return QDF_STATUS_SUCCESS; 316 } 317 318 QDF_STATUS wlan_green_ap_start(struct wlan_objmgr_pdev *pdev) 319 { 320 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 321 322 if (!pdev) { 323 green_ap_err("pdev context passed is NULL"); 324 return QDF_STATUS_E_INVAL; 325 } 326 327 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 328 pdev, WLAN_UMAC_COMP_GREEN_AP); 329 if (!green_ap_ctx) { 330 green_ap_err("green ap context obtained is NULL"); 331 return QDF_STATUS_E_FAILURE; 332 } 333 334 green_ap_debug("Green AP start received"); 335 336 /* Make sure the start function does not get called 2 times */ 337 qdf_spin_lock_bh(&green_ap_ctx->lock); 338 339 if (wlan_is_egap_enabled(green_ap_ctx)) { 340 qdf_spin_unlock_bh(&green_ap_ctx->lock); 341 green_ap_debug("enhanced green ap support is enabled"); 342 return QDF_STATUS_SUCCESS; 343 } 344 345 if (green_ap_ctx->ps_state == WLAN_GREEN_AP_PS_IDLE_STATE) { 346 if (green_ap_ctx->ps_enable) { 347 qdf_spin_unlock_bh(&green_ap_ctx->lock); 348 return wlan_green_ap_state_mc(green_ap_ctx, 349 WLAN_GREEN_AP_PS_START_EVENT); 350 } 351 } 352 353 qdf_spin_unlock_bh(&green_ap_ctx->lock); 354 return QDF_STATUS_E_ALREADY; 355 } 356 357 QDF_STATUS wlan_green_ap_stop(struct wlan_objmgr_pdev *pdev) 358 { 359 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 360 361 if (!pdev) { 362 green_ap_err("pdev context passed is NULL"); 363 return QDF_STATUS_E_INVAL; 364 } 365 366 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 367 pdev, WLAN_UMAC_COMP_GREEN_AP); 368 if (!green_ap_ctx) { 369 green_ap_err("green ap context obtained is NULL"); 370 return QDF_STATUS_E_FAILURE; 371 } 372 373 green_ap_debug("Green AP stop received"); 374 375 qdf_spin_lock_bh(&green_ap_ctx->lock); 376 if (wlan_is_egap_enabled(green_ap_ctx)) { 377 qdf_spin_unlock_bh(&green_ap_ctx->lock); 378 green_ap_debug("enhanced green ap support is enabled"); 379 return QDF_STATUS_SUCCESS; 380 } 381 382 /* Delete the timer just to be sure */ 383 qdf_timer_stop(&green_ap_ctx->ps_timer); 384 385 /* Disable the power save */ 386 green_ap_ctx->ps_enable = WLAN_GREEN_AP_PS_DISABLE; 387 388 qdf_spin_unlock_bh(&green_ap_ctx->lock); 389 return wlan_green_ap_state_mc(green_ap_ctx, 390 WLAN_GREEN_AP_PS_STOP_EVENT); 391 } 392 393 QDF_STATUS wlan_green_ap_add_sta(struct wlan_objmgr_pdev *pdev) 394 { 395 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 396 397 if (!pdev) { 398 green_ap_err("pdev context passed is NULL"); 399 return QDF_STATUS_E_INVAL; 400 } 401 402 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 403 pdev, WLAN_UMAC_COMP_GREEN_AP); 404 if (!green_ap_ctx) { 405 green_ap_err("green ap context obtained is NULL"); 406 return QDF_STATUS_E_FAILURE; 407 } 408 409 green_ap_debug("Green AP add sta received"); 410 411 qdf_spin_lock_bh(&green_ap_ctx->lock); 412 if (wlan_is_egap_enabled(green_ap_ctx)) { 413 qdf_spin_unlock_bh(&green_ap_ctx->lock); 414 green_ap_debug("enhanced green ap support is enabled"); 415 return QDF_STATUS_SUCCESS; 416 } 417 qdf_spin_unlock_bh(&green_ap_ctx->lock); 418 419 return wlan_green_ap_state_mc(green_ap_ctx, 420 WLAN_GREEN_AP_ADD_STA_EVENT); 421 } 422 423 QDF_STATUS wlan_green_ap_add_multistream_sta(struct wlan_objmgr_pdev *pdev) 424 { 425 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 426 427 if (!pdev) { 428 green_ap_err("pdev context passed is NULL"); 429 return QDF_STATUS_E_INVAL; 430 } 431 432 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 433 pdev, WLAN_UMAC_COMP_GREEN_AP); 434 if (!green_ap_ctx) { 435 green_ap_err("green ap context obtained is NULL"); 436 return QDF_STATUS_E_FAILURE; 437 } 438 439 green_ap_debug("Green AP add multistream sta received"); 440 441 qdf_spin_lock_bh(&green_ap_ctx->lock); 442 if (wlan_is_egap_enabled(green_ap_ctx)) { 443 qdf_spin_unlock_bh(&green_ap_ctx->lock); 444 green_ap_debug("enhanced green ap support is enabled"); 445 return QDF_STATUS_SUCCESS; 446 } 447 qdf_spin_unlock_bh(&green_ap_ctx->lock); 448 449 return wlan_green_ap_state_mc(green_ap_ctx, 450 WLAN_GREEN_AP_ADD_MULTISTREAM_STA_EVENT); 451 } 452 453 QDF_STATUS wlan_green_ap_del_sta(struct wlan_objmgr_pdev *pdev) 454 { 455 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 456 457 if (!pdev) { 458 green_ap_err("pdev context passed is NULL"); 459 return QDF_STATUS_E_INVAL; 460 } 461 462 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 463 pdev, WLAN_UMAC_COMP_GREEN_AP); 464 if (!green_ap_ctx) { 465 green_ap_err("green ap context obtained is NULL"); 466 return QDF_STATUS_E_FAILURE; 467 } 468 469 green_ap_debug("Green AP del sta received"); 470 471 qdf_spin_lock_bh(&green_ap_ctx->lock); 472 if (wlan_is_egap_enabled(green_ap_ctx)) { 473 qdf_spin_unlock_bh(&green_ap_ctx->lock); 474 green_ap_debug("enhanced green ap support is enabled"); 475 return QDF_STATUS_SUCCESS; 476 } 477 qdf_spin_unlock_bh(&green_ap_ctx->lock); 478 479 return wlan_green_ap_state_mc(green_ap_ctx, 480 WLAN_GREEN_AP_DEL_STA_EVENT); 481 } 482 483 QDF_STATUS wlan_green_ap_del_multistream_sta(struct wlan_objmgr_pdev *pdev) 484 { 485 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 486 487 if (!pdev) { 488 green_ap_err("pdev context passed is NULL"); 489 return QDF_STATUS_E_INVAL; 490 } 491 492 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 493 pdev, WLAN_UMAC_COMP_GREEN_AP); 494 if (!green_ap_ctx) { 495 green_ap_err("green ap context obtained is NULL"); 496 return QDF_STATUS_E_FAILURE; 497 } 498 499 green_ap_debug("Green AP del multistream sta received"); 500 501 qdf_spin_lock_bh(&green_ap_ctx->lock); 502 if (wlan_is_egap_enabled(green_ap_ctx)) { 503 qdf_spin_unlock_bh(&green_ap_ctx->lock); 504 green_ap_info("enhanced green ap support is enabled"); 505 return QDF_STATUS_SUCCESS; 506 } 507 qdf_spin_unlock_bh(&green_ap_ctx->lock); 508 509 return wlan_green_ap_state_mc(green_ap_ctx, 510 WLAN_GREEN_AP_DEL_MULTISTREAM_STA_EVENT); 511 } 512 513 bool wlan_green_ap_is_ps_enabled(struct wlan_objmgr_pdev *pdev) 514 { 515 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 516 517 if (!pdev) { 518 green_ap_err("pdev context passed is NULL"); 519 return QDF_STATUS_E_INVAL; 520 } 521 522 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 523 pdev, WLAN_UMAC_COMP_GREEN_AP); 524 if (!green_ap_ctx) { 525 green_ap_err("green ap context obtained is NULL"); 526 return QDF_STATUS_E_FAILURE; 527 } 528 529 if ((green_ap_ctx->ps_state == WLAN_GREEN_AP_PS_ON_STATE) && 530 (green_ap_ctx->ps_enable)) 531 return true; 532 533 return false; 534 535 } 536 537 void wlan_green_ap_suspend_handle(struct wlan_objmgr_pdev *pdev) 538 { 539 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 540 541 if (!pdev) { 542 green_ap_err("pdev context passed is NULL"); 543 return; 544 } 545 546 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 547 pdev, WLAN_UMAC_COMP_GREEN_AP); 548 549 if (!green_ap_ctx) { 550 green_ap_err("green ap context obtained is NULL"); 551 return; 552 } 553 554 wlan_green_ap_stop(pdev); 555 556 green_ap_ctx->ps_enable = WLAN_GREEN_AP_PS_SUSPEND; 557 } 558 559 bool wlan_green_ap_is_ps_waiting(struct wlan_objmgr_pdev *pdev) 560 { 561 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 562 563 if (!pdev) { 564 green_ap_err("pdev context passed is NULL"); 565 return QDF_STATUS_E_INVAL; 566 } 567 568 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 569 pdev, WLAN_UMAC_COMP_GREEN_AP); 570 if (!green_ap_ctx) { 571 green_ap_err("green ap context obtained is NULL"); 572 return QDF_STATUS_E_FAILURE; 573 } 574 575 if ((green_ap_ctx->ps_state == WLAN_GREEN_AP_PS_WAIT_STATE) && 576 (green_ap_ctx->ps_enable)) { 577 return true; 578 } 579 580 return false; 581 } 582