qcacld-3.0: Enable D0WOW for pcie

Enable FEATURE_WLAN_DOWOW for pcie.
This is for backward compatible with rome fw.

Change-Id: Ia2107ff6939666b4a0bd19d57149d17814f2dfb5
CRs-Fixed: 2070426
diff --git a/Kbuild b/Kbuild
index 9396890..fc28afb 100644
--- a/Kbuild
+++ b/Kbuild
@@ -2197,6 +2197,13 @@
 CDEFINES += -DWLAN_FEATURE_NAN_CONVERGENCE
 endif
 
+#Flag to enable/disable WLAN D0-WOW
+ifeq ($(CONFIG_PCI_MSM), y)
+ifeq ($(CONFIG_ROME_IF),pci)
+CDEFINES += -DFEATURE_WLAN_D0WOW
+endif
+endif
+
 ifeq ($(CONFIG_LITHIUM),y)
 CDEFINES += -DCONFIG_SHADOW_V2
 CDEFINES += -DQCA6290_HEADERS_DEF
diff --git a/components/pmo/core/src/wlan_pmo_suspend_resume.c b/components/pmo/core/src/wlan_pmo_suspend_resume.c
index 48e96d4..f43a55c 100644
--- a/components/pmo/core/src/wlan_pmo_suspend_resume.c
+++ b/components/pmo/core/src/wlan_pmo_suspend_resume.c
@@ -1110,6 +1110,7 @@
 	}
 
 	psoc_ctx = pmo_psoc_get_priv(psoc);
+	psoc_ctx->wow.wow_state = pmo_wow_state_none;
 	qdf_event_set(&psoc_ctx->wow.target_resume);
 out:
 	PMO_EXIT();
diff --git a/components/pmo/dispatcher/inc/wlan_pmo_common_public_struct.h b/components/pmo/dispatcher/inc/wlan_pmo_common_public_struct.h
index 62e9cf5..2c2f39e 100644
--- a/components/pmo/dispatcher/inc/wlan_pmo_common_public_struct.h
+++ b/components/pmo/dispatcher/inc/wlan_pmo_common_public_struct.h
@@ -271,6 +271,7 @@
  * @enable_mc_list: true if psoc supports mc addr list else false
  * @active_mode_offload: true if psoc supports active mode offload else false
  * @ap_arpns_support: true if psoc supports arp ns for ap mode
+ * @d0_wow_supported: true if psoc supports D0 wow command
  * @max_wow_filters: maximum number of wow filter supported
  * @ra_ratelimit_enable: true when ra filtering ins eanbled else false
  * @ra_ratelimit_interval: ra packets interval
@@ -298,6 +299,7 @@
 	bool enable_mc_list;
 	bool active_mode_offload;
 	bool ap_arpns_support;
+	bool d0_wow_supported;
 	uint8_t max_wow_filters;
 	bool ra_ratelimit_enable;
 	uint16_t ra_ratelimit_interval;
diff --git a/components/pmo/dispatcher/inc/wlan_pmo_obj_mgmt_public_struct.h b/components/pmo/dispatcher/inc/wlan_pmo_obj_mgmt_public_struct.h
index 9e6762a..9b37e79 100644
--- a/components/pmo/dispatcher/inc/wlan_pmo_obj_mgmt_public_struct.h
+++ b/components/pmo/dispatcher/inc/wlan_pmo_obj_mgmt_public_struct.h
@@ -102,6 +102,8 @@
  * @psoc_get_runtime_pm_in_progress: fp to get runtime pm is in progress status
  * @psoc_send_host_wakeup_ind: fp tp send host wake indication to fwr
  * @psoc_send_target_resume_req: fp to send target resume request
