xref: /wlan-dirver/qca-wifi-host-cmn/umac/green_ap/dispatcher/src/wlan_green_ap_api.c (revision d0c05845839e5f2ba5a8dcebe0cd3e4cd4e8dfcf)
1 /*
2  * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022 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 green ap north bound interface definitions
22  */
23 #include <wlan_green_ap_api.h>
24 #include <../../core/src/wlan_green_ap_main_i.h>
25 #include <wlan_objmgr_global_obj.h>
26 #include "cfg_green_ap_params.h"
27 #include "cfg_ucfg_api.h"
28 
29 QDF_STATUS wlan_green_ap_get_capab(
30 			struct wlan_objmgr_pdev *pdev)
31 {
32 	struct wlan_lmac_if_green_ap_tx_ops *green_ap_tx_ops;
33 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
34 
35 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(pdev,
36 					WLAN_UMAC_COMP_GREEN_AP);
37 
38 	if (!green_ap_ctx) {
39 		green_ap_err("green ap context obtained is NULL");
40 		return QDF_STATUS_E_FAILURE;
41 	}
42 
43 
44 	green_ap_tx_ops = wlan_psoc_get_green_ap_tx_ops(green_ap_ctx);
45 	if (!green_ap_tx_ops) {
46 		green_ap_err("green ap tx ops obtained are NULL");
47 		return QDF_STATUS_E_EXISTS;
48 	}
49 
50 	if (green_ap_tx_ops->get_capab)
51 		return green_ap_tx_ops->get_capab(pdev);
52 
53 	return QDF_STATUS_SUCCESS;
54 }
55 
56 /**
57  * wlan_green_ap_pdev_obj_create_notification() - called from objmgr when pdev
58  *                                                is created
59  * @pdev: pdev context
60  * @arg: argument
61  *
62  * This function gets called from object manager when pdev is being created and
63  * creates green ap context and attach it to objmgr.
64  *
65  * Return: QDF_STATUS_SUCCESS - in case of success
66  */
67 static QDF_STATUS wlan_green_ap_pdev_obj_create_notification(
68 			struct wlan_objmgr_pdev *pdev, void *arg)
69 {
70 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
71 	QDF_STATUS status = QDF_STATUS_SUCCESS;
72 
73 	if (!pdev) {
74 		green_ap_err("pdev context passed is NULL");
75 		return QDF_STATUS_E_INVAL;
76 	}
77 
78 	green_ap_ctx = qdf_mem_malloc(sizeof(*green_ap_ctx));
79 	if (!green_ap_ctx)
80 		return QDF_STATUS_E_NOMEM;
81 
82 	green_ap_ctx->ps_state = WLAN_GREEN_AP_PS_IDLE_STATE;
83 	green_ap_ctx->ps_event = WLAN_GREEN_AP_PS_WAIT_EVENT;
84 	green_ap_ctx->ps_mode = WLAN_GREEN_AP_MODE_NO_STA;
85 	green_ap_ctx->num_nodes = 0;
86 	green_ap_ctx->num_nodes_multistream = 0;
87 	green_ap_ctx->ps_on_time = WLAN_GREEN_AP_PS_ON_TIME;
88 	green_ap_ctx->ps_trans_time = WLAN_GREEN_AP_PS_TRANS_TIME;
89 
90 	green_ap_ctx->pdev = pdev;
91 
92 	qdf_timer_init(NULL, &green_ap_ctx->ps_timer,
93 		       wlan_green_ap_timer_fn,
94 		       pdev, QDF_TIMER_TYPE_WAKE_APPS);
95 
96 	qdf_spinlock_create(&green_ap_ctx->lock);
97 	if (wlan_objmgr_pdev_component_obj_attach(pdev,
98 				WLAN_UMAC_COMP_GREEN_AP,
99 				green_ap_ctx, QDF_STATUS_SUCCESS)
100 			!= QDF_STATUS_SUCCESS) {
101 		green_ap_err("Failed to attach green ap ctx in pdev ctx");
102 		status = QDF_STATUS_E_FAILURE;
103 		goto err_pdev_attach;
104 	}
105 
106 	green_ap_info("Green AP creation successful, green ap ctx: %pK, pdev: %pK",
107 		      green_ap_ctx, pdev);
108 
109 	return QDF_STATUS_SUCCESS;
110 
111 err_pdev_attach:
112 	qdf_spinlock_destroy(&green_ap_ctx->lock);
113 	qdf_timer_free(&green_ap_ctx->ps_timer);
114 	qdf_mem_free(green_ap_ctx);
115 	return status;
116 }
117 
118 /**
119  * wlan_green_ap_pdev_obj_destroy_notification() - called from objmgr when
120  *                                                 pdev is destroyed
121  * @pdev: pdev context
122  * @arg: argument
123  *
124  * This function gets called from object manager when pdev is being destroyed
125  * and deletes green ap context and detach it from objmgr.
126  *
127  * Return: QDF_STATUS_SUCCESS - in case of success
128  */
129 static QDF_STATUS wlan_green_ap_pdev_obj_destroy_notification(
130 			struct wlan_objmgr_pdev *pdev, void *arg)
131 {
132 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
133 
134 	if (!pdev) {
135 		green_ap_err("pdev context passed is NULL");
136 		return QDF_STATUS_E_INVAL;
137 	}
138 
139 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
140 			pdev, WLAN_UMAC_COMP_GREEN_AP);
141 	if (!green_ap_ctx) {
142 		green_ap_err("green ap context is already NULL");
143 		return QDF_STATUS_E_FAILURE;
144 	}
145 
146 	green_ap_info("Deleting green ap pdev obj, green ap ctx: %pK, pdev: %pK",
147 		      green_ap_ctx, pdev);
148 
149 	if (wlan_objmgr_pdev_component_obj_detach(pdev,
150 				WLAN_UMAC_COMP_GREEN_AP, green_ap_ctx) !=
151 				QDF_STATUS_SUCCESS) {
152 		green_ap_err("Failed to detach green ap ctx in psoc ctx");
153 		return QDF_STATUS_E_FAILURE;
154 	}
155 
156 	qdf_timer_free(&green_ap_ctx->ps_timer);
157 	qdf_spinlock_destroy(&green_ap_ctx->lock);
158 
159 	qdf_mem_free(green_ap_ctx);
160 	green_ap_info("green ap deletion successful");
161 
162 	return QDF_STATUS_SUCCESS;
163 }
164 
165 QDF_STATUS wlan_green_ap_init(void)
166 {
167 	QDF_STATUS status = QDF_STATUS_SUCCESS;
168 
169 	status = wlan_objmgr_register_pdev_create_handler(
170 				WLAN_UMAC_COMP_GREEN_AP,
171 				wlan_green_ap_pdev_obj_create_notification,
172 				NULL);
173 	if (status != QDF_STATUS_SUCCESS) {
174 		green_ap_err("Failed to register green ap obj create handler");
175 		goto err_pdev_create;
176 	}
177 
178 	status = wlan_objmgr_register_pdev_destroy_handler(
179 				WLAN_UMAC_COMP_GREEN_AP,
180 				wlan_green_ap_pdev_obj_destroy_notification,
181 				NULL);
182 	if (status != QDF_STATUS_SUCCESS) {
183 		green_ap_err("Failed to register green ap obj destroy handler");
184 		goto err_pdev_delete;
185 	}
186 
187 	green_ap_info("Successfully registered create and destroy handlers with objmgr");
188 	return QDF_STATUS_SUCCESS;
189 
190 err_pdev_delete:
191 	wlan_objmgr_unregister_pdev_create_handler(
192 				WLAN_UMAC_COMP_GREEN_AP,
193 				wlan_green_ap_pdev_obj_create_notification,
194 				NULL);
195 err_pdev_create:
196 	return status;
197 }
198 
199 QDF_STATUS wlan_green_ap_deinit(void)
200 {
201 	if (wlan_objmgr_unregister_pdev_create_handler(
202 				WLAN_UMAC_COMP_GREEN_AP,
203 				wlan_green_ap_pdev_obj_create_notification,
204 				NULL)
205 			!= QDF_STATUS_SUCCESS) {
206 		return QDF_STATUS_E_FAILURE;
207 	}
208 
209 	if (wlan_objmgr_unregister_pdev_destroy_handler(
210 				WLAN_UMAC_COMP_GREEN_AP,
211 				wlan_green_ap_pdev_obj_destroy_notification,
212 				NULL)
213 			!= QDF_STATUS_SUCCESS) {
214 		return QDF_STATUS_E_FAILURE;
215 	}
216 
217 	green_ap_info("Successfully unregistered create and destroy handlers with objmgr");
218 	return QDF_STATUS_SUCCESS;
219 }
220 
221 QDF_STATUS wlan_green_ap_pdev_open(struct wlan_objmgr_pdev *pdev)
222 {
223 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
224 	struct wlan_objmgr_psoc *psoc;
225 
226 	if (!pdev) {
227 		green_ap_err("pdev is NULL");
228 		return QDF_STATUS_E_INVAL;
229 	}
230 
231 	psoc = wlan_pdev_get_psoc(pdev);
232 
233 	if (!psoc) {
234 		green_ap_err("psoc is NULL");
235 		return QDF_STATUS_E_INVAL;
236 	}
237 
238 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
239 			pdev, WLAN_UMAC_COMP_GREEN_AP);
240 	if (!green_ap_ctx) {
241 		green_ap_err("green ap context obtained is NULL");
242 		return QDF_STATUS_E_FAILURE;
243 	}
244 
245 	qdf_spin_lock_bh(&green_ap_ctx->lock);
246 	green_ap_ctx->ps_enable = cfg_get(psoc,
247 					CFG_ENABLE_GREEN_AP_FEATURE);
248 	green_ap_ctx->egap_params.host_enable_egap = cfg_get(psoc,
249 					CFG_ENABLE_EGAP_FEATURE);
250 	green_ap_ctx->egap_params.egap_inactivity_time = cfg_get(psoc,
251 					CFG_EGAP_INACT_TIME_FEATURE);
252 	green_ap_ctx->egap_params.egap_wait_time = cfg_get(psoc,
253 					CFG_EGAP_WAIT_TIME_FEATURE);
254 	green_ap_ctx->egap_params.egap_feature_flags = cfg_get(psoc,
255 					CFG_EGAP_FLAGS_FEATURE);
256 
257 	qdf_spin_unlock_bh(&green_ap_ctx->lock);
258 
259 	return QDF_STATUS_SUCCESS;
260 }
261 
262 QDF_STATUS wlan_green_ap_start(struct wlan_objmgr_pdev *pdev)
263 {
264 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
265 
266 	if (!pdev) {
267 		green_ap_err("pdev context passed is NULL");
268 		return QDF_STATUS_E_INVAL;
269 	}
270 
271 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
272 			pdev, WLAN_UMAC_COMP_GREEN_AP);
273 	if (!green_ap_ctx) {
274 		green_ap_err("green ap context obtained is NULL");
275 		return QDF_STATUS_E_FAILURE;
276 	}
277 
278 	green_ap_debug("Green AP start received");
279 
280 	/* Make sure the start function does not get called 2 times */
281 	qdf_spin_lock_bh(&green_ap_ctx->lock);
282 
283 	if (wlan_is_egap_enabled(green_ap_ctx)) {
284 		qdf_spin_unlock_bh(&green_ap_ctx->lock);
285 		green_ap_debug("enhanced green ap support is enabled");
286 		return QDF_STATUS_SUCCESS;
287 	}
288 
289 	if (green_ap_ctx->ps_state == WLAN_GREEN_AP_PS_IDLE_STATE) {
290 		if (green_ap_ctx->ps_enable) {
291 			qdf_spin_unlock_bh(&green_ap_ctx->lock);
292 			return wlan_green_ap_state_mc(green_ap_ctx,
293 					      WLAN_GREEN_AP_PS_START_EVENT);
294 		}
295 	}
296 
297 	qdf_spin_unlock_bh(&green_ap_ctx->lock);
298 	return QDF_STATUS_E_ALREADY;
299 }
300 
301 QDF_STATUS wlan_green_ap_stop(struct wlan_objmgr_pdev *pdev)
302 {
303 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
304 
305 	if (!pdev) {
306 		green_ap_err("pdev context passed is NULL");
307 		return QDF_STATUS_E_INVAL;
308 	}
309 
310 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
311 			pdev, WLAN_UMAC_COMP_GREEN_AP);
312 	if (!green_ap_ctx) {
313 		green_ap_err("green ap context obtained is NULL");
314 		return QDF_STATUS_E_FAILURE;
315 	}
316 
317 	green_ap_debug("Green AP stop received");
318 
319 	qdf_spin_lock_bh(&green_ap_ctx->lock);
320 	if (wlan_is_egap_enabled(green_ap_ctx)) {
321 		qdf_spin_unlock_bh(&green_ap_ctx->lock);
322 		green_ap_debug("enhanced green ap support is enabled");
323 		return QDF_STATUS_SUCCESS;
324 	}
325 
326 	/* Delete the timer just to be sure */
327 	qdf_timer_stop(&green_ap_ctx->ps_timer);
328 
329 	/* Disable the power save */
330 	green_ap_ctx->ps_enable = WLAN_GREEN_AP_PS_DISABLE;
331 
332 	qdf_spin_unlock_bh(&green_ap_ctx->lock);
333 	return wlan_green_ap_state_mc(green_ap_ctx,
334 				      WLAN_GREEN_AP_PS_STOP_EVENT);
335 }
336 
337 QDF_STATUS wlan_green_ap_add_sta(struct wlan_objmgr_pdev *pdev)
338 {
339 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
340 
341 	if (!pdev) {
342 		green_ap_err("pdev context passed is NULL");
343 		return QDF_STATUS_E_INVAL;
344 	}
345 
346 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
347 			pdev, WLAN_UMAC_COMP_GREEN_AP);
348 	if (!green_ap_ctx) {
349 		green_ap_err("green ap context obtained is NULL");
350 		return QDF_STATUS_E_FAILURE;
351 	}
352 
353 	green_ap_debug("Green AP add sta received");
354 
355 	qdf_spin_lock_bh(&green_ap_ctx->lock);
356 	if (wlan_is_egap_enabled(green_ap_ctx)) {
357 		qdf_spin_unlock_bh(&green_ap_ctx->lock);
358 		green_ap_debug("enhanced green ap support is enabled");
359 		return QDF_STATUS_SUCCESS;
360 	}
361 	qdf_spin_unlock_bh(&green_ap_ctx->lock);
362 
363 	return wlan_green_ap_state_mc(green_ap_ctx,
364 				      WLAN_GREEN_AP_ADD_STA_EVENT);
365 }
366 
367 QDF_STATUS wlan_green_ap_add_multistream_sta(struct wlan_objmgr_pdev *pdev)
368 {
369 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
370 
371 	if (!pdev) {
372 		green_ap_err("pdev context passed is NULL");
373 		return QDF_STATUS_E_INVAL;
374 	}
375 
376 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
377 			pdev, WLAN_UMAC_COMP_GREEN_AP);
378 	if (!green_ap_ctx) {
379 		green_ap_err("green ap context obtained is NULL");
380 		return QDF_STATUS_E_FAILURE;
381 	}
382 
383 	green_ap_debug("Green AP add multistream sta received");
384 
385 	qdf_spin_lock_bh(&green_ap_ctx->lock);
386 	if (wlan_is_egap_enabled(green_ap_ctx)) {
387 		qdf_spin_unlock_bh(&green_ap_ctx->lock);
388 		green_ap_debug("enhanced green ap support is enabled");
389 		return QDF_STATUS_SUCCESS;
390 	}
391 	qdf_spin_unlock_bh(&green_ap_ctx->lock);
392 
393 	return wlan_green_ap_state_mc(green_ap_ctx,
394 			WLAN_GREEN_AP_ADD_MULTISTREAM_STA_EVENT);
395 }
396 
397 QDF_STATUS wlan_green_ap_del_sta(struct wlan_objmgr_pdev *pdev)
398 {
399 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
400 
401 	if (!pdev) {
402 		green_ap_err("pdev context passed is NULL");
403 		return QDF_STATUS_E_INVAL;
404 	}
405 
406 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
407 			pdev, WLAN_UMAC_COMP_GREEN_AP);
408 	if (!green_ap_ctx) {
409 		green_ap_err("green ap context obtained is NULL");
410 		return QDF_STATUS_E_FAILURE;
411 	}
412 
413 	green_ap_debug("Green AP del sta received");
414 
415 	qdf_spin_lock_bh(&green_ap_ctx->lock);
416 	if (wlan_is_egap_enabled(green_ap_ctx)) {
417 		qdf_spin_unlock_bh(&green_ap_ctx->lock);
418 		green_ap_debug("enhanced green ap support is enabled");
419 		return QDF_STATUS_SUCCESS;
420 	}
421 	qdf_spin_unlock_bh(&green_ap_ctx->lock);
422 
423 	return wlan_green_ap_state_mc(green_ap_ctx,
424 				      WLAN_GREEN_AP_DEL_STA_EVENT);
425 }
426 
427 QDF_STATUS wlan_green_ap_del_multistream_sta(struct wlan_objmgr_pdev *pdev)
428 {
429 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
430 
431 	if (!pdev) {
432 		green_ap_err("pdev context passed is NULL");
433 		return QDF_STATUS_E_INVAL;
434 	}
435 
436 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
437 			pdev, WLAN_UMAC_COMP_GREEN_AP);
438 	if (!green_ap_ctx) {
439 		green_ap_err("green ap context obtained is NULL");
440 		return QDF_STATUS_E_FAILURE;
441 	}
442 
443 	green_ap_debug("Green AP del multistream sta received");
444 
445 	qdf_spin_lock_bh(&green_ap_ctx->lock);
446 	if (wlan_is_egap_enabled(green_ap_ctx)) {
447 		qdf_spin_unlock_bh(&green_ap_ctx->lock);
448 		green_ap_info("enhanced green ap support is enabled");
449 		return QDF_STATUS_SUCCESS;
450 	}
451 	qdf_spin_unlock_bh(&green_ap_ctx->lock);
452 
453 	return wlan_green_ap_state_mc(green_ap_ctx,
454 			WLAN_GREEN_AP_DEL_MULTISTREAM_STA_EVENT);
455 }
456 
457 bool wlan_green_ap_is_ps_enabled(struct wlan_objmgr_pdev *pdev)
458 {
459 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
460 
461 	if (!pdev) {
462 		green_ap_err("pdev context passed is NULL");
463 		return QDF_STATUS_E_INVAL;
464 	}
465 
466 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
467 			pdev, WLAN_UMAC_COMP_GREEN_AP);
468 	if (!green_ap_ctx) {
469 		green_ap_err("green ap context obtained is NULL");
470 		return QDF_STATUS_E_FAILURE;
471 	}
472 
473 	if ((green_ap_ctx->ps_state == WLAN_GREEN_AP_PS_ON_STATE) &&
474 			(green_ap_ctx->ps_enable))
475 		return true;
476 
477 	return false;
478 
479 }
480 
481 void wlan_green_ap_suspend_handle(struct wlan_objmgr_pdev *pdev)
482 {
483 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
484 
485 	if (!pdev) {
486 		green_ap_err("pdev context passed is NULL");
487 		return;
488 	}
489 
490 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
491 				pdev, WLAN_UMAC_COMP_GREEN_AP);
492 
493 	if (!green_ap_ctx) {
494 		green_ap_err("green ap context obtained is NULL");
495 		return;
496 	}
497 
498 	wlan_green_ap_stop(pdev);
499 
500 	green_ap_ctx->ps_enable = WLAN_GREEN_AP_PS_SUSPEND;
501 }
502 
503 bool wlan_green_ap_is_ps_waiting(struct wlan_objmgr_pdev *pdev)
504 {
505 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
506 
507 	if (!pdev) {
508 		green_ap_err("pdev context passed is NULL");
509 		return QDF_STATUS_E_INVAL;
510 	}
511 
512 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
513 			pdev, WLAN_UMAC_COMP_GREEN_AP);
514 	if (!green_ap_ctx) {
515 		green_ap_err("green ap context obtained is NULL");
516 		return QDF_STATUS_E_FAILURE;
517 	}
518 
519 	if ((green_ap_ctx->ps_state == WLAN_GREEN_AP_PS_WAIT_STATE) &&
520 	    (green_ap_ctx->ps_enable)) {
521 		return true;
522 	}
523 
524 	return false;
525 }
526