xref: /wlan-dirver/qca-wifi-host-cmn/umac/green_ap/core/src/wlan_green_ap_main.c (revision 4865edfd190c086bbe2c69aae12a8226f877b91e)
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, WLAN_GREEN_AP_ID) == 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