Browse Source

qcacmn: Add LPHB, Suspend and Resume support in PMO

Add LPHB,Suspend and resume support in PMO.

Change-Id: Iaa4f9dab417d1dfe208eb39e16c7de0bae8b32f2
CRs-Fixed: 2015161
Mukul Sharma 8 years ago
parent
commit
011a8aea10
22 changed files with 4733 additions and 57 deletions
  1. 51 0
      power_management_offloads/core/inc/wlan_pmo_lphb.h
  2. 177 0
      power_management_offloads/core/inc/wlan_pmo_main.h
  3. 447 0
      power_management_offloads/core/inc/wlan_pmo_suspend_resume.h
  4. 456 0
      power_management_offloads/core/inc/wlan_pmo_wow.h
  5. 252 0
      power_management_offloads/core/src/wlan_pmo_lphb.c
  6. 1032 0
      power_management_offloads/core/src/wlan_pmo_suspend_resume.c
  7. 145 0
      power_management_offloads/core/src/wlan_pmo_wow.c
  8. 145 0
      power_management_offloads/dispatcher/inc/wlan_pmo_common_public_struct.h
  9. 176 0
      power_management_offloads/dispatcher/inc/wlan_pmo_lphb_public_struct.h
  10. 30 8
      power_management_offloads/dispatcher/inc/wlan_pmo_obj_mgmt_api.h
  11. 25 6
      power_management_offloads/dispatcher/inc/wlan_pmo_obj_mgmt_public_struct.h
  12. 163 0
      power_management_offloads/dispatcher/inc/wlan_pmo_tgt_api.h
  13. 210 0
      power_management_offloads/dispatcher/inc/wlan_pmo_ucfg_api.h
  14. 40 31
      power_management_offloads/dispatcher/inc/wlan_pmo_wow_public_struct.h
  15. 201 12
      power_management_offloads/dispatcher/src/wlan_pmo_obj_mgmt_api.c
  16. 159 0
      power_management_offloads/dispatcher/src/wlan_pmo_tgt_lphb.c
  17. 208 0
      power_management_offloads/dispatcher/src/wlan_pmo_tgt_suspend_resume.c
  18. 124 0
      power_management_offloads/dispatcher/src/wlan_pmo_ucfg_api.c
  19. 166 0
      target_if/pmo/inc/target_if_pmo.h
  20. 312 0
      target_if/pmo/src/target_if_pmo_lphb.c
  21. 32 0
      target_if/pmo/src/target_if_pmo_main.c
  22. 182 0
      target_if/pmo/src/target_if_pmo_suspend_resume.c

+ 51 - 0
power_management_offloads/core/inc/wlan_pmo_lphb.h

@@ -0,0 +1,51 @@
+/*
+* Copyright (c) 2017 The Linux Foundation. All rights reserved.
+*
+* Permission to use, copy, modify, and/or distribute this software for
+* any purpose with or without fee is hereby granted, provided that the
+* above copyright notice and this permission notice appear in all
+* copies.
+*
+* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*/
+/**
+ * DOC: Declare low power heart beat offload feature API's
+ */
+
+#ifndef _WLAN_PMO_LPHB_H_
+#define _WLAN_PMO_LPHB_H_
+
+#include "wlan_pmo_lphb_public_struct.h"
+
+/**
+ * pmo_core_lphb_config_req() - API to configure lphb request
+ * @psoc: objmgr psoc handle
+ * @lphb_req: low power heart beat configuration request
+ * @lphb_cb_ctx: low power heart beat context
+ * @callback: osif callback which need to be called when host get lphb event
+ *
+ * API to configure lphb request
+ *
+ * Return: QDF_STATUS_SUCCESS in case of success else return error
+ */
+QDF_STATUS pmo_core_lphb_config_req(struct wlan_objmgr_psoc *psoc,
+		struct pmo_lphb_req *lphb_req, void *lphb_cb_ctx,
+		pmo_lphb_callback callback);
+
+/**
+ * pmo_core_apply_lphb(): apply cached LPHB settings
+ * @psoc: objmgr psoc handle
+ *
+ * LPHB cache, if any item was enabled, should be
+ * applied.
+ */
+void pmo_core_apply_lphb(struct wlan_objmgr_psoc *psoc);
+
+#endif /* end  of _WLAN_PMO_LPHB_H_ */

+ 177 - 0
power_management_offloads/core/inc/wlan_pmo_main.h

@@ -52,6 +52,9 @@
 #define PMO_ENTER() pmo_logfl(QDF_TRACE_LEVEL_INFO, "enter")
 #define PMO_EXIT() pmo_logfl(QDF_TRACE_LEVEL_INFO, "exit")
 
