xref: /wlan-dirver/qca-wifi-host-cmn/umac/green_ap/core/src/wlan_green_ap_main.c (revision a86b23ee68a2491aede2e03991f3fb37046f4e41)
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 
392 	wlan_vdev_obj_lock(vdev);
393 	if (wlan_vdev_mlme_get_opmode(vdev) != QDF_SAP_MODE)
394 		*flag = 1;
395 
396 	wlan_vdev_obj_unlock(vdev);
397 }
398 
399