qcacld-3.0: Re-enable TWT before host TWT trigger mode

Disable the current TWT session and re-enable the TWT if the
current session in FW trigger mode before changing the TWT mode
to host trigger mode.

Change-Id: I7de2126605685c85a240d38356d439cb4be8cce1
CRs-Fixed: 2539353
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h
index 857a304..b1a8225 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -1953,6 +1953,7 @@
 	struct board_info hw_bd_info;
 #ifdef WLAN_SUPPORT_TWT
 	enum twt_status twt_state;
+	qdf_event_t twt_disable_comp_evt;
 #endif
 #ifdef FEATURE_WLAN_APF
 	uint32_t apf_version;
diff --git a/core/hdd/inc/wlan_hdd_twt.h b/core/hdd/inc/wlan_hdd_twt.h
index 81e0435..909d3dc 100644
--- a/core/hdd/inc/wlan_hdd_twt.h
+++ b/core/hdd/inc/wlan_hdd_twt.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019 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
@@ -82,6 +82,15 @@
  */
 void hdd_send_twt_enable_cmd(struct hdd_context *hdd_ctx);
 
+#define TWT_DISABLE_COMPLETE_TIMEOUT 1000
+/**
+ * hdd_send_twt_disable_cmd() - Send TWT disable command to target
+ * @hdd_ctx: HDD Context
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS hdd_send_twt_disable_cmd(struct hdd_context *hdd_ctx);
+
 /**
  * wlan_hdd_twt_init() - Initialize TWT
  * @hdd_ctx: pointer to global HDD Context
@@ -114,6 +123,11 @@
 {
 }
 
+static inline QDF_STATUS hdd_send_twt_disable_cmd(struct hdd_context *hdd_ctx)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
 static inline void wlan_hdd_twt_init(struct hdd_context *hdd_ctx)
 {
 }
diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c
index f240a9f..5650e1c 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/core/hdd/src/wlan_hdd_cfg80211.c
@@ -8415,6 +8415,7 @@
 		struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
 		struct nlattr *twt_session;
 		int tmp, rc;
+		uint32_t congestion_timeout = 0;
 
 		if ((adapter->device_mode != QDF_STA_MODE &&
 		     adapter->device_mode != QDF_P2P_CLIENT_MODE) ||
@@ -8540,6 +8541,19 @@
 				  params.flag_flow_type,
 				  params.flag_protection);
 
+			ucfg_mlme_get_twt_congestion_timeout(hdd_ctx->psoc,
+							&congestion_timeout);
+			if (congestion_timeout) {
+				ret_val = qdf_status_to_os_return(
+					hdd_send_twt_disable_cmd(hdd_ctx));
+				if (ret_val) {
+					hdd_err("Failed to disable TWT");
+					goto send_err;
+				}
+				ucfg_mlme_set_twt_congestion_timeout(
+						hdd_ctx->psoc, 0);
+				hdd_send_twt_enable_cmd(hdd_ctx);
+			}
 			ret_val = qdf_status_to_os_return(
 					wma_twt_process_add_dialog(&params));
 			if (ret_val)
diff --git a/core/hdd/src/wlan_hdd_twt.c b/core/hdd/src/wlan_hdd_twt.c
index 649c37c..0d9cdce 100644
--- a/core/hdd/src/wlan_hdd_twt.c
+++ b/core/hdd/src/wlan_hdd_twt.c
@@ -74,6 +74,18 @@
 		wma_send_twt_enable_cmd(pdev_id, congestion_timeout, bcast_val);
 }
 
+QDF_STATUS hdd_send_twt_disable_cmd(struct hdd_context *hdd_ctx)
+{
+	uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id;
+
+	hdd_debug("TWT disable cmd :pdev:%d", pdev_id);
+
+	wma_send_twt_disable_cmd(pdev_id);
+
+	return qdf_wait_single_event(&hdd_ctx->twt_disable_comp_evt,
+				     TWT_DISABLE_COMPLETE_TIMEOUT);
+}
+
 /**
  * hdd_twt_enable_comp_cb() - TWT enable complete event callback
  * @hdd_handle: opaque handle for the global HDD Context
@@ -126,6 +138,7 @@
 {
 	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
 	enum twt_status prev_state;
+	QDF_STATUS status;
 
 	if (!hdd_ctx) {
 		hdd_err("TWT: Invalid HDD Context");
@@ -136,6 +149,10 @@
 
 	hdd_debug("TWT: State transitioned from %d to %d",
 		  prev_state, hdd_ctx->twt_state);
+
+	status = qdf_event_set(&hdd_ctx->twt_disable_comp_evt);
+	if (!QDF_IS_STATUS_SUCCESS(status))
+		hdd_err("Failed to set twt_disable_comp_evt");
 }
 
 void wlan_hdd_twt_init(struct hdd_context *hdd_ctx)
@@ -156,6 +173,14 @@
 		hdd_err("Register twt disable complete failed");
 		goto twt_init_fail;
 	}
+
+	status = qdf_event_create(&hdd_ctx->twt_disable_comp_evt);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		hdd_err("twt_disable_comp_evt init failed");
+		sme_deregister_twt_disable_complete_cb(hdd_ctx->mac_handle);
+		goto twt_init_fail;
+	}
+
 	hdd_send_twt_enable_cmd(hdd_ctx);
 	return;
 
@@ -175,5 +200,9 @@
 	if (!QDF_IS_STATUS_SUCCESS(status))
 		hdd_err("De-register of twt enable cb failed: %d", status);
 
+	if (!QDF_IS_STATUS_SUCCESS(qdf_event_destroy(
+				   &hdd_ctx->twt_disable_comp_evt)))
+		hdd_err("Failed to destroy twt_disable_comp_evt");
+
 	hdd_ctx->twt_state = TWT_CLOSED;
 }
diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h
index 247df03..94e7a3c 100644
--- a/core/wma/inc/wma_internal.h
+++ b/core/wma/inc/wma_internal.h
@@ -1751,8 +1751,43 @@
 					      uint8_t *event,
 					      uint32_t len);
 
+#ifdef WLAN_SUPPORT_TWT
+/**
+ * wma_twt_en_complete_event_handler - TWT enable complete event handler
+ * @handle: wma handle
+ * @event: buffer with event
+ * @len: buffer length
+ *
+ * Return: 0 on success
+ */
 int wma_twt_en_complete_event_handler(void *handle,
 				      uint8_t *event, uint32_t len);