+#define PMO_VDEV_IN_STA_MODE(mode)\
+	((mode == QDF_STA_MODE || mode == QDF_P2P_CLIENT_MODE) == 1 ? 1 : 0)
+
 static inline enum tQDF_ADAPTER_MODE pmo_get_vdev_opmode(
 			struct wlan_objmgr_vdev *vdev)
 {
@@ -208,4 +211,178 @@ QDF_STATUS pmo_core_get_psoc_config(struct wlan_objmgr_psoc *psoc,
 QDF_STATUS pmo_core_update_psoc_config(struct wlan_objmgr_psoc *psoc,
 		struct pmo_psoc_cfg *psoc_cfg);
 
+
+/**
+ * pmo_core_get_vdev_op_mode(): API to get the vdev operation mode
+ * @vdev: objmgr vdev handle
+ *
+ * API to get the vdev operation mode
+ *
+ * Return QDF_MAX_NO_OF_MODE - in case of error else return vdev opmode
+ */
+static inline enum tQDF_ADAPTER_MODE pmo_core_get_vdev_op_mode(
+					struct wlan_objmgr_vdev *vdev)
+{
+	enum tQDF_ADAPTER_MODE op_mode = QDF_MAX_NO_OF_MODE;
+
+	if (!vdev)
+		return op_mode;
+	wlan_vdev_obj_lock(vdev);
+	op_mode = wlan_vdev_mlme_get_opmode(vdev);
+	wlan_vdev_obj_unlock(vdev);
+
+	return op_mode;
+}
+
+/**
+ * pmo_core_psoc_update_dp_handle() - update psoc data path handle
+ * @psoc: objmgr psoc handle
+ * @dp_hdl: psoc data path handle
+ *
+ * Return: None
+ */
+static inline
+void pmo_core_psoc_update_dp_handle(struct wlan_objmgr_psoc *psoc,
+	void *dp_hdl)
+{
+	struct pmo_psoc_priv_obj *psoc_ctx;
+
+	psoc_ctx = pmo_get_psoc_priv_ctx(psoc);
+	if (!psoc_ctx)
+		return;
+	qdf_spin_lock_bh(&psoc_ctx->lock);
+	psoc_ctx->dp_hdl = dp_hdl;
+	qdf_spin_unlock_bh(&psoc_ctx->lock);
+}
+
+/**
+ * pmo_core_psoc_get_dp_handle() - Get psoc data path handle
+ * @psoc: objmgr psoc handle
+ *
+ * Return: psoc data path handle
+ */
+static inline
+void *pmo_core_psoc_get_dp_handle(struct wlan_objmgr_psoc *psoc)
+{
+	void *dp_hdl;
+	struct pmo_psoc_priv_obj *psoc_ctx;
+
+	psoc_ctx = pmo_get_psoc_priv_ctx(psoc);
+	if (!psoc_ctx)
+		return NULL;
+	qdf_spin_lock_bh(&psoc_ctx->lock);
+	dp_hdl = psoc_ctx->dp_hdl;
+	qdf_spin_unlock_bh(&psoc_ctx->lock);
+
+	return dp_hdl;
+}
+
+/**
+ * pmo_core_vdev_update_dp_handle() - update vdev data path handle
+ * @vdev: objmgr vdev handle
+ * @dp_hdl: Vdev data path handle
+ *
+ * Return: None
+ */
+static inline
+void pmo_core_vdev_update_dp_handle(struct wlan_objmgr_vdev *vdev,
+	void *dp_hdl)
+{
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_get_vdev_priv_ctx(vdev);
+	if (!vdev_ctx)
+		return;
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	vdev_ctx->vdev_dp_hdl = dp_hdl;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+}
+
+/**
+ * pmo_core_vdev_get_dp_handle() - Get vdev data path handle
+ * @vdev: objmgr vdev handle
+ *
+ * Return: Vdev data path handle
+ */
+static inline
+void *pmo_core_vdev_get_dp_handle(struct wlan_objmgr_vdev *vdev)
+{
+	void *dp_hdl;
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_get_vdev_priv_ctx(vdev);
+	if (!vdev_ctx)
+		return NULL;
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	dp_hdl = vdev_ctx->vdev_dp_hdl;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+
+	return dp_hdl;
+}
+
+/**
+ * pmo_core_psoc_update_htc_handle() - update psoc htc layer handle
+ * @psoc: objmgr psoc handle
+ * @htc_hdl: psoc htc layer handle
+ *
+ * Return: None
+ */
+static inline
+void pmo_core_psoc_update_htc_handle(struct wlan_objmgr_psoc *psoc,
+	void *htc_hdl)
+{
+	struct pmo_psoc_priv_obj *psoc_ctx;
+
+	psoc_ctx = pmo_get_psoc_priv_ctx(psoc);
+	if (!psoc_ctx)
+		return;
+	qdf_spin_lock_bh(&psoc_ctx->lock);
+	psoc_ctx->htc_hdl = htc_hdl;
+	qdf_spin_unlock_bh(&psoc_ctx->lock);
+}
+
+/**
+ * pmo_core_psoc_get_htc_handle() - Get psoc htc layer handle
+ * @psoc: objmgr psoc handle
+ *
+ * Return: psoc htc layer handle
+ */
+static inline
+void *pmo_core_psoc_get_htc_handle(struct wlan_objmgr_psoc *psoc)
+{
+	void *htc_hdl;
+	struct pmo_psoc_priv_obj *psoc_ctx;
+
+	psoc_ctx = pmo_get_psoc_priv_ctx(psoc);
+	if (!psoc_ctx)
+		return NULL;
+	qdf_spin_lock_bh(&psoc_ctx->lock);
+	htc_hdl = psoc_ctx->htc_hdl;
+	qdf_spin_unlock_bh(&psoc_ctx->lock);
+
+	return htc_hdl;
+}
+
+/**
+ * pmo_is_vdev_up() - API to check whether vdev is UP
+ * @vdev: objmgr vdev handle
+ *
+ * Return:true if vdev is up else false
+ */
+static inline
+bool pmo_is_vdev_up(struct wlan_objmgr_vdev *vdev)
+{
+	enum wlan_vdev_state state = WLAN_VDEV_S_INIT;
+
+	if (!vdev) {
+		pmo_err("vdev context is invalid!");
+		return false;
+	}
+	wlan_vdev_obj_lock(vdev);
+	state = wlan_vdev_mlme_get_state(vdev);
+	wlan_vdev_obj_unlock(vdev);
+
+	return (state == WLAN_VDEV_S_RUN) ? true : false;
+}
+
 #endif /* end  of _WLAN_PMO_MAIN_H_ */

+ 447 - 0
power_management_offloads/core/inc/wlan_pmo_suspend_resume.h

@@ -0,0 +1,447 @@
+/*
+* Copyright (c) 2017 The Linux Foundation. All rights reserved.
+*
+* Permission to use, copy, modify, and/or distribute this software for
+* any purpose with or without fee is hereby granted, provided that the
+* above copyright notice and this permission notice appear in all
+* copies.
+*
+* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*/
+/**
+ * DOC: Declare suspend / resume related API's
+ */
+
+#ifndef _WLAN_PMO_SUSPEND_RESUME_H_
+#define _WLAN_PMO_SUSPEND_RESUME_H_
+
+#include "wlan_pmo_common_public_struct.h"
+#include "wlan_pmo_wow.h"
+
+/**
+ * pmo_core_configure_dynamic_wake_events(): configure dyanmic wake events
+ * @wma: wma handle
+ *
+ * Some wake events need to be enabled dynamically. Control those here.
+ *
+ * Return: none
+ */
+void pmo_core_configure_dynamic_wake_events(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * pmo_core_get_wow_bus_suspend(): API to get wow bus is suspended or not
+ * @psoc: objmgr psoc handle
+ *
+ * Return: True if bus suspende else false
+ */
+static inline
+bool pmo_core_get_wow_bus_suspend(struct wlan_objmgr_psoc *psoc)
+{
+	bool value;
+	struct pmo_psoc_priv_obj *psoc_ctx;
+
+	psoc_ctx = pmo_get_psoc_priv_ctx(psoc);
+	if (!psoc_ctx)
+		return false;
+
+	qdf_spin_lock_bh(&psoc_ctx->lock);
+	value = psoc_ctx->wow.is_wow_bus_suspended;
+	qdf_spin_unlock_bh(&psoc_ctx->lock);
+
+	return value;
+}
+
+/**
+ * pmo_core_psoc_user_space_suspend_req() -  Core handle user space suspend req
+ * @psoc: objmgr psoc handle
+ * @type: type of suspend
+ *
+ * Pmo core Handles user space suspend request for psoc
+ *
+ * Return: QDF status
+ */
+QDF_STATUS pmo_core_psoc_user_space_suspend_req(struct wlan_objmgr_psoc *psoc,
+		enum qdf_suspend_type type);
+
+/**
+ * pmo_core_psoc_user_space_resume_req() - Core handle user space resume req
+ * @psoc: objmgr psoc handle
+ * @type: type of suspend from resume required
+ *
+ * Pmo core Handles user space resume request for psoc
+ *
+ * Return: QDF status
+ */
+QDF_STATUS pmo_core_psoc_user_space_resume_req(struct wlan_objmgr_psoc *psoc,
+		enum qdf_suspend_type type);
+
+/**
+ * pmo_core_psoc_bus_suspend_req(): handles bus suspend for psoc
+ * @psoc: objmgr psoc
+ * @type: is this suspend part of runtime suspend or system suspend?
+ * @wow_params: collection of wow enable override parameters
+ *
+ * Bails if a scan is in progress.
+ * Calls the appropriate handlers based on configuration and event.
+ *
+ * Return: QDF_STATUS_SUCCESS for success or error code
+ */
+QDF_STATUS pmo_core_psoc_bus_suspend_req(struct wlan_objmgr_psoc *psoc,
+		enum qdf_suspend_type type,
+		struct pmo_wow_enable_params *wow_params);
+
+/**
+ * pmo_core_psoc_suspend_target() -Send suspend target command
+ * @psoc: objmgr psoc handle
+ * @disable_target_intr: disable target interrupt
+ *
+ * Return: QDF_STATUS_SUCCESS for success or error code
+ */
+QDF_STATUS pmo_core_psoc_suspend_target(struct wlan_objmgr_psoc *psoc,
+		int disable_target_intr);
+
+/**
+ * pmo_core_psoc_bus_resume() -handle bus resume request for psoc
+ * @psoc: objmgr psoc handle
+ * @type: is this suspend part of runtime suspend or system suspend?
+ *
+ * Return:QDF_STATUS_SUCCESS on success else error code
+ */
+QDF_STATUS pmo_core_psoc_bus_resume_req(struct wlan_objmgr_psoc *psoc,
+		enum qdf_suspend_type type);
+
+/**
+ * pmo_core_get_vdev_dtim_period() - Get vdev dtim period
+ * @vdev: objmgr vdev handle
+ *
+ * Return: Vdev dtim period
+ */
+static inline
+uint8_t pmo_core_get_vdev_dtim_period(struct wlan_objmgr_vdev *vdev)
+{
+	uint8_t dtim_period = 0;
+
+	if (!vdev) {
+		pmo_err("vdev is null");
+		QDF_ASSERT(0);
+		return 0;
+	}
+	wlan_vdev_obj_lock(vdev);
+	/* TODO */
+	/* dtim_period = wlan_vdev_mlme_get_dtim_period(vdev); */
+	wlan_vdev_obj_unlock(vdev);
+
+	return dtim_period;
+}
+
+/**
+ * pmo_core_get_vdev_beacon_interval() - Get vdev beacon interval
+ * @vdev: objmgr vdev handle
+ *
+ * Return: Vdev beacon interval
+ */
+static inline
+uint16_t pmo_core_get_vdev_beacon_interval(struct wlan_objmgr_vdev *vdev)
+{
+	uint16_t beacon_interval = 0;
+
+	if (!vdev) {
+		pmo_err("vdev is null");
+		QDF_ASSERT(0);
+		return 0;
+	}
+	wlan_vdev_obj_lock(vdev);
+	/* TODO */
+	/* beacon_interval = wlan_vdev_mlme_get_beacon_interval(vdev); */
+	wlan_vdev_obj_unlock(vdev);
+
+	return beacon_interval;
+}
+
+/**
+ * pmo_core_update_alt_modulated_dtim_enable() - update alt modulatate dtim
+ * @vdev: objmgr vdev handle
+ * @value: true when alt modulated dtim enable else false
+ *
+ * Return: None
+ */
+static inline
+void pmo_core_update_alt_modulated_dtim_enable(struct wlan_objmgr_vdev *vdev,
+	bool value)
+{
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_get_vdev_priv_ctx(vdev);
+	if (!vdev_ctx)
+		return;
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	vdev_ctx->alt_modulated_dtim_enable = value;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+}
+
+/**
+ * pmo_core_vdev_set_dtim_policy() - Set vdev beacon dtim policy
+ * @vdev: objmgr vdev handle
+ * @value: carry vdev dtim policy
+ *
+ * Return: None
+ */
+static inline
+void pmo_core_vdev_set_dtim_policy(struct wlan_objmgr_vdev *vdev,
+	uint32_t value)
+{
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_get_vdev_priv_ctx(vdev);
+	if (!vdev_ctx)
+		return;
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	vdev_ctx->dtim_policy = value;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+}
+
+/**
+ * pmo_core_vdev_get_dtim_policy() - Get vdev beacon dtim policy
+ * @vdev: objmgr vdev handle
+ *
+ * Return: vdev dtim policy
+ */
+static inline
+uint32_t pmo_core_vdev_get_dtim_policy(struct wlan_objmgr_vdev *vdev)
+{
+	uint32_t value;
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_get_vdev_priv_ctx(vdev);
+	if (!vdev_ctx)
+		return 0;
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	value = vdev_ctx->dtim_policy;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+
+	return value;
+}
+
+/**
+ * pmo_core_update_power_save_mode() - update power save mode
+ * @vdev: objmgr vdev handle
+ * @value:describe vdev power save mode
+ *
+ * Return: None
+ */
+static inline
+void pmo_core_psoc_update_power_save_mode(struct wlan_objmgr_psoc *psoc,
+	uint8_t value)
+{
+	struct pmo_psoc_priv_obj *psoc_ctx;
+
+	psoc_ctx = pmo_get_psoc_priv_ctx(psoc);
+	if (!psoc_ctx)
+		return;
+	qdf_spin_lock_bh(&psoc_ctx->lock);
+	psoc_ctx->psoc_cfg.power_save_mode = value;
+	qdf_spin_unlock_bh(&psoc_ctx->lock);
+}
+
+/**
+ * pmo_core_psoc_get_power_save_mode() - Get psoc power save mode
+ * @psoc: objmgr psoc handle
+ *
+ * Return: vdev psoc power save mode value
+ */
+static inline
+uint8_t pmo_core_psoc_get_power_save_mode(struct wlan_objmgr_psoc *psoc)
+{
+	uint8_t value;
+	struct pmo_psoc_priv_obj *psoc_ctx;
+
+	psoc_ctx = pmo_get_psoc_priv_ctx(psoc);
+	if (!psoc_ctx)
+		return 0;
+	qdf_spin_lock_bh(&psoc_ctx->lock);
+	value = psoc_ctx->psoc_cfg.power_save_mode;
+	qdf_spin_unlock_bh(&psoc_ctx->lock);
+
+	return value;
+}
+
+/**
+ * pmo_core_psoc_get_qpower_config() - get qpower configuration
+ * @psoc: objmgr psoc handle
+ *
+ * Power Save Offload configuration:
+ * 0 -> Power save offload is disabled
+ * 1 -> Legacy Power save enabled + Deep sleep Disabled
+ * 2 -> QPower enabled + Deep sleep Disabled
+ * 3 -> Legacy Power save enabled + Deep sleep Enabled
+ * 4 -> QPower enabled + Deep sleep Enabled
+ * 5 -> Duty cycling QPower enabled
+ *
+ * Return: enum powersave_qpower_mode with below values
+ * QPOWER_DISABLED if QPOWER is disabled
+ * QPOWER_ENABLED if QPOWER is enabled
+ * QPOWER_DUTY_CYCLING if DUTY CYCLING QPOWER is enabled
+ */
+static inline
+enum pmo_power_save_qpower_mode pmo_core_psoc_get_qpower_config(
+		struct wlan_objmgr_psoc *psoc)
+{
+	uint8_t ps_mode = pmo_core_psoc_get_power_save_mode(psoc);
+
+	switch (ps_mode) {
+	case pmo_ps_qpower_no_deep_sleep:
+	case pmo_ps_qpower_deep_sleep:
+		pmo_info("QPOWER is enabled in power save mode %d", ps_mode);
+		return pmo_qpower_enabled;
+	case pmo_ps_duty_cycling_qpower:
+		pmo_info("DUTY cycling QPOWER is enabled in power save mode %d",
+			ps_mode);
+		return pmo_qpower_duty_cycling;
+	default:
+		pmo_info("QPOWER is disabled in power save mode %d",
+			ps_mode);
+		return pmo_qpower_disabled;
+	}
+}
+
+/**
+ * pmo_core_vdev_update_pause_bitmap() - update vdev pause bitmap value
+ * @vdev: objmgr vdev handle
+ * @value: value of pause bitmap
+ *
+ * Return: None
+ */
+static inline
+void pmo_core_vdev_update_pause_bitmap(struct wlan_objmgr_vdev *vdev,
+		uint16_t value)
+{
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_get_vdev_priv_ctx(vdev);
+	if (!vdev_ctx)
+		return;
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	vdev_ctx->pause_bitmap = value;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+}
+
+/**
+ * pmo_core_vdev_get_pause_bitmap() - Get vdev pause bitmap
+ * @vdev: objmgr vdev handle
+ *
+ * Return: vdev pause bitmap
+ */
+static inline
+uint16_t pmo_core_vdev_get_pause_bitmap(struct wlan_objmgr_vdev *vdev)
+{
+	uint16_t value;
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_get_vdev_priv_ctx(vdev);
+	if (!vdev_ctx)
+		return 0;
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	value = vdev_ctx->pause_bitmap;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+
+	return value;
+}
+
+/**
+ * wma_is_vdev_in_ap_mode() - check that vdev is in ap mode or not
+ * @wma: wma handle
+ * @vdev_id: vdev id
+ *
+ * Helper function to know whether given vdev id
+ * is in AP mode or not.
+ *
+ * Return: True/False
+ */
+static inline
+bool pmo_is_vdev_in_ap_mode(struct wlan_objmgr_vdev *vdev)
+{
+	enum tQDF_ADAPTER_MODE mode;
+
+	mode = pmo_get_vdev_opmode(vdev);
+
+	return (mode == QDF_SAP_MODE || mode == QDF_P2P_GO_MODE) == 1 ? 1 : 0;
+}
+
+#ifdef QCA_IBSS_SUPPORT
+/**
+ * pmo_is_vdev_in_ibss_mode() - check that vdev is in ibss mode or not
+ * @vdev: objmgr vdev handle
+ * @vdev_id: vdev id
+ *
+ * Helper function to know whether given vdev id
+ * is in IBSS mode or not.
+ *
+ * Return: True/False
+ */
+static inline
+bool pmo_is_vdev_in_ibss_mode(struct wlan_objmgr_vdev *vdev)
+{
+	enum tQDF_ADAPTER_MODE mode;
+
+	mode = pmo_get_vdev_opmode(vdev);
+
+	return (mode == QDF_IBSS_MODE) ? true : false;
+}
+#else
+static inline bool pmo_is_vdev_in_ibss_mode(struct wlan_objmgr_vdev *vdev)
+{
+	return false;
+}
+#endif /* QCA_IBSS_SUPPORT */
+
+/**
+ * pmo_handle_initial_wake_up() - handle initial wake up
+ * @cb_ctx: callback context
+ *
+ * Return: None
+ */
+void pmo_core_psoc_handle_initial_wake_up(void *cb_ctx);
+
+/**
+ * pmo_core_psoc_is_target_wake_up_received() - check for initial wake up
+ *
+ * Check if target initial wake up is received and fail PM suspend gracefully
+ *
+ * Return: -EAGAIN if initial wake up is received else 0
+ */
+int pmo_core_psoc_is_target_wake_up_received(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * pmo_core_psoc_clear_target_wake_up() - clear initial wake up
+ *
+ * Clear target initial wake up reason
+ *
+ * Return: 0 for success and negative error code for failure
+ */
+int pmo_core_psoc_clear_target_wake_up(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * pmo_core_psoc_target_suspend_acknowledge() - update target susspend status
+ * @context: HTC_INIT_INFO->context
+ * @wow_nack: true when wow is rejected
+ *
+ * Return: none
+ */
+void pmo_core_psoc_target_suspend_acknowledge(void *context, bool wow_nack);
+
+/**
+ * pmo_core_psoc_wakeup_host_event_received() - received host wake up event
+ * @psoc: objmgr psoc handle
+ *
+ * Return: None
+ */
+void pmo_core_psoc_wakeup_host_event_received(struct wlan_objmgr_psoc *psoc);
+
+#endif /* end  of _WLAN_PMO_SUSPEND_RESUME_H_ */

+ 456 - 0
power_management_offloads/core/inc/wlan_pmo_wow.h

@@ -254,4 +254,460 @@ void pmo_core_enable_wakeup_event(struct wlan_objmgr_psoc *psoc,
 void pmo_core_disable_wakeup_event(struct wlan_objmgr_psoc *psoc,
 	uint32_t vdev_id, uint32_t bitmap);
 
+/**
+ * pmo_is_wow_applicable(): should enable wow
+ * @psoc: objmgr psoc object
+ *
+ *  Enable WOW if any one of the condition meets,
+ *  1) Is any one of vdev in beaconning mode (in AP mode) ?
+ *  2) Is any one of vdev in connected state (in STA mode) ?
+ *  3) Is PNO in progress in any one of vdev ?
+ *  4) Is Extscan in progress in any one of vdev ?
+ *  5) Is P2P listen offload in any one of vdev?
+ *  6) Is any vdev in NAN data mode? BSS is already started at the
+ *     the time of device creation. It is ready to accept data
+ *     requests.
+ *  7) If LPASS feature is enabled
+ *  8) If NaN feature is enabled
+ *  If none of above conditions is true then return false
+ *
+ * Return: true if wma needs to configure wow false otherwise.
+ */
+bool pmo_core_is_wow_applicable(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * pmo_core_update_wow_enable() - update wow enable flag
+ * @psoc_ctx: Pointer to objmgr psoc handle
+ * @value: true if wow mode enable else false
+ *
+ * Return: None
+ */
+static inline
+void pmo_core_update_wow_enable(struct pmo_psoc_priv_obj *psoc_ctx,
+	bool value)
+{
+	qdf_spin_lock_bh(&psoc_ctx->lock);
+	psoc_ctx->wow.wow_enable = value;
+	qdf_spin_unlock_bh(&psoc_ctx->lock);
+}
+
+/**
+ * pmo_core_is_wow_mode_enabled() - check if wow needs to be enabled in fw
+ * @psoc_ctx: Pointer to objmgr psoc handle
+ *
+ * API to check if wow mode is enabled in fwr as part of apps suspend or not
+ *
+ * Return: true is wow mode is enabled else false
+ */
+static inline
+bool pmo_core_is_wow_enabled(struct pmo_psoc_priv_obj *psoc_ctx)
+{
+	bool value;
+
+	if (!psoc_ctx) {
+		pmo_err("psoc_ctx is null");
+		return false;
+	}
+
+	qdf_spin_lock_bh(&psoc_ctx->lock);
+	value = psoc_ctx->wow.wow_enable;
+	qdf_spin_unlock_bh(&psoc_ctx->lock);
+	pmo_debug("WoW enable %d", value);
+
+	return value;
+}
+
+/**
+ * pmo_core_set_wow_nack() - Set wow nack flag
+ * @psoc_ctx: Pointer to objmgr psoc handle
+ * @value: true if received wow nack from else false
+ *
+ * Return: None
+ */
+static inline
+void pmo_core_set_wow_nack(struct pmo_psoc_priv_obj *psoc_ctx, bool value)
+{
+	qdf_spin_lock_bh(&psoc_ctx->lock);
+	psoc_ctx->wow.wow_nack = value;
+	qdf_spin_unlock_bh(&psoc_ctx->lock);
+}
+
+/**
+ * pmo_core_get_wow_nack() - Get wow nack flag
+ * @psoc_ctx: Pointer to objmgr psoc handle
+ *
+ * Return: wow nack flag
+ */
+static inline
+bool pmo_core_get_wow_nack(struct pmo_psoc_priv_obj *psoc_ctx)
+{
+	bool value;
+
+	qdf_spin_lock_bh(&psoc_ctx->lock);
+	value = psoc_ctx->wow.wow_nack;
+	qdf_spin_unlock_bh(&psoc_ctx->lock);
+
+	return value;
+}
+/**
+ * pmo_core_update_wow_enable_cmd_sent() - update wow enable cmd sent flag
+ * @psoc_ctx: Pointer to objmgr psoc handle
+ * @value: true if wow enable cmd sent else false
+ *
+ * Return: None
+ */
+static inline
+void pmo_core_update_wow_enable_cmd_sent(struct pmo_psoc_priv_obj *psoc_ctx,
+	bool value)
+{
+	qdf_spin_lock_bh(&psoc_ctx->lock);
+	psoc_ctx->wow.wow_enable_cmd_sent = value;
+	qdf_spin_unlock_bh(&psoc_ctx->lock);
+}
+
+/**
+ * pmo_core_get_wow_enable_cmd_sent() - Get wow enable cmd sent flag
+ * @psoc_ctx: Pointer to objmgr psoc handle
+ *
+ * Return: return true if wow enable cmd sent else false
+ */
+static inline
+bool pmo_core_get_wow_enable_cmd_sent(struct pmo_psoc_priv_obj *psoc_ctx)
+{
+	bool value;
+
+	qdf_spin_lock_bh(&psoc_ctx->lock);
+	value = psoc_ctx->wow.wow_enable_cmd_sent;
+	qdf_spin_unlock_bh(&psoc_ctx->lock);
+
+	return value;
+}
+
+/**
+ * pmo_core_update_wow_initial_wake_up() - update wow initial wake up
+ * @psoc_ctx: Pointer to objmgr psoc handle
+ * @value: true if wow initial wake up is received else false
+ *
+ * Return: None
+ */
+static inline
+void pmo_core_update_wow_initial_wake_up(struct pmo_psoc_priv_obj *psoc_ctx,
+	bool value)
+{
+	qdf_spin_lock_bh(&psoc_ctx->lock);
+	psoc_ctx->wow.wow_initial_wake_up = value;
+	qdf_spin_unlock_bh(&psoc_ctx->lock);
+}
+
+/**
+ * pmo_core_get_wow_initial_wake_up() - Get wow initial wake up
+ * @psoc_ctx: Pointer to objmgr psoc handle
+ *
+ * Return:  true if wow initial wake up is received else false
+ */
+static inline
+bool pmo_core_get_wow_initial_wake_up(struct pmo_psoc_priv_obj *psoc_ctx)
+{
+	bool value;
+
+	qdf_spin_lock_bh(&psoc_ctx->lock);
+	value = psoc_ctx->wow.wow_initial_wake_up;
+	qdf_spin_unlock_bh(&psoc_ctx->lock);
+
+	return value;
+}
+
+#ifdef FEATURE_WLAN_SCAN_PNO
+/**
+ * pmo_core_is_nlo_scan_in_progress(): check if nlo scan is in progress
+ * @vdev: objmgr vdev handle
+ *
+ * Return: TRUE/FALSE
+ */
+static inline
+bool pmo_core_is_nlo_scan_in_progress(struct wlan_objmgr_vdev *vdev)
+{
+	bool nlo_in_progress;
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_get_vdev_priv_ctx(vdev);
+	if (!vdev_ctx)
+		return false;
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	nlo_in_progress = vdev_ctx->nlo_in_progress;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+
+	return nlo_in_progress;
+}
+
+/**
+ * pmo_core_is_nlo_scan_match_found(): check if a nlo scan match was found
+ * @vdev: objmgr vdev handle
+ *
+ * Return: TRUE/FALSE
+ */
+static inline
+bool pmo_core_is_nlo_scan_match_found(struct wlan_objmgr_vdev *vdev)
+{
+	bool nlo_match_received;
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_get_vdev_priv_ctx(vdev);
+	if (!vdev_ctx)
+		return false;
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	nlo_match_received = vdev_ctx->nlo_match_received;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+
+	return nlo_match_received;
+}
+
+/**
+ * pmo_core_update_nlo_scan_in_progress(): update nlo scan is in progress flags
+ * @vdev: objmgr vdev handle
+ * @value:true if pno scan is in progress else false
+ *
+ * Return: None
+ */
+static inline
+void pmo_core_update_nlo_scan_in_progress(struct wlan_objmgr_vdev *vdev,
+	bool value)
+{
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_get_vdev_priv_ctx(vdev);
+	if (!vdev_ctx)
+		return;
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	vdev_ctx->nlo_in_progress = value;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+}
+
+/**
+ * pmo_core_update_nlo_match_found(): Update nlo scan match flag to value
+ * @vdev: objmgr vdev handle
+ * @value:true if nlo scan match event received else false
+ *
+ * Return: TRUE/FALSE
+ */
+static inline
+void pmo_core_update_nlo_match_found(struct wlan_objmgr_vdev *vdev,
+	bool value)
+{
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_get_vdev_priv_ctx(vdev);
+	if (!vdev_ctx)
+		return;
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	vdev_ctx->nlo_match_received = value;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+}
+#else
+/**
+ * pmo_is_nlo_scan_in_progress(): dummy
+ *
+ * Return: False since no pnoscan cannot be in progress
+ * when feature flag is not defined.
+ */
+static inline
+bool pmo_core_is_nlo_scan_in_progress(struct wlan_objmgr_vdev *vdev)
+{
+	return false;
+}
+
+/**
+ * wma_is_pnoscan_match_found(): dummy
+ * @vdev: objmgr vdev handle
+ *
+ * Return: False since no pnoscan cannot occur
+ * when feature flag is not defined.
+ */
+static inline
+bool pmo_core_is_nlo_scan_match_found(struct wlan_objmgr_vdev *vdev)
+{
+	return false;
+}
+
+static inline
+void pmo_core_update_nlo_scan_in_progress(struct wlan_objmgr_vdev *vdev,
+	bool value)
+{
+}
+
+static inline
+void pmo_core_update_nlo_match_found(struct wlan_objmgr_vdev *vdev,
+	bool value)
+{
+}
+#endif
+
+#ifdef FEATURE_WLAN_EXTSCAN
+/**
+ * pmo_core_is_extscan_in_progress(): check if a extscan is in progress
+ * @vdev: objmgr vdev handle
+ *
+ * Return: TRUE/FALSE
+ */
+static inline
+bool pmo_core_is_extscan_in_progress(struct wlan_objmgr_vdev *vdev)
+{
+	bool extscan_in_progress;
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_get_vdev_priv_ctx(vdev);
+	if (!vdev_ctx)
+		return false;
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	extscan_in_progress = vdev_ctx->extscan_in_progress;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+
+	return extscan_in_progress;
+}
+
+/**
+ * pmo_core_update_extscan_in_progress(): update extscan is in progress flags
+ * @vdev: objmgr vdev handle
+ * @value:true if extscan is in progress else false
+ *
+ * Return: TRUE/FALSE
+ */
+static inline
+void pmo_core_update_extscan_in_progress(struct wlan_objmgr_vdev *vdev,
+	bool value)
+{
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_get_vdev_priv_ctx(vdev);
+	if (!vdev_ctx)
+		return;
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	vdev_ctx->extscan_in_progress = value;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+}
+#else
+static inline
+bool pmo_core_is_extscan_in_progress(struct wlan_objmgr_vdev *vdev)
+{
+	return false;
+}
+
+static inline
+void pmo_core_update_extscan_in_progress(struct wlan_objmgr_vdev *vdev,
+	bool value)
+{
+}
+#endif
+
+/**
+ * pmo_core_is_p2plo_in_progress(): check if p2plo is in progress
+ * @vdev: objmgr vdev handle
+ *
+ * Return: TRUE/FALSE
+ */
+static inline
+bool pmo_core_is_p2plo_in_progress(struct wlan_objmgr_vdev *vdev)
+{
+	bool p2plo_in_progress;
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_get_vdev_priv_ctx(vdev);
+	if (!vdev_ctx)
+		return false;
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	p2plo_in_progress = vdev_ctx->p2plo_in_progress;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+
+	return p2plo_in_progress;
+}
+
+/**
+ * pmo_core_update_p2plo_in_progress(): update p2plo is in progress flags
+ * @vdev: objmgr vdev handle
+ * @value:true if p2plo is in progress else false
+ *
+ * Return: TRUE/FALSE
+ */
+static inline
+void pmo_core_update_p2plo_in_progress(struct wlan_objmgr_vdev *vdev,
+	bool value)
+{
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_get_vdev_priv_ctx(vdev);
+	if (!vdev_ctx)
+		return;
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	vdev_ctx->p2plo_in_progress = value;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+}
+
+#ifdef WLAN_FEATURE_LPSS
+/**
+ * pmo_is_lpass_enabled() - check if lpass is enabled
+ * @vdev: objmgr vdev handle
+ *
+ * WoW is needed if LPASS or NaN feature is enabled in INI because
+ * target can't wake up itself if its put in PDEV suspend when LPASS
+ * or NaN features are supported
+ *
+ * Return: true if lpass is enabled else false
+ */
+static inline
+bool pmo_core_is_lpass_enabled(struct wlan_objmgr_vdev *vdev)
+{
+	bool lpass_enable;
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_get_vdev_priv_ctx(vdev);
+	if (!vdev_ctx)
+		return false;
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	lpass_enable = vdev_ctx->pmo_psoc_ctx->psoc_cfg.lpass_enable;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+
+	return lpass_enable;
+}
+#else
+static inline
+bool pmo_core_is_lpass_enabled(struct wlan_objmgr_vdev *vdev)
+{
+	return false;
+}
+#endif
+
+#ifdef WLAN_FEATURE_NAN
+/**
+ * pmo_is_nan_enabled() - check if NaN is enabled
+ * @vdev: objmgr vdev handle
+ *
+ * WoW is needed if LPASS or NaN feature is enabled in INI because
+ * target can't wake up itself if its put in PDEV suspend when LPASS
+ * or NaN features are supported
+ *
+ * Return: true if NaN is enabled else false
+ */
+static inline
+bool pmo_core_is_nan_enabled(struct wlan_objmgr_vdev *vdev)
+{
+	bool nan_enable;
+	struct pmo_vdev_priv_obj *vdev_ctx;
+
+	vdev_ctx = pmo_get_vdev_priv_ctx(vdev);
+	if (!vdev_ctx)
+		return false;
+	qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+	nan_enable = vdev_ctx->pmo_psoc_ctx->psoc_cfg.nan_enable;
+	qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+
+	return nan_enable;
+}
+#else
+static inline
+bool pmo_core_is_nan_enabled(struct wlan_objmgr_vdev *vdev)
+{
+	return false;
+}
+#endif
+
 #endif /* end  of _WLAN_PMO_WOW_H_ */

+ 252 - 0
power_management_offloads/core/src/wlan_pmo_lphb.c

@@ -0,0 +1,252 @@
+/*
+* Copyright (c) 2017 The Linux Foundation. All rights reserved.
+*
+* Permission to use, copy, modify, and/or distribute this software for
+* any purpose with or without fee is hereby granted, provided that the
+* above copyright notice and this permission notice appear in all
+* copies.
+*
+* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*/
+/**
+ * DOC: Implements low power heart beat offload feature API's
+ */
+
+#include "wlan_pmo_lphb.h"
+#include "wlan_pmo_tgt_api.h"
+#include "wlan_pmo_main.h"
+#include "wlan_pmo_obj_mgmt_public_struct.h"
+
+#ifdef FEATURE_WLAN_LPHB
+/**
+ * pmo_core_send_lphb_enable() - enable command of LPHB configuration requests
+ * @psoc: objmgr psoc handle
+ * @psoc_ctx: pmo private psoc ctx
+ * @lphb_conf_req: lphb request which need s to configure in fwr
+ * @by_user: whether this call is from user or cached resent
+ *
+ * Return: QDF status
+ */
+static QDF_STATUS pmo_core_send_lphb_enable(struct wlan_objmgr_psoc *psoc,
+			struct pmo_psoc_priv_obj *psoc_ctx,
+			struct pmo_lphb_req *lphb_conf_req, bool by_user)
+{
+	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
+	struct pmo_lphb_enable_req *ts_lphb_enable;
+	int i;
+
+	if (lphb_conf_req == NULL) {
+		pmo_err("LPHB configuration is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	ts_lphb_enable = &(lphb_conf_req->params.lphb_enable_req);
+	qdf_status = pmo_tgt_send_lphb_enable(psoc, ts_lphb_enable);
+	if (qdf_status != QDF_STATUS_SUCCESS)
+		goto out;
+
+	/* No need to cache non user request */
+	if (!by_user) {
+		qdf_status = QDF_STATUS_SUCCESS;
+		goto out;
+	}
+
+	/* target already configured, now cache command status */
+	if (ts_lphb_enable->enable) {
+		i = ts_lphb_enable->item - 1;
+		qdf_spin_lock_bh(&psoc_ctx->lock);
+		psoc_ctx->wow.lphb_cache[i].cmd
+			= pmo_lphb_set_en_param_indid;
+		psoc_ctx->wow.lphb_cache[i].params.lphb_enable_req.enable =
+			ts_lphb_enable->enable;
+		psoc_ctx->wow.lphb_cache[i].params.lphb_enable_req.item =
+			ts_lphb_enable->item;
+		psoc_ctx->wow.lphb_cache[i].params.lphb_enable_req.session =
+			ts_lphb_enable->session;
+		qdf_spin_unlock_bh(&psoc_ctx->lock);
+		pmo_info("cached LPHB status in WMA context for item %d", i);
+	} else {
+		qdf_spin_lock_bh(&psoc_ctx->lock);
+		qdf_mem_zero((void *)&psoc_ctx->wow.lphb_cache,
+				sizeof(psoc_ctx->wow.lphb_cache));
+		qdf_spin_unlock_bh(&psoc_ctx->lock);
+		pmo_info("cleared all cached LPHB status in WMA context");
+	}
+
+out:
+	return qdf_status;
+}
+
+/**
+ * pmo_core_send_lphb_tcp_params() - Send tcp params of LPHB requests
+ * @psoc: objmgr psoc handle
+ * @lphb_conf_req: lphb request which needs to be configured in fwr
+ *
+ * Return: QDF status
+ */
+static
+QDF_STATUS pmo_core_send_lphb_tcp_params(struct wlan_objmgr_psoc *psoc,
+			struct pmo_lphb_req *lphb_conf_req)
+{
+	return pmo_tgt_send_lphb_tcp_params(psoc,
+			&lphb_conf_req->params.lphb_tcp_params);
+
+}
+
+/**
+ * pmo_core_send_lphb_tcp_pkt_filter() - Send tcp packet filter command of LPHB
+ * @psoc: objmgr psoc handle
+ * @lphb_conf_req: lphb request which needs to be configured in fwr
+ *
+ * Return: QDF status
+ */
+static
+QDF_STATUS pmo_core_send_lphb_tcp_pkt_filter(struct wlan_objmgr_psoc *psoc,
+			struct pmo_lphb_req *lphb_conf_req)
+{
+	return pmo_tgt_send_lphb_tcp_pkt_filter(psoc,
+			&lphb_conf_req->params.lphb_tcp_filter_req);
+}
+
+/**
+ * pmo_core_send_lphb_udp_params() - Send udp param command of LPHB
+ * @psoc: objmgr psoc handle
+ * @lphb_conf_req: lphb request which needs to be configured in fwr
+ *
+ * Return: QDF status
+ */
+static
+QDF_STATUS pmo_core_send_lphb_udp_params(struct wlan_objmgr_psoc *psoc,
+			struct pmo_lphb_req *lphb_conf_req)
+{
+	return pmo_tgt_send_lphb_udp_params(psoc,
+			&lphb_conf_req->params.lphb_udp_params);
+}
+
+/**
+ * pmo_core_send_lphb_udp_pkt_filter() - Send udp pkt filter command of LPHB
+ * @psoc: objmgr psoc handle
+ * @lphb_conf_req: lphb request which need s to configure in fwr
+ *
+ * Return: QDF status
+ */
+static
+QDF_STATUS pmo_core_send_lphb_udp_pkt_filter(struct wlan_objmgr_psoc *psoc,
+			struct pmo_lphb_req *lphb_conf_req)
+{
+	return pmo_tgt_send_lphb_udp_pkt_filter(psoc,
+			&lphb_conf_req->params.lphb_udp_filter_req);
+}
+
+/**
+ * pmo_process_lphb_conf_req() - handle LPHB configuration requests
+ * @psoc: objmgr psoc handle
+ * @psoc_ctx: pmo private psoc ctx
+ * @lphb_conf_req: lphb request which needs to be configured in fwr
+ *
+ * Return: QDF status
+ */
+static QDF_STATUS pmo_process_lphb_conf_req(struct wlan_objmgr_psoc *psoc,
+		struct pmo_psoc_priv_obj *psoc_ctx,
+		struct pmo_lphb_req *lphb_conf_req)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	pmo_info("LPHB configuration cmd id is %d", lphb_conf_req->cmd);
+	switch (lphb_conf_req->cmd) {
+	case pmo_lphb_set_en_param_indid:
+		status = pmo_core_send_lphb_enable(psoc, psoc_ctx,
+					lphb_conf_req, true);
+		break;
+
+	case pmo_lphb_set_tcp_pararm_indid:
+		status = pmo_core_send_lphb_tcp_params(psoc, lphb_conf_req);
+		break;
+
+	case pmo_lphb_set_tcp_pkt_filter_indid:
+		status = pmo_core_send_lphb_tcp_pkt_filter(psoc, lphb_conf_req);
+		break;
+
+	case pmo_lphb_set_udp_pararm_indid:
+		status = pmo_core_send_lphb_udp_params(psoc, lphb_conf_req);
+		break;
+
+	case pmo_lphb_set_udp_pkt_filter_indid:
+		status = pmo_core_send_lphb_udp_pkt_filter(psoc, lphb_conf_req);
+		break;
+
+	case pmo_lphb_set_network_info_indid:
+	default:
+		break;
+	}
+
+	return status;
+}
+
+void pmo_core_apply_lphb(struct wlan_objmgr_psoc *psoc)
+{
+	int i;
+	struct pmo_psoc_priv_obj *psoc_ctx;
+
+	psoc_ctx = pmo_get_psoc_priv_ctx(psoc);
+	if (!psoc_ctx) {
+		pmo_err("psoc ctx is null");
+		return;
+	}
+	pmo_debug("checking LPHB cache");
+	for (i = 0; i < 2; i++) {
+		if (psoc_ctx->wow.lphb_cache[i].params.lphb_enable_req.enable) {
+			pmo_debug("LPHB cache for item %d is marked as enable",
+				i + 1);
+			pmo_core_send_lphb_enable(psoc, psoc_ctx,
+				&(psoc_ctx->wow.lphb_cache[i]), false);
+		}
+	}
+}
+
+QDF_STATUS pmo_core_lphb_config_req(struct wlan_objmgr_psoc *psoc,
+		struct pmo_lphb_req *lphb_req, void *lphb_cb_ctx,
+		pmo_lphb_callback callback)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct pmo_psoc_priv_obj *psoc_ctx;
+
+	if (lphb_req == NULL) {
+		pmo_err("LPHB configuration is NULL");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	psoc_ctx = pmo_get_psoc_priv_ctx(psoc);
+	if (!psoc_ctx) {
+		pmo_err("psoc ctx is null");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	if (pmo_lphb_set_en_param_indid == lphb_req->cmd) {
+		if (!lphb_cb_ctx) {
+			pmo_err("lphb callback context is null");
+			return QDF_STATUS_E_NULL_VALUE;
+		}
+		if (!callback) {
+			pmo_err("lphb callback function is null");
+			return QDF_STATUS_E_NULL_VALUE;
+		}
+		qdf_spin_lock_bh(&psoc_ctx->lock);
+		psoc_ctx->wow.lphb_cb_ctx = lphb_cb_ctx;
+		psoc_ctx->wow.lphb_cb = callback;
+		qdf_spin_unlock_bh(&psoc_ctx->lock);
+	}
+	status = pmo_process_lphb_conf_req(psoc, psoc_ctx, lphb_req);
+
+	return status;
+}
+
+#endif /* FEATURE_WLAN_LPHB */
+

+ 1032 - 0
power_management_offloads/core/src/wlan_pmo_suspend_resume.c

@@ -0,0 +1,1032 @@
+/*
+* Copyright (c) 2017 The Linux Foundation. All rights reserved.
+*
+* Permission to use, copy, modify, and/or distribute this software for
+* any purpose with or without fee is hereby granted, provided that the
+* above copyright notice and this permission notice appear in all
+* copies.
+*
+* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*/
+/**
+ * DOC: Define API's for suspend / resume handling
+ */
+
+#include "wlan_pmo_wow.h"
+#include "wlan_pmo_tgt_api.h"
+#include "wlan_pmo_main.h"
+#include "wlan_pmo_obj_mgmt_public_struct.h"
+#include "wlan_pmo_lphb.h"
+#include "wlan_pmo_suspend_resume.h"
+#include "cdp_txrx_ops.h"
+#include "cdp_txrx_flow_ctrl_legacy.h"
+#include "htc_api.h"
+#include "wlan_pmo_obj_mgmt_api.h"
+
+/**
+ * pmo_core_calculate_listen_interval() - Calculate vdev listen interval
+ * @vdev: objmgr vdev handle
+ * @vdev_ctx: pmo vdev priv ctx
+ * @listen_interval: listen interval which is computed for vdev
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS pmo_core_calculate_listen_interval(
+			struct wlan_objmgr_vdev *vdev,
+			struct pmo_vdev_priv_obj *vdev_ctx,
+			uint32_t *listen_interval)
+{
+	uint32_t max_mod_dtim;
+	uint32_t beacon_interval_mod;
+	struct pmo_psoc_cfg *psoc_cfg = &vdev_ctx->pmo_psoc_ctx->psoc_cfg;
+
+	if (psoc_cfg->sta_dynamic_dtim) {
+		*listen_interval = psoc_cfg->sta_dynamic_dtim;
+	} else if ((psoc_cfg->sta_mod_dtim) &&
+		   (psoc_cfg->sta_max_li_mod_dtim)) {
+		/*
+		 * When the system is in suspend
+		 * (maximum beacon will be at 1s == 10)
+		 * If maxModulatedDTIM ((MAX_LI_VAL = 10) / AP_DTIM)
+		 * equal or larger than MDTIM
+		 * (configured in WCNSS_qcom_cfg.ini)
+		 * Set LI to MDTIM * AP_DTIM
+		 * If Dtim = 2 and Mdtim = 2 then LI is 4
+		 * Else
+		 * Set LI to maxModulatedDTIM * AP_DTIM
+		 */
+		beacon_interval_mod =
+			pmo_core_get_vdev_beacon_interval(vdev) / 100;
+		if (beacon_interval_mod == 0)
+			beacon_interval_mod = 1;
+
+		max_mod_dtim = psoc_cfg->sta_max_li_mod_dtim /
+			(pmo_core_get_vdev_dtim_period(vdev)
+			 * beacon_interval_mod);
+
+		if (max_mod_dtim <= 0)
+			max_mod_dtim = 1;
+
+		if (max_mod_dtim >= psoc_cfg->sta_mod_dtim) {
+			*listen_interval =
+				(psoc_cfg->sta_mod_dtim *
+				pmo_core_get_vdev_dtim_period(vdev));
+		} else {
+			*listen_interval =
+				(max_mod_dtim *
+				pmo_core_get_vdev_dtim_period(vdev));
+		}
+	} else {
+		return QDF_STATUS_E_FAULT;
+	}
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * pmo_core_set_vdev_suspend_dtim() - set suspend dtim parameters in fw
+ * @psoc: objmgr psoc handle
+ * @vdev: objmgr vdev handle
+ * @vdev_ctx: pmo vdev priv ctx
+ *
+ * Return: none
+ */
+static void pmo_core_set_vdev_suspend_dtim(struct wlan_objmgr_psoc *psoc,
+		struct wlan_objmgr_vdev *vdev,
+		struct pmo_vdev_priv_obj *vdev_ctx)
+{
+	uint32_t listen_interval;
+	QDF_STATUS ret;
+	uint8_t vdev_id;
+	enum pmo_power_save_qpower_mode qpower_config;
+	enum tQDF_ADAPTER_MODE opmode = pmo_core_get_vdev_op_mode(vdev);
+
+	qpower_config = pmo_core_psoc_get_qpower_config(psoc);
+	vdev_id = pmo_get_vdev_id(vdev);
+	if (PMO_VDEV_IN_STA_MODE(opmode) &&
+	    pmo_core_get_vdev_dtim_period(vdev) != 0) {
+		/* calculate listen interval */
+		ret = pmo_core_calculate_listen_interval(vdev, vdev_ctx,
+				&listen_interval);
+		if (ret != QDF_STATUS_SUCCESS) {
+			/* even it fails continue fwr will take default LI */
+			pmo_info("Fail to calculate listen interval");
+		}
+
+		ret = pmo_tgt_vdev_update_param_req(vdev,
+				pmo_vdev_param_listen_interval,
+				listen_interval);
+		if (QDF_IS_STATUS_ERROR(ret)) {
+			/* even it fails continue fwr will take default LI */
+			pmo_info("Failed to Set Listen Interval vdevId %d",
+				 vdev_id);
+		}
+		pmo_debug("Set Listen Interval vdevId %d Listen Intv %d",
+			 vdev_id, listen_interval);
+
+		if (qpower_config) {
+			pmo_debug("disable Qpower in suspend mode!");
+			ret = pmo_tgt_send_vdev_sta_ps_param(vdev,
+					pmo_sta_ps_enable_qpower, 0);
+			if (QDF_IS_STATUS_ERROR(ret))
+				pmo_info("Failed to disable Qpower in suspend mode!");
+		}
+
+		ret = pmo_tgt_vdev_update_param_req(vdev,
+				pmo_vdev_param_dtim_policy,
+				pmo_normal_dtim);
+		if (QDF_IS_STATUS_ERROR(ret))
+			pmo_info("Failed to Set to Normal DTIM vdevId %d",
+				vdev_id);
+
+		/* Set it to Normal DTIM */
+		pmo_core_vdev_set_dtim_policy(vdev, pmo_normal_dtim);
+		pmo_debug("Set DTIM Policy to Normal Dtim vdevId %d", vdev_id);
+	}
+}
+
+/**
+ * pmo_core_set_suspend_dtim() - set suspend dtim
+ * @psoc: objmgr psoc handle
+ *
+ * Return: none
+ */
+static void pmo_core_set_suspend_dtim(struct wlan_objmgr_psoc *psoc)
+{
+	uint8_t vdev_id;
+	struct wlan_objmgr_psoc_objmgr *objmgr;
+	struct wlan_objmgr_vdev *vdev;
+	struct pmo_vdev_priv_obj *vdev_ctx;
+	bool alt_mdtim_enabled = false;
+	QDF_STATUS ret;
+
+	/* Iterate through VDEV list */
+	for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) {
+		wlan_psoc_obj_lock(psoc);
+		objmgr = &psoc->soc_objmgr;
+		if (!objmgr->wlan_vdev_list[vdev_id]) {
+			wlan_psoc_obj_unlock(psoc);
+			continue;
+		}
+		vdev = objmgr->wlan_vdev_list[vdev_id];
+		wlan_psoc_obj_unlock(psoc);
+
+		if (vdev) {
+			vdev_ctx = pmo_get_vdev_priv_ctx(vdev);
+			ret = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_PMO_ID);
+			if (ret != QDF_STATUS_SUCCESS)
+				continue;
+			qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+			alt_mdtim_enabled = vdev_ctx->alt_modulated_dtim_enable;
+			qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+			if (!alt_mdtim_enabled)
+				pmo_core_set_vdev_suspend_dtim(psoc,
+					vdev, vdev_ctx);
+			wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
+		}
+	}
+}
+
+/**
+ * pmo_core_update_wow_bus_suspend() - set wow bus suspend flag
+ * @psoc: objmgr psoc handle
+ * @psoc_ctx: pmo psoc priv ctx
+ * @val: true for enable else false
+ * Return: none
+ */
+static inline
+void pmo_core_update_wow_bus_suspend(struct wlan_objmgr_psoc *psoc,
+		struct pmo_psoc_priv_obj *psoc_ctx, int val)
+{
+	qdf_spin_lock_bh(&psoc_ctx->lock);
+	psoc_ctx->wow.is_wow_bus_suspended = val;
+	qdf_spin_unlock_bh(&psoc_ctx->lock);
+	pmo_tgt_psoc_update_wow_bus_suspend_state(psoc, val);
+}
+
+void pmo_core_configure_dynamic_wake_events(struct wlan_objmgr_psoc *psoc)
+{
+	int vdev_id;
+	int enable_mask;
+	int disable_mask;
+	struct wlan_objmgr_psoc_objmgr *objmgr;
+	struct wlan_objmgr_vdev *vdev;
+
+	/* Iterate through VDEV list */
+	for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) {
+		wlan_psoc_obj_lock(psoc);
+		objmgr = &psoc->soc_objmgr;
+		if (!objmgr->wlan_vdev_list[vdev_id]) {
+			wlan_psoc_obj_unlock(psoc);
+			continue;
+		}
+		vdev = objmgr->wlan_vdev_list[vdev_id];
+		wlan_psoc_obj_unlock(psoc);
+
+		enable_mask = 0;
+		disable_mask = 0;
+		if (pmo_core_is_nlo_scan_in_progress(vdev)) {
+			if (pmo_core_is_nlo_scan_match_found(vdev))
+				enable_mask |=
+					(1 << WOW_NLO_SCAN_COMPLETE_EVENT);
+			else
+				disable_mask |=
+					(1 << WOW_NLO_SCAN_COMPLETE_EVENT);
+		}
+
+		if (enable_mask != 0)
+			pmo_core_enable_wakeup_event(psoc, vdev_id,
+				enable_mask);
+		if (disable_mask != 0)
+			pmo_core_disable_wakeup_event(psoc, vdev_id,
+					disable_mask);
+	}
+}
+
+QDF_STATUS pmo_core_psoc_user_space_suspend_req(struct wlan_objmgr_psoc *psoc,
+		enum qdf_suspend_type type)
+{
+	struct pmo_psoc_priv_obj *psoc_ctx;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	PMO_ENTER();
+
+	status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_PMO_ID);
+	if (status != QDF_STATUS_SUCCESS) {
+		pmo_err("pmo cannot get the reference out of psoc");
+		goto out;
+	}
+
+	psoc_ctx = pmo_get_psoc_priv_ctx(psoc);
+	if (!psoc_ctx) {
+		pmo_err("pmo psoc ctx is null");
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto dec_psoc_ref;
+	}
+
+	/* Suspend all components before sending target suspend command */
+	status = pmo_suspend_all_components(psoc, type);
+	if (status != QDF_STATUS_SUCCESS) {
+		pmo_err("Failed to suspend all component");
+		goto dec_psoc_ref;
+	}
+
+	if (pmo_core_is_wow_applicable(psoc)) {
+		pmo_info("WOW Suspend");
+		pmo_core_apply_lphb(psoc);
+
+		pmo_core_configure_dynamic_wake_events(psoc);
+		pmo_core_update_wow_enable(psoc_ctx, true);
+		pmo_core_update_wow_enable_cmd_sent(psoc_ctx, false);
+	}
+
+	/* Set the Suspend DTIM Parameters */
+	pmo_core_set_suspend_dtim(psoc);
+
+	/*
+	 * To handle race between hif_pci_suspend and
+	 * unpause/pause tx handler
+	 */
+	pmo_core_update_wow_bus_suspend(psoc, psoc_ctx, true);
+dec_psoc_ref:
+	wlan_objmgr_psoc_release_ref(psoc, WLAN_PMO_ID);
+out:
+	PMO_EXIT();
+
+	return status;
+}
+
+/**
+ * pmo_core_set_vdev_resume_dtim() - set resume dtim parameters in fw
+ * @psoc: objmgr psoc handle
+ * @vdev: objmgr vdev handle
+ * @vdev_ctx: pmo vdev priv ctx
+ *
+ * Return: none
+ */
+static void pmo_core_set_vdev_resume_dtim(struct wlan_objmgr_psoc *psoc,
+		struct wlan_objmgr_vdev *vdev,
+		struct pmo_vdev_priv_obj *vdev_ctx)
+{
+	enum pmo_power_save_qpower_mode qpower_config;
+	QDF_STATUS ret;
+	uint8_t vdev_id;
+	enum tQDF_ADAPTER_MODE opmode = pmo_core_get_vdev_op_mode(vdev);
+	uint32_t cfg_data_val = 0;
+
+	qpower_config = pmo_core_psoc_get_qpower_config(psoc);
+	vdev_id = pmo_get_vdev_id(vdev);
+	if ((PMO_VDEV_IN_STA_MODE(opmode)) &&
+	    (pmo_core_vdev_get_dtim_policy(vdev) == pmo_normal_dtim)) {
+/*
+		if (!mac) {
+			WMA_LOGE(FL("Failed to get mac context"));
+			return;
+		}
+		if ((wlan_cfg_get_int(mac, WNI_CFG_LISTEN_INTERVAL,
+				      &cfg_data_val) != eSIR_SUCCESS)) {
+			pmo_err("Failed to get value for listen interval");
+			cfg_data_val = POWERSAVE_DEFAULT_LISTEN_INTERVAL;
+		}
+*/
+		cfg_data_val = 1;
+		ret = pmo_tgt_vdev_update_param_req(vdev,
+				pmo_vdev_param_listen_interval, cfg_data_val);
+		if (QDF_IS_STATUS_ERROR(ret)) {
+			/* Even it fails continue Fw will take default LI */
+			pmo_err("Failed to Set Listen Interval vdevId %d",
+				 vdev_id);
+		}
+		pmo_debug("Set Listen Interval vdevId %d Listen Intv %d",
+			 vdev_id, cfg_data_val);
+
+		ret = pmo_tgt_vdev_update_param_req(vdev,
+				pmo_vdev_param_dtim_policy,
+				pmo_stick_dtim);
+		if (QDF_IS_STATUS_ERROR(ret)) {
+			/* Set it back to Stick DTIM */
+			pmo_err("Failed to Set to Stick DTIM vdevId %d",
+				 vdev_id);
+		}
+		pmo_core_vdev_set_dtim_policy(vdev, pmo_stick_dtim);
+		pmo_debug("Set DTIM Policy to Stick Dtim vdevId %d", vdev_id);
+
+		if (qpower_config) {
+			pmo_debug("enable Qpower in resume mode!");
+			ret = pmo_tgt_send_vdev_sta_ps_param(vdev,
+				pmo_sta_ps_enable_qpower, qpower_config);
+			if (QDF_IS_STATUS_ERROR(ret))
+				pmo_err("Failed to enable Qpower in resume");
+		}
+	}
+}
+
+/**
+ * pmo_core_set_resume_dtim() - set resume time dtim
+ * @psoc: objmgr psoc handle
+ *
+ * Return: none
+ */
+static void pmo_core_set_resume_dtim(struct wlan_objmgr_psoc *psoc)
+{
+	uint8_t vdev_id;
+	struct wlan_objmgr_psoc_objmgr *objmgr;
+	struct wlan_objmgr_vdev *vdev;
+	struct pmo_vdev_priv_obj *vdev_ctx;
+	bool alt_mdtim_enabled = false;
+	QDF_STATUS ret;
+
+	/* Iterate through VDEV list */
+	for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) {
+		wlan_psoc_obj_lock(psoc);
+		objmgr = &psoc->soc_objmgr;
+		if (!objmgr->wlan_vdev_list[vdev_id]) {
+			wlan_psoc_obj_unlock(psoc);
+			continue;
+		}
+		vdev = objmgr->wlan_vdev_list[vdev_id];
+		wlan_psoc_obj_unlock(psoc);
+
+		if (vdev) {
+			vdev_ctx = pmo_get_vdev_priv_ctx(vdev);
+			ret = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_PMO_ID);
+			if (ret != QDF_STATUS_SUCCESS)
+				continue;
+			qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
+			alt_mdtim_enabled = vdev_ctx->alt_modulated_dtim_enable;
+			qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
+			if (!alt_mdtim_enabled)
+				pmo_core_set_vdev_resume_dtim(psoc,
+					vdev, vdev_ctx);
+			wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
+		}
+	}
+}
+
+/**
+ * pmo_unpause_vdev - unpause all vdev
+ * @psoc: objmgr psoc handle
+ *
+ * unpause all vdev aftter resume/coming out of wow mode
+ *
+ * Return: none
+ */
+static void pmo_unpause_all_vdev(struct wlan_objmgr_psoc *psoc)
+{
+	uint8_t vdev_id;
+	struct wlan_objmgr_psoc_objmgr *objmgr;
+	struct wlan_objmgr_vdev *vdev;
+
+	/* Iterate through VDEV list */
+	for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) {
+		wlan_psoc_obj_lock(psoc);
+		objmgr = &psoc->soc_objmgr;
+		if (!objmgr->wlan_vdev_list[vdev_id]) {
+			wlan_psoc_obj_unlock(psoc);
+			continue;
+		}
+		vdev = objmgr->wlan_vdev_list[vdev_id];
+		wlan_psoc_obj_unlock(psoc);
+		if (vdev) {
+#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2)
+			/*
+			 * When host resume, by default,
+			 * unpause all active vdev
+			 */
+			if (pmo_core_vdev_get_pause_bitmap(vdev)) {
+				cdp_fc_vdev_unpause(
+					pmo_core_psoc_get_dp_handle(psoc),
+					pmo_core_vdev_get_dp_handle(vdev),
+					0xffffffff);
+				/* wma_vdev_update_pause_bitmap(vdev_id, 0); */
+			}
+#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
+		}
+	}
+}
+
+QDF_STATUS pmo_core_psoc_user_space_resume_req(struct wlan_objmgr_psoc *psoc,
+		enum qdf_suspend_type type)
+{
+	struct pmo_psoc_priv_obj *psoc_ctx;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	PMO_ENTER();
+
+	status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_PMO_ID);
+	if (status != QDF_STATUS_SUCCESS) {
+		pmo_err("pmo cannot get the reference out of psoc");
+		goto out;
+	}
+
+	psoc_ctx = pmo_get_psoc_priv_ctx(psoc);
+	if (!psoc_ctx) {
+		pmo_err("pmo psoc ctx is null");
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto dec_psoc_ref;
+	}
+
+	/* Resume all components */
+	status = pmo_resume_all_components(psoc, type);
+	if (status != QDF_STATUS_SUCCESS) {
+		pmo_err("Failed to resume all the components");
+		goto dec_psoc_ref;
+	}
+
+	/* Reset the DTIM Parameters */
+	pmo_core_set_resume_dtim(psoc);
+	/* need to reset if hif_pci_suspend_fails */
+	pmo_core_update_wow_bus_suspend(psoc, psoc_ctx, false);
+	/* unpause the vdev if left paused and hif_pci_suspend fails */
+	pmo_unpause_all_vdev(psoc);
+
+dec_psoc_ref:
+	wlan_objmgr_psoc_release_ref(psoc, WLAN_PMO_ID);
+out:
+	PMO_EXIT();
+
+	return status;
+}
+
+/**
+ * pmo_core_enable_wow_in_fw() - enable wow in fw
+ * @psoc: objmgr psoc handle
+ * @psoc_ctx: pmo psoc private ctx
+ * @wow_params: collection of wow enable override parameters
+ *
+ * Return: QDF status
+ */
+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)
+{
+	int host_credits, wmi_pending_cmds;
+	struct pmo_wow_cmd_params param = {0};
+	QDF_STATUS status;
+
+	PMO_ENTER();
+	qdf_event_reset(&psoc_ctx->wow.target_suspend);
+	pmo_core_set_wow_nack(psoc_ctx, false);
+	host_credits = pmo_tgt_psoc_get_host_credits(psoc);
+	wmi_pending_cmds = pmo_tgt_psoc_get_pending_cmnds(psoc);
+	pmo_debug("Credits:%d; Pending_Cmds: %d",
+		host_credits, wmi_pending_cmds);
+
+	param.enable = true;
+	if (wow_params->is_unit_test)
+		param.flags = WMI_WOW_FLAG_UNIT_TEST_ENABLE;
+
+	switch (wow_params->interface_pause) {
+	default:
+		pmo_err("Invalid interface pause setting: %d",
+			 wow_params->interface_pause);
+		/* intentional fall-through to default */
+	case PMO_WOW_INTERFACE_PAUSE_DEFAULT:
+		param.can_suspend_link =
+			htc_can_suspend_link(
+				pmo_core_psoc_get_htc_handle(psoc));
+		break;
+	case PMO_WOW_INTERFACE_PAUSE_ENABLE:
+		param.can_suspend_link = true;
+		break;
+	case PMO_WOW_INTERFACE_PAUSE_DISABLE:
+		param.can_suspend_link = false;
+		break;
+	}
+
+	switch (wow_params->resume_trigger) {
+	default:
+		pmo_err("Invalid resume trigger setting: %d",
+			 wow_params->resume_trigger);
+		/* intentional fall-through to default */
+	case PMO_WOW_RESUME_TRIGGER_DEFAULT:
+	case PMO_WOW_RESUME_TRIGGER_GPIO:
+		/*
+		 * GPIO is currently implicit. This means you can't actually
+		 * force GPIO if a platform's default wake trigger is HTC wakeup
+		 */
+		break;
+	case PMO_WOW_RESUME_TRIGGER_HTC_WAKEUP:
+		param.flags |= WMI_WOW_FLAG_DO_HTC_WAKEUP;
+		break;
+	}
+
+	status = pmo_tgt_psoc_send_wow_enable_req(psoc, &param);
+	if (status != QDF_STATUS_SUCCESS) {
+		pmo_err("Failed to enable wow in fw");
+		goto out;
+	}
+
+	pmo_tgt_update_target_suspend_flag(psoc, true);
+
+	if (qdf_wait_single_event(&psoc_ctx->wow.target_suspend,
+				  PMO_TGT_SUSPEND_COMPLETE_TIMEOUT)
+	    != QDF_STATUS_SUCCESS) {
+		pmo_err("Failed to receive WoW Enable Ack from FW");
+		pmo_err("Credits:%d; Pending_Cmds: %d",
+			pmo_tgt_psoc_get_host_credits(psoc),
+			pmo_tgt_psoc_get_pending_cmnds(psoc));
+		pmo_tgt_update_target_suspend_flag(psoc, false);
+		status = QDF_STATUS_E_FAILURE;
+		QDF_BUG(0);
+		goto out;
+	}
+
+	if (pmo_core_get_wow_nack(psoc_ctx)) {
+		pmo_err("FW not ready to WOW");
+		pmo_tgt_update_target_suspend_flag(psoc, false);
+		status = QDF_STATUS_E_AGAIN;
+		goto out;
+	}
+
+	host_credits = pmo_tgt_psoc_get_host_credits(psoc);
+	wmi_pending_cmds = pmo_tgt_psoc_get_pending_cmnds(psoc);
+
+	if (host_credits < PMO_WOW_REQUIRED_CREDITS) {
+		pmo_err("No Credits after HTC ACK:%d, pending_cmds:%d,"
+			 "cannot resume back", host_credits, wmi_pending_cmds);
+		htc_dump_counter_info(pmo_core_psoc_get_htc_handle(psoc));
+/*
+		if (!cds_is_driver_recovering())
+			QDF_BUG(0);
+		else
+			pmo_err("SSR in progress, ignore no credit issue");
+*/
+	}
+	pmo_debug("WOW enabled successfully in fw: credits:%d pending_cmds: %d",
+		host_credits, wmi_pending_cmds);
+
+	pmo_core_update_wow_enable_cmd_sent(psoc_ctx, true);
+out:
+	PMO_EXIT();
+
+	return status;
+}
+
+QDF_STATUS pmo_core_psoc_suspend_target(struct wlan_objmgr_psoc *psoc,
+		int disable_target_intr)
+{
+	QDF_STATUS status;
+	struct pmo_suspend_params param;
+	struct pmo_psoc_priv_obj *psoc_ctx;
+
+	PMO_ENTER();
+
+	psoc_ctx = pmo_get_psoc_priv_ctx(psoc);
+	if (!psoc_ctx) {
+		pmo_err("psoc ctx is null");
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto out;
+	}
+
+	qdf_event_reset(&psoc_ctx->wow.target_suspend);
+	param.disable_target_intr = disable_target_intr;
+	status = pmo_tgt_psoc_send_supend_req(psoc, &param);
+	if (status != QDF_STATUS_SUCCESS)
+		goto out;
+
+	pmo_tgt_update_target_suspend_flag(psoc, true);
+
+	if (qdf_wait_single_event(&psoc_ctx->wow.target_suspend,
+				  PMO_TGT_SUSPEND_COMPLETE_TIMEOUT)
+	    != QDF_STATUS_SUCCESS) {
+		status = QDF_STATUS_E_TIMEOUT;
+		pmo_err("Failed to get ACK from firmware for pdev suspend");
+		pmo_tgt_update_target_suspend_flag(psoc, false);
+		/* wma_suspend_target_timeout(pmac->sme.enableSelfRecovery); */
+	}
+out:
+	PMO_EXIT();
+
+	return status;
+}
+
+QDF_STATUS pmo_core_psoc_bus_suspend_req(struct wlan_objmgr_psoc *psoc,
+		enum qdf_suspend_type type,
+		struct pmo_wow_enable_params *wow_params)
+{
+	struct pmo_psoc_priv_obj *psoc_ctx;
+	QDF_STATUS status;
+	bool wow_mode_selected = false;
+
+	PMO_ENTER();
+	if (!psoc) {
+		pmo_err("psoc is NULL");
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto out;
+	}
+
+	if (!wow_params) {
+		pmo_err("wow_params is NULL");
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto out;
+	}
+
+	status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_PMO_ID);
+	if (status != QDF_STATUS_SUCCESS) {
+		pmo_err("pmo cannot get the reference out of psoc");
+		goto out;
+	}
+
+	psoc_ctx = pmo_get_psoc_priv_ctx(psoc);
+	if (!psoc_ctx) {
+		pmo_err("psoc_ctx is NULL");
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto dec_psoc_ref;
+	}
+
+/* TODO - scan manager need to provide the below public api
+	if (wma_check_scan_in_progress(handle)) {
+		pmo_err("Scan in progress. Aborting suspend");
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto out;
+	}
+*/
+
+	if (type == QDF_SYSTEM_SUSPEND) {
+		wow_mode_selected = pmo_core_is_wow_enabled(psoc_ctx);
+		pmo_info("wow mode selected %d", wow_mode_selected);
+	}
+
+	if (wow_mode_selected)
+		status = pmo_core_enable_wow_in_fw(psoc, psoc_ctx, wow_params);
+	else
+		status = pmo_core_psoc_suspend_target(psoc, 0);
+dec_psoc_ref:
+	wlan_objmgr_psoc_release_ref(psoc, WLAN_PMO_ID);
+out:
+	PMO_EXIT();
+
+	return status;
+}
+
+/**
+ * pmo_core_psoc_send_host_wakeup_ind_to_fw() - send wakeup ind to fw
+ * @psoc: objmgr psoc handle
+ * @psoc_ctx: pmo psoc private context
+ *
+ * Sends host wakeup indication to FW. On receiving this indication,
+ * FW will come out of WOW.
+ *
+ * Return: QDF status
+ */
+static
+QDF_STATUS pmo_core_psoc_send_host_wakeup_ind_to_fw(
+			struct wlan_objmgr_psoc *psoc,
+			struct pmo_psoc_priv_obj *psoc_ctx)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	PMO_ENTER();
+	qdf_event_reset(&psoc_ctx->wow.target_resume);
+
+	status = pmo_tgt_psoc_send_host_wakeup_ind(psoc);
+	if (status) {
+		status = QDF_STATUS_E_FAILURE;
+		goto out;
+	}
+	pmo_debug("Host wakeup indication sent to fw");
+
+	status = qdf_wait_single_event(&psoc_ctx->wow.target_resume,
+					PMO_RESUME_TIMEOUT);
+	if (status != QDF_STATUS_SUCCESS) {
+		pmo_err("Timeout waiting for resume event from FW");
+		pmo_err("Pending commands %d credits %d",
+			pmo_tgt_psoc_get_pending_cmnds(psoc),
+			pmo_tgt_psoc_get_host_credits(psoc));
+		QDF_BUG(0);
+	} else {
+		pmo_debug("Host wakeup received");
+	}
+
+	if (status == QDF_STATUS_SUCCESS)
+		pmo_tgt_update_target_suspend_flag(psoc, false);
+out:
+	PMO_EXIT();
+
+	return status;
+}
+
+/**
+ * pmo_core_psoc_disable_wow_in_fw() -  Disable wow in bus resume context.
+ * @psoc: objmgr psoc handle
+ * @psoc_ctx: pmo psoc private context
+ *
+ * Return: QDF_STATUS_SUCCESS for success or error code
+ */
+static
+QDF_STATUS pmo_core_psoc_disable_wow_in_fw(struct wlan_objmgr_psoc *psoc,
+			struct pmo_psoc_priv_obj *psoc_ctx)
+{
+	QDF_STATUS ret;
+
+	PMO_ENTER();
+	ret = pmo_core_psoc_send_host_wakeup_ind_to_fw(psoc, psoc_ctx);
+	if (ret != QDF_STATUS_SUCCESS)
+		goto out;
+
+	pmo_core_update_wow_enable(psoc_ctx, false);
+	pmo_core_update_wow_enable_cmd_sent(psoc_ctx, false);
+
+	/* To allow the tx pause/unpause events */
+	pmo_core_update_wow_bus_suspend(psoc, psoc_ctx, false);
+	/* Unpause the vdev as we are resuming */
+	pmo_unpause_all_vdev(psoc);
+out:
+	PMO_EXIT();
+
+	return ret;
+}
+
+/**
+ * pmo_core_psoc_resume_target() - resume target
+ * @psoc: objmgr psoc handle
+ * @psoc_ctx: pmo psoc private context
+ *
+ * Return: QDF_STATUS_SUCCESS for success or error code
+ */
+static
+QDF_STATUS pmo_core_psoc_resume_target(struct wlan_objmgr_psoc *psoc,
+		struct pmo_psoc_priv_obj *psoc_ctx)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	PMO_ENTER();
+	qdf_event_reset(&psoc_ctx->wow.target_resume);
+
+	status = pmo_tgt_psoc_send_target_resume_req(psoc);
+	if (status != QDF_STATUS_SUCCESS) {
+		status = QDF_STATUS_E_FAILURE;
+		goto out;
+	}
+
+	status = qdf_wait_single_event(&psoc_ctx->wow.target_resume,
+			PMO_RESUME_TIMEOUT);
+	if (status != QDF_STATUS_SUCCESS) {
+		pmo_fatal("Timeout waiting for resume event from FW");
+		pmo_fatal("Pending commands %d credits %d",
+			pmo_tgt_psoc_get_pending_cmnds(psoc),
+			pmo_tgt_psoc_get_host_credits(psoc));
+		QDF_BUG(0);
+	} else {
+		pmo_debug("Host wakeup received");
+	}
+
+	if (status == QDF_STATUS_SUCCESS)
+		pmo_tgt_update_target_suspend_flag(psoc, false);
+out:
+	PMO_EXIT();
+
+	return status;
+}
+
+QDF_STATUS pmo_core_psoc_bus_resume_req(struct wlan_objmgr_psoc *psoc,
+		enum qdf_suspend_type type)
+{
+	struct pmo_psoc_priv_obj *psoc_ctx;
+	bool wow_mode;
+	QDF_STATUS status;
+
+	PMO_ENTER();
+	if (!psoc) {
+		pmo_err("psoc is null");
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto out;
+	}
+
+	status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_PMO_ID);
+	if (status != QDF_STATUS_SUCCESS) {
+		pmo_err("pmo cannot get the reference out of psoc");
+		goto out;
+	}
+
+	psoc_ctx = pmo_get_psoc_priv_ctx(psoc);
+	if (!psoc_ctx) {
+		pmo_err("psoc_ctx is null");
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto dec_psoc_ref;
+	}
+
+	wow_mode = pmo_core_is_wow_enabled(psoc_ctx);
+	pmo_info("wow mode %d", wow_mode);
+
+	pmo_core_update_wow_initial_wake_up(psoc_ctx, false);
+
+	if (wow_mode)
+		status = pmo_core_psoc_disable_wow_in_fw(psoc, psoc_ctx);
+	else
+		status = pmo_core_psoc_resume_target(psoc, psoc_ctx);
+dec_psoc_ref:
+	wlan_objmgr_psoc_release_ref(psoc, WLAN_PMO_ID);
+out:
+	PMO_EXIT();
+
+	return status;
+}
+
+void pmo_core_psoc_target_suspend_acknowledge(void *context, bool wow_nack)
+{
+	struct pmo_psoc_priv_obj *psoc_ctx;
+	struct wlan_objmgr_psoc *psoc = (struct wlan_objmgr_psoc *)context;
+	QDF_STATUS status;
+
+	PMO_ENTER();
+	if (!psoc) {
+		pmo_err("psoc is null");
+		goto out;
+	}
+
+	status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_PMO_ID);
+	if (status != QDF_STATUS_SUCCESS) {
+		pmo_err("Failed to get psoc reference");
+		goto out;
+	}
+
+	psoc_ctx = pmo_get_psoc_priv_ctx(psoc);
+	if (!psoc_ctx) {
+		pmo_err("psoc_ctx is null");
+		goto dec_ref;
+	}
+
+	pmo_core_set_wow_nack(psoc_ctx, wow_nack);
+	qdf_event_set(&psoc_ctx->wow.target_suspend);
+	if (wow_nack && !pmo_tgt_psoc_get_runtime_pm_in_progress(psoc)) {
+		qdf_wake_lock_timeout_acquire(&psoc_ctx->wow.wow_wake_lock,
+						PMO_WAKE_LOCK_TIMEOUT);
+	}
+dec_ref:
+	wlan_objmgr_psoc_release_ref(psoc, WLAN_PMO_ID);
+out:
+	PMO_EXIT();
+}
+
+void pmo_core_psoc_wakeup_host_event_received(struct wlan_objmgr_psoc *psoc)
+{
+	struct pmo_psoc_priv_obj *psoc_ctx;
+
+	PMO_ENTER();
+	if (!psoc) {
+		pmo_err("psoc is null");
+		goto out;
+	}
+	psoc_ctx = pmo_get_psoc_priv_ctx(psoc);
+	if (!psoc_ctx) {
+		pmo_err("psoc_ctx is null");
+		goto out;
+	}
+	qdf_event_set(&psoc_ctx->wow.target_resume);
+out:
+	PMO_EXIT();
+}
+
+int pmo_core_psoc_is_target_wake_up_received(struct wlan_objmgr_psoc *psoc)
+{
+	struct pmo_psoc_priv_obj *psoc_ctx;
+	int ret = 0;
+	QDF_STATUS status;
+
+	if (!psoc) {
+		pmo_err("psoc is NULL");
+		ret = -EAGAIN;
+		goto out;
+	}
+
+	status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_PMO_ID);
+	if (status != QDF_STATUS_SUCCESS) {
+		pmo_err("Failed to get psoc reference");
+		ret = -EAGAIN;
+		goto out;
+	}
+
+	psoc_ctx = pmo_get_psoc_priv_ctx(psoc);
+	if (!psoc_ctx) {
+		pmo_err("psoc_ctx is null");
+		ret = -EAGAIN;
+		goto dec_ref;
+	}
+
+	if (pmo_core_get_wow_initial_wake_up(psoc_ctx)) {
+		pmo_err("Target initial wake up received try again");
+		ret = -EAGAIN;
+	}
+dec_ref:
+	wlan_objmgr_psoc_release_ref(psoc, WLAN_PMO_ID);
+out:
+	PMO_EXIT();
+
+	return ret;
+}
+
+
+int pmo_core_psoc_clear_target_wake_up(struct wlan_objmgr_psoc *psoc)
+{
+	struct pmo_psoc_priv_obj *psoc_ctx;
+	int ret = 0;
+	QDF_STATUS status;
+
+	if (!psoc) {
+		pmo_err("psoc is NULL");
+		ret = -EAGAIN;
+		goto out;
+	}
+
+	status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_PMO_ID);
+	if (status != QDF_STATUS_SUCCESS) {
+		pmo_err("Failed to get psoc reference");
+		ret = -EAGAIN;
+		goto out;
+	}
+
+	psoc_ctx = pmo_get_psoc_priv_ctx(psoc);
+	if (!psoc_ctx) {
+		pmo_err("psoc_ctx is null");
+		ret = -EAGAIN;
+		goto dec_ref;
+	}
+
+	pmo_core_update_wow_initial_wake_up(psoc_ctx, false);
+dec_ref:
+	wlan_objmgr_psoc_release_ref(psoc, WLAN_PMO_ID);
+out:
+	PMO_EXIT();
+
+	return ret;
+}
+
+void pmo_core_psoc_handle_initial_wake_up(void *cb_ctx)
+{
+	struct pmo_psoc_priv_obj *psoc_ctx;
+	struct wlan_objmgr_psoc *psoc = (struct wlan_objmgr_psoc *)cb_ctx;
+	QDF_STATUS status;
+
+	PMO_ENTER();
+	if (!psoc) {
+		pmo_err("cb ctx/psoc is null");
+		goto out;
+	}
+
+	status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_PMO_ID);
+	if (status != QDF_STATUS_SUCCESS) {
+		pmo_err("Failed to get psoc reference");
+		goto out;
+	}
+
+	psoc_ctx = pmo_get_psoc_priv_ctx(psoc);
+	if (!psoc_ctx) {
+		pmo_err("psoc_ctx is null");
+		goto dec_ref;
+	}
+	pmo_core_update_wow_initial_wake_up(psoc_ctx, true);
+dec_ref:
+	wlan_objmgr_psoc_release_ref(psoc, WLAN_PMO_ID);
+out:
+	PMO_EXIT();
+}
+

