Browse Source

qcacld-3.0: 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 after sending
RSO stop command to firmware 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.

Also, set WMI_ROAM_SCAN_MODE_FLAG_REPORT_STATUS always when MLO is
supported while sending RSO_STOP to firmware. It's sent only
in case of wpa_supplicant disabled roaming currently.

Change-Id: I8182e60beb9288dba23cc72e978dc781c8ab1707
CRs-Fixed: 3106023
Srinivas Dasari 3 years ago
parent
commit
db3c1a98e5

+ 1 - 0
components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c

@@ -1920,6 +1920,7 @@ static struct mlme_ext_ops ext_ops = {
 #ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE
 	.mlme_vdev_send_set_mac_addr = vdevmgr_mlme_vdev_send_set_mac_addr,
 #endif
+	.mlme_cm_ext_rso_stop_cb = cm_send_rso_stop,
 };
 
 #ifdef WLAN_FEATURE_11BE_MLO

+ 10 - 1
components/target_if/connection_mgr/inc/target_if_cm_roam_event.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 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
@@ -31,6 +31,15 @@
 #include <target_if.h>
 
 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
+/**
+ * target_if_cm_get_roam_rx_ops() - Get CM roam rx ops registered
+ * @psoc: pointer to psoc object
+ *
+ * Return: roam rx ops of connection mgr
+ */
+struct wlan_cm_roam_rx_ops *
+target_if_cm_get_roam_rx_ops(struct wlan_objmgr_psoc *psoc);
+
 /**
  * target_if_cm_roam_sync_event() - Target IF handler for roam sync events
  * @scn: target handle

+ 43 - 0
components/target_if/connection_mgr/inc/target_if_cm_roam_offload.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2020, 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
@@ -32,4 +33,46 @@
  */
 QDF_STATUS
 target_if_cm_roam_register_tx_ops(struct wlan_cm_roam_tx_ops *tx_ops);
+
+#ifdef WLAN_FEATURE_11BE_MLO
+/**
+ * target_if_stop_rso_stop_timer() - Stop the RSO_STOP timer
+ * @roam_event: Roam event data
+ *
+ * This stops the RSO stop timer in below cases,
+ * 1. If the reason is RSO_STATUS and notif is CM_ROAM_NOTIF_SCAN_MODE_SUCCESS
+ * 2. If wait started already and received HO_FAIL event
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+target_if_stop_rso_stop_timer(struct roam_offload_roam_event *roam_event);
+#else
+static inline QDF_STATUS
+target_if_stop_rso_stop_timer(struct roam_offload_roam_event *roam_event)
+{
+	roam_event->rso_timer_stopped = false;
+	return QDF_STATUS_E_NOSUPPORT;
+}
+#endif
+
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+/**
+ * target_if_cm_send_rso_stop_failure_rsp() - Send RSO_STOP failure rsp to CM
+ * @psoc: psoc object
+ * @vdev_id: vdev_id on which RSO stop is issued
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+target_if_cm_send_rso_stop_failure_rsp(struct wlan_objmgr_psoc *psoc,
+				       uint8_t vdev_id);
+#else
+static inline QDF_STATUS
+target_if_cm_send_rso_stop_failure_rsp(struct wlan_objmgr_psoc *psoc,
+				       uint8_t vdev_id)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+#endif
 #endif

+ 10 - 1
components/target_if/connection_mgr/src/target_if_cm_roam_event.c

@@ -30,8 +30,9 @@
 #include "wlan_mlme_main.h"
 #include <../../core/src/wlan_cm_roam_i.h>
 #include "wlan_cm_roam_api.h"
+#include "target_if_cm_roam_offload.h"
 
-static inline struct wlan_cm_roam_rx_ops *
+struct wlan_cm_roam_rx_ops *
 target_if_cm_get_roam_rx_ops(struct wlan_objmgr_psoc *psoc)
 {
 	struct wlan_mlme_psoc_ext_obj *psoc_ext_priv;
@@ -238,6 +239,14 @@ int target_if_cm_roam_event(ol_scn_t scn, uint8_t *event, uint32_t len)
 
 	roam_event->psoc = psoc;
 
+	/**
+	 * Stop the timer upon RSO stop status success. The timer shall continue
+	 * to run upon HO_FAIL status and would be stopped upon HO_FAILED event
+	 */
+	if (roam_event->reason == ROAM_REASON_RSO_STATUS ||
+	    roam_event->reason == ROAM_REASON_HO_FAILED)
+		target_if_stop_rso_stop_timer(roam_event);
+
 	roam_rx_ops = target_if_cm_get_roam_rx_ops(psoc);
 	if (!roam_rx_ops || !roam_rx_ops->roam_event_rx) {
 		target_if_err("No valid roam rx ops");

+ 172 - 10
components/target_if/connection_mgr/src/target_if_cm_roam_offload.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 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
@@ -28,6 +28,9 @@
 #include "wlan_crypto_global_api.h"
 #include "wlan_mlme_main.h"
 #include "wlan_cm_roam_api.h"
+#include <target_if_vdev_mgr_rx_ops.h>
+#include <target_if_vdev_mgr_tx_ops.h>
+#include "target_if_cm_roam_event.h"
 
 static struct wmi_unified
 *target_if_cm_roam_get_wmi_handle_from_vdev(struct wlan_objmgr_vdev *vdev)
@@ -1093,6 +1096,141 @@ end:
 	return status;
 }
 
