qcacmn: FW Link switch request event handler and cnf resp

Once the FW sends the link switch request to host handle
the request from scheduler thread and send confirmation
back on completion of link switch process with status of
link switch (success/failure).

Add new serialization command type for link switch.

Introduce flags to get the current state of link switch
request, set the state to idle when no link switch in
progress or once the current link switch is completed.
Access to state is protected with MLO dev context lock.
Implement various helper API to:
    a) Transition link switch to next state.
    b) Get current state of link switch.
    c) To check whether any link switch is in progress.
    c) To check whether link switch is happening
       on assoc VDEV or not.

Introduce a new VDEV flag to suggest the VDEV is in
link switch process and also implement helper APIs to
set/get/clear this VDEV flag.
   a) The flag is set at start of link switch, once
      the FW request params are validated and before
      proceeding for link switch disconnect on VDEV.
   b) Clear the flag once the Link switch confirmation
      is sent to FW.

Validate the link switch request params:
     a) IEEE link ID's received.
     b) Check if new connection is part of MLO connection.
     c) Check if VDEV is MLO STA VDEV or not.
     d) Is VDEV in connected state or not, that means
        VDEV is not in transitioning state due to disconnect.
     e) Check if any link switch in progress on this MLD
     f) Current link ID of VDEV equals the FW params.

If validation is successful, serialize the link switch
command and in the serialization activation start the
actual link switch process.

Change-Id: Ie582650541054c8cf39aaa8316e86a7a40256a15
CRs-Fixed: 3556422
Šī revīzija ir iekļauta:
Vinod Kumar Pirla
2023-07-06 03:33:50 -07:00
revīziju iesūtīja Rahul Choudhary
vecāks 10448e6108
revīzija af6cf93a07
13 mainīti faili ar 970 papildinājumiem un 16 dzēšanām

Parādīt failu

