From db3c1a98e51f01485c313e2a62aaa9ab66b7ea9c Mon Sep 17 00:00:00 2001 From: Srinivas Dasari Date: Tue, 21 Dec 2021 16:28:34 +0530 Subject: [PATCH] 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 --- .../core/src/wlan_mlme_vdev_mgr_interface.c | 1 + .../inc/target_if_cm_roam_event.h | 11 +- .../inc/target_if_cm_roam_offload.h | 43 +++++ .../src/target_if_cm_roam_event.c | 11 +- .../src/target_if_cm_roam_offload.c | 182 +++++++++++++++++- .../core/src/wlan_cm_host_util.c | 4 +- .../core/src/wlan_cm_roam_fw_sync.c | 11 +- .../core/src/wlan_cm_roam_offload.c | 56 +++++- .../core/src/wlan_cm_roam_offload.h | 8 +- .../core/src/wlan_cm_roam_offload_event.c | 3 +- .../core/src/wlan_cm_vdev_api.h | 29 +++ .../core/src/wlan_cm_vdev_disconnect.c | 38 +++- .../inc/wlan_cm_roam_public_struct.h | 13 +- .../dispatcher/src/wlan_cm_roam_api.c | 36 +++- .../dispatcher/src/wlan_cm_roam_ucfg_api.c | 5 +- components/wmi/src/wmi_unified_roam_tlv.c | 21 ++ 16 files changed, 429 insertions(+), 43 deletions(-) diff --git a/components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c b/components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c index d5a81e77bf..dedda2c385 100644 --- a/components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c +++ b/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 diff --git a/components/target_if/connection_mgr/inc/target_if_cm_roam_event.h b/components/target_if/connection_mgr/inc/target_if_cm_roam_event.h index 0fa221de77..ae46c7dd0b 100644 --- a/components/target_if/connection_mgr/inc/target_if_cm_roam_event.h +++ b/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 #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 diff --git a/components/target_if/connection_mgr/inc/target_if_cm_roam_offload.h b/components/target_if/connection_mgr/inc/target_if_cm_roam_offload.h index 74c2266ec2..7ccf40680b 100644 --- a/components/target_if/connection_mgr/inc/target_if_cm_roam_offload.h +++ b/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 diff --git a/components/target_if/connection_mgr/src/target_if_cm_roam_event.c b/components/target_if/connection_mgr/src/target_if_cm_roam_event.c index b6b0422eff..df0e79d589 100644 --- a/components/target_if/connection_mgr/src/target_if_cm_roam_event.c +++ b/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"); diff --git a/components/target_if/connection_mgr/src/target_if_cm_roam_offload.c b/components/target_if/connection_mgr/src/target_if_cm_roam_offload.c index 1b9112170b..18f5d3446c 100644 --- a/components/target_if/connection_mgr/src/target_if_cm_roam_offload.c +++ b/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 +#include +#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; } diff --git a/components/umac/mlme/connection_mgr/core/src/wlan_cm_host_util.c b/components/umac/mlme/connection_mgr/core/src/wlan_cm_host_util.c index ae8ee723d0..2cdbce7815 100644 --- a/components/umac/mlme/connection_mgr/core/src/wlan_cm_host_util.c +++ b/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; } diff --git a/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_fw_sync.c b/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_fw_sync.c index 877bfae0e4..92b0ad2386 100644 --- a/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_fw_sync.c +++ b/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); } diff --git a/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c b/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c index 56f7e4f1cd..a1117bc867 100644 --- a/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c +++ b/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 */ diff --git a/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.h b/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.h index 7f3d55d29b..d9f7efd366 100644 --- a/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.h +++ b/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 diff --git a/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload_event.c b/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload_event.c index 540a9c4b13..af6d6521ea 100644 --- a/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload_event.c +++ b/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; } diff --git a/components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_api.h b/components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_api.h index ad99e36249..75032b6310 100644 --- a/components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_api.h +++ b/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__ */ diff --git a/components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_disconnect.c b/components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_disconnect.c index 791a86f368..8dc815306c 100644 --- a/components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_disconnect.c +++ b/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; +} diff --git a/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h b/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h index 14f6d7de49..a2086e07ee 100644 --- a/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h +++ b/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; }; /** diff --git a/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c b/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c index 6f1e649211..0710d3ed03 100644 --- a/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c +++ b/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; diff --git a/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_ucfg_api.c b/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_ucfg_api.c index d5fbe0958f..4cbbffcc38 100644 --- a/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_ucfg_api.c +++ b/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; } diff --git a/components/wmi/src/wmi_unified_roam_tlv.c b/components/wmi/src/wmi_unified_roam_tlv.c index 11310d13f5..02a41f0d6d 100644 --- a/components/wmi/src/wmi_unified_roam_tlv.c +++ b/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 */