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 8f77ad2b5c..4070bc13c1 100644 --- a/target_if/mlo_mgr/src/target_if_mlo_mgr.c +++ b/target_if/mlo_mgr/src/target_if_mlo_mgr.c @@ -650,6 +650,52 @@ QDF_STATUS target_if_mlo_send_vdev_pause(struct wlan_objmgr_psoc *psoc, return wmi_send_mlo_vdev_pause(wmi_handle, info); } +#ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE +static QDF_STATUS target_if_mlo_send_peer_ptqm_migrate_cmd( + struct wlan_objmgr_vdev *vdev, + struct peer_ptqm_migrate_params *param) +{ + struct wlan_objmgr_pdev *pdev = NULL; + struct wmi_unified *wmi_handle; + QDF_STATUS status; + + if (!vdev || !param) { + target_if_err("Invalid input"); + return QDF_STATUS_E_INVAL; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + target_if_err("null pdev"); + return QDF_STATUS_E_NULL_VALUE; + } + + wmi_handle = lmac_get_pdev_wmi_handle(pdev); + if (!wmi_handle) { + target_if_err("Failed to get WMI handle!"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_peer_ptqm_migrate_send(wmi_handle, param); + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("Failed to send peer ptqm migration WMI"); + + return status; +} + +static void target_if_mlo_register_peer_ptqm_migrate_send( + struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops) +{ + mlo_tx_ops->peer_ptqm_migrate_send = + target_if_mlo_send_peer_ptqm_migrate_cmd; +} +#else +static void target_if_mlo_register_peer_ptqm_migrate_send( + struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops) +{ +} +#endif + /** * target_if_mlo_register_tx_ops() - lmac handler to register mlo tx ops * callback functions @@ -685,6 +731,7 @@ 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_peer_ptqm_migrate_send(mlo_tx_ops); return QDF_STATUS_SUCCESS; } 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 0b9494ce8b..93458f258f 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 @@ -1512,6 +1512,7 @@ struct wlan_lmac_if_son_rx_ops { * @send_tid_to_link_mapping: function to send T2LM command to FW * @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 */ struct wlan_lmac_if_mlo_tx_ops { QDF_STATUS (*register_events)(struct wlan_objmgr_psoc *psoc); @@ -1532,6 +1533,11 @@ struct wlan_lmac_if_mlo_tx_ops { const struct mlo_link_removal_cmd_params *param); QDF_STATUS (*send_vdev_pause)(struct wlan_objmgr_psoc *psoc, struct mlo_vdev_pause *info); +#ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE + QDF_STATUS (*peer_ptqm_migrate_send)( + struct wlan_objmgr_vdev *vdev, + struct peer_ptqm_migrate_params *param); +#endif /* QCA_SUPPORT_PRIMARY_LINK_MIGRATE */ }; /** diff --git a/umac/mlo_mgr/inc/wlan_mlo_mgr_ap.h b/umac/mlo_mgr/inc/wlan_mlo_mgr_ap.h index d9a1fd4702..5b4b66a20f 100644 --- a/umac/mlo_mgr/inc/wlan_mlo_mgr_ap.h +++ b/umac/mlo_mgr/inc/wlan_mlo_mgr_ap.h @@ -579,4 +579,21 @@ QDF_STATUS mlo_peer_create_get_frm_buf( */ uint16_t wlan_mlo_ap_get_active_links(struct wlan_objmgr_vdev *vdev); +#ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE +/** + * mlo_ap_ml_ptqm_peerid_free() - API to clear ml peer id bmap set for + * ptqm migration + * @ml_dev: ML dev pointer + * @mlo_peer_id: MLO peer id + * + * Return: none + */ +void mlo_ap_ml_ptqm_peerid_free(struct wlan_mlo_dev_context *ml_dev, + uint16_t mlo_peer_id); +#else +static inline +void mlo_ap_ml_ptqm_peerid_free(struct wlan_mlo_dev_context *ml_dev, + uint16_t mlo_peer_id) +{ } +#endif /* QCA_SUPPORT_PRIMARY_LINK_MIGRATE */ #endif diff --git a/umac/mlo_mgr/inc/wlan_mlo_mgr_cmn.h b/umac/mlo_mgr/inc/wlan_mlo_mgr_cmn.h index 9d1a260e9f..6c738101f3 100644 --- a/umac/mlo_mgr/inc/wlan_mlo_mgr_cmn.h +++ b/umac/mlo_mgr/inc/wlan_mlo_mgr_cmn.h @@ -625,3 +625,28 @@ util_parse_bw_ind(struct wlan_ie_bw_ind *bw_ind, uint8_t *ccfs0, uint8_t *ccfs1, enum phy_ch_width *ch_width, uint16_t *puncture_bitmap); #endif + +#ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE +/** + * mlo_mlme_ptqm_migrate_timer_cb() - Timer callback for ptqm migration + * @arg: timer function argument + * + * Return: None + */ +void mlo_mlme_ptqm_migrate_timer_cb(void *arg); + +/* + * wlan_mlo_set_ptqm_migration() - API to trigger ptqm migration. + * @vdev: vdev object + * @ml_peer: ml peer object + * @link_migration: flag to indicate if all peers of vdev need migration + * or individual peer migration + * @link_id: link id for new ptqm + * + * Return: Success if migration is triggered, else failure + */ +QDF_STATUS wlan_mlo_set_ptqm_migration(struct wlan_objmgr_vdev *vdev, + struct wlan_mlo_peer_context *ml_peer, + bool link_migration, + uint32_t link_id); +#endif diff --git a/umac/mlo_mgr/inc/wlan_mlo_mgr_public_structs.h b/umac/mlo_mgr/inc/wlan_mlo_mgr_public_structs.h index 71767caff1..f204388f51 100644 --- a/umac/mlo_mgr/inc/wlan_mlo_mgr_public_structs.h +++ b/umac/mlo_mgr/inc/wlan_mlo_mgr_public_structs.h @@ -468,6 +468,11 @@ struct wlan_mlo_peer_list { * @ap_ctx: AP related information * @t2lm_ctx: T2LM related information * @epcs_ctx: EPCS related information + * @ptqm_migrate_timer: timer for ptqm migration + * @mlo_peer_id_bmap: mlo_peer_id bitmap for ptqm migration + * + * NB: Not using kernel-doc format since the kernel-doc script doesn't + * handle the qdf_bitmap() macro */ struct wlan_mlo_dev_context { qdf_list_node_t node; @@ -490,6 +495,10 @@ struct wlan_mlo_dev_context { struct wlan_mlo_ap *ap_ctx; struct wlan_t2lm_context t2lm_ctx; struct wlan_epcs_context epcs_ctx; +#ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE + qdf_timer_t ptqm_migrate_timer; + qdf_bitmap(mlo_peer_id_bmap, MAX_MLO_PEER_ID); +#endif }; /** @@ -1152,4 +1161,90 @@ struct mlo_link_disable_request_evt_params { struct qdf_mac_addr mld_addr; uint32_t link_id_bitmap; }; + +#ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE +/** + * struct peer_ptqm_migrate_entry - peer ptqm migrate entry + * @ml_peer_id: ML peer id + * @hw_link_id: HW link id + */ +struct peer_ptqm_migrate_entry { + uint16_t ml_peer_id; + uint16_t hw_link_id; +}; + +/** + * struct peer_ptqm_migrate_params - peer ptqm migrate request parameter + * @vdev_id: vdev id + * @num_peers: peer count + * @peer_list: list of peers to be migrated + */ +struct peer_ptqm_migrate_params { + uint8_t vdev_id; + uint16_t num_peers; + struct peer_ptqm_migrate_entry *peer_list; +}; + +/** + * struct peer_ptqm_migrate_list_entry - peer ptqm migrate list + * @peer: objmgr peer object + * @mlo_peer_id: mlo peer id + * @new_hw_link_id: hw link id of new primary + * @peer_list_elem: peer ptqm migrate entry list + */ +struct peer_ptqm_migrate_list_entry { + struct wlan_objmgr_peer *peer; + uint32_t mlo_peer_id; + uint8_t new_hw_link_id; + + TAILQ_ENTRY(peer_ptqm_migrate_list_entry) peer_list_elem; +}; + +/** + * struct peer_migrate_ptqm_multi_entries - multi ptqm migrate peer entry params + * @num_entries: Number of entries in the peer_list list + * @peer_list: List to hold the peer entries to be migrated + * + * NB: Not using kernel-doc format since the kernel-doc script doesn't + * handle the TAILQ_HEAD() macro + */ +struct peer_migrate_ptqm_multi_entries { + uint16_t num_entries; + + TAILQ_HEAD(, peer_ptqm_migrate_list_entry) peer_list; +}; + +enum primary_link_peer_migration_evenr_status { + PRIMARY_LINK_PEER_MIGRATION_SUCCESS, + PRIMARY_LINK_PEER_MIGRATION_IN_PROGRESS, + PRIMARY_LINK_PEER_MIGRATION_DELETE_IN_PROGRESS, + PRIMARY_LINK_PEER_MIGRATION_DELETED, + PRIMARY_LINK_PEER_MIGRATION_TX_PIPES_FAILED, + PRIMARY_LINK_PEER_MIGRATION_RX_PIPES_FAILED, + + /* Add any new status above this line */ + PRIMARY_LINK_PEER_MIGRATION_FAIL = 255, +}; + +/** + * struct peer_ptqm_migrate_event_params - peer ptqm migrate event parameter + * @vdev_id: vdev id + * @num_peers: peer count + */ +struct peer_ptqm_migrate_event_params { + uint8_t vdev_id; + uint16_t num_peers; +}; + +/** + * struct peer_entry_ptqm_migrate_event_params - peer entry ptqm migrate + * event parameter + * @ml_peer_id: ML peer id + * @status: migration status + */ +struct peer_entry_ptqm_migrate_event_params { + uint16_t ml_peer_id; + enum primary_link_peer_migration_evenr_status status; +}; +#endif /* QCA_SUPPORT_PRIMARY_LINK_MIGRATE */ #endif diff --git a/umac/mlo_mgr/src/wlan_mlo_mgr_ap.c b/umac/mlo_mgr/src/wlan_mlo_mgr_ap.c index 7e9a08e7ce..30c0827481 100644 --- a/umac/mlo_mgr/src/wlan_mlo_mgr_ap.c +++ b/umac/mlo_mgr/src/wlan_mlo_mgr_ap.c @@ -478,6 +478,16 @@ uint16_t mlo_ap_ml_peerid_alloc(void) return mlo_peer_id; } +#ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE +void mlo_ap_ml_ptqm_peerid_free(struct wlan_mlo_dev_context *ml_dev, + uint16_t mlo_peer_id) +{ + /* Free the bitmap for ptqm migration */ + if (qdf_test_bit(mlo_peer_id, ml_dev->mlo_peer_id_bmap)) + qdf_clear_bit(mlo_peer_id, ml_dev->mlo_peer_id_bmap); +} +#endif + void mlo_ap_ml_peerid_free(uint16_t mlo_peer_id) { struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); diff --git a/umac/mlo_mgr/src/wlan_mlo_mgr_main.c b/umac/mlo_mgr/src/wlan_mlo_mgr_main.c index 1e431c9153..976f949772 100644 --- a/umac/mlo_mgr/src/wlan_mlo_mgr_main.c +++ b/umac/mlo_mgr/src/wlan_mlo_mgr_main.c @@ -686,6 +686,24 @@ static inline void mlo_epcs_ctx_init(struct wlan_mlo_dev_context *ml_dev) qdf_mem_zero(epcs_ctx, sizeof(struct wlan_epcs_context)); } +#ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE +/** + * mlo_ptqm_migration_init() - API to initialize ptqm migration timer + * @ml_dev: Pointer to ML Dev context + * + * Return: None + */ +static inline void mlo_ptqm_migration_init(struct wlan_mlo_dev_context *ml_dev) +{ + qdf_timer_init(NULL, &ml_dev->ptqm_migrate_timer, + mlo_mlme_ptqm_migrate_timer_cb, (void *)(ml_dev), + QDF_TIMER_TYPE_WAKE_APPS); +} +#else +static inline void mlo_ptqm_migration_init(struct wlan_mlo_dev_context *ml_dev) +{ } +#endif + static QDF_STATUS mlo_dev_ctx_init(struct wlan_objmgr_vdev *vdev) { struct wlan_mlo_dev_context *ml_dev; @@ -763,10 +781,29 @@ static QDF_STATUS mlo_dev_ctx_init(struct wlan_objmgr_vdev *vdev) mlo_t2lm_ctx_init(ml_dev, vdev); mlo_epcs_ctx_init(ml_dev); + mlo_ptqm_migration_init(ml_dev); return status; } +#ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE +/** + * mlo_ptqm_migration_deinit() - API to deinitialize ptqm migration timer + * @ml_dev: Pointer to ML Dev context + * + * Return: None + */ +static inline void mlo_ptqm_migration_deinit( + struct wlan_mlo_dev_context *ml_dev) +{ + qdf_timer_free(&ml_dev->ptqm_migrate_timer); +} +#else +static inline void mlo_ptqm_migration_deinit( + struct wlan_mlo_dev_context *ml_dev) +{ } +#endif + /** * mlo_t2lm_ctx_deinit() - API to deinitialize the t2lm context with the default * values. @@ -857,6 +894,7 @@ static QDF_STATUS mlo_dev_ctx_deinit(struct wlan_objmgr_vdev *vdev) else if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) qdf_mem_free(ml_dev->ap_ctx); + mlo_ptqm_migration_deinit(ml_dev); mlo_t2lm_ctx_deinit(vdev); tsf_recalculation_lock_destroy(ml_dev); mlo_dev_lock_destroy(ml_dev); diff --git a/umac/mlo_mgr/src/wlan_mlo_mgr_peer.c b/umac/mlo_mgr/src/wlan_mlo_mgr_peer.c index 59a44a8f2b..bac6a39112 100644 --- a/umac/mlo_mgr/src/wlan_mlo_mgr_peer.c +++ b/umac/mlo_mgr/src/wlan_mlo_mgr_peer.c @@ -714,6 +714,7 @@ static void mlo_peer_free(struct wlan_mlo_peer_context *ml_peer) mlo_debug("ML Peer " QDF_MAC_ADDR_FMT " is freed", QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); mlo_peer_lock_destroy(ml_peer); + mlo_ap_ml_ptqm_peerid_free(ml_dev, ml_peer->mlo_peer_id); mlo_ap_ml_peerid_free(ml_peer->mlo_peer_id); mlo_peer_free_aid(ml_dev, ml_peer); mlo_peer_free_primary_umac(ml_dev, ml_peer); diff --git a/umac/mlo_mgr/src/wlan_mlo_mgr_peer_list.c b/umac/mlo_mgr/src/wlan_mlo_mgr_peer_list.c index b79223fbcf..a383a11f1c 100644 --- a/umac/mlo_mgr/src/wlan_mlo_mgr_peer_list.c +++ b/umac/mlo_mgr/src/wlan_mlo_mgr_peer_list.c @@ -350,6 +350,8 @@ struct wlan_mlo_peer_context *wlan_mlo_get_mlpeer_by_ml_peerid( return NULL; } +qdf_export_symbol(wlan_mlo_get_mlpeer_by_ml_peerid); + struct wlan_mlo_peer_context *wlan_mlo_get_mlpeer( struct wlan_mlo_dev_context *ml_dev, struct qdf_mac_addr *ml_addr) diff --git a/umac/mlo_mgr/src/wlan_mlo_mgr_primary_umac.c b/umac/mlo_mgr/src/wlan_mlo_mgr_primary_umac.c index 9fe3106908..c4ca565335 100644 --- a/umac/mlo_mgr/src/wlan_mlo_mgr_primary_umac.c +++ b/umac/mlo_mgr/src/wlan_mlo_mgr_primary_umac.c @@ -55,6 +55,8 @@ struct mlo_all_link_rssi { #define ML_INVALID_PRIMARY_TQM 0xff /* Congestion value */ #define ML_PRIMARY_TQM_CONGESTION 30 +/* PTQM migration timeout value in ms */ +#define ML_PRIMARY_TQM_MIGRATRION_TIMEOUT 4000 static void wlan_mlo_peer_get_rssi(struct wlan_objmgr_psoc *psoc, void *obj, void *args) @@ -728,4 +730,505 @@ void wlan_objmgr_mlo_update_primary_info(struct wlan_objmgr_peer *peer) } qdf_export_symbol(wlan_objmgr_mlo_update_primary_info); -#endif + +void mlo_mlme_ptqm_migrate_timer_cb(void *arg) +{ + struct wlan_mlo_dev_context *ml_dev = (struct wlan_mlo_dev_context *)arg; + struct wlan_mlo_peer_context *ml_peer = NULL; + uint16_t i = 0; + + if (!ml_dev) + return; + + /* Check for pending bitmaps and issue disconnect */ + for (i = 0; i < MAX_MLO_PEER_ID; i++) { + if (qdf_test_bit(i, ml_dev->mlo_peer_id_bmap)) { + ml_peer = wlan_mlo_get_mlpeer_by_ml_peerid(ml_dev, i); + if (ml_peer && ml_peer->primary_umac_migration_in_progress) { + ml_peer->primary_umac_migration_in_progress = false; + mlo_err("Issue disconnect for ml peer with ml peer id:%d", i); + wlan_mlo_peer_deauth_init(ml_peer, + NULL, 0); + } + qdf_clear_bit(i, ml_dev->mlo_peer_id_bmap); + } + } +} + +/** + * wlan_mlo_send_ptqm_migrate_cmd() - API to send WMI to trigger ptqm migration + * @vdev: objmgr vdev object + * @list: peer list to be migrated + * + * API to send WMI to trigger ptqm migration + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wlan_mlo_send_ptqm_migrate_cmd(struct wlan_objmgr_vdev *vdev, + struct peer_migrate_ptqm_multi_entries *list) +{ + struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + struct peer_ptqm_migrate_params param = {0}; + struct peer_ptqm_migrate_entry *peer_list = NULL; + struct peer_ptqm_migrate_list_entry *peer_entry, *tmp_entry; + struct wlan_mlo_dev_context *ml_dev = NULL; + uint16_t i = 0; + + ml_dev = vdev->mlo_dev_ctx; + if (!ml_dev) + return QDF_STATUS_E_FAILURE; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + mlo_err("null psoc"); + return QDF_STATUS_E_NULL_VALUE; + } + + mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops; + if (!mlo_tx_ops || !mlo_tx_ops->peer_ptqm_migrate_send) { + mlo_err("mlo_tx_ops is null!"); + return QDF_STATUS_E_NULL_VALUE; + } + + param.vdev_id = wlan_vdev_get_id(vdev); + param.num_peers = list->num_entries; + + param.peer_list = qdf_mem_malloc(sizeof(struct peer_ptqm_migrate_entry) * + list->num_entries); + if (!param.peer_list) { + mlo_err("Failed to allocate memory for ptqm migration command"); + return QDF_STATUS_E_FAILURE; + } + + peer_list = param.peer_list; + + TAILQ_FOREACH_SAFE(peer_entry, &list->peer_list, + peer_list_elem, tmp_entry) { + peer_list[i].ml_peer_id = peer_entry->mlo_peer_id; + peer_list[i].hw_link_id = peer_entry->new_hw_link_id; + + qdf_set_bit(peer_entry->mlo_peer_id, + ml_dev->mlo_peer_id_bmap); + + mlo_debug("idx:%d, ml_peer_id:%d, hw_link_id:%d", + i, peer_list[i].ml_peer_id, + peer_list[i].hw_link_id); + i++; + } + + status = mlo_tx_ops->peer_ptqm_migrate_send(vdev, ¶m); + if (QDF_IS_STATUS_ERROR(status)) { + mlo_err("Failed to send WMI for ptqm migration"); + qdf_mem_free(param.peer_list); + return QDF_STATUS_E_FAILURE; + } + + /* Set timeout equal to peer delete timeout as requested by FW. + * Timeout value to be optimized later. Timeout value will be + * updated later based on stress testings. + */ + qdf_timer_mod(&ml_dev->ptqm_migrate_timer, + ML_PRIMARY_TQM_MIGRATRION_TIMEOUT); + + qdf_mem_free(param.peer_list); + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_mlo_get_new_ptqm_id() - API to get new ptqm ID + * @curr_vdev: objmgr vdev object for current primary link + * @ml_peer: ml peer object + * @new_primary_link_id: new primary link id + * @new_hw_link_id: hw link id for new primary TQM + * + * API to get new ptqm ID + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wlan_mlo_get_new_ptqm_id(struct wlan_objmgr_vdev *curr_vdev, + struct wlan_mlo_peer_context *ml_peer, + uint8_t new_primary_link_id, + uint16_t *new_hw_link_id) +{ + uint8_t current_primary_link_id = WLAN_LINK_ID_INVALID; + struct wlan_objmgr_vdev *tmp_vdev = NULL; + struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = { NULL }; + struct wlan_mlo_link_peer_entry *peer_entry; + QDF_STATUS status; + uint8_t i = 0, idx = 0; + + if (wlan_vdev_mlme_get_opmode(curr_vdev) == QDF_SAP_MODE && + QDF_IS_STATUS_ERROR(wlan_mlo_peer_is_assoc_done(ml_peer))) { + mlo_err("ML peer " QDF_MAC_ADDR_FMT " is not associated", + QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); + return QDF_STATUS_E_INVAL; + } + + *new_hw_link_id = INVALID_HW_LINK_ID; + current_primary_link_id = + wlan_mlo_peer_get_primary_peer_link_id_by_ml_peer(ml_peer); + if (current_primary_link_id == WLAN_LINK_ID_INVALID) { + mlo_err("ML peer " QDF_MAC_ADDR_FMT "current primary link id is invalid", + QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); + return QDF_STATUS_E_INVAL; + } + + if (current_primary_link_id == new_primary_link_id) { + mlo_err("current and requested link_id are same"); + return QDF_STATUS_E_INVAL; + } + + for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { + peer_entry = &ml_peer->peer_list[i]; + if (!peer_entry || !peer_entry->link_peer) + continue; + + if (wlan_peer_get_peer_type(peer_entry->link_peer) == + WLAN_PEER_MLO_BRIDGE) + goto exit; + } + + for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { + peer_entry = &ml_peer->peer_list[i]; + if (!peer_entry || !peer_entry->link_peer) + continue; + + tmp_vdev = wlan_peer_get_vdev(peer_entry->link_peer); + if (!tmp_vdev || tmp_vdev == curr_vdev) + continue; + + status = wlan_objmgr_vdev_try_get_ref(tmp_vdev, + WLAN_MLME_SB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + mlo_err("failed to get vdev ref"); + continue; + } + wlan_vdev_list[idx++] = tmp_vdev; + } + + if (new_primary_link_id == WLAN_LINK_ID_INVALID) { + mlo_debug("Invalid link id provided, select new link id"); + ml_peer->migrate_primary_umac_psoc_id = + wlan_mld_get_best_primary_umac_w_rssi(ml_peer, wlan_vdev_list); + if (ml_peer->migrate_primary_umac_psoc_id == + ML_PRIMARY_UMAC_ID_INVAL) { + mlo_err("Unable to fetch new primary link id for ml peer " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); + goto exit; + } + for (i = 0; i < idx; i++) { + if (ml_peer->migrate_primary_umac_psoc_id == + wlan_vdev_get_psoc_id(wlan_vdev_list[i])) { + *new_hw_link_id = wlan_mlo_get_pdev_hw_link_id( + wlan_vdev_get_pdev(wlan_vdev_list[i])); + break; + } + } + } else { + /* check if provided link id is part of current ml peer links */ + for (i = 0; i < idx; i++) { + if (new_primary_link_id == wlan_vdev_get_link_id(wlan_vdev_list[i])) { + /* Check if the soc is enabled to be pumac or not */ + if (wlan_vdev_skip_pumac(wlan_vdev_list[i])) { + mlo_err("Given link %d cannot be selected as primary", + new_primary_link_id); + goto exit; + } + *new_hw_link_id = wlan_mlo_get_pdev_hw_link_id( + wlan_vdev_get_pdev(wlan_vdev_list[i])); + break; + } + } + } + + if (*new_hw_link_id == INVALID_HW_LINK_ID) { + mlo_err("New primary link id not found for ml peer " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); + goto exit; + } + + if (i < idx) { + if (wlan_vdev_mlme_op_flags_get(wlan_vdev_list[i], + WLAN_VDEV_OP_MLO_LINK_REMOVAL_IN_PROGRESS)) { + mlo_err("New selected primary link is going for removal, skip migration"); + goto exit; + } + } + + for (i = 0; i < idx; i++) + wlan_objmgr_vdev_release_ref(wlan_vdev_list[i], + WLAN_MLME_SB_ID); + + return QDF_STATUS_SUCCESS; + +exit: + ml_peer->migrate_primary_umac_psoc_id = ML_PRIMARY_UMAC_ID_INVAL; + + for (i = 0; i < idx; i++) + wlan_objmgr_vdev_release_ref(wlan_vdev_list[i], + WLAN_MLME_SB_ID); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wlan_mlo_free_ptqm_migrate_list() - API to free peer ptqm migration list + * @list: peer ptqm migration list + * + * API to free peer ptqm migration list + * + * Return: void + */ +static void wlan_mlo_free_ptqm_migrate_list( + struct peer_migrate_ptqm_multi_entries *list) +{ + struct peer_ptqm_migrate_list_entry *peer_entry, *tmp_entry; + + TAILQ_FOREACH_SAFE(peer_entry, &list->peer_list, + peer_list_elem, tmp_entry) { + TAILQ_REMOVE(&list->peer_list, peer_entry, peer_list_elem); + list->num_entries--; + if (peer_entry->peer) + wlan_objmgr_peer_release_ref(peer_entry->peer, + WLAN_MLME_SB_ID); + qdf_mem_free(peer_entry); + } +} + +/** + * wlan_mlo_reset_ptqm_migrate_list() - API to reset peer ptqm migration list + * @ml_dev: MLO dev context + * @list: peer ptqm migration list + * + * API to reset peer ptqm migration list + * + * Return: void + */ +static void wlan_mlo_reset_ptqm_migrate_list( + struct wlan_mlo_dev_context *ml_dev, + struct peer_migrate_ptqm_multi_entries *list) +{ + struct peer_ptqm_migrate_list_entry *peer_entry, *tmp_entry; + + if (!ml_dev) + return; + + TAILQ_FOREACH_SAFE(peer_entry, &list->peer_list, + peer_list_elem, tmp_entry) { + if (peer_entry->peer) { + qdf_clear_bit(peer_entry->mlo_peer_id, ml_dev->mlo_peer_id_bmap); + peer_entry->peer->mlo_peer_ctx->primary_umac_migration_in_progress = false; + peer_entry->peer->mlo_peer_ctx->migrate_primary_umac_psoc_id = + ML_PRIMARY_UMAC_ID_INVAL; + } + } +} + +/** + * wlan_mlo_build_ptqm_migrate_list() - API to build peer ptqm migration list + * @vdev: objmgr vdev list + * @object: peer object + * @arg: list pointer + * + * API to build peer ptqm migration list + * + * Return: void + */ +static void wlan_mlo_build_ptqm_migrate_list(struct wlan_objmgr_vdev *vdev, + void *object, void *arg) +{ + struct wlan_objmgr_peer *peer = (struct wlan_objmgr_peer *)object; + struct peer_migrate_ptqm_multi_entries *list = + (struct peer_migrate_ptqm_multi_entries *)arg; + struct peer_ptqm_migrate_list_entry *peer_entry; + struct wlan_mlo_peer_context *ml_peer; + uint16_t new_hw_link_id = INVALID_HW_LINK_ID; + uint8_t current_primary_link_id = WLAN_LINK_ID_INVALID; + QDF_STATUS status; + + if (!wlan_peer_is_mlo(peer) || !peer->mlo_peer_ctx) + return; + + ml_peer = peer->mlo_peer_ctx; + + if (ml_peer->link_peer_cnt == 1) + return; + + if (ml_peer->primary_umac_migration_in_progress) { + mlo_err("peer " QDF_MAC_ADDR_FMT " primary umac migration already in progress", + QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); + return; + } + + current_primary_link_id = wlan_mlo_peer_get_primary_peer_link_id_by_ml_peer(ml_peer); + if (current_primary_link_id == WLAN_LINK_ID_INVALID || + current_primary_link_id != wlan_vdev_get_link_id(vdev)) { + mlo_debug("peer " QDF_MAC_ADDR_FMT " not having primary on current vdev", + QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); + return; + } + + status = wlan_mlo_get_new_ptqm_id(vdev, ml_peer, + WLAN_LINK_ID_INVALID, + &new_hw_link_id); + if (QDF_IS_STATUS_ERROR(status)) { + mlo_err("peer " QDF_MAC_ADDR_FMT " unable to get new ptqm id", + QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); + return; + } + ml_peer->primary_umac_migration_in_progress = true; + + peer_entry = (struct peer_ptqm_migrate_list_entry *) + qdf_mem_malloc(sizeof(struct peer_ptqm_migrate_list_entry)); + if (!peer_entry) { + mlo_err("peer " QDF_MAC_ADDR_FMT " unable to allocate peer entry", + QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); + return; + } + + status = wlan_objmgr_peer_try_get_ref(peer, WLAN_MLME_SB_ID); + peer_entry->peer = peer; + peer_entry->new_hw_link_id = new_hw_link_id; + peer_entry->mlo_peer_id = ml_peer->mlo_peer_id; + TAILQ_INSERT_TAIL(&list->peer_list, peer_entry, peer_list_elem); + list->num_entries++; +} + +/** + * wlan_mlo_trigger_link_ptqm_migration() - API to trigger ptqm migration + * for a link + * @vdev: objmgr vdev object + * + * API to trigger ptqm migration of all peers having primary on given link + * + * Return: QDF_STATUS + */ +static QDF_STATUS wlan_mlo_trigger_link_ptqm_migration( + struct wlan_objmgr_vdev *vdev) +{ + struct peer_migrate_ptqm_multi_entries migrate_list = {0}; + QDF_STATUS status; + + TAILQ_INIT(&migrate_list.peer_list); + wlan_objmgr_iterate_peerobj_list(vdev, + wlan_mlo_build_ptqm_migrate_list, + &migrate_list, WLAN_MLME_NB_ID); + + /* trigger WMI */ + if (migrate_list.num_entries == 0) { + mlo_err("No peer found"); + return QDF_STATUS_SUCCESS; + } + + status = wlan_mlo_send_ptqm_migrate_cmd(vdev, &migrate_list); + if (QDF_IS_STATUS_ERROR(status)) + wlan_mlo_reset_ptqm_migrate_list(vdev->mlo_dev_ctx, + &migrate_list); + wlan_mlo_free_ptqm_migrate_list(&migrate_list); + return status; +} + +QDF_STATUS wlan_mlo_set_ptqm_migration(struct wlan_objmgr_vdev *vdev, + struct wlan_mlo_peer_context *ml_peer, + bool link_migration, + uint32_t link_id) +{ + uint16_t new_hw_link_id = INVALID_HW_LINK_ID; + struct peer_migrate_ptqm_multi_entries migrate_list = {0}; + struct peer_ptqm_migrate_list_entry *peer_entry; + struct wlan_objmgr_vdev *curr_vdev = NULL; + uint8_t current_primary_link_id = WLAN_LINK_ID_INVALID; + QDF_STATUS status; + + if (!vdev) { + mlo_err("Vdev is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (link_migration == false && !ml_peer) { + mlo_err("ML peer is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (link_migration) { + if (wlan_vdev_mlme_op_flags_get(vdev, WLAN_VDEV_OP_MLO_LINK_REMOVAL_IN_PROGRESS)) { + mlo_err("Link removal in progress, skip umac migration for vdev:%d", + wlan_vdev_get_id(vdev)); + return QDF_STATUS_E_INVAL; + } + mlo_err("Trigger migration for full link"); + // trigger full link migration + status = wlan_mlo_trigger_link_ptqm_migration(vdev); + if (QDF_IS_STATUS_ERROR(status)) + mlo_err("Failed to trigger link migration"); + return status; + } + + if (ml_peer->link_peer_cnt == 1) { + mlo_err("peer " QDF_MAC_ADDR_FMT " is SLO", + QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); + return QDF_STATUS_E_INVAL; + } + + if (ml_peer->primary_umac_migration_in_progress) { + mlo_err("peer " QDF_MAC_ADDR_FMT " primary umac migration already in progress", + QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); + return QDF_STATUS_E_INVAL; + } + + current_primary_link_id = wlan_mlo_peer_get_primary_peer_link_id_by_ml_peer(ml_peer); + if (current_primary_link_id == WLAN_LINK_ID_INVALID) { + mlo_err("Current primary link id is invalid"); + return QDF_STATUS_E_INVAL; + } + + curr_vdev = mlo_get_vdev_by_link_id(vdev, current_primary_link_id); + if (!curr_vdev) { + mlo_err("Unable to get current primary vdev"); + return QDF_STATUS_E_INVAL; + } + + status = wlan_mlo_get_new_ptqm_id(curr_vdev, ml_peer, + link_id, &new_hw_link_id); + if (QDF_IS_STATUS_ERROR(status)) { + mlo_err("peer " QDF_MAC_ADDR_FMT " unable to get new ptqm id", + QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes)); + goto exit; + } + ml_peer->primary_umac_migration_in_progress = true; + + peer_entry = (struct peer_ptqm_migrate_list_entry *) + qdf_mem_malloc(sizeof(struct peer_ptqm_migrate_list_entry)); + if (!peer_entry) { + mlo_err("Failed to allocate peer entry"); + goto exit; + } + + peer_entry->new_hw_link_id = new_hw_link_id; + peer_entry->mlo_peer_id = ml_peer->mlo_peer_id; + TAILQ_INIT(&migrate_list.peer_list); + TAILQ_INSERT_TAIL(&migrate_list.peer_list, peer_entry, peer_list_elem); + migrate_list.num_entries = 1; + + //trigger WMI + status = wlan_mlo_send_ptqm_migrate_cmd(curr_vdev, &migrate_list); + if (QDF_IS_STATUS_ERROR(status)) + wlan_mlo_reset_ptqm_migrate_list(curr_vdev->mlo_dev_ctx, + &migrate_list); + wlan_mlo_free_ptqm_migrate_list(&migrate_list); + + mlo_release_vdev_ref(curr_vdev); + + return status; + +exit: + if (curr_vdev) + mlo_release_vdev_ref(curr_vdev); + + return QDF_STATUS_E_FAILURE; +} +#endif /* QCA_SUPPORT_PRIMARY_LINK_MIGRATE */ diff --git a/wmi/inc/wmi_unified_11be_api.h b/wmi/inc/wmi_unified_11be_api.h index cd8d0fc51d..f969855787 100644 --- a/wmi/inc/wmi_unified_11be_api.h +++ b/wmi/inc/wmi_unified_11be_api.h @@ -219,4 +219,46 @@ QDF_STATUS wmi_extract_mlo_link_disable_request_evt( struct mlo_link_disable_request_evt_params *params); #endif /* WLAN_FEATURE_11BE */ +#ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE +/** + * wmi_unified_peer_ptqm_migrate_send() - send PEER ptqm migrate command to fw + * @wmi_hdl: wmi handle + * @param: pointer to hold peer ptqm migrate parameters + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_peer_ptqm_migrate_send( + wmi_unified_t wmi_hdl, + struct peer_ptqm_migrate_params *param); + +/** + * wmi_extract_peer_ptqm_migrate_event() - extract peer ptqm migrate event params + * @wmi: wmi handle + * @evt_buf: pointer to event buffer + * @resp: Pointer to host structure to get the event params + * + * This function gets called to extract peer ptqm migrate event params + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_extract_peer_ptqm_migrate_event( + wmi_unified_t wmi, void *evt_buf, + struct peer_ptqm_migrate_event_params *resp); + +/** + * wmi_extract_peer_ptqm_entry_param() - extract peer entry ptqm migrate param + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @index: Index into pdev stats + * @entry: Pointer to peer entry params + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_extract_peer_ptqm_entry_param( + wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, + struct peer_entry_ptqm_migrate_event_params *entry); +#endif /* QCA_SUPPORT_PRIMARY_LINK_MIGRATE */ #endif /*_WMI_UNIFIED_11BE_API_H_*/ diff --git a/wmi/inc/wmi_unified_param.h b/wmi/inc/wmi_unified_param.h index 90a66f63df..3b6d52754d 100644 --- a/wmi/inc/wmi_unified_param.h +++ b/wmi/inc/wmi_unified_param.h @@ -5309,6 +5309,9 @@ typedef enum { wmi_csa_ie_received_event_id, #ifdef WLAN_FEATURE_11BE_MLO wmi_mlo_link_state_info_eventid, +#endif +#ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE + wmi_peer_ptqm_migration_response_eventid, #endif wmi_events_max, } wmi_conv_event_id; diff --git a/wmi/inc/wmi_unified_priv.h b/wmi/inc/wmi_unified_priv.h index f12efe0c5b..81b2b63cec 100644 --- a/wmi/inc/wmi_unified_priv.h +++ b/wmi/inc/wmi_unified_priv.h @@ -3311,6 +3311,22 @@ QDF_STATUS (*extract_csa_ie_received_ev_params)(wmi_unified_t wmi_handle, void *evt_buf, uint8_t *vdev_id, struct csa_offload_params *csa_event); +#ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE +QDF_STATUS (*send_peer_ptqm_migrate_cmd)( + wmi_unified_t wmi, + struct peer_ptqm_migrate_params *param); + +QDF_STATUS (*extract_peer_ptqm_migrate_event)( + struct wmi_unified *wmi_handle, + uint8_t *buf, + struct peer_ptqm_migrate_event_params *params); + +QDF_STATUS (*extract_peer_entry_ptqm_migrate_event)( + struct wmi_unified *wmi_handle, + uint8_t *buf, + uint32_t index, + struct peer_entry_ptqm_migrate_event_params *entry); +#endif /* QCA_SUPPORT_PRIMARY_LINK_MIGRATE */ }; /* Forward declaration for psoc*/ diff --git a/wmi/src/wmi_unified_11be_api.c b/wmi/src/wmi_unified_11be_api.c index 2925e10444..7872f63573 100644 --- a/wmi/src/wmi_unified_11be_api.c +++ b/wmi/src/wmi_unified_11be_api.c @@ -211,3 +211,42 @@ QDF_STATUS wmi_extract_mgmt_rx_mlo_link_removal_info( return QDF_STATUS_E_FAILURE; } + +#ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE +QDF_STATUS wmi_unified_peer_ptqm_migrate_send( + wmi_unified_t wmi_hdl, + struct peer_ptqm_migrate_params *param) +{ + if (wmi_hdl->ops->send_peer_ptqm_migrate_cmd) + return wmi_hdl->ops->send_peer_ptqm_migrate_cmd(wmi_hdl, param); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_extract_peer_ptqm_migrate_event( + wmi_unified_t wmi, void *evt_buf, + struct peer_ptqm_migrate_event_params *resp) +{ + if (wmi->ops->extract_peer_ptqm_migrate_event) { + return wmi->ops->extract_peer_ptqm_migrate_event(wmi, + evt_buf, + resp); + } + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_extract_peer_ptqm_entry_param( + wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, + struct peer_entry_ptqm_migrate_event_params *entry) +{ + if (wmi_handle->ops->extract_peer_entry_ptqm_migrate_event) + return wmi_handle->ops->extract_peer_entry_ptqm_migrate_event( + wmi_handle, evt_buf, + index, entry); + + return QDF_STATUS_E_FAILURE; +} +#endif /* QCA_SUPPORT_PRIMARY_LINK_MIGRATE */ diff --git a/wmi/src/wmi_unified_11be_tlv.c b/wmi/src/wmi_unified_11be_tlv.c index a7ad30a436..3ad14edbde 100644 --- a/wmi/src/wmi_unified_11be_tlv.c +++ b/wmi/src/wmi_unified_11be_tlv.c @@ -1876,6 +1876,171 @@ QDF_STATUS extract_mgmt_rx_ml_cu_params_tlv(wmi_unified_t wmi_handle, return QDF_STATUS_SUCCESS; } +#ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE +/** + * send_peer_ptqm_migrate_cmd_tlv() - send PEER ptqm migrate command to fw + * @wmi_handle: wmi handle + * @param: pointer to hold peer ptqm migrate parameter + * + * Return: QDF_STATUS_SUCCESS for success else error code + */ +static QDF_STATUS send_peer_ptqm_migrate_cmd_tlv( + wmi_unified_t wmi_handle, + struct peer_ptqm_migrate_params *param) +{ + /* Todo: copy send_peer_delete_all_cmd_tlv */ + uint16_t i = 0; + wmi_buf_t buf; + uint8_t *buf_ptr; + wmi_mlo_primary_link_peer_migration_fixed_param *cmd; + uint32_t len = sizeof(*cmd); + uint16_t num_entry = 0; + uint16_t max_entry_per_cmd = 0, max_entry_cnt = 0; + struct peer_ptqm_migrate_entry *param_list = param->peer_list; + wmi_mlo_new_primary_link_peer_info *entry; + uint32_t pending_cnt = param->num_peers; + + /* Get max entries which can be send in a single WMI command. + * If no. of entries is more than max entries supported, multiple + * WMI commands will be send. + */ + max_entry_per_cmd = (wmi_get_max_msg_len(wmi_handle) - + sizeof(*cmd) - WMI_TLV_HDR_SIZE) / + (sizeof(wmi_mlo_new_primary_link_peer_info)); + + if (param->num_peers > max_entry_per_cmd) + max_entry_cnt = max_entry_per_cmd; + else + max_entry_cnt = param->num_peers; + + wmi_debug("Setting max entry limit as %u", max_entry_cnt); + while (pending_cnt > 0) { + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; + if (pending_cnt >= max_entry_cnt) + num_entry = max_entry_cnt; + else + num_entry = pending_cnt; + + len += num_entry * sizeof(wmi_mlo_new_primary_link_peer_info); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + + cmd = (wmi_mlo_primary_link_peer_migration_fixed_param *) + wmi_buf_data(buf); + WMITLV_SET_HDR( + &cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_mlo_primary_link_peer_migration_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_mlo_primary_link_peer_migration_fixed_param)); + buf_ptr += sizeof(*cmd); + cmd->vdev_id = param->vdev_id; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + num_entry * sizeof(wmi_mlo_new_primary_link_peer_info)); + buf_ptr += WMI_TLV_HDR_SIZE; + entry = (wmi_mlo_new_primary_link_peer_info *)buf_ptr; + for (i = 0; i < num_entry; i++) { + WMITLV_SET_HDR(&entry[i].tlv_header, + WMITLV_TAG_STRUC_wmi_mlo_new_primary_link_peer_info, + WMITLV_GET_STRUCT_TLVLEN(wmi_mlo_new_primary_link_peer_info)); + WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_ML_PEER_ID_SET( + entry[i].new_link_info, + param_list[i].ml_peer_id); + WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_HW_LINK_ID_SET( + entry[i].new_link_info, + param_list[i].hw_link_id); + wmi_debug("i:%d, ml_peer_id:%d, hw_link_id:%d", + i, entry[i].ml_peer_id, entry[i].hw_link_id); + } + pending_cnt -= num_entry; + param_list += num_entry; + + wmi_mtrace(WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_CMDID, + cmd->vdev_id, 0); + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_CMDID)) { + wmi_err("num_entries:%d failed!", + param->num_peers); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + wmi_debug("num_entries:%d done!", + num_entry); + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +extract_peer_ptqm_migrate_evt_param_tlv( + struct wmi_unified *wmi_handle, + uint8_t *buf, + struct peer_ptqm_migrate_event_params *params) +{ + WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_EVENTID_param_tlvs *param_buf; + wmi_mlo_primary_link_peer_migration_compl_fixed_param *ev; + + param_buf = + (WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_EVENTID_param_tlvs *)buf; + if (!param_buf) { + wmi_err_rl("Param_buf is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (!param_buf->primary_link_peer_migration_status) { + wmi_err_rl("primary_link_peer_migration_status not present in event"); + return QDF_STATUS_E_FAILURE; + } + + ev = (wmi_mlo_primary_link_peer_migration_compl_fixed_param *) + param_buf->fixed_param; + + params->vdev_id = ev->vdev_id; + params->num_peers = param_buf->num_primary_link_peer_migration_status; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +extract_peer_entry_ptqm_migrate_evt_param_tlv( + struct wmi_unified *wmi_handle, + uint8_t *buf, + uint32_t index, + struct peer_entry_ptqm_migrate_event_params *params) +{ + WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_EVENTID_param_tlvs *param_buf; + + param_buf = + (WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_EVENTID_param_tlvs *)buf; + if (!param_buf) { + wmi_err_rl("Param_buf is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (index > param_buf->num_primary_link_peer_migration_status) { + wmi_err_rl("Index greater than total peer entries"); + return QDF_STATUS_E_FAILURE; + } + + if (!param_buf->primary_link_peer_migration_status) { + wmi_err_rl("primary_link_peer_migration_status not present in event"); + return QDF_STATUS_E_FAILURE; + } + + params->ml_peer_id = + WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_STATUS_ML_PEER_ID_GET( + param_buf->primary_link_peer_migration_status[index].status_info); + + params->status = + WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_STATUS_STATUS_GET( + param_buf->primary_link_peer_migration_status[index].status_info); + return QDF_STATUS_SUCCESS; +} +#endif /* QCA_SUPPORT_PRIMARY_LINK_MIGRATE */ + void wmi_11be_attach_tlv(wmi_unified_t wmi_handle) { struct wmi_ops *ops = wmi_handle->ops; @@ -1912,4 +2077,9 @@ void wmi_11be_attach_tlv(wmi_unified_t wmi_handle) extract_mlo_link_disable_request_evt_param_tlv; ops->send_mlo_vdev_pause = send_mlo_vdev_pause_cmd_tlv; +#ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE + ops->send_peer_ptqm_migrate_cmd = send_peer_ptqm_migrate_cmd_tlv; + 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 */ } diff --git a/wmi/src/wmi_unified_tlv.c b/wmi/src/wmi_unified_tlv.c index 7301e62910..964813eec5 100644 --- a/wmi/src/wmi_unified_tlv.c +++ b/wmi/src/wmi_unified_tlv.c @@ -21774,6 +21774,11 @@ static void populate_tlv_events_id(WMI_EVT_ID *event_ids) #endif event_ids[wmi_csa_ie_received_event_id] = WMI_CSA_IE_RECEIVED_EVENTID; + +#ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE + event_ids[wmi_peer_ptqm_migration_response_eventid] = + WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_EVENTID; +#endif } #ifdef WLAN_FEATURE_LINK_LAYER_STATS