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:

revīziju iesūtīja
Rahul Choudhary

vecāks
10448e6108
revīzija
af6cf93a07
@@ -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
|
||||
|
@@ -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, ¶ms);
|
||||
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
|
||||
|
Atsaukties uz šo jaunā problēmā
Block a user