+ * @psoc_send_d0wow_enable_req: fp to send D0 WOW enable request
+ * @psoc_send_d0wow_disable_req: fp to send D0 WOW disable request
  */
 struct wlan_pmo_tx_ops {
 	QDF_STATUS (*send_arp_offload_req)(struct wlan_objmgr_vdev *vdev,
@@ -196,6 +198,10 @@
 	QDF_STATUS (*psoc_send_host_wakeup_ind)(struct wlan_objmgr_psoc *psoc);
 	QDF_STATUS (*psoc_send_target_resume_req)(
 			struct wlan_objmgr_psoc *psoc);
+	QDF_STATUS (*psoc_send_d0wow_enable_req)(
+			struct wlan_objmgr_psoc *psoc);
+	QDF_STATUS (*psoc_send_d0wow_disable_req)(
+			struct wlan_objmgr_psoc *psoc);
 
 };
 
diff --git a/components/pmo/dispatcher/inc/wlan_pmo_wow_public_struct.h b/components/pmo/dispatcher/inc/wlan_pmo_wow_public_struct.h
index aa2c261..bfc8749 100644
--- a/components/pmo/dispatcher/inc/wlan_pmo_wow_public_struct.h
+++ b/components/pmo/dispatcher/inc/wlan_pmo_wow_public_struct.h
@@ -174,10 +174,25 @@
 };
 
 /**
+ * enum pmo_wow_state: enumeration of wow state
+ * @pmo_wow_state_none: not in wow state
+ * @pmo_wow_state_legacy_d0: in d0 wow state trigger by legacy d0 wow command
+ * @pmo_wow_state_unified_d0: in d0 wow state trigger by unified wow command
+ * @pmo_wow_state_unified_d3: in d3 wow state trigger by unified wow command
+ */
+enum pmo_wow_state {
+	pmo_wow_state_none = 0,
+	pmo_wow_state_legacy_d0,
+	pmo_wow_state_unified_d0,
+	pmo_wow_state_unified_d3,
+};
+
+/**
  * struct pmo_wow - store wow patterns
  * @wow_enable: wow enable/disable
  * @wow_enable_cmd_sent: is wow enable command sent to fw
  * @is_wow_bus_suspended: true if bus is suspended
+ * @wow_state: state of wow
  * @target_suspend: target suspend event
  * @target_resume: target resume event
  * @wow_nack: wow negative ack flag
@@ -197,6 +212,7 @@
 	bool wow_enable;
 	bool wow_enable_cmd_sent;
 	bool is_wow_bus_suspended;
+	enum pmo_wow_state wow_state;
 	qdf_event_t target_suspend;
 	qdf_event_t target_resume;
 	int wow_nack;
diff --git a/components/pmo/dispatcher/src/wlan_pmo_tgt_suspend_resume.c b/components/pmo/dispatcher/src/wlan_pmo_tgt_suspend_resume.c
index 0108dfc..787ec98 100644
--- a/components/pmo/dispatcher/src/wlan_pmo_tgt_suspend_resume.c
+++ b/components/pmo/dispatcher/src/wlan_pmo_tgt_suspend_resume.c
@@ -133,14 +133,28 @@
 QDF_STATUS pmo_tgt_psoc_send_wow_enable_req(struct wlan_objmgr_psoc *psoc,
 	struct pmo_wow_cmd_params *param)
 {
+	struct pmo_psoc_priv_obj *psoc_ctx;
 	struct wlan_pmo_tx_ops pmo_tx_ops;
 
+	psoc_ctx = pmo_psoc_get_priv(psoc);
 	pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc);
+
+	if (psoc_ctx->psoc_cfg.d0_wow_supported && !param->can_suspend_link) {
+		if (!pmo_tx_ops.psoc_send_d0wow_enable_req) {
+			pmo_err("psoc_send_d0wow_enable_req is null");
+			return QDF_STATUS_E_NULL_VALUE;
+		}
+		psoc_ctx->wow.wow_state = pmo_wow_state_legacy_d0;
+		pmo_debug("Sending D0WOW enable command...");
+		return pmo_tx_ops.psoc_send_d0wow_enable_req(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;
 	}
-
+	psoc_ctx->wow.wow_state = param->can_suspend_link ?
+		pmo_wow_state_unified_d3 : pmo_wow_state_unified_d0;
 	return pmo_tx_ops.psoc_send_wow_enable_req(psoc, param);
 }
 
@@ -189,14 +203,26 @@
 
 QDF_STATUS pmo_tgt_psoc_send_host_wakeup_ind(struct wlan_objmgr_psoc *psoc)
 {
+	struct pmo_psoc_priv_obj *psoc_ctx;
 	struct wlan_pmo_tx_ops pmo_tx_ops;
 
+	psoc_ctx = pmo_psoc_get_priv(psoc);
 	pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc);
+
+	if (psoc_ctx->psoc_cfg.d0_wow_supported &&
+	    psoc_ctx->wow.wow_state == pmo_wow_state_legacy_d0) {
+		if (!pmo_tx_ops.psoc_send_d0wow_disable_req) {
+			pmo_err("psoc_send_d0wow_disable_req is null");
+			return QDF_STATUS_E_NULL_VALUE;
+		}
+		pmo_debug("Sending D0WOW disable command...");
+		return pmo_tx_ops.psoc_send_d0wow_disable_req(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);
 }
 
diff --git a/components/target_if/pmo/inc/target_if_pmo.h b/components/target_if/pmo/inc/target_if_pmo.h
index 6d8aad5..d5b772c 100644
--- a/components/target_if/pmo/inc/target_if_pmo.h
+++ b/components/target_if/pmo/inc/target_if_pmo.h
@@ -433,6 +433,24 @@
 		struct wlan_objmgr_psoc *psoc);
 
 /**
+ * target_if_pmo_psoc_send_d0wow_enable_req() - send d0 wow enable request
+ * @psoc: objmgr psoc
+ *
+ * Return: return QDF_STATUS_SUCCESS on success else error code
+ */
+QDF_STATUS target_if_pmo_psoc_send_d0wow_enable_req(
+		struct wlan_objmgr_psoc *psoc);
+
+/**
+ * target_if_pmo_psoc_send_d0wow_disable_req() - send d0 wow disable request
+ * @psoc: objmgr psoc
+ *
+ * Return: return QDF_STATUS_SUCCESS on success else error code
+ */
+QDF_STATUS target_if_pmo_psoc_send_d0wow_disable_req(
+		struct wlan_objmgr_psoc *psoc);
+
+/**
  * target_if_pmo_register_tx_ops() - Register PMO component TX OPS
  * @tx_ops: PMO if transmit ops
  *
diff --git a/components/target_if/pmo/src/target_if_pmo_main.c b/components/target_if/pmo/src/target_if_pmo_main.c
index 6361209..834f88f 100644
--- a/components/target_if/pmo/src/target_if_pmo_main.c
+++ b/components/target_if/pmo/src/target_if_pmo_main.c
@@ -99,6 +99,10 @@
 		target_if_pmo_psoc_send_host_wakeup_ind;
 	pmo_tx_ops->psoc_send_target_resume_req =
 		target_if_pmo_psoc_send_target_resume_req;
+	pmo_tx_ops->psoc_send_d0wow_enable_req =
+		target_if_pmo_psoc_send_d0wow_enable_req;
+	pmo_tx_ops->psoc_send_d0wow_disable_req =
+		target_if_pmo_psoc_send_d0wow_disable_req;
 	pmo_tx_ops->send_set_pkt_filter =
 		target_if_pmo_send_pkt_filter_req;
 	pmo_tx_ops->send_clear_pkt_filter =
diff --git a/components/target_if/pmo/src/target_if_pmo_suspend_resume.c b/components/target_if/pmo/src/target_if_pmo_suspend_resume.c
index fbbd638..8378df3 100644
--- a/components/target_if/pmo/src/target_if_pmo_suspend_resume.c
+++ b/components/target_if/pmo/src/target_if_pmo_suspend_resume.c
@@ -183,3 +183,30 @@
 					TGT_WILDCARD_PDEV_ID);
 }
 
+#ifdef FEATURE_WLAN_D0WOW
+QDF_STATUS target_if_pmo_psoc_send_d0wow_enable_req(
+		struct wlan_objmgr_psoc *psoc)
+{
+	return wmi_unified_d0wow_enable_send(GET_WMI_HDL_FROM_PSOC(psoc),
+			TGT_WILDCARD_PDEV_ID);
+}
+
+QDF_STATUS target_if_pmo_psoc_send_d0wow_disable_req(
+		struct wlan_objmgr_psoc *psoc)
+{
+	return wmi_unified_d0wow_disable_send(GET_WMI_HDL_FROM_PSOC(psoc),
+			TGT_WILDCARD_PDEV_ID);
+}
+#else
+QDF_STATUS target_if_pmo_psoc_send_d0wow_enable_req(
+		struct wlan_objmgr_psoc *psoc)
+{
+	return QDF_STATUS_E_INVAL;
+}
+
+QDF_STATUS target_if_pmo_psoc_send_d0wow_disable_req(
+		struct wlan_objmgr_psoc *psoc)
+{
+	return QDF_STATUS_E_INVAL;
+}
+#endif
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index 2508cd7..9568bac 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -12152,6 +12152,7 @@
 {
 }
 #endif
+
 /**
  * hdd_update_pmo_config - API to update pmo configuration parameters
  * @hdd_ctx: HDD context
@@ -12190,6 +12191,7 @@
 	psoc_cfg.active_mode_offload =
 		hdd_ctx->config->active_mode_offload;
 	psoc_cfg.ap_arpns_support = hdd_ctx->ap_arpns_support;
+	psoc_cfg.d0_wow_supported = wma_d0_wow_is_supported();
 	psoc_cfg.max_wow_filters = hdd_ctx->config->maxWoWFilters;
 	psoc_cfg.sta_dynamic_dtim = hdd_ctx->config->enableDynamicDTIM;
 	psoc_cfg.sta_mod_dtim = hdd_ctx->config->enableModulatedDTIM;
diff --git a/core/wma/inc/wma_api.h b/core/wma/inc/wma_api.h
index 2050bd7..63a490b 100644
--- a/core/wma/inc/wma_api.h
+++ b/core/wma/inc/wma_api.h
@@ -301,6 +301,19 @@
 
 bool wma_is_service_enabled(WMI_SERVICE service_type);
 
+#ifdef FEATURE_WLAN_D0WOW
+static inline bool wma_d0_wow_is_supported(void)
+{
+	return wma_is_service_enabled(WMI_SERVICE_D0WOW) &&
+	       (!wma_is_service_enabled(WMI_SERVICE_UNIFIED_WOW_CAPABILITY));
+}
+#else
+static inline bool wma_d0_wow_is_supported(void)
+{
+	return false;
+}
+#endif
+
 /**
  * wma_store_pdev() - store pdev
  * @wma_ctx:	wma context
diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h
index e02e4b6..da82850 100644
--- a/core/wma/inc/wma_internal.h
+++ b/core/wma/inc/wma_internal.h
@@ -972,6 +972,9 @@
 
 int wma_wow_wakeup_host_event(void *handle, uint8_t *event,
 				     uint32_t len);
+
+int wma_d0_wow_disable_ack_event(void *handle, uint8_t *event, uint32_t len);
+
 int wma_pdev_resume_event_handler(void *handle, uint8_t *event, uint32_t len);
 
 QDF_STATUS wma_wow_enter(tp_wma_handle wma, tpSirHalWowlEnterParams info);
diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c
index 2885a93..787f5b8 100644
--- a/core/wma/src/wma_features.c
+++ b/core/wma/src/wma_features.c
@@ -2803,6 +2803,46 @@
 	return errno;
 }
 
+#ifdef FEATURE_WLAN_D0WOW
+/**
+ * wma_d0_wow_disable_ack_event() - wakeup host event handler
+ * @handle: wma handle
+ * @event: event data
+ * @len: buffer length
+ *
+ * Handler to catch D0-WOW disable ACK event.  This event will have
+ * reason why the firmware has woken the host.
+ * This is for backward compatible with cld2.0.
+ *
+ * Return: 0 for success or error
+ */
+int wma_d0_wow_disable_ack_event(void *handle, uint8_t *event, uint32_t len)
+{
+	tp_wma_handle wma = (tp_wma_handle)handle;
+	WMI_D0_WOW_DISABLE_ACK_EVENTID_param_tlvs *param_buf;
+	wmi_d0_wow_disable_ack_event_fixed_param *resp_data;
+
+	param_buf = (WMI_D0_WOW_DISABLE_ACK_EVENTID_param_tlvs *)event;
+	if (!param_buf) {
+		WMA_LOGE("Invalid D0-WOW disable ACK event buffer!");
+		return -EINVAL;
+	}
+
+	resp_data = param_buf->fixed_param;
+
+	pmo_ucfg_psoc_wakeup_host_event_received(wma->psoc);
+
+	WMA_LOGD("Received D0-WOW disable ACK");
+
+	return 0;
+}
+#else
+int wma_d0_wow_disable_ack_event(void *handle, uint8_t *event, uint32_t len)
+{
+	return 0;
+}
+#endif
+
 /**
  * wma_pdev_resume_event_handler() - PDEV resume event handler
  * @handle: wma handle
diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c
index ffc708d..a9c6e83 100644
--- a/core/wma/src/wma_main.c
+++ b/core/wma/src/wma_main.c
@@ -3534,6 +3534,20 @@
 		goto end;
 	}
 
+	if (wma_d0_wow_is_supported()) {
+		status = wmi_unified_register_event_handler(
+				wma_handle->wmi_handle,
+				WMI_D0_WOW_DISABLE_ACK_EVENTID,
+				wma_d0_wow_disable_ack_event,
+				WMA_RX_TASKLET_CTX);
+		if (status) {
+			WMA_LOGE("%s: Failed to register d0wow disable ack"
+				 " event handler", __func__);
+			qdf_status = QDF_STATUS_E_FAILURE;
+			goto end;
+		}
+	}
+
 	status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
 				WMI_PDEV_RESUME_EVENTID,
 				wma_pdev_resume_event_handler,