@@ -92,10 +92,27 @@ enum wlan_mlo_link_switch_reason {
MLO_LINK_SWITCH_REASON_MAX,
};
/*
* enum mlo_link_switch_req_state - Enum to maintain the current state of
* link switch request.
* @MLO_LINK_SWITCH_STATE_IDLE: The last link switch request is inactive
* @MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK: Current link disconnect
* in progress.
* @MLO_LINK_SWITCH_STATE_SET_MAC_ADDR: MAC address update in progress
* @MLO_LINK_SWITCH_STATE_CONNECT_NEW_LINK: New link connect in progress.
* @MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS: Link switch completed successfully
*/
enum mlo_link_switch_req_state {
MLO_LINK_SWITCH_STATE_IDLE,
MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK,
MLO_LINK_SWITCH_STATE_SET_MAC_ADDR,
MLO_LINK_SWITCH_STATE_CONNECT_NEW_LINK,
MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS,
};
/**
* struct wlan_mlo_link_switch_req - Data Structure because of link switch
* request
* @is_in_progress: is link switch in progress
* @restore_vdev_flag: VDEV Flag to be restored post link switch.
* @vdev_id: VDEV Id of the link which is under link switch
* @curr_ieee_link_id: Current link id of the ML link
@@ -103,11 +120,11 @@ enum wlan_mlo_link_switch_reason {
* @peer_mld_addr: Peer MLD address
* @new_primary_freq: primary frequency of link switch link
* @new_phymode: Phy mode of link switch link
* @state: Current state of link switch
* @reason: Link switch reason
* @link_switch_ts: Link switch timestamp
*/
struct wlan_mlo_link_switch_req {
bool is_in_progress;
bool restore_vdev_flag;
uint8_t vdev_id;
uint8_t curr_ieee_link_id;
@@ -115,6 +132,7 @@ struct wlan_mlo_link_switch_req {
struct qdf_mac_addr peer_mld_addr;
uint32_t new_primary_freq;
uint32_t new_phymode;
enum mlo_link_switch_req_state state;
enum wlan_mlo_link_switch_reason reason;
qdf_time_t link_switch_ts;
};
@@ -246,12 +264,108 @@ struct mlo_link_info *mlo_mgr_get_ap_link(struct wlan_objmgr_vdev *vdev);
*/
void mlo_mgr_osif_update_connect_info(struct wlan_objmgr_vdev *vdev,
int32_t link_id);
#else
static inline void
mlo_mgr_osif_update_connect_info(struct wlan_objmgr_vdev *vdev, int32_t link_id)
{
}
#endif
/**
* mlo_mgr_link_switch_init_state() - Set the current state of link switch
* to init state.
* @mlo_dev_ctx: MLO dev context
*
* Sets the current state of link switch to MLO_LINK_SWITCH_STATE_IDLE with
* MLO dev context lock held.
*
* Return: void
*/
void mlo_mgr_link_switch_init_state(struct wlan_mlo_dev_context *mlo_dev_ctx);
/**
* mlo_mgr_link_switch_trans_next_state() - Transition to next state based
* on current state.
* @mlo_dev_ctx: MLO dev context
*
* Move to next state in link switch process based on current state with
* MLO dev context lock held.
*
* Return: void
*/
void
mlo_mgr_link_switch_trans_next_state(struct wlan_mlo_dev_context *mlo_dev_ctx);
/**
* mlo_mgr_link_switch_get_curr_state() - Get the current state of link switch.
* @mlo_dev_ctx: MLO dev context.
*
* Get the current state of link switch with MLO dev context lock held.
*
* Return: void
*/
enum mlo_link_switch_req_state
mlo_mgr_link_switch_get_curr_state(struct wlan_mlo_dev_context *mlo_dev_ctx);
/**
* mlo_mgr_is_link_switch_in_progress() - Check in link ctx in MLO dev context
* if the last received link switch is in progress.
* @vdev: VDEV object manager
*
* The API is to be called for VDEV which has MLO dev context and link context
* initialized. Returns the value of 'is_in_progress' flag in last received
* link switch request.
*
* Return: bool
*/
bool mlo_mgr_is_link_switch_in_progress(struct wlan_objmgr_vdev *vdev);
/**
* mlo_mgr_is_link_switch_on_assoc_vdev() - API to query whether link switch
* is on-going on assoc VDEV.
* @vdev: VDEV object manager
*
* Return: bool
*/
bool mlo_mgr_is_link_switch_on_assoc_vdev(struct wlan_objmgr_vdev *vdev);
/**
* mlo_mgr_ser_link_switch_cmd() - The API will serialize link switch
* command in serialization queue.
* @vdev: VDEV objmgr pointer
* @req: Link switch request parameters
*
* On receiving link switch request with valid parameters from FW, this
* API will serialize the link switch command to procced for link switch
* on @vdev once the command comes to active queue.
*
* Return: QDF_STATUS
*/
QDF_STATUS mlo_mgr_ser_link_switch_cmd(struct wlan_objmgr_vdev *vdev,
struct wlan_mlo_link_switch_req *req);
/**
* mlo_mgr_remove_link_switch_cmd() - The API will remove the link switch
* command from active serialization queue.
* @vdev: VDEV object manager
*
* Once link switch process on @vdev is completed either in success of failure
* case, the API removes the link switch command from serialization queue.
*
* Return: void
*/
void mlo_mgr_remove_link_switch_cmd(struct wlan_objmgr_vdev *vdev);
/**
* mlo_mgr_link_switch_validate_request() - Validate link switch request
* received from FW.
* @vdev: VDEV object manager
* @req: Request params from FW
*
* The API performs initial validation of link switch params received from FW
* before serializing the link switch cmd. If any of the params is invalid or
* the current status of MLO manager can't allow link switch, the API returns
* failure and link switch has to be terminated.
*
* Return: QDF_STATUS
*/
QDF_STATUS
mlo_mgr_link_switch_validate_request(struct wlan_objmgr_vdev *vdev,
struct wlan_mlo_link_switch_req *req);
/**
* mlo_mgr_link_switch_request_params() - Link switch request params from FW.
@@ -277,7 +391,6 @@ QDF_STATUS mlo_mgr_link_switch_request_params(struct wlan_objmgr_psoc *psoc,
*/
QDF_STATUS mlo_mgr_link_switch_complete(struct wlan_objmgr_vdev *vdev);
#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
/**
* mlo_mgr_link_switch_init() - API to initialize link switch
* @ml_dev: MLO dev context
@@ -300,6 +413,11 @@ QDF_STATUS mlo_mgr_link_switch_init(struct wlan_mlo_dev_context *ml_dev);
*/
QDF_STATUS mlo_mgr_link_switch_deinit(struct wlan_mlo_dev_context *ml_dev);
#else
static inline void
mlo_mgr_osif_update_connect_info(struct wlan_objmgr_vdev *vdev, int32_t link_id)
{
}
static inline QDF_STATUS
mlo_mgr_link_switch_deinit(struct wlan_mlo_dev_context *ml_dev)
{
@@ -311,5 +429,65 @@ mlo_mgr_link_switch_init(struct wlan_mlo_dev_context *ml_dev)
{
return QDF_STATUS_SUCCESS;
}
static inline void
mlo_mgr_link_switch_init_state(struct wlan_mlo_dev_context *mlo_dev_ctx)
{
}
static inline void
mlo_mgr_link_switch_trans_next_state(struct wlan_mlo_dev_context *mlo_dev_ctx)
{
}
static inline enum mlo_link_switch_req_state
mlo_mgr_link_switch_get_curr_state(struct wlan_mlo_dev_context *mlo_dev_ctx)
{
return MLO_LINK_SWITCH_STATE_IDLE;
}
static inline bool
mlo_mgr_is_link_switch_in_progress(struct wlan_objmgr_vdev *vdev)
{
return false;
}
static inline bool
mlo_mgr_is_link_switch_on_assoc_vdev(struct wlan_objmgr_vdev *vdev)
{
return false;
}
static inline QDF_STATUS
mlo_mgr_ser_link_switch_cmd(struct wlan_objmgr_vdev *vdev,
struct wlan_mlo_link_switch_req *req)
{
return QDF_STATUS_E_NOSUPPORT;
}
static inline void
mlo_mgr_remove_link_switch_cmd(struct wlan_objmgr_vdev *vdev)
{
}
static inline QDF_STATUS
mlo_mgr_link_switch_validate_request(struct wlan_objmgr_vdev *vdev,
struct wlan_mlo_link_switch_req *req)
{
return QDF_STATUS_E_NOSUPPORT;
}
static inline QDF_STATUS
mlo_mgr_link_switch_request_params(struct wlan_objmgr_psoc *psoc,
void *evt_params)
{
return QDF_STATUS_E_NOSUPPORT;
}
static inline QDF_STATUS
mlo_mgr_link_switch_complete(struct wlan_objmgr_vdev *vdev)
{
return QDF_STATUS_E_NOSUPPORT;
}
#endif
#endif

Parādīt failu

@@ -18,8 +18,10 @@
* DOC: contains MLO manager Link Switch related functionality
*/
#include <wlan_mlo_mgr_link_switch.h>
#include <wlan_objmgr_vdev_obj.h>
#include <wlan_mlo_mgr_cmn.h>
#include <wlan_mlo_mgr_main.h>
#include <wlan_mlo_mgr_sta.h>
#include <wlan_serialization_api.h>
#include <wlan_cm_api.h>
void mlo_mgr_update_link_info_mac_addr(struct wlan_objmgr_vdev *vdev,
struct wlan_mlo_link_mac_update *ml_mac_update)
@@ -214,6 +216,77 @@ void mlo_mgr_free_link_info_wmi_chan(struct wlan_mlo_dev_context *ml_dev)
}
}
#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
bool mlo_mgr_is_link_switch_in_progress(struct wlan_objmgr_vdev *vdev)
{
enum mlo_link_switch_req_state state;
struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
if (!mlo_dev_ctx)
return false;
state = mlo_mgr_link_switch_get_curr_state(mlo_dev_ctx);
return (state != MLO_LINK_SWITCH_STATE_IDLE);
}
bool mlo_mgr_is_link_switch_on_assoc_vdev(struct wlan_objmgr_vdev *vdev)
{
if (!mlo_mgr_is_link_switch_in_progress(vdev))
return false;
return vdev->mlo_dev_ctx->link_ctx->last_req.restore_vdev_flag;
}
void mlo_mgr_link_switch_init_state(struct wlan_mlo_dev_context *mlo_dev_ctx)
{
mlo_dev_lock_acquire(mlo_dev_ctx);
mlo_dev_ctx->link_ctx->last_req.state = MLO_LINK_SWITCH_STATE_IDLE;
mlo_dev_lock_release(mlo_dev_ctx);
}
void
mlo_mgr_link_switch_trans_next_state(struct wlan_mlo_dev_context *mlo_dev_ctx)
{
enum mlo_link_switch_req_state cur_state, next_state;
mlo_dev_lock_acquire(mlo_dev_ctx);
cur_state = mlo_dev_ctx->link_ctx->last_req.state;
switch (cur_state) {
case MLO_LINK_SWITCH_STATE_IDLE:
next_state = MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK;
break;
case MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK:
next_state = MLO_LINK_SWITCH_STATE_SET_MAC_ADDR;
break;
case MLO_LINK_SWITCH_STATE_SET_MAC_ADDR:
next_state = MLO_LINK_SWITCH_STATE_CONNECT_NEW_LINK;
break;
case MLO_LINK_SWITCH_STATE_CONNECT_NEW_LINK:
next_state = MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS;
break;
case MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS:
next_state = MLO_LINK_SWITCH_STATE_IDLE;
break;
default:
QDF_ASSERT(0);
break;
}
mlo_dev_ctx->link_ctx->last_req.state = next_state;
mlo_dev_lock_release(mlo_dev_ctx);
}
enum mlo_link_switch_req_state
mlo_mgr_link_switch_get_curr_state(struct wlan_mlo_dev_context *mlo_dev_ctx)
{
enum mlo_link_switch_req_state state;
mlo_dev_lock_acquire(mlo_dev_ctx);
state = mlo_dev_ctx->link_ctx->last_req.state;
mlo_dev_lock_release(mlo_dev_ctx);
return state;
}
QDF_STATUS mlo_mgr_link_switch_init(struct wlan_mlo_dev_context *ml_dev)
{
ml_dev->link_ctx =
@@ -222,6 +295,7 @@ QDF_STATUS mlo_mgr_link_switch_init(struct wlan_mlo_dev_context *ml_dev)
if (!ml_dev->link_ctx)
return QDF_STATUS_E_NOMEM;
mlo_mgr_link_switch_init_state(ml_dev);
mlo_mgr_alloc_link_info_wmi_chan(ml_dev);
mlo_mgr_update_link_info_reset(ml_dev);
@@ -236,7 +310,6 @@ QDF_STATUS mlo_mgr_link_switch_deinit(struct wlan_mlo_dev_context *ml_dev)
return QDF_STATUS_SUCCESS;
}
#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
void
mlo_mgr_osif_update_connect_info(struct wlan_objmgr_vdev *vdev, int32_t link_id)
{
@@ -263,4 +336,270 @@ mlo_mgr_osif_update_connect_info(struct wlan_objmgr_vdev *vdev, int32_t link_id)
osif_bss_update_cb(&link_info->link_addr, &link_info->ap_link_addr,
link_id);
}
static QDF_STATUS
mlo_mgr_start_link_switch(struct wlan_objmgr_vdev *vdev,
struct wlan_serialization_command *cmd)
{
uint8_t vdev_id, old_link_id, new_link_id;
struct mlo_link_switch_context *link_ctx = vdev->mlo_dev_ctx->link_ctx;
struct wlan_mlo_link_switch_req *req = &link_ctx->last_req;
vdev_id = wlan_vdev_get_id(vdev);
old_link_id = req->curr_ieee_link_id;
new_link_id = req->new_ieee_link_id;
mlo_debug("VDEV %d start link switch", vdev_id);
if (!wlan_cm_is_vdev_connected(vdev) ||
wlan_vdev_get_link_id(vdev) != old_link_id) {
mlo_err("Link switch req link id mismatch, curr link id %d",
wlan_vdev_get_link_id(vdev));
return QDF_STATUS_E_INVAL;
}
wlan_vdev_mlme_set_mlo_link_switch_in_progress(vdev);
if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) {
wlan_vdev_mlme_set_mlo_link_vdev(vdev);
req->restore_vdev_flag = true;
}
mlo_mgr_remove_link_switch_cmd(vdev);
return QDF_STATUS_SUCCESS;
}
static QDF_STATUS
mlo_mgr_ser_link_switch_cb(struct wlan_serialization_command *cmd,
enum wlan_serialization_cb_reason reason)
{
struct wlan_objmgr_vdev *vdev;
QDF_STATUS status = QDF_STATUS_SUCCESS;
if (!cmd) {
mlo_err("cmd is NULL, reason: %d", reason);
QDF_ASSERT(0);
return QDF_STATUS_E_NULL_VALUE;
}
vdev = cmd->vdev;
switch (reason) {
case WLAN_SER_CB_ACTIVATE_CMD:
status = mlo_mgr_start_link_switch(vdev, cmd);
break;
case WLAN_SER_CB_RELEASE_MEM_CMD:
mlo_mgr_link_switch_complete(vdev);
break;
case WLAN_SER_CB_CANCEL_CMD:
mlo_err("Link switch cmd cancelled");
break;
case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
mlo_err("Link switch active cmd timeout");
break;
default:
QDF_ASSERT(0);
mlo_mgr_link_switch_complete(vdev);
break;
}
return status;
}
void mlo_mgr_remove_link_switch_cmd(struct wlan_objmgr_vdev *vdev)
{
struct wlan_serialization_queued_cmd_info cmd_info;
enum mlo_link_switch_req_state cur_state;
uint8_t vdev_id = wlan_vdev_get_id(vdev);
struct wlan_mlo_link_switch_req *req;
req = &vdev->mlo_dev_ctx->link_ctx->last_req;
if (req->restore_vdev_flag) {
wlan_vdev_mlme_clear_mlo_link_vdev(vdev);
req->restore_vdev_flag = false;
}
cur_state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx);
if (cur_state == MLO_LINK_SWITCH_STATE_IDLE)
return;
cmd_info.cmd_id = (vdev_id << 16) + (req->new_ieee_link_id << 8) +
(req->curr_ieee_link_id);
cmd_info.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD;
cmd_info.cmd_type = WLAN_SER_CMD_MLO_VDEV_LINK_SWITCH;
cmd_info.vdev = vdev;
cmd_info.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE;
wlan_serialization_remove_cmd(&cmd_info);
}
#define MLO_MGR_MAX_LSWITCH_TIMEOUT 35000
QDF_STATUS mlo_mgr_ser_link_switch_cmd(struct wlan_objmgr_vdev *vdev,
struct wlan_mlo_link_switch_req *req)
{
enum wlan_serialization_status ser_cmd_status;
struct wlan_serialization_command cmd = {0};
uint8_t vdev_id = wlan_vdev_get_id(vdev);
struct mlo_link_switch_context *link_ctx;
if (!vdev->mlo_dev_ctx) {
mlo_err("ML dev ctx NULL, reject link switch");
return QDF_STATUS_E_INVAL;
}
link_ctx = vdev->mlo_dev_ctx->link_ctx;
link_ctx->last_req = *req;
cmd.cmd_type = WLAN_SER_CMD_MLO_VDEV_LINK_SWITCH;
cmd.cmd_id = (vdev_id << 16) + (req->new_ieee_link_id << 8) +
(req->curr_ieee_link_id);
cmd.cmd_cb = mlo_mgr_ser_link_switch_cb;
cmd.source = WLAN_UMAC_COMP_MLO_MGR;
cmd.is_high_priority = false;
cmd.cmd_timeout_duration = MLO_MGR_MAX_LSWITCH_TIMEOUT;
cmd.vdev = vdev;
cmd.is_blocking = true;
ser_cmd_status = wlan_serialization_request(&cmd);
switch (ser_cmd_status) {
case WLAN_SER_CMD_PENDING:
mlo_debug("Link switch cmd in pending queue");
break;
case WLAN_SER_CMD_ACTIVE:
mlo_debug("Link switch cmd in active queue");
break;
default:
return QDF_STATUS_E_INVAL;
}
return QDF_STATUS_SUCCESS;
}
QDF_STATUS
mlo_mgr_link_switch_validate_request(struct wlan_objmgr_vdev *vdev,
struct wlan_mlo_link_switch_req *req)
{
QDF_STATUS status = QDF_STATUS_E_INVAL;
uint8_t vdev_id = wlan_vdev_get_id(vdev);
if (req->curr_ieee_link_id >= WLAN_INVALID_LINK_ID ||
req->new_ieee_link_id >= WLAN_INVALID_LINK_ID) {
mlo_err("Invalid link params, curr link id %d, new link id %d",
req->curr_ieee_link_id, req->new_ieee_link_id);
return status;
}
if (!mlo_mgr_get_ap_link_by_link_id(vdev, req->new_ieee_link_id)) {
mlo_err("New link id %d not part of association",
req->new_ieee_link_id);
return status;
}
if (!mlo_is_mld_sta(vdev)) {
mlo_err("Link switch req not valid for VDEV %d", vdev_id);
return status;
}
if (!wlan_cm_is_vdev_connected(vdev)) {
mlo_err("VDEV %d not in connected state", vdev_id);
return status;
}
if (mlo_mgr_is_link_switch_in_progress(vdev)) {
mlo_err("Link switch already in progress");
return status;
}
if (wlan_vdev_get_link_id(vdev) != req->curr_ieee_link_id) {
mlo_err("VDEV %d link id wrong, curr link id %d",
vdev_id, wlan_vdev_get_link_id(vdev));
return status;
}
return QDF_STATUS_SUCCESS;
}
QDF_STATUS mlo_mgr_link_switch_request_params(struct wlan_objmgr_psoc *psoc,
void *evt_params)
{
QDF_STATUS status;
struct wlan_mlo_link_switch_req *req;
struct wlan_objmgr_vdev *vdev;
if (!evt_params) {
mlo_err("Invalid params");
return QDF_STATUS_E_INVAL;
}
req = (struct wlan_mlo_link_switch_req *)evt_params;
/* The reference is released on Link Switch status confirm to FW */
vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, req->vdev_id,
WLAN_MLO_MGR_ID);
if (!vdev) {
mlo_err("Invalid VDEV for link switch");
return QDF_STATUS_E_INVAL;
}
status = mlo_mgr_link_switch_validate_request(vdev, req);
if (QDF_IS_STATUS_ERROR(status)) {
wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
mlo_debug("Link switch params/request invalid");
return QDF_STATUS_E_INVAL;
}
mlo_debug("VDEV %d, curr_link_id %d, new_link_id %d, new_freq %d, new_phymode: %d, reason %d",
req->vdev_id, req->curr_ieee_link_id, req->new_ieee_link_id,
req->new_primary_freq, req->new_phymode, req->reason);
status = mlo_mgr_ser_link_switch_cmd(vdev, req);
if (QDF_IS_STATUS_ERROR(status)) {
/* Release ref as link switch is not serialized */
wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
mlo_err("Failed to serialize link switch command");
}
return status;
}
QDF_STATUS mlo_mgr_link_switch_complete(struct wlan_objmgr_vdev *vdev)
{
QDF_STATUS status;
enum mlo_link_switch_req_state state;
struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops;
struct wlan_mlo_link_switch_cnf params = {0};
struct mlo_link_switch_context *link_ctx;
struct wlan_mlo_link_switch_req *req;
struct wlan_objmgr_psoc *psoc;
/* Not checking NULL value as reference is already taken for vdev */
psoc = wlan_vdev_get_psoc(vdev);
link_ctx = vdev->mlo_dev_ctx->link_ctx;
req = &link_ctx->last_req;
mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops;
if (!mlo_tx_ops || !mlo_tx_ops->send_mlo_link_switch_cnf_cmd) {
mlo_err("handler is not registered");
status = QDF_STATUS_E_NULL_VALUE;
goto release_ref;
}
state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx);
if (state != MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS)
params.status = MLO_LINK_SWITCH_CNF_STATUS_REJECT;
else
params.status = MLO_LINK_SWITCH_CNF_STATUS_ACCEPT;
params.vdev_id = wlan_vdev_get_id(vdev);
params.reason = MLO_LINK_SWITCH_CNF_REASON_BSS_PARAMS_CHANGED;
status = mlo_tx_ops->send_mlo_link_switch_cnf_cmd(psoc, &params);
mlo_debug("VDEV %d link switch completed", params.vdev_id);
release_ref:
mlo_mgr_link_switch_init_state(vdev->mlo_dev_ctx);
wlan_vdev_mlme_clear_mlo_link_switch_in_progress(vdev);
wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
return status;
}
#endif