+#ifdef WLAN_FEATURE_11BE_MLO
+static QDF_STATUS
+target_if_start_rso_stop_timer(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_objmgr_psoc *psoc;
+	uint8_t vdev_id;
+	struct wlan_lmac_if_mlme_rx_ops *rx_ops;
+	struct vdev_response_timer *vdev_rsp;
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		target_if_err("psoc handle is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	vdev_id = wlan_vdev_get_id(vdev);
+	rx_ops = target_if_vdev_mgr_get_rx_ops(psoc);
+	if (!rx_ops || !rx_ops->psoc_get_vdev_response_timer_info) {
+		mlme_err("VEV_%d: PSOC_%d No Rx Ops", vdev_id,
+			 wlan_psoc_get_id(psoc));
+		return QDF_STATUS_E_INVAL;
+	}
+
+	vdev_rsp = rx_ops->psoc_get_vdev_response_timer_info(psoc, vdev_id);
+	if (!vdev_rsp) {
+		mlme_err("VDEV_%d: PSOC_%d No vdev rsp timer", vdev_id,
+			 wlan_psoc_get_id(psoc));
+		return QDF_STATUS_E_INVAL;
+	}
+
+	vdev_rsp->expire_time = RSO_STOP_RESPONSE_TIMER;
+
+	return target_if_vdev_mgr_rsp_timer_start(psoc, vdev_rsp,
+						  RSO_STOP_RESPONSE_BIT);
+}
+
+QDF_STATUS
+target_if_stop_rso_stop_timer(struct roam_offload_roam_event *roam_event)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct vdev_response_timer *vdev_rsp;
+	struct wlan_lmac_if_mlme_rx_ops *rx_ops;
+
+	roam_event->rso_timer_stopped = false;
+	rx_ops = target_if_vdev_mgr_get_rx_ops(roam_event->psoc);
+	if (!rx_ops || !rx_ops->vdev_mgr_start_response) {
+		mlme_err("No Rx Ops");
+		return QDF_STATUS_E_INVAL;
+	}
+	vdev_rsp = rx_ops->psoc_get_vdev_response_timer_info(roam_event->psoc,
+							roam_event->vdev_id);
+	if (!vdev_rsp) {
+		mlme_err("vdev response timer is null VDEV_%d PSOC_%d",
+			 roam_event->vdev_id,
+			 wlan_psoc_get_id(roam_event->psoc));
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if ((roam_event->reason == ROAM_REASON_RSO_STATUS &&
+	     (roam_event->notif == CM_ROAM_NOTIF_SCAN_MODE_SUCCESS ||
+	      roam_event->notif == CM_ROAM_NOTIF_SCAN_MODE_FAIL)) ||
+	    roam_event->reason == ROAM_REASON_HO_FAILED) {
+		status = target_if_vdev_mgr_rsp_timer_stop(roam_event->psoc,
+					vdev_rsp, RSO_STOP_RESPONSE_BIT);
+		if (QDF_IS_STATUS_SUCCESS(status))
+			roam_event->rso_timer_stopped = true;
+		else
+			mlme_err("PSOC_%d VDEV_%d: VDE MGR RSP Timer stop failed",
+				 roam_event->psoc->soc_objmgr.psoc_id,
+				 roam_event->vdev_id);
+	} else if (roam_event->reason == ROAM_REASON_RSO_STATUS &&
+		   roam_event->notif == CM_ROAM_NOTIF_HO_FAIL) {
+		mlme_debug("HO_FAIL happened, wait for HO_FAIL event vdev_id: %u",
+			   roam_event->vdev_id);
+	}
+
+	return status;
+}
+
+#else
+static inline QDF_STATUS
+target_if_start_rso_stop_timer(struct wlan_objmgr_vdev *vdev)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+#endif
+
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+QDF_STATUS
+target_if_cm_send_rso_stop_failure_rsp(struct wlan_objmgr_psoc *psoc,
+				       uint8_t vdev_id)
+{
+	struct wlan_cm_roam_rx_ops *roam_rx_ops;
+	struct roam_offload_roam_event roam_event = {0};
+
+	roam_event.vdev_id = vdev_id;
+	roam_event.psoc = psoc;
+	roam_event.reason = ROAM_REASON_RSO_STATUS;
+	roam_event.notif = CM_ROAM_NOTIF_SCAN_MODE_FAIL;
+	roam_event.rso_timer_stopped = true;
+
+	roam_rx_ops = target_if_cm_get_roam_rx_ops(psoc);
+	if (!roam_rx_ops || !roam_rx_ops->roam_event_rx) {
+		target_if_err("No valid roam rx ops");
+		return QDF_STATUS_E_INVAL;
+	}
+	roam_rx_ops->roam_event_rx(&roam_event);
+
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
+static QDF_STATUS
+target_if_cm_roam_abort_rso_stop_timer(struct wlan_objmgr_psoc *psoc,
+				       uint8_t vdev_id)
+{
+	struct vdev_response_timer *vdev_rsp;
+	struct wlan_lmac_if_mlme_rx_ops *rx_ops;
+
+	rx_ops = target_if_vdev_mgr_get_rx_ops(psoc);
+	if (!rx_ops || !rx_ops->vdev_mgr_start_response) {
+		mlme_err("No Rx Ops");
+		return QDF_STATUS_E_INVAL;
+	}
+	vdev_rsp = rx_ops->psoc_get_vdev_response_timer_info(psoc, vdev_id);
+	if (!vdev_rsp) {
+		mlme_err("vdev response timer is null VDEV_%d PSOC_%d",
+			 vdev_id, wlan_psoc_get_id(psoc));
+		return QDF_STATUS_E_INVAL;
+	}
+
+	return target_if_vdev_mgr_rsp_timer_stop(psoc, vdev_rsp,
+						 RSO_STOP_RESPONSE_BIT);
+}
+
 /**
  * target_if_cm_roam_send_stop() - Send roam stop related commands
  * to wmi
@@ -1108,6 +1246,8 @@ target_if_cm_roam_send_stop(struct wlan_objmgr_vdev *vdev,
 			    struct wlan_roam_stop_config *req)
 {
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	QDF_STATUS timer_start_status = QDF_STATUS_E_NOSUPPORT;
+	QDF_STATUS rso_stop_status = QDF_STATUS_E_INVAL;
 	wmi_unified_t wmi_handle;
 	struct wlan_objmgr_psoc *psoc;
 	uint8_t vdev_id;
@@ -1116,6 +1256,12 @@ target_if_cm_roam_send_stop(struct wlan_objmgr_vdev *vdev,
 	if (!wmi_handle)
 		return QDF_STATUS_E_FAILURE;
 
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		target_if_err("psoc handle is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
 	/* Send 11k offload disable command to FW as part of RSO Stop */
 	status = target_if_cm_roam_offload_11k_params(wmi_handle,
 						      &req->roam_11k_params);
@@ -1133,15 +1279,12 @@ target_if_cm_roam_send_stop(struct wlan_objmgr_vdev *vdev,
 		goto end;
 	}
 
-	psoc = wlan_vdev_get_psoc(vdev);
-	if (!psoc) {
-		target_if_err("psoc handle is NULL");
-		return QDF_STATUS_E_INVAL;
-	}
+	if (req->start_rso_stop_timer)
+		timer_start_status = target_if_start_rso_stop_timer(vdev);
 
-	status = target_if_cm_roam_scan_offload_mode(wmi_handle,
-						     &req->rso_config);
-	if (QDF_IS_STATUS_ERROR(status)) {
+	rso_stop_status = target_if_cm_roam_scan_offload_mode(wmi_handle,
+							      &req->rso_config);
+	if (QDF_IS_STATUS_ERROR(rso_stop_status)) {
 		target_if_err("vdev:%d Send RSO mode cmd failed",
 			      req->rso_config.vdev_id);
 		goto end;
@@ -1181,13 +1324,32 @@ target_if_cm_roam_send_stop(struct wlan_objmgr_vdev *vdev,
 	 * disconnect
 	 */
 	vdev_id = wlan_vdev_get_id(vdev);
-	if (req->rso_config.rso_mode_info.roam_scan_mode == WMI_ROAM_SCAN_MODE_NONE) {
+	if (req->rso_config.rso_mode_info.roam_scan_mode ==
+	    WMI_ROAM_SCAN_MODE_NONE) {
 		req->roam_triggers.vdev_id = vdev_id;
 		req->roam_triggers.trigger_bitmap = 0;
 		req->roam_triggers.roam_scan_scheme_bitmap = 0;
 		target_if_cm_roam_triggers(vdev, &req->roam_triggers);
 	}
 end:
+	if (QDF_IS_STATUS_SUCCESS(timer_start_status)) {
+		if (QDF_IS_STATUS_SUCCESS(rso_stop_status)) {
+			/*
+			 * Started the timer and send RSO stop to firmware
+			 * successfully. Wait for RSO STOP response from fw.
+			 */
+			req->send_rso_stop_resp = false;
+		} else {
+			/*
+			 * Started the timer and but failed to send RSO stop to
+			 * firmware. Stop the timer and let the response be
+			 * poseted from CM.
+			 */
+			target_if_cm_roam_abort_rso_stop_timer(psoc,
+						wlan_vdev_get_id(vdev));
+		}
+	}
+
 	return status;
 }
 

+ 3 - 1
components/umac/mlme/connection_mgr/core/src/wlan_cm_host_util.c

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2021 The Linux Foundation. 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
@@ -238,7 +239,8 @@ QDF_STATUS cm_handle_roam_start(struct wlan_objmgr_vdev *vdev,
 		cm_roam_state_change(wlan_vdev_get_pdev(vdev),
 				     wlan_vdev_get_id(vdev),
 				     WLAN_ROAM_RSO_STOPPED,
-				     REASON_OS_REQUESTED_ROAMING_NOW);
+				     REASON_OS_REQUESTED_ROAMING_NOW,
+				     NULL, false);
 	return QDF_STATUS_SUCCESS;
 }
 

+ 7 - 4
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_fw_sync.c

@@ -66,7 +66,7 @@ QDF_STATUS cm_fw_roam_sync_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 			 vdev_id);
 		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
 		return cm_roam_stop_req(psoc, vdev_id,
-					REASON_ROAM_SYNCH_FAILED);
+					REASON_ROAM_SYNCH_FAILED, NULL, false);
 	}
 
 	status = cm_sm_deliver_event(vdev, WLAN_CM_SM_EV_ROAM_SYNC,
@@ -75,7 +75,8 @@ QDF_STATUS cm_fw_roam_sync_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 	if (QDF_IS_STATUS_ERROR(status)) {
 		mlme_err("EV ROAM SYNC REQ not handled");
 		cm_fw_roam_abort_req(psoc, vdev_id);
-		cm_roam_stop_req(psoc, vdev_id, REASON_ROAM_SYNCH_FAILED);
+		cm_roam_stop_req(psoc, vdev_id, REASON_ROAM_SYNCH_FAILED,
+				 NULL, false);
 	}
 
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
@@ -117,7 +118,8 @@ cm_fw_send_vdev_roam_event(struct cnx_mgr *cm_ctx, uint16_t data_len,
 
 	if (QDF_IS_STATUS_ERROR(status))
 		cm_roam_stop_req(psoc, roam_req->req.vdev_id,
-				 REASON_ROAM_SYNCH_FAILED);
+				 REASON_ROAM_SYNCH_FAILED,
+				 NULL, false);
 
 error:
 	if (QDF_IS_STATUS_ERROR(status))
@@ -882,7 +884,8 @@ error:
 		wlan_cm_free_connect_rsp(rsp);
 
 	if (QDF_IS_STATUS_ERROR(status)) {
-		cm_roam_stop_req(psoc, vdev_id, REASON_ROAM_SYNCH_FAILED);
+		cm_roam_stop_req(psoc, vdev_id, REASON_ROAM_SYNCH_FAILED,
+				 NULL, false);
 		cm_abort_fw_roam(cm_ctx, cm_id);
 		mlo_update_connected_links(vdev, 0);
 	}

+ 46 - 10
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c

@@ -929,7 +929,7 @@ QDF_STATUS cm_rso_set_roam_trigger(struct wlan_objmgr_pdev *pdev,
 	status = cm_roam_state_change(pdev, vdev_id,
 			trigger->trigger_bitmap ? WLAN_ROAM_RSO_ENABLED :
 			WLAN_ROAM_DEINIT,
-			reason);
+			reason, NULL, false);
 	if (QDF_IS_STATUS_ERROR(status))
 		return status;
 
@@ -2948,7 +2948,7 @@ static void cm_fill_stop_reason(struct wlan_roam_stop_config *stop_req,
 
 QDF_STATUS
 cm_roam_stop_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
-		 uint8_t reason)
+		 uint8_t reason, bool *send_resp, bool start_timer)
 {
 	struct wlan_roam_stop_config *stop_req;
 	QDF_STATUS status;
@@ -2990,6 +2990,9 @@ cm_roam_stop_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 	cm_fill_stop_reason(stop_req, reason);
 	if (wlan_cm_host_roam_in_progress(psoc, vdev_id))
 		stop_req->middle_of_roaming = 1;
+	if (send_resp)
+		stop_req->send_rso_stop_resp = *send_resp;
+	stop_req->start_rso_stop_timer = start_timer;
 	/*
 	 * If roam synch propagation is in progress and an user space
 	 * disconnect is requested, then there is no need to send the
@@ -3028,6 +3031,8 @@ cm_roam_stop_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 	if (QDF_IS_STATUS_ERROR(status)) {
 		mlme_debug("fail to send roam stop");
 	}
+	if (send_resp)
+		*send_resp = stop_req->send_rso_stop_resp;
 
 rel_vdev_ref:
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
@@ -3439,7 +3444,7 @@ QDF_STATUS cm_roam_send_rso_cmd(struct wlan_objmgr_psoc *psoc,
 static QDF_STATUS
 cm_roam_switch_to_rso_stop(struct wlan_objmgr_pdev *pdev,
 			   uint8_t vdev_id,
-			   uint8_t reason)
+			   uint8_t reason, bool *send_resp, bool start_timer)
 {
 	enum roam_offload_state cur_state;
 	QDF_STATUS status;
@@ -3450,7 +3455,8 @@ cm_roam_switch_to_rso_stop(struct wlan_objmgr_pdev *pdev,
 	case WLAN_ROAM_RSO_ENABLED:
 	case WLAN_ROAMING_IN_PROG:
 	case WLAN_ROAM_SYNCH_IN_PROG:
-		status = cm_roam_stop_req(psoc, vdev_id, reason);
+		status = cm_roam_stop_req(psoc, vdev_id, reason,
+					  send_resp, start_timer);
 		if (QDF_IS_STATUS_ERROR(status)) {
 			mlme_err("ROAM: Unable to switch to RSO STOP State");
 			return QDF_STATUS_E_FAILURE;
@@ -3501,7 +3507,7 @@ cm_roam_switch_to_deinit(struct wlan_objmgr_pdev *pdev,
 	case WLAN_ROAM_RSO_ENABLED:
 	case WLAN_ROAMING_IN_PROG:
 	case WLAN_ROAM_SYNCH_IN_PROG:
-		cm_roam_switch_to_rso_stop(pdev, vdev_id, reason);
+		cm_roam_switch_to_rso_stop(pdev, vdev_id, reason, NULL, false);
 		break;
 	case WLAN_ROAM_RSO_STOPPED:
 		/*
@@ -3522,7 +3528,8 @@ cm_roam_switch_to_deinit(struct wlan_objmgr_pdev *pdev,
 		if (sup_disabled_roam) {
 			mlme_err("vdev[%d]: supplicant disabled roam. clear roam scan mode",
 				 vdev_id);
-			cm_roam_switch_to_rso_stop(pdev, vdev_id, reason);
+			cm_roam_switch_to_rso_stop(pdev, vdev_id, reason,
+						   NULL, false);
 		}
 
 	case WLAN_ROAM_INIT:
@@ -3650,7 +3657,8 @@ cm_roam_switch_to_init(struct wlan_objmgr_pdev *pdev,
 				cm_roam_state_change(pdev, temp_vdev_id,
 						     WLAN_ROAM_DEINIT,
 						     is_vdev_primary ?
-					     REASON_ROAM_SET_PRIMARY : reason);
+					     REASON_ROAM_SET_PRIMARY : reason,
+						     NULL, false);
 			} else {
 				mlme_info("CM_RSO: Roam module already initialized on vdev:[%d]",
 					  temp_vdev_id);
@@ -3847,7 +3855,8 @@ cm_roam_switch_to_rso_enable(struct wlan_objmgr_pdev *pdev,
 
 	mlme_debug("ROAM: RSO disabled by Supplicant on vdev[%d]", vdev_id);
 	return cm_roam_state_change(pdev, vdev_id, WLAN_ROAM_RSO_STOPPED,
-				    REASON_SUPPLICANT_DISABLED_ROAMING);
+				    REASON_SUPPLICANT_DISABLED_ROAMING,
+				    NULL, false);
 }
 
 /**
@@ -4217,7 +4226,7 @@ QDF_STATUS
 cm_roam_state_change(struct wlan_objmgr_pdev *pdev,
 		     uint8_t vdev_id,
 		     enum roam_offload_state requested_state,
-		     uint8_t reason)
+		     uint8_t reason, bool *send_resp, bool start_timer)
 {
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
 	struct wlan_objmgr_vdev *vdev;
@@ -4260,7 +4269,8 @@ cm_roam_state_change(struct wlan_objmgr_pdev *pdev,
 		status = cm_roam_switch_to_rso_enable(pdev, vdev_id, reason);
 		break;
 	case WLAN_ROAM_RSO_STOPPED:
-		status = cm_roam_switch_to_rso_stop(pdev, vdev_id, reason);
+		status = cm_roam_switch_to_rso_stop(pdev, vdev_id, reason,
+						    send_resp, start_timer);
 		break;
 	case WLAN_ROAMING_IN_PROG:
 		status = cm_roam_switch_to_roam_start(pdev, vdev_id, reason);
@@ -5840,4 +5850,30 @@ cm_roam_beacon_loss_disconnect_event(struct qdf_mac_addr bssid, int32_t rssi,
 	return status;
 }
 #endif /* WLAN_FEATURE_CONNECTIVITY_LOGGING */
+
+QDF_STATUS
+cm_send_rso_stop(struct wlan_objmgr_vdev *vdev)
+{
+	bool send_resp = true, start_timer;
+
+	if (!vdev) {
+		mlme_err("vdev is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+	start_timer = cm_roam_offload_enabled(wlan_vdev_get_psoc(vdev));
+
+	cm_roam_state_change(wlan_vdev_get_pdev(vdev), wlan_vdev_get_id(vdev),
+			     WLAN_ROAM_RSO_STOPPED, REASON_DRIVER_DISABLED,
+			     &send_resp, start_timer);
+	/*
+	 * RSO stop resp is not supported or RSO STOP timer/req failed,
+	 * then send resp from here
+	 */
+	if (send_resp)
+		wlan_cm_rso_stop_continue_disconnect(wlan_vdev_get_psoc(vdev),
+						     wlan_vdev_get_id(vdev),
+						     false);
+
+	return QDF_STATUS_SUCCESS;
+}
 #endif  /* WLAN_FEATURE_ROAM_OFFLOAD */

+ 6 - 2
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.h

@@ -106,6 +106,8 @@ void cm_roam_result_info_event(struct wmi_roam_result *res,
  * @vdev_id: vdev id
  * @requested_state: roam state to be set
  * @reason: reason for changing roam state for the requested vdev id
+ * @send_resp: send rso stop response
+ * @start_timer: start timer for rso stop
  *
  * This function posts roam state change to roam state machine handling
  *
@@ -115,7 +117,7 @@ QDF_STATUS
 cm_roam_state_change(struct wlan_objmgr_pdev *pdev,
 		     uint8_t vdev_id,
 		     enum roam_offload_state requested_state,
-		     uint8_t reason);
+		     uint8_t reason, bool *send_resp, bool start_timer);
 
 /**
  * cm_handle_sta_sta_roaming_enablement() - To handle roaming in case
@@ -169,12 +171,14 @@ QDF_STATUS cm_rso_set_roam_trigger(struct wlan_objmgr_pdev *pdev,
  * @psoc: psoc pointer
  * @vdev_id: vdev id
  * @reason: reason for changing roam state for the requested vdev id
+ * @send_resp: send rso stop response
+ * @start_timer: start timer for rso stop
  *
  * Return: QDF_STATUS
  */
 QDF_STATUS
 cm_roam_stop_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
-		 uint8_t reason);
+		 uint8_t reason, bool *send_resp, bool start_timer);
 
 /**
  * cm_roam_fill_rssi_change_params() - Fill roam scan rssi change parameters

+ 2 - 1
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload_event.c

@@ -532,7 +532,8 @@ err:
 		wlan_mlo_roam_abort_on_link(psoc, sync_ind);
 		cm_fw_roam_abort_req(psoc, sync_ind->roamed_vdev_id);
 		cm_roam_stop_req(psoc, sync_ind->roamed_vdev_id,
-				 REASON_ROAM_SYNCH_FAILED);
+				 REASON_ROAM_SYNCH_FAILED,
+				 NULL, false);
 	}
 	return status;
 }

+ 29 - 0
components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_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
@@ -689,4 +690,32 @@ QDF_STATUS wlan_cm_send_connect_rsp(struct scheduler_msg *msg);
  * Return: void
  */
 void wlan_cm_free_connect_rsp(struct cm_vdev_join_rsp *rsp);
+
+/**
+ * wlan_cm_rso_stop_continue_disconnect() - Continue disconnect after RSO stop
+ * @psoc: psoc object
+ * @vdev_id: vdev id
+ * @is_ho_fail: Carries true if HO_FAIL happened
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+wlan_cm_rso_stop_continue_disconnect(struct wlan_objmgr_psoc *psoc,
+				     uint8_t vdev_id, bool is_ho_fail);
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+/**
+ * cm_send_rso_stop() - Send RSP stop req to firmware
+ * @vdev: VDEV object
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+cm_send_rso_stop(struct wlan_objmgr_vdev *vdev);
+#else
+static inline QDF_STATUS
+cm_send_rso_stop(struct wlan_objmgr_vdev *vdev)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+#endif
 #endif /* __WLAN_CM_VDEV_API_H__ */

+ 36 - 2
components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_disconnect.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
@@ -82,8 +83,6 @@ QDF_STATUS cm_disconnect_start_ind(struct wlan_objmgr_vdev *vdev,
 		wlan_p2p_cleanup_roc_by_vdev(vdev);
 		wlan_tdls_notify_sta_disconnect(req->vdev_id, false,
 						user_disconnect, vdev);
-		cm_roam_state_change(pdev, req->vdev_id, WLAN_ROAM_RSO_STOPPED,
-				     REASON_DRIVER_DISABLED);
 	}
 	cm_abort_connect_request_timers(vdev);
 
@@ -401,3 +400,38 @@ QDF_STATUS cm_handle_disconnect_resp(struct scheduler_msg *msg)
 
 	return QDF_STATUS_SUCCESS;
 }
+
+QDF_STATUS
+wlan_cm_rso_stop_continue_disconnect(struct wlan_objmgr_psoc *psoc,
+				     uint8_t vdev_id, bool is_ho_fail)
+{
+	struct wlan_objmgr_vdev *vdev = NULL;
+	struct wlan_cm_vdev_discon_req *req;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
+						    WLAN_MLME_SB_ID);
+	if (!vdev) {
+		mlme_err("vdev_id: %d vdev not found", vdev_id);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	req = qdf_mem_malloc(sizeof(*req));
+	if (!req) {
+		status = QDF_STATUS_E_NOMEM;
+		goto done;
+	}
+
+	if (!cm_get_active_disconnect_req(vdev, req)) {
+		mlme_err("vdev: %d: Active disconnect not found", vdev_id);
+		status = QDF_STATUS_E_EXISTS;
+		goto done;
+	}
+	wlan_cm_disc_cont_after_rso_stop(vdev, is_ho_fail, req);
+
+done:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID);
+	qdf_mem_free(req);
+
+	return status;
+}