+ 145 - 0
power_management_offloads/core/src/wlan_pmo_wow.c

@@ -111,3 +111,148 @@ out:
 
 }
 
+/**
+ * pmo_is_beaconning_vdev_up(): check if a beaconning vdev is up
+ * @psoc: objmgr psoc handle
+ *
+ * Return TRUE if beaconning vdev is up
+ */
+static
+bool pmo_is_beaconning_vdev_up(struct wlan_objmgr_psoc *psoc)
+{
+	int vdev_id;
+	struct wlan_objmgr_psoc_objmgr *objmgr;
+	struct wlan_objmgr_vdev *vdev;
+	enum tQDF_ADAPTER_MODE vdev_opmode;
+	QDF_STATUS status;
+
+	/* Iterate through VDEV list */
+	for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) {
+		wlan_psoc_obj_lock(psoc);
+		objmgr = &psoc->soc_objmgr;
+		if (!objmgr->wlan_vdev_list[vdev_id]) {
+			wlan_psoc_obj_unlock(psoc);
+			continue;
+		}
+		vdev = objmgr->wlan_vdev_list[vdev_id];
+		wlan_psoc_obj_unlock(psoc);
+
+		status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_PMO_ID);
+		if (status != QDF_STATUS_SUCCESS)
+			continue;
+
+		vdev_opmode = pmo_get_vdev_opmode(vdev);
+		if (pmo_is_vdev_in_beaconning_mode(vdev_opmode) &&
+		    pmo_is_vdev_up(vdev)) {
+			wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
+			return true;
+		}
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
+	}
+
+	return false;
+}
+
+/**
+ * pmo_support_wow_for_beaconing: wow query for beaconning
+ * @psoc: objmgr psoc handle
+ *
+ * Need to configure wow to enable beaconning offload when
+ * a beaconing vdev is up and beaonning offload is configured.
+ *
+ * Return: true if we need to enable wow for beaconning offload
+ */
+static
+bool pmo_support_wow_for_beaconing(struct wlan_objmgr_psoc *psoc)
+{
+	/*
+	 * if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
+	 *			WMI_SERVICE_BEACON_OFFLOAD))
+	 */
+	if (pmo_is_beaconning_vdev_up(psoc))
+		return true;
+
+	return false;
+}
+
+bool pmo_core_is_wow_applicable(struct wlan_objmgr_psoc *psoc)
+{
+	int vdev_id;
+	struct wlan_objmgr_psoc_objmgr *objmgr;
+	struct wlan_objmgr_vdev *vdev;
+	bool is_wow_applicable = false;
+	QDF_STATUS status;
+
+	if (!psoc) {
+		pmo_err("psoc is null");
+		return false;
+	}
+
+	if (pmo_support_wow_for_beaconing(psoc)) {
+		pmo_debug("one of vdev is in beaconning mode, enabling wow");
+		return true;
+	}
+
+	/* Iterate through VDEV list */
+	for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) {
+		wlan_psoc_obj_lock(psoc);
+		objmgr = &psoc->soc_objmgr;
+		if (!objmgr->wlan_vdev_list[vdev_id]) {
+			wlan_psoc_obj_unlock(psoc);
+			continue;
+		}
+		vdev = objmgr->wlan_vdev_list[vdev_id];
+		wlan_psoc_obj_unlock(psoc);
+
+		status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_PMO_ID);
+		if (status != QDF_STATUS_SUCCESS)
+			continue;
+
+		if (pmo_core_is_vdev_connected(vdev)) {
+			wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
+			pmo_debug("STA is connected, enabling wow");
+			is_wow_applicable = true;
+			break;
+		} else if (pmo_core_is_nlo_scan_in_progress(vdev)) {
+			wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
+			pmo_debug("NLO is in progress, enabling wow");
+			is_wow_applicable = true;
+			break;
+		} else if (pmo_core_is_extscan_in_progress(vdev)) {
+			wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
+			pmo_debug("EXT is in progress, enabling wow");
+			is_wow_applicable = true;
+			break;
+		} else if (pmo_core_is_p2plo_in_progress(vdev)) {
+			wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
+			pmo_debug("P2P LO is in progress, enabling wow");
+			is_wow_applicable = true;
+			break;
+		} else if (pmo_core_is_lpass_enabled(vdev)) {
+			wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
+			pmo_debug("LPASS is enabled, enabling WoW");
+			is_wow_applicable = true;
+			break;
+		} else if (pmo_core_is_nan_enabled(vdev)) {
+			wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
+			pmo_debug("NAN is enabled, enabling WoW");
+			is_wow_applicable = true;
+			break;
+		} else if (pmo_core_get_vdev_op_mode(vdev) == QDF_NDI_MODE) {
+			wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
+			pmo_debug("vdev %d is in NAN data mode, enabling wow",
+				vdev_id);
+			is_wow_applicable = true;
+			break;
+		}
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
+	}
+
+	if (is_wow_applicable)
+		return true;
+	pmo_debug("All vdev are in disconnected state\n"
+		"and pno/extscan is not in progress, skipping wow");
+
+	return false;
+}
+

