1 /*
2  * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2023-2024 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  * DOC: define utility API related to the pmo component
21  * called by other components
22  */
23 
24 #include "wlan_pmo_obj_mgmt_api.h"
25 #include "wlan_pmo_tgt_api.h"
26 #include "wlan_pmo_static_config.h"
27 #include "wlan_pmo_main.h"
28 #include "target_if_pmo.h"
29 
pmo_init(void)30 QDF_STATUS pmo_init(void)
31 {
32 	QDF_STATUS status;
33 	struct wlan_pmo_ctx *pmo_ctx;
34 
35 	pmo_enter();
36 	if (pmo_allocate_ctx() != QDF_STATUS_SUCCESS) {
37 		pmo_err("unable to allocate psoc ctx");
38 		status = QDF_STATUS_E_FAULT;
39 		goto out;
40 	}
41 
42 	pmo_ctx = pmo_get_context();
43 	if (!pmo_ctx) {
44 		pmo_err("unable to get pmo ctx");
45 		status = QDF_STATUS_E_INVAL;
46 		goto out;
47 	}
48 
49 	status = wlan_objmgr_register_psoc_create_handler(
50 			WLAN_UMAC_COMP_PMO,
51 			pmo_psoc_object_created_notification,
52 			(void *)pmo_ctx);
53 	if (status != QDF_STATUS_SUCCESS) {
54 		pmo_err("unable to register psoc create handle");
55 		goto out;
56 	}
57 
58 	status = wlan_objmgr_register_psoc_destroy_handler(
59 			WLAN_UMAC_COMP_PMO,
60 			 pmo_psoc_object_destroyed_notification,
61 			(void *)pmo_ctx);
62 	if (status != QDF_STATUS_SUCCESS) {
63 		pmo_err("unable to register psoc create handle");
64 		goto out;
65 	}
66 
67 	status = wlan_objmgr_register_vdev_create_handler(
68 			WLAN_UMAC_COMP_PMO,
69 			pmo_vdev_object_created_notification,
70 			(void *)pmo_ctx);
71 	if (status != QDF_STATUS_SUCCESS) {
72 		pmo_err("unable to register vdev create handle");
73 		goto out;
74 	}
75 
76 	status = wlan_objmgr_register_vdev_destroy_handler(
77 			WLAN_UMAC_COMP_PMO,
78 			pmo_vdev_object_destroyed_notification,
79 			(void *)pmo_ctx);
80 	if (status != QDF_STATUS_SUCCESS)
81 		pmo_err("unable to register vdev create handle");
82 out:
83 	pmo_exit();
84 
85 	return status;
86 }
87 
pmo_deinit(void)88 QDF_STATUS pmo_deinit(void)
89 {
90 	QDF_STATUS status;
91 	struct wlan_pmo_ctx *pmo_ctx;
92 
93 	pmo_enter();
94 	pmo_ctx = pmo_get_context();
95 	if (!pmo_ctx) {
96 		pmo_err("unable to get pmo ctx");
97 		status =  QDF_STATUS_E_FAILURE;
98 		goto out;
99 	}
100 
101 	status = wlan_objmgr_unregister_psoc_create_handler(
102 			WLAN_UMAC_COMP_PMO,
103 			pmo_psoc_object_created_notification,
104 			(void *)pmo_ctx);
105 	if (status != QDF_STATUS_SUCCESS) {
106 		pmo_err("unable to unregister psoc create handle");
107 		goto out;
108 	}
109 
110 	status = wlan_objmgr_unregister_psoc_destroy_handler(
111 			WLAN_UMAC_COMP_PMO,
112 			 pmo_psoc_object_destroyed_notification,
113 			(void *)pmo_ctx);
114 	if (status != QDF_STATUS_SUCCESS) {
115 		pmo_err("unable to unregister psoc create handle");
116 		goto out;
117 	}
118 
119 	status = wlan_objmgr_unregister_vdev_create_handler(
120 			WLAN_UMAC_COMP_PMO,
121 			pmo_vdev_object_created_notification,
122 			(void *)pmo_ctx);
123 	if (status != QDF_STATUS_SUCCESS) {
124 		pmo_err("unable to unregister vdev create handle");
125 		goto out;
126 	}
127 
128 	status = wlan_objmgr_unregister_vdev_destroy_handler(
129 			WLAN_UMAC_COMP_PMO,
130 			pmo_vdev_object_destroyed_notification,
131 			(void *)pmo_ctx);
132 	if (status != QDF_STATUS_SUCCESS) {
133 		pmo_err("unable to unregister vdev create handle");
134 		goto out;
135 	}
136 
137 out:
138 	pmo_free_ctx();
139 	pmo_exit();
140 
141 	return status;
142 }
143 
pmo_psoc_object_created_notification(struct wlan_objmgr_psoc * psoc,void * arg)144 QDF_STATUS pmo_psoc_object_created_notification(
145 		struct wlan_objmgr_psoc *psoc, void *arg)
146 {
147 	struct pmo_psoc_priv_obj *psoc_ctx = NULL;
148 	QDF_STATUS status;
149 	struct wlan_pmo_ctx *pmo_ctx;
150 
151 	pmo_enter();
152 	pmo_ctx = pmo_get_context();
153 	if (!pmo_ctx) {
154 		QDF_ASSERT(0);
155 		pmo_err("unable to get pmo ctx");
156 		status = QDF_STATUS_E_FAILURE;
157 		goto out;
158 	}
159 
160 	psoc_ctx = qdf_mem_malloc(sizeof(*psoc_ctx));
161 	if (!psoc_ctx) {
162 		status = QDF_STATUS_E_NOMEM;
163 		goto out;
164 	}
165 
166 	status = wlan_objmgr_psoc_component_obj_attach(psoc,
167 			WLAN_UMAC_COMP_PMO,
168 			psoc_ctx,
169 			QDF_STATUS_SUCCESS);
170 	if (status != QDF_STATUS_SUCCESS) {
171 		pmo_err("Failed to attach psoc_ctx with psoc");
172 		qdf_mem_free(psoc_ctx);
173 		status = QDF_STATUS_E_FAILURE;
174 		goto out;
175 	}
176 	qdf_spinlock_create(&psoc_ctx->lock);
177 	qdf_wake_lock_create(&psoc_ctx->wow.wow_wake_lock, "pmo_wow_wl");
178 	status = qdf_event_create(&psoc_ctx->wow.target_suspend);
179 	if (status != QDF_STATUS_SUCCESS) {
180 		pmo_err("target suspend event initialization failed");
181 		status = QDF_STATUS_E_FAILURE;
182 		goto out;
183 	}
184 	status = qdf_event_create(&psoc_ctx->wow.target_resume);
185 	if (status != QDF_STATUS_SUCCESS) {
186 		pmo_err("target resume event initialization failed");
187 		status = QDF_STATUS_E_FAILURE;
188 		goto out;
189 	}
190 
191 	qdf_atomic_init(&psoc_ctx->wow.wow_initial_wake_up);
192 	/* Register PMO tx ops*/
193 	target_if_pmo_register_tx_ops(&psoc_ctx->pmo_tx_ops);
194 out:
195 	pmo_exit();
196 
197 	return status;
198 }
199 
pmo_psoc_object_destroyed_notification(struct wlan_objmgr_psoc * psoc,void * arg)200 QDF_STATUS pmo_psoc_object_destroyed_notification(
201 		struct wlan_objmgr_psoc *psoc, void *arg)
202 {
203 	struct pmo_psoc_priv_obj *psoc_ctx = NULL;
204 	QDF_STATUS status;
205 
206 	pmo_enter();
207 
208 	psoc_ctx = pmo_psoc_get_priv(psoc);
209 
210 	status = wlan_objmgr_psoc_component_obj_detach(psoc,
211 			WLAN_UMAC_COMP_PMO,
212 			psoc_ctx);
213 	if (status != QDF_STATUS_SUCCESS) {
214 		pmo_err("Failed to detach psoc_ctx from psoc");
215 		status = QDF_STATUS_E_FAILURE;
216 		goto out;
217 	}
218 
219 	qdf_spinlock_destroy(&psoc_ctx->lock);
220 	qdf_event_destroy(&psoc_ctx->wow.target_suspend);
221 	qdf_event_destroy(&psoc_ctx->wow.target_resume);
222 	qdf_wake_lock_destroy(&psoc_ctx->wow.wow_wake_lock);
223 	qdf_mem_zero(psoc_ctx, sizeof(*psoc_ctx));
224 	qdf_mem_free(psoc_ctx);
225 out:
226 	pmo_exit();
227 
228 	return status;
229 }
230 
231 #ifdef FEATURE_WLAN_DYNAMIC_ARP_NS_OFFLOAD
232 static inline void
pmo_vdev_dynamic_arp_ns_offload_init(struct pmo_vdev_priv_obj * vdev_ctx)233 pmo_vdev_dynamic_arp_ns_offload_init(struct pmo_vdev_priv_obj *vdev_ctx)
234 {
235 	qdf_runtime_lock_init(&vdev_ctx->dyn_arp_ns_offload_rt_lock);
236 }
237 
238 static inline void
pmo_vdev_dynamic_arp_ns_offload_deinit(struct pmo_vdev_priv_obj * vdev_ctx)239 pmo_vdev_dynamic_arp_ns_offload_deinit(struct pmo_vdev_priv_obj *vdev_ctx)
240 {
241 	qdf_runtime_lock_deinit(&vdev_ctx->dyn_arp_ns_offload_rt_lock);
242 }
243 #else
244 static inline void
pmo_vdev_dynamic_arp_ns_offload_init(struct pmo_vdev_priv_obj * vdev_ctx)245 pmo_vdev_dynamic_arp_ns_offload_init(struct pmo_vdev_priv_obj *vdev_ctx) {}
246 
247 static inline void
pmo_vdev_dynamic_arp_ns_offload_deinit(struct pmo_vdev_priv_obj * vdev_ctx)248 pmo_vdev_dynamic_arp_ns_offload_deinit(struct pmo_vdev_priv_obj *vdev_ctx) {}
249 #endif
250 
pmo_vdev_object_created_notification(struct wlan_objmgr_vdev * vdev,void * arg)251 QDF_STATUS pmo_vdev_object_created_notification(
252 		struct wlan_objmgr_vdev *vdev, void *arg)
253 {
254 	struct pmo_psoc_priv_obj *psoc_ctx = NULL;
255 	struct wlan_objmgr_psoc *psoc;
256 	struct pmo_vdev_priv_obj *vdev_ctx;
257 	QDF_STATUS status;
258 
259 	pmo_enter();
260 
261 	psoc = pmo_vdev_get_psoc(vdev);
262 
263 	psoc_ctx = pmo_psoc_get_priv(psoc);
264 
265 	vdev_ctx = qdf_mem_malloc(sizeof(*vdev_ctx));
266 	if (!vdev_ctx) {
267 		status = QDF_STATUS_E_NOMEM;
268 		goto out;
269 	}
270 
271 	status = wlan_objmgr_vdev_component_obj_attach(vdev,
272 			 WLAN_UMAC_COMP_PMO,
273 			(void *)vdev_ctx, QDF_STATUS_SUCCESS);
274 	if (status != QDF_STATUS_SUCCESS) {
275 		pmo_err("Failed to attach vdev_ctx with vdev");
276 		qdf_mem_free(vdev_ctx);
277 		goto out;
278 	}
279 
280 	qdf_spinlock_create(&vdev_ctx->pmo_vdev_lock);
281 	vdev_ctx->magic_ptrn_enable =
282 		psoc_ctx->psoc_cfg.magic_ptrn_enable;
283 	vdev_ctx->ptrn_match_enable =
284 		psoc_ctx->psoc_cfg.ptrn_match_enable_all_vdev;
285 	vdev_ctx->pmo_psoc_ctx = psoc_ctx;
286 	qdf_atomic_init(&vdev_ctx->gtk_err_enable);
287 	pmo_vdev_dynamic_arp_ns_offload_init(vdev_ctx);
288 	/*
289 	 * Update Powersave mode
290 	 * 0 - PMO_PS_ADVANCED_POWER_SAVE_DISABLE
291 	 * 1 - PMO_PS_ADVANCED_POWER_SAVE_ENABLE
292 	 * 2 - PMO_PS_ADVANCED_POWER_SAVE_USER_DEFINED
293 	 */
294 	vdev_ctx->ps_params.opm_mode = psoc_ctx->psoc_cfg.power_save_mode;
295 	vdev_ctx->ps_params.ps_ito = PMO_PS_DATA_INACTIVITY_TIMEOUT;
296 	vdev_ctx->ps_params.spec_wake = PMO_PS_DATA_SPEC_WAKE;
297 
298 out:
299 	pmo_exit();
300 
301 	return QDF_STATUS_SUCCESS;
302 }
303 
pmo_vdev_ready(struct wlan_objmgr_vdev * vdev,struct qdf_mac_addr * bridgeaddr)304 QDF_STATUS pmo_vdev_ready(struct wlan_objmgr_vdev *vdev,
305 			  struct qdf_mac_addr *bridgeaddr)
306 {
307 	QDF_STATUS status;
308 
309 	status = pmo_vdev_get_ref(vdev);
310 	if (QDF_IS_STATUS_ERROR(status))
311 		return status;
312 
313 	/* Set Bridge MAC address */
314 	pmo_set_vdev_bridge_addr(vdev, bridgeaddr);
315 
316 	/* Register static configuration with firmware */
317 	pmo_register_wow_wakeup_events(vdev);
318 
319 	/* Register default wow patterns with firmware */
320 	pmo_register_wow_default_patterns(vdev);
321 
322 	wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
323 
324 	/*
325 	 * The above APIs should return a status but don't.
326 	 * Just return success for now.
327 	 */
328 	return QDF_STATUS_SUCCESS;
329 }
330 
pmo_vdev_object_destroyed_notification(struct wlan_objmgr_vdev * vdev,void * arg)331 QDF_STATUS pmo_vdev_object_destroyed_notification(
332 		struct wlan_objmgr_vdev *vdev, void *arg)
333 {
334 	struct pmo_vdev_priv_obj *vdev_ctx = NULL;
335 	QDF_STATUS status = QDF_STATUS_SUCCESS;
336 
337 	vdev_ctx = pmo_vdev_get_priv(vdev);
338 
339 	status = wlan_objmgr_vdev_component_obj_detach(vdev,
340 			 WLAN_UMAC_COMP_PMO,
341 			(void *)vdev_ctx);
342 	if (status != QDF_STATUS_SUCCESS)
343 		pmo_err("Failed to detach vdev_ctx with vdev");
344 
345 	qdf_spinlock_destroy(&vdev_ctx->pmo_vdev_lock);
346 	pmo_vdev_dynamic_arp_ns_offload_deinit(vdev_ctx);
347 	qdf_mem_free(vdev_ctx);
348 
349 	return status;
350 }
351 
pmo_register_suspend_handler(enum wlan_umac_comp_id id,pmo_psoc_suspend_handler handler,void * arg)352 QDF_STATUS pmo_register_suspend_handler(
353 		enum wlan_umac_comp_id id,
354 		pmo_psoc_suspend_handler handler,
355 		void *arg)
356 {
357 	struct wlan_pmo_ctx *pmo_ctx;
358 	QDF_STATUS status = QDF_STATUS_SUCCESS;
359 
360 	pmo_enter();
361 	pmo_ctx = pmo_get_context();
362 	if (!pmo_ctx) {
363 		QDF_ASSERT(0);
364 		pmo_err("unable to get pmo ctx");
365 		status = QDF_STATUS_E_FAILURE;
366 		goto out;
367 	}
368 
369 	if (id < 0 || id >= WLAN_UMAC_MAX_COMPONENTS) {
370 		pmo_err("component id: %d is %s then valid components id",
371 			id, id < 0 ? "Less" : "More");
372 		status = QDF_STATUS_E_FAILURE;
373 		goto out;
374 	}
375 
376 	qdf_spin_lock_bh(&pmo_ctx->lock);
377 	pmo_ctx->pmo_suspend_handler[id] = handler;
378 	pmo_ctx->pmo_suspend_handler_arg[id] = arg;
379 	qdf_spin_unlock_bh(&pmo_ctx->lock);
380 out:
381 	pmo_exit();
382 
383 	return status;
384 }
385 
pmo_unregister_suspend_handler(enum wlan_umac_comp_id id,pmo_psoc_suspend_handler handler)386 QDF_STATUS pmo_unregister_suspend_handler(
387 		enum wlan_umac_comp_id id,
388 		pmo_psoc_suspend_handler handler)
389 {
390 	struct wlan_pmo_ctx *pmo_ctx;
391 	QDF_STATUS status = QDF_STATUS_SUCCESS;
392 
393 	pmo_enter();
394 	pmo_ctx = pmo_get_context();
395 	if (!pmo_ctx) {
396 		QDF_ASSERT(0);
397 		pmo_err("unable to get pmo ctx");
398 		status = QDF_STATUS_E_FAILURE;
399 		goto out;
400 	}
401 
402 	if (id < 0 || id >= WLAN_UMAC_MAX_COMPONENTS) {
403 		pmo_err("component id: %d is %s then valid components id",
404 			id, id < 0 ? "Less" : "More");
405 		status = QDF_STATUS_E_FAILURE;
406 		goto out;
407 	}
408 
409 	qdf_spin_lock_bh(&pmo_ctx->lock);
410 	if (pmo_ctx->pmo_suspend_handler[id] == handler) {
411 		pmo_ctx->pmo_suspend_handler[id] = NULL;
412 		pmo_ctx->pmo_suspend_handler_arg[id] = NULL;
413 		qdf_spin_unlock_bh(&pmo_ctx->lock);
414 	} else {
415 		qdf_spin_unlock_bh(&pmo_ctx->lock);
416 		pmo_err("can't find suspend handler for component id: %d ", id);
417 		status = QDF_STATUS_E_FAILURE;
418 	}
419 out:
420 	pmo_exit();
421 
422 	return status;
423 }
424 
pmo_register_resume_handler(enum wlan_umac_comp_id id,pmo_psoc_resume_handler handler,void * arg)425 QDF_STATUS pmo_register_resume_handler(
426 		enum wlan_umac_comp_id id,
427 		pmo_psoc_resume_handler handler,
428 		void *arg)
429 {
430 	struct wlan_pmo_ctx *pmo_ctx;
431 	QDF_STATUS status = QDF_STATUS_SUCCESS;
432 
433 	pmo_enter();
434 	pmo_ctx = pmo_get_context();
435 	if (!pmo_ctx) {
436 		pmo_err("unable to get pmo ctx");
437 		status = QDF_STATUS_E_FAILURE;
438 		goto out;
439 	}
440 
441 	if (id < 0 || id >= WLAN_UMAC_MAX_COMPONENTS) {
442 		pmo_err("component id: %d is %s then valid components id",
443 			id, id < 0 ? "Less" : "More");
444 		status = QDF_STATUS_E_FAILURE;
445 		goto out;
446 	}
447 
448 	qdf_spin_lock_bh(&pmo_ctx->lock);
449 	pmo_ctx->pmo_resume_handler[id] = handler;
450 	pmo_ctx->pmo_resume_handler_arg[id] = arg;
451 	qdf_spin_unlock_bh(&pmo_ctx->lock);
452 out:
453 	pmo_exit();
454 
455 	return status;
456 }
457 
pmo_unregister_resume_handler(enum wlan_umac_comp_id id,pmo_psoc_resume_handler handler)458 QDF_STATUS pmo_unregister_resume_handler(
459 		enum wlan_umac_comp_id id,
460 		pmo_psoc_resume_handler handler)
461 {
462 	struct wlan_pmo_ctx *pmo_ctx;
463 	QDF_STATUS status = QDF_STATUS_SUCCESS;
464 
465 	pmo_enter();
466 	pmo_ctx = pmo_get_context();
467 	if (!pmo_ctx) {
468 		pmo_err("unable to get pmo ctx");
469 		status = QDF_STATUS_E_FAILURE;
470 		goto out;
471 	}
472 
473 	if (id < 0 || id >= WLAN_UMAC_MAX_COMPONENTS) {
474 		pmo_err("component id: %d is %s then valid components id",
475 			id, id < 0 ? "Less" : "More");
476 		status = QDF_STATUS_E_FAILURE;
477 		goto out;
478 	}
479 
480 	qdf_spin_lock_bh(&pmo_ctx->lock);
481 	if (pmo_ctx->pmo_resume_handler[id] == handler) {
482 		pmo_ctx->pmo_resume_handler[id] = NULL;
483 		pmo_ctx->pmo_resume_handler_arg[id] = NULL;
484 		qdf_spin_unlock_bh(&pmo_ctx->lock);
485 	} else {
486 		qdf_spin_unlock_bh(&pmo_ctx->lock);
487 		pmo_err("can't find resume handler for component id: %d ", id);
488 		status = QDF_STATUS_E_FAILURE;
489 	}
490 out:
491 	pmo_exit();
492 
493 	return status;
494 }
495 
pmo_suspend_all_components(struct wlan_objmgr_psoc * psoc,enum qdf_suspend_type suspend_type)496 QDF_STATUS pmo_suspend_all_components(struct wlan_objmgr_psoc *psoc,
497 				      enum qdf_suspend_type suspend_type)
498 {
499 	QDF_STATUS status = QDF_STATUS_SUCCESS;
500 	QDF_STATUS resume_status;
501 	struct wlan_pmo_ctx *pmo_ctx;
502 	int i;
503 	pmo_psoc_suspend_handler handler;
504 	void *arg;
505 
506 	pmo_ctx = pmo_get_context();
507 	if (!pmo_ctx) {
508 		pmo_err("unable to get pmo ctx");
509 		status = QDF_STATUS_E_FAILURE;
510 		goto exit_with_status;
511 	}
512 
513 	/* call each component's suspend handler */
514 	for (i = 0; i < WLAN_UMAC_MAX_COMPONENTS; i++) {
515 		qdf_spin_lock_bh(&pmo_ctx->lock);
516 		handler = pmo_ctx->pmo_suspend_handler[i];
517 		arg = pmo_ctx->pmo_suspend_handler_arg[i];
518 		qdf_spin_unlock_bh(&pmo_ctx->lock);
519 
520 		if (!handler)
521 			continue;
522 
523 		status = handler(psoc, arg);
524 		if (QDF_IS_STATUS_ERROR(status)) {
525 			pmo_err("component %d failed to suspend; status: %d",
526 				i, status);
527 			goto suspend_recovery;
528 		}
529 	}
530 
531 	goto exit_with_status;
532 
533 suspend_recovery:
534 	/* resume, starting with the last successfully suspended component */
535 	for (i -= 1; i >= 0; i--) {
536 		qdf_spin_lock_bh(&pmo_ctx->lock);
537 		handler = pmo_ctx->pmo_resume_handler[i];
538 		arg = pmo_ctx->pmo_resume_handler_arg[i];
539 		qdf_spin_unlock_bh(&pmo_ctx->lock);
540 
541 		if (!handler)
542 			continue;
543 
544 		resume_status = handler(psoc, arg);
545 		if (QDF_IS_STATUS_ERROR(resume_status))
546 			QDF_DEBUG_PANIC("component %d failed resume; status:%d",
547 					i, resume_status);
548 	}
549 
550 exit_with_status:
551 	return status;
552 }
553 
pmo_resume_all_components(struct wlan_objmgr_psoc * psoc,enum qdf_suspend_type suspend_type)554 QDF_STATUS pmo_resume_all_components(struct wlan_objmgr_psoc *psoc,
555 				     enum qdf_suspend_type suspend_type)
556 {
557 	QDF_STATUS status = QDF_STATUS_SUCCESS;
558 	struct wlan_pmo_ctx *pmo_ctx;
559 	uint8_t i;
560 	pmo_psoc_suspend_handler handler;
561 	void *arg;
562 
563 	pmo_ctx = pmo_get_context();
564 	if (!pmo_ctx) {
565 		pmo_err("unable to get pmo ctx");
566 		QDF_ASSERT(0);
567 		status = QDF_STATUS_E_FAILURE;
568 		goto exit_with_status;
569 	}
570 
571 	/* call each component's resume handler */
572 	for (i = 0; i < WLAN_UMAC_MAX_COMPONENTS; i++) {
573 		qdf_spin_lock_bh(&pmo_ctx->lock);
574 		handler = pmo_ctx->pmo_resume_handler[i];
575 		arg = pmo_ctx->pmo_resume_handler_arg[i];
576 		qdf_spin_unlock_bh(&pmo_ctx->lock);
577 
578 		if (!handler)
579 			continue;
580 
581 		status = handler(psoc, arg);
582 		if (QDF_IS_STATUS_ERROR(status)) {
583 			pmo_fatal("Non-recoverable failure occurred!");
584 			pmo_fatal("component %d failed to resume; status: %d",
585 				  i, status);
586 			QDF_BUG(0);
587 		}
588 	}
589 
590 exit_with_status:
591 	return status;
592 }
593 
pmo_register_pause_bitmap_notifier(struct wlan_objmgr_psoc * psoc,pmo_notify_pause_bitmap handler)594 QDF_STATUS pmo_register_pause_bitmap_notifier(struct wlan_objmgr_psoc *psoc,
595 		pmo_notify_pause_bitmap handler)
596 {
597 	struct pmo_psoc_priv_obj *psoc_ctx;
598 	QDF_STATUS status;
599 
600 	if (!psoc) {
601 		pmo_err("psoc is null");
602 		return QDF_STATUS_E_NULL_VALUE;
603 	}
604 
605 	if (!handler) {
606 		pmo_err("pmo_notify_vdev_pause_bitmap is null");
607 		return QDF_STATUS_E_NULL_VALUE;
608 	}
609 
610 	status = pmo_psoc_get_ref(psoc);
611 	if (status != QDF_STATUS_SUCCESS) {
612 		pmo_err("pmo cannot get the reference out of psoc");
613 		return status;
614 	}
615 
616 	pmo_psoc_with_ctx(psoc, psoc_ctx) {
617 		psoc_ctx->pause_bitmap_notifier = handler;
618 	}
619 
620 	pmo_psoc_put_ref(psoc);
621 
622 	return QDF_STATUS_SUCCESS;
623 }
624 
pmo_unregister_pause_bitmap_notifier(struct wlan_objmgr_psoc * psoc)625 QDF_STATUS pmo_unregister_pause_bitmap_notifier(struct wlan_objmgr_psoc *psoc)
626 {
627 	struct pmo_psoc_priv_obj *psoc_ctx;
628 	QDF_STATUS status;
629 
630 	if (!psoc) {
631 		pmo_err("psoc is null");
632 		return QDF_STATUS_E_NULL_VALUE;
633 	}
634 
635 	status = pmo_psoc_get_ref(psoc);
636 	if (status != QDF_STATUS_SUCCESS) {
637 		pmo_err("pmo cannot get the reference out of psoc");
638 		return status;
639 	}
640 
641 	pmo_psoc_with_ctx(psoc, psoc_ctx) {
642 		psoc_ctx->pause_bitmap_notifier = NULL;
643 	}
644 
645 	pmo_psoc_put_ref(psoc);
646 
647 	return QDF_STATUS_SUCCESS;
648 }
649 
pmo_register_get_pause_bitmap(struct wlan_objmgr_psoc * psoc,pmo_get_pause_bitmap handler)650 QDF_STATUS pmo_register_get_pause_bitmap(struct wlan_objmgr_psoc *psoc,
651 		pmo_get_pause_bitmap handler)
652 {
653 	struct pmo_psoc_priv_obj *psoc_ctx;
654 	QDF_STATUS status;
655 
656 	if (!psoc) {
657 		pmo_err("psoc is null");
658 		return QDF_STATUS_E_NULL_VALUE;
659 	}
660 
661 	if (!handler) {
662 		pmo_err("pmo_get_pause_bitmap is null");
663 		return QDF_STATUS_E_NULL_VALUE;
664 	}
665 
666 	status = pmo_psoc_get_ref(psoc);
667 	if (status != QDF_STATUS_SUCCESS) {
668 		pmo_err("pmo cannot get the reference out of psoc");
669 		return status;
670 	}
671 
672 	pmo_psoc_with_ctx(psoc, psoc_ctx) {
673 		psoc_ctx->get_pause_bitmap = handler;
674 	}
675 
676 	pmo_psoc_put_ref(psoc);
677 
678 	return QDF_STATUS_SUCCESS;
679 }
680 
pmo_unregister_get_pause_bitmap(struct wlan_objmgr_psoc * psoc)681 QDF_STATUS pmo_unregister_get_pause_bitmap(struct wlan_objmgr_psoc *psoc)
682 {
683 	struct pmo_psoc_priv_obj *psoc_ctx;
684 	QDF_STATUS status;
685 
686 	if (!psoc) {
687 		pmo_err("psoc is null");
688 		return QDF_STATUS_E_NULL_VALUE;
689 	}
690 
691 	status = pmo_psoc_get_ref(psoc);
692 	if (status != QDF_STATUS_SUCCESS) {
693 		pmo_err("pmo cannot get the reference out of psoc");
694 		return status;
695 	}
696 
697 	pmo_psoc_with_ctx(psoc, psoc_ctx) {
698 		psoc_ctx->get_pause_bitmap = NULL;
699 	}
700 
701 	pmo_psoc_put_ref(psoc);
702 
703 	return QDF_STATUS_SUCCESS;
704 }
705 
pmo_register_is_device_in_low_pwr_mode(struct wlan_objmgr_psoc * psoc,pmo_is_device_in_low_pwr_mode handler)706 QDF_STATUS pmo_register_is_device_in_low_pwr_mode(struct wlan_objmgr_psoc *psoc,
707 		pmo_is_device_in_low_pwr_mode handler)
708 {
709 	struct pmo_psoc_priv_obj *psoc_ctx;
710 	QDF_STATUS status;
711 
712 	if (!psoc) {
713 		pmo_err("psoc is null");
714 		return QDF_STATUS_E_NULL_VALUE;
715 	}
716 
717 	if (!handler) {
718 		pmo_err("pmo_get_pause_bitmap is null");
719 		return QDF_STATUS_E_NULL_VALUE;
720 	}
721 
722 	status = pmo_psoc_get_ref(psoc);
723 	if (status != QDF_STATUS_SUCCESS) {
724 		pmo_err("pmo cannot get the reference out of psoc");
725 		return status;
726 	}
727 
728 	pmo_psoc_with_ctx(psoc, psoc_ctx) {
729 		psoc_ctx->is_device_in_low_pwr_mode = handler;
730 	}
731 
732 	pmo_psoc_put_ref(psoc);
733 
734 	return QDF_STATUS_SUCCESS;
735 }
736 
737 QDF_STATUS
pmo_unregister_is_device_in_low_pwr_mode(struct wlan_objmgr_psoc * psoc)738 pmo_unregister_is_device_in_low_pwr_mode(struct wlan_objmgr_psoc *psoc)
739 {
740 	struct pmo_psoc_priv_obj *psoc_ctx;
741 	QDF_STATUS status;
742 
743 	if (!psoc) {
744 		pmo_err("psoc is null");
745 		return QDF_STATUS_E_NULL_VALUE;
746 	}
747 
748 	status = pmo_psoc_get_ref(psoc);
749 	if (status != QDF_STATUS_SUCCESS) {
750 		pmo_err("pmo cannot get the reference out of psoc");
751 		return status;
752 	}
753 
754 	pmo_psoc_with_ctx(psoc, psoc_ctx) {
755 		psoc_ctx->is_device_in_low_pwr_mode = NULL;
756 	}
757 
758 	pmo_psoc_put_ref(psoc);
759 
760 	return QDF_STATUS_SUCCESS;
761 }
762 
pmo_register_get_dtim_period_callback(struct wlan_objmgr_psoc * psoc,pmo_get_dtim_period handler)763 QDF_STATUS pmo_register_get_dtim_period_callback(struct wlan_objmgr_psoc *psoc,
764 						 pmo_get_dtim_period handler)
765 {
766 	struct pmo_psoc_priv_obj *psoc_ctx;
767 	QDF_STATUS status;
768 
769 	if (!psoc) {
770 		pmo_err("psoc is null");
771 		return QDF_STATUS_E_NULL_VALUE;
772 	}
773 
774 	if (!handler) {
775 		pmo_err("pmo_get_dtim_period is null");
776 		return QDF_STATUS_E_NULL_VALUE;
777 	}
778 
779 	status = pmo_psoc_get_ref(psoc);
780 	if (status != QDF_STATUS_SUCCESS) {
781 		pmo_err("pmo cannot get the reference out of psoc");
782 		return status;
783 	}
784 
785 	pmo_psoc_with_ctx(psoc, psoc_ctx) {
786 		psoc_ctx->get_dtim_period = handler;
787 	}
788 	pmo_psoc_put_ref(psoc);
789 
790 	return QDF_STATUS_SUCCESS;
791 }
792 
793 QDF_STATUS
pmo_unregister_get_dtim_period_callback(struct wlan_objmgr_psoc * psoc)794 pmo_unregister_get_dtim_period_callback(struct wlan_objmgr_psoc *psoc)
795 {
796 	struct pmo_psoc_priv_obj *psoc_ctx;
797 	QDF_STATUS status;
798 
799 	if (!psoc) {
800 		pmo_err("psoc is null");
801 		return QDF_STATUS_E_NULL_VALUE;
802 	}
803 
804 	status = pmo_psoc_get_ref(psoc);
805 	if (status != QDF_STATUS_SUCCESS) {
806 		pmo_err("pmo cannot get the reference out of psoc");
807 		return status;
808 	}
809 
810 	pmo_psoc_with_ctx(psoc, psoc_ctx) {
811 		psoc_ctx->get_dtim_period = NULL;
812 	}
813 	pmo_psoc_put_ref(psoc);
814 
815 	return QDF_STATUS_SUCCESS;
816 }
817 
818 QDF_STATUS
pmo_register_get_beacon_interval_callback(struct wlan_objmgr_psoc * psoc,pmo_get_beacon_interval handler)819 pmo_register_get_beacon_interval_callback(struct wlan_objmgr_psoc *psoc,
820 					  pmo_get_beacon_interval handler)
821 {
822 	struct pmo_psoc_priv_obj *psoc_ctx;
823 	QDF_STATUS status;
824 
825 	if (!psoc) {
826 		pmo_err("psoc is null");
827 		return QDF_STATUS_E_NULL_VALUE;
828 	}
829 
830 	if (!handler) {
831 		pmo_err("pmo_get_beacon_interval is null");
832 		return QDF_STATUS_E_NULL_VALUE;
833 	}
834 
835 	status = pmo_psoc_get_ref(psoc);
836 	if (status != QDF_STATUS_SUCCESS) {
837 		pmo_err("pmo cannot get the reference out of psoc");
838 		return status;
839 	}
840 
841 	pmo_psoc_with_ctx(psoc, psoc_ctx) {
842 		psoc_ctx->get_beacon_interval = handler;
843 	}
844 	pmo_psoc_put_ref(psoc);
845 
846 	return QDF_STATUS_SUCCESS;
847 }
848 
849 QDF_STATUS
pmo_unregister_get_beacon_interval_callback(struct wlan_objmgr_psoc * psoc)850 pmo_unregister_get_beacon_interval_callback(struct wlan_objmgr_psoc *psoc)
851 {
852 	struct pmo_psoc_priv_obj *psoc_ctx;
853 	QDF_STATUS status;
854 
855 	if (!psoc) {
856 		pmo_err("psoc is null");
857 		return QDF_STATUS_E_NULL_VALUE;
858 	}
859 
860 	status = pmo_psoc_get_ref(psoc);
861 	if (status != QDF_STATUS_SUCCESS) {
862 		pmo_err("pmo cannot get the reference out of psoc");
863 		return status;
864 	}
865 
866 	pmo_psoc_with_ctx(psoc, psoc_ctx) {
867 		psoc_ctx->get_beacon_interval = NULL;
868 	}
869 	pmo_psoc_put_ref(psoc);
870 
871 	return QDF_STATUS_SUCCESS;
872 }
873 
874 bool
wlan_pmo_get_sap_mode_bus_suspend(struct wlan_objmgr_psoc * psoc)875 wlan_pmo_get_sap_mode_bus_suspend(struct wlan_objmgr_psoc *psoc)
876 {
877 	struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc);
878 
879 	if (!pmo_psoc_ctx)
880 		return false;
881 
882 	return pmo_psoc_ctx->psoc_cfg.is_bus_suspend_enabled_in_sap_mode;
883 }
884 
885 bool
wlan_pmo_get_go_mode_bus_suspend(struct wlan_objmgr_psoc * psoc)886 wlan_pmo_get_go_mode_bus_suspend(struct wlan_objmgr_psoc *psoc)
887 {
888 	struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc);
889 
890 	if (!pmo_psoc_ctx)
891 		return false;
892 
893 	return pmo_psoc_ctx->psoc_cfg.is_bus_suspend_enabled_in_go_mode;
894 }
895 
wlan_pmo_no_op_on_page_fault(struct wlan_objmgr_psoc * psoc)896 bool wlan_pmo_no_op_on_page_fault(struct wlan_objmgr_psoc *psoc)
897 {
898 	return pmo_no_op_on_page_fault(psoc);
899 }
900 
wlan_pmo_enable_ssr_on_page_fault(struct wlan_objmgr_psoc * psoc)901 bool wlan_pmo_enable_ssr_on_page_fault(struct wlan_objmgr_psoc *psoc)
902 {
903 	return pmo_enable_ssr_on_page_fault(psoc);
904 }
905 
906 uint8_t
wlan_pmo_get_min_pagefault_wakeups_for_action(struct wlan_objmgr_psoc * psoc)907 wlan_pmo_get_min_pagefault_wakeups_for_action(struct wlan_objmgr_psoc *psoc)
908 {
909 	return pmo_get_min_pagefault_wakeups_for_action(psoc);
910 }
911 
912 uint32_t
wlan_pmo_get_interval_for_pagefault_wakeup_counts(struct wlan_objmgr_psoc * psoc)913 wlan_pmo_get_interval_for_pagefault_wakeup_counts(struct wlan_objmgr_psoc *psoc)
914 {
915 	return pmo_get_interval_for_pagefault_wakeup_counts(psoc);
916 }
917 
wlan_pmo_get_listen_interval(struct wlan_objmgr_vdev * vdev,uint32_t * listen_interval)918 QDF_STATUS wlan_pmo_get_listen_interval(struct wlan_objmgr_vdev *vdev,
919 					uint32_t *listen_interval)
920 {
921 	return pmo_core_get_listen_interval(vdev, listen_interval);
922 }
923 
wlan_pmo_set_ps_params(struct wlan_objmgr_vdev * vdev,struct pmo_ps_params * ps_params)924 void wlan_pmo_set_ps_params(struct wlan_objmgr_vdev *vdev,
925 			    struct pmo_ps_params *ps_params)
926 {
927 	pmo_core_vdev_set_ps_params(vdev, ps_params);
928 }
929 
wlan_pmo_get_ps_params(struct wlan_objmgr_vdev * vdev,struct pmo_ps_params * ps_params)930 QDF_STATUS wlan_pmo_get_ps_params(struct wlan_objmgr_vdev *vdev,
931 				  struct pmo_ps_params *ps_params)
932 {
933 	return pmo_core_vdev_get_ps_params(vdev, ps_params);
934 }
935