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