+ 145 - 0
power_management_offloads/dispatcher/inc/wlan_pmo_common_public_struct.h

@@ -36,6 +36,7 @@
 #include "wmi_unified.h"
 #include "qdf_status.h"
 #include "qdf_lock.h"
+#include "qdf_event.h"
 
 #define PMO_IPV4_ADDR_LEN         4
 
@@ -53,6 +54,9 @@
 #define PMO_IPV6_ADDR_AC_TYPE                 1
 
 #define PMO_80211_ADDR_LEN  6  /* size of 802.11 address */
+
+#define PMO_WOW_REQUIRED_CREDITS 1
+
 /**
  * enum pmo_offload_type: tell offload type
  * @pmo_arp_offload: arp offload
@@ -65,6 +69,135 @@ enum pmo_offload_type {
 	pmo_gtk_offload,
 };
 
+/**
+ * enum pmo_vdev_param_id: tell vdev param id
+ * @pmo_vdev_param_listen_interval: vdev listen interval param id
+ * @pmo_vdev_param_dtim_policy: vdev param dtim policy
+ * @pmo_vdev_max_param: Max vdev param id
+ */
+enum pmo_vdev_param_id {
+	pmo_vdev_param_listen_interval = 0,
+	pmo_vdev_param_dtim_policy,
+	pmo_vdev_max_param
+};
+
+/**
+ * enum pmo_beacon_dtim_policy: tell vdev beacon policy
+ * @pmo_ignore_dtim: fwr need to igonre dtime policy
+ * @pmo_normal_dtim: fwr need to use normal dtime policy
+ * @pmo_stick_dtim: fwr need to use stick dtime policy
+ * @auto_dtim: fwr need to auto dtime policy
+ */
+enum pmo_beacon_dtim_policy {
+	pmo_ignore_dtim = 0x01,
+	pmo_normal_dtim = 0x02,
+	pmo_stick_dtim = 0x03,
+	pmo_auto_dtim = 0x04,
+};
+
+/**
+ * @pmo_sta_ps_param_rx_wake_policy: Controls how frames are retrievd from AP
+ *  while STA is sleeping.
+ * @pmo_sta_ps_param_tx_wake_threshold: STA will go active after this many TX
+ * @pmo_sta_ps_param_pspoll_count:No of PS-Poll to send before STA wakes up
+ * @pmo_sta_ps_param_inactivity_time: TX/RX inactivity time in msec before
+    going to sleep.
+ * @pmo_sta_ps_param_uapsd: Set uapsd configuration.
+ * @pmo_sta_ps_param_qpower_pspoll_count: No of PS-Poll to send before
+    STA wakes up in QPower Mode.
+ * @pmo_sta_ps_enable_qpower:  Enable QPower
+ * @pmo_sta_ps_param_qpower_max_tx_before_wake: Number of TX frames before the
+    entering the Active state
+ */
+enum pmo_sta_powersave_param {
+	pmo_sta_ps_param_rx_wake_policy = 0,
+	pmo_sta_ps_param_tx_wake_threshold = 1,
+	pmo_sta_ps_param_pspoll_count = 2,
+	pmo_sta_ps_param_inactivity_time = 3,
+	pmo_sta_ps_param_uapsd = 4,
+	pmo_sta_ps_param_qpower_pspoll_count = 5,
+	pmo_sta_ps_enable_qpower = 6,
+	pmo_sta_ps_param_qpower_max_tx_before_wake = 7,
+};
+
+/**
+ * enum powersave_qpower_mode: QPOWER modes
+ * @pmo_qpower_disabled: Qpower is disabled
+ * @pmo_qpower_enabled: Qpower is enabled
+ * @pmo_qpower_duty_cycling: Qpower is enabled with duty cycling
+ */
+enum pmo_power_save_qpower_mode {
+	pmo_qpower_disabled = 0,
+	pmo_qpower_enabled = 1,
+	pmo_qpower_duty_cycling = 2
+};
+
+/**
+ * enum powersave_qpower_mode: powersave_mode
+ * @pmo_ps_not_supported: Power save is not supported
+ * @pmo_ps_legacy_no_deep_sleep: Legacy pwr save enabled and deep sleep disabled
+ * @pmo_ps_qpower_no_deep_sleep: QPOWER enabled and deep sleep disabled
+ * @pmo_ps_legacy_deep_sleep: Legacy power save enabled and deep sleep enabled
+ * @pmo_ps_qpower_deep_sleep: QPOWER enabled and deep sleep enabled
+ * @pmo_ps_duty_cycling_qpower: QPOWER enabled in duty cycling mode
+ */
+enum pmo_powersave_mode {
+	pmo_ps_not_supported = 0,
+	pmo_ps_legacy_no_deep_sleep = 1,
+	pmo_ps_qpower_no_deep_sleep = 2,
+	pmo_ps_legacy_deep_sleep = 3,
+	pmo_ps_qpower_deep_sleep = 4,
+	pmo_ps_duty_cycling_qpower = 5
+};
+
+/**
+ * enum wow_resume_trigger - resume trigger override setting values
+ * @PMO_WOW_RESUME_TRIGGER_DEFAULT: fw to use platform default resume trigger
+ * @PMO_WOW_RESUME_TRIGGER_HTC_WAKEUP: force fw to use HTC Wakeup to resume
+ * @PMO_WOW_RESUME_TRIGGER_GPIO: force fw to use GPIO to resume
+ * @PMO_WOW_RESUME_TRIGGER_COUNT: number of resume trigger options
+ */
+enum pmo_wow_resume_trigger {
+	/* always first */
+	PMO_WOW_RESUME_TRIGGER_DEFAULT = 0,
+	PMO_WOW_RESUME_TRIGGER_HTC_WAKEUP,
+	PMO_WOW_RESUME_TRIGGER_GPIO,
+	/* always last */
+	PMO_WOW_RESUME_TRIGGER_COUNT
+};
+
+/**
+ * enum wow_interface_pause - interface pause override setting values
+ * @PMO_WOW_INTERFACE_PAUSE_DEFAULT: use platform default iface pause setting
+ * @PMO_WOW_INTERFACE_PAUSE_ENABLE: force interface pause setting to enabled
+ * @PMO_WOW_INTERFACE_PAUSE_DISABLE: force interface pause setting to disabled
+ * @PMO_WOW_INTERFACE_PAUSE_COUNT: number of interface pause options
+ */
+enum pmo_wow_interface_pause {
+	/* always first */
+	PMO_WOW_INTERFACE_PAUSE_DEFAULT = 0,
+	PMO_WOW_INTERFACE_PAUSE_ENABLE,
+	PMO_WOW_INTERFACE_PAUSE_DISABLE,
+	/* always last */
+	PMO_WOW_INTERFACE_PAUSE_COUNT
+};
+
+#define PMO_TGT_SUSPEND_COMPLETE_TIMEOUT   6000
+#define PMO_WAKE_LOCK_TIMEOUT              1000
+#define PMO_RESUME_TIMEOUT                 25000
+
+/**
+ * struct wow_enable_params - A collection of wow enable override parameters
+ * @is_unit_test: true to notify fw this is a unit-test suspend
+ * @interface_pause: used to override the interface pause indication sent to fw
+ * @resume_trigger: used to force fw to use a particular resume method
+ */
+struct pmo_wow_enable_params {
+	bool is_unit_test;
+	enum pmo_wow_interface_pause interface_pause;
+	enum pmo_wow_resume_trigger resume_trigger;
+};
+
 /**
  * typedef for psoc suspend handler
  */
