Browse Source

qcacmn: Wait for RSO stop response from firmware

Firmware doesn't expect any vdev commands from host while RSO stop
is happening. It sends a response to the RSO_STOP command once
it's done with cleanup. Host needs to run a timer and wait for a
maximum of 6 seconds for the response. Host can stop the timer and
allow the commands to firmware in the below cases,
1. RSO_STOP response with success status
2. RSO_STOP response with HO_FAIL status followed by
   HO_FAIL event: Host needs to wait till HO_FAIL event is
   received

If firmware doesn't send any response in the 6 seconds wait, issue
a recovery to help to check the firmware state.

Change-Id: I4577f9b0aac71c0c86bd32b59e69d9527bf107b9
CRs-Fixed: 3106032
Srinivas Dasari 3 years ago
parent
commit
f8921a74b9

+ 2 - 0
qdf/inc/qdf_types.h

@@ -1412,6 +1412,7 @@ enum qdf_suspend_type {
  * @QDF_VDEV_SM_OUT_OF_SYNC: Vdev SM is out of sync and connect req received
  * when already connected
  * @QDF_STATS_REQ_TIMEDOUT: Stats request timedout
+ * @QDF_RSO_STOP_RSP_TIMEOUT: Firmware hasn't sent RSO stop response
  */
 enum qdf_hang_reason {
 	QDF_REASON_UNSPECIFIED,
@@ -1443,6 +1444,7 @@ enum qdf_hang_reason {
 	QDF_VDEV_SM_OUT_OF_SYNC,
 	QDF_STATS_REQ_TIMEDOUT,
 	QDF_TX_DESC_LEAK,
+	QDF_RSO_STOP_RSP_TIMEOUT,
 };
 
 /**

+ 13 - 0
target_if/mlme/vdev_mgr/inc/target_if_vdev_mgr_tx_ops.h

@@ -118,4 +118,17 @@ QDF_STATUS target_if_vdev_mgr_rsp_timer_stop(
 				struct vdev_response_timer *vdev_rsp,
 				enum wlan_vdev_mgr_tgt_if_rsp_bit clear_bit);
 
+/**
+ * target_if_vdev_mgr_rsp_timer_start() - API to start response timer for
+ * vdev manager operations
+ * @psoc: pointer to psoc object
+ * @vdev_rsp: vdev response timer
+ * @set_bit: enum of wlan_vdev_mgr_tgt_if_rsp_bit
+ *
+ * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error
+ */
+QDF_STATUS
+target_if_vdev_mgr_rsp_timer_start(struct wlan_objmgr_psoc *psoc,
+				   struct vdev_response_timer *vdev_rsp,
+				   enum wlan_vdev_mgr_tgt_if_rsp_bit set_bit);
 #endif /* __TARGET_IF_VDEV_MGR_TX_OPS_H__ */

+ 31 - 3
target_if/mlme/vdev_mgr/src/target_if_vdev_mgr_rx_ops.c

@@ -33,6 +33,9 @@
 #include <wlan_vdev_mlme_main.h>
 #include <wmi_unified_vdev_api.h>
 #include <target_if_psoc_wake_lock.h>
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+#include <target_if_cm_roam_offload.h>
+#endif
 
 static inline
 void target_if_vdev_mgr_handle_recovery(struct wlan_objmgr_psoc *psoc,
@@ -49,6 +52,22 @@ void target_if_vdev_mgr_handle_recovery(struct wlan_objmgr_psoc *psoc,
 				wlan_psoc_get_id(psoc), vdev_id);
 }
 
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+static inline QDF_STATUS
+target_if_send_rso_stop_failure_rsp(struct wlan_objmgr_psoc *psoc,
+				    uint8_t vdev_id)
+{
+	return target_if_cm_send_rso_stop_failure_rsp(psoc, vdev_id);
+}
+#else
+static inline QDF_STATUS
+target_if_send_rso_stop_failure_rsp(struct wlan_objmgr_psoc *psoc,
+				    uint8_t vdev_id)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+#endif
+
 void target_if_vdev_mgr_rsp_timer_cb(void *arg)
 {
 	struct wlan_objmgr_psoc *psoc;
@@ -83,9 +102,10 @@ void target_if_vdev_mgr_rsp_timer_cb(void *arg)
 	    !qdf_atomic_test_bit(RESTART_RESPONSE_BIT, &vdev_rsp->rsp_status) &&
 	    !qdf_atomic_test_bit(STOP_RESPONSE_BIT, &vdev_rsp->rsp_status) &&
 	    !qdf_atomic_test_bit(DELETE_RESPONSE_BIT, &vdev_rsp->rsp_status) &&
-	    !qdf_atomic_test_bit(
-			PEER_DELETE_ALL_RESPONSE_BIT,
-			&vdev_rsp->rsp_status)) {
+	    !qdf_atomic_test_bit(PEER_DELETE_ALL_RESPONSE_BIT,
+				 &vdev_rsp->rsp_status) &&
+	    !qdf_atomic_test_bit(RSO_STOP_RESPONSE_BIT,
+				 &vdev_rsp->rsp_status)) {
 		mlme_debug("No response bit is set, ignoring actions :%d",
 			   vdev_rsp->vdev_id);
 		return;
@@ -151,6 +171,14 @@ void target_if_vdev_mgr_rsp_timer_cb(void *arg)
 						   recovery_reason, rsp_pos);
 		rx_ops->vdev_mgr_peer_delete_all_response(psoc,
 							  &peer_del_all_rsp);
+	} else if (qdf_atomic_test_bit(RSO_STOP_RESPONSE_BIT,
+				       &vdev_rsp->rsp_status)) {
+		rsp_pos = RSO_STOP_RESPONSE_BIT;
+		recovery_reason = QDF_RSO_STOP_RSP_TIMEOUT;
+		target_if_vdev_mgr_rsp_timer_stop(psoc, vdev_rsp, rsp_pos);
+		target_if_vdev_mgr_handle_recovery(psoc, vdev_id,
+						   recovery_reason, rsp_pos);
+		target_if_send_rso_stop_failure_rsp(psoc, vdev_id);
 	} else {
 		mlme_err("PSOC_%d VDEV_%d: Unknown error",
 			 wlan_psoc_get_id(psoc), vdev_id);

+ 4 - 4
target_if/mlme/vdev_mgr/src/target_if_vdev_mgr_tx_ops.c

@@ -101,10 +101,10 @@ target_if_vdev_mgr_rsp_timer_stop(struct wlan_objmgr_psoc *psoc,
 	return QDF_STATUS_E_FAILURE;
 }
 
-static QDF_STATUS target_if_vdev_mgr_rsp_timer_start(
-				struct wlan_objmgr_psoc *psoc,
-				struct vdev_response_timer *vdev_rsp,
-				enum wlan_vdev_mgr_tgt_if_rsp_bit set_bit)
+QDF_STATUS
+target_if_vdev_mgr_rsp_timer_start(struct wlan_objmgr_psoc *psoc,
+				   struct vdev_response_timer *vdev_rsp,
+				   enum wlan_vdev_mgr_tgt_if_rsp_bit set_bit)
 {
 	uint8_t rsp_pos;
 	uint8_t vdev_id;

+ 60 - 15
umac/mlme/connection_mgr/core/src/wlan_cm_disconnect.c

@@ -377,18 +377,69 @@ QDF_STATUS cm_disconnect_active(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id)
 {
 	struct wlan_cm_vdev_discon_req *req;
 	struct cm_req *cm_req;
-	struct qdf_mac_addr bssid = QDF_MAC_ADDR_ZERO_INIT;
-	QDF_STATUS status;
+	QDF_STATUS status = QDF_STATUS_E_NOSUPPORT;
 
 	cm_req = cm_get_req_by_cm_id(cm_ctx, *cm_id);
 	if (!cm_req)
 		return QDF_STATUS_E_INVAL;
 
+	cm_ctx->active_cm_id = *cm_id;
+
+	if (wlan_vdev_mlme_get_opmode(cm_ctx->vdev) == QDF_STA_MODE)
+		status = mlme_cm_rso_stop_req(cm_ctx->vdev);
+
+	if (status != QDF_STATUS_E_NOSUPPORT)
+		return status;
+
 	req = qdf_mem_malloc(sizeof(*req));
 	if (!req)
 		return QDF_STATUS_E_NOMEM;
 
-	cm_ctx->active_cm_id = *cm_id;
+	req->cm_id = *cm_id;
+	req->req.vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
+	req->req.source = cm_req->discon_req.req.source;
+	req->req.reason_code = cm_req->discon_req.req.reason_code;
+	req->req.is_no_disassoc_disconnect =
+			cm_req->discon_req.req.is_no_disassoc_disconnect;
+
+	cm_disconnect_continue_after_rso_stop(cm_ctx->vdev, false,
+					      req);
+	qdf_mem_free(req);
+
+	return status;
+}
+
+QDF_STATUS
+cm_disconnect_continue_after_rso_stop(struct wlan_objmgr_vdev *vdev,
+				      bool is_ho_fail,
+				      struct wlan_cm_vdev_discon_req *req)
+{
+	struct cm_req *cm_req;
+	QDF_STATUS status;
+	struct qdf_mac_addr bssid = QDF_MAC_ADDR_ZERO_INIT;
+	struct cnx_mgr *cm_ctx = cm_get_cm_ctx(vdev);
+
+	if (!cm_ctx)
+		return QDF_STATUS_E_INVAL;
+
+	if ((CM_ID_GET_PREFIX(req->cm_id)) != DISCONNECT_REQ_PREFIX) {
+		mlme_err(CM_PREFIX_FMT "active req is not disconnect req",
+			 CM_PREFIX_REF(wlan_vdev_get_id(vdev), req->cm_id));
+		return QDF_STATUS_E_INVAL;
+	}
+
+	cm_req = cm_get_req_by_cm_id(cm_ctx, req->cm_id);
+	if (!cm_req)
+		return QDF_STATUS_E_INVAL;
+
+	if (is_ho_fail) {
+		mlme_debug(CM_PREFIX_FMT "Updating source(%d) and reason code (%d) to RSO reason and source as ho fail is received in RSO stop",
+			   CM_PREFIX_REF(req->req.vdev_id, req->cm_id),
+			   req->req.source, req->req.reason_code);
+		req->req.source = CM_MLME_DISCONNECT;
+		req->req.reason_code = REASON_FW_TRIGGERED_ROAM_FAILURE;
+	}
+
 	wlan_vdev_get_bss_peer_mac(cm_ctx->vdev, &bssid);
 	/*
 	 * for northbound req, bssid is not provided so update it from vdev
@@ -396,31 +447,25 @@ QDF_STATUS cm_disconnect_active(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id)
 	 */
 	if (qdf_is_macaddr_zero(&cm_req->discon_req.req.bssid) ||
 	    qdf_is_macaddr_broadcast(&cm_req->discon_req.req.bssid))
-		qdf_copy_macaddr(&cm_req->discon_req.req.bssid, &bssid);
+		qdf_copy_macaddr(&cm_req->discon_req.req.bssid,
+				 &req->req.bssid);
 
 	qdf_copy_macaddr(&req->req.bssid, &bssid);
-
-	req->cm_id = *cm_id;
-	req->req.vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
-	req->req.source = cm_req->discon_req.req.source;
-	req->req.reason_code = cm_req->discon_req.req.reason_code;
-	req->req.is_no_disassoc_disconnect =
-			cm_req->discon_req.req.is_no_disassoc_disconnect;
-
 	cm_update_scan_mlme_on_disconnect(cm_ctx->vdev,
 					  &cm_req->discon_req);
 
-	mlme_debug(CM_PREFIX_FMT "disconnect " QDF_MAC_ADDR_FMT " source %d reason %d",
+	mlme_debug(CM_PREFIX_FMT "disconnect " QDF_MAC_ADDR_FMT
+		   " source %d reason %d is_ho_fail: %u",
 		   CM_PREFIX_REF(req->req.vdev_id, req->cm_id),
 		   QDF_MAC_ADDR_REF(req->req.bssid.bytes),
-		   req->req.source, req->req.reason_code);
+		   req->req.source, req->req.reason_code, is_ho_fail);
+
 	status = mlme_cm_disconnect_req(cm_ctx->vdev, req);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		mlme_err(CM_PREFIX_FMT "disconnect req fail",
 			 CM_PREFIX_REF(req->req.vdev_id, req->cm_id));
 		cm_send_disconnect_resp(cm_ctx, req->cm_id);
 	}
-	qdf_mem_free(req);
 
 	return status;
 }

+ 14 - 1
umac/mlme/connection_mgr/core/src/wlan_cm_main_api.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012-2015, 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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
@@ -460,6 +461,19 @@ void cm_initiate_internal_disconnect(struct cnx_mgr *cm_ctx);
  */
 void cm_send_disconnect_resp(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id);
 
+/**
+ * cm_disconnect_continue_after_rso_stop() - Continue disconnect after RSO stop
+ * @vdev: Objmgr vdev
+ * @is_ho_fail: True if ho_fail happened
+ * @req: pointer to cm vdev disconnect req
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+cm_disconnect_continue_after_rso_stop(struct wlan_objmgr_vdev *vdev,
+				      bool is_ho_fail,
+				      struct wlan_cm_vdev_discon_req *req);
+
 /*************** UTIL APIs ****************/
 
 /**
@@ -1153,5 +1167,4 @@ void cm_set_candidate_custom_sort_cb(
 				 qdf_list_t *list));
 
 #endif
-
 #endif /* __WLAN_CM_MAIN_API_H__ */

+ 16 - 0
umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_api.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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
@@ -459,4 +460,19 @@ void wlan_cm_set_candidate_custom_sort_cb(
  */
 struct reduced_neighbor_report *wlan_cm_get_rnr(struct wlan_objmgr_vdev *vdev,
 						wlan_cm_id cm_id);
+
+/**
+ * wlan_cm_disc_cont_after_rso_stop() - Continue disconnect after RSO stop
+ * @vdev: Objmgr vdev
+ * @is_ho_fail: True if ho_fail happened
+ * @req: pointer to cm vdev disconnect req
+
+ * This is a wrapper to call core API cm_disconnect_continue_after_rso_stop
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+wlan_cm_disc_cont_after_rso_stop(struct wlan_objmgr_vdev *vdev,
+				 bool is_ho_fail,
+				 struct wlan_cm_vdev_discon_req *req);
 #endif /* __WLAN_CM_UCFG_API_H */

+ 4 - 2
umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_public_struct.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2012-2015,2020-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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
@@ -35,7 +35,9 @@
 typedef uint32_t wlan_cm_id;
 
 /* Diconnect active timeout */
-#define DISCONNECT_TIMEOUT   STOP_RESPONSE_TIMER + DELETE_RESPONSE_TIMER + 1000
+#define DISCONNECT_TIMEOUT \
+	((STOP_RESPONSE_TIMER) + (DELETE_RESPONSE_TIMER) +\
+	 (RSO_STOP_RESPONSE_TIMER) + (1000))
 
 /*
  * Disconnect command wait timeout VDEV timeouts + 5 sec buff for current active

+ 10 - 0
umac/mlme/connection_mgr/dispatcher/src/wlan_cm_api.c

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012-2015, 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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
@@ -370,3 +371,12 @@ struct reduced_neighbor_report *wlan_cm_get_rnr(struct wlan_objmgr_vdev *vdev,
 
 	return NULL;
 }
+
+QDF_STATUS
+wlan_cm_disc_cont_after_rso_stop(struct wlan_objmgr_vdev *vdev,
+				 bool is_ho_fail,
+				 struct wlan_cm_vdev_discon_req *req)
+{
+	return cm_disconnect_continue_after_rso_stop(vdev, is_ho_fail,
+						     req);
+}

+ 10 - 0
umac/mlme/include/wlan_mlme_cmn.h

@@ -258,6 +258,7 @@ struct mlme_twt_ops {
  *                                          complete
  * @mlme_cm_ext_vdev_down_req_cb:           callback to send vdev down to FW
  * @mlme_cm_ext_roam_start_ind_cb:          callback to indicate roam start
+ * @mlme_cm_ext_rso_stop_cb:                callback to send rso stop to FW
  * @mlme_cm_ext_reassoc_req_cb:             callback for reassoc request to
  *                                          VDEV/PEER SM
  * @mlme_vdev_send_set_mac_addr:            callback to send set MAC address
@@ -329,6 +330,7 @@ struct mlme_ext_ops {
 	QDF_STATUS (*mlme_cm_ext_roam_start_ind_cb)(
 				struct wlan_objmgr_vdev *vdev,
 				struct wlan_cm_roam_req *req);
+	QDF_STATUS (*mlme_cm_ext_rso_stop_cb)(struct wlan_objmgr_vdev *vdev);
 	QDF_STATUS (*mlme_cm_ext_reassoc_req_cb)(
 				struct wlan_objmgr_vdev *vdev,
 				struct wlan_cm_vdev_reassoc_req *req);
@@ -629,6 +631,14 @@ QDF_STATUS mlme_cm_connect_complete_ind(struct wlan_objmgr_vdev *vdev,
 QDF_STATUS mlme_cm_roam_start_ind(struct wlan_objmgr_vdev *vdev,
 				  struct wlan_cm_roam_req *req);
 
+/**
+ * mlme_cm_rso_stop_req() - Connection manager ext RSO stop request
+ * @vdev: VDEV object
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS mlme_cm_rso_stop_req(struct wlan_objmgr_vdev *vdev);
+
 /**
  * mlme_cm_reassoc_req() - Connection manager ext reassoc request
  * @vdev: VDEV object

+ 10 - 0
umac/mlme/mlme_objmgr/dispatcher/src/wlan_cmn_mlme_main.c

@@ -356,6 +356,16 @@ QDF_STATUS mlme_cm_roam_start_ind(struct wlan_objmgr_vdev *vdev,
 	return ret;
 }
 
+QDF_STATUS mlme_cm_rso_stop_req(struct wlan_objmgr_vdev *vdev)
+{
+	QDF_STATUS ret = QDF_STATUS_E_NOSUPPORT;
+
+	if ((glbl_ops) && glbl_ops->mlme_cm_ext_rso_stop_cb)
+		ret = glbl_ops->mlme_cm_ext_rso_stop_cb(vdev);
+
+	return ret;
+}
+
 QDF_STATUS mlme_cm_reassoc_req(struct wlan_objmgr_vdev *vdev,
 			       struct wlan_cm_vdev_reassoc_req *req)
 {

+ 6 - 0
umac/mlme/vdev_mgr/dispatcher/inc/wlan_vdev_mgr_tgt_if_rx_defs.h

@@ -42,6 +42,7 @@
  * STOP_RESPONSE_BIT: vdev stop response bit
  * DELETE_RESPONSE_BIT:  vdev delete response bit
  * PEER_DELETE_ALL_RESPONSE_BIT: vdev peer delete all response bit
+ * RSO_STOP_RESPONSE_BIT : RSO stop response bit
  */
 enum wlan_vdev_mgr_tgt_if_rsp_bit {
 	START_RESPONSE_BIT = 0,
@@ -49,6 +50,7 @@ enum wlan_vdev_mgr_tgt_if_rsp_bit {
 	STOP_RESPONSE_BIT = 2,
 	DELETE_RESPONSE_BIT = 3,
 	PEER_DELETE_ALL_RESPONSE_BIT = 4,
+	RSO_STOP_RESPONSE_BIT = 5,
 	RESPONSE_BIT_MAX,
 };
 
@@ -66,6 +68,7 @@ static inline char *string_from_rsp_bit(enum wlan_vdev_mgr_tgt_if_rsp_bit bit)
 					"STOP",
 					"DELETE",
 					"PEER DELETE ALL",
+					"RSO STOP",
 					"RESPONE MAX"};
 	return (char *)strings[bit];
 }
@@ -76,17 +79,20 @@ static inline char *string_from_rsp_bit(enum wlan_vdev_mgr_tgt_if_rsp_bit bit)
 #define STOP_RESPONSE_TIMER            (4000 + PMO_RESUME_TIMEOUT)
 #define DELETE_RESPONSE_TIMER          (4000 + PMO_RESUME_TIMEOUT)
 #define PEER_DELETE_ALL_RESPONSE_TIMER (6000 + PMO_RESUME_TIMEOUT)
+#define RSO_STOP_RESPONSE_TIMER        (6000 + PMO_RESUME_TIMEOUT)
 #elif defined(QCA_LOWMEM_CONFIG) || defined(QCA_512M_CONFIG) || \
 defined(QCA_WIFI_QCA5018)
 #define START_RESPONSE_TIMER           15000
 #define STOP_RESPONSE_TIMER            15000
 #define DELETE_RESPONSE_TIMER          15000
 #define PEER_DELETE_ALL_RESPONSE_TIMER 15000
+#define RSO_STOP_RESPONSE_TIMER        15000
 #else
 #define START_RESPONSE_TIMER           8000
 #define STOP_RESPONSE_TIMER            6000
 #define DELETE_RESPONSE_TIMER          4000
 #define PEER_DELETE_ALL_RESPONSE_TIMER 6000
+#define RSO_STOP_RESPONSE_TIMER        6000
 #endif
 
 #ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE