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