@@ -124,6 +257,12 @@ enum pmo_offload_trigger {
  * @deauth_enable: true when wake up on deauth is enabled else false
  * @disassoc_enable:  true when wake up on disassoc is enabled else false
  * @bmiss_enable: true when wake up on bmiss is enabled else false
+ * @nan_enable:  true when nan is enabled else false
+ * @lpass_enable: true when lpass is enabled else false
+ * @sta_dynamic_dtim: station dynamic DTIM value
+ * @sta_mod_dtim: station modulated DTIM value
+ * @sta_max_li_mod_dtim: station max listen interval DTIM value
+ * @power_save_mode: power save mode for psoc
  */
 struct pmo_psoc_cfg {
 	bool ptrn_match_enable_all_vdev;
@@ -142,6 +281,12 @@ struct pmo_psoc_cfg {
 	bool deauth_enable;
 	bool disassoc_enable;
 	bool bmiss_enable;
+	bool nan_enable;
+	bool lpass_enable;
+	uint8_t sta_dynamic_dtim;
+	uint8_t sta_mod_dtim;
+	uint8_t sta_max_li_mod_dtim;
+	uint8_t power_save_mode;
 };
 
 #endif /* end  of _WLAN_PMO_COMMONP_STRUCT_H_ */

+ 176 - 0
power_management_offloads/dispatcher/inc/wlan_pmo_lphb_public_struct.h

@@ -0,0 +1,176 @@
+/*
+* Copyright (c) 2017 The Linux Foundation. All rights reserved.
+*
+* Permission to use, copy, modify, and/or distribute this software for
+* any purpose with or without fee is hereby granted, provided that the
+* above copyright notice and this permission notice appear in all
+* copies.
+*
+* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*/
+ /**
+  * DOC: Declare various struct, macros which shall be used in
+  * pmo lphb offload feature.
+  *
+  * Note: This file shall not contain public API's prototype/declarations.
+  *
+  */
+
+#ifndef _WLAN_PMO_LPHB_PUBLIC_STRUCT_H_
+#define _WLAN_PMO_LPHB_PUBLIC_STRUCT_H_
+
+#include "wlan_pmo_common_public_struct.h"
+
+#ifdef FEATURE_WLAN_LPHB
+#define PMO_SIR_LPHB_FILTER_LEN   64
+
+/**
+ * enum lphb_ind_type -Low power heart beat indication type
+ * @pmo_lphb_set_en_param_indid: lphb enable indication
+ * @pmo_lphb_set_tcp_pararm_indid: lphb tcp param indication
+ * @pmo_lphb_set_tcp_pkt_filter_indid: lphb tcp packet filter indication
+ * @pmo_lphb_set_udp_pararm_indid: lphb udp param indication
+ * @pmo_lphb_set_udp_pkt_filter_indid: lphb udp packet filter indication
+ * @pmo_lphb_set_network_info_indid: lphb network information indication
+ */
+enum lphb_ind_type {
+	pmo_lphb_set_en_param_indid,
+	pmo_lphb_set_tcp_pararm_indid,
+	pmo_lphb_set_tcp_pkt_filter_indid,
+	pmo_lphb_set_udp_pararm_indid,
+	pmo_lphb_set_udp_pkt_filter_indid,
+	pmo_lphb_set_network_info_indid,
+};
+
+/**
+ * struct pmo_lphb_enable_req -Low power heart beat enable request
+ * @enable: lphb enable request
+ * @item: request item
+ * @session: lphb session
+ */
+struct pmo_lphb_enable_req {
+	uint8_t enable;
+	uint8_t item;
+	uint8_t session;
+};
+
+/**
+ * struct pmo_lphb_tcp_params - Low power heart beat tcp params
+ * @srv_ip: source ip address
+ * @dev_ip: destination ip address
+ * @src_port: source port
+ * @dst_port: destination port
+ * @timeout: tcp timeout value
+ * @session: session on which lphb needs to be configured
+ * @gateway_mac: gateway mac address
+ * @time_period_sec: time period in seconds
+ * @tcp_sn: tcp sequence number
+ */
+struct pmo_lphb_tcp_params {
+	uint32_t srv_ip;
+	uint32_t dev_ip;
+	uint16_t src_port;
+	uint16_t dst_port;
+	uint16_t timeout;
+	uint8_t session;
+	struct qdf_mac_addr gateway_mac;
+	uint16_t time_period_sec;
+	uint32_t tcp_sn;
+};
+
+/**
+ * struct pmo_lphb_tcp_filter_req - Low power heart beat tcp filter request
+ * @length: length of filter
+ * @offset: offset of filter
+ * @session: session on which lphb needs to be configured
+ * @filter: filter buffer
+ */
+struct pmo_lphb_tcp_filter_req {
+	uint16_t length;
+	uint8_t offset;
+	uint8_t session;
+	uint8_t filter[PMO_SIR_LPHB_FILTER_LEN];
+};
+
+/**
+ * struct pmo_lphb_udp_params - Low power heart beat udp params
+ * @srv_ip: source ip address
+ * @dev_ip: destination ip address
+ * @src_port: source port
+ * @dst_port: destination port
+ * @timeout: tcp timeout value
+ * @session: session on which lphb needs to be configured
+ * @gateway_mac: gateway mac address
+ * @time_period_sec: time period in seconds
+ */
+struct pmo_lphb_udp_params {
+	uint32_t srv_ip;
+	uint32_t dev_ip;
+	uint16_t src_port;
+	uint16_t dst_port;
+	uint16_t interval;
+	uint16_t timeout;
+	uint8_t session;
+	struct qdf_mac_addr gateway_mac;
+};
+
+/**
+ * struct pmo_lphb_udp_filter_req - Low power heart beat udp filter request
+ * @length: length of filter
+ * @offset: offset of filter
+ * @session: session on which lphb needs to be configured
+ * @filter: filter buffer
+ */
+struct pmo_lphb_udp_filter_req {
+	uint16_t length;
+	uint8_t offset;
+	uint8_t session;
+	uint8_t filter[PMO_SIR_LPHB_FILTER_LEN];
+};
+
+/**
+ * struct pmo_lphb_req - Low power heart beat request
+ * @cmd: lphb command type
+ * @dummy: whether dummy or not
+ * @params: based on command lphb request buffer
+ */
+struct pmo_lphb_req {
+	uint16_t cmd;
+	uint16_t dummy;
+	union {
+		struct pmo_lphb_enable_req lphb_enable_req;
+		struct pmo_lphb_tcp_params lphb_tcp_params;
+		struct pmo_lphb_tcp_filter_req lphb_tcp_filter_req;
+		struct pmo_lphb_udp_params lphb_udp_params;
+		struct pmo_lphb_udp_filter_req lphb_udp_filter_req;
+	} params;
+};
+
+/**
+ * struct pmo_lphb_rsp - Low power heart beat response
+ * @session_idx: session id
+ * @protocol_type: tell protocol type
+ * @event_reason: carry reason of lphb event
+ */
+struct pmo_lphb_rsp {
+	uint8_t session_idx;
+	uint8_t protocol_type;   /*TCP or UDP */
+	uint8_t event_reason;
+};
+#endif /* FEATURE_WLAN_LPHB */
+
+/*
+ * Define typedef for lphb callback when fwr send response
+ */
+typedef
+void (*pmo_lphb_callback)(void *cb_ctx, struct pmo_lphb_rsp *ind_param);
+
+#endif /* end  of _WLAN_PMO_LPHB_PUBLIC_STRUCT_H_ */
+

+ 30 - 8
power_management_offloads/dispatcher/inc/wlan_pmo_obj_mgmt_api.h

@@ -105,6 +105,17 @@ QDF_STATUS pmo_register_suspend_handler(
 		pmo_psoc_suspend_handler handler,
 		void *arg);
 
+/**
+ * pmo_unregister_suspend_handler():unregister suspend handler for components
+ * @id: component id
+ * @handler: resume handler for the mention component
+ *
+ * Return QDF_STATUS status -in case of success else return error
+ */
+QDF_STATUS pmo_unregister_suspend_handler(
+		enum wlan_umac_comp_id id,
+		pmo_psoc_suspend_handler handler);
+
 /**
  * pmo_register_resume_handler(): API to register resume handler for components
  * @id: component id
@@ -119,23 +130,34 @@ QDF_STATUS pmo_register_resume_handler(
 		void *arg);
 
 /**
- * pmo_suspend_psoc(): API to suspend psoc
+ * pmo_unregister_resume_handler(): unregister resume handler for components
+ * @id: component id
+ * @handler: resume handler for the mention component
+ *
+ * Return QDF_STATUS status - in case of success else return error
+ */
+QDF_STATUS pmo_unregister_resume_handler(
+		enum wlan_umac_comp_id id,
+		pmo_psoc_resume_handler handler);
+
+/**
+ * pmo_suspend_all_components(): API to suspend all component
  * @psoc:objmgr psoc
- * @is_runtime_suspend: true for run time suspend else false
+ * @suspend_type: Tell suspend type (apps suspend / runtime suspend)
  *
  * Return QDF_STATUS status - in case of success else return error
  */
-QDF_STATUS pmo_suspend_psoc(struct wlan_objmgr_psoc *psoc,
-		bool is_runtime_suspend);
+QDF_STATUS pmo_suspend_all_components(struct wlan_objmgr_psoc *psoc,
+		enum qdf_suspend_type suspend_type);
 
 /**
- * pmo_resume_psoc(): API to resume psoc
+ * pmo_resume_all_components(): API to resume all component
  * @psoc:objmgr psoc
- * @is_runtime_resume: true for run time resume else false
+ * @suspend_type: Tell suspend type from which resume is required
  *
  * Return QDF_STATUS status - in case of success else return error
  */
-QDF_STATUS pmo_resume_psoc(struct wlan_objmgr_psoc *psoc,
-		bool is_runtime_resume);
+QDF_STATUS pmo_resume_all_components(struct wlan_objmgr_psoc *psoc,
+		enum qdf_suspend_type suspend_type);
 
 #endif /* end  of _WLAN_PMO_OBJ_MGMT_API_H_ */

+ 25 - 6
power_management_offloads/dispatcher/inc/wlan_pmo_obj_mgmt_public_struct.h

@@ -35,16 +35,17 @@
 
 /**
  * struct pmo_psoc_priv_obj - psoc related data require for pmo
- * @wow: place holder for psoc wow configuration
- * @ps_config: place holder for psoc power configuration
  * @psoc_cfg: place holder for psoc configuration
- * @wow: true  wow configuration
- * @lphb_cache: lphb cache
+ * @wow: wow configuration
+ * @dp_hdl: psoc data path handle
+ * @htc_hdl: htc layer handle
  * @lock: spin lock for pmo psoc
  */
 struct pmo_psoc_priv_obj {
 	struct pmo_psoc_cfg psoc_cfg;
 	struct pmo_wow wow;
+	void *dp_hdl;
+	void *htc_hdl;
 	qdf_spinlock_t lock;
 };
 
@@ -78,10 +79,19 @@ struct wlan_pmo_ctx {
  * @gtk_err_enable: gtk error is enabled or not
  * @vdev_bpf_req: place holder for apf/bpf for vdev
  * @vdev_pkt_filter: place holder for vdev packet filter
- * @dtim_period: dtim period
  * @ptrn_match_enable: true when pattern match is enabled else false
  * @num_wow_default_patterns: number of wow default patterns for vdev
  * @num_wow_user_patterns: number of user wow patterns for vdev
+ * @nlo_in_progress: true when pno/nlo in progress else false
+ * @nlo_match_received: true when nlo match recevied from fwr else false
+ * @extscan_in_progress: true when extscan in progress else false
+ * @p2plo_in_progress: true when p2plo_in_progress in progress else false
+ * @dtim_period: dtim period for vdev
+ * @beacon_interval: vdev beacon interval
+ * @alt_modulated_dtim_enabled:dynamic modulated dtim enabled
+ * @dtim_policy: tells vdev beacon dtim policy
+ * @pause_bitmap: tell about reason why vde is paused
+ * @vdev_dp_hdl: vdev data path handle
  * @pmo_vdev_lock: spin lock for pmo vdev priv ctx
  */
 struct pmo_vdev_priv_obj {
@@ -93,10 +103,19 @@ struct pmo_vdev_priv_obj {
 	struct pmo_gtk_req vdev_gtk_req;
 	struct pmo_gtk_rsp_req vdev_gtk_rsp_req;
 	qdf_atomic_t gtk_err_enable;
-	uint8_t dtim_period;
 	bool ptrn_match_enable;
 	uint8_t num_wow_default_patterns;
 	uint8_t num_wow_user_patterns;
+	bool nlo_in_progress;
+	bool nlo_match_received;
+	bool extscan_in_progress;
+	bool p2plo_in_progress;
+	uint8_t dtim_period;
+	uint8_t beacon_interval;
+	bool alt_modulated_dtim_enable;
+	uint32_t dtim_policy;
+	uint16_t pause_bitmap;
+	void *vdev_dp_hdl;
 	qdf_spinlock_t pmo_vdev_lock;
 };
 

+ 163 - 0
power_management_offloads/dispatcher/inc/wlan_pmo_tgt_api.h

@@ -184,4 +184,167 @@ QDF_STATUS pmo_tgt_get_gtk_rsp(struct wlan_objmgr_vdev *vdev);
 QDF_STATUS pmo_tgt_gtk_rsp_evt(struct wlan_objmgr_psoc *psoc,
 		struct pmo_gtk_rsp_params *rsp_param);
 
+/**
+ * pmo_tgt_send_lphb_enable() - enable command of LPHB configuration requests
+ * @psoc: objmgr psoc handle
+ * @ts_lphb_enable: lphb enable request which needs to configure in fwr
+ *
+ * Return: QDF status
+ */
+QDF_STATUS pmo_tgt_send_lphb_enable(struct wlan_objmgr_psoc *psoc,
+			struct pmo_lphb_enable_req *ts_lphb_enable);
+
+/**
+ * pmo_tgt_send_lphb_tcp_params() - set tcp params of LPHB configuration req
+ * @psoc: objmgr psoc handle
+ * @ts_lphb_tcp_param: lphb tcp params which needs to configure in fwr
+ *
+ * Return: QDF status
+ */
+QDF_STATUS pmo_tgt_send_lphb_tcp_params(struct wlan_objmgr_psoc *psoc,
+			struct pmo_lphb_tcp_params *ts_lphb_tcp_param);
+
+/**
+ * pmo_tgt_send_lphb_tcp_pkt_filter() - send tcp packet filter command of LPHB
+ * @psoc: objmgr psoc handle
+ * @ts_lphb_tcp_filter: lphb tcp filter request which needs to configure in fwr
+ *
+ * Return: QDF status
+ */
+QDF_STATUS pmo_tgt_send_lphb_tcp_pkt_filter(struct wlan_objmgr_psoc *psoc,
+			struct pmo_lphb_tcp_filter_req *ts_lphb_tcp_filter);
+
+/**
+ * pmo_tgt_send_lphb_udp_params() - Send udp param command of LPHB
+ * @psoc: objmgr psoc handle
+ * @ts_lphb_udp_param: lphb udp params which needs to configure in fwr
+ *
+ * Return: QDF status
+ */
+QDF_STATUS pmo_tgt_send_lphb_udp_params(struct wlan_objmgr_psoc *psoc,
+			struct pmo_lphb_udp_params *ts_lphb_udp_param);
+
+/**
+ * pmo_tgt_send_lphb_udp_pkt_filter() - Send udp pkt filter command of LPHB
+ * @psoc: objmgr psoc handle
+ * @ts_lphb_udp_filter: lphb udp filter request which needs to configure in fwr
+ *
+ * Return: QDF status
+ */
+QDF_STATUS pmo_tgt_send_lphb_udp_pkt_filter(struct wlan_objmgr_psoc *psoc,
+			struct pmo_lphb_udp_filter_req *ts_lphb_udp_filter);
+
+
+/**
+ * pmo_tgt_lphb_rsp_evt() - receive lphb rsp event from fwr
+ * @psoc: objmgr psoc
+ * @rsp_param: lphb response parameters
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS pmo_tgt_lphb_rsp_evt(struct wlan_objmgr_psoc *psoc,
+			struct pmo_lphb_rsp *rsp_param);
+
+/**
+ * pmo_tgt_vdev_update_param_req() - Update vdev param value to fwr
+ * @vdev: objmgr vdev
+ * @param_id: tell vdev param id which needs to be updated in fwr
+ * @param_value: vdev parameter value
+ *
+ * Return: QDF status
+ */
+QDF_STATUS pmo_tgt_vdev_update_param_req(struct wlan_objmgr_vdev *vdev,
+		enum pmo_vdev_param_id param_id, uint32_t param_value);
+
+/**
+ * pmo_tgt_send_vdev_sta_ps_param() - Send vdev sta power save param to fwr
+ * @vdev: objmgr vdev
+ * @ps_param: sta mode ps power save params type
+ * @param_value: power save parameter value
+ *
+ * Return: QDF status
+ */
+QDF_STATUS pmo_tgt_send_vdev_sta_ps_param(struct wlan_objmgr_vdev *vdev,
+		enum pmo_sta_powersave_param ps_param, uint32_t param_value);
+
+/**
+ * pmo_tgt_update_wow_bus_suspend_state() - update wow bus suspend state flag
+ * @psoc: objmgr psoc
+ * @val: true for setting wow suspend flag to set else false
+ *
+ * Return: None
+ */
+void pmo_tgt_psoc_update_wow_bus_suspend_state(struct wlan_objmgr_psoc *psoc,
+		uint8_t val);
+
+/**
+ * pmo_tgt_get_host_credits() - Get host credits
+ * @psoc: objmgr psoc
+ *
+ * Return: Pending WMI commands on success else EAGAIN on error
+ */
+int pmo_tgt_psoc_get_host_credits(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * pmo_tgt_get_pending_cmnds() - Get pending commands
+ * @psoc: objmgr psoc
+ *
+ * Return: Pending WMI commands on success else EAGAIN on error
+ */
+int pmo_tgt_psoc_get_pending_cmnds(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * pmo_tgt_update_target_suspend_flag() - Set WMI target Suspend flag
+ * @psoc: objmgr psoc
+ * @val: true on suspend false for resume
+ *
+ * Return: Pending WMI commands on success else EAGAIN on error
+ */
+void pmo_tgt_update_target_suspend_flag(struct wlan_objmgr_psoc *psoc,
+		uint8_t val);
+
+/**
+ * pmo_tgt_psoc_send_wow_enable_req() -Send wow enable request
+ * @psoc: objmgr psoc
+ * @param: WOW enable request buffer
+ *
+ * Return: QDF_STATUS_SUCCESS on success else error code
+ */
+QDF_STATUS pmo_tgt_psoc_send_wow_enable_req(struct wlan_objmgr_psoc *psoc,
+	struct pmo_wow_cmd_params *param);
+
+/**
+ * pmo_tgt_psoc_send_supend_req() -Send target suspend request to fwr
+ * @psoc: objmgr psoc
+ * @param: suspend request buffer
+ *
+ * Return: QDF_STATUS_SUCCESS on success else error code
+ */
+QDF_STATUS pmo_tgt_psoc_send_supend_req(struct wlan_objmgr_psoc *psoc,
+		struct pmo_suspend_params *param);
+
+/**
+ * pmo_tgt_psoc_get_runtime_pm_in_progress() -get runtime status
+ * @psoc: objmgr psoc
+ *
+ * Return: true if runtime pm is in progress else false
+ */
+bool pmo_tgt_psoc_get_runtime_pm_in_progress(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * pmo_tgt_psoc_send_host_wakeup_ind() -Send host wake up indication to fwr
+ * @psoc: objmgr psoc
+ *
+ * Return: QDF_STATUS_SUCCESS on success else error code
+ */
+QDF_STATUS pmo_tgt_psoc_send_host_wakeup_ind(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * pmo_tgt_psoc_send_target_resume_req() -Send target resume request
+ * @psoc: objmgr psoc
+ *
+ * Return: QDF_STATUS_SUCCESS on success else error code
+ */
+QDF_STATUS pmo_tgt_psoc_send_target_resume_req(struct wlan_objmgr_psoc *psoc);
+
 #endif /* end  of _WLAN_PMO_TGT_API_H_ */

+ 210 - 0
power_management_offloads/dispatcher/inc/wlan_pmo_ucfg_api.h

@@ -287,4 +287,214 @@ QDF_STATUS pmo_ucfg_disable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev);
 QDF_STATUS pmo_ucfg_get_gtk_rsp(struct wlan_objmgr_vdev *vdev,
 		struct pmo_gtk_rsp_req *gtk_rsp_req);
 
+/**
+ * pmo_ucfg_update_nlo_scan_in_progress(): update nlo scan is in progress flags
+ * @vdev: objmgr vdev handle
+ * @value:true if pno scan is in progress else false
+ *
+ * Return: TRUE/FALSE
+ */
+void pmo_ucfg_update_nlo_scan_in_progress(struct wlan_objmgr_vdev *vdev,
+	bool value);
+
+/**
+ * pmo_ucfg_update_nlo_match_found(): Update nlo scan match flag to value
+ * @vdev: objmgr vdev handle
+ * @value:true if nlo scan match event received else false
+ *
+ * Return: TRUE/FALSE
+ */
+void pmo_ucfg_update_nlo_match_found(struct wlan_objmgr_vdev *vdev,
+	bool value);
+
+/**
+ * pmo_ucfg_update_extscan_in_progress(): update extscan is in progress flags
+ * @vdev: objmgr vdev handle
+ * @value:true if extscan is in progress else false
+ *
+ * Return: TRUE/FALSE
+ */
+void pmo_ucfg_update_extscan_in_progress(struct wlan_objmgr_vdev *vdev,
+	bool value);
+
+/**
+ * pmo_ucfg_update_p2plo_in_progress(): update p2plo is in progress flags
+ * @vdev: objmgr vdev handle
+ * @value:true if p2plo is in progress else false
+ *
+ * Return: TRUE/FALSE
+ */
+void pmo_ucfg_update_p2plo_in_progress(struct wlan_objmgr_vdev *vdev,
+	bool value);
+
+/**
+ * pmo_ucfg_lphb_config_req() -  Handles lphb config request for psoc
+ * @psoc: objmgr psoc handle
+ * @lphb_req: low power heart beat request
+ * @lphb_cb_ctx: Context which needs to pass to soif when lphb callback called
+ * @callback: upon receiving of lphb indication from fwr call lphb callback
+ *
+ * Return: QDF status
+ */
+QDF_STATUS pmo_ucfg_lphb_config_req(struct wlan_objmgr_psoc *psoc,
+		struct pmo_lphb_req *lphb_req, void *lphb_cb_ctx,
+		pmo_lphb_callback callback);
+
+/**
+ * pmo_ucfg_update_alt_modulated_dtim_enable() - update alt modulatate dtim
+ * @vdev: objmgr vdev handle
+ * @value: true for alt_modulated_dtim enable else false
+ *
+ * Return: QDF status
+ */
+void pmo_ucfg_update_alt_modulated_dtim_enable(struct wlan_objmgr_vdev *vdev,
+	bool value);
+
+/**
+ * pmo_ucfg_psoc_update_power_save_mode() - update power save mode
+ * @vdev: objmgr vdev handle
+ * @value:vdev power save mode
+ *
+ * Return: None
+ */
+void pmo_ucfg_psoc_update_power_save_mode(struct wlan_objmgr_psoc *psoc,
+	uint8_t value);
+
+/**
+ * pmo_ucfg_psoc_update_dp_handle() - update psoc data path handle
+ * @psoc: objmgr psoc handle
+ * @dp_hdl: psoc data path handle
+ *
+ * Return: None
+ */
+void pmo_ucfg_psoc_update_dp_handle(struct wlan_objmgr_psoc *psoc,
+	void *dp_hdl);
+
+/**
+ * pmo_ucfg_vdev_update_dp_handle() - update vdev data path handle
+ * @vdev: objmgr vdev handle
+ * @dp_hdl: vdev data path handle
+ *
+ * Return: None
+ */
+void pmo_ucfg_vdev_update_dp_handle(struct wlan_objmgr_vdev *vdev,
+	void *dp_hdl);
+
+/**
+ * pmo_ucfg_psoc_update_htc_handle() - update psoc htc layer handle
+ * @psoc: objmgr psoc handle
+ * @htc_handle: psoc host-to-tagret layer (htc) handle
+ *
+ * Return: None
+ */
+void pmo_ucfg_psoc_update_htc_handle(struct wlan_objmgr_psoc *psoc,
+		void *htc_handle);
+
+/**
+ * pmo_ucfg_psoc_user_space_suspend_req() -  Handles user space suspend req
+ * @psoc: objmgr psoc handle
+ * @type: type of suspend
+ *
+ * Handles user space suspend indication for psoc
+ *
+ * Return: QDF status
+ */
+QDF_STATUS pmo_ucfg_psoc_user_space_suspend_req(struct wlan_objmgr_psoc *psoc,
+		enum qdf_suspend_type type);
+
+/**
+ * pmo_ucfg_psoc_user_space_resume_req() -  Handles user space resume req
+ * @psoc: objmgr psoc handle
+ * @type: type of suspend from which resume needed
+ *
+ * Handles user space resume indication for psoc
+ *
+ * Return: QDF status
+ */
+QDF_STATUS pmo_ucfg_psoc_user_space_resume_req(struct wlan_objmgr_psoc *psoc,
+		enum qdf_suspend_type type);
+
+/**
+ * pmo_ucfg_psoc_bus_suspend_req(): handles bus suspend for psoc
+ * @psoc: objmgr psoc
+ * @type: is this suspend part of runtime suspend or system suspend?
+ * @wow_params: collection of wow enable override parameters
+ *
+ * Bails if a scan is in progress.
+ * Calls the appropriate handlers based on configuration and event.
+ *
+ * Return: QDF_STATUS_SUCCESS for success or error code
+ */
+QDF_STATUS pmo_ucfg_psoc_bus_suspend_req(struct wlan_objmgr_psoc *psoc,
+		enum qdf_suspend_type type,
+		struct pmo_wow_enable_params *wow_params);
+
+/**
+ * pmo_ucfg_psoc_suspend_target() -Send suspend target command
+ * @psoc: objmgr psoc handle
+ * @disable_target_intr: disable target interrupt
+ *
+ * Return: QDF_STATUS_SUCCESS for success or error code
+ */
+QDF_STATUS pmo_ucfg_psoc_suspend_target(struct wlan_objmgr_psoc *psoc,
+		int disable_target_intr);
+
+/**
+ * pmo_ucfg_psoc_bus_resume() -handle bus resume request for psoc
+ * @psoc: objmgr psoc handle
+ * @type: is this suspend part of runtime suspend or system suspend?
+ *
+ * Return:QDF_STATUS_SUCCESS on success else error code
+ */
+QDF_STATUS pmo_ucfg_psoc_bus_resume_req(struct wlan_objmgr_psoc *psoc,
+		enum qdf_suspend_type type);
+
+/**
+ * pmo_ucfg_get_wow_bus_suspend(): API to check if wow bus is suspended or not
+ * @psoc: objmgr psoc handle
+ *
+ * Return: True if bus suspende else false
+ */
+bool pmo_ucfg_get_wow_bus_suspend(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * pmo_ucfg_psoc_handle_initial_wake_up() - update initial wake up
+ * @cb_ctx: objmgr psoc handle as void * due to htc layer is not aware psoc
+ *
+ * Return: None
+ */
+void pmo_ucfg_psoc_handle_initial_wake_up(void *cb_ctx);
+
+/**
+ * pmo_ucfg_psoc_is_target_wake_up_received() - Get initial wake up status
+ * @psoc: objmgr psoc handle
+ *
+ * Return: 0 on success else error code
+ */
+int pmo_ucfg_psoc_is_target_wake_up_received(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * pmo_ucfg_psoc_is_target_wake_up_received() - Clear initial wake up status
+ * @psoc: objmgr psoc handle
+ *
+ * Return: 0 on success else error code
+ */
+int pmo_ucfg_psoc_clear_target_wake_up(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * pmo_ucfg_psoc_target_suspend_acknowledge() - Clear initial wake up status
+ * @psoc: objmgr psoc handle
+ *
+ * Return: None
+ */
+void pmo_ucfg_psoc_target_suspend_acknowledge(void *context, bool wow_nack);
+
+/**
+ * pmo_ucfg_psoc_wakeup_host_event_received() - got host wake up evennt from fwr
+ * @psoc: objmgr psoc handle
+ *
+ * Return: None
+ */
+void pmo_ucfg_psoc_wakeup_host_event_received(struct wlan_objmgr_psoc *psoc);
+
 #endif /* end  of _WLAN_PMO_UCFG_API_H_ */

+ 40 - 31
power_management_offloads/dispatcher/inc/wlan_pmo_wow_public_struct.h

@@ -24,6 +24,8 @@
   */
 
 #ifndef _WLAN_PMO_WOW_PUBLIC_STRUCT_H_
+#include "wlan_pmo_lphb_public_struct.h"
+
 #define _WLAN_PMO_WOW_PUBLIC_STRUCT_H_
 
 #define PMO_WOWL_PTRN_MAX_SIZE          146
@@ -141,42 +143,20 @@ enum pmo_wow_action_wakeup_opertion {
 	pmo_action_wakeup_del_set,
 };
 
-/**
- * struct pmo_lphb_enable_req -pmo lphb enable request
- * @enable: true if enable else false
- * @item: item number
- * @session: session number
- */
-struct pmo_lphb_enable_req {
-	bool enable;
-	uint8_t item;
-	uint8_t session;
-};
-
-/**
- * struct pmo_lphb_req -pmo lphb request
- * @cmd: command
- * @dummy: true if dummy else false
- * @params: place holder for lphb enable request
- */
-struct pmo_lphb_req {
-	uint16_t cmd;
-	uint16_t dummy;
-	union {
-		struct pmo_lphb_enable_req lphb_enable_req;
-	} params;
-};
-
 /**
  * struct pmo_wow - store wow patterns
- * @magic_ptrn_enable: magic pattern enable/disable
  * @wow_enable: wow enable/disable
  * @wow_enable_cmd_sent: is wow enable command sent to fw
- * @deauth_enable: is deauth wakeup enable/disable
- * @disassoc_enable: is disassoc wakeup enable/disable
- * @bmiss_enable: is bmiss wakeup enable/disable
- * @gtk_pdev_enable: is GTK based wakeup enable/disable
+ * @is_wow_bus_suspended: true if bus is suspended
+ * @target_suspend: target suspend event
+ * @target_resume: target resume event
+ * @wow_nack: wow negative ack flag
+ * @wow_initial_wake_up: target initial wake up is received
+ * @wow_wake_lock: wow wake lock
  * @lphb_cache: lphb cache
+ * @lphb_cb_ctx: callback context for lphb, kept as void* as
+ *                        osif structures are opaque to pmo.
+ * @pmo_lphb_callback: registered os if calllback function
  *
  * This structure stores wow patterns and
  * wow related parameters in host.
@@ -184,11 +164,19 @@ struct pmo_lphb_req {
 struct pmo_wow {
 	bool wow_enable;
 	bool wow_enable_cmd_sent;
+	bool is_wow_bus_suspended;
+	qdf_event_t target_suspend;
+	qdf_event_t target_resume;
+	int wow_nack;
+	bool wow_initial_wake_up;
+	qdf_wake_lock_t wow_wake_lock;
 	/*
 	 * currently supports only vdev 0.
 	 * cache has two entries: one for TCP and one for UDP.
 	 */
 	struct pmo_lphb_req lphb_cache[2];
+	void *lphb_cb_ctx;
+	pmo_lphb_callback lphb_cb;
 };
 
 /* WOW related structures */
@@ -229,4 +217,25 @@ struct pmo_wow_enter_params {
 	uint8_t wow_bss_conn_loss;
 };
 
+/**
+ * struct pmo_wow_cmd_params - wow cmd parameter
+ * @enable: wow enable or disable flag
+ * @can_suspend_link: flag to indicate if link can be suspended
+ * @pause_iface_config: interface config
+ */
+struct pmo_wow_cmd_params {
+	bool enable;
+	bool can_suspend_link;
+	uint8_t pause_iface_config;
+	uint32_t flags;
+};
+
+/**
+ * struct pmo_suspend_params - suspend cmd parameter
+ * @disable_target_intr: disable target interrupt
+ */
+struct pmo_suspend_params {
+	uint8_t disable_target_intr;
+};
+
 #endif /* end  of _WLAN_PMO_WOW_PUBLIC_STRUCT_H_ */

+ 201 - 12
power_management_offloads/dispatcher/src/wlan_pmo_obj_mgmt_api.c

@@ -172,6 +172,19 @@ QDF_STATUS pmo_psoc_object_created_notification(
 		goto out;
 	}
 	qdf_spinlock_create(&psoc_ctx->lock);
+	qdf_wake_lock_create(&psoc_ctx->wow.wow_wake_lock, "pmo_wow_wl");
+	status = qdf_event_create(&psoc_ctx->wow.target_suspend);
+	if (status != QDF_STATUS_SUCCESS) {
+		pmo_err("target suspend event initialization failed");
+		status = QDF_STATUS_E_FAILURE;
+		goto out;
+	}
+	status = qdf_event_create(&psoc_ctx->wow.target_resume);
+	if (status != QDF_STATUS_SUCCESS) {
+		pmo_err("target resume event initialization failed");
+		status = QDF_STATUS_E_FAILURE;
+		goto out;
+	}
 out:
 	PMO_EXIT();
 
@@ -202,6 +215,9 @@ QDF_STATUS pmo_psoc_object_destroyed_notification(
 	}
 
 	qdf_spinlock_destroy(&psoc_ctx->lock);
+	qdf_event_destroy(&psoc_ctx->wow.target_suspend);
+	qdf_event_destroy(&psoc_ctx->wow.target_resume);
+	qdf_wake_lock_destroy(&psoc_ctx->wow.wow_wake_lock);
 	qdf_mem_free(psoc_ctx);
 out:
 	PMO_EXIT();
@@ -317,10 +333,49 @@ QDF_STATUS pmo_register_suspend_handler(
 		goto out;
 	}
 
-	qdf_spin_lock(&pmo_ctx->lock);
+	qdf_spin_lock_bh(&pmo_ctx->lock);
 	pmo_ctx->pmo_suspend_handler[id] = handler;
-	pmo_ctx->pmo_suspend_handler_arg[id] = handler;
-	qdf_spin_unlock(&pmo_ctx->lock);
+	pmo_ctx->pmo_suspend_handler_arg[id] = arg;
+	qdf_spin_unlock_bh(&pmo_ctx->lock);
+out:
+	PMO_EXIT();
+
+	return status;
+}
+
+QDF_STATUS pmo_unregister_suspend_handler(
+		enum wlan_umac_comp_id id,
+		pmo_psoc_suspend_handler handler)
+{
+	struct wlan_pmo_ctx *pmo_ctx;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	PMO_ENTER();
+	pmo_ctx = pmo_get_context();
+	if (!pmo_ctx) {
+		QDF_ASSERT(0);
+		pmo_err("unable to get pmo ctx");
+		status = QDF_STATUS_E_FAILURE;
+		goto out;
+	}
+
+	if (id > WLAN_UMAC_MAX_COMPONENTS || id < 0) {
+		pmo_err("component id: %d is %s then valid components id",
+			id, id < 0 ? "Less" : "More");
+		status = QDF_STATUS_E_FAILURE;
+		goto out;
+	}
+
+	qdf_spin_lock_bh(&pmo_ctx->lock);
+	if (pmo_ctx->pmo_suspend_handler[id] == handler) {
+		pmo_ctx->pmo_suspend_handler[id] = NULL;
+		pmo_ctx->pmo_suspend_handler_arg[id] = NULL;
+		qdf_spin_unlock_bh(&pmo_ctx->lock);
+	} else {
+		qdf_spin_unlock_bh(&pmo_ctx->lock);
+		pmo_err("can't find suspend handler for component id: %d ", id);
+		status = QDF_STATUS_E_FAILURE;
+	}
 out:
 	PMO_EXIT();
 
@@ -350,25 +405,159 @@ QDF_STATUS pmo_register_resume_handler(
 		goto out;
 	}
 
-	qdf_spin_lock(&pmo_ctx->lock);
+	qdf_spin_lock_bh(&pmo_ctx->lock);
 	pmo_ctx->pmo_resume_handler[id] = handler;
-	pmo_ctx->pmo_resume_handler_arg[id] = handler;
-	qdf_spin_unlock(&pmo_ctx->lock);
+	pmo_ctx->pmo_resume_handler_arg[id] = arg;
+	qdf_spin_unlock_bh(&pmo_ctx->lock);
 out:
 	PMO_EXIT();
 
 	return status;
 }
 
-QDF_STATUS pmo_suspend_psoc(struct wlan_objmgr_psoc *psoc,
-		bool is_runtime_suspend)
+QDF_STATUS pmo_unregister_resume_handler(
+		enum wlan_umac_comp_id id,
+		pmo_psoc_resume_handler handler)
 {
-	return QDF_STATUS_SUCCESS;
+	struct wlan_pmo_ctx *pmo_ctx;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	PMO_ENTER();
+	pmo_ctx = pmo_get_context();
+	if (!pmo_ctx) {
+		pmo_err("unable to get pmo ctx");
+		status = QDF_STATUS_E_FAILURE;
+		goto out;
+	}
+
+	if (id > WLAN_UMAC_MAX_COMPONENTS || id < 0) {
+		pmo_err("component id: %d is %s then valid components id",
+			id, id < 0 ? "Less" : "More");
+		status = QDF_STATUS_E_FAILURE;
+		goto out;
+	}
+
+	qdf_spin_lock_bh(&pmo_ctx->lock);
+	if (pmo_ctx->pmo_resume_handler[id] == handler) {
+		pmo_ctx->pmo_resume_handler[id] = NULL;
+		pmo_ctx->pmo_resume_handler_arg[id] = NULL;
+		qdf_spin_unlock_bh(&pmo_ctx->lock);
+	} else {
+		qdf_spin_unlock_bh(&pmo_ctx->lock);
+		pmo_err("can't find resume handler for component id: %d ", id);
+		status = QDF_STATUS_E_FAILURE;
+	}
+out:
+	PMO_EXIT();
+
+	return status;
 }
 
-QDF_STATUS pmo_resume_psoc(struct wlan_objmgr_psoc *psoc,
-		bool is_runtime_resume)
+QDF_STATUS pmo_suspend_all_components(struct wlan_objmgr_psoc *psoc,
+	enum qdf_suspend_type suspend_type)
 {
-	return QDF_STATUS_SUCCESS;
+	pmo_psoc_suspend_handler handler;
+	uint8_t index = 0;
+	QDF_STATUS suspend_status = QDF_STATUS_SUCCESS;
+	QDF_STATUS resume_status = QDF_STATUS_SUCCESS;
+	void *arg;
+	struct wlan_pmo_ctx *pmo_ctx;
+
+	PMO_ENTER();
+	pmo_ctx = pmo_get_context();
+	if (!pmo_ctx) {
+		QDF_ASSERT(0);
+		pmo_err("unable to get pmo ctx");
+		suspend_status = QDF_STATUS_E_FAILURE;
+		goto out;
+	}
+
+	/* call all component's Suspend Handler */
+	while (index < WLAN_UMAC_MAX_COMPONENTS) {
+		qdf_spin_lock_bh(&pmo_ctx->lock);
+		if (pmo_ctx->pmo_suspend_handler[index]) {
+			handler = pmo_ctx->pmo_suspend_handler[index];
+			arg = pmo_ctx->pmo_suspend_handler_arg[index];
+			qdf_spin_unlock_bh(&pmo_ctx->lock);
+			suspend_status = handler(psoc, arg);
+			if (suspend_status != QDF_STATUS_SUCCESS) {
+				pmo_err("component id: %d failed to suspend status: %d",
+					index, suspend_status);
+				QDF_ASSERT(0);
+				/* break, no need to suspend next components */
+				break;
+			}
+		} else {
+			qdf_spin_unlock_bh(&pmo_ctx->lock);
+		}
+		index++;
+	}
+
+	/* resume the succefully suspended components */
+	if (suspend_status != QDF_STATUS_SUCCESS) {
+		while (index >= 0) {
+			/*
+			 * index points to id which refuse suspend
+			 * so go to previous id.
+			 */
+			index--;
+			qdf_spin_lock_bh(&pmo_ctx->lock);
+			handler = pmo_ctx->pmo_resume_handler[index];
+			arg = pmo_ctx->pmo_resume_handler_arg[index];
+			qdf_spin_unlock_bh(&pmo_ctx->lock);
+			/* TODO: if resume got failed for some component ?? */
+			resume_status = handler(psoc, arg);
+			if (resume_status != QDF_STATUS_SUCCESS) {
+				pmo_err("Component id: %d failed to resume status: %d",
+					index, resume_status);
+				QDF_ASSERT(0);
+			}
+		}
+	}
+out:
+	PMO_EXIT();
+
+	return suspend_status;
+}
+
+QDF_STATUS pmo_resume_all_components(struct wlan_objmgr_psoc *psoc,
+	enum qdf_suspend_type suspend_type)
+{
+	uint8_t index = 0;
+	QDF_STATUS component_ret = QDF_STATUS_SUCCESS;
+	void *arg;
+	struct wlan_pmo_ctx *pmo_ctx;
+	pmo_psoc_suspend_handler handler;
+
+	PMO_ENTER();
+	pmo_ctx = pmo_get_context();
+	if (!pmo_ctx) {
+		QDF_ASSERT(0);
+		pmo_err("unable to get pmo ctx");
+		component_ret = QDF_STATUS_E_FAILURE;
+		goto out;
+	}
+
+	/* call all components Resume Handler */
+	while (index < WLAN_UMAC_MAX_COMPONENTS) {
+		qdf_spin_lock_bh(&pmo_ctx->lock);
+		if (pmo_ctx->pmo_resume_handler[index]) {
+			handler = pmo_ctx->pmo_resume_handler[index];
+			arg = pmo_ctx->pmo_resume_handler_arg[index];
+			qdf_spin_unlock_bh(&pmo_ctx->lock);
+			component_ret = handler(psoc, arg);
+			if (component_ret != QDF_STATUS_SUCCESS) {
+				pmo_err("Component id: %d failed to resume status: %d",
+					index, component_ret);
+				QDF_ASSERT(0);
+			}
+		} else {
+			qdf_spin_unlock_bh(&pmo_ctx->lock);
+		}
+		index++;
 }
+out:
+	PMO_EXIT();
 
+	return component_ret;
+}

+ 159 - 0
power_management_offloads/dispatcher/src/wlan_pmo_tgt_lphb.c

@@ -0,0 +1,159 @@
+/*
+* Copyright (c) 2017 The Linux Foundation. All rights reserved.
+*
+* Permission to use, copy, modify, and/or distribute this software for
+* any purpose with or without fee is hereby granted, provided that the
+* above copyright notice and this permission notice appear in all
+* copies.
+*
+* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*/
+/**
+ * DOC: Implements public API for pmo low power hear beat feature
+ * to interact with target/WMI.
+ */
+
+#include "wlan_pmo_tgt_api.h"
+#include "wlan_pmo_lphb_public_struct.h"
+#include "wlan_pmo_obj_mgmt_public_struct.h"
+
+QDF_STATUS pmo_tgt_send_lphb_enable(struct wlan_objmgr_psoc *psoc,
+		struct pmo_lphb_enable_req *ts_lphb_enable)
+{
+	QDF_STATUS status;
+	struct wlan_lmac_if_pmo_tx_ops pmo_tx_ops;
+
+	PMO_ENTER();
+	pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc);
+	if (!pmo_tx_ops.send_lphb_enable) {
+		pmo_err("send_lphb_enable is null");
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto out;
+	}
+	status = pmo_tx_ops.send_lphb_enable(psoc, ts_lphb_enable);
+	if (status != QDF_STATUS_SUCCESS)
+		pmo_err("Failed to send lphb enable");
+out:
+	PMO_EXIT();
+
+	return status;
+}
+
+QDF_STATUS pmo_tgt_send_lphb_tcp_params(struct wlan_objmgr_psoc *psoc,
+		struct pmo_lphb_tcp_params *ts_lphb_tcp_param)
+{
+	QDF_STATUS status;
+	struct wlan_lmac_if_pmo_tx_ops pmo_tx_ops;
+
+	PMO_ENTER();
+	pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc);
+	if (!pmo_tx_ops.send_lphb_tcp_params) {
+		pmo_err("send_lphb_tcp_params is null");
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto out;
+	}
+	status = pmo_tx_ops.send_lphb_tcp_params(psoc, ts_lphb_tcp_param);
+	if (status != QDF_STATUS_SUCCESS)
+		pmo_err("Failed to send lphb tcp params");
+out:
+	PMO_EXIT();
+
+	return status;
+}
+
+QDF_STATUS pmo_tgt_send_lphb_tcp_pkt_filter(struct wlan_objmgr_psoc *psoc,
+		struct pmo_lphb_tcp_filter_req *ts_lphb_tcp_filter)
+{
+	QDF_STATUS status;
+	struct wlan_lmac_if_pmo_tx_ops pmo_tx_ops;
+
+	PMO_ENTER();
+	pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc);
+	if (!pmo_tx_ops.send_lphb_tcp_filter_req) {
+		pmo_err("send_lphb_tcp_filter_req is null");
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto out;
+	}
+	status = pmo_tx_ops.send_lphb_tcp_filter_req(psoc, ts_lphb_tcp_filter);
+	if (status != QDF_STATUS_SUCCESS)
+		pmo_err("Failed to send lphb tcp filter req");
+out:
+	PMO_EXIT();
+
+	return status;
+}
+
+QDF_STATUS pmo_tgt_send_lphb_udp_params(struct wlan_objmgr_psoc *psoc,
+		struct pmo_lphb_udp_params *ts_lphb_udp_param)
+{
+	QDF_STATUS status;
+	struct wlan_lmac_if_pmo_tx_ops pmo_tx_ops;
+
+	PMO_ENTER();
+	pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc);
+	if (!pmo_tx_ops.send_lphb_upd_params) {
+		pmo_err("send_lphb_upd_params is null");
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto out;
+	}
+	status = pmo_tx_ops.send_lphb_upd_params(psoc, ts_lphb_udp_param);
+	if (status != QDF_STATUS_SUCCESS)
+		pmo_err("Failed to send lphb udp param");
+out:
+	PMO_EXIT();
+
+	return status;
+}
+
+QDF_STATUS pmo_tgt_send_lphb_udp_pkt_filter(struct wlan_objmgr_psoc *psoc,
+		struct pmo_lphb_udp_filter_req *ts_lphb_udp_filter)
+{
+	QDF_STATUS status;
+	struct wlan_lmac_if_pmo_tx_ops pmo_tx_ops;
+
+	PMO_ENTER();
+	pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc);
+	if (!pmo_tx_ops.send_lphb_udp_filter_req) {
+		pmo_err("send_lphb_udp_filter_req is null");
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto out;
+	}
+	status = pmo_tx_ops.send_lphb_udp_filter_req(psoc, ts_lphb_udp_filter);
+	if (status != QDF_STATUS_SUCCESS)
+		pmo_err("Failed to send lphb udp filter req");
+out:
+	PMO_EXIT();
+
+	return status;
+}
+
+QDF_STATUS pmo_tgt_lphb_rsp_evt(struct wlan_objmgr_psoc *psoc,
+			struct pmo_lphb_rsp *rsp_param)
+{
+	struct pmo_psoc_priv_obj *psoc_ctx;
+
+	psoc_ctx = pmo_get_psoc_priv_ctx(psoc);
+	if (!psoc_ctx) {
+		pmo_err("psoc_ctx is null");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	if (psoc_ctx->wow.lphb_cb && psoc_ctx->wow.lphb_cb_ctx) {
+		pmo_info("callback:%p context:%p psoc:%p",
+			psoc_ctx->wow.lphb_cb, psoc_ctx->wow.lphb_cb_ctx, psoc);
+		psoc_ctx->wow.lphb_cb(psoc_ctx->wow.lphb_cb_ctx, rsp_param);
+	} else {
+		pmo_err("lphb rsp callback/context is null for psoc %p",
+			psoc);
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+

+ 208 - 0
power_management_offloads/dispatcher/src/wlan_pmo_tgt_suspend_resume.c

@@ -0,0 +1,208 @@
+/*
+* Copyright (c) 2017 The Linux Foundation. All rights reserved.
+*
+* Permission to use, copy, modify, and/or distribute this software for
+* any purpose with or without fee is hereby granted, provided that the
+* above copyright notice and this permission notice appear in all
+* copies.
+*
+* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+* PERFORMANCE OF THIS SOFTWARE.
+*/
+/**
+ * DOC: Implements public API for pmo to interact with target/WMI
+ */
+
+#include "wlan_pmo_tgt_api.h"
+#include "wlan_pmo_wow.h"
+#include "wlan_pmo_obj_mgmt_public_struct.h"
+
+QDF_STATUS pmo_tgt_vdev_update_param_req(struct wlan_objmgr_vdev *vdev,
+		enum pmo_vdev_param_id param_id, uint32_t param_value)
+{
+	QDF_STATUS status;
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_lmac_if_pmo_tx_ops pmo_tx_ops;
+
+	PMO_ENTER();
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		pmo_err("Failed to find psoc from from vdev:%p",
+			vdev);
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto out;
+	}
+
+	pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc);
+	if (!pmo_tx_ops.send_vdev_param_update_req) {
+		pmo_err("send_vdev_param_update_req is null");
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto out;
+	}
+
+	status = pmo_tx_ops.send_vdev_param_update_req(vdev, param_id,
+			param_value);
+out:
+	PMO_EXIT();
+
+	return status;
+}
+
+QDF_STATUS pmo_tgt_send_vdev_sta_ps_param(struct wlan_objmgr_vdev *vdev,
+		enum pmo_sta_powersave_param ps_param, uint32_t param_value)
+{
+	QDF_STATUS status;
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_lmac_if_pmo_tx_ops pmo_tx_ops;
+
+	PMO_ENTER();
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		pmo_err("Failed to find psoc from from vdev:%p",
+			vdev);
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto out;
+	}
+
+	pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc);
+	if (!pmo_tx_ops.send_vdev_sta_ps_param_req) {
+		pmo_err("send_vdev_param_set_req is null");
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto out;
+	}
+
+	status = pmo_tx_ops.send_vdev_sta_ps_param_req(vdev, ps_param,
+			param_value);
+out:
+	PMO_EXIT();
+
+	return status;
+}
+
+void pmo_tgt_psoc_update_wow_bus_suspend_state(struct wlan_objmgr_psoc *psoc,
+		uint8_t val)
+{
+	struct wlan_lmac_if_pmo_tx_ops pmo_tx_ops;
+
+	pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc);
+	if (!pmo_tx_ops.psoc_update_wow_bus_suspend) {
+		pmo_err("psoc_update_wow_bus_suspend is null");
+		return;
+	}
+	pmo_tx_ops.psoc_update_wow_bus_suspend(psoc, val);
+}
+
+int pmo_tgt_psoc_get_host_credits(struct wlan_objmgr_psoc *psoc)
+{
+
+	struct wlan_lmac_if_pmo_tx_ops pmo_tx_ops;
+
+	pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc);
+	if (!pmo_tx_ops.psoc_get_host_credits) {
+		pmo_err("psoc_get_host_credits is null");
+		return 0;
+	}
+
+	return pmo_tx_ops.psoc_get_host_credits(psoc);
+}
+
+int pmo_tgt_psoc_get_pending_cmnds(struct wlan_objmgr_psoc *psoc)
+{
+
+	struct wlan_lmac_if_pmo_tx_ops pmo_tx_ops;
+
+	pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc);
+	if (!pmo_tx_ops.psoc_get_pending_cmnds) {
+		pmo_err("psoc_get_pending_cmnds is null");
+		return -EAGAIN;
+	}
+
+	return pmo_tx_ops.psoc_get_pending_cmnds(psoc);
+}
+
+void pmo_tgt_update_target_suspend_flag(struct wlan_objmgr_psoc *psoc,
+		uint8_t val)
+{
+	struct wlan_lmac_if_pmo_tx_ops pmo_tx_ops;
+
+	pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc);
+	if (!pmo_tx_ops.update_target_suspend_flag) {
+		pmo_err("update_target_suspend_flag is null");
+		return;
+	}
+	pmo_tx_ops.update_target_suspend_flag(psoc, val);
+}
+
+QDF_STATUS pmo_tgt_psoc_send_wow_enable_req(struct wlan_objmgr_psoc *psoc,
+	struct pmo_wow_cmd_params *param)
+{
+	struct wlan_lmac_if_pmo_tx_ops pmo_tx_ops;
+
+	pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc);
+	if (!pmo_tx_ops.psoc_send_wow_enable_req) {
+		pmo_err("psoc_send_wow_enable_req is null");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	return pmo_tx_ops.psoc_send_wow_enable_req(psoc, param);
+}
+
+QDF_STATUS pmo_tgt_psoc_send_supend_req(struct wlan_objmgr_psoc *psoc,
+		struct pmo_suspend_params *param)
+{
+	struct wlan_lmac_if_pmo_tx_ops pmo_tx_ops;
+
+	pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc);
+	if (!pmo_tx_ops.psoc_send_supend_req) {
+		pmo_err("psoc_send_supend_req is null");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	return pmo_tx_ops.psoc_send_supend_req(psoc, param);
+}
+
+bool pmo_tgt_psoc_get_runtime_pm_in_progress(struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_lmac_if_pmo_tx_ops pmo_tx_ops;
+
+	pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc);
+	if (!pmo_tx_ops.psoc_get_runtime_pm_in_progress) {
+		pmo_err("psoc_get_runtime_pm_in_progress is null");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	return pmo_tx_ops.psoc_get_runtime_pm_in_progress(psoc);
+}
+
+QDF_STATUS pmo_tgt_psoc_send_host_wakeup_ind(struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_lmac_if_pmo_tx_ops pmo_tx_ops;
+
+	pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc);
+	if (!pmo_tx_ops.psoc_send_host_wakeup_ind) {
+		pmo_err("psoc_send_host_wakeup_ind is null");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	return pmo_tx_ops.psoc_send_host_wakeup_ind(psoc);
+}
+
+QDF_STATUS pmo_tgt_psoc_send_target_resume_req(struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_lmac_if_pmo_tx_ops pmo_tx_ops;
+
+	pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc);
+	if (!pmo_tx_ops.psoc_send_target_resume_req) {
+		pmo_err("send_target_resume_req is null");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	return pmo_tx_ops.psoc_send_target_resume_req(psoc);
+}
+

