xref: /wlan-dirver/qca-wifi-host-cmn/umac/green_ap/core/src/wlan_green_ap_main.c (revision c90cb55572eee60b3b13d0766be45322765a8a97)
1 /*
2  * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /**
21  * DOC: This file contains main green ap function definitions
22  */
23 
24 #include "wlan_green_ap_main_i.h"
25 
26 /**
27  * wlan_green_ap_ant_ps_reset() - Reset function
28  * @green_ap_ctx: green ap context
29  *
30  * Reset function, so that Antenna Mask can come into effect.
31  *                This applies for only few of the hardware chips
32  *
33  * Return: QDF_STATUS
34  */
35 static QDF_STATUS wlan_green_ap_ant_ps_reset
36 		(struct wlan_pdev_green_ap_ctx *green_ap_ctx)
37 {
38 	struct wlan_lmac_if_green_ap_tx_ops *green_ap_tx_ops;
39 	struct wlan_objmgr_pdev *pdev;
40 
41 	if (!green_ap_ctx) {
42 		green_ap_err("green ap context obtained is NULL");
43 		return QDF_STATUS_E_FAILURE;
44 	}
45 	pdev = green_ap_ctx->pdev;
46 
47 	green_ap_tx_ops = wlan_psoc_get_green_ap_tx_ops(green_ap_ctx);
48 	if (!green_ap_tx_ops) {
49 		green_ap_err("green ap tx ops obtained are NULL");
50 		return QDF_STATUS_E_FAILURE;
51 	}
52 
53 	if (!green_ap_tx_ops->reset_dev)
54 		return QDF_STATUS_SUCCESS;
55 
56 	/*
57 	 * Add protection against green AP enabling interrupts
58 	 * when not valid or no VAPs exist
59 	 */
60 	if (wlan_util_is_vdev_active(pdev, WLAN_GREEN_AP_ID) ==
61 						QDF_STATUS_SUCCESS)
62 		green_ap_tx_ops->reset_dev(pdev);
63 	else
64 		green_ap_err("Green AP tried to enable IRQs when invalid");
65 
66 	return QDF_STATUS_SUCCESS;
67 }
68 
69 struct wlan_lmac_if_green_ap_tx_ops *
70 wlan_psoc_get_green_ap_tx_ops(struct wlan_pdev_green_ap_ctx *green_ap_ctx)
71 {
72 	struct wlan_objmgr_psoc *psoc;
73 	struct wlan_objmgr_pdev *pdev = green_ap_ctx->pdev;
74 	struct wlan_lmac_if_tx_ops *tx_ops;
75 
76 	if (!pdev) {
77 		green_ap_err("pdev context obtained is NULL");
78 		return NULL;
79 	}
80 
81 	psoc = wlan_pdev_get_psoc(pdev);
82 	if (!psoc) {
83 		green_ap_err("pdev context obtained is NULL");
84 		return NULL;
85 	}
86 
87 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
88 	if (!tx_ops) {
89 		green_ap_err("tx_ops is NULL");
90 		return NULL;
91 	}
92 
93 	return &tx_ops->green_ap_tx_ops;
94 }
95 
96 bool wlan_is_egap_enabled(struct wlan_pdev_green_ap_ctx *green_ap_ctx)
97 {
98 	struct wlan_green_ap_egap_params *egap_params;
99 
100 	if (!green_ap_ctx) {
101 		green_ap_err("green ap context passed is NULL");
102 		return QDF_STATUS_E_INVAL;
103 	}
104 	egap_params = &green_ap_ctx->egap_params;
105 
106 	if (egap_params->fw_egap_support &&
107 	    egap_params->host_enable_egap &&
108 	    egap_params->egap_feature_flags)
109 		return true;
110 	return false;
111 }
112 qdf_export_symbol(wlan_is_egap_enabled);
113 
114 /**
115  * wlan_green_ap_ps_event_state_update() - Update PS state and event
116  * @green_ap_ctx: Green AP pdev context
117  * @state: ps state
118  * @event: ps event
119  *
120  * Return: Success or Failure
121  */
122 static QDF_STATUS wlan_green_ap_ps_event_state_update(
123 			struct wlan_pdev_green_ap_ctx *green_ap_ctx,
124 			enum wlan_green_ap_ps_state state,
125 			enum wlan_green_ap_ps_event event)
126 {
127 	if (!green_ap_ctx) {
128 		green_ap_err("green ap context obtained is NULL");
129 		return QDF_STATUS_E_FAILURE;
130 	}
131 
132 	green_ap_ctx->ps_state = state;
133 	green_ap_ctx->ps_event = event;
134 
135 	return QDF_STATUS_SUCCESS;
136 }
137 
138 QDF_STATUS wlan_green_ap_state_mc(struct wlan_pdev_green_ap_ctx *green_ap_ctx,
139 				  enum wlan_green_ap_ps_event event)
140 {
141 	struct wlan_lmac_if_green_ap_tx_ops *green_ap_tx_ops;
142 	uint8_t pdev_id;
143 
144 	/*
145 	 * Remove the assignments once channel info is available for
146 	 * converged component.
147 	 */
148 	uint16_t channel = 1;
149 	uint32_t channel_flags = 1;
150 
151 	if (!green_ap_ctx) {
152 		green_ap_err("green ap context obtained is NULL");
153 		return QDF_STATUS_E_FAILURE;
154 	}
155 
156 	if (!green_ap_ctx->pdev) {
157 		green_ap_err("pdev obtained is NULL");
158 		return QDF_STATUS_E_FAILURE;
159 	}
160 	pdev_id = wlan_objmgr_pdev_get_pdev_id(green_ap_ctx->pdev);
161 
162 	green_ap_tx_ops = wlan_psoc_get_green_ap_tx_ops(green_ap_ctx);
163 	if (!green_ap_tx_ops) {
164 		green_ap_err("green ap tx ops obtained are NULL");
165 		return QDF_STATUS_E_FAILURE;
166 	}
167 
168 	if (!green_ap_tx_ops->ps_on_off_send) {
169 		green_ap_err("tx op for sending enable/disable green ap is NULL");
170 		return QDF_STATUS_E_FAILURE;
171 	}
172 
173 	qdf_spin_lock_bh(&green_ap_ctx->lock);
174 
175 	if (green_ap_tx_ops->get_current_channel)
176 		channel = green_ap_tx_ops->get_current_channel(
177 						green_ap_ctx->pdev);
178 
179 	if (green_ap_tx_ops->get_current_channel_flags)
180 		channel_flags = green_ap_tx_ops->get_current_channel_flags(
181 							green_ap_ctx->pdev);
182 
183 	/* handle the green ap ps event */
184 	switch (event) {
185 	case WLAN_GREEN_AP_ADD_STA_EVENT:
186 		green_ap_ctx->num_nodes++;
187 		break;
188 
189 	case WLAN_GREEN_AP_DEL_STA_EVENT:
190 		if (green_ap_ctx->num_nodes)
191 			green_ap_ctx->num_nodes--;
192 		break;
193 
194 	case WLAN_GREEN_AP_ADD_MULTISTREAM_STA_EVENT:
195 		green_ap_ctx->num_nodes_multistream++;
196 		break;
197 
198 	case WLAN_GREEN_AP_DEL_MULTISTREAM_STA_EVENT:
199 		if (green_ap_ctx->num_nodes_multistream)
200 			green_ap_ctx->num_nodes_multistream--;
201 		break;
202 
203 	case WLAN_GREEN_AP_PS_START_EVENT:
204 	case WLAN_GREEN_AP_PS_STOP_EVENT:
205 	case WLAN_GREEN_AP_PS_ON_EVENT:
206 	case WLAN_GREEN_AP_PS_WAIT_EVENT:
207 		break;
208 
209 	default:
210 		green_ap_err("Invalid event: %d", event);
211 		break;
212 	}
213 
214 	green_ap_debug("Green-AP event: %d, state: %d, num_nodes: %d",
215 		       event, green_ap_ctx->ps_state, green_ap_ctx->num_nodes);
216 
217 	/* Confirm that power save is enabled before doing state transitions */
218 	if (!green_ap_ctx->ps_enable) {
219 		green_ap_debug("Green-AP is disabled");
220 		if (green_ap_ctx->ps_state == WLAN_GREEN_AP_PS_ON_STATE) {
221 			if (green_ap_tx_ops->ps_on_off_send(green_ap_ctx->pdev,
222 								false, pdev_id))
223 				green_ap_err("failed to set green ap mode");
224 			wlan_green_ap_ant_ps_reset(green_ap_ctx);
225 		}
226 		wlan_green_ap_ps_event_state_update(
227 				green_ap_ctx,
228 				WLAN_GREEN_AP_PS_IDLE_STATE,
229 				WLAN_GREEN_AP_PS_WAIT_EVENT);
230 		goto done;
231 	}
232 
233 	/* handle the green ap ps state */
234 	switch (green_ap_ctx->ps_state) {
235 	case WLAN_GREEN_AP_PS_IDLE_STATE:
236 		if ((green_ap_ctx->num_nodes &&
237 		     green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NO_STA) ||
238 		    (green_ap_ctx->num_nodes_multistream &&
239 		     green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NUM_STREAM)) {
240 			/*
241 			 * Multistream nodes present, switchoff the power save
242 			 */
243 			green_ap_info("Transition to OFF from IDLE");
244 			wlan_green_ap_ps_event_state_update(
245 					green_ap_ctx,
246 					WLAN_GREEN_AP_PS_OFF_STATE,
247 					WLAN_GREEN_AP_PS_WAIT_EVENT);
248 		} else {
249 			/* No Active nodes, get into power save */
250 			green_ap_info("Transition to WAIT from IDLE");
251 			wlan_green_ap_ps_event_state_update(
252 					green_ap_ctx,
253 					WLAN_GREEN_AP_PS_WAIT_STATE,
254 					WLAN_GREEN_AP_PS_WAIT_EVENT);
255 			qdf_timer_start(&green_ap_ctx->ps_timer,
256 					green_ap_ctx->ps_trans_time * 1000);
257 		}
258 		break;
259 
260 	case WLAN_GREEN_AP_PS_OFF_STATE:
261 		if ((!green_ap_ctx->num_nodes &&
262 		     green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NO_STA) ||
263 		    (!green_ap_ctx->num_nodes_multistream &&
264 		     green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NUM_STREAM)) {
265 			green_ap_info("Transition to WAIT from OFF");
266 			wlan_green_ap_ps_event_state_update(
267 						green_ap_ctx,
268 						WLAN_GREEN_AP_PS_WAIT_STATE,
269 						WLAN_GREEN_AP_PS_WAIT_EVENT);
270 			qdf_timer_start(&green_ap_ctx->ps_timer,
271 					green_ap_ctx->ps_trans_time * 1000);
272 		}
273 		break;
274 
275 	case WLAN_GREEN_AP_PS_WAIT_STATE:
276 		if ((!green_ap_ctx->num_nodes &&
277 		     green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NO_STA) ||
278 		    (!green_ap_ctx->num_nodes_multistream &&
279 		     green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NUM_STREAM)) {
280 			if (event == WLAN_GREEN_AP_DEL_MULTISTREAM_STA_EVENT)
281 				break;
282 			if ((channel == 0) || (channel_flags == 0)) {
283 				/*
284 				 * Stay in the current state and restart the
285 				 * timer to check later.
286 				 */
287 				qdf_timer_start(&green_ap_ctx->ps_timer,
288 					green_ap_ctx->ps_on_time * 1000);
289 			} else {
290 				wlan_green_ap_ps_event_state_update(
291 						green_ap_ctx,
292 						WLAN_GREEN_AP_PS_ON_STATE,
293 						WLAN_GREEN_AP_PS_WAIT_EVENT);
294 
295 				green_ap_info("Transition to ON from WAIT");
296 				green_ap_tx_ops->ps_on_off_send(
297 					green_ap_ctx->pdev, true, pdev_id);
298 				wlan_green_ap_ant_ps_reset(green_ap_ctx);
299 
300 				if (green_ap_ctx->ps_on_time)
301 					qdf_timer_start(&green_ap_ctx->ps_timer,
302 						green_ap_ctx->ps_on_time * 1000);
303 			}
304 		} else {
305 			green_ap_info("Transition to OFF from WAIT");
306 			qdf_timer_stop(&green_ap_ctx->ps_timer);
307 			wlan_green_ap_ps_event_state_update(
308 						green_ap_ctx,
309 						WLAN_GREEN_AP_PS_OFF_STATE,
310 						WLAN_GREEN_AP_PS_WAIT_EVENT);
311 		}
312 		break;
313 
314 	case WLAN_GREEN_AP_PS_ON_STATE:
315 		if ((green_ap_ctx->num_nodes &&
316 		     green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NO_STA) ||
317 		    (green_ap_ctx->num_nodes_multistream &&
318 		     green_ap_ctx->ps_mode == WLAN_GREEN_AP_MODE_NUM_STREAM)) {
319 			qdf_timer_stop(&green_ap_ctx->ps_timer);
320 			if (green_ap_tx_ops->ps_on_off_send(
321 					green_ap_ctx->pdev, false, pdev_id)) {
322 				green_ap_err("Failed to set Green AP mode");
323 				goto done;
324 			}
325 			wlan_green_ap_ant_ps_reset(green_ap_ctx);
326 			green_ap_info("Transition to OFF from ON\n");
327 			wlan_green_ap_ps_event_state_update(
328 						green_ap_ctx,
329 						WLAN_GREEN_AP_PS_OFF_STATE,
330 						WLAN_GREEN_AP_PS_WAIT_EVENT);
331 		} else if ((green_ap_ctx->ps_event ==
332 					WLAN_GREEN_AP_PS_WAIT_EVENT) &&
333 			   (green_ap_ctx->ps_on_time)) {
334 			/* ps_on_time timeout, switch to ps wait */
335 			wlan_green_ap_ps_event_state_update(
336 						green_ap_ctx,
337 						WLAN_GREEN_AP_PS_WAIT_STATE,
338 						WLAN_GREEN_AP_PS_ON_EVENT);
339 
340 			if (green_ap_tx_ops->ps_on_off_send(
341 					green_ap_ctx->pdev, false, pdev_id)) {
342 				green_ap_err("Failed to set Green AP mode");
343 				goto done;
344 			}
345 
346 			wlan_green_ap_ant_ps_reset(green_ap_ctx);
347 			green_ap_info("Transition to WAIT from ON\n");
348 			qdf_timer_start(&green_ap_ctx->ps_timer,
349 					green_ap_ctx->ps_trans_time * 1000);
350 		}
351 		break;
352 
353 	default:
354 		green_ap_err("invalid state %d", green_ap_ctx->ps_state);
355 		wlan_green_ap_ps_event_state_update(
356 						green_ap_ctx,
357 						WLAN_GREEN_AP_PS_OFF_STATE,
358 						WLAN_GREEN_AP_PS_WAIT_EVENT);
359 		break;
360 	}
361 
362 done:
363 	qdf_spin_unlock_bh(&green_ap_ctx->lock);
364 	return QDF_STATUS_SUCCESS;
365 }
366 
367 void wlan_green_ap_timer_fn(void *pdev)
368 {
369 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
370 	struct wlan_objmgr_pdev *pdev_ctx = (struct wlan_objmgr_pdev *)pdev;
371 
372 	if (!pdev_ctx) {
373 		green_ap_err("pdev context passed is NULL");
374 		return;
375 	}
376 
377 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
378 			pdev_ctx, WLAN_UMAC_COMP_GREEN_AP);
379 	if (!green_ap_ctx) {
380 		green_ap_err("green ap context obtained is NULL");
381 		return;
382 	}
383 	wlan_green_ap_state_mc(green_ap_ctx, green_ap_ctx->ps_event);
384 }
385 
386 void wlan_green_ap_check_mode(struct wlan_objmgr_pdev *pdev,
387 		void *object,
388 		void *arg)
389 {
390 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
391 	uint8_t *flag = (uint8_t *)arg;
392 	enum QDF_OPMODE mode = QDF_MAX_NO_OF_MODE;
393 
394 	wlan_vdev_obj_lock(vdev);
395 	mode = wlan_vdev_mlme_get_opmode(vdev);
396 
397 	if (mode != QDF_SAP_MODE && mode != QDF_STA_MODE)
398 		*flag = 1;
399 
400 	wlan_vdev_obj_unlock(vdev);
401 }
402 
403 #ifdef WLAN_SUPPORT_GAP_LL_PS_MODE
404 #define LOW_LATENCY_MAX_CMDID 0x00000080
405 
406 uint32_t wlan_green_ap_get_cookie_id(struct wlan_pdev_green_ap_ctx *green_ap_ctx,
407 				     enum wlan_green_ap_ll_ps_state state)
408 {
409 	uint32_t id;
410 	qdf_atomic_t *cmd_cnt;
411 
412 	qdf_spin_lock_bh(&green_ap_ctx->lock);
413 
414 	if (!state)
415 		cmd_cnt = &green_ap_ctx->ps_dis_cmd_cnt;
416 	else
417 		cmd_cnt = &green_ap_ctx->ps_en_cmd_cnt;
418 
419 	id = qdf_atomic_read(cmd_cnt);
420 
421 	if (id >= LOW_LATENCY_MAX_CMDID) {
422 		green_ap_debug("Cookie id Max limit reached");
423 
424 		if (!state)
425 			qdf_atomic_set(cmd_cnt, 0);
426 		else
427 			qdf_atomic_set(cmd_cnt, 1);
428 
429 		id = qdf_atomic_read(cmd_cnt);
430 	}
431 
432 	qdf_atomic_add(2, cmd_cnt);
433 	qdf_spin_unlock_bh(&green_ap_ctx->lock);
434 
435 	green_ap_debug("Cookie id : %x", id);
436 
437 	return id;
438 }
439 
440 QDF_STATUS
441 wlan_green_ap_send_ll_ps_event_params(struct wlan_objmgr_pdev *pdev,
442 		struct wlan_green_ap_ll_ps_event_param *event_param)
443 {
444 	QDF_STATUS status;
445 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
446 
447 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
448 			pdev, WLAN_UMAC_COMP_GREEN_AP);
449 
450 	if (!green_ap_ctx) {
451 		green_ap_err("green ap context obtained is NULL");
452 		return QDF_STATUS_E_FAILURE;
453 	}
454 
455 	status = green_ap_ctx->hdd_cback.send_event(green_ap_ctx->vdev, event_param);
456 
457 	return status;
458 }
459 #endif
460