xref: /wlan-driver/qcacld-3.0/components/pmo/core/src/wlan_pmo_suspend_resume.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1 /*
2  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022-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 /**
21  * DOC: Define API's for suspend / resume handling
22  */
23 
24 #include "wlan_pmo_wow.h"
25 #include "wlan_pmo_tgt_api.h"
26 #include "wlan_pmo_main.h"
27 #include "wlan_pmo_obj_mgmt_public_struct.h"
28 #include "wlan_pmo_lphb.h"
29 #include "wlan_pmo_hw_filter.h"
30 #include "wlan_pmo_suspend_resume.h"
31 #include "cdp_txrx_ops.h"
32 #include "cdp_txrx_misc.h"
33 #include "cdp_txrx_flow_ctrl_legacy.h"
34 #include "hif.h"
35 #include "htc_api.h"
36 #include "wlan_pmo_obj_mgmt_api.h"
37 #include <wlan_scan_ucfg_api.h>
38 #include <wlan_dp_api.h>
39 #include "cds_api.h"
40 #include "wlan_pmo_static_config.h"
41 #include "wlan_mlme_ucfg_api.h"
42 #include "cfg_mlme_sap.h"
43 #include "cfg_ucfg_api.h"
44 #include "cdp_txrx_bus.h"
45 #include "wlan_pmo_ucfg_api.h"
46 #include "hif.h"
47 #include "target_type.h"
48 
49 /**
50  * pmo_core_get_vdev_dtim_period() - Get vdev dtim period
51  * @vdev: objmgr vdev handle
52  *
53  * Return: Vdev dtim period
54  */
pmo_core_get_vdev_dtim_period(struct wlan_objmgr_vdev * vdev)55 static uint8_t pmo_core_get_vdev_dtim_period(struct wlan_objmgr_vdev *vdev)
56 {
57 	uint8_t dtim_period = 0;
58 	struct pmo_psoc_priv_obj *psoc_ctx;
59 	struct wlan_objmgr_psoc *psoc;
60 	QDF_STATUS ret = QDF_STATUS_E_FAILURE;
61 
62 	psoc = pmo_vdev_get_psoc(vdev);
63 
64 	pmo_psoc_with_ctx(psoc, psoc_ctx) {
65 		if (psoc_ctx->get_dtim_period)
66 			ret = psoc_ctx->get_dtim_period(pmo_vdev_get_id(vdev),
67 							&dtim_period);
68 	}
69 
70 	if (QDF_IS_STATUS_ERROR(ret))
71 		pmo_err("Failed to get to dtim period for vdevId %d",
72 				pmo_vdev_get_id(vdev));
73 
74 	return dtim_period;
75 }
76 
77 /**
78  * pmo_core_get_vdev_beacon_interval() - Get vdev beacon interval
79  * @vdev: objmgr vdev handle
80  *
81  * Return: Vdev beacon interval
82  */
pmo_core_get_vdev_beacon_interval(struct wlan_objmgr_vdev * vdev)83 static uint16_t pmo_core_get_vdev_beacon_interval(struct wlan_objmgr_vdev *vdev)
84 {
85 	uint16_t beacon_interval = 0;
86 	struct pmo_psoc_priv_obj *psoc_ctx;
87 	struct wlan_objmgr_psoc *psoc;
88 	QDF_STATUS ret = QDF_STATUS_E_FAILURE;
89 
90 	psoc = pmo_vdev_get_psoc(vdev);
91 
92 	pmo_psoc_with_ctx(psoc, psoc_ctx) {
93 		if (psoc_ctx->get_beacon_interval)
94 			ret = psoc_ctx->get_beacon_interval(
95 							pmo_vdev_get_id(vdev),
96 							&beacon_interval);
97 	}
98 
99 	if (QDF_IS_STATUS_ERROR(ret))
100 		pmo_err("Failed to get beacon interval for vdev id %d",
101 			pmo_vdev_get_id(vdev));
102 
103 	return beacon_interval;
104 }
105 
106 /**
107  * pmo_core_calculate_listen_interval() - Calculate vdev listen interval
108  * @vdev: objmgr vdev handle
109  * @vdev_ctx: pmo vdev priv ctx
110  * @listen_interval: listen interval which is computed for vdev
111  *
112  * Return: QDF_STATUS
113  */
pmo_core_calculate_listen_interval(struct wlan_objmgr_vdev * vdev,struct pmo_vdev_priv_obj * vdev_ctx,uint32_t * listen_interval)114 static QDF_STATUS pmo_core_calculate_listen_interval(
115 			struct wlan_objmgr_vdev *vdev,
116 			struct pmo_vdev_priv_obj *vdev_ctx,
117 			uint32_t *listen_interval)
118 {
119 	uint32_t max_mod_dtim, max_dtim = 0;
120 	uint32_t beacon_interval_mod;
121 	struct pmo_psoc_cfg *psoc_cfg = &vdev_ctx->pmo_psoc_ctx->psoc_cfg;
122 	struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev);
123 
124 	if (psoc_cfg->sta_dynamic_dtim) {
125 		*listen_interval = psoc_cfg->sta_dynamic_dtim;
126 	} else if ((psoc_cfg->sta_mod_dtim) &&
127 		   (psoc_cfg->sta_max_li_mod_dtim)) {
128 		/*
129 		 * When the system is in suspend
130 		 * (maximum beacon will be at 1s == 10)
131 		 * If maxModulatedDTIM ((MAX_LI_VAL = 10) / AP_DTIM)
132 		 * equal or larger than MDTIM
133 		 * (configured in WCNSS_qcom_cfg.ini)
134 		 * Set LI to MDTIM * AP_DTIM
135 		 * If Dtim = 2 and Mdtim = 2 then LI is 4
136 		 * Else
137 		 * Set LI to maxModulatedDTIM * AP_DTIM
138 		 */
139 		beacon_interval_mod =
140 			pmo_core_get_vdev_beacon_interval(vdev) / 100;
141 		if (beacon_interval_mod == 0)
142 			beacon_interval_mod = 1;
143 
144 		max_dtim = pmo_core_get_vdev_dtim_period(vdev) *
145 					beacon_interval_mod;
146 
147 		if (!max_dtim) {
148 			pmo_err("Invalid dtim period");
149 			return QDF_STATUS_E_INVAL;
150 		}
151 
152 		max_mod_dtim = psoc_cfg->sta_max_li_mod_dtim / max_dtim;
153 
154 		if (max_mod_dtim <= 0)
155 			max_mod_dtim = 1;
156 
157 		if (max_mod_dtim >= psoc_cfg->sta_mod_dtim) {
158 			*listen_interval =
159 				(psoc_cfg->sta_mod_dtim *
160 				pmo_core_get_vdev_dtim_period(vdev));
161 		} else {
162 			*listen_interval =
163 				(max_mod_dtim *
164 				pmo_core_get_vdev_dtim_period(vdev));
165 		}
166 	} else {
167 		/* Get Listen Interval */
168 		if (QDF_IS_STATUS_ERROR(ucfg_mlme_get_listen_interval(psoc,
169 							    listen_interval))) {
170 			pmo_err("Failed to get value for listen interval");
171 			*listen_interval = cfg_default(CFG_LISTEN_INTERVAL);
172 		}
173 	}
174 
175 	pmo_info("sta dynamic dtim %d sta mod dtim %d sta_max_li_mod_dtim %d max_dtim %d",
176 		 psoc_cfg->sta_dynamic_dtim, psoc_cfg->sta_mod_dtim,
177 		 psoc_cfg->sta_max_li_mod_dtim, max_dtim);
178 
179 	return QDF_STATUS_SUCCESS;
180 }
181 
pmo_configure_vdev_suspend_params(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_vdev * vdev,struct pmo_vdev_priv_obj * vdev_ctx)182 static void pmo_configure_vdev_suspend_params(
183 					struct wlan_objmgr_psoc *psoc,
184 					struct wlan_objmgr_vdev *vdev,
185 					struct pmo_vdev_priv_obj *vdev_ctx)
186 {
187 	QDF_STATUS ret;
188 	uint8_t vdev_id;
189 	enum QDF_OPMODE opmode = pmo_core_get_vdev_op_mode(vdev);
190 	struct pmo_psoc_cfg *psoc_cfg = &vdev_ctx->pmo_psoc_ctx->psoc_cfg;
191 	uint8_t  ito_repeat_count_value = 0;
192 	uint32_t non_wow_inactivity_time, wow_inactivity_time;
193 
194 	vdev_id = pmo_vdev_get_id(vdev);
195 	if (!PMO_VDEV_IN_STA_MODE(opmode))
196 		return;
197 	ret = pmo_tgt_send_vdev_sta_ps_param(vdev,
198 					pmo_sta_ps_param_inactivity_time,
199 					psoc_cfg->wow_data_inactivity_timeout);
200 	if (QDF_IS_STATUS_ERROR(ret)) {
201 		pmo_err("Failed to Set wow inactivity timeout vdevId %d",
202 			vdev_id);
203 	}
204 	ret = pmo_tgt_send_vdev_sta_ps_param(vdev,
205 					     pmo_sta_ps_param_spec_wake_interval,
206 					     psoc_cfg->wow_spec_wake_interval);
207 	if (QDF_IS_STATUS_ERROR(ret)) {
208 		pmo_err("Failed to Set wow spec wake interval vdevId %d",
209 			vdev_id);
210 	}
211 
212 	non_wow_inactivity_time = PMO_PS_DATA_INACTIVITY_TIMEOUT;
213 	wow_inactivity_time = psoc_cfg->wow_data_inactivity_timeout;
214 	/*
215 	 * To keep ito repeat count same in wow mode as in non wow mode,
216 	 * modulating ito repeat count value.
217 	 */
218 	ito_repeat_count_value = (non_wow_inactivity_time /
219 				  wow_inactivity_time) *
220 					psoc_cfg->ito_repeat_count;
221 	if (ito_repeat_count_value)
222 		ret = pmo_tgt_send_vdev_sta_ps_param(vdev,
223 					pmo_sta_ps_param_ito_repeat_count,
224 					psoc_cfg->wow_data_inactivity_timeout);
225 	if (QDF_IS_STATUS_ERROR(ret)) {
226 		pmo_err("Failed to Set ito repeat count vdevId %d",
227 			vdev_id);
228 	}
229 
230 	pmo_exit();
231 }
232 
pmo_configure_vdev_resume_params(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_vdev * vdev,struct pmo_vdev_priv_obj * vdev_ctx)233 static void pmo_configure_vdev_resume_params(
234 					struct wlan_objmgr_psoc *psoc,
235 					struct wlan_objmgr_vdev *vdev,
236 					struct pmo_vdev_priv_obj *vdev_ctx)
237 {
238 	QDF_STATUS ret;
239 	uint8_t vdev_id;
240 	enum QDF_OPMODE opmode = pmo_core_get_vdev_op_mode(vdev);
241 
242 	pmo_enter();
243 
244 	vdev_id = pmo_vdev_get_id(vdev);
245 	if (!PMO_VDEV_IN_STA_MODE(opmode))
246 		return;
247 	ret = pmo_tgt_send_vdev_sta_ps_param(vdev,
248 					 pmo_sta_ps_param_inactivity_time,
249 					 vdev_ctx->ps_params.ps_ito);
250 	if (QDF_IS_STATUS_ERROR(ret)) {
251 		pmo_err("Failed to Set inactivity timeout vdevId %d",
252 			vdev_id);
253 	}
254 	ret = pmo_tgt_send_vdev_sta_ps_param(vdev,
255 					     pmo_sta_ps_param_spec_wake_interval,
256 					     vdev_ctx->ps_params.spec_wake);
257 	if (QDF_IS_STATUS_ERROR(ret)) {
258 		pmo_err("Failed to Set wow spec wake interval vdevId %d",
259 			vdev_id);
260 	}
261 }
262 
263 /**
264  * pmo_core_set_vdev_suspend_dtim() - set suspend dtim parameters in fw
265  * @psoc: objmgr psoc handle
266  * @vdev: objmgr vdev handle
267  * @vdev_ctx: pmo vdev priv ctx
268  *
269  * Return: none
270  */
pmo_core_set_vdev_suspend_dtim(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_vdev * vdev,struct pmo_vdev_priv_obj * vdev_ctx)271 static void pmo_core_set_vdev_suspend_dtim(struct wlan_objmgr_psoc *psoc,
272 		struct wlan_objmgr_vdev *vdev,
273 		struct pmo_vdev_priv_obj *vdev_ctx)
274 {
275 	QDF_STATUS ret;
276 	uint8_t vdev_id;
277 	enum QDF_OPMODE opmode = pmo_core_get_vdev_op_mode(vdev);
278 	uint32_t listen_interval = cfg_default(CFG_LISTEN_INTERVAL);
279 
280 	vdev_id = pmo_vdev_get_id(vdev);
281 	if (PMO_VDEV_IN_STA_MODE(opmode) &&
282 	    pmo_core_get_vdev_dtim_period(vdev) != 0) {
283 		/* calculate listen interval */
284 		ret = pmo_core_calculate_listen_interval(vdev, vdev_ctx,
285 				&listen_interval);
286 		if (ret != QDF_STATUS_SUCCESS) {
287 			/* even it fails continue fwr will take default LI */
288 			pmo_debug("Fail to calculate listen interval");
289 		}
290 		ret = pmo_tgt_vdev_update_param_req(vdev,
291 					pmo_vdev_param_listen_interval,
292 					listen_interval);
293 		if (QDF_IS_STATUS_ERROR(ret)) {
294 			/* even it fails continue fwr will take default LI */
295 			pmo_debug("Failed to Set Listen Interval vdevId %d",
296 				 vdev_id);
297 		}
298 		pmo_debug("Set Listen Interval vdevId %d Listen Intv %d",
299 			  vdev_id, listen_interval);
300 
301 		pmo_core_vdev_set_restore_dtim(vdev, true);
302 	}
303 }
304 
305 /*
306  * pmo_is_listen_interval_user_set() - Check if listen interval is configured
307  * by user or not
308  * @vdev_ctx: PMO vdev private object
309  *
310  * Return: true if listen interval is user configured else false
311  */
312 static inline
pmo_is_listen_interval_user_set(struct pmo_vdev_priv_obj * vdev_ctx)313 bool pmo_is_listen_interval_user_set(struct pmo_vdev_priv_obj *vdev_ctx)
314 {
315 	bool retval;
316 
317 	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
318 	retval = vdev_ctx->dyn_modulated_dtim_enabled
319 		 || vdev_ctx->dyn_listen_interval;
320 	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
321 
322 	return retval;
323 }
324 
325 /**
326  * pmo_core_set_suspend_dtim() - set suspend dtim
327  * @psoc: objmgr psoc handle
328  *
329  * Return: none
330  */
pmo_core_set_suspend_dtim(struct wlan_objmgr_psoc * psoc)331 static void pmo_core_set_suspend_dtim(struct wlan_objmgr_psoc *psoc)
332 {
333 	uint8_t vdev_id;
334 	struct wlan_objmgr_vdev *vdev;
335 	struct pmo_vdev_priv_obj *vdev_ctx;
336 	struct pmo_psoc_priv_obj *psoc_ctx;
337 	bool li_offload_support = false;
338 
339 	pmo_psoc_with_ctx(psoc, psoc_ctx) {
340 		li_offload_support = psoc_ctx->caps.li_offload;
341 	}
342 
343 	if (li_offload_support)
344 		pmo_debug("listen interval offload support is enabled");
345 
346 	/* Iterate through VDEV list */
347 	for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) {
348 		vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
349 							    WLAN_PMO_ID);
350 		if (!vdev)
351 			continue;
352 
353 		vdev_ctx = pmo_vdev_get_priv(vdev);
354 		if (!pmo_is_listen_interval_user_set(vdev_ctx)
355 		    && !li_offload_support)
356 			pmo_core_set_vdev_suspend_dtim(psoc, vdev, vdev_ctx);
357 		pmo_configure_vdev_suspend_params(psoc, vdev, vdev_ctx);
358 		wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
359 	}
360 }
361 
362 /**
363  * pmo_core_update_wow_bus_suspend() - set wow bus suspend flag
364  * @psoc: objmgr psoc handle
365  * @psoc_ctx: pmo psoc priv ctx
366  * @val: true for enable else false
367  * Return: none
368  */
369 static inline
pmo_core_update_wow_bus_suspend(struct wlan_objmgr_psoc * psoc,struct pmo_psoc_priv_obj * psoc_ctx,int val)370 void pmo_core_update_wow_bus_suspend(struct wlan_objmgr_psoc *psoc,
371 		struct pmo_psoc_priv_obj *psoc_ctx, int val)
372 {
373 	qdf_spin_lock_bh(&psoc_ctx->lock);
374 	psoc_ctx->wow.is_wow_bus_suspended = val;
375 	qdf_spin_unlock_bh(&psoc_ctx->lock);
376 	pmo_tgt_psoc_update_wow_bus_suspend_state(psoc, val);
377 }
378 
379 /* Define for conciseness */
380 #define BM_LEN PMO_WOW_MAX_EVENT_BM_LEN
381 #define EV_NLO WOW_NLO_SCAN_COMPLETE_EVENT
382 #define EV_PWR WOW_CHIP_POWER_FAILURE_DETECT_EVENT
383 
pmo_core_configure_dynamic_wake_events(struct wlan_objmgr_psoc * psoc)384 void pmo_core_configure_dynamic_wake_events(struct wlan_objmgr_psoc *psoc)
385 {
386 	int vdev_id;
387 	uint32_t adapter_type;
388 	uint32_t enable_mask[BM_LEN];
389 	uint32_t disable_mask[BM_LEN];
390 	struct wlan_objmgr_vdev *vdev;
391 	struct pmo_psoc_priv_obj *psoc_ctx;
392 	bool enable_configured;
393 	bool disable_configured;
394 
395 	/* Iterate through VDEV list */
396 	for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) {
397 
398 		enable_configured = false;
399 		disable_configured = false;
400 
401 		qdf_mem_zero(enable_mask,  sizeof(uint32_t) * BM_LEN);
402 		qdf_mem_zero(disable_mask, sizeof(uint32_t) * BM_LEN);
403 
404 		vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
405 							    WLAN_PMO_ID);
406 		if (!vdev)
407 			continue;
408 
409 		if (ucfg_scan_get_pno_in_progress(vdev)) {
410 			if (ucfg_scan_get_pno_match(vdev)) {
411 				pmo_set_wow_event_bitmap(EV_NLO,
412 							 BM_LEN,
413 							 enable_mask);
414 				enable_configured = true;
415 			} else {
416 				pmo_set_wow_event_bitmap(EV_NLO,
417 							 BM_LEN,
418 							 disable_mask);
419 				disable_configured = true;
420 			}
421 		}
422 
423 		adapter_type = pmo_get_vdev_opmode(vdev);
424 
425 		psoc_ctx = pmo_psoc_get_priv(psoc);
426 
427 		if (psoc_ctx->psoc_cfg.auto_power_save_fail_mode ==
428 		    PMO_FW_TO_SEND_WOW_IND_ON_PWR_FAILURE &&
429 		    (adapter_type == QDF_STA_MODE ||
430 		     adapter_type == QDF_P2P_CLIENT_MODE)) {
431 			if (psoc_ctx->is_device_in_low_pwr_mode &&
432 			    psoc_ctx->is_device_in_low_pwr_mode(vdev_id)) {
433 				pmo_set_wow_event_bitmap(EV_PWR,
434 							 BM_LEN,
435 							 enable_mask);
436 				enable_configured = true;
437 			}
438 		}
439 
440 		if (enable_configured)
441 			pmo_tgt_enable_wow_wakeup_event(vdev, enable_mask);
442 		if (disable_configured)
443 			pmo_tgt_disable_wow_wakeup_event(vdev, disable_mask);
444 
445 		wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
446 	}
447 
448 }
449 
pmo_core_enable_runtime_pm_offloads(struct wlan_objmgr_psoc * psoc)450 static void pmo_core_enable_runtime_pm_offloads(struct wlan_objmgr_psoc *psoc)
451 {
452 	uint8_t vdev_id;
453 	struct wlan_objmgr_vdev *vdev;
454 
455 	/* Iterate through VDEV list */
456 	for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) {
457 		vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
458 							    WLAN_PMO_ID);
459 		if (!vdev)
460 			continue;
461 
462 		pmo_register_action_frame_patterns(vdev, QDF_RUNTIME_SUSPEND);
463 		wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
464 	}
465 }
466 
pmo_core_disable_runtime_pm_offloads(struct wlan_objmgr_psoc * psoc)467 static void pmo_core_disable_runtime_pm_offloads(struct wlan_objmgr_psoc *psoc)
468 {
469 	uint8_t vdev_id;
470 	struct wlan_objmgr_vdev *vdev;
471 
472 	/* Iterate through VDEV list */
473 	for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) {
474 		vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
475 							    WLAN_PMO_ID);
476 		if (!vdev)
477 			continue;
478 
479 		pmo_clear_action_frame_patterns(vdev);
480 		wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
481 	}
482 }
483 
484 /**
485  * pmo_core_psoc_configure_suspend(): configure suspend req events
486  * @psoc: objmgr psoc
487  * @is_runtime_pm: indicate if it is used by runtime PM
488  *
489  * Responsibility of the caller to take the psoc reference.
490  *
491  * Return: QDF_STATUS_SUCCESS for success or error code
492  */
pmo_core_psoc_configure_suspend(struct wlan_objmgr_psoc * psoc,bool is_runtime_pm)493 static QDF_STATUS pmo_core_psoc_configure_suspend(struct wlan_objmgr_psoc *psoc,
494 						  bool is_runtime_pm)
495 {
496 	struct pmo_psoc_priv_obj *psoc_ctx;
497 	struct hif_target_info *tgt_info;
498 	struct hif_opaque_softc *hif_ctx;
499 
500 	psoc_ctx = pmo_psoc_get_priv(psoc);
501 
502 	if (is_runtime_pm)
503 		pmo_core_enable_runtime_pm_offloads(psoc);
504 
505 	hif_ctx = pmo_core_psoc_get_hif_handle(psoc);
506 	if (!hif_ctx) {
507 		pmo_err("Invalid hif ctx");
508 		return QDF_STATUS_E_NULL_VALUE;
509 	}
510 	tgt_info = hif_get_target_info_handle(hif_ctx);
511 
512 	if ((is_runtime_pm) ||
513 	    (psoc_ctx->psoc_cfg.suspend_mode == PMO_SUSPEND_WOW &&
514 	    ((tgt_info->target_type == TARGET_TYPE_QCA6490) ||
515 	    pmo_core_is_wow_applicable(psoc)))) {
516 		pmo_debug("WOW Suspend");
517 		pmo_core_apply_lphb(psoc);
518 		/*
519 		 * Dynamic wake events should not be needed for runtime PM.
520 		 * Any wake events can be configured by default if they are
521 		 * really needed for runtime PM. In fact, most of them are
522 		 * only needed for system suspend.
523 		 */
524 		if (!is_runtime_pm)
525 			pmo_core_configure_dynamic_wake_events(psoc);
526 		pmo_core_update_wow_enable(psoc_ctx, true);
527 		pmo_core_update_wow_enable_cmd_sent(psoc_ctx, false);
528 	} else {
529 		pmo_debug("Non WOW PDEV Suspend");
530 		pmo_core_update_wow_enable(psoc_ctx, false);
531 	}
532 
533 	/*
534 	 * For runtime PM, since system is awake, DTIM related commands
535 	 * do not have to be sent with WOW sequence. They can be sent
536 	 * through other paths which will just trigger a runtime resume.
537 	 */
538 	if (!is_runtime_pm)
539 		pmo_core_set_suspend_dtim(psoc);
540 
541 	/*
542 	 * To handle race between hif_pci_suspend and unpause/pause tx handler.
543 	 * This happens when host sending WMI_WOW_ENABLE_CMDID to FW and receive
544 	 * WMI_TX_PAUSE_EVENT with ACTON_UNPAUSE almost at same time.
545 	 */
546 	pmo_core_update_wow_bus_suspend(psoc, psoc_ctx, true);
547 
548 	pmo_exit();
549 
550 	return QDF_STATUS_SUCCESS;
551 }
552 
pmo_core_psoc_user_space_suspend_req(struct wlan_objmgr_psoc * psoc,enum qdf_suspend_type type)553 QDF_STATUS pmo_core_psoc_user_space_suspend_req(struct wlan_objmgr_psoc *psoc,
554 		enum qdf_suspend_type type)
555 {
556 	QDF_STATUS status;
557 
558 	pmo_enter();
559 
560 	status = pmo_psoc_get_ref(psoc);
561 	if (status != QDF_STATUS_SUCCESS) {
562 		pmo_err("pmo cannot get the reference out of psoc");
563 		goto out;
564 	}
565 
566 	status = pmo_core_psoc_configure_suspend(psoc, false);
567 	if (status != QDF_STATUS_SUCCESS)
568 		pmo_err("Failed to configure suspend");
569 
570 	pmo_psoc_put_ref(psoc);
571 out:
572 	return status;
573 }
574 
575 /**
576  * pmo_core_set_vdev_resume_dtim() - set resume dtim parameters in fw
577  * @psoc: objmgr psoc handle
578  * @vdev: objmgr vdev handle
579  * @vdev_ctx: pmo vdev priv ctx
580  *
581  * Return: none
582  */
pmo_core_set_vdev_resume_dtim(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_vdev * vdev,struct pmo_vdev_priv_obj * vdev_ctx)583 static void pmo_core_set_vdev_resume_dtim(struct wlan_objmgr_psoc *psoc,
584 		struct wlan_objmgr_vdev *vdev,
585 		struct pmo_vdev_priv_obj *vdev_ctx)
586 {
587 	QDF_STATUS ret;
588 	uint8_t vdev_id;
589 	enum QDF_OPMODE opmode = pmo_core_get_vdev_op_mode(vdev);
590 	int32_t cfg_data_val = 0;
591 
592 	vdev_id = pmo_vdev_get_id(vdev);
593 	if ((PMO_VDEV_IN_STA_MODE(opmode)) &&
594 	    (pmo_core_vdev_get_restore_dtim(vdev))) {
595 		/* Get Listen Interval */
596 		if (QDF_IS_STATUS_ERROR(ucfg_mlme_get_listen_interval(psoc,
597 							      &cfg_data_val))) {
598 			pmo_err("Failed to get value for listen interval");
599 			cfg_data_val = cfg_default(CFG_LISTEN_INTERVAL);
600 		}
601 
602 		ret = pmo_tgt_vdev_update_param_req(vdev,
603 				pmo_vdev_param_listen_interval, cfg_data_val);
604 		if (QDF_IS_STATUS_ERROR(ret)) {
605 			/* Even it fails continue Fw will take default LI */
606 			pmo_err("Failed to Set Listen Interval vdevId %d",
607 				 vdev_id);
608 		}
609 		pmo_debug("Set Listen Interval vdevId %d Listen Intv %d",
610 			  vdev_id, cfg_data_val);
611 		pmo_core_vdev_set_restore_dtim(vdev, false);
612 	}
613 }
614 
615 /**
616  * pmo_core_set_resume_dtim() - set resume time dtim
617  * @psoc: objmgr psoc handle
618  *
619  * Return: none
620  */
pmo_core_set_resume_dtim(struct wlan_objmgr_psoc * psoc)621 static void pmo_core_set_resume_dtim(struct wlan_objmgr_psoc *psoc)
622 {
623 	uint8_t vdev_id;
624 	struct wlan_objmgr_vdev *vdev;
625 	struct pmo_vdev_priv_obj *vdev_ctx;
626 	struct pmo_psoc_priv_obj *psoc_ctx;
627 	bool li_offload_support = false;
628 
629 	pmo_psoc_with_ctx(psoc, psoc_ctx) {
630 		li_offload_support = psoc_ctx->caps.li_offload;
631 	}
632 
633 	if (li_offload_support)
634 		pmo_debug("listen interval offload support is enabled");
635 
636 	/* Iterate through VDEV list */
637 	for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) {
638 		vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
639 							    WLAN_PMO_ID);
640 		if (!vdev)
641 			continue;
642 
643 		vdev_ctx = pmo_vdev_get_priv(vdev);
644 		if (!pmo_is_listen_interval_user_set(vdev_ctx)
645 		    && !li_offload_support)
646 			pmo_core_set_vdev_resume_dtim(psoc, vdev, vdev_ctx);
647 		pmo_configure_vdev_resume_params(psoc, vdev, vdev_ctx);
648 		wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
649 	}
650 }
651 
652 #if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2)
653 /**
654  * pmo_unpause_all_vdev() - unpause all vdev
655  * @psoc: objmgr psoc handle
656  * @psoc_ctx: pmo psoc contaxt
657  *
658  * unpause all vdev aftter resume/coming out of wow mode
659  *
660  * Return: none
661  */
pmo_unpause_all_vdev(struct wlan_objmgr_psoc * psoc,struct pmo_psoc_priv_obj * psoc_ctx)662 static void pmo_unpause_all_vdev(struct wlan_objmgr_psoc *psoc,
663 				 struct pmo_psoc_priv_obj *psoc_ctx)
664 {
665 	uint8_t vdev_id;
666 
667 	/* Iterate through VDEV list */
668 	for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) {
669 		/* When host resumes, by default unpause all active vdev */
670 		if (pmo_core_vdev_get_pause_bitmap(psoc_ctx, vdev_id)) {
671 			cdp_fc_vdev_unpause(pmo_core_psoc_get_dp_handle(psoc),
672 					    vdev_id,
673 					    0xffffffff, 0);
674 			if (psoc_ctx->pause_bitmap_notifier)
675 				psoc_ctx->pause_bitmap_notifier(vdev_id, 0);
676 		}
677 	}
678 }
679 #else
pmo_unpause_all_vdev(struct wlan_objmgr_psoc * psoc,struct pmo_psoc_priv_obj * psoc_ctx)680 static inline void pmo_unpause_all_vdev(struct wlan_objmgr_psoc *psoc,
681 					struct pmo_psoc_priv_obj *psoc_ctx)
682 {
683 }
684 #endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
685 
686 /**
687  * pmo_core_psoc_configure_resume(): configure events after bus resume
688  * @psoc: objmgr psoc
689  * @is_runtime_pm: indicate if it is used by runtime PM
690  *
691  * Responsibility of the caller to take the psoc reference.
692  *
693  * Return: QDF_STATUS_SUCCESS for success or error code
694  */
pmo_core_psoc_configure_resume(struct wlan_objmgr_psoc * psoc,bool is_runtime_pm)695 static QDF_STATUS pmo_core_psoc_configure_resume(struct wlan_objmgr_psoc *psoc,
696 						 bool is_runtime_pm)
697 {
698 	struct pmo_psoc_priv_obj *psoc_ctx;
699 
700 	psoc_ctx = pmo_psoc_get_priv(psoc);
701 	if (is_runtime_pm)
702 		pmo_core_disable_runtime_pm_offloads(psoc);
703 
704 	/*
705 	 * For runtime PM, since system is awake, DTIM related commands
706 	 * do not have to be sent with WOW sequence. They can be sent
707 	 * through other paths which will just trigger a runtime resume.
708 	 */
709 	if (!is_runtime_pm)
710 		pmo_core_set_resume_dtim(psoc);
711 	pmo_core_update_wow_bus_suspend(psoc, psoc_ctx, false);
712 	pmo_unpause_all_vdev(psoc, psoc_ctx);
713 
714 	return QDF_STATUS_SUCCESS;
715 }
716 
pmo_core_psoc_user_space_resume_req(struct wlan_objmgr_psoc * psoc,enum qdf_suspend_type type)717 QDF_STATUS pmo_core_psoc_user_space_resume_req(struct wlan_objmgr_psoc *psoc,
718 		enum qdf_suspend_type type)
719 {
720 	QDF_STATUS status = QDF_STATUS_SUCCESS;
721 
722 	pmo_enter();
723 
724 	status = pmo_psoc_get_ref(psoc);
725 	if (status != QDF_STATUS_SUCCESS) {
726 		pmo_err("pmo cannot get the reference out of psoc");
727 		goto out;
728 	}
729 
730 	status = pmo_core_psoc_configure_resume(psoc, false);
731 	if (status != QDF_STATUS_SUCCESS)
732 		pmo_err("Failed to configure resume");
733 
734 	pmo_psoc_put_ref(psoc);
735 out:
736 	pmo_exit();
737 
738 	return status;
739 }
740 
741 /**
742  * pmo_core_enable_wow_in_fw() - enable wow in fw
743  * @psoc: objmgr psoc handle
744  * @psoc_ctx: pmo psoc private ctx
745  * @wow_params: collection of wow enable override parameters
746  * @type: type of wow suspend
747  *
748  * Return: QDF status
749  */
750 static QDF_STATUS
pmo_core_enable_wow_in_fw(struct wlan_objmgr_psoc * psoc,struct pmo_psoc_priv_obj * psoc_ctx,struct pmo_wow_enable_params * wow_params,enum qdf_suspend_type type)751 pmo_core_enable_wow_in_fw(struct wlan_objmgr_psoc *psoc,
752 			  struct pmo_psoc_priv_obj *psoc_ctx,
753 			  struct pmo_wow_enable_params *wow_params,
754 			  enum qdf_suspend_type type)
755 {
756 	int host_credits, wmi_pending_cmds;
757 	struct pmo_wow_cmd_params param = {0};
758 	struct pmo_psoc_cfg *psoc_cfg = &psoc_ctx->psoc_cfg;
759 	QDF_STATUS status;
760 	void *hif_ctx;
761 	uint16_t reason_code;
762 
763 	hif_ctx = pmo_core_psoc_get_hif_handle(psoc);
764 	qdf_event_reset(&psoc_ctx->wow.target_suspend);
765 	pmo_core_set_wow_nack(psoc_ctx, false, 0);
766 	host_credits = pmo_tgt_psoc_get_host_credits(psoc);
767 	wmi_pending_cmds = pmo_tgt_psoc_get_pending_cmnds(psoc);
768 	pmo_debug("Credits:%d; Pending_Cmds: %d",
769 		host_credits, wmi_pending_cmds);
770 
771 	param.enable = true;
772 	if (wow_params->is_unit_test)
773 		param.flags = WMI_WOW_FLAG_UNIT_TEST_ENABLE;
774 
775 	switch (wow_params->interface_pause) {
776 	default:
777 		pmo_err("Invalid interface pause setting: %d",
778 			 wow_params->interface_pause);
779 		/* intentional to default */
780 		fallthrough;
781 	case PMO_WOW_INTERFACE_PAUSE_DEFAULT:
782 		param.can_suspend_link =
783 			htc_can_suspend_link(
784 				pmo_core_psoc_get_htc_handle(psoc));
785 		break;
786 	case PMO_WOW_INTERFACE_PAUSE_ENABLE:
787 		param.can_suspend_link = true;
788 		break;
789 	case PMO_WOW_INTERFACE_PAUSE_DISABLE:
790 		param.can_suspend_link = false;
791 		break;
792 	}
793 
794 	switch (wow_params->resume_trigger) {
795 	default:
796 		pmo_err("Invalid resume trigger setting: %d",
797 			 wow_params->resume_trigger);
798 		fallthrough;
799 	case PMO_WOW_RESUME_TRIGGER_DEFAULT:
800 	case PMO_WOW_RESUME_TRIGGER_GPIO:
801 		/*
802 		 * GPIO is currently implicit. This means you can't actually
803 		 * force GPIO if a platform's default wake trigger is HTC wakeup
804 		 */
805 		break;
806 	case PMO_WOW_RESUME_TRIGGER_HTC_WAKEUP:
807 		param.flags |= WMI_WOW_FLAG_DO_HTC_WAKEUP;
808 		break;
809 	}
810 
811 	if (psoc_ctx->psoc_cfg.d0_wow_supported &&
812 	    !psoc_ctx->caps.unified_wow &&
813 	    !param.can_suspend_link) {
814 		psoc_ctx->wow.wow_state = pmo_wow_state_legacy_d0;
815 	} else if (param.can_suspend_link) {
816 		psoc_ctx->wow.wow_state = pmo_wow_state_unified_d3;
817 	} else {
818 		psoc_ctx->wow.wow_state = pmo_wow_state_unified_d0;
819 	}
820 
821 	if (htc_can_suspend_link(pmo_core_psoc_get_htc_handle(psoc))) {
822 		if (qdf_is_drv_connected()) {
823 			pmo_info("drv wow is enabled");
824 			param.flags |= WMI_WOW_FLAG_ENABLE_DRV_PCIE_L1SS_SLEEP;
825 		} else {
826 			pmo_debug("non-drv wow is enabled");
827 		}
828 	} else {
829 		pmo_info("Prevent link down, non-drv wow is enabled");
830 		if (hif_ctx) {
831 			hif_rtpm_print_prevent_list();
832 			htc_log_link_user_votes();
833 		}
834 	}
835 	if (wow_params->is_unit_test) {
836 		pmo_info("Unit test WoW, force DRV mode");
837 		param.flags |= WMI_WOW_FLAG_ENABLE_DRV_PCIE_L1SS_SLEEP;
838 	}
839 	if (type == QDF_SYSTEM_SUSPEND) {
840 		pmo_info("system suspend wow");
841 		param.flags |= WMI_WOW_FLAG_SYSTEM_SUSPEND_WOW;
842 	} else if (type == QDF_UNIT_TEST_WOW_SUSPEND) {
843 		pmo_info("unit test wow suspend");
844 	} else {
845 		pmo_debug("RTPM wow");
846 	}
847 
848 	if (psoc_cfg->is_mod_dtim_on_sys_suspend_enabled) {
849 		pmo_debug("mod DTIM enabled");
850 		param.flags |= WMI_WOW_FLAG_MOD_DTIM_ON_SYS_SUSPEND;
851 	}
852 
853 	if (psoc_cfg->sta_forced_dtim) {
854 		pmo_debug("forced DTIM enabled");
855 		param.flags |= WMI_WOW_FLAG_FORCED_DTIM_ON_SYS_SUSPEND;
856 	}
857 	status = pmo_tgt_psoc_send_wow_enable_req(psoc, &param);
858 	if (status != QDF_STATUS_SUCCESS) {
859 		pmo_err("Failed to enable wow in fw");
860 		goto out;
861 	}
862 
863 	pmo_tgt_update_target_suspend_flag(psoc, true);
864 
865 	status = qdf_wait_for_event_completion(&psoc_ctx->wow.target_suspend,
866 					       PMO_TARGET_SUSPEND_TIMEOUT);
867 	if (QDF_IS_STATUS_ERROR(status)) {
868 		if (hif_ctx) {
869 			hif_display_ctrl_traffic_pipes_state(hif_ctx);
870 			hif_display_latest_desc_hist(hif_ctx);
871 		}
872 		pmo_err("Failed to receive WoW Enable Ack from FW");
873 		pmo_err("Credits:%d; Pending_Cmds: %d",
874 			pmo_tgt_psoc_get_host_credits(psoc),
875 			pmo_tgt_psoc_get_pending_cmnds(psoc));
876 		if (!psoc_ctx->wow.target_suspend.force_set) {
877 			pmo_tgt_psoc_set_wow_enable_ack_failed(psoc);
878 			qdf_trigger_self_recovery(psoc, QDF_SUSPEND_TIMEOUT);
879 		}
880 		pmo_tgt_update_target_suspend_flag(psoc, false);
881 		goto out;
882 	}
883 
884 	if (pmo_core_get_wow_nack(psoc_ctx)) {
885 		reason_code = pmo_core_get_wow_reason_code(psoc_ctx);
886 		pmo_err("FW not ready to WOW reason code: %d", reason_code);
887 		pmo_tgt_update_target_suspend_flag(psoc, false);
888 		status = QDF_STATUS_E_AGAIN;
889 		goto out;
890 	}
891 
892 	pmo_tgt_update_target_suspend_acked_flag(psoc, true);
893 
894 	host_credits = pmo_tgt_psoc_get_host_credits(psoc);
895 	wmi_pending_cmds = pmo_tgt_psoc_get_pending_cmnds(psoc);
896 
897 	if (host_credits < PMO_WOW_REQUIRED_CREDITS) {
898 		pmo_err("No Credits after HTC ACK:%d, pending_cmds:%d,"
899 			 "cannot resume back", host_credits, wmi_pending_cmds);
900 		htc_dump_counter_info(pmo_core_psoc_get_htc_handle(psoc));
901 		qdf_trigger_self_recovery(psoc, QDF_SUSPEND_NO_CREDIT);
902 	}
903 	pmo_debug("WOW enabled successfully in fw: credits:%d pending_cmds: %d",
904 		host_credits, wmi_pending_cmds);
905 
906 	hif_latency_detect_timer_stop(pmo_core_psoc_get_hif_handle(psoc));
907 
908 	if (hif_rtpm_get_autosuspend_delay() == WOW_LARGE_RX_RTPM_DELAY)
909 		hif_rtpm_restore_autosuspend_delay();
910 
911 	pmo_core_update_wow_enable_cmd_sent(psoc_ctx, true);
912 
913 out:
914 	return status;
915 }
916 
pmo_core_psoc_suspend_target(struct wlan_objmgr_psoc * psoc,int disable_target_intr)917 QDF_STATUS pmo_core_psoc_suspend_target(struct wlan_objmgr_psoc *psoc,
918 					int disable_target_intr)
919 {
920 	QDF_STATUS status;
921 	struct pmo_suspend_params param;
922 	struct pmo_psoc_priv_obj *psoc_ctx;
923 	void *dp_soc = pmo_core_psoc_get_dp_handle(psoc);
924 
925 	pmo_enter();
926 
927 	psoc_ctx = pmo_psoc_get_priv(psoc);
928 
929 	cdp_process_target_suspend_req(dp_soc, OL_TXRX_PDEV_ID);
930 	qdf_event_reset(&psoc_ctx->wow.target_suspend);
931 	param.disable_target_intr = disable_target_intr;
932 	status = pmo_tgt_psoc_send_supend_req(psoc, &param);
933 	if (status != QDF_STATUS_SUCCESS)
934 		goto out;
935 
936 	pmo_tgt_update_target_suspend_flag(psoc, true);
937 
938 	status = qdf_wait_for_event_completion(&psoc_ctx->wow.target_suspend,
939 					       PMO_TARGET_SUSPEND_TIMEOUT);
940 	if (QDF_IS_STATUS_ERROR(status)) {
941 		pmo_err("Failed to get ACK from firmware for pdev suspend");
942 		pmo_tgt_update_target_suspend_flag(psoc, false);
943 		if (!psoc_ctx->wow.target_suspend.force_set)
944 			qdf_trigger_self_recovery(psoc, QDF_SUSPEND_TIMEOUT);
945 	} else {
946 		pmo_tgt_update_target_suspend_acked_flag(psoc, true);
947 	}
948 
949 out:
950 	pmo_exit();
951 
952 	return status;
953 }
954 
pmo_core_psoc_bus_suspend_req(struct wlan_objmgr_psoc * psoc,enum qdf_suspend_type type,struct pmo_wow_enable_params * wow_params)955 QDF_STATUS pmo_core_psoc_bus_suspend_req(struct wlan_objmgr_psoc *psoc,
956 		enum qdf_suspend_type type,
957 		struct pmo_wow_enable_params *wow_params)
958 {
959 	struct pmo_psoc_priv_obj *psoc_ctx;
960 	QDF_STATUS status;
961 	bool wow_mode_selected = false;
962 	qdf_time_t begin, end;
963 
964 	if (!psoc) {
965 		pmo_err("psoc is NULL");
966 		status = QDF_STATUS_E_NULL_VALUE;
967 		goto out;
968 	}
969 
970 	if (!wow_params) {
971 		pmo_err("wow_params is NULL");
972 		status = QDF_STATUS_E_NULL_VALUE;
973 		goto out;
974 	}
975 
976 	status = pmo_psoc_get_ref(psoc);
977 	if (status != QDF_STATUS_SUCCESS) {
978 		pmo_err("pmo cannot get the reference out of psoc");
979 		goto out;
980 	}
981 
982 	psoc_ctx = pmo_psoc_get_priv(psoc);
983 
984 	wow_mode_selected = pmo_core_is_wow_enabled(psoc_ctx);
985 
986 	begin = qdf_get_log_timestamp_usecs();
987 	if (wow_mode_selected)
988 		status = pmo_core_enable_wow_in_fw(psoc, psoc_ctx,
989 						   wow_params,
990 						   type);
991 	else
992 		status = pmo_core_psoc_suspend_target(psoc, 0);
993 	end = qdf_get_log_timestamp_usecs();
994 	pmo_debug("fw took total time %lu microseconds to enable wow",
995 		  end - begin);
996 
997 	pmo_psoc_put_ref(psoc);
998 out:
999 	return status;
1000 }
1001 
pmo_core_txrx_suspend(struct wlan_objmgr_psoc * psoc)1002 QDF_STATUS pmo_core_txrx_suspend(struct wlan_objmgr_psoc *psoc)
1003 {
1004 	struct pmo_psoc_priv_obj *pmo_ctx;
1005 	QDF_STATUS status;
1006 	void *hif_ctx;
1007 	void *dp_soc;
1008 	int ret;
1009 
1010 	status = pmo_psoc_get_ref(psoc);
1011 	if (QDF_IS_STATUS_ERROR(status)) {
1012 		pmo_err("pmo cannot get the reference out of psoc");
1013 		return status;
1014 	}
1015 
1016 	pmo_ctx = pmo_psoc_get_priv(psoc);
1017 	if (pmo_core_get_wow_state(pmo_ctx) != pmo_wow_state_unified_d3)
1018 		goto out;
1019 
1020 	hif_ctx = pmo_core_psoc_get_hif_handle(psoc);
1021 	dp_soc = pmo_core_psoc_get_dp_handle(psoc);
1022 	if (!hif_ctx || !dp_soc) {
1023 		pmo_err("Invalid ctx hif: %pK, dp: %pK", hif_ctx, dp_soc);
1024 		status = QDF_STATUS_E_INVAL;
1025 		goto out;
1026 	}
1027 
1028 	ret = hif_disable_grp_irqs(hif_ctx);
1029 	if (ret && ret != -EOPNOTSUPP) {
1030 		pmo_err("Prevent suspend, failed to disable grp irqs: %d", ret);
1031 		status =  qdf_status_from_os_return(ret);
1032 		goto out;
1033 	}
1034 
1035 	if (ret == -EOPNOTSUPP) {
1036 		/* For chips, which not support IRQ disable,
1037 		 * drain will not be called, display and check
1038 		 * rings HP/TP once again
1039 		 */
1040 		if (!cdp_display_txrx_hw_info(dp_soc)) {
1041 			pmo_err("Prevent suspend, ring not empty");
1042 			status = QDF_STATUS_E_AGAIN;
1043 		}
1044 
1045 		goto out;
1046 	}
1047 
1048 	status = cdp_drain_txrx(dp_soc, 0);
1049 	if (QDF_IS_STATUS_ERROR(status)) {
1050 		pmo_err("Prevent suspend unable to drain txrx status:%u",
1051 			status);
1052 		ret = hif_enable_grp_irqs(hif_ctx);
1053 		if (ret && ret != -EOPNOTSUPP) {
1054 			pmo_err("Failed to enable grp irqs: %d", ret);
1055 			qdf_trigger_self_recovery(psoc, QDF_ENABLE_IRQ_FAILURE);
1056 		}
1057 		goto out;
1058 	}
1059 
1060 	pmo_ctx->wow.txrx_suspended = true;
1061 out:
1062 	pmo_psoc_put_ref(psoc);
1063 	return status;
1064 }
1065 
pmo_core_txrx_resume(struct wlan_objmgr_psoc * psoc)1066 QDF_STATUS pmo_core_txrx_resume(struct wlan_objmgr_psoc *psoc)
1067 {
1068 	struct pmo_psoc_priv_obj *pmo_ctx;
1069 	QDF_STATUS status;
1070 	void *hif_ctx;
1071 	int ret;
1072 
1073 	status = pmo_psoc_get_ref(psoc);
1074 	if (QDF_IS_STATUS_ERROR(status)) {
1075 		pmo_err("pmo cannot get the reference out of psoc");
1076 		return status;
1077 	}
1078 
1079 	pmo_ctx = pmo_psoc_get_priv(psoc);
1080 	if (!pmo_ctx->wow.txrx_suspended)
1081 		goto out;
1082 
1083 	hif_ctx = pmo_core_psoc_get_hif_handle(psoc);
1084 	if (!hif_ctx) {
1085 		pmo_err("Invalid hif ctx");
1086 		status = QDF_STATUS_E_INVAL;
1087 		goto out;
1088 	}
1089 
1090 	ret = hif_enable_grp_irqs(hif_ctx);
1091 	if (ret && ret != -EOPNOTSUPP) {
1092 		pmo_err("Failed to enable grp irqs: %d", ret);
1093 		status = qdf_status_from_os_return(ret);
1094 		goto out;
1095 	}
1096 
1097 	pmo_ctx->wow.txrx_suspended = false;
1098 out:
1099 	pmo_psoc_put_ref(psoc);
1100 	return status;
1101 }
1102 
1103 #ifdef FEATURE_RUNTIME_PM
1104 #define PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(__condition) ({ \
1105 	typeof(__condition) condition = __condition; \
1106 	if (condition && !qdf_is_fw_down()) \
1107 		QDF_BUG(0); \
1108 })
1109 
pmo_core_psoc_bus_runtime_suspend(struct wlan_objmgr_psoc * psoc,pmo_pld_auto_suspend_cb pld_cb)1110 QDF_STATUS pmo_core_psoc_bus_runtime_suspend(struct wlan_objmgr_psoc *psoc,
1111 					     pmo_pld_auto_suspend_cb pld_cb)
1112 {
1113 	void *hif_ctx;
1114 	void *dp_soc;
1115 	uint8_t pdev_id;
1116 	void *htc_ctx;
1117 	QDF_STATUS status;
1118 	int ret;
1119 	struct pmo_wow_enable_params wow_params = {0};
1120 	struct pmo_psoc_priv_obj *psoc_ctx;
1121 	qdf_time_t begin, end;
1122 	int pending;
1123 
1124 	pmo_enter();
1125 
1126 	if (!psoc) {
1127 		pmo_err("psoc is NULL");
1128 		status = QDF_STATUS_E_INVAL;
1129 		goto out;
1130 	}
1131 
1132 	status = pmo_psoc_get_ref(psoc);
1133 	if (status != QDF_STATUS_SUCCESS) {
1134 		pmo_err("pmo cannot get the reference out of psoc");
1135 		goto out;
1136 	}
1137 
1138 	hif_ctx = pmo_core_psoc_get_hif_handle(psoc);
1139 	dp_soc = pmo_core_psoc_get_dp_handle(psoc);
1140 	pdev_id = pmo_core_psoc_get_txrx_handle(psoc);
1141 	htc_ctx = pmo_core_psoc_get_htc_handle(psoc);
1142 	if (!hif_ctx || !dp_soc || !htc_ctx ||
1143 	    pdev_id == OL_TXRX_INVALID_PDEV_ID) {
1144 		pmo_err("Invalid hif: %pK, dp: %pK, pdev_id: %d, htc: %pK",
1145 			hif_ctx, dp_soc, pdev_id, htc_ctx);
1146 		status = QDF_STATUS_E_INVAL;
1147 		goto dec_psoc_ref;
1148 	}
1149 
1150 	wow_params.interface_pause = PMO_WOW_INTERFACE_PAUSE_ENABLE;
1151 	wow_params.resume_trigger = PMO_WOW_RESUME_TRIGGER_GPIO;
1152 
1153 	ret = hif_pre_runtime_suspend(hif_ctx);
1154 	if (ret) {
1155 		status = qdf_status_from_os_return(ret);
1156 		goto runtime_failure;
1157 	}
1158 
1159 	status = wlan_dp_runtime_suspend(dp_soc, pdev_id);
1160 	if (status != QDF_STATUS_SUCCESS)
1161 		goto runtime_failure;
1162 
1163 	ret = htc_runtime_suspend(htc_ctx);
1164 	if (ret) {
1165 		status = qdf_status_from_os_return(ret);
1166 		goto dp_runtime_resume;
1167 	}
1168 
1169 	status = pmo_tgt_psoc_set_runtime_pm_inprogress(psoc, true);
1170 	if (status != QDF_STATUS_SUCCESS)
1171 		goto resume_htc;
1172 
1173 	status = pmo_core_psoc_configure_suspend(psoc, true);
1174 	if (status != QDF_STATUS_SUCCESS)
1175 		goto resume_htc;
1176 
1177 	status = pmo_core_psoc_bus_suspend_req(psoc, QDF_RUNTIME_SUSPEND,
1178 					       &wow_params);
1179 	if (status != QDF_STATUS_SUCCESS)
1180 		goto pmo_resume_configure;
1181 
1182 	ret = hif_runtime_suspend(hif_ctx);
1183 	if (ret) {
1184 		status = qdf_status_from_os_return(ret);
1185 		goto pmo_bus_resume;
1186 	}
1187 
1188 	status = pmo_core_txrx_suspend(psoc);
1189 	if (QDF_IS_STATUS_ERROR(status))
1190 		goto resume_hif;
1191 
1192 	pending = cdp_rx_get_pending(cds_get_context(QDF_MODULE_ID_SOC));
1193 	if (pending) {
1194 		pmo_debug("Prevent suspend, RX frame pending %d", pending);
1195 		status = QDF_STATUS_E_BUSY;
1196 		goto resume_txrx;
1197 	}
1198 
1199 	if (pld_cb) {
1200 		begin = qdf_get_log_timestamp_usecs();
1201 		ret = pld_cb();
1202 		end = qdf_get_log_timestamp_usecs();
1203 		pmo_debug("runtime pci bus suspend took total time %lu microseconds",
1204 			  end - begin);
1205 
1206 		if (ret) {
1207 			status = qdf_status_from_os_return(ret);
1208 			goto resume_txrx;
1209 		}
1210 	}
1211 
1212 	if (hif_pm_get_wake_irq_type(hif_ctx) == HIF_PM_CE_WAKE) {
1213 		/*
1214 		 * In moselle, there is no separate interrupt for wake_irq,
1215 		 * shares CE interrupt, there is a chance of wow wakeup
1216 		 * while suspend is in-progress, so handling such scenario
1217 		 */
1218 		hif_rtpm_suspend_lock();
1219 		psoc_ctx = pmo_psoc_get_priv(psoc);
1220 		if (pmo_core_get_wow_initial_wake_up(psoc_ctx)) {
1221 			hif_rtpm_suspend_unlock();
1222 			pmo_err("Target wake up received before suspend completion");
1223 			status = QDF_STATUS_E_BUSY;
1224 			goto resume_txrx;
1225 		}
1226 		hif_process_runtime_suspend_success();
1227 		hif_rtpm_suspend_unlock();
1228 	} else {
1229 		hif_process_runtime_suspend_success();
1230 	}
1231 
1232 	if (hif_try_prevent_ep_vote_access(hif_ctx)) {
1233 		pmo_debug("Prevent suspend, ep work pending");
1234 		status = QDF_STATUS_E_BUSY;
1235 		goto resume_txrx;
1236 	}
1237 
1238 	goto dec_psoc_ref;
1239 
1240 resume_txrx:
1241 	PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(QDF_STATUS_SUCCESS !=
1242 		pmo_core_txrx_resume(psoc));
1243 
1244 resume_hif:
1245 	PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(hif_runtime_resume(hif_ctx));
1246 
1247 pmo_bus_resume:
1248 	PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(QDF_STATUS_SUCCESS !=
1249 		pmo_core_psoc_bus_resume_req(psoc, QDF_RUNTIME_SUSPEND));
1250 
1251 pmo_resume_configure:
1252 	PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(QDF_STATUS_SUCCESS !=
1253 		pmo_core_psoc_configure_resume(psoc, true));
1254 
1255 resume_htc:
1256 	PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(QDF_STATUS_SUCCESS !=
1257 		pmo_tgt_psoc_set_runtime_pm_inprogress(psoc, false));
1258 
1259 dp_runtime_resume:
1260 	PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(QDF_STATUS_SUCCESS !=
1261 		wlan_dp_runtime_resume(dp_soc, pdev_id));
1262 
1263 runtime_failure:
1264 	hif_process_runtime_suspend_failure();
1265 
1266 /* always make sure HTC queue kicker is at the end, so if any
1267  * cmd is pending during suspending, it can re-trigger if suspend
1268  * failure.
1269  */
1270 PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(htc_runtime_resume(htc_ctx));
1271 
1272 dec_psoc_ref:
1273 	pmo_psoc_put_ref(psoc);
1274 
1275 out:
1276 	pmo_exit();
1277 
1278 	return status;
1279 }
1280 
pmo_core_psoc_bus_runtime_resume(struct wlan_objmgr_psoc * psoc,pmo_pld_auto_resume_cb pld_cb)1281 QDF_STATUS pmo_core_psoc_bus_runtime_resume(struct wlan_objmgr_psoc *psoc,
1282 					    pmo_pld_auto_resume_cb pld_cb)
1283 {
1284 	int ret;
1285 	void *hif_ctx;
1286 	void *dp_soc;
1287 	uint8_t pdev_id;
1288 	void *htc_ctx;
1289 	QDF_STATUS status;
1290 	qdf_time_t begin, end;
1291 
1292 	pmo_enter();
1293 
1294 	if (!psoc) {
1295 		pmo_err("psoc is NULL");
1296 		status = QDF_STATUS_E_INVAL;
1297 		goto out;
1298 	}
1299 
1300 	status = pmo_psoc_get_ref(psoc);
1301 	if (status != QDF_STATUS_SUCCESS) {
1302 		pmo_err("pmo cannot get the reference out of psoc");
1303 		goto out;
1304 	}
1305 
1306 	hif_ctx = pmo_core_psoc_get_hif_handle(psoc);
1307 	dp_soc = pmo_core_psoc_get_dp_handle(psoc);
1308 	pdev_id = pmo_core_psoc_get_txrx_handle(psoc);
1309 	htc_ctx = pmo_core_psoc_get_htc_handle(psoc);
1310 	if (!hif_ctx || !dp_soc || !htc_ctx ||
1311 	    pdev_id == OL_TXRX_INVALID_PDEV_ID) {
1312 		pmo_err("Invalid hif: %pK, dp: %pK, pdev_id: %d, htc: %pK",
1313 			hif_ctx, dp_soc, pdev_id, htc_ctx);
1314 		status = QDF_STATUS_E_INVAL;
1315 		goto dec_psoc_ref;
1316 	}
1317 
1318 	hif_pre_runtime_resume();
1319 	if (pld_cb) {
1320 		begin = qdf_get_log_timestamp_usecs();
1321 		ret = pld_cb();
1322 		end = qdf_get_log_timestamp_usecs();
1323 		pmo_debug("pci bus resume took total time %lu microseconds",
1324 			  end - begin);
1325 		if (ret) {
1326 			status = QDF_STATUS_E_FAILURE;
1327 			goto fail;
1328 		}
1329 	}
1330 
1331 	if (hif_runtime_resume(hif_ctx)) {
1332 		status = QDF_STATUS_E_FAILURE;
1333 		goto fail;
1334 	}
1335 
1336 	status = pmo_core_psoc_bus_resume_req(psoc, QDF_RUNTIME_SUSPEND);
1337 	if (status != QDF_STATUS_SUCCESS)
1338 		goto fail;
1339 
1340 	status = pmo_core_txrx_resume(psoc);
1341 	if (QDF_IS_STATUS_ERROR(status))
1342 		goto fail;
1343 
1344 	hif_process_runtime_resume_linkup();
1345 
1346 	status = pmo_core_psoc_configure_resume(psoc, true);
1347 	if (status != QDF_STATUS_SUCCESS)
1348 		goto fail;
1349 
1350 	status = pmo_tgt_psoc_set_runtime_pm_inprogress(psoc, false);
1351 	if (status != QDF_STATUS_SUCCESS)
1352 		goto fail;
1353 
1354 	hif_process_runtime_resume_success();
1355 
1356 	if (htc_runtime_resume(htc_ctx)) {
1357 		status = QDF_STATUS_E_FAILURE;
1358 		goto fail;
1359 	}
1360 
1361 	status = wlan_dp_runtime_resume(dp_soc, pdev_id);
1362 	if (status != QDF_STATUS_SUCCESS)
1363 		goto fail;
1364 
1365 fail:
1366 	if (status != QDF_STATUS_SUCCESS)
1367 		qdf_trigger_self_recovery(psoc, QDF_RESUME_TIMEOUT);
1368 
1369 dec_psoc_ref:
1370 	pmo_psoc_put_ref(psoc);
1371 
1372 out:
1373 	return status;
1374 }
1375 #endif
1376 
1377 /**
1378  * pmo_core_psoc_send_host_wakeup_ind_to_fw() - send wakeup ind to fw
1379  * @psoc: objmgr psoc handle
1380  * @psoc_ctx: pmo psoc private context
1381  *
1382  * Sends host wakeup indication to FW. On receiving this indication,
1383  * FW will come out of WOW.
1384  *
1385  * Return: QDF status
1386  */
1387 static
pmo_core_psoc_send_host_wakeup_ind_to_fw(struct wlan_objmgr_psoc * psoc,struct pmo_psoc_priv_obj * psoc_ctx)1388 QDF_STATUS pmo_core_psoc_send_host_wakeup_ind_to_fw(
1389 			struct wlan_objmgr_psoc *psoc,
1390 			struct pmo_psoc_priv_obj *psoc_ctx)
1391 {
1392 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1393 	void *hif_ctx;
1394 
1395 	hif_ctx = pmo_core_psoc_get_hif_handle(psoc);
1396 
1397 	if (!hif_ctx) {
1398 		pmo_err("hif_ctx is NULL");
1399 		status = QDF_STATUS_E_INVAL;
1400 		goto out;
1401 	}
1402 
1403 	hif_set_ep_intermediate_vote_access(hif_ctx);
1404 
1405 	qdf_event_reset(&psoc_ctx->wow.target_resume);
1406 
1407 	status = pmo_tgt_psoc_send_host_wakeup_ind(psoc);
1408 	if (status) {
1409 		hif_set_ep_vote_access(hif_ctx,
1410 				       HIF_EP_VOTE_NONDP_ACCESS,
1411 				       HIF_EP_VOTE_ACCESS_DISABLE);
1412 		status = QDF_STATUS_E_FAILURE;
1413 		goto out;
1414 	}
1415 	pmo_info("Host wakeup indication sent to fw");
1416 
1417 	status = qdf_wait_for_event_completion(&psoc_ctx->wow.target_resume,
1418 					PMO_RESUME_TIMEOUT);
1419 	if (status != QDF_STATUS_SUCCESS) {
1420 		pmo_err("Timeout waiting for resume event from FW");
1421 		pmo_err("Pending commands %d credits %d",
1422 			pmo_tgt_psoc_get_pending_cmnds(psoc),
1423 			pmo_tgt_psoc_get_host_credits(psoc));
1424 
1425 		if (!psoc_ctx->wow.target_resume.force_set)
1426 			qdf_trigger_self_recovery(psoc, QDF_RESUME_TIMEOUT);
1427 	} else {
1428 		pmo_debug("Host wakeup received");
1429 		pmo_tgt_update_target_suspend_flag(psoc, false);
1430 		pmo_tgt_update_target_suspend_acked_flag(psoc, false);
1431 		hif_set_ep_vote_access(hif_ctx,
1432 				       HIF_EP_VOTE_NONDP_ACCESS,
1433 				       HIF_EP_VOTE_ACCESS_ENABLE);
1434 		hif_set_ep_vote_access(hif_ctx,
1435 				       HIF_EP_VOTE_DP_ACCESS,
1436 				       HIF_EP_VOTE_ACCESS_ENABLE);
1437 	}
1438 out:
1439 	return status;
1440 }
1441 
1442 /**
1443  * pmo_core_psoc_disable_wow_in_fw() -  Disable wow in bus resume context.
1444  * @psoc: objmgr psoc handle
1445  * @psoc_ctx: pmo psoc private context
1446  *
1447  * Return: QDF_STATUS_SUCCESS for success or error code
1448  */
1449 static
pmo_core_psoc_disable_wow_in_fw(struct wlan_objmgr_psoc * psoc,struct pmo_psoc_priv_obj * psoc_ctx)1450 QDF_STATUS pmo_core_psoc_disable_wow_in_fw(struct wlan_objmgr_psoc *psoc,
1451 			struct pmo_psoc_priv_obj *psoc_ctx)
1452 {
1453 	QDF_STATUS ret;
1454 
1455 	ret = pmo_core_psoc_send_host_wakeup_ind_to_fw(psoc, psoc_ctx);
1456 	if (ret != QDF_STATUS_SUCCESS)
1457 		goto out;
1458 
1459 	pmo_core_update_wow_enable_cmd_sent(psoc_ctx, false);
1460 
1461 	/* To allow the tx pause/unpause events */
1462 	pmo_core_update_wow_bus_suspend(psoc, psoc_ctx, false);
1463 	/* Unpause the vdev as we are resuming */
1464 	pmo_unpause_all_vdev(psoc, psoc_ctx);
1465 out:
1466 	return ret;
1467 }
1468 
1469 /**
1470  * pmo_core_psoc_resume_target() - resume target
1471  * @psoc: objmgr psoc handle
1472  * @psoc_ctx: pmo psoc private context
1473  *
1474  * Return: QDF_STATUS_SUCCESS for success or error code
1475  */
1476 static
pmo_core_psoc_resume_target(struct wlan_objmgr_psoc * psoc,struct pmo_psoc_priv_obj * psoc_ctx)1477 QDF_STATUS pmo_core_psoc_resume_target(struct wlan_objmgr_psoc *psoc,
1478 		struct pmo_psoc_priv_obj *psoc_ctx)
1479 {
1480 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1481 
1482 	qdf_event_reset(&psoc_ctx->wow.target_resume);
1483 
1484 	status = pmo_tgt_psoc_send_target_resume_req(psoc);
1485 	if (status != QDF_STATUS_SUCCESS) {
1486 		status = QDF_STATUS_E_FAILURE;
1487 		goto out;
1488 	}
1489 
1490 	status = qdf_wait_single_event(&psoc_ctx->wow.target_resume,
1491 			PMO_RESUME_TIMEOUT);
1492 	if (status != QDF_STATUS_SUCCESS) {
1493 		pmo_fatal("Timeout waiting for resume event from FW");
1494 		pmo_fatal("Pending commands %d credits %d",
1495 			pmo_tgt_psoc_get_pending_cmnds(psoc),
1496 			pmo_tgt_psoc_get_host_credits(psoc));
1497 		if (!psoc_ctx->wow.target_resume.force_set)
1498 			qdf_trigger_self_recovery(psoc, QDF_RESUME_TIMEOUT);
1499 	} else {
1500 		pmo_debug("Host wakeup received");
1501 		pmo_tgt_update_target_suspend_flag(psoc, false);
1502 		pmo_tgt_update_target_suspend_acked_flag(psoc, false);
1503 	}
1504 out:
1505 	return status;
1506 }
1507 
pmo_core_psoc_bus_resume_req(struct wlan_objmgr_psoc * psoc,enum qdf_suspend_type type)1508 QDF_STATUS pmo_core_psoc_bus_resume_req(struct wlan_objmgr_psoc *psoc,
1509 		enum qdf_suspend_type type)
1510 {
1511 	struct pmo_psoc_priv_obj *psoc_ctx;
1512 	bool wow_mode;
1513 	QDF_STATUS status;
1514 	qdf_time_t begin, end;
1515 
1516 	if (!psoc) {
1517 		pmo_err("psoc is null");
1518 		status = QDF_STATUS_E_NULL_VALUE;
1519 		goto out;
1520 	}
1521 
1522 	status = pmo_psoc_get_ref(psoc);
1523 	if (status != QDF_STATUS_SUCCESS) {
1524 		pmo_err("pmo cannot get the reference out of psoc");
1525 		goto out;
1526 	}
1527 
1528 	hif_latency_detect_timer_start(pmo_core_psoc_get_hif_handle(psoc));
1529 
1530 	psoc_ctx = pmo_psoc_get_priv(psoc);
1531 	wow_mode = pmo_core_is_wow_enabled(psoc_ctx);
1532 	pmo_debug("wow mode %d", wow_mode);
1533 
1534 	pmo_core_update_wow_initial_wake_up(psoc_ctx, 0);
1535 
1536 	/* If target was not suspended, bail out */
1537 	if (qdf_is_fw_down() || !pmo_tgt_is_target_suspended(psoc)) {
1538 		pmo_psoc_put_ref(psoc);
1539 		status = QDF_STATUS_E_AGAIN;
1540 		goto out;
1541 	}
1542 
1543 	begin = qdf_get_log_timestamp_usecs();
1544 	if (wow_mode)
1545 		status = pmo_core_psoc_disable_wow_in_fw(psoc, psoc_ctx);
1546 	else
1547 		status = pmo_core_psoc_resume_target(psoc, psoc_ctx);
1548 	end = qdf_get_log_timestamp_usecs();
1549 	pmo_debug("fw took total time %lu microseconds to disable wow",
1550 		  end - begin);
1551 
1552 	pmo_psoc_put_ref(psoc);
1553 
1554 out:
1555 	return status;
1556 }
1557 
pmo_core_psoc_target_suspend_acknowledge(void * context,bool wow_nack,uint16_t reason_code)1558 void pmo_core_psoc_target_suspend_acknowledge(void *context, bool wow_nack,
1559 					      uint16_t reason_code)
1560 {
1561 	struct pmo_psoc_priv_obj *psoc_ctx;
1562 	struct wlan_objmgr_psoc *psoc = (struct wlan_objmgr_psoc *)context;
1563 	void *dp_soc = pmo_core_psoc_get_dp_handle(psoc);
1564 	QDF_STATUS status;
1565 
1566 	if (!psoc) {
1567 		pmo_err("psoc is null");
1568 		goto out;
1569 	}
1570 
1571 	status = pmo_psoc_get_ref(psoc);
1572 	if (status != QDF_STATUS_SUCCESS) {
1573 		pmo_err("Failed to get psoc reference");
1574 		goto out;
1575 	}
1576 
1577 	psoc_ctx = pmo_psoc_get_priv(psoc);
1578 
1579 	pmo_core_set_wow_nack(psoc_ctx, wow_nack, reason_code);
1580 	qdf_event_set(&psoc_ctx->wow.target_suspend);
1581 	if (!pmo_tgt_psoc_get_runtime_pm_in_progress(psoc)) {
1582 		if (wow_nack)
1583 			qdf_wake_lock_timeout_acquire(
1584 				&psoc_ctx->wow.wow_wake_lock,
1585 				PMO_WAKE_LOCK_TIMEOUT);
1586 		else
1587 			cdp_process_wow_ack_rsp(dp_soc, OL_TXRX_PDEV_ID);
1588 	}
1589 
1590 	pmo_psoc_put_ref(psoc);
1591 out:
1592 	pmo_exit();
1593 }
1594 
pmo_core_psoc_wakeup_host_event_received(struct wlan_objmgr_psoc * psoc)1595 void pmo_core_psoc_wakeup_host_event_received(struct wlan_objmgr_psoc *psoc)
1596 {
1597 	struct pmo_psoc_priv_obj *psoc_ctx;
1598 
1599 	if (!psoc) {
1600 		pmo_err("psoc is null");
1601 		return;
1602 	}
1603 
1604 	psoc_ctx = pmo_psoc_get_priv(psoc);
1605 	psoc_ctx->wow.wow_state = pmo_wow_state_none;
1606 	qdf_event_set(&psoc_ctx->wow.target_resume);
1607 }
1608 
pmo_core_psoc_is_target_wake_up_received(struct wlan_objmgr_psoc * psoc)1609 int pmo_core_psoc_is_target_wake_up_received(struct wlan_objmgr_psoc *psoc)
1610 {
1611 	struct pmo_psoc_priv_obj *psoc_ctx;
1612 	int ret = 0;
1613 	QDF_STATUS status;
1614 
1615 	if (!psoc) {
1616 		pmo_err("psoc is NULL");
1617 		ret = -EAGAIN;
1618 		goto out;
1619 	}
1620 
1621 	status = pmo_psoc_get_ref(psoc);
1622 	if (status != QDF_STATUS_SUCCESS) {
1623 		pmo_err("Failed to get psoc reference");
1624 		ret = -EAGAIN;
1625 		goto out;
1626 	}
1627 
1628 	psoc_ctx = pmo_psoc_get_priv(psoc);
1629 	if (pmo_core_get_wow_initial_wake_up(psoc_ctx)) {
1630 		pmo_err("Target initial wake up received try again");
1631 		ret = -EAGAIN;
1632 	}
1633 
1634 	pmo_psoc_put_ref(psoc);
1635 out:
1636 	pmo_exit();
1637 
1638 	return ret;
1639 }
1640 
1641 
pmo_core_psoc_clear_target_wake_up(struct wlan_objmgr_psoc * psoc)1642 int pmo_core_psoc_clear_target_wake_up(struct wlan_objmgr_psoc *psoc)
1643 {
1644 	struct pmo_psoc_priv_obj *psoc_ctx;
1645 	int ret = 0;
1646 	QDF_STATUS status;
1647 
1648 	if (!psoc) {
1649 		pmo_err("psoc is NULL");
1650 		ret = -EAGAIN;
1651 		goto out;
1652 	}
1653 
1654 	status = pmo_psoc_get_ref(psoc);
1655 	if (status != QDF_STATUS_SUCCESS) {
1656 		pmo_err("Failed to get psoc reference");
1657 		ret = -EAGAIN;
1658 		goto out;
1659 	}
1660 
1661 	psoc_ctx = pmo_psoc_get_priv(psoc);
1662 	pmo_core_update_wow_initial_wake_up(psoc_ctx, 0);
1663 
1664 	pmo_psoc_put_ref(psoc);
1665 out:
1666 	return ret;
1667 }
1668 
pmo_core_psoc_handle_initial_wake_up(void * cb_ctx)1669 void pmo_core_psoc_handle_initial_wake_up(void *cb_ctx)
1670 {
1671 	struct pmo_psoc_priv_obj *psoc_ctx;
1672 	struct wlan_objmgr_psoc *psoc = (struct wlan_objmgr_psoc *)cb_ctx;
1673 	void *hif_ctx;
1674 
1675 	if (!psoc) {
1676 		pmo_err("cb ctx/psoc is null");
1677 		return;
1678 	}
1679 
1680 	psoc_ctx = pmo_psoc_get_priv(psoc);
1681 	hif_ctx = psoc_ctx->hif_hdl;
1682 	if (!hif_ctx)
1683 		pmo_err("hif ctx is null, request resume not called");
1684 	else if(hif_pm_get_wake_irq_type(hif_ctx) == HIF_PM_CE_WAKE)
1685 		hif_rtpm_check_and_request_resume(true);
1686 
1687 	pmo_core_update_wow_initial_wake_up(psoc_ctx, 1);
1688 }
1689 
pmo_core_config_listen_interval(struct wlan_objmgr_vdev * vdev,uint32_t new_li)1690 QDF_STATUS pmo_core_config_listen_interval(struct wlan_objmgr_vdev *vdev,
1691 					   uint32_t new_li)
1692 {
1693 	QDF_STATUS status;
1694 	uint8_t vdev_id;
1695 	uint32_t listen_interval;
1696 	struct pmo_vdev_priv_obj *vdev_ctx;
1697 	struct pmo_psoc_priv_obj *psoc_ctx;
1698 	struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev);
1699 
1700 	pmo_enter();
1701 
1702 	status = pmo_vdev_get_ref(vdev);
1703 	if (QDF_IS_STATUS_ERROR(status))
1704 		goto out;
1705 
1706 	vdev_ctx = pmo_vdev_get_priv(vdev);
1707 	vdev_id =  pmo_vdev_get_id(vdev);
1708 
1709 	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
1710 	if (vdev_ctx->dyn_listen_interval == new_li) {
1711 		qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
1712 		status = QDF_STATUS_SUCCESS;
1713 		pmo_debug("Listen Interval(%d) already set for vdev id %d",
1714 			new_li, vdev_id);
1715 		goto dec_ref;
1716 	}
1717 
1718 	vdev_ctx->dyn_listen_interval = new_li;
1719 	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
1720 
1721 	listen_interval = new_li ? new_li : cfg_default(CFG_LISTEN_INTERVAL);
1722 
1723 	if (!new_li) {
1724 		/* Configure default LI as we do on resume */
1725 		pmo_psoc_with_ctx(pmo_vdev_get_psoc(vdev), psoc_ctx) {
1726 			if (QDF_IS_STATUS_ERROR(
1727 				ucfg_mlme_get_listen_interval(psoc,
1728 							   &listen_interval))) {
1729 				pmo_err("Failed to get listen interval");
1730 				listen_interval =
1731 					       cfg_default(CFG_LISTEN_INTERVAL);
1732 			}
1733 		}
1734 	}
1735 
1736 	pmo_debug("Set Listen Interval %d for vdevId %d", listen_interval,
1737 			vdev_id);
1738 	ucfg_mlme_set_sap_listen_interval(psoc, listen_interval);
1739 	status = pmo_tgt_vdev_update_param_req(vdev,
1740 					       pmo_vdev_param_listen_interval,
1741 					       listen_interval);
1742 	if (QDF_IS_STATUS_ERROR(status)) {
1743 		/* even it fails continue fwr will take default LI */
1744 		pmo_err("Failed to Set Listen Interval");
1745 	}
1746 
1747 	/* Set it to Normal DTIM */
1748 	status = pmo_tgt_vdev_update_param_req(vdev,
1749 					       pmo_vdev_param_dtim_policy,
1750 					       pmo_normal_dtim);
1751 	if (QDF_IS_STATUS_ERROR(status)) {
1752 		pmo_err("Failed to set Normal DTIM for vdev id %d", vdev_id);
1753 	} else {
1754 		pmo_debug("Set DTIM Policy to Normal for vdev id %d", vdev_id);
1755 		pmo_core_vdev_set_restore_dtim(vdev, true);
1756 	}
1757 
1758 dec_ref:
1759 	wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
1760 out:
1761 	pmo_exit();
1762 
1763 	return status;
1764 }
1765 
1766 #ifdef WLAN_FEATURE_IGMP_OFFLOAD
1767 QDF_STATUS
pmo_core_enable_igmp_offload(struct wlan_objmgr_vdev * vdev,struct pmo_igmp_offload_req * pmo_igmp_req)1768 pmo_core_enable_igmp_offload(struct wlan_objmgr_vdev *vdev,
1769 			     struct pmo_igmp_offload_req *pmo_igmp_req)
1770 {
1771 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1772 	uint8_t vdev_id;
1773 	enum QDF_OPMODE op_mode;
1774 	struct pmo_vdev_priv_obj *vdev_ctx;
1775 	uint32_t version_support;
1776 
1777 	if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS)
1778 		return QDF_STATUS_E_INVAL;
1779 
1780 	op_mode = pmo_get_vdev_opmode(vdev);
1781 	if (QDF_STA_MODE != op_mode) {
1782 		pmo_debug("igmp offload supported in STA mode");
1783 		return QDF_STATUS_E_INVAL;
1784 	}
1785 
1786 	vdev_ctx = pmo_vdev_get_priv(vdev);
1787 	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
1788 	if (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.igmp_offload_enable) {
1789 		pmo_debug("igmp offload not supported");
1790 		qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
1791 		return QDF_STATUS_E_NOSUPPORT;
1792 	}
1793 	version_support =
1794 		vdev_ctx->pmo_psoc_ctx->psoc_cfg.igmp_version_support;
1795 	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
1796 	vdev_id = pmo_vdev_get_id(vdev);
1797 	pmo_igmp_req->vdev_id = vdev_id;
1798 	pmo_igmp_req->version_support = version_support;
1799 	status = pmo_tgt_send_igmp_offload_req(vdev, pmo_igmp_req);
1800 
1801 	return status;
1802 }
1803 #endif
1804 
pmo_core_config_forced_dtim(struct wlan_objmgr_vdev * vdev,uint32_t dynamic_dtim)1805 QDF_STATUS pmo_core_config_forced_dtim(struct wlan_objmgr_vdev *vdev,
1806 				       uint32_t dynamic_dtim)
1807 {
1808 	struct pmo_vdev_priv_obj *vdev_ctx;
1809 	uint8_t vdev_id;
1810 	QDF_STATUS status;
1811 
1812 	vdev_id = pmo_vdev_get_id(vdev);
1813 	vdev_ctx = pmo_vdev_get_priv(vdev);
1814 
1815 	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
1816 	vdev_ctx->dyn_modulated_dtim = dynamic_dtim;
1817 	vdev_ctx->dyn_modulated_dtim_enabled = dynamic_dtim >= 1;
1818 	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
1819 
1820 	status = pmo_tgt_vdev_update_param_req(vdev,
1821 					       pmo_vdev_param_forced_dtim_count,
1822 					       dynamic_dtim);
1823 
1824 	if (QDF_IS_STATUS_ERROR(status)) {
1825 		pmo_err("Failed to set forced DTIM for vdev id %d",
1826 			vdev_id);
1827 	}
1828 
1829 	wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
1830 	return status;
1831 }
1832 
1833 static QDF_STATUS
pmo_core_config_non_li_offload_modulated_dtim(struct wlan_objmgr_vdev * vdev,uint32_t mod_dtim)1834 pmo_core_config_non_li_offload_modulated_dtim(struct wlan_objmgr_vdev *vdev,
1835 					      uint32_t mod_dtim)
1836 {
1837 	struct pmo_vdev_priv_obj *vdev_ctx;
1838 	struct pmo_psoc_cfg *psoc_cfg;
1839 	bool prev_dtim_enabled;
1840 	uint32_t listen_interval;
1841 	uint32_t beacon_interval_mod;
1842 	uint32_t max_mod_dtim;
1843 	QDF_STATUS status;
1844 	uint8_t vdev_id;
1845 	uint32_t max_dtim;
1846 
1847 	pmo_enter();
1848 
1849 	status = pmo_vdev_get_ref(vdev);
1850 	if (status != QDF_STATUS_SUCCESS)
1851 		goto out;
1852 
1853 	vdev_id = pmo_vdev_get_id(vdev);
1854 	vdev_ctx = pmo_vdev_get_priv(vdev);
1855 	psoc_cfg = &vdev_ctx->pmo_psoc_ctx->psoc_cfg;
1856 
1857 	if (psoc_cfg->sta_forced_dtim)
1858 		return pmo_core_config_forced_dtim(vdev, mod_dtim);
1859 
1860 	/* Calculate Maximum allowed modulated DTIM */
1861 	beacon_interval_mod =
1862 		pmo_core_get_vdev_beacon_interval(vdev) / 100;
1863 	if (!beacon_interval_mod)
1864 		beacon_interval_mod = 1;
1865 
1866 	max_dtim = (pmo_core_get_vdev_dtim_period(vdev)
1867 		 * beacon_interval_mod);
1868 
1869 	if (!max_dtim) {
1870 		pmo_err("Invalid dtim period");
1871 		wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
1872 		return QDF_STATUS_E_INVAL;
1873 	}
1874 
1875 	max_mod_dtim = psoc_cfg->sta_max_li_mod_dtim /
1876 		max_dtim;
1877 
1878 	if (!max_mod_dtim)
1879 		max_mod_dtim = 1;
1880 
1881 	/* Calculate Listen Interval from provided mod DTIM */
1882 	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
1883 	vdev_ctx->dyn_modulated_dtim = mod_dtim;
1884 	prev_dtim_enabled = vdev_ctx->dyn_modulated_dtim_enabled;
1885 	vdev_ctx->dyn_modulated_dtim_enabled = mod_dtim != 1;
1886 	if (vdev_ctx->dyn_modulated_dtim > max_mod_dtim) {
1887 		listen_interval = max_mod_dtim *
1888 			pmo_core_get_vdev_dtim_period(vdev);
1889 	} else {
1890 		listen_interval = vdev_ctx->dyn_modulated_dtim  *
1891 			pmo_core_get_vdev_dtim_period(vdev);
1892 	}
1893 	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
1894 
1895 	if (prev_dtim_enabled || mod_dtim != 1) {
1896 		status = pmo_tgt_vdev_update_param_req(vdev,
1897 					pmo_vdev_param_listen_interval,
1898 					listen_interval);
1899 		if (QDF_IS_STATUS_ERROR(status))
1900 			/* even it fails continue fwr will take default LI */
1901 			pmo_err("Failed to set Listen Interval for vdev id %d",
1902 				vdev_id);
1903 		else
1904 			pmo_debug("Set Listen Interval %d for  vdev id %d",
1905 				  listen_interval, vdev_id);
1906 
1907 		status = pmo_tgt_vdev_update_param_req(vdev,
1908 				pmo_vdev_param_dtim_policy,
1909 				pmo_normal_dtim);
1910 		if (QDF_IS_STATUS_ERROR(status)) {
1911 			pmo_err("Failed to set Normal DTIM for vdev id %d",
1912 				vdev_id);
1913 		} else {
1914 			pmo_debug("Set DTIM Policy to Normal for vdev id %d",
1915 				  vdev_id);
1916 			pmo_core_vdev_set_restore_dtim(vdev, true);
1917 		}
1918 	}
1919 
1920 	wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
1921 out:
1922 	pmo_exit();
1923 	return status;
1924 }
1925 
1926 static QDF_STATUS
pmo_core_config_li_offload_modulated_dtim(struct wlan_objmgr_vdev * vdev,uint32_t mod_dtim)1927 pmo_core_config_li_offload_modulated_dtim(struct wlan_objmgr_vdev *vdev,
1928 					  uint32_t mod_dtim)
1929 {
1930 	struct pmo_vdev_priv_obj *vdev_ctx;
1931 	struct pmo_psoc_cfg *psoc_cfg;
1932 	QDF_STATUS status;
1933 	uint8_t vdev_id;
1934 
1935 	pmo_enter();
1936 
1937 	status = pmo_vdev_get_ref(vdev);
1938 	if (status != QDF_STATUS_SUCCESS)
1939 		goto out;
1940 
1941 	vdev_id = pmo_vdev_get_id(vdev);
1942 	vdev_ctx = pmo_vdev_get_priv(vdev);
1943 	psoc_cfg = &vdev_ctx->pmo_psoc_ctx->psoc_cfg;
1944 
1945 	if (mod_dtim > psoc_cfg->sta_max_li_mod_dtim)
1946 		mod_dtim = psoc_cfg->sta_max_li_mod_dtim;
1947 	pmo_core_vdev_set_moddtim_user(vdev, mod_dtim);
1948 	pmo_core_vdev_set_moddtim_user_enabled(vdev, true);
1949 
1950 	if (!ucfg_pmo_is_vdev_connected(vdev)) {
1951 		pmo_core_vdev_set_moddtim_user_active(vdev, false);
1952 		wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
1953 		goto out;
1954 	}
1955 
1956 	status = pmo_tgt_vdev_update_param_req(vdev,
1957 					       pmo_vdev_param_moddtim,
1958 					       mod_dtim);
1959 	if (QDF_IS_STATUS_SUCCESS(status)) {
1960 		pmo_debug("Set modulated dtim for vdev id %d",
1961 			  vdev_id);
1962 		pmo_core_vdev_set_moddtim_user_active(vdev, true);
1963 	} else {
1964 		pmo_err("Failed to Set modulated dtim for vdev id %d",
1965 			vdev_id);
1966 	}
1967 
1968 	wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
1969 out:
1970 	pmo_exit();
1971 	return status;
1972 }
1973 
pmo_core_config_modulated_dtim(struct wlan_objmgr_vdev * vdev,uint32_t mod_dtim)1974 QDF_STATUS pmo_core_config_modulated_dtim(struct wlan_objmgr_vdev *vdev,
1975 					  uint32_t mod_dtim)
1976 {
1977 	struct pmo_vdev_priv_obj *vdev_ctx;
1978 	struct pmo_psoc_priv_obj *psoc_ctx;
1979 	QDF_STATUS status;
1980 
1981 	vdev_ctx = pmo_vdev_get_priv(vdev);
1982 	psoc_ctx = vdev_ctx->pmo_psoc_ctx;
1983 
1984 	if (psoc_ctx->caps.li_offload)
1985 		status = pmo_core_config_li_offload_modulated_dtim(vdev,
1986 								mod_dtim);
1987 	else
1988 		status = pmo_core_config_non_li_offload_modulated_dtim(vdev,
1989 								mod_dtim);
1990 
1991 	return status;
1992 }
1993 
1994 #ifdef SYSTEM_PM_CHECK
pmo_core_system_resume(struct wlan_objmgr_psoc * psoc)1995 void pmo_core_system_resume(struct wlan_objmgr_psoc *psoc)
1996 {
1997 	struct pmo_psoc_priv_obj *psoc_ctx;
1998 	QDF_STATUS status;
1999 
2000 	if (!psoc) {
2001 		pmo_err("psoc is NULL");
2002 		return;
2003 	}
2004 
2005 	status = pmo_psoc_get_ref(psoc);
2006 	if (status != QDF_STATUS_SUCCESS) {
2007 		pmo_err("pmo cannot get the reference out of psoc");
2008 		return;
2009 	}
2010 
2011 	psoc_ctx = pmo_psoc_get_priv(psoc);
2012 
2013 	htc_system_resume(psoc_ctx->htc_hdl);
2014 
2015 	pmo_psoc_put_ref(psoc);
2016 }
2017 #endif
2018