+ 124 - 0
power_management_offloads/dispatcher/src/wlan_pmo_ucfg_api.c

@@ -26,6 +26,8 @@
 #include "wlan_pmo_wow.h"
 #include "wlan_pmo_mc_addr_filtering.h"
 #include "wlan_pmo_main.h"
+#include "wlan_pmo_lphb.h"
+#include "wlan_pmo_suspend_resume.h"
 
 QDF_STATUS pmo_ucfg_get_psoc_config(struct wlan_objmgr_psoc *psoc,
 		struct pmo_psoc_cfg *psoc_cfg)
@@ -173,4 +175,126 @@ QDF_STATUS pmo_ucfg_get_gtk_rsp(struct wlan_objmgr_vdev *vdev,
 	return pmo_core_get_gtk_rsp(vdev, gtk_rsp_req);
 }
 
+void pmo_ucfg_update_nlo_scan_in_progress(struct wlan_objmgr_vdev *vdev,
+	bool value)
+{
+	pmo_core_update_nlo_scan_in_progress(vdev, value);
+}
+
+void pmo_ucfg_update_nlo_match_found(struct wlan_objmgr_vdev *vdev,
+	bool value)
+{
+	pmo_core_update_nlo_match_found(vdev, value);
+}
+
+void pmo_ucfg_update_extscan_in_progress(struct wlan_objmgr_vdev *vdev,
+	bool value)
+{
+	pmo_core_update_extscan_in_progress(vdev, value);
+}
+
+void pmo_ucfg_update_p2plo_in_progress(struct wlan_objmgr_vdev *vdev,
+	bool value)
+{
+	pmo_core_update_p2plo_in_progress(vdev, value);
+}
+
+QDF_STATUS pmo_ucfg_lphb_config_req(struct wlan_objmgr_psoc *psoc,
+		struct pmo_lphb_req *lphb_req, void *lphb_cb_ctx,
+		pmo_lphb_callback callback)
+{
+	return pmo_core_lphb_config_req(psoc, lphb_req, lphb_cb_ctx, callback);
+}
+
+void pmo_ucfg_update_alt_modulated_dtim_enable(struct wlan_objmgr_vdev *vdev,
+	bool value)
+{
+	pmo_core_update_alt_modulated_dtim_enable(vdev, value);
+}
+
+void pmo_ucfg_psoc_update_power_save_mode(struct wlan_objmgr_psoc *psoc,
+	uint8_t value)
+{
+	pmo_core_psoc_update_power_save_mode(psoc, value);
+}
+
+void pmo_ucfg_psoc_update_dp_handle(struct wlan_objmgr_psoc *psoc,
+		void *dp_handle)
+{
+	pmo_core_psoc_update_dp_handle(psoc, dp_handle);
+}
+
+void pmo_ucfg_vdev_update_dp_handle(struct wlan_objmgr_vdev *vdev,
+		void *dp_handle)
+{
+	pmo_core_vdev_update_dp_handle(vdev, dp_handle);
+}
+
+void pmo_ucfg_psoc_update_htc_handle(struct wlan_objmgr_psoc *psoc,
+		void *htc_handle)
+{
+	pmo_core_psoc_update_htc_handle(psoc, htc_handle);
+}
+
+void pmo_ucfg_psoc_handle_initial_wake_up(void *cb_ctx)
+{
+	return pmo_core_psoc_handle_initial_wake_up(cb_ctx);
+}
+
+QDF_STATUS pmo_ucfg_psoc_user_space_suspend_req(struct wlan_objmgr_psoc *psoc,
+		enum qdf_suspend_type type)
+{
+	return pmo_core_psoc_user_space_suspend_req(psoc, type);
+}
+
+
+QDF_STATUS pmo_ucfg_psoc_user_space_resume_req(struct wlan_objmgr_psoc *psoc,
+		enum qdf_suspend_type type)
+{
+	return pmo_core_psoc_user_space_resume_req(psoc, type);
+}
+
+QDF_STATUS pmo_ucfg_psoc_bus_suspend_req(struct wlan_objmgr_psoc *psoc,
+		enum qdf_suspend_type type,
+		struct pmo_wow_enable_params *wow_params)
+{
+	return pmo_core_psoc_bus_suspend_req(psoc, type, wow_params);
+}
+
+QDF_STATUS pmo_ucfg_psoc_suspend_target(struct wlan_objmgr_psoc *psoc,
+		int disable_target_intr)
+{
+	return pmo_core_psoc_suspend_target(psoc, disable_target_intr);
+}
+
+QDF_STATUS pmo_ucfg_psoc_bus_resume_req(struct wlan_objmgr_psoc *psoc,
+		enum qdf_suspend_type type)
+{
+	return pmo_core_psoc_bus_resume_req(psoc, type);
+}
+
+bool pmo_ucfg_get_wow_bus_suspend(struct wlan_objmgr_psoc *psoc)
+{
+	return pmo_core_get_wow_bus_suspend(psoc);
+}
+
+int pmo_ucfg_psoc_is_target_wake_up_received(struct wlan_objmgr_psoc *psoc)
+{
+	return pmo_core_psoc_is_target_wake_up_received(psoc);
+}
+
+int pmo_ucfg_psoc_clear_target_wake_up(struct wlan_objmgr_psoc *psoc)
+{
+	return pmo_core_psoc_clear_target_wake_up(psoc);
+}
+
+void pmo_ucfg_psoc_target_suspend_acknowledge(void *context, bool wow_nack)
+{
+	pmo_core_psoc_target_suspend_acknowledge(context, wow_nack);
+}
+
+void pmo_ucfg_psoc_wakeup_host_event_received(struct wlan_objmgr_psoc *psoc)
+{
+	pmo_core_psoc_wakeup_host_event_received(psoc);
+}
 

