diff --git a/target_if/mlo_mgr/src/target_if_mlo_mgr.c b/target_if/mlo_mgr/src/target_if_mlo_mgr.c index 0331bfc374..38cfe83070 100644 --- a/target_if/mlo_mgr/src/target_if_mlo_mgr.c +++ b/target_if/mlo_mgr/src/target_if_mlo_mgr.c @@ -191,6 +191,139 @@ target_if_extract_mlo_link_removal_info_mgmt_rx( return QDF_STATUS_SUCCESS; } +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE +static QDF_STATUS +target_if_send_mlo_link_switch_cnf_cmd(struct wlan_objmgr_psoc *psoc, + struct wlan_mlo_link_switch_cnf *params) +{ + struct wmi_unified *wmi_handle = NULL; + + if (!psoc) { + target_if_err("null pdev"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!params) { + target_if_err("params is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("null wmi handle"); + return QDF_STATUS_E_NULL_VALUE; + } + + return wmi_send_mlo_link_switch_req_cnf_cmd(wmi_handle, params); +} + +static int +target_if_mlo_link_switch_request_event_handler(ol_scn_t scn, uint8_t *data, + uint32_t datalen) +{ + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct wlan_lmac_if_mlo_rx_ops *mlo_rx_ops; + QDF_STATUS status; + struct wlan_mlo_link_switch_req req = {0}; + + if (!scn || !data) { + target_if_err("scn: 0x%pK, data: 0x%pK", scn, data); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("null psoc"); + return -EINVAL; + } + + mlo_rx_ops = target_if_mlo_get_rx_ops(psoc); + if (!mlo_rx_ops || !mlo_rx_ops->mlo_link_switch_request_handler) { + target_if_err("callback not registered"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + status = wmi_extract_mlo_link_switch_request_evt(wmi_handle, data, + &req); + + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Unable to extract fixed param, ret = %d", + status); + goto exit; + } + + status = mlo_rx_ops->mlo_link_switch_request_handler(psoc, &req); + +exit: + return status; +} + +static inline void +target_if_mlo_register_link_switch_cnf_handler(struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops) +{ + mlo_tx_ops->send_mlo_link_switch_cnf_cmd = + target_if_send_mlo_link_switch_cnf_cmd; +} + +static QDF_STATUS +target_if_mlo_register_link_switch_event_handler(struct wmi_unified *wmi_handle) +{ + QDF_STATUS status; + + status = wmi_unified_register_event_handler( + wmi_handle, + wmi_mlo_link_switch_request_eventid, + target_if_mlo_link_switch_request_event_handler, + WMI_RX_SERIALIZER_CTX); + + return status; +} + +static inline void +target_if_mlo_unregister_link_switch_event_handler(struct wmi_unified *wmi_handle) +{ + wmi_unified_unregister_event(wmi_handle, + wmi_mlo_link_switch_request_eventid); +} +#else +static inline QDF_STATUS +target_if_mlo_register_link_switch_event_handler(struct wmi_unified *wmi_handle) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline void +target_if_mlo_unregister_link_switch_event_handler(struct wmi_unified *wmi_handle) +{ +} + +static inline QDF_STATUS +target_if_send_mlo_link_switch_cnf_cmd(struct wlan_objmgr_psoc *psoc, + struct wlan_mlo_link_switch_cnf *params) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +target_if_mlo_register_link_switch_cnf_handler(struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops) +{ +} + +static inline int +target_if_mlo_link_switch_request_event_handler(ol_scn_t scn, uint8_t *data, + uint32_t datalen) +{ + return 0; +} +#endif + /** * target_if_mlo_link_disable_request_event_handler() - Handler for MLO * link disable request event sent by the FW @@ -287,7 +420,7 @@ target_if_mlo_register_event_handler(struct wlan_objmgr_psoc *psoc) if (QDF_IS_STATUS_ERROR(status)) { target_if_err("Register mlo link set active resp cb errcode %d", status); - if (status == QDF_STATUS_E_NOSUPPORT) + if (status == QDF_STATUS_E_NOSUPPORT) status = QDF_STATUS_SUCCESS; } @@ -301,7 +434,15 @@ target_if_mlo_register_event_handler(struct wlan_objmgr_psoc *psoc) if (QDF_IS_STATUS_ERROR(status)) { target_if_err("Couldn't register handler for link disable request WMI event %d", status); - if (status == QDF_STATUS_E_NOSUPPORT) + if (status == QDF_STATUS_E_NOSUPPORT) + status = QDF_STATUS_SUCCESS; + } + + status = target_if_mlo_register_link_switch_event_handler(wmi_handle); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Couldn't register handler for link switch WMI event %d", + status); + if (status == QDF_STATUS_E_NOSUPPORT) status = QDF_STATUS_SUCCESS; } @@ -343,6 +484,8 @@ target_if_mlo_unregister_event_handler(struct wlan_objmgr_psoc *psoc) wmi_unified_unregister_event(wmi_handle, wmi_mlo_link_disable_request_eventid); + target_if_mlo_unregister_link_switch_event_handler(wmi_handle); + return QDF_STATUS_SUCCESS; } @@ -734,6 +877,8 @@ target_if_mlo_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) target_if_request_ml_link_state_info; mlo_tx_ops->send_vdev_pause = target_if_mlo_send_vdev_pause; + target_if_mlo_register_link_switch_cnf_handler(mlo_tx_ops); + target_if_mlo_register_peer_ptqm_migrate_send(mlo_tx_ops); return QDF_STATUS_SUCCESS; } diff --git a/umac/cmn_services/obj_mgr/inc/wlan_objmgr_vdev_obj.h b/umac/cmn_services/obj_mgr/inc/wlan_objmgr_vdev_obj.h index 6325bdf2bf..288efac36c 100644 --- a/umac/cmn_services/obj_mgr/inc/wlan_objmgr_vdev_obj.h +++ b/umac/cmn_services/obj_mgr/inc/wlan_objmgr_vdev_obj.h @@ -238,6 +238,8 @@ /* MLO link removal is in progress on this VDEV */ #define WLAN_VDEV_OP_MLO_LINK_REMOVAL_IN_PROGRESS 0x01000000 +/* MLO link switch is in progress on this VDEV */ +#define WLAN_VDEV_OP_MLO_LINK_SWITCH_IN_PROGRESS 0x02000000 /* flag to indicate disconnect only legacy peers due to moving to DFS channel * from non-DFS channel @@ -1760,6 +1762,70 @@ void wlan_vdev_mlme_set_mlo_link_vdev(struct wlan_objmgr_vdev *vdev); * Return: void */ void wlan_vdev_mlme_clear_mlo_link_vdev(struct wlan_objmgr_vdev *vdev); + +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE +/** + * wlan_vdev_mlme_set_mlo_link_switch_in_progress() - Set link switch in + * progress flag for VDEV. + * @vdev: VDEV object manager. + * + * Return: void + */ +static inline void +wlan_vdev_mlme_set_mlo_link_switch_in_progress(struct wlan_objmgr_vdev *vdev) +{ + unsigned long flag = WLAN_VDEV_OP_MLO_LINK_SWITCH_IN_PROGRESS; + + wlan_vdev_mlme_op_flags_set(vdev, flag); +} + +/** + * wlan_vdev_mlme_clear_mlo_link_switch_in_progress() - Clear link switch in + * progress flag for VDEV. + * @vdev: VDEV object manager + * + * Return: void + */ +static inline void +wlan_vdev_mlme_clear_mlo_link_switch_in_progress(struct wlan_objmgr_vdev *vdev) +{ + unsigned long flag = WLAN_VDEV_OP_MLO_LINK_SWITCH_IN_PROGRESS; + + wlan_vdev_mlme_op_flags_clear(vdev, flag); +} + +/** + * wlan_vdev_mlme_is_mlo_link_switch_in_progress() - Return true if VDEV is + * in link transitioning state. + * @vdev: VDEV object manager. + * + * Return: bool + */ +static inline bool +wlan_vdev_mlme_is_mlo_link_switch_in_progress(struct wlan_objmgr_vdev *vdev) +{ + unsigned long flag = WLAN_VDEV_OP_MLO_LINK_SWITCH_IN_PROGRESS; + + return wlan_vdev_mlme_op_flags_get(vdev, flag); +} +#else +static inline void +wlan_vdev_mlme_set_mlo_link_switch_in_progress(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline void +wlan_vdev_mlme_clear_mlo_link_switch_in_progress(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline bool +wlan_vdev_mlme_is_mlo_link_switch_in_progress(struct wlan_objmgr_vdev *vdev) +{ + return false; +} +#endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ + #ifdef WLAN_MCAST_MLO /** * wlan_vdev_mlme_is_mlo_mcast_vdev() - whether it is mlo mcast vdev or not @@ -1875,6 +1941,22 @@ void wlan_vdev_mlme_clear_mlo_link_vdev(struct wlan_objmgr_vdev *vdev) { } +static inline void +wlan_vdev_mlme_set_mlo_link_switch_in_progress(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline void +wlan_vdev_mlme_clear_mlo_link_switch_in_progress(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline bool +wlan_vdev_mlme_is_mlo_link_switch_in_progress(struct wlan_objmgr_vdev *vdev) +{ + return false; +} + static inline bool wlan_vdev_mlme_is_mlo_link_vdev(struct wlan_objmgr_vdev *vdev) { diff --git a/umac/cmn_services/serialization/inc/wlan_serialization_api.h b/umac/cmn_services/serialization/inc/wlan_serialization_api.h index 01e4f71c61..665b1d38a6 100644 --- a/umac/cmn_services/serialization/inc/wlan_serialization_api.h +++ b/umac/cmn_services/serialization/inc/wlan_serialization_api.h @@ -199,6 +199,7 @@ typedef QDF_STATUS (*wlan_ser_umac_cmd_cb)(void *umac_cmd); * @WLAN_SER_CMD_PDEV_CSA_RESTART: Cmd to CSA restart all AP VDEVs of a PDEV * @WLAN_SER_CMD_VDEV_ROAM: Cmd to roam a STA VDEV * @WLAN_SER_CMD_SET_MLO_LINK: Cmd to force mlo link active/inactive + * @WLAN_SER_CMD_MLO_VDEV_LINK_SWITCH: Cmd to serialize link switch operation * @WLAN_SER_CMD_MAX: Max enumeration */ enum wlan_serialization_cmd_type { @@ -233,6 +234,7 @@ enum wlan_serialization_cmd_type { WLAN_SER_CMD_PDEV_CSA_RESTART, WLAN_SER_CMD_VDEV_ROAM, WLAN_SER_CMD_SET_MLO_LINK, + WLAN_SER_CMD_MLO_VDEV_LINK_SWITCH, WLAN_SER_CMD_MAX }; diff --git a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h index 0951683bc6..ccc65a7e0a 100644 --- a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h +++ b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h @@ -59,6 +59,10 @@ #include #endif +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE +#include +#endif + /* Number of dev type: Direct attach and Offload */ #define MAX_DEV_TYPE 2 @@ -1526,6 +1530,7 @@ struct wlan_lmac_if_son_rx_ops { * @send_link_removal_cmd: function to send MLO link removal command to FW * @send_vdev_pause: function to send MLO vdev pause to FW * @peer_ptqm_migrate_send: API to send peer ptqm migration request to FW + * @send_mlo_link_switch_cnf_cmd: Send link switch status to FW */ struct wlan_lmac_if_mlo_tx_ops { QDF_STATUS (*register_events)(struct wlan_objmgr_psoc *psoc); @@ -1551,6 +1556,11 @@ struct wlan_lmac_if_mlo_tx_ops { struct wlan_objmgr_vdev *vdev, struct peer_ptqm_migrate_params *param); #endif /* QCA_SUPPORT_PRIMARY_LINK_MIGRATE */ +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE + QDF_STATUS + (*send_mlo_link_switch_cnf_cmd)(struct wlan_objmgr_psoc *psoc, + struct wlan_mlo_link_switch_cnf *params); +#endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ }; /** @@ -1560,6 +1570,8 @@ struct wlan_lmac_if_mlo_tx_ops { * @mlo_link_removal_handler: function pointer for MLO link removal handler * @process_mlo_link_state_info_event: function pointer for mlo link state * @mlo_link_disable_request_handler: function ptr for mlo link disable request + * @mlo_link_switch_request_handler: Handler function pointer to deliver link + * switch request params from FW to host. */ struct wlan_lmac_if_mlo_rx_ops { QDF_STATUS @@ -1577,6 +1589,11 @@ struct wlan_lmac_if_mlo_rx_ops { QDF_STATUS (*mlo_link_disable_request_handler)( struct wlan_objmgr_psoc *psoc, void *evt_params); +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE + QDF_STATUS + (*mlo_link_switch_request_handler)(struct wlan_objmgr_psoc *psoc, + void *evt_params); +#endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ }; #endif diff --git a/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c b/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c index 4eb9e2effa..e19a92520a 100644 --- a/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c +++ b/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c @@ -975,6 +975,20 @@ wlan_lmac_if_umac_ftm_rx_ops_register(struct wlan_lmac_if_rx_ops *rx_ops) #endif #ifdef WLAN_FEATURE_11BE_MLO +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE +static inline void +wlan_lmac_if_mlo_rx_link_switch_ops_register(struct wlan_lmac_if_rx_ops *rx_ops) +{ + rx_ops->mlo_rx_ops.mlo_link_switch_request_handler = + mlo_mgr_link_switch_request_params; +} +#else +static inline void +wlan_lmac_if_mlo_rx_link_switch_ops_register(struct wlan_lmac_if_rx_ops *rx_ops) +{ +} +#endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ + /** * wlan_lmac_if_mlo_mgr_rx_ops_register() - API to register mlo mgr Rx Ops * @rx_ops: pointer to lmac rx ops @@ -995,6 +1009,8 @@ wlan_lmac_if_mlo_mgr_rx_ops_register(struct wlan_lmac_if_rx_ops *rx_ops) wlan_handle_ml_link_state_info_event; rx_ops->mlo_rx_ops.mlo_link_disable_request_handler = wlan_mlo_link_disable_request_handler; + + wlan_lmac_if_mlo_rx_link_switch_ops_register(rx_ops); } #else static void diff --git a/umac/mlo_mgr/inc/wlan_mlo_mgr_link_switch.h b/umac/mlo_mgr/inc/wlan_mlo_mgr_link_switch.h index 044b2cb0f7..d8b2621e2a 100644 --- a/umac/mlo_mgr/inc/wlan_mlo_mgr_link_switch.h +++ b/umac/mlo_mgr/inc/wlan_mlo_mgr_link_switch.h @@ -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 diff --git a/umac/mlo_mgr/src/wlan_mlo_mgr_link_switch.c b/umac/mlo_mgr/src/wlan_mlo_mgr_link_switch.c index d25e91ab58..6551d6733f 100644 --- a/umac/mlo_mgr/src/wlan_mlo_mgr_link_switch.c +++ b/umac/mlo_mgr/src/wlan_mlo_mgr_link_switch.c @@ -18,8 +18,10 @@ * DOC: contains MLO manager Link Switch related functionality */ #include -#include -#include +#include +#include +#include +#include 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 diff --git a/wmi/inc/wmi_unified_11be_api.h b/wmi/inc/wmi_unified_11be_api.h index f969855787..3f75ab25d6 100644 --- a/wmi/inc/wmi_unified_11be_api.h +++ b/wmi/inc/wmi_unified_11be_api.h @@ -204,6 +204,47 @@ QDF_STATUS wmi_extract_mlo_link_state_info_event( void *evt_buf, struct ml_link_state_info_event *params); +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE +/** + * wmi_send_mlo_link_switch_req_cnf_cmd() - Send WMI command to FW on + * status of Link switch request received. + * @wmi: wmi handle + * @params: Params to send to FW. + * + * Return: QDF_STATUS. + */ +QDF_STATUS +wmi_send_mlo_link_switch_req_cnf_cmd(wmi_unified_t wmi, + struct wlan_mlo_link_switch_cnf *params); + +/** + * wmi_extract_mlo_link_switch_request_evt() - Extract fixed params TLV + * from the MLO link switch request WMI event. + * @wmi: wmi handle + * @buf: pointer to event buffer + * @req: MLO link switch request event params. + * + * Return: QDF_STATUS + */ +QDF_STATUS +wmi_extract_mlo_link_switch_request_evt(struct wmi_unified *wmi, void *buf, + struct wlan_mlo_link_switch_req *req); +#else +static inline QDF_STATUS +wmi_send_mlo_link_switch_req_cnf_cmd(wmi_unified_t wmi, + struct wlan_mlo_link_switch_cnf *params) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wmi_extract_mlo_link_switch_request_evt(struct wmi_unified *wmi, void *buf, + struct wlan_mlo_link_switch_req *req) +{ + return QDF_STATUS_SUCCESS; +} +#endif + /** * wmi_extract_mlo_link_disable_request_evt() - Extract fixed parameters TLV * from the MLO link disable request WMI event diff --git a/wmi/inc/wmi_unified_param.h b/wmi/inc/wmi_unified_param.h index d515a097e9..a537dfc79a 100644 --- a/wmi/inc/wmi_unified_param.h +++ b/wmi/inc/wmi_unified_param.h @@ -1224,6 +1224,8 @@ struct wmi_host_link_state_params { * @nstr_bitmap_size: Indicates size of NSTR bitmap, * as per the 802.11be specification * @mlo_bridge_peer: indicate if it is bridge peer + * @link_switch_in_progress: Flag to indicate FW MLO peer assoc params are sent + * for the peer due to link switch * @unused: spare bits * @mld_mac: MLD mac address * @logical_link_index: Unique index for links of the mlo. Starts with Zero @@ -1257,7 +1259,8 @@ struct peer_assoc_mlo_params { nstr_bitmap_present:1, nstr_bitmap_size:1, mlo_bridge_peer:1, - unused:20; + link_switch_in_progress:1, + unused:19; uint8_t mld_mac[QDF_MAC_ADDR_SIZE]; uint32_t logical_link_index; uint32_t ml_peer_id; @@ -5282,6 +5285,9 @@ typedef enum { wmi_mlo_link_set_active_resp_eventid, wmi_mlo_link_removal_eventid, wmi_mlo_link_disable_request_eventid, +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE + wmi_mlo_link_switch_request_eventid, +#endif #endif wmi_pdev_fips_extend_event_id, wmi_roam_frame_event_id, diff --git a/wmi/inc/wmi_unified_priv.h b/wmi/inc/wmi_unified_priv.h index cfa7a95b05..570bb059da 100644 --- a/wmi/inc/wmi_unified_priv.h +++ b/wmi/inc/wmi_unified_priv.h @@ -97,6 +97,7 @@ #ifdef WLAN_FEATURE_11BE_MLO #include #include "wlan_mlo_mgr_public_structs.h" +#include #endif #if defined(WLAN_SUPPORT_TWT) && defined(WLAN_TWT_CONV_SUPPORTED) @@ -3146,6 +3147,16 @@ QDF_STATUS (*extract_mlo_link_disable_request_evt_param)( struct wmi_unified *wmi_handle, void *buf, struct mlo_link_disable_request_evt_params *params); + +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE +QDF_STATUS +(*extract_mlo_link_switch_request_event)(struct wmi_unified *wmi_handle, + void *buf, + struct wlan_mlo_link_switch_req *req); +QDF_STATUS +(*send_mlo_link_switch_req_cnf_cmd)(wmi_unified_t wmi_handle, + struct wlan_mlo_link_switch_cnf *params); +#endif #endif #ifdef WLAN_FEATURE_SON diff --git a/wmi/src/wmi_unified_11be_api.c b/wmi/src/wmi_unified_11be_api.c index 7872f63573..2dcf32c267 100644 --- a/wmi/src/wmi_unified_11be_api.c +++ b/wmi/src/wmi_unified_11be_api.c @@ -81,6 +81,31 @@ QDF_STATUS wmi_send_mlo_vdev_tid_to_link_map_cmd( return QDF_STATUS_E_FAILURE; } +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE +QDF_STATUS +wmi_send_mlo_link_switch_req_cnf_cmd(wmi_unified_t wmi, + struct wlan_mlo_link_switch_cnf *params) +{ + if (wmi->ops->send_mlo_link_switch_req_cnf_cmd) + return wmi->ops->send_mlo_link_switch_req_cnf_cmd(wmi, params); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_extract_mlo_link_switch_request_evt(struct wmi_unified *wmi, + void *buf, + struct wlan_mlo_link_switch_req *req) +{ + if (wmi->ops->extract_mlo_link_switch_request_event) + return wmi->ops->extract_mlo_link_switch_request_event(wmi, + buf, + req); + + return QDF_STATUS_E_FAILURE; +} +#endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ + QDF_STATUS wmi_send_mlo_link_state_request_cmd( wmi_unified_t wmi, struct wmi_host_link_state_params *params) @@ -140,7 +165,6 @@ QDF_STATUS wmi_extract_mlo_link_disable_request_evt( return QDF_STATUS_E_FAILURE; } - #endif /* WLAN_FEATURE_11BE */ QDF_STATUS diff --git a/wmi/src/wmi_unified_11be_tlv.c b/wmi/src/wmi_unified_11be_tlv.c index 9728fc6620..6f5b0302e8 100644 --- a/wmi/src/wmi_unified_11be_tlv.c +++ b/wmi/src/wmi_unified_11be_tlv.c @@ -1413,6 +1413,89 @@ static uint8_t *populate_link_control_tlv( } #endif +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE +/** + * extract_mlo_link_switch_request_event_tlv() - Extract fixed + * params TLV from MLO link switch request WMI event. + * @wmi_handle: wmi handle + * @buf: Pointer to event buffer. + * @req: MLO Link switch event parameters. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +extract_mlo_link_switch_request_event_tlv(struct wmi_unified *wmi_handle, + void *buf, + struct wlan_mlo_link_switch_req *req) +{ + WMI_MLO_LINK_SWITCH_REQUEST_EVENTID_param_tlvs *param_buf = buf; + wmi_mlo_link_switch_req_evt_fixed_param *ev; + + if (!param_buf) { + wmi_err_rl("buf is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!req) { + wmi_err_rl("req is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + ev = param_buf->fixed_param; + req->vdev_id = ev->vdev_id; + req->curr_ieee_link_id = ev->curr_ieee_link_id; + req->new_ieee_link_id = ev->new_ieee_link_id; + req->new_primary_freq = ev->new_primary_freq; + req->new_phymode = ev->new_phymode; + req->reason = ev->reason; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +send_link_switch_request_cnf_cmd_tlv(wmi_unified_t wmi_handle, + struct wlan_mlo_link_switch_cnf *params) +{ + wmi_mlo_link_switch_cnf_fixed_param *cmd; + wmi_buf_t buf; + uint8_t *buf_ptr; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + uint32_t buf_len; + + buf_len = sizeof(wmi_mlo_link_switch_cnf_fixed_param); + + buf = wmi_buf_alloc(wmi_handle, buf_len); + if (!buf) { + wmi_err("wmi buf alloc failed for vdev id %d while link state cmd send: ", + params->vdev_id); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + cmd = (wmi_mlo_link_switch_cnf_fixed_param *)buf_ptr; + + WMITLV_SET_HDR( + &cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_mlo_link_switch_cnf_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_mlo_link_switch_cnf_fixed_param)); + + cmd->vdev_id = params->vdev_id; + cmd->status = params->status; + cmd->reason = params->reason; + buf_ptr += sizeof(wmi_mlo_link_switch_cnf_fixed_param); + wmi_mtrace(WMI_MLO_LINK_SWITCH_CONF_CMDID, cmd->vdev_id, 0); + ret = wmi_unified_cmd_send(wmi_handle, buf, buf_len, + WMI_MLO_LINK_SWITCH_CONF_CMDID); + if (ret) { + wmi_err("Failed to send ml link switch cnf command to FW: %d vdev id %d", + ret, cmd->vdev_id); + wmi_buf_free(buf); + } + return ret; +} +#endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ + static QDF_STATUS send_link_state_request_cmd_tlv(wmi_unified_t wmi_handle, struct wmi_host_link_state_params *params) @@ -2365,4 +2448,10 @@ void wmi_11be_attach_tlv(wmi_unified_t wmi_handle) ops->extract_peer_ptqm_migrate_event = extract_peer_ptqm_migrate_evt_param_tlv; ops->extract_peer_entry_ptqm_migrate_event = extract_peer_entry_ptqm_migrate_evt_param_tlv; #endif /* QCA_SUPPORT_PRIMARY_LINK_MIGRATE */ +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE + ops->extract_mlo_link_switch_request_event = + extract_mlo_link_switch_request_event_tlv; + ops->send_mlo_link_switch_req_cnf_cmd = + send_link_switch_request_cnf_cmd_tlv; +#endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ } diff --git a/wmi/src/wmi_unified_tlv.c b/wmi/src/wmi_unified_tlv.c index 8f39f7eb75..b9fe2e87ad 100644 --- a/wmi/src/wmi_unified_tlv.c +++ b/wmi/src/wmi_unified_tlv.c @@ -21452,6 +21452,10 @@ static void populate_tlv_events_id_mlo(WMI_EVT_ID *event_ids) WMI_MLO_VDEV_LINK_INFO_EVENTID; event_ids[wmi_mlo_link_disable_request_eventid] = WMI_MLO_LINK_DISABLE_REQUEST_EVENTID; +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE + event_ids[wmi_mlo_link_switch_request_eventid] = + WMI_MLO_LINK_SWITCH_REQUEST_EVENTID; +#endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ } #else /* WLAN_FEATURE_11BE_MLO */ static inline void populate_tlv_events_id_mlo(WMI_EVT_ID *event_ids)