+ 11 - 2
components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h

@@ -1727,6 +1727,8 @@ struct wlan_roam_start_config {
  * @idle_params: idle params
  * @roam_triggers: roam triggers parameters
  * @rssi_params: roam scan rssi threshold parameters
+ * @send_rso_stop_resp: send rso stop response
+ * @start_rso_stop_timer: start rso stop timer
  */
 struct wlan_roam_stop_config {
 	uint8_t reason;
@@ -1739,6 +1741,8 @@ struct wlan_roam_stop_config {
 	struct wlan_roam_idle_params idle_params;
 	struct wlan_roam_triggers roam_triggers;
 	struct wlan_roam_offload_scan_rssi_params rssi_params;
+	bool send_rso_stop_resp;
+	bool start_rso_stop_timer;
 };
 
 /**
@@ -1989,8 +1993,11 @@ struct roam_invoke_req {
  * @CM_ROAM_NOTIF_DISASSOC_RECV: indicate disassoc received, notif_params to be
 				 sent as reason code, notif_params1 to be sent
 				 as frame length
+ * @CM_ROAM_NOTIF_HO_FAIL: indicates that roaming scan mode is successful but
+			   caused disconnection and subsequent
+			   WMI_ROAM_REASON_HO_FAILED is event expected
  * @CM_ROAM_NOTIF_SCAN_END: indicate roam scan end, notif_params to be sent
-			      as WMI_ROAM_TRIGGER_REASON_ID
+			    as WMI_ROAM_TRIGGER_REASON_ID
  */
 enum cm_roam_notif {
 	CM_ROAM_NOTIF_INVALID = 0,
@@ -2004,7 +2011,8 @@ enum cm_roam_notif {
 	CM_ROAM_NOTIF_SCAN_START,
 	CM_ROAM_NOTIF_DEAUTH_RECV,
 	CM_ROAM_NOTIF_DISASSOC_RECV,
-	CM_ROAM_NOTIF_SCAN_END = 12,
+	CM_ROAM_NOTIF_HO_FAIL,
+	CM_ROAM_NOTIF_SCAN_END,
 };
 
 /**
@@ -2146,6 +2154,7 @@ struct roam_offload_roam_event {
 	uint32_t notif_params1;
 	struct cm_hw_mode_trans_ind *hw_mode_trans_ind;
 	uint8_t *deauth_disassoc_frame;
+	bool rso_timer_stopped;
 };
 
 /**

+ 29 - 7
components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c

@@ -85,7 +85,8 @@ wlan_cm_enable_roaming_on_connected_sta(struct wlan_objmgr_pdev *pdev,
 	return cm_roam_state_change(pdev,
 				    sta_vdev_id,
 				    WLAN_ROAM_RSO_ENABLED,
-				    REASON_CTX_INIT);
+				    REASON_CTX_INIT,
+				    NULL, false);
 }
 
 QDF_STATUS wlan_cm_roam_state_change(struct wlan_objmgr_pdev *pdev,
@@ -93,7 +94,8 @@ QDF_STATUS wlan_cm_roam_state_change(struct wlan_objmgr_pdev *pdev,
 				     enum roam_offload_state requested_state,
 				     uint8_t reason)
 {
-	return cm_roam_state_change(pdev, vdev_id, requested_state, reason);
+	return cm_roam_state_change(pdev, vdev_id, requested_state, reason,
+				    NULL, false);
 }
 
 QDF_STATUS wlan_cm_roam_send_rso_cmd(struct wlan_objmgr_psoc *psoc,
@@ -199,7 +201,7 @@ QDF_STATUS wlan_cm_disable_rso(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id,
 		   vdev_id, cm_roam_get_requestor_string(requestor));
 
 	status = cm_roam_state_change(pdev, vdev_id, WLAN_ROAM_RSO_STOPPED,
-				      REASON_DRIVER_DISABLED);
+				      REASON_DRIVER_DISABLED, NULL, false);
 	cm_roam_release_lock(vdev);
 
 release_ref:
@@ -234,7 +236,7 @@ QDF_STATUS wlan_cm_enable_rso(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id,
 		   vdev_id, cm_roam_get_requestor_string(requestor));
 
 	status = cm_roam_state_change(pdev, vdev_id, WLAN_ROAM_RSO_ENABLED,
-				      REASON_DRIVER_ENABLED);
+				      REASON_DRIVER_ENABLED, NULL, false);
 	cm_roam_release_lock(vdev);
 
 release_ref:
@@ -291,7 +293,7 @@ exit:
 QDF_STATUS wlan_cm_roam_stop_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 				 uint8_t reason)
 {
-	return cm_roam_stop_req(psoc, vdev_id, reason);
+	return cm_roam_stop_req(psoc, vdev_id, reason, NULL, false);
 }
 
 bool wlan_cm_same_band_sta_allowed(struct wlan_objmgr_psoc *psoc)
@@ -1722,11 +1724,11 @@ QDF_STATUS cm_mlme_roam_preauth_fail(struct wlan_objmgr_vdev *vdev,
 	if (req->source == CM_ROAMING_FW)
 		cm_roam_state_change(pdev, vdev_id,
 				     ROAM_SCAN_OFFLOAD_RESTART,
-				     roam_reason);
+				     roam_reason, NULL, false);
 	else
 		cm_roam_state_change(pdev, vdev_id,
 				     ROAM_SCAN_OFFLOAD_START,
-				     roam_reason);
+				     roam_reason, NULL, false);
 	return QDF_STATUS_SUCCESS;
 }
 #endif
@@ -2480,10 +2482,30 @@ cm_roam_event_handler(struct roam_offload_roam_event *roam_event)
 						  roam_event->rssi);
 		break;
 	case ROAM_REASON_HO_FAILED:
+		/*
+		 * Continue disconnect only if RSO_STOP timer is running when
+		 * this event is received and stopped as part of this.
+		 * Otherwise it's a normal HO_FAIL event and handle it in
+		 * legacy way.
+		 */
+		if (roam_event->rso_timer_stopped)
+			wlan_cm_rso_stop_continue_disconnect(roam_event->psoc,
+						roam_event->vdev_id, true);
+		/* fallthrough */
 	case ROAM_REASON_INVALID:
 		cm_handle_roam_offload_events(roam_event);
 		break;
 	case ROAM_REASON_RSO_STATUS:
+		/*
+		 * roam_event->rso_timer_stopped is set to true in target_if
+		 * only if RSO_STOP timer is running and it's stopped
+		 * successfully
+		 */
+		if (roam_event->rso_timer_stopped &&
+		    (roam_event->notif == CM_ROAM_NOTIF_SCAN_MODE_SUCCESS ||
+		     roam_event->notif == CM_ROAM_NOTIF_SCAN_MODE_FAIL))
+			wlan_cm_rso_stop_continue_disconnect(roam_event->psoc,
+						roam_event->vdev_id, false);
 		cm_rso_cmd_status_event_handler(roam_event->vdev_id,
 						roam_event->notif);
 		break;

+ 3 - 2
components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_ucfg_api.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 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
@@ -101,7 +101,8 @@ ucfg_user_space_enable_disable_rso(struct wlan_objmgr_pdev *pdev,
 	state = (is_fast_roam_enabled) ?
 		WLAN_ROAM_RSO_ENABLED : WLAN_ROAM_RSO_STOPPED;
 	status = cm_roam_state_change(pdev, vdev_id, state,
-				      REASON_SUPPLICANT_DISABLED_ROAMING);
+				      REASON_SUPPLICANT_DISABLED_ROAMING,
+				      NULL, false);
 
 	return status;
 }

+ 21 - 0
components/wmi/src/wmi_unified_roam_tlv.c

@@ -2575,6 +2575,8 @@ wmi_convert_fw_notif_to_cm_notif(uint32_t fw_notif)
 		return CM_ROAM_NOTIF_DEAUTH_RECV;
 	case WMI_ROAM_NOTIF_DISASSOC_RECV:
 		return CM_ROAM_NOTIF_DISASSOC_RECV;
+	case WMI_ROAM_NOTIF_SCAN_MODE_SUCCESS_WITH_HO_FAIL:
+		return CM_ROAM_NOTIF_HO_FAIL;
 	case WMI_ROAM_NOTIF_SCAN_END:
 		return CM_ROAM_NOTIF_SCAN_END;
 	default:
@@ -4032,6 +4034,23 @@ wmi_fill_rso_start_scan_tlv(struct wlan_roam_scan_offload_params *rso_req,
 	return QDF_STATUS_SUCCESS;
 }
 
+#ifdef WLAN_FEATURE_11BE_MLO
+static void
+wmi_set_rso_stop_report_status(wmi_roam_scan_mode_fixed_param *rso_fp)
+{
+	/**
+	 * Set the REPORT status flag always, so that firmware sends RSO stop
+	 * status always
+	 */
+	rso_fp->flags |= WMI_ROAM_SCAN_MODE_FLAG_REPORT_STATUS;
+}
+#else
+static void
+wmi_set_rso_stop_report_status(wmi_roam_scan_mode_fixed_param *rso_fp)
+{
+}
+#endif
+
 /**
  * send_roam_scan_offload_mode_cmd_tlv() - send roam scan mode request to fw
  * @wmi_handle: wmi handle
@@ -4101,6 +4120,8 @@ send_roam_scan_offload_mode_cmd_tlv(
 		roam_scan_mode_fp->flags |=
 				WMI_ROAM_SCAN_MODE_FLAG_REPORT_STATUS;
 		goto send_roam_scan_mode_cmd;
+	} else {
+		wmi_set_rso_stop_report_status(roam_scan_mode_fp);
 	}
 
 	/* Fill in scan parameters suitable for roaming scan */