+ 166 - 0
target_if/pmo/inc/target_if_pmo.h

@@ -183,6 +183,172 @@ QDF_STATUS target_if_pmo_send_gtk_response_req(struct wlan_objmgr_vdev *vdev);
 int target_if_pmo_gtk_offload_status_event(void *scn_handle,
 	uint8_t *event, uint32_t len);
 
+/**
+ * target_if_pmo_send_lphb_enable() - enable command of LPHB config req
+ * @psoc: objmgr psoc handle
+ * @ts_lphb_enable: lphb enable request which needs to configure in fwr
+ *
+ * Return: QDF status
+ */
+QDF_STATUS target_if_pmo_send_lphb_enable(struct wlan_objmgr_psoc *psoc,
+			struct pmo_lphb_enable_req *ts_lphb_enable);
+
+/**
+ * target_if_pmo_send_lphb_tcp_params() - set lphb tcp params config request
+ * @psoc: objmgr psoc handle
+ * @ts_lphb_tcp_param: lphb tcp params which needs to configure in fwr
+ *
+ * Return: QDF status
+ */
+QDF_STATUS target_if_pmo_send_lphb_tcp_params(struct wlan_objmgr_psoc *psoc,
+			struct pmo_lphb_tcp_params *ts_lphb_tcp_param);
+
+/**
+ * target_if_pmo_send_lphb_tcp_pkt_filter() - send lphb tcp packet filter req
+ * @psoc: objmgr psoc handle
+ * @ts_lphb_tcp_filter: lphb tcp filter request which needs to configure in fwr
+ *
+ * Return: QDF status
+ */
+QDF_STATUS target_if_pmo_send_lphb_tcp_pkt_filter(struct wlan_objmgr_psoc *psoc,
+			struct pmo_lphb_tcp_filter_req *ts_lphb_tcp_filter);
+
+/**
+ * target_if_pmo_send_lphb_udp_params() - Send udp param command of LPHB
+ * @psoc: objmgr psoc handle
+ * @ts_lphb_udp_param: lphb udp params which needs to configure in fwr
+ *
+ * Return: QDF status
+ */
+QDF_STATUS target_if_pmo_send_lphb_udp_params(struct wlan_objmgr_psoc *psoc,
+			struct pmo_lphb_udp_params *ts_lphb_udp_param);
+
+/**
+ * target_if_pmo_send_lphb_udp_pkt_filter() - Send lphb udp pkt filter cmd req
+ * @psoc: objmgr psoc handle
+ * @ts_lphb_udp_filter: lphb udp filter request which needs to configure in fwr
+ *
+ * Return: QDF status
+ */
+QDF_STATUS target_if_pmo_send_lphb_udp_pkt_filter(struct wlan_objmgr_psoc *psoc,
+			struct pmo_lphb_udp_filter_req *ts_lphb_udp_filter);
+
+/**
+ * target_if_pmo_lphb_evt_handler() - send LPHB indication to os if /HDD
+ * @psoc: objmgr psoc handle
+ * @event: lphb event buffer
+ *
+ * Return: QDF_STATUS_SUCCESS for success else error code
+ */
+QDF_STATUS target_if_pmo_lphb_evt_handler(struct wlan_objmgr_psoc *psoc,
+		uint8_t *event);
+
+/**
+ * target_if_pmo_send_vdev_update_param_req() - Send vdev param value to fwr
+ * @vdev: objmgr vdev
+ * @param_id: tell vdev param id which needs to be updated in fwr
+ * @param_value: vdev parameter value
+ *
+ * Return: QDF status
+ */
+QDF_STATUS target_if_pmo_send_vdev_update_param_req(
+		struct wlan_objmgr_vdev *vdev,
+		uint32_t param_id, uint32_t param_value);
+
+/**
+ * target_if_pmo_send_vdev_ps_param_req() - Send vdev ps param value to fwr
+ * @vdev: objmgr vdev
+ * @param_id: tell vdev param id which needs to be updated in fwr
+ * @param_value: vdev parameter value
+ *
+ * Return: QDF status
+ */
+QDF_STATUS target_if_pmo_send_vdev_ps_param_req(
+		struct wlan_objmgr_vdev *vdev,
+		uint32_t param_id,
+		uint32_t param_value);
+
+/**
+ * target_if_pmo_psoc_update_bus_suspend() - update wmi bus suspend flag
+ * @psoc: objmgr psoc
+ * @value: bus suspend value
+ *
+ * Return: None
+ */
+void target_if_pmo_psoc_update_bus_suspend(struct wlan_objmgr_psoc *psoc,
+		uint8_t value);
+
+/**
+ * target_if_pmo_psoc_get_host_credits() - get available host credits
+ * @psoc: objmgr psoc
+ *
+ * Return: return host credits
+ */
+int target_if_pmo_psoc_get_host_credits(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * target_if_pmo_psoc_get_pending_cmnds() - get wmi pending commands
+ * @psoc: objmgr psoc
+ *
+ * Return: return wmi pending commands
+ */
+int target_if_pmo_psoc_get_pending_cmnds(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * target_if_pmo_update_target_suspend_flag() - set wmi target suspend flag
+ * @psoc: objmgr psoc
+ * @value: value
+ *
+ * Return: return wmi pending commands
+ */
+void target_if_pmo_update_target_suspend_flag(struct wlan_objmgr_psoc *psoc,
+		uint8_t value);
+
+/**
+ * target_if_pmo_psoc_send_wow_enable_req() -send wow enable request
+ * @psoc: objmgr psoc
+ * @param: wow command params
+ *
+ * Return: return QDF_STATUS_SUCCESS on success else error code
+ */
+QDF_STATUS target_if_pmo_psoc_send_wow_enable_req(struct wlan_objmgr_psoc *psoc,
+		struct pmo_wow_cmd_params *param);
+
+/**
+ * target_if_pmo_psoc_send_suspend_req() - fp to send suspend request
+ * @psoc: objmgr psoc
+ * @param: target suspend params
+ *
+ * Return: return QDF_STATUS_SUCCESS on success else error code
+ */
+QDF_STATUS target_if_pmo_psoc_send_suspend_req(struct wlan_objmgr_psoc *psoc,
+		struct pmo_suspend_params *param);
+
+/**
+ * target_if_pmo_get_runtime_pm_in_progress() - fp to get runtime pm status
+ * @psoc: objmgr psoc
+ *
+ * Return: true if runtime pm in progress else false
+ */
+bool target_if_pmo_get_runtime_pm_in_progress(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * target_if_pmo_psoc_send_host_wakeup_ind() - send host wake ind to fwr
+ * @psoc: objmgr psoc
+ *
+ * Return: return QDF_STATUS_SUCCESS on success else error code
+ */
+QDF_STATUS target_if_pmo_psoc_send_host_wakeup_ind(
+		struct wlan_objmgr_psoc *psoc);
+
+/**
+ * target_if_pmo_psoc_send_target_resume_req() -send target resume request
+ * @psoc: objmgr psoc
+ *
+ * Return: return QDF_STATUS_SUCCESS on success else error code
+ */
+QDF_STATUS target_if_pmo_psoc_send_target_resume_req(
+		struct wlan_objmgr_psoc *psoc);
 
 #endif
 

+ 312 - 0
target_if/pmo/src/target_if_pmo_lphb.c

@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * DOC: target_if_pmo_lphb.c
+ *
+ * Target interface file for pmo component to
+ * send lphb offload related cmd and process event.
+ */
+#ifdef FEATURE_WLAN_LPHB
+
+#include "target_if.h"
+#include "target_if_pmo.h"
+#include "wmi_unified_pmo_api.h"
+
+QDF_STATUS target_if_pmo_send_lphb_enable(struct wlan_objmgr_psoc *psoc,
+			struct pmo_lphb_enable_req *ts_lphb_enable)
+{
+	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
+	int status = 0;
+	wmi_hb_set_enable_cmd_fixed_param hb_enable_fp;
+
+	if (ts_lphb_enable == NULL) {
+		target_if_err("LPHB Enable configuration is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	target_if_info("PMO_HB_SET_ENABLE enable=%d, item=%d, session=%d",
+		ts_lphb_enable->enable,
+		ts_lphb_enable->item, ts_lphb_enable->session);
+
+	if ((ts_lphb_enable->item != 1) && (ts_lphb_enable->item != 2)) {
+		pmo_err("LPHB configuration wrong item %d",
+			ts_lphb_enable->item);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* fill in values */
+	hb_enable_fp.vdev_id = ts_lphb_enable->session;
+	hb_enable_fp.enable = ts_lphb_enable->enable;
+	hb_enable_fp.item = ts_lphb_enable->item;
+	hb_enable_fp.session = ts_lphb_enable->session;
+
+	status = wmi_unified_lphb_config_hbenable_cmd(
+			GET_WMI_HDL_FROM_PSOC(psoc),
+			&hb_enable_fp);
+	if (status != EOK) {
+		qdf_status = QDF_STATUS_E_FAILURE;
+		goto error;
+	}
+	return QDF_STATUS_SUCCESS;
+error:
+
+	return qdf_status;
+}
+
+QDF_STATUS target_if_pmo_send_lphb_tcp_params(struct wlan_objmgr_psoc *psoc,
+			struct pmo_lphb_tcp_params *ts_lphb_tcp_param)
+{
+	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
+	int status = 0;
+	wmi_hb_set_tcp_params_cmd_fixed_param hb_tcp_params_fp = {0};
+
+	if (ts_lphb_tcp_param == NULL) {
+		target_if_err("TCP params LPHB configuration is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	target_if_info("PMO --> WMI_HB_SET_TCP_PARAMS srv_ip=%08x, "
+		"dev_ip=%08x, src_port=%d, dst_port=%d, timeout=%d, "
+		"session=%d, gateway_mac= %pM, time_period_sec=%d,"
+		"tcp_sn=%d", ts_lphb_tcp_param->srv_ip,
+		ts_lphb_tcp_param->dev_ip, ts_lphb_tcp_param->src_port,
+		ts_lphb_tcp_param->dst_port, ts_lphb_tcp_param->timeout,
+		ts_lphb_tcp_param->session,
+		ts_lphb_tcp_param->gateway_mac.bytes,
+		ts_lphb_tcp_param->time_period_sec, ts_lphb_tcp_param->tcp_sn);
+
+	/* fill in values */
+	hb_tcp_params_fp.vdev_id = ts_lphb_tcp_param->session;
+	hb_tcp_params_fp.srv_ip = ts_lphb_tcp_param->srv_ip;
+	hb_tcp_params_fp.dev_ip = ts_lphb_tcp_param->dev_ip;
+	hb_tcp_params_fp.seq = ts_lphb_tcp_param->tcp_sn;
+	hb_tcp_params_fp.src_port = ts_lphb_tcp_param->src_port;
+	hb_tcp_params_fp.dst_port = ts_lphb_tcp_param->dst_port;
+	hb_tcp_params_fp.interval = ts_lphb_tcp_param->time_period_sec;
+	hb_tcp_params_fp.timeout = ts_lphb_tcp_param->timeout;
+	hb_tcp_params_fp.session = ts_lphb_tcp_param->session;
+	WMI_CHAR_ARRAY_TO_MAC_ADDR(ts_lphb_tcp_param->gateway_mac.bytes,
+				   &hb_tcp_params_fp.gateway_mac);
+
+	status = wmi_unified_lphb_config_tcp_params_cmd(
+			GET_WMI_HDL_FROM_PSOC(psoc),
+			&hb_tcp_params_fp);
+	if (status != EOK) {
+		qdf_status = QDF_STATUS_E_FAILURE;
+		goto error;
+	}
+
+	return QDF_STATUS_SUCCESS;
+error:
+	return qdf_status;
+}
+
+QDF_STATUS target_if_pmo_send_lphb_tcp_pkt_filter(struct wlan_objmgr_psoc *psoc,
+			struct pmo_lphb_tcp_filter_req *ts_lphb_tcp_filter)
+{
+	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
+	int status = 0;
+	wmi_hb_set_tcp_pkt_filter_cmd_fixed_param hb_tcp_filter_fp = {0};
+
+	if (ts_lphb_tcp_filter == NULL) {
+		target_if_err("TCP PKT FILTER LPHB configuration is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	target_if_info("SET_TCP_PKT_FILTER length=%d, offset=%d, session=%d, "
+		"filter=%2x:%2x:%2x:%2x:%2x:%2x ...",
+		ts_lphb_tcp_filter->length, ts_lphb_tcp_filter->offset,
+		ts_lphb_tcp_filter->session, ts_lphb_tcp_filter->filter[0],
+		ts_lphb_tcp_filter->filter[1], ts_lphb_tcp_filter->filter[2],
+		ts_lphb_tcp_filter->filter[3], ts_lphb_tcp_filter->filter[4],
+		ts_lphb_tcp_filter->filter[5]);
+
+	/* fill in values */
+	hb_tcp_filter_fp.vdev_id = ts_lphb_tcp_filter->session;
+	hb_tcp_filter_fp.length = ts_lphb_tcp_filter->length;
+	hb_tcp_filter_fp.offset = ts_lphb_tcp_filter->offset;
+	hb_tcp_filter_fp.session = ts_lphb_tcp_filter->session;
+	memcpy((void *)&hb_tcp_filter_fp.filter,
+	       (void *)&ts_lphb_tcp_filter->filter,
+	       WMI_WLAN_HB_MAX_FILTER_SIZE);
+
+	status = wmi_unified_lphb_config_tcp_pkt_filter_cmd(
+			GET_WMI_HDL_FROM_PSOC(psoc),
+			&hb_tcp_filter_fp);
+	if (status != EOK) {
+		qdf_status = QDF_STATUS_E_FAILURE;
+		goto error;
+	}
+
+	return QDF_STATUS_SUCCESS;
+error:
+	return qdf_status;
+}
+
+QDF_STATUS target_if_pmo_send_lphb_udp_params(struct wlan_objmgr_psoc *psoc,
+			struct pmo_lphb_udp_params *ts_lphb_udp_param)
+{
+	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
+	int status = 0;
+	wmi_hb_set_udp_params_cmd_fixed_param hb_udp_params_fp = {0};
+
+	if (ts_lphb_udp_param == NULL) {
+		target_if_err("UDP param for LPHB configuration is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	target_if_info("HB_SET_UDP_PARAMS srv_ip=%d, dev_ip=%d, src_port=%d, "
+		"dst_port=%d, interval=%d, timeout=%d, session=%d, "
+		"gateway_mac= %pM",
+		ts_lphb_udp_param->srv_ip, ts_lphb_udp_param->dev_ip,
+		ts_lphb_udp_param->src_port, ts_lphb_udp_param->dst_port,
+		ts_lphb_udp_param->interval, ts_lphb_udp_param->timeout,
+		ts_lphb_udp_param->session,
+		ts_lphb_udp_param->gateway_mac.bytes);
+
+	/* fill in values */
+	hb_udp_params_fp.vdev_id = ts_lphb_udp_param->session;
+	hb_udp_params_fp.srv_ip = ts_lphb_udp_param->srv_ip;
+	hb_udp_params_fp.dev_ip = ts_lphb_udp_param->dev_ip;
+	hb_udp_params_fp.src_port = ts_lphb_udp_param->src_port;
+	hb_udp_params_fp.dst_port = ts_lphb_udp_param->dst_port;
+	hb_udp_params_fp.interval = ts_lphb_udp_param->interval;
+	hb_udp_params_fp.timeout = ts_lphb_udp_param->timeout;
+	hb_udp_params_fp.session = ts_lphb_udp_param->session;
+	WMI_CHAR_ARRAY_TO_MAC_ADDR(ts_lphb_udp_param->gateway_mac.bytes,
+				   &hb_udp_params_fp.gateway_mac);
+
+	status = wmi_unified_lphb_config_udp_params_cmd(
+			GET_WMI_HDL_FROM_PSOC(psoc),
+			&hb_udp_params_fp);
+	if (status != EOK) {
+		qdf_status = QDF_STATUS_E_FAILURE;
+		goto error;
+	}
+
+	return QDF_STATUS_SUCCESS;
+error:
+	return qdf_status;
+}
+
+/**
+ * target_if_pmo_lphb_send_udp_pkt_filter() - Send LPHB udp pkt filter req
+ * @psoc: objmgr psoc handle
+ * @ts_lphb_udp_filter: lphb udp filter request which needs to configure in fwr
+ *
+ * Return: QDF status
+ */
+QDF_STATUS target_if_pmo_send_lphb_udp_pkt_filter(struct wlan_objmgr_psoc *psoc,
+			struct pmo_lphb_udp_filter_req *ts_lphb_udp_filter)
+{
+	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
+	int status = 0;
+	wmi_hb_set_udp_pkt_filter_cmd_fixed_param hb_udp_filter_fp = {0};
+
+	if (ts_lphb_udp_filter == NULL) {
+		target_if_err("LPHB UDP packet filter configuration is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	target_if_info("SET_UDP_PKT_FILTER length=%d, offset=%d, session=%d, "
+		"filter=%2x:%2x:%2x:%2x:%2x:%2x ...",
+		ts_lphb_udp_filter->length, ts_lphb_udp_filter->offset,
+		ts_lphb_udp_filter->session, ts_lphb_udp_filter->filter[0],
+		ts_lphb_udp_filter->filter[1], ts_lphb_udp_filter->filter[2],
+		ts_lphb_udp_filter->filter[3], ts_lphb_udp_filter->filter[4],
+		ts_lphb_udp_filter->filter[5]);
+
+	/* fill in values */
+	hb_udp_filter_fp.vdev_id = ts_lphb_udp_filter->session;
+	hb_udp_filter_fp.length = ts_lphb_udp_filter->length;
+	hb_udp_filter_fp.offset = ts_lphb_udp_filter->offset;
+	hb_udp_filter_fp.session = ts_lphb_udp_filter->session;
+	qdf_mem_copy((void *)&hb_udp_filter_fp.filter,
+	       (void *)&ts_lphb_udp_filter->filter,
+	       WMI_WLAN_HB_MAX_FILTER_SIZE);
+
+	status = wmi_unified_lphb_config_udp_pkt_filter_cmd(
+			GET_WMI_HDL_FROM_PSOC(psoc),
+			&hb_udp_filter_fp);
+	if (status != EOK) {
+		qdf_status = QDF_STATUS_E_FAILURE;
+		goto error;
+	}
+
+	return QDF_STATUS_SUCCESS;
+error:
+	return qdf_status;
+}
+
+QDF_STATUS target_if_pmo_lphb_evt_handler(struct wlan_objmgr_psoc *psoc,
+		uint8_t *event)
+{
+	wmi_hb_ind_event_fixed_param *hb_fp;
+	struct pmo_lphb_rsp *slphb_indication = NULL;
+	QDF_STATUS qdf_status;
+	struct wlan_lmac_if_pmo_rx_ops *pmo_rx_ops;
+
+	TARGET_IF_ENTER();
+	if (!psoc) {
+		target_if_err("psoc ptr is NULL");
+		qdf_status = QDF_STATUS_E_NULL_VALUE;
+		goto out;
+	}
+
+	pmo_rx_ops = &psoc->soc_cb.rx_ops.pmo_rx_ops;
+	if (!pmo_rx_ops->lphb_rsp_event) {
+		target_if_err("lphb_rsp_event is NULL");
+		qdf_status = QDF_STATUS_E_INVAL;
+		goto out;
+	}
+
+	hb_fp = (wmi_hb_ind_event_fixed_param *) event;
+	if (!hb_fp) {
+		pmo_err("Invalid wmi_hb_ind_event_fixed_param buffer");
+		qdf_status = QDF_STATUS_E_INVAL;
+		goto out;
+	}
+
+	pmo_debug("lphb indication received with\n"
+		  "vdev_id=%d, session=%d, reason=%d",
+		hb_fp->vdev_id, hb_fp->session, hb_fp->reason);
+
+	slphb_indication = (struct pmo_lphb_rsp *)qdf_mem_malloc(
+				sizeof(struct pmo_lphb_rsp));
+
+	if (!slphb_indication) {
+		target_if_err("Invalid LPHB indication buffer");
+		qdf_status = QDF_STATUS_E_NOMEM;
+		goto out;
+	}
+
+	slphb_indication->session_idx = hb_fp->session;
+	slphb_indication->protocol_type = hb_fp->reason;
+	slphb_indication->event_reason = hb_fp->reason;
+
+	qdf_status = pmo_rx_ops->lphb_rsp_event(psoc, slphb_indication);
+	if (qdf_status != QDF_STATUS_SUCCESS)
+		target_if_err("Failed to lphb_rsp_event");
+out:
+	if (slphb_indication)
+		qdf_mem_free(slphb_indication);
+
+	return qdf_status;
+}
+#endif
+

+ 32 - 0
target_if/pmo/src/target_if_pmo_main.c

@@ -58,6 +58,38 @@ void target_if_pmo_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
 		target_if_pmo_send_gtk_response_req;
 	pmo_tx_ops->send_action_frame_pattern_req =
 		target_if_pmo_send_action_frame_patterns;
+	pmo_tx_ops->send_lphb_enable =
+		target_if_pmo_send_lphb_enable;
+	pmo_tx_ops->send_lphb_tcp_params =
+		target_if_pmo_send_lphb_tcp_params;
+	pmo_tx_ops->send_lphb_tcp_filter_req =
+		target_if_pmo_send_lphb_tcp_pkt_filter;
+	pmo_tx_ops->send_lphb_upd_params =
+		target_if_pmo_send_lphb_udp_params;
+	pmo_tx_ops->send_lphb_udp_filter_req =
+		target_if_pmo_send_lphb_udp_pkt_filter;
+	pmo_tx_ops->send_vdev_param_update_req =
+		target_if_pmo_send_vdev_update_param_req;
+	pmo_tx_ops->send_vdev_sta_ps_param_req =
+		target_if_pmo_send_vdev_ps_param_req;
+	pmo_tx_ops->psoc_update_wow_bus_suspend =
+		target_if_pmo_psoc_update_bus_suspend;
+	pmo_tx_ops->psoc_get_host_credits =
+		target_if_pmo_psoc_get_host_credits;
+	pmo_tx_ops->psoc_get_pending_cmnds =
+		target_if_pmo_psoc_get_pending_cmnds;
+	pmo_tx_ops->update_target_suspend_flag =
+		target_if_pmo_update_target_suspend_flag;
+	pmo_tx_ops->psoc_send_wow_enable_req =
+		target_if_pmo_psoc_send_wow_enable_req;
+	pmo_tx_ops->psoc_send_supend_req =
+		target_if_pmo_psoc_send_suspend_req;
+	pmo_tx_ops->psoc_get_runtime_pm_in_progress =
+		target_if_pmo_get_runtime_pm_in_progress;
+	pmo_tx_ops->psoc_send_host_wakeup_ind =
+		target_if_pmo_psoc_send_host_wakeup_ind;
+	pmo_tx_ops->psoc_send_target_resume_req =
+		target_if_pmo_psoc_send_target_resume_req;
 
 }
 

+ 182 - 0
target_if/pmo/src/target_if_pmo_suspend_resume.c

@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * DOC: target_if_pmo_static.c
+ *
+ * Target interface file for pmo component to
+ * send suspend / resume related cmd and process event.
+ */
+
+
+#include "target_if.h"
+#include "target_if_pmo.h"
+#include "wmi_unified_api.h"
+
+#define TGT_WILDCARD_PDEV_ID 0x0
+
+QDF_STATUS target_if_pmo_send_vdev_update_param_req(
+		struct wlan_objmgr_vdev *vdev,
+		uint32_t param_id, uint32_t param_value)
+{
+	uint8_t vdev_id;
+	struct wlan_objmgr_psoc *psoc;
+	struct vdev_set_params param = {0};
+
+	if (!vdev) {
+		target_if_err("vdev ptr passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	wlan_vdev_obj_lock(vdev);
+	psoc = wlan_vdev_get_psoc(vdev);
+	vdev_id = wlan_vdev_get_id(vdev);
+	wlan_vdev_obj_unlock(vdev);
+	if (!psoc) {
+		target_if_err("psoc handle is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	switch (param_id) {
+	case pmo_vdev_param_listen_interval:
+		param_id = WMI_VDEV_PARAM_LISTEN_INTERVAL;
+		break;
+	case pmo_vdev_param_dtim_policy:
+		param_id = WMI_VDEV_PARAM_DTIM_POLICY;
+		break;
+	default:
+		target_if_err("invalid vdev param id %d", param_id);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	param.if_id = vdev_id;
+	param.param_id = param_id;
+	param.param_value = param_value;
+	target_if_info("set vdev param vdev_id: %d value: %d for param_id: %d",
+		vdev_id, param_value, param_id);
+	return wmi_unified_vdev_set_param_send(GET_WMI_HDL_FROM_PSOC(psoc),
+			&param);
+}
+
+QDF_STATUS target_if_pmo_send_vdev_ps_param_req(
+		struct wlan_objmgr_vdev *vdev,
+		uint32_t param_id,
+		uint32_t param_value)
+{
+	uint8_t vdev_id;
+	struct wlan_objmgr_psoc *psoc;
+	QDF_STATUS status;
+	struct sta_ps_params sta_ps_param = {0};
+
+	if (!vdev) {
+		target_if_err("vdev ptr passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	wlan_vdev_obj_lock(vdev);
+	psoc = wlan_vdev_get_psoc(vdev);
+	vdev_id = wlan_vdev_get_id(vdev);
+	wlan_vdev_obj_unlock(vdev);
+	if (!psoc) {
+		target_if_err("psoc handle is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	switch (param_id) {
+	case pmo_sta_ps_enable_qpower:
+		param_id = WMI_STA_PS_ENABLE_QPOWER;
+		break;
+	default:
+		target_if_err("invalid vdev param id %d", param_id);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	sta_ps_param.vdev_id = vdev_id;
+	sta_ps_param.param = param_id;
+	sta_ps_param.value = param_value;
+	target_if_info("set vdev param vdev_id: %d value: %d for param_id: %d",
+		vdev_id, param_value, param_id);
+
+	status = wmi_unified_sta_ps_cmd_send(GET_WMI_HDL_FROM_PSOC(psoc),
+			&sta_ps_param);
+	if (QDF_IS_STATUS_ERROR(status))
+		return status;
+
+	return status;
+
+}
+
+void target_if_pmo_psoc_update_bus_suspend(struct wlan_objmgr_psoc *psoc,
+		uint8_t value)
+{
+	wmi_set_is_wow_bus_suspended(GET_WMI_HDL_FROM_PSOC(psoc), value);
+}
+
+int target_if_pmo_psoc_get_host_credits(struct wlan_objmgr_psoc *psoc)
+{
+	return wmi_get_host_credits(GET_WMI_HDL_FROM_PSOC(psoc));
+}
+
+int target_if_pmo_psoc_get_pending_cmnds(struct wlan_objmgr_psoc *psoc)
+{
+	return wmi_get_pending_cmds(GET_WMI_HDL_FROM_PSOC(psoc));
+}
+
+void target_if_pmo_update_target_suspend_flag(struct wlan_objmgr_psoc *psoc,
+		uint8_t value)
+{
+	wmi_set_target_suspend(GET_WMI_HDL_FROM_PSOC(psoc), value);
+}
+
+QDF_STATUS target_if_pmo_psoc_send_wow_enable_req(
+		struct wlan_objmgr_psoc *psoc,
+		struct pmo_wow_cmd_params *param)
+{
+	return wmi_unified_wow_enable_send(GET_WMI_HDL_FROM_PSOC(psoc),
+			(struct wow_cmd_params *)param,
+			TGT_WILDCARD_PDEV_ID);
+}
+
+QDF_STATUS target_if_pmo_psoc_send_suspend_req(
+		struct wlan_objmgr_psoc *psoc,
+		struct pmo_suspend_params *param)
+{
+	return wmi_unified_suspend_send(GET_WMI_HDL_FROM_PSOC(psoc),
+			(struct suspend_params *) param,
+			TGT_WILDCARD_PDEV_ID);
+}
+
+bool target_if_pmo_get_runtime_pm_in_progress(
+		struct wlan_objmgr_psoc *psoc)
+{
+	return wmi_get_runtime_pm_inprogress(GET_WMI_HDL_FROM_PSOC(psoc));
+}
+
+QDF_STATUS target_if_pmo_psoc_send_host_wakeup_ind(
+		struct wlan_objmgr_psoc *psoc)
+{
+	return wmi_unified_host_wakeup_ind_to_fw_cmd(
+			GET_WMI_HDL_FROM_PSOC(psoc));
+}
+
+QDF_STATUS target_if_pmo_psoc_send_target_resume_req(
+		struct wlan_objmgr_psoc *psoc)
+{
+	return wmi_unified_resume_send(GET_WMI_HDL_FROM_PSOC(psoc),
+					TGT_WILDCARD_PDEV_ID);
+}
+