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