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