qcacmn: Add support for ptqm migration

Add support for ptqm migration

Change-Id: I3f3d6e410bee554477e8e058b1da51f2af5abb23
CRs-Fixed: 3529926
Bu işleme şunda yer alıyor:
Himanshu Batra
2023-04-04 18:46:58 +05:30
işlemeyi yapan: Rahul Choudhary
ebeveyn 6f407b1a93
işleme be34bbe6fc
16 değiştirilmiş dosya ile 1020 ekleme ve 1 silme

Dosyayı Görüntüle

@@ -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;
}

Dosyayı Görüntüle

@@ -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 */
};
/**

Dosyayı Görüntüle

@@ -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

Dosyayı Görüntüle

@@ -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

Dosyayı Görüntüle

@@ -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

Dosyayı Görüntüle

@@ -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();

Dosyayı Görüntüle

@@ -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);

Dosyayı Görüntüle

@@ -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);

Dosyayı Görüntüle

@@ -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)

Dosyayı Görüntüle

@@ -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, &param);
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 */

Dosyayı Görüntüle

@@ -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_*/

Dosyayı Görüntüle

@@ -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;

Dosyayı Görüntüle

@@ -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*/

Dosyayı Görüntüle

@@ -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 */

Dosyayı Görüntüle

@@ -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 */
}

Dosyayı Görüntüle

@@ -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