diff --git a/components/dp/core/inc/wlan_dp_main.h b/components/dp/core/inc/wlan_dp_main.h index caaef788ce..3c4c1eb966 100644 --- a/components/dp/core/inc/wlan_dp_main.h +++ b/components/dp/core/inc/wlan_dp_main.h @@ -328,6 +328,19 @@ QDF_STATUS wlan_dp_txrx_pdev_attach(ol_txrx_soc_handle soc); QDF_STATUS wlan_dp_txrx_pdev_detach(ol_txrx_soc_handle soc, uint8_t pdev_id, int force); +#ifdef WLAN_FEATURE_11BE_MLO +/** + * dp_link_switch_notification() - DP notifier for MLO link switch + * @vdev: Objmgr vdev handle + * @lswitch_req: Link switch request params + * + * Return: QDF_STATUS + */ +QDF_STATUS +dp_link_switch_notification(struct wlan_objmgr_vdev *vdev, + struct wlan_mlo_link_switch_req *lswitch_req); +#endif + /** * dp_peer_obj_create_notification(): dp peer create handler * @peer: peer which is going to created by objmgr diff --git a/components/dp/core/src/wlan_dp_main.c b/components/dp/core/src/wlan_dp_main.c index 4ad99564cc..102f9e3b25 100644 --- a/components/dp/core/src/wlan_dp_main.c +++ b/components/dp/core/src/wlan_dp_main.c @@ -44,6 +44,7 @@ #ifdef FEATURE_DIRECT_LINK #include "dp_internal.h" #endif +#include #ifdef WLAN_DP_PROFILE_SUPPORT /* Memory profile table based on supported caps */ @@ -953,6 +954,127 @@ dp_intf_get_next_deflink_candidate(struct wlan_dp_intf *dp_intf, return NULL; } + +/** + * dp_change_def_link() - Change default link for the dp_intf + * @dp_intf: DP interface for which default link is to be changed + * @dp_link: link on which link switch notification arrived. + * @lswitch_req: Link switch request params + * + * This API is called only when dp_intf->def_link == dp_link, + * and there is a need to change the def_link of the dp_intf, + * due to any reason. + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +dp_change_def_link(struct wlan_dp_intf *dp_intf, + struct wlan_dp_link *dp_link, + struct wlan_mlo_link_switch_req *lswitch_req) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + struct wlan_dp_link *next_def_link; + cdp_config_param_type peer_param = {0}; + QDF_STATUS status; + + next_def_link = dp_intf_get_next_deflink_candidate(dp_intf, dp_link); + if (!is_dp_link_valid(next_def_link)) { + /* Unable to get candidate for next def_link */ + dp_info("Unable to get next def link %pK", next_def_link); + return QDF_STATUS_E_FAILURE; + } + + /* + * Switch dp_vdev related params + * - Change vdev of MLD peer. + */ + dp_info("Peer " QDF_MAC_ADDR_FMT ", change vdev %d -> %d", + QDF_MAC_ADDR_REF(lswitch_req->peer_mld_addr.bytes), + dp_link->link_id, next_def_link->link_id); + peer_param.new_vdev_id = next_def_link->link_id; + status = cdp_txrx_set_peer_param(dp_ctx->cdp_soc, + /* Current vdev for remote MLD peer */ + dp_link->link_id, + lswitch_req->peer_mld_addr.bytes, + CDP_CONFIG_MLD_PEER_VDEV, + peer_param); + + /* + * DP link switch checks and process is completed successfully. + * Change the def_link to the partner link + */ + if (QDF_IS_STATUS_SUCCESS(status)) + dp_intf->def_link = next_def_link; + + return status; +} + +QDF_STATUS +dp_link_switch_notification(struct wlan_objmgr_vdev *vdev, + struct wlan_mlo_link_switch_req *lswitch_req) +{ + /* Add prints to string and print it at last, so we have only 1 print */ + struct wlan_dp_psoc_context *dp_ctx; + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + dp_ctx = dp_get_context(); + + dp_link = dp_get_vdev_priv_obj(vdev); + if (!is_dp_link_valid(dp_link)) { + dp_err("dp_link from vdev %pK is invalid", vdev); + return QDF_STATUS_E_INVAL; + } + + dp_intf = dp_link->dp_intf; + dp_info("Link switch req for dp_link %pK id %d (" QDF_MAC_ADDR_FMT + "), dp_intf %pK (" QDF_MAC_ADDR_FMT + ") cur_def_link %pK id %d device_mode %d num_links %d", + dp_link, dp_link->link_id, + QDF_MAC_ADDR_REF(dp_link->mac_addr.bytes), + dp_intf, QDF_MAC_ADDR_REF(dp_intf->mac_addr.bytes), + dp_intf->def_link, dp_intf->def_link->link_id, + dp_intf->device_mode, dp_intf->num_links); + + if (dp_intf->device_mode != QDF_STA_MODE) { + /* Link switch supported only for STA mode */ + status = QDF_STATUS_E_INVAL; + goto exit; + } + + if (dp_intf->num_links == 1) { + /* There is only one link, so we cannot switch */ + status = QDF_STATUS_E_CANCELED; + goto exit; + } + + if (dp_link != dp_intf->def_link) { + /* default link is not being switched, so DP is fine */ + goto exit; + } + + /* Recipe to be done before switching a default link */ + status = dp_change_def_link(dp_intf, dp_link, lswitch_req); + if (QDF_IS_STATUS_ERROR(status)) { + /* Failed to switch default link */ + dp_info("Failed to change def_link for dp_intf %pK", dp_intf); + goto exit; + } + +exit: + dp_info("Link switch req %s (ret %d) for dp_link %pK id %d (" + QDF_MAC_ADDR_FMT "), dp_intf %pK (" QDF_MAC_ADDR_FMT + ") cur_def_link %pK id %d device_mode %d num_links %d", + QDF_IS_STATUS_ERROR(status) ? "Failed" : "Successful", + status, dp_link, dp_link->link_id, + QDF_MAC_ADDR_REF(dp_link->mac_addr.bytes), + dp_intf, QDF_MAC_ADDR_REF(dp_intf->mac_addr.bytes), + dp_intf->def_link, dp_intf->def_link->link_id, + dp_intf->device_mode, dp_intf->num_links); + + return status; +} #else static struct wlan_dp_link * dp_intf_get_next_deflink_candidate(struct wlan_dp_intf *dp_intf, diff --git a/components/dp/dispatcher/src/wlan_dp_ucfg_api.c b/components/dp/dispatcher/src/wlan_dp_ucfg_api.c index 45712b2468..7196beaa8c 100644 --- a/components/dp/dispatcher/src/wlan_dp_ucfg_api.c +++ b/components/dp/dispatcher/src/wlan_dp_ucfg_api.c @@ -40,6 +40,9 @@ #include "wlan_dp_prealloc.h" #include "wlan_dp_rx_thread.h" #include +#ifdef WLAN_FEATURE_11BE_MLO +#include "wlan_mlo_mgr_public_api.h" +#endif #ifdef FEATURE_DIRECT_LINK /** @@ -82,6 +85,55 @@ QDF_STATUS wlan_dp_set_vdev_direct_link_cfg(struct wlan_objmgr_psoc *psoc, } #endif +#ifdef WLAN_FEATURE_11BE_MLO +static inline +QDF_STATUS wlan_dp_update_vdev_mac_addr(struct wlan_dp_psoc_context *dp_ctx, + struct wlan_dp_link *dp_link, + struct qdf_mac_addr *new_mac_addr) +{ + cdp_config_param_type vdev_param = {0}; + + qdf_mem_copy(&vdev_param.mac_addr, new_mac_addr, QDF_MAC_ADDR_SIZE); + + /* CDP API to change the mac address */ + return cdp_txrx_set_vdev_param(dp_ctx->cdp_soc, dp_link->link_id, + CDP_VDEV_SET_MAC_ADDR, vdev_param); +} + +static QDF_STATUS wlan_dp_register_link_switch_notifier(void) +{ + return wlan_mlo_mgr_register_link_switch_notifier( + WLAN_COMP_DP, + dp_link_switch_notification); +} + +static QDF_STATUS wlan_dp_unregister_link_switch_notifier(void) +{ + return wlan_mlo_mgr_unregister_link_switch_notifier(WLAN_COMP_DP); +} +#else +static inline +QDF_STATUS wlan_dp_update_vdev_mac_addr(struct wlan_dp_psoc_context *dp_ctx, + struct wlan_dp_link *dp_link, + struct qdf_mac_addr *new_mac_addr) +{ + /* Link switch should be done only for 802.11BE */ + qdf_assert(0); + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS wlan_dp_register_link_switch_notifier(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS wlan_dp_unregister_link_switch_notifier(void) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** Add sanity for multiple link switches in parallel */ QDF_STATUS ucfg_dp_update_link_mac_addr(struct wlan_objmgr_vdev *vdev, struct qdf_mac_addr *new_mac_addr, bool is_link_switch) @@ -100,6 +152,10 @@ QDF_STATUS ucfg_dp_update_link_mac_addr(struct wlan_objmgr_vdev *vdev, qdf_copy_macaddr(&dp_link->mac_addr, new_mac_addr); + if (is_link_switch) + status = wlan_dp_update_vdev_mac_addr(dp_ctx, dp_link, + new_mac_addr); + return status; } @@ -330,11 +386,25 @@ QDF_STATUS ucfg_dp_init(void) WLAN_COMP_DP, dp_peer_obj_destroy_notification, NULL); - if (QDF_IS_STATUS_ERROR(status)) + if (QDF_IS_STATUS_ERROR(status)) { dp_err("wlan_objmgr_register_peer_destroy_handler failed"); - else - return QDF_STATUS_SUCCESS; + goto fail_destroy_peer; + } + status = wlan_dp_register_link_switch_notifier(); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("wlan_mlomgr_register_link_switch_handler failed"); + goto fail_link_switch; + } + + return QDF_STATUS_SUCCESS; + +fail_link_switch: + wlan_objmgr_unregister_peer_destroy_handler( + WLAN_COMP_DP, dp_peer_obj_destroy_notification, + NULL); + +fail_destroy_peer: wlan_objmgr_unregister_peer_create_handler(WLAN_COMP_DP, dp_peer_obj_create_notification, NULL); @@ -378,6 +448,9 @@ QDF_STATUS ucfg_dp_deinit(void) dp_info("DP module dispatcher deinit"); + /* de-register link switch handler */ + wlan_dp_unregister_link_switch_notifier(); + /* de-register peer delete handler functions. */ status = wlan_objmgr_unregister_peer_destroy_handler( WLAN_COMP_DP,