Kaynağa Gözat

qcacld-3.0: Separate TWT enable command wrt req/res role

1. Currently, the same twt enable api hdd_send_twt_enable_cmd()
sends to firmware for both requestor and responder role.

2. When firmware receives enable command, it will be busy to
handle that command. If any back to back enable command, it can
lead to some issues.

As part of this change, decouple enable api based on requestor
and responder role as per below:
for requestor: hdd_send_twt_requestor_enable_cmd()
for responder: hdd_send_twt_responder_enable_cmd()

Synchronize twt enable command to avoid back to back command
issue.

Change-Id: I3d3840740fee7413d6123ece919c42558e9b35d1
CRs-Fixed: 2937540
Srinivas Girigowda 4 yıl önce
ebeveyn
işleme
bd0961f3db

+ 4 - 0
components/mlme/dispatcher/inc/wlan_mlme_public_struct.h

@@ -1470,6 +1470,8 @@ struct wlan_mlme_acs {
  * @twt_congestion_timeout: congestion timeout value
  * @enable_twt_24ghz: Enable/disable host TWT when STA is connected in
  * 2.4Ghz
+ * @req_flag: requestor flag enable/disable
+ * @res_flag: responder flag enable/disable
  */
 struct wlan_mlme_cfg_twt {
 	bool is_twt_enabled;
@@ -1483,6 +1485,8 @@ struct wlan_mlme_cfg_twt {
 	bool is_twt_statistics_tgt_cap_enabled;
 	uint32_t twt_congestion_timeout;
 	bool enable_twt_24ghz;
+	bool req_flag;
+	bool res_flag;
 };
 
 /**

+ 35 - 0
components/mlme/dispatcher/inc/wlan_mlme_twt_ucfg_api.h

@@ -199,6 +199,26 @@ QDF_STATUS
 ucfg_mlme_set_twt_bcast_responder(struct wlan_objmgr_psoc *psoc,
 				  bool val);
 
+/**
+ * ucfg_mlme_set_twt_requestor_flag() - Set twt requestor flag
+ * @psoc: pointer to psoc object
+ * @val: Value to be set to config
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS ucfg_mlme_set_twt_requestor_flag(struct wlan_objmgr_psoc *psoc,
+					    bool val);
+
+/**
+ * ucfg_mlme_set_twt_responder_flag() - Set twt responder flag
+ * @psoc: pointer to psoc object
+ * @val: Value to be set to config
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS ucfg_mlme_set_twt_responder_flag(struct wlan_objmgr_psoc *psoc,
+					    bool val);
+
 /**
  * ucfg_mlme_is_twt_setup_in_progress() - Get TWT setup in progress for
  * given dialog id
@@ -590,6 +610,20 @@ ucfg_mlme_set_twt_bcast_responder(struct wlan_objmgr_psoc *psoc,
 	return QDF_STATUS_E_NOSUPPORT;
 }
 
+static inline QDF_STATUS
+ucfg_mlme_set_twt_requestor_flag(struct wlan_objmgr_psoc *psoc,
+				 bool val)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+
+static inline QDF_STATUS
+ucfg_mlme_set_twt_responder_flag(struct wlan_objmgr_psoc *psoc,
+				 bool val)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+
 static inline
 bool ucfg_mlme_is_flexible_twt_enabled(struct wlan_objmgr_psoc *psoc)
 {
@@ -670,5 +704,6 @@ ucfg_mlme_get_twt_session_state(struct wlan_objmgr_psoc *psoc,
 {
 	return WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED;
 }
+
 #endif /* defined(WLAN_SUPPORT_TWT) && defined(WLAN_FEATURE_11AX) */
 #endif /* _WLAN_MLME_TWT_UCFG_API_H_ */

+ 28 - 0
components/mlme/dispatcher/src/wlan_mlme_twt_ucfg_api.c

@@ -89,6 +89,34 @@ ucfg_mlme_set_twt_responder(struct wlan_objmgr_psoc *psoc,
 	return QDF_STATUS_SUCCESS;
 }
 
+QDF_STATUS
+ucfg_mlme_set_twt_requestor_flag(struct wlan_objmgr_psoc *psoc, bool val)
+{
+	struct wlan_mlme_psoc_ext_obj *mlme_obj;
+
+	mlme_obj = mlme_get_psoc_ext_obj(psoc);
+	if (!mlme_obj)
+		return QDF_STATUS_E_INVAL;
+
+	mlme_obj->cfg.twt_cfg.req_flag = val;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+ucfg_mlme_set_twt_responder_flag(struct wlan_objmgr_psoc *psoc, bool val)
+{
+	struct wlan_mlme_psoc_ext_obj *mlme_obj;
+
+	mlme_obj = mlme_get_psoc_ext_obj(psoc);
+	if (!mlme_obj)
+		return QDF_STATUS_E_INVAL;
+
+	mlme_obj->cfg.twt_cfg.res_flag = val;
+
+	return QDF_STATUS_SUCCESS;
+}
+
 QDF_STATUS
 ucfg_mlme_get_twt_congestion_timeout(struct wlan_objmgr_psoc *psoc,
 				     uint32_t *val)

+ 1 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -2137,6 +2137,7 @@ struct hdd_context {
 #ifdef WLAN_SUPPORT_TWT
 	enum twt_status twt_state;
 	qdf_event_t twt_disable_comp_evt;
+	qdf_event_t twt_enable_comp_evt;
 #endif
 #ifdef FEATURE_WLAN_APF
 	uint32_t apf_version;

+ 22 - 4
core/hdd/inc/wlan_hdd_twt.h

@@ -130,12 +130,22 @@ void hdd_update_tgt_twt_cap(struct hdd_context *hdd_ctx,
 			    struct wma_tgt_cfg *cfg);
 
 /**
- * hdd_send_twt_enable_cmd() - Send TWT enable command to target
+ * hdd_send_twt_requestor_enable_cmd() - Send TWT requestor enable command to
+ * target
  * @hdd_ctx: HDD Context
  *
- * Return: None
+ * Return: QDF_STATUS
  */
-void hdd_send_twt_enable_cmd(struct hdd_context *hdd_ctx);
+QDF_STATUS hdd_send_twt_requestor_enable_cmd(struct hdd_context *hdd_ctx);
+
+/**
+ * hdd_send_twt_responder_enable_cmd() - Send TWT responder enable command to
+ * target
+ * @hdd_ctx: HDD Context
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS hdd_send_twt_responder_enable_cmd(struct hdd_context *hdd_ctx);
 
 /**
  * hdd_send_twt_disable_cmd() - Send TWT disable command to target
@@ -235,8 +245,16 @@ static inline void hdd_update_tgt_twt_cap(struct hdd_context *hdd_ctx,
 {
 }
 
-static inline void hdd_send_twt_enable_cmd(struct hdd_context *hdd_ctx)
+static inline
+QDF_STATUS hdd_send_twt_requestor_enable_cmd(struct hdd_context *hdd_ctx)
+{
+	return QDF_STATUS_E_FAILURE;
+}
+
+static inline
+QDF_STATUS hdd_send_twt_responder_enable_cmd(struct hdd_context *hdd_ctx)
 {
+	return QDF_STATUS_E_FAILURE;
 }
 
 static inline QDF_STATUS hdd_send_twt_disable_cmd(struct hdd_context *hdd_ctx)

+ 24 - 0
core/hdd/src/wlan_hdd_hostapd.c

@@ -96,6 +96,7 @@
 #include "ftm_time_sync_ucfg_api.h"
 #include <wlan_hdd_dcs.h>
 #include "wlan_tdls_ucfg_api.h"
+#include "wlan_mlme_twt_ucfg_api.h"
 #include "wlan_if_mgr_ucfg_api.h"
 #include "wlan_if_mgr_public_struct.h"
 #include "wlan_hdd_bootup_marker.h"
@@ -6485,6 +6486,23 @@ hdd_sap_nan_check_and_disable_unsupported_ndi(struct wlan_objmgr_psoc *psoc,
 }
 #endif
 
+#if defined(WLAN_SUPPORT_TWT) && \
+	(LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+static void
+wlan_hdd_update_twt_responder(struct hdd_context *hdd_ctx,
+			      struct cfg80211_ap_settings *params)
+{
+	ucfg_mlme_set_twt_responder(hdd_ctx->psoc, params->twt_responder);
+	if (params->twt_responder)
+		hdd_send_twt_responder_enable_cmd(hdd_ctx);
+}
+#else
+static inline void
+wlan_hdd_update_twt_responder(struct hdd_context *hdd_ctx,
+			      struct cfg80211_ap_settings *params)
+{}
+#endif
+
 /**
  * __wlan_hdd_cfg80211_start_ap() - start soft ap mode
  * @wiphy: Pointer to wiphy structure
@@ -6782,6 +6800,12 @@ static int __wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy,
 		adapter->session.ap.sap_config.ch_width_orig =
 						chandef->width;
 
+		/*
+		 * Enable/disable TWT responder based on
+		 * the twt_responder flag
+		 */
+		wlan_hdd_update_twt_responder(hdd_ctx, params);
+
 		hdd_place_marker(adapter, "TRY TO START", NULL);
 		status =
 			wlan_hdd_cfg80211_start_bss(adapter,

+ 5 - 4
core/hdd/src/wlan_hdd_p2p.c

@@ -914,7 +914,6 @@ void hdd_clean_up_interface(struct hdd_context *hdd_ctx,
 	hdd_stop_adapter(hdd_ctx, adapter);
 	hdd_deinit_adapter(hdd_ctx, adapter, true);
 	hdd_close_adapter(hdd_ctx, adapter, true);
-	hdd_send_twt_enable_cmd(hdd_ctx);
 }
 
 int __wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
@@ -1214,10 +1213,12 @@ int wlan_hdd_set_power_save(struct hdd_adapter *adapter,
 	hdd_debug("p2p set power save, status:%d", status);
 
 	/* P2P-GO-NOA and TWT do not go hand in hand */
-	if (ps_config->duration)
+	if (ps_config->duration) {
 		hdd_send_twt_role_disable_cmd(hdd_ctx, TWT_RESPONDER);
-	else
-		hdd_send_twt_enable_cmd(hdd_ctx);
+	} else {
+		hdd_send_twt_requestor_enable_cmd(hdd_ctx);
+		hdd_send_twt_responder_enable_cmd(hdd_ctx);
+	}
 
 	return qdf_status_to_os_return(status);
 }

+ 99 - 18
core/hdd/src/wlan_hdd_twt.c

@@ -39,6 +39,7 @@
 #include <wlan_mlme_twt_ucfg_api.h>
 
 #define TWT_DISABLE_COMPLETE_TIMEOUT 4000
+#define TWT_ENABLE_COMPLETE_TIMEOUT  4000
 
 #define TWT_FLOW_TYPE_ANNOUNCED 0
 #define TWT_FLOW_TYPE_UNANNOUNCED 1
@@ -316,6 +317,7 @@ int hdd_test_config_twt_setup_session(struct hdd_adapter *adapter,
 	uint32_t congestion_timeout = 0;
 	int ret = 0;
 	int cmd_id;
+	QDF_STATUS qdf_status;
 
 	if (adapter->device_mode != QDF_STA_MODE &&
 	    adapter->device_mode != QDF_P2P_CLIENT_MODE) {
@@ -359,8 +361,17 @@ int hdd_test_config_twt_setup_session(struct hdd_adapter *adapter,
 				hdd_err("Failed to disable TWT");
 				return ret;
 			}
+
 			ucfg_mlme_set_twt_congestion_timeout(adapter->hdd_ctx->psoc, 0);
-			hdd_send_twt_enable_cmd(adapter->hdd_ctx);
+
+			qdf_status = hdd_send_twt_requestor_enable_cmd(
+							adapter->hdd_ctx);
+
+			ret = qdf_status_to_os_return(qdf_status);
+			if (ret) {
+				hdd_err("Failed to Enable TWT");
+				return ret;
+			}
 		}
 
 		ret = qdf_status_to_os_return(sme_test_config_twt_setup(&params));
@@ -1606,8 +1617,15 @@ static int hdd_twt_setup_session(struct hdd_adapter *adapter,
 			hdd_err("Failed to disable TWT");
 			return ret;
 		}
+
 		ucfg_mlme_set_twt_congestion_timeout(adapter->hdd_ctx->psoc, 0);
-		hdd_send_twt_enable_cmd(adapter->hdd_ctx);
+
+		ret = qdf_status_to_os_return(
+			hdd_send_twt_requestor_enable_cmd(adapter->hdd_ctx));
+		if (ret) {
+			hdd_err("Failed to Enable TWT");
+			return ret;
+		}
 	}
 
 	if (ucfg_mlme_is_max_twt_sessions_reached(adapter->hdd_ctx->psoc,
@@ -3550,32 +3568,28 @@ void hdd_update_tgt_twt_cap(struct hdd_context *hdd_ctx,
 					     cfg->twt_stats_enabled);
 }
 
-void hdd_send_twt_enable_cmd(struct hdd_context *hdd_ctx)
+QDF_STATUS hdd_send_twt_requestor_enable_cmd(struct hdd_context *hdd_ctx)
 {
 	uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id;
 	struct twt_enable_disable_conf twt_en_dis = {0};
-	bool is_requestor_en, is_responder_en;
-	bool twt_bcast_requestor = false, twt_bcast_responder = false;
+	bool is_requestor_en, twt_bcast_requestor = false;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
 
-	/* Get MLME TWT config */
 	ucfg_mlme_get_twt_requestor(hdd_ctx->psoc, &is_requestor_en);
-	ucfg_mlme_get_twt_responder(hdd_ctx->psoc, &is_responder_en);
-
-	ucfg_mlme_get_twt_bcast_responder(hdd_ctx->psoc, &twt_bcast_responder);
 	ucfg_mlme_get_twt_bcast_requestor(hdd_ctx->psoc, &twt_bcast_requestor);
-	twt_en_dis.bcast_en = (twt_bcast_requestor || twt_bcast_responder);
+	twt_en_dis.bcast_en = twt_bcast_requestor;
 
 	ucfg_mlme_get_twt_congestion_timeout(hdd_ctx->psoc,
 					     &twt_en_dis.congestion_timeout);
-	hdd_debug("TWT mlme cfg:req: %d, res:%d, bcast:%d, cong:%d, pdev:%d",
-		  is_requestor_en, is_responder_en, twt_en_dis.bcast_en,
+	hdd_debug("TWT mlme cfg:req: %d, bcast:%d, cong:%d, pdev:%d",
+		  is_requestor_en, twt_en_dis.bcast_en,
 		  twt_en_dis.congestion_timeout, pdev_id);
 
 	/* The below code takes care of the following :
-	 * If user wants to separately enable requestor and responder roles,
-	 * and also the broadcast TWT capaibilities separately for each role.
-	 * This is done by reusing the INI configuration to indicate the user
-	 * preference and sending the command accordingly.
+	 * If user wants to separately enable requestor role, and also the
+	 * broadcast TWT capabilities separately for each role. This is done
+	 * by reusing the INI configuration to indicate the user preference
+	 * and sending the command accordingly.
 	 * Legacy targets did not provide this. Newer targets provide this.
 	 *
 	 * 1. The MLME config holds the intersection of fw cap and user config
@@ -3595,9 +3609,50 @@ void hdd_send_twt_enable_cmd(struct hdd_context *hdd_ctx)
 		else
 			twt_en_dis.oper = WMI_TWT_OPERATION_INDIVIDUAL;
 
+		ucfg_mlme_set_twt_requestor_flag(hdd_ctx->psoc, true);
+		qdf_event_reset(&hdd_ctx->twt_enable_comp_evt);
 		wma_send_twt_enable_cmd(pdev_id, &twt_en_dis);
+		status = qdf_wait_single_event(&hdd_ctx->twt_enable_comp_evt,
+					       TWT_ENABLE_COMPLETE_TIMEOUT);
+
+		if (QDF_IS_STATUS_ERROR(status)) {
+			hdd_warn("TWT Requestor Enable timedout");
+			ucfg_mlme_set_twt_requestor_flag(hdd_ctx->psoc, false);
+		}
 	}
 
+	return status;
+}
+
+QDF_STATUS hdd_send_twt_responder_enable_cmd(struct hdd_context *hdd_ctx)
+{
+	uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id;
+	struct twt_enable_disable_conf twt_en_dis = {0};
+	bool is_responder_en, twt_bcast_responder = false;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	ucfg_mlme_get_twt_responder(hdd_ctx->psoc, &is_responder_en);
+	ucfg_mlme_get_twt_bcast_responder(hdd_ctx->psoc, &twt_bcast_responder);
+	twt_en_dis.bcast_en = twt_bcast_responder;
+
+	hdd_debug("TWT responder mlme cfg:res:%d, bcast:%d, pdev:%d",
+		  is_responder_en, twt_en_dis.bcast_en, pdev_id);
+
+	/* The below code takes care of the following :
+	 * If user wants to separately enable responder roles, and also the
+	 * broadcast TWT capabilities separately for each role. This is done
+	 * by reusing the INI configuration to indicate the user preference
+	 * and sending the command accordingly.
+	 * Legacy targets did not provide this. Newer targets provide this.
+	 *
+	 * 1. The MLME config holds the intersection of fw cap and user config
+	 * 2. This may result in two enable commands sent for legacy, but
+	 *    that's fine, since the firmware returns harmlessly for the
+	 *    second command.
+	 * 3. The new two parameters in the enable command are ignored
+	 *    by legacy targets, and honored by new targets.
+	 */
+
 	/* If responder configured, send responder bcast/ucast config */
 	if (is_responder_en) {
 		twt_en_dis.role = WMI_TWT_ROLE_RESPONDER;
@@ -3607,10 +3662,19 @@ void hdd_send_twt_enable_cmd(struct hdd_context *hdd_ctx)
 		else
 			twt_en_dis.oper = WMI_TWT_OPERATION_INDIVIDUAL;
 
+		ucfg_mlme_set_twt_responder_flag(hdd_ctx->psoc, true);
+		qdf_event_reset(&hdd_ctx->twt_enable_comp_evt);
 		wma_send_twt_enable_cmd(pdev_id, &twt_en_dis);
+		status = qdf_wait_single_event(&hdd_ctx->twt_enable_comp_evt,
+					       TWT_ENABLE_COMPLETE_TIMEOUT);
+
+		if (QDF_IS_STATUS_ERROR(status)) {
+			hdd_warn("TWT Responder Enable timedout");
+			ucfg_mlme_set_twt_responder_flag(hdd_ctx->psoc, false);
+		}
 	}
 
-	return;
+	return status;
 }
 
 QDF_STATUS hdd_send_twt_disable_cmd(struct hdd_context *hdd_ctx)
@@ -3650,6 +3714,7 @@ hdd_twt_enable_comp_cb(hdd_handle_t hdd_handle,
 {
 	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
 	enum twt_status prev_state;
+	QDF_STATUS status;
 
 	prev_state = hdd_ctx->twt_state;
 	if (params->status == WMI_HOST_ENABLE_TWT_STATUS_OK ||
@@ -3665,6 +3730,7 @@ hdd_twt_enable_comp_cb(hdd_handle_t hdd_handle,
 			break;
 		}
 	}
+
 	if (params->status == WMI_HOST_ENABLE_TWT_INVALID_PARAM ||
 	    params->status == WMI_HOST_ENABLE_TWT_STATUS_UNKNOWN_ERROR)
 		hdd_ctx->twt_state = TWT_INIT;
@@ -3672,6 +3738,10 @@ hdd_twt_enable_comp_cb(hdd_handle_t hdd_handle,
 	hdd_debug("TWT: pdev ID:%d, status:%d State transitioned from %d to %d",
 		  params->pdev_id, params->status,
 		  prev_state, hdd_ctx->twt_state);
+
+	status = qdf_event_set(&hdd_ctx->twt_enable_comp_evt);
+	if (QDF_IS_STATUS_ERROR(status))
+		hdd_err("Failed to set twt_enable_comp_evt");
 }
 
 /**
@@ -3769,6 +3839,13 @@ void wlan_hdd_twt_init(struct hdd_context *hdd_ctx)
 		return;
 	}
 
+	status = qdf_event_create(&hdd_ctx->twt_enable_comp_evt);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		sme_clear_twt_complete_cb(hdd_ctx->mac_handle);
+		hdd_err("twt_enable_comp_evt init failed");
+		return;
+	}
+
 	status = qdf_event_create(&hdd_ctx->twt_disable_comp_evt);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		sme_clear_twt_complete_cb(hdd_ctx->mac_handle);
@@ -3776,7 +3853,7 @@ void wlan_hdd_twt_init(struct hdd_context *hdd_ctx)
 		return;
 	}
 
-	hdd_send_twt_enable_cmd(hdd_ctx);
+	hdd_send_twt_requestor_enable_cmd(hdd_ctx);
 }
 
 void wlan_hdd_twt_deinit(struct hdd_context *hdd_ctx)
@@ -3787,6 +3864,10 @@ void wlan_hdd_twt_deinit(struct hdd_context *hdd_ctx)
 	if (QDF_IS_STATUS_ERROR(status))
 		hdd_err("Failed to destroy twt_disable_comp_evt");
 
+	status = qdf_event_destroy(&hdd_ctx->twt_enable_comp_evt);
+	if (QDF_IS_STATUS_ERROR(status))
+		hdd_err("Failed to destroy twt_enable_comp_evt");
+
 	status = sme_clear_twt_complete_cb(hdd_ctx->mac_handle);
 	if (QDF_IS_STATUS_ERROR(status))
 		hdd_err("De-register of twt disable cb failed: %d", status);