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