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 main green ap function definitions 22 */ 23 24 #include "wlan_green_ap_main_i.h" 25 26 /* 27 * wlan_green_ap_ant_ps_reset() - Reset function 28 * @green_ap - green ap context 29 * 30 * Reset fiunction, so that Antenna Mask can come into effect. 31 * This applies for only few of the hardware chips 32 * 33 * Return: QDF_STATUS 34 */ 35 static QDF_STATUS wlan_green_ap_ant_ps_reset 36 (struct wlan_pdev_green_ap_ctx *green_ap_ctx) 37 { 38 struct wlan_lmac_if_green_ap_tx_ops *green_ap_tx_ops; 39 struct wlan_objmgr_pdev *pdev; 40 41 if (!green_ap_ctx) { 42 green_ap_err("green ap context obtained is NULL"); 43 return QDF_STATUS_E_FAILURE; 44 } 45 pdev = green_ap_ctx->pdev; 46 47 green_ap_tx_ops = wlan_psoc_get_green_ap_tx_ops(green_ap_ctx); 48 if (!green_ap_tx_ops) { 49 green_ap_err("green ap tx ops obtained are NULL"); 50 return QDF_STATUS_E_FAILURE; 51 } 52 53 if (!green_ap_tx_ops->reset_dev) 54 return QDF_STATUS_SUCCESS; 55 56 /* 57 * Add protection against green AP enabling interrupts 58 * when not valid or no VAPs exist 59 */ 60 if (wlan_util_is_vdev_active(pdev, WLAN_GREEN_AP_ID) == 61 QDF_STATUS_SUCCESS) 62 green_ap_tx_ops->reset_dev(pdev); 63 else 64 green_ap_err("Green AP tried to enable IRQs when invalid"); 65 66 return QDF_STATUS_SUCCESS; 67 } 68 69 struct wlan_lmac_if_green_ap_tx_ops * 70 wlan_psoc_get_green_ap_tx_ops(struct wlan_pdev_green_ap_ctx *green_ap_ctx) 71 { 72 struct wlan_objmgr_psoc *psoc; 73 struct wlan_objmgr_pdev *pdev = green_ap_ctx->pdev; 74 struct wlan_lmac_if_tx_ops *tx_ops; 75 76 if (!pdev) { 77 green_ap_err("pdev context obtained is NULL"); 78 return NULL; 79 } 80 81 psoc = wlan_pdev_get_psoc(pdev); 82 if (!psoc) { 83 green_ap_err("pdev context obtained is NULL"); 84 return NULL; 85 } 86 87 tx_ops = wlan_psoc_get_lmac_if_txops(psoc); 88 if (!tx_ops) { 89 green_ap_err("tx_ops is NULL"); 90 return NULL; 91 } 92 93 return &tx_ops->green_ap_tx_ops; 94 } 95 96 bool wlan_is_egap_enabled(struct wlan_pdev_green_ap_ctx *green_ap_ctx) 97 { 98 struct wlan_green_ap_egap_params *egap_params; 99 100 if (!green_ap_ctx) { 101 green_ap_err("green ap context passed is NULL"); 102 return QDF_STATUS_E_INVAL; 103 } 104 egap_params = &green_ap_ctx->egap_params; 105 106 if (egap_params->fw_egap_support && 107 egap_params->host_enable_egap && 108 egap_params->egap_feature_flags) 109 return true; 110 return false; 111 } 112 qdf_export_symbol(wlan_is_egap_enabled); 113 114 /** 115 * wlan_green_ap_ps_event_state_update() - Update PS state and event 116 * @pdev: pdev pointer 117 * @state: ps state 118 * @event: ps event 119 * 120 * @Return: Success or Failure 121 */ 122 static QDF_STATUS wlan_green_ap_ps_event_state_update( 123 struct wlan_pdev_green_ap_ctx *green_ap_ctx, 124 enum wlan_green_ap_ps_state state, 125 enum wlan_green_ap_ps_event event) 126 { 127 if (!green_ap_ctx) { 128 green_ap_err("green ap context obtained is NULL"); 129 return QDF_STATUS_E_FAILURE; 130 } 131 132 green_ap_ctx->ps_state = state; 133 green_ap_ctx->ps_event = event; 134 135 return QDF_STATUS_SUCCESS; 136 } 137 138 QDF_STATUS wlan_green_ap_state_mc(struct wlan_pdev_green_ap_ctx *green_ap_ctx, 139 enum wlan_green_ap_ps_event event) 140 { 141 struct wlan_lmac_if_green_ap_tx_ops *green_ap_tx_ops; 142 uint8_t pdev_id; 143 144 /* 145 * Remove the assignments once channel info is available for 146 * converged component. 147 */ 148 uint16_t channel = 1; 149 uint32_t channel_flags = 1; 150 151 if (!green_ap_ctx) { 152 green_ap_err("green ap context obtained is NULL"); 153 return QDF_STATUS_E_FAILURE; 154 } 155 156 if (!green_ap_ctx->pdev) { 157 green_ap_err("pdev obtained is NULL"); 158 return QDF_STATUS_E_FAILURE; 159 } 160 pdev_id = wlan_objmgr_pdev_get_pdev_id(green_ap_ctx->pdev); 161 162 green_ap_tx_ops = wlan_psoc_get_green_ap_tx_ops(green_ap_ctx); 163 if (!green_ap_tx_ops) { 164 green_ap_err("green ap tx ops obtained are NULL"); 165 return QDF_STATUS_E_FAILURE; 166 } 167 168 if (!green_ap_tx_ops->ps_on_off_send) { 169 green_ap_err("tx op for sending enable/disable green ap is NULL"); 170 return QDF_STATUS_E_FAILURE; 171 } 172 173 qdf_spin_lock_bh(&green_ap_ctx->lock); 174 175 if (green_ap_tx_ops->get_current_channel) 176 channel = green_ap_tx_ops->get_current_channel( 177 green_ap_ctx->pdev); 178 179 if (green_ap_tx_ops->get_current_channel_flags) 180 channel_flags = green_ap_tx_ops->get_current_channel_flags( 181 green_ap_ctx->pdev); 182 183 /* handle the green ap ps event */ 184 switch (event) { 185 case WLAN_GREEN_AP_ADD_STA_EVENT: 186 green_ap_ctx->num_nodes++; 187 break; 188 189 case WLAN_GREEN_AP_DEL_STA_EVENT: 190 if (green_ap_ctx->num_nodes) 191 green_ap_ctx->num_nodes--; 192 break; 193 194 case WLAN_GREEN_AP_ADD_MULTISTREAM_STA_EVENT: 195 green_ap_ctx->num_nodes_multistream++; 196 break; 197 198 case WLAN_GREEN_AP_DEL_MULTISTREAM_STA_EVENT: 199 if (green_ap_ctx->num_nodes_multistream) 200 green_ap_ctx->num_nodes_multistream--; 201 break; 202 203 case WLAN_GREEN_AP_PS_START_EVENT: 204 case WLAN_GREEN_AP_PS_STOP_EVENT: 205 case WLAN_GREEN_AP_PS_ON_EVENT: 206 case WLAN_GREEN_AP_PS_WAIT_EVENT: 207 break; 208 209 default: 210 green_ap_err("Invalid event: %d", event); 211 break; 212 } 213 214 green_ap_debug("Green-AP event: %d, state: %d, num_nodes: %d", 215 event, green_ap_ctx->ps_state, green_ap_ctx->num_nodes); 216 217 /* Confirm that power save is enabled before doing state transitions */ 218 if (!green_ap_ctx->ps_enable) { 219 green_ap_debug("Green-AP is disabled"); 220 if (green_ap_ctx->ps_state == WLAN_GREEN_AP_PS_ON_STATE) { 221 if (green_ap_tx_ops->ps_on_off_send(green_ap_ctx->pdev, 222 false, pdev_id)) 223 green_ap_err("failed to set green ap mode"); 224 wlan_green_ap_ant_ps_reset(green_ap_ctx); 225 } 226 wlan_green_ap_ps_event_state_update( 227 green_ap_ctx, 228 WLAN_GREEN_AP_PS_IDLE_STATE, 229 WLAN_GREEN_AP_PS_WAIT_EVENT); 230 goto done; 231 } 232 233 /* handle the green ap ps state */ 234 switch (green_ap_ctx->ps_state) { 235 case WLAN_GREEN_AP_PS_IDLE_STATE: 236 if ((green_ap_ctx->num_nodes && 237 green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NO_STA) || 238 (green_ap_ctx->num_nodes_multistream && 239 green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NUM_STREAM)) { 240 /* 241 * Multistream nodes present, switchoff the power save 242 */ 243 green_ap_info("Transition to OFF from IDLE"); 244 wlan_green_ap_ps_event_state_update( 245 green_ap_ctx, 246 WLAN_GREEN_AP_PS_OFF_STATE, 247 WLAN_GREEN_AP_PS_WAIT_EVENT); 248 } else { 249 /* No Active nodes, get into power save */ 250 green_ap_info("Transition to WAIT from IDLE"); 251 wlan_green_ap_ps_event_state_update( 252 green_ap_ctx, 253 WLAN_GREEN_AP_PS_WAIT_STATE, 254 WLAN_GREEN_AP_PS_WAIT_EVENT); 255 qdf_timer_start(&green_ap_ctx->ps_timer, 256 green_ap_ctx->ps_trans_time * 1000); 257 } 258 break; 259 260 case WLAN_GREEN_AP_PS_OFF_STATE: 261 if ((!green_ap_ctx->num_nodes && 262 green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NO_STA) || 263 (!green_ap_ctx->num_nodes_multistream && 264 green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NUM_STREAM)) { 265 green_ap_info("Transition to WAIT from OFF"); 266 wlan_green_ap_ps_event_state_update( 267 green_ap_ctx, 268 WLAN_GREEN_AP_PS_WAIT_STATE, 269 WLAN_GREEN_AP_PS_WAIT_EVENT); 270 qdf_timer_start(&green_ap_ctx->ps_timer, 271 green_ap_ctx->ps_trans_time * 1000); 272 } 273 break; 274 275 case WLAN_GREEN_AP_PS_WAIT_STATE: 276 if ((!green_ap_ctx->num_nodes && 277 green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NO_STA) || 278 (!green_ap_ctx->num_nodes_multistream && 279 green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NUM_STREAM)) { 280 if (event == WLAN_GREEN_AP_DEL_MULTISTREAM_STA_EVENT) 281 break; 282 if ((channel == 0) || (channel_flags == 0)) { 283 /* 284 * Stay in the current state and restart the 285 * timer to check later. 286 */ 287 qdf_timer_start(&green_ap_ctx->ps_timer, 288 green_ap_ctx->ps_on_time * 1000); 289 } else { 290 wlan_green_ap_ps_event_state_update( 291 green_ap_ctx, 292 WLAN_GREEN_AP_PS_ON_STATE, 293 WLAN_GREEN_AP_PS_WAIT_EVENT); 294 295 green_ap_info("Transition to ON from WAIT"); 296 green_ap_tx_ops->ps_on_off_send( 297 green_ap_ctx->pdev, true, pdev_id); 298 wlan_green_ap_ant_ps_reset(green_ap_ctx); 299 300 if (green_ap_ctx->ps_on_time) 301 qdf_timer_start(&green_ap_ctx->ps_timer, 302 green_ap_ctx->ps_on_time * 1000); 303 } 304 } else { 305 green_ap_info("Transition to OFF from WAIT"); 306 qdf_timer_stop(&green_ap_ctx->ps_timer); 307 wlan_green_ap_ps_event_state_update( 308 green_ap_ctx, 309 WLAN_GREEN_AP_PS_OFF_STATE, 310 WLAN_GREEN_AP_PS_WAIT_EVENT); 311 } 312 break; 313 314 case WLAN_GREEN_AP_PS_ON_STATE: 315 if ((green_ap_ctx->num_nodes && 316 green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NO_STA) || 317 (green_ap_ctx->num_nodes_multistream && 318 green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NUM_STREAM)) { 319 qdf_timer_stop(&green_ap_ctx->ps_timer); 320 if (green_ap_tx_ops->ps_on_off_send( 321 green_ap_ctx->pdev, false, pdev_id)) { 322 green_ap_err("Failed to set Green AP mode"); 323 goto done; 324 } 325 wlan_green_ap_ant_ps_reset(green_ap_ctx); 326 green_ap_info("Transition to OFF from ON\n"); 327 wlan_green_ap_ps_event_state_update( 328 green_ap_ctx, 329 WLAN_GREEN_AP_PS_OFF_STATE, 330 WLAN_GREEN_AP_PS_WAIT_EVENT); 331 } else if ((green_ap_ctx->ps_event == 332 WLAN_GREEN_AP_PS_WAIT_EVENT) && 333 (green_ap_ctx->ps_on_time)) { 334 /* ps_on_time timeout, switch to ps wait */ 335 wlan_green_ap_ps_event_state_update( 336 green_ap_ctx, 337 WLAN_GREEN_AP_PS_WAIT_STATE, 338 WLAN_GREEN_AP_PS_ON_EVENT); 339 340 if (green_ap_tx_ops->ps_on_off_send( 341 green_ap_ctx->pdev, false, pdev_id)) { 342 green_ap_err("Failed to set Green AP mode"); 343 goto done; 344 } 345 346 wlan_green_ap_ant_ps_reset(green_ap_ctx); 347 green_ap_info("Transition to WAIT from ON\n"); 348 qdf_timer_start(&green_ap_ctx->ps_timer, 349 green_ap_ctx->ps_trans_time * 1000); 350 } 351 break; 352 353 default: 354 green_ap_err("invalid state %d", green_ap_ctx->ps_state); 355 wlan_green_ap_ps_event_state_update( 356 green_ap_ctx, 357 WLAN_GREEN_AP_PS_OFF_STATE, 358 WLAN_GREEN_AP_PS_WAIT_EVENT); 359 break; 360 } 361 362 done: 363 qdf_spin_unlock_bh(&green_ap_ctx->lock); 364 return QDF_STATUS_SUCCESS; 365 } 366 367 void wlan_green_ap_timer_fn(void *pdev) 368 { 369 struct wlan_pdev_green_ap_ctx *green_ap_ctx; 370 struct wlan_objmgr_pdev *pdev_ctx = (struct wlan_objmgr_pdev *)pdev; 371 372 if (!pdev_ctx) { 373 green_ap_err("pdev context passed is NULL"); 374 return; 375 } 376 377 green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( 378 pdev_ctx, WLAN_UMAC_COMP_GREEN_AP); 379 if (!green_ap_ctx) { 380 green_ap_err("green ap context obtained is NULL"); 381 return; 382 } 383 wlan_green_ap_state_mc(green_ap_ctx, green_ap_ctx->ps_event); 384 } 385 386 void wlan_green_ap_check_mode(struct wlan_objmgr_pdev *pdev, 387 void *object, 388 void *arg) 389 { 390 struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object; 391 uint8_t *flag = (uint8_t *)arg; 392 enum QDF_OPMODE mode = QDF_MAX_NO_OF_MODE; 393 394 wlan_vdev_obj_lock(vdev); 395 mode = wlan_vdev_mlme_get_opmode(vdev); 396 397 if (mode != QDF_SAP_MODE && mode != QDF_STA_MODE) 398 *flag = 1; 399 400 wlan_vdev_obj_unlock(vdev); 401 } 402 403