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