+
+/**
+ * wma_twt_disable_comp_event_handler- TWT disable complete event handler
+ * @handle: wma handle
+ * @event: buffer with event
+ * @len: buffer length
+ *
+ * Return: 0 on success
+ */
+int wma_twt_disable_comp_event_handler(void *handle, uint8_t *event,
+				       uint32_t len);
+#else
+static inline int wma_twt_en_complete_event_handler(void *handle,
+						    uint8_t *event,
+						    uint32_t len)
+{
+	return 0;
+}
+
+static inline int wma_twt_disable_comp_event_handler(void *handle,
+						     uint8_t *event,
+						     uint32_t len)
+{
+	return 0;
+}
+#endif
 /**
  * wma_get_roam_scan_stats() - Get roam scan stats request
  * @handle: wma handle
diff --git a/core/wma/inc/wma_twt.h b/core/wma/inc/wma_twt.h
index 0cecfc2..43f64d8 100644
--- a/core/wma/inc/wma_twt.h
+++ b/core/wma/inc/wma_twt.h
@@ -46,6 +46,14 @@
 			   struct peer_assoc_params *cmd);
 
 /**
+ * wma_send_twt_disable_cmd() - Send TWT disable command to firmware
+ * @pdev_id: pdev id
+ *
+ * Return: None
+ */
+void wma_send_twt_disable_cmd(uint32_t pdev_id);
+
+/**
  * wma_twt_process_add_dialog() - Process twt add dialog command
  * @params: add dialog configuration param
  *
@@ -69,6 +77,10 @@
 	WMA_LOGD(FL("TWT not supported as WLAN_SUPPORT_TWT is disabled"));
 }
 
+static inline void wma_send_twt_disable_cmd(uint32_t pdev_id)
+{
+}
+
 static inline void wma_set_twt_peer_caps(tpAddStaParams params,
 					 struct peer_assoc_params *cmd)
 {
diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c
index 98b5650..a4572ba 100644
--- a/core/wma/src/wma_main.c
+++ b/core/wma/src/wma_main.c
@@ -3631,6 +3631,10 @@
 					   wmi_twt_enable_complete_event_id,
 					   wma_twt_en_complete_event_handler,
 					   WMA_RX_SERIALIZER_CTX);
+	wmi_unified_register_event_handler(wma_handle->wmi_handle,
+					   wmi_twt_disable_complete_event_id,
+					   wma_twt_disable_comp_event_handler,
+					   WMA_RX_SERIALIZER_CTX);
 #endif
 
 	wma_register_apf_events(wma_handle);
diff --git a/core/wma/src/wma_twt.c b/core/wma/src/wma_twt.c
index 029aab6..84e88a6 100644
--- a/core/wma/src/wma_twt.c
+++ b/core/wma/src/wma_twt.c
@@ -82,6 +82,42 @@
 	return status;
 }
 
+void wma_send_twt_disable_cmd(uint32_t pdev_id)
+{
+	t_wma_handle *wma = cds_get_context(QDF_MODULE_ID_WMA);
+	struct wmi_twt_disable_param twt_disable_params = {0};
+	int32_t ret;
+
+	if (!wma) {
+		WMA_LOGE("Invalid WMA context, Disable TWT failed");
+		return;
+	}
+	twt_disable_params.pdev_id = pdev_id;
+	ret = wmi_unified_twt_disable_cmd(wma->wmi_handle, &twt_disable_params);
+
+	if (ret)
+		WMA_LOGE("Failed to disable TWT");
+}
+
+int wma_twt_disable_comp_event_handler(void *handle, uint8_t *event,
+				       uint32_t len)
+{
+	struct mac_context *mac;
+
+	mac = (struct mac_context *)cds_get_context(QDF_MODULE_ID_PE);
+	if (!mac) {
+		WMA_LOGE("Invalid MAC context");
+		return -EINVAL;
+	}
+
+	WMA_LOGD("TWT: Rcvd TWT disable comp event");
+
+	if (mac->sme.twt_disable_cb)
+		mac->sme.twt_disable_cb(mac->hdd_handle);
+
+	return 0;
+}
+
 void wma_set_twt_peer_caps(tpAddStaParams params, struct peer_assoc_params *cmd)
 {
 	if (params->twt_requestor)