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