xref: /wlan-dirver/qca-wifi-host-cmn/umac/green_ap/dispatcher/src/wlan_green_ap_api.c (revision 3149adf58a329e17232a4c0e58d460d025edd55a)
1 /*
2  * Copyright (c) 2017-2018 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 
26 QDF_STATUS wlan_green_ap_get_capab(
27 			struct wlan_objmgr_pdev *pdev)
28 {
29 	struct wlan_lmac_if_green_ap_tx_ops *green_ap_tx_ops;
30 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
31 
32 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(pdev,
33 					WLAN_UMAC_COMP_GREEN_AP);
34 
35 	if (!green_ap_ctx) {
36 		green_ap_err("green ap context obtained is NULL");
37 		return QDF_STATUS_E_FAILURE;
38 	}
39 
40 
41 	green_ap_tx_ops = wlan_psoc_get_green_ap_tx_ops(green_ap_ctx);
42 	if (!green_ap_tx_ops) {
43 		green_ap_err("green ap tx ops obtained are NULL");
44 		return QDF_STATUS_E_EXISTS;
45 	}
46 
47 	if (green_ap_tx_ops->get_capab)
48 		return green_ap_tx_ops->get_capab(pdev);
49 
50 	return QDF_STATUS_SUCCESS;
51 }
52 
53 /**
54  * wlan_green_ap_pdev_obj_create_notification() - called from objmgr when pdev
55  *                                                is created
56  * @pdev: pdev context
57  * @arg: argument
58  *
59  * This function gets called from object manager when pdev is being created and
60  * creates green ap context and attach it to objmgr.
61  *
62  * Return: QDF_STATUS_SUCCESS - in case of success
63  */
64 static QDF_STATUS wlan_green_ap_pdev_obj_create_notification(
65 			struct wlan_objmgr_pdev *pdev, void *arg)
66 {
67 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
68 	QDF_STATUS status = QDF_STATUS_SUCCESS;
69 
70 	if (!pdev) {
71 		green_ap_err("pdev context passed is NULL");
72 		return QDF_STATUS_E_INVAL;
73 	}
74 
75 	green_ap_ctx = qdf_mem_malloc(sizeof(*green_ap_ctx));
76 	if (!green_ap_ctx) {
77 		green_ap_err("Memory allocation for Green AP context failed!");
78 		return QDF_STATUS_E_NOMEM;
79 	}
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->num_nodes = 0;
84 	green_ap_ctx->ps_on_time = WLAN_GREEN_AP_PS_ON_TIME;
85 	green_ap_ctx->ps_trans_time = WLAN_GREEN_AP_PS_TRANS_TIME;
86 
87 	green_ap_ctx->pdev = pdev;
88 
89 	qdf_timer_init(NULL, &green_ap_ctx->ps_timer,
90 		       wlan_green_ap_timer_fn,
91 		       pdev, QDF_TIMER_TYPE_WAKE_APPS);
92 
93 	qdf_spinlock_create(&green_ap_ctx->lock);
94 	if (wlan_objmgr_pdev_component_obj_attach(pdev,
95 				WLAN_UMAC_COMP_GREEN_AP,
96 				green_ap_ctx, QDF_STATUS_SUCCESS)
97 			!= QDF_STATUS_SUCCESS) {
98 		green_ap_err("Failed to attach green ap ctx in pdev ctx");
99 		status = QDF_STATUS_E_FAILURE;
100 		goto err_pdev_attach;
101 	}
102 
103 	green_ap_info("Green AP creation successful, green ap ctx: %pK, pdev: %pK",
104 		      green_ap_ctx, pdev);
105 
106 	return QDF_STATUS_SUCCESS;
107 
108 err_pdev_attach:
109 	qdf_spinlock_destroy(&green_ap_ctx->lock);
110 	qdf_timer_free(&green_ap_ctx->ps_timer);
111 	qdf_mem_free(green_ap_ctx);
112 	return status;
113 }
114 
115 /**
116  * wlan_green_ap_pdev_obj_destroy_notification() - called from objmgr when
117  *                                                 pdev is destroyed
118  * @pdev: pdev context
119  * @arg: argument
120  *
121  * This function gets called from object manager when pdev is being destroyed
122  * and deletes green ap context and detach it from objmgr.
123  *
124  * Return: QDF_STATUS_SUCCESS - in case of success
125  */
126 static QDF_STATUS wlan_green_ap_pdev_obj_destroy_notification(
127 			struct wlan_objmgr_pdev *pdev, void *arg)
128 {
129 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
130 
131 	if (!pdev) {
132 		green_ap_err("pdev context passed is NULL");
133 		return QDF_STATUS_E_INVAL;
134 	}
135 
136 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
137 			pdev, WLAN_UMAC_COMP_GREEN_AP);
138 	if (!green_ap_ctx) {
139 		green_ap_err("green ap context is already NULL");
140 		return QDF_STATUS_E_FAILURE;
141 	}
142 
143 	green_ap_info("Deleting green ap pdev obj, green ap ctx: %pK, pdev: %pK",
144 		      green_ap_ctx, pdev);
145 
146 	if (wlan_objmgr_pdev_component_obj_detach(pdev,
147 				WLAN_UMAC_COMP_GREEN_AP, green_ap_ctx) !=
148 				QDF_STATUS_SUCCESS) {
149 		green_ap_err("Failed to detach green ap ctx in psoc ctx");
150 		return QDF_STATUS_E_FAILURE;
151 	}
152 
153 	qdf_timer_free(&green_ap_ctx->ps_timer);
154 	qdf_spinlock_destroy(&green_ap_ctx->lock);
155 
156 	qdf_mem_free(green_ap_ctx);
157 	green_ap_info("green ap deletion successful, pdev: %pK", pdev);
158 
159 	return QDF_STATUS_SUCCESS;
160 }
161 
162 QDF_STATUS wlan_green_ap_init(void)
163 {
164 	QDF_STATUS status = QDF_STATUS_SUCCESS;
165 
166 	status = wlan_objmgr_register_pdev_create_handler(
167 				WLAN_UMAC_COMP_GREEN_AP,
168 				wlan_green_ap_pdev_obj_create_notification,
169 				NULL);
170 	if (status != QDF_STATUS_SUCCESS) {
171 		green_ap_err("Failed to register green ap obj create handler");
172 		goto err_pdev_create;
173 	}
174 
175 	status = wlan_objmgr_register_pdev_destroy_handler(
176 				WLAN_UMAC_COMP_GREEN_AP,
177 				wlan_green_ap_pdev_obj_destroy_notification,
178 				NULL);
179 	if (status != QDF_STATUS_SUCCESS) {
180 		green_ap_err("Failed to register green ap obj destroy handler");
181 		goto err_pdev_delete;
182 	}
183 
184 	green_ap_info("Successfully registered create and destroy handlers with objmgr");
185 	return QDF_STATUS_SUCCESS;
186 
187 err_pdev_delete:
188 	wlan_objmgr_unregister_pdev_create_handler(
189 				WLAN_UMAC_COMP_GREEN_AP,
190 				wlan_green_ap_pdev_obj_create_notification,
191 				NULL);
192 err_pdev_create:
193 	return status;
194 }
195 
196 QDF_STATUS wlan_green_ap_deinit(void)
197 {
198 	if (wlan_objmgr_unregister_pdev_create_handler(
199 				WLAN_UMAC_COMP_GREEN_AP,
200 				wlan_green_ap_pdev_obj_create_notification,
201 				NULL)
202 			!= QDF_STATUS_SUCCESS) {
203 		return QDF_STATUS_E_FAILURE;
204 	}
205 
206 	if (wlan_objmgr_unregister_pdev_destroy_handler(
207 				WLAN_UMAC_COMP_GREEN_AP,
208 				wlan_green_ap_pdev_obj_destroy_notification,
209 				NULL)
210 			!= QDF_STATUS_SUCCESS) {
211 		return QDF_STATUS_E_FAILURE;
212 	}
213 
214 	green_ap_info("Successfully unregistered create and destroy handlers with objmgr");
215 	return QDF_STATUS_SUCCESS;
216 }
217 
218 QDF_STATUS wlan_green_ap_start(struct wlan_objmgr_pdev *pdev)
219 {
220 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
221 
222 	if (!pdev) {
223 		green_ap_err("pdev context passed is NULL");
224 		return QDF_STATUS_E_INVAL;
225 	}
226 
227 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
228 			pdev, WLAN_UMAC_COMP_GREEN_AP);
229 	if (!green_ap_ctx) {
230 		green_ap_err("green ap context obtained is NULL");
231 		return QDF_STATUS_E_FAILURE;
232 	}
233 
234 	green_ap_debug("Green AP start received");
235 
236 	/* Make sure the start function does not get called 2 times */
237 	qdf_spin_lock_bh(&green_ap_ctx->lock);
238 
239 	if (wlan_is_egap_enabled(green_ap_ctx)) {
240 		qdf_spin_unlock_bh(&green_ap_ctx->lock);
241 		green_ap_debug("enhanced green ap support is enabled");
242 		return QDF_STATUS_SUCCESS;
243 	}
244 
245 	if (green_ap_ctx->ps_state == WLAN_GREEN_AP_PS_IDLE_STATE) {
246 		if (green_ap_ctx->ps_enable) {
247 			qdf_spin_unlock_bh(&green_ap_ctx->lock);
248 			return wlan_green_ap_state_mc(green_ap_ctx,
249 					      WLAN_GREEN_AP_PS_START_EVENT);
250 		}
251 	}
252 
253 	qdf_spin_unlock_bh(&green_ap_ctx->lock);
254 	return QDF_STATUS_E_ALREADY;
255 }
256 
257 QDF_STATUS wlan_green_ap_stop(struct wlan_objmgr_pdev *pdev)
258 {
259 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
260 
261 	if (!pdev) {
262 		green_ap_err("pdev context passed is NULL");
263 		return QDF_STATUS_E_INVAL;
264 	}
265 
266 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
267 			pdev, WLAN_UMAC_COMP_GREEN_AP);
268 	if (!green_ap_ctx) {
269 		green_ap_err("green ap context obtained is NULL");
270 		return QDF_STATUS_E_FAILURE;
271 	}
272 
273 	green_ap_debug("Green AP stop received");
274 
275 	qdf_spin_lock_bh(&green_ap_ctx->lock);
276 	if (wlan_is_egap_enabled(green_ap_ctx)) {
277 		qdf_spin_unlock_bh(&green_ap_ctx->lock);
278 		green_ap_debug("enhanced green ap support is enabled");
279 		return QDF_STATUS_SUCCESS;
280 	}
281 
282 	/* Delete the timer just to be sure */
283 	qdf_timer_stop(&green_ap_ctx->ps_timer);
284 
285 	/* Disable the power save */
286 	green_ap_ctx->ps_enable = WLAN_GREEN_AP_PS_DISABLE;
287 
288 	qdf_spin_unlock_bh(&green_ap_ctx->lock);
289 	return wlan_green_ap_state_mc(green_ap_ctx,
290 				      WLAN_GREEN_AP_PS_STOP_EVENT);
291 }
292 
293 QDF_STATUS wlan_green_ap_add_sta(struct wlan_objmgr_pdev *pdev)
294 {
295 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
296 
297 	if (!pdev) {
298 		green_ap_err("pdev context passed is NULL");
299 		return QDF_STATUS_E_INVAL;
300 	}
301 
302 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
303 			pdev, WLAN_UMAC_COMP_GREEN_AP);
304 	if (!green_ap_ctx) {
305 		green_ap_err("green ap context obtained is NULL");
306 		return QDF_STATUS_E_FAILURE;
307 	}
308 
309 	green_ap_debug("Green AP add sta received");
310 
311 	qdf_spin_lock_bh(&green_ap_ctx->lock);
312 	if (wlan_is_egap_enabled(green_ap_ctx)) {
313 		qdf_spin_unlock_bh(&green_ap_ctx->lock);
314 		green_ap_debug("enhanced green ap support is enabled");
315 		return QDF_STATUS_SUCCESS;
316 	}
317 	qdf_spin_unlock_bh(&green_ap_ctx->lock);
318 
319 	return wlan_green_ap_state_mc(green_ap_ctx,
320 				      WLAN_GREEN_AP_ADD_STA_EVENT);
321 }
322 
323 QDF_STATUS wlan_green_ap_del_sta(struct wlan_objmgr_pdev *pdev)
324 {
325 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
326 
327 	if (!pdev) {
328 		green_ap_err("pdev context passed is NULL");
329 		return QDF_STATUS_E_INVAL;
330 	}
331 
332 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
333 			pdev, WLAN_UMAC_COMP_GREEN_AP);
334 	if (!green_ap_ctx) {
335 		green_ap_err("green ap context obtained is NULL");
336 		return QDF_STATUS_E_FAILURE;
337 	}
338 
339 	green_ap_debug("Green AP del sta received");
340 
341 	qdf_spin_lock_bh(&green_ap_ctx->lock);
342 	if (wlan_is_egap_enabled(green_ap_ctx)) {
343 		qdf_spin_unlock_bh(&green_ap_ctx->lock);
344 		green_ap_info("enhanced green ap support is enabled");
345 		return QDF_STATUS_SUCCESS;
346 	}
347 	qdf_spin_unlock_bh(&green_ap_ctx->lock);
348 
349 	return wlan_green_ap_state_mc(green_ap_ctx,
350 				      WLAN_GREEN_AP_DEL_STA_EVENT);
351 }
352 
353 bool wlan_green_ap_is_ps_enabled(struct wlan_objmgr_pdev *pdev)
354 {
355 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
356 
357 	if (!pdev) {
358 		green_ap_err("pdev context passed is NULL");
359 		return QDF_STATUS_E_INVAL;
360 	}
361 
362 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
363 			pdev, WLAN_UMAC_COMP_GREEN_AP);
364 	if (!green_ap_ctx) {
365 		green_ap_err("green ap context obtained is NULL");
366 		return QDF_STATUS_E_FAILURE;
367 	}
368 
369 	if ((green_ap_ctx->ps_state == WLAN_GREEN_AP_PS_ON_STATE) &&
370 			(green_ap_ctx->ps_enable))
371 		return true;
372 
373 	return false;
374 
375 }
376 
377 void wlan_green_ap_suspend_handle(struct wlan_objmgr_pdev *pdev)
378 {
379 	struct wlan_pdev_green_ap_ctx *green_ap_ctx;
380 
381 	if (!pdev) {
382 		green_ap_err("pdev context passed is NULL");
383 		return;
384 	}
385 
386 	green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj(
387 				pdev, WLAN_UMAC_COMP_GREEN_AP);
388 
389 	if (!green_ap_ctx) {
390 		green_ap_err("green ap context obtained is NULL");
391 		return;
392 	}
393 
394 	wlan_green_ap_stop(pdev);
395 
396 	green_ap_ctx->ps_enable = WLAN_GREEN_AP_PS_SUSPEND;
397 }
398