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, ¶m);
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, ¶m);
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