From 5c85cfb5a0e17ce776ab86803e6e76c8fe616e8a Mon Sep 17 00:00:00 2001 From: Jinwei Chen Date: Mon, 9 Aug 2021 04:09:05 -0700 Subject: [PATCH] qcacmn: cdp/dp peer change for MLO cdp/dp peer change for MLO Change-Id: I9b8eb741317a0dc7337aff7e773148892e531ba2 CRs-Fixed: 3031166 --- dp/inc/cdp_txrx_cmn.h | 7 +- dp/inc/cdp_txrx_cmn_struct.h | 25 + dp/inc/cdp_txrx_ops.h | 5 +- dp/wifi3.0/dp_internal.h | 5 - dp/wifi3.0/dp_main.c | 191 +++++-- dp/wifi3.0/dp_peer.c | 1001 ++++++++++++++++++++++++++-------- dp/wifi3.0/dp_peer.h | 463 ++++++++++++++++ dp/wifi3.0/dp_rx_defrag.c | 8 +- dp/wifi3.0/dp_rx_err.c | 2 +- dp/wifi3.0/dp_types.h | 60 +- 10 files changed, 1489 insertions(+), 278 deletions(-) diff --git a/dp/inc/cdp_txrx_cmn.h b/dp/inc/cdp_txrx_cmn.h index 566d8477bf..1c345e7e11 100644 --- a/dp/inc/cdp_txrx_cmn.h +++ b/dp/inc/cdp_txrx_cmn.h @@ -373,11 +373,12 @@ static inline QDF_STATUS cdp_peer_create return QDF_STATUS_E_FAILURE; return soc->ops->cmn_drv_ops->txrx_peer_create(soc, vdev_id, - peer_mac_addr); + peer_mac_addr, CDP_LINK_PEER_TYPE); } static inline void cdp_peer_setup - (ol_txrx_soc_handle soc, uint8_t vdev_id, uint8_t *peer_mac) + (ol_txrx_soc_handle soc, uint8_t vdev_id, uint8_t *peer_mac, + struct cdp_peer_setup_info *setup_info) { if (!soc || !soc->ops) { dp_cdp_debug("Invalid Instance:"); @@ -390,7 +391,7 @@ static inline void cdp_peer_setup return; soc->ops->cmn_drv_ops->txrx_peer_setup(soc, vdev_id, - peer_mac); + peer_mac, setup_info); } /* diff --git a/dp/inc/cdp_txrx_cmn_struct.h b/dp/inc/cdp_txrx_cmn_struct.h index 99f9e26d4d..d5fda34c53 100644 --- a/dp/inc/cdp_txrx_cmn_struct.h +++ b/dp/inc/cdp_txrx_cmn_struct.h @@ -385,6 +385,31 @@ enum htt_cmn_t2h_en_stats_status { HTT_CMN_T2H_EN_STATS_STATUS_SERIES_DONE = 7, }; +/** + * enum cdp_peer_type - Peer type + * @CDP_INVALID_PEER_TYPE: invalid peer type + * @CDP_LINK_PEER_TYPE: legacy peer or link peer for MLO connection + * @CDP_MLD_PEER_TYPE: MLD peer for MLO connection + */ +enum cdp_peer_type { + CDP_INVALID_PEER_TYPE, + CDP_LINK_PEER_TYPE, + CDP_MLD_PEER_TYPE, +}; + +/** + * struct cdp_peer_setup_info: MLO connection info for cdp_peer_setup() + * @mld_peer_mac: mld peer mac address pointer + * @is_assoc_link: set true for first MLO link peer association + * @is_primary_link: for MCC, the first link will always be primary link, + for WIN, other link might be primary link. + */ +struct cdp_peer_setup_info { + uint8_t *mld_peer_mac; + uint8_t is_assoc_link:1, + is_primary_link:1; +}; + /** * struct ol_txrx_peer_state - Peer state information */ diff --git a/dp/inc/cdp_txrx_ops.h b/dp/inc/cdp_txrx_ops.h index 38d1b31852..30a0021b07 100644 --- a/dp/inc/cdp_txrx_ops.h +++ b/dp/inc/cdp_txrx_ops.h @@ -156,11 +156,12 @@ struct cdp_cmn_ops { QDF_STATUS (*txrx_peer_create) (ol_txrx_soc_handle soc, uint8_t vdev_id, - uint8_t *peer_mac_addr); + uint8_t *peer_mac_addr, enum cdp_peer_type peer_type); QDF_STATUS (*txrx_peer_setup)(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, - uint8_t *peer_mac); + uint8_t *peer_mac, + struct cdp_peer_setup_info *setup_info); QDF_STATUS (*txrx_cp_peer_del_response) diff --git a/dp/wifi3.0/dp_internal.h b/dp/wifi3.0/dp_internal.h index 5af7e600ea..213aa24690 100644 --- a/dp/wifi3.0/dp_internal.h +++ b/dp/wifi3.0/dp_internal.h @@ -1543,11 +1543,6 @@ void dp_peer_ppdu_delayed_ba_cleanup(struct dp_peer *peer); extern void dp_peer_rx_init(struct dp_pdev *pdev, struct dp_peer *peer); void dp_peer_cleanup(struct dp_vdev *vdev, struct dp_peer *peer); void dp_peer_rx_cleanup(struct dp_vdev *vdev, struct dp_peer *peer); -extern struct dp_peer *dp_peer_find_hash_find(struct dp_soc *soc, - uint8_t *peer_mac_addr, - int mac_addr_is_aligned, - uint8_t vdev_id, - enum dp_mod_id id); #ifdef DP_PEER_EXTENDED_API /** diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 6980541da7..6997f18b3c 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -214,7 +214,8 @@ dp_soc_attach(struct cdp_ctrl_objmgr_psoc *ctrl_psoc, struct ol_if_ops *ol_ops, uint16_t device_id); static inline QDF_STATUS dp_peer_create_wifi3(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, - uint8_t *peer_mac_addr); + uint8_t *peer_mac_addr, + enum cdp_peer_type peer_type); static QDF_STATUS dp_peer_delete_wifi3(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, uint8_t *peer_mac, uint32_t bitmap); @@ -6037,7 +6038,7 @@ static QDF_STATUS dp_vdev_attach_wifi3(struct cdp_soc_t *cdp_soc, if (wlan_op_mode_sta == vdev->opmode) dp_peer_create_wifi3((struct cdp_soc_t *)soc, vdev_id, - vdev->mac_addr.raw); + vdev->mac_addr.raw, CDP_LINK_PEER_TYPE); return QDF_STATUS_SUCCESS; fail0: @@ -6137,19 +6138,9 @@ static QDF_STATUS dp_vdev_register_wifi3(struct cdp_soc_t *soc_hdl, return QDF_STATUS_SUCCESS; } -/** - * dp_peer_delete() - delete DP peer - * - * @soc: Datatpath soc - * @peer: Datapath peer - * @arg: argument to iter function - * - * Return: void - */ -static void -dp_peer_delete(struct dp_soc *soc, - struct dp_peer *peer, - void *arg) +void dp_peer_delete(struct dp_soc *soc, + struct dp_peer *peer, + void *arg) { if (!peer->valid) return; @@ -6293,8 +6284,49 @@ static QDF_STATUS dp_vdev_detach_wifi3(struct cdp_soc_t *cdp_soc, return QDF_STATUS_SUCCESS; } +#ifdef WLAN_FEATURE_11BE_MLO +/** + * is_dp_peer_can_reuse() - check if the dp_peer match condition to be reused + * @vdev: Target DP vdev handle + * @peer: DP peer handle to be checked + * @peer_mac_addr: Target peer mac address + * @peer_type: Target peer type + * + * Return: true - if match, false - not match + */ +static inline +bool is_dp_peer_can_reuse(struct dp_vdev *vdev, + struct dp_peer *peer, + uint8_t *peer_mac_addr, + enum cdp_peer_type peer_type) +{ + if (peer->bss_peer && (peer->vdev == vdev) && + (peer->peer_type == peer_type) && + (qdf_mem_cmp(peer_mac_addr, peer->mac_addr.raw, + QDF_MAC_ADDR_SIZE) == 0)) + return true; + + return false; +} +#else +static inline +bool is_dp_peer_can_reuse(struct dp_vdev *vdev, + struct dp_peer *peer, + uint8_t *peer_mac_addr, + enum cdp_peer_type peer_type) +{ + if (peer->bss_peer && (peer->vdev == vdev) && + (qdf_mem_cmp(peer_mac_addr, peer->mac_addr.raw, + QDF_MAC_ADDR_SIZE) == 0)) + return true; + + return false; +} +#endif + static inline struct dp_peer *dp_peer_can_reuse(struct dp_vdev *vdev, - uint8_t *peer_mac_addr) + uint8_t *peer_mac_addr, + enum cdp_peer_type peer_type) { struct dp_peer *peer; struct dp_soc *soc = vdev->pdev->soc; @@ -6304,9 +6336,8 @@ static inline struct dp_peer *dp_peer_can_reuse(struct dp_vdev *vdev, inactive_list_elem) { /* reuse bss peer only when vdev matches*/ - if (peer->bss_peer && (peer->vdev == vdev) && - qdf_mem_cmp(peer_mac_addr, peer->mac_addr.raw, - QDF_MAC_ADDR_SIZE) == 0) { + if (is_dp_peer_can_reuse(vdev, peer, + peer_mac_addr, peer_type)) { /* increment ref count for cdp_peer_create*/ if (dp_peer_get_ref(soc, peer, DP_MOD_ID_CONFIG) == QDF_STATUS_SUCCESS) { @@ -6365,12 +6396,13 @@ static inline void dp_peer_rx_bufq_resources_init(struct dp_peer *peer) * @soc_hdl: Datapath soc handle * @vdev_id: id of vdev * @peer_mac_addr: Peer MAC address + * @peer_type: link or MLD peer type * * Return: 0 on success, -1 on failure */ static QDF_STATUS dp_peer_create_wifi3(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, - uint8_t *peer_mac_addr) + uint8_t *peer_mac_addr, enum cdp_peer_type peer_type) { struct dp_peer *peer; int i; @@ -6395,17 +6427,18 @@ dp_peer_create_wifi3(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, * If a peer entry with given MAC address already exists, * reuse the peer and reset the state of peer. */ - peer = dp_peer_can_reuse(vdev, peer_mac_addr); + peer = dp_peer_can_reuse(vdev, peer_mac_addr, peer_type); if (peer) { - dp_peer_vdev_list_add(soc, vdev, peer); - - dp_peer_find_hash_add(soc, peer); qdf_atomic_init(&peer->is_default_route_set); dp_peer_cleanup(vdev, peer); - for (i = 0; i < DP_MAX_TIDS; i++) - qdf_spinlock_create(&peer->rx_tid[i].tid_lock); + dp_peer_vdev_list_add(soc, vdev, peer); + dp_peer_find_hash_add(soc, peer); + + dp_peer_rx_tids_create(peer); + if (IS_MLO_DP_MLD_PEER(peer)) + dp_mld_peer_init_link_peers_info(peer); qdf_spin_lock_bh(&soc->ast_lock); dp_peer_delete_ast_entries(soc, peer); @@ -6474,6 +6507,7 @@ dp_peer_create_wifi3(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, /* store provided params */ peer->vdev = vdev; + DP_PEER_SET_TYPE(peer, peer_type); /* get the vdev reference for new peer */ dp_vdev_get_ref(soc, vdev, DP_MOD_ID_CHILD); @@ -6534,8 +6568,9 @@ dp_peer_create_wifi3(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, peer->sta_self_peer = 1; } - for (i = 0; i < DP_MAX_TIDS; i++) - qdf_spinlock_create(&peer->rx_tid[i].tid_lock); + dp_peer_rx_tids_create(peer); + if (IS_MLO_DP_MLD_PEER(peer)) + dp_mld_peer_init_link_peers_info(peer); peer->valid = 1; dp_local_peer_id_alloc(pdev, peer); @@ -6584,6 +6619,90 @@ dp_peer_create_wifi3(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, return QDF_STATUS_SUCCESS; } +#ifdef WLAN_FEATURE_11BE_MLO +QDF_STATUS dp_peer_mlo_setup( + struct dp_soc *soc, + struct dp_peer *peer, + uint8_t vdev_id, + struct cdp_peer_setup_info *setup_info) +{ + struct dp_peer *mld_peer = NULL; + + /* Non-MLO connection, do nothing */ + if (!setup_info || !setup_info->mld_peer_mac) + return QDF_STATUS_SUCCESS; + + /* To do: remove this check if link/mld peer mac_addr allow to same */ + if (!qdf_mem_cmp(setup_info->mld_peer_mac, peer->mac_addr.raw, + QDF_MAC_ADDR_SIZE)) { + dp_peer_err("Same mac addres for link/mld peer"); + return QDF_STATUS_E_FAILURE; + } + + /* if this is the first assoc link */ + if (setup_info->is_assoc_link) + /* create MLD peer */ + dp_peer_create_wifi3((struct cdp_soc_t *)soc, + vdev_id, + setup_info->mld_peer_mac, + CDP_MLD_PEER_TYPE); + + peer->assoc_link = setup_info->is_assoc_link; + peer->primary_link = setup_info->is_primary_link; + mld_peer = dp_peer_find_hash_find(soc, + setup_info->mld_peer_mac, + 0, DP_VDEV_ALL, DP_MOD_ID_CDP); + if (mld_peer) { + if (setup_info->is_assoc_link) { + /* assign rx_tid to mld peer */ + mld_peer->rx_tid = peer->rx_tid; + /* no cdp_peer_setup for MLD peer, + * set it for addba processing + */ + qdf_atomic_set(&mld_peer->is_default_route_set, 1); + } else { + /* free link peer origial rx_tids mem */ + dp_peer_rx_tids_destroy(peer); + /* assign mld peer rx_tid to link peer */ + peer->rx_tid = mld_peer->rx_tid; + } + + if (setup_info->is_primary_link && + !setup_info->is_assoc_link) { + /* + * if first link is not the primary link, + * then need to change mld_peer->vdev as + * primary link dp_vdev is not same one + * during mld peer creation. + */ + + /* relase the ref to original dp_vdev */ + dp_vdev_unref_delete(soc, mld_peer->vdev, + DP_MOD_ID_CDP); + /* + * get the ref to new dp_vdev, + * increase dp_vdev ref_cnt + */ + mld_peer->vdev = dp_vdev_get_ref_by_id(soc, vdev_id, + DP_MOD_ID_CDP); + } + + /* associate mld and link peer */ + dp_link_peer_add_mld_peer(peer, mld_peer); + dp_mld_peer_add_link_peer(mld_peer, peer); + + dp_peer_unref_delete(mld_peer, DP_MOD_ID_CDP); + } else { + peer->mld_peer = NULL; + dp_err("mld peer" QDF_MAC_ADDR_FMT "not found!", + QDF_MAC_ADDR_REF(setup_info->mld_peer_mac)); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} +#endif + /* * dp_vdev_get_default_reo_hash() - get reo dest ring and hash values for a vdev * @vdev: Datapath VDEV handle @@ -6707,12 +6826,14 @@ static void dp_peer_setup_get_reo_hash(struct dp_vdev *vdev, * @soc_hdl: soc handle object * @vdev_id : vdev_id of vdev object * @peer_mac: Peer's mac address + * @peer_setup_info: peer setup info for MLO * * Return: QDF_STATUS */ static QDF_STATUS dp_peer_setup_wifi3(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, - uint8_t *peer_mac) + uint8_t *peer_mac, + struct cdp_peer_setup_info *setup_info) { struct dp_soc *soc = (struct dp_soc *)soc_hdl; struct dp_pdev *pdev; @@ -6767,6 +6888,12 @@ dp_peer_setup_wifi3(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, qdf_atomic_set(&peer->is_default_route_set, 1); + status = dp_peer_mlo_setup(soc, peer, vdev->vdev_id, setup_info); + if (QDF_IS_STATUS_ERROR(status)) { + dp_peer_err("peer mlo setup failed"); + qdf_assert_always(0); + } + if (vdev_opmode != wlan_op_mode_monitor) dp_peer_rx_init(pdev, peer); @@ -7275,7 +7402,6 @@ void dp_peer_unref_delete(struct dp_peer *peer, enum dp_mod_id mod_id) struct cdp_peer_cookie peer_cookie; struct dp_peer *tmp_peer; bool found = false; - int tid = 0; if (mod_id > DP_MOD_ID_RX) QDF_ASSERT(qdf_atomic_dec_return(&peer->mod_refs[mod_id]) >= 0); @@ -7345,9 +7471,6 @@ void dp_peer_unref_delete(struct dp_peer *peer, enum dp_mod_id mod_id) dp_peer_cleanup(vdev, peer); dp_monitor_peer_detach(soc, peer); - for (tid = 0; tid < DP_MAX_TIDS; tid++) - qdf_spinlock_destroy(&peer->rx_tid[tid].tid_lock); - qdf_spinlock_destroy(&peer->peer_state_lock); qdf_mem_free(peer); @@ -7428,6 +7551,8 @@ static QDF_STATUS dp_peer_delete_wifi3(struct cdp_soc_t *soc_hdl, dp_peer_vdev_list_remove(soc, vdev, peer); + dp_peer_mlo_delete(soc, peer); + qdf_spin_lock_bh(&soc->inactive_peer_list_lock); TAILQ_INSERT_TAIL(&soc->inactive_peer_list, peer, inactive_list_elem); diff --git a/dp/wifi3.0/dp_peer.c b/dp/wifi3.0/dp_peer.c index c81b74fbd7..11608b7a70 100644 --- a/dp/wifi3.0/dp_peer.c +++ b/dp/wifi3.0/dp_peer.c @@ -159,22 +159,6 @@ dp_set_ssn_valid_flag(struct hal_reo_cmd_params *params, valid); } -static inline int dp_peer_find_mac_addr_cmp( - union dp_align_mac_addr *mac_addr1, - union dp_align_mac_addr *mac_addr2) -{ - /* - * Intentionally use & rather than &&. - * because the operands are binary rather than generic boolean, - * the functionality is equivalent. - * Using && has the advantage of short-circuited evaluation, - * but using & has the advantage of no conditional branching, - * which is a more significant benefit. - */ - return !((mac_addr1->align4.bytes_abcd == mac_addr2->align4.bytes_abcd) - & (mac_addr1->align4.bytes_ef == mac_addr2->align4.bytes_ef)); -} - QDF_STATUS dp_peer_ast_table_attach(struct dp_soc *soc) { uint32_t max_ast_index; @@ -244,6 +228,7 @@ static int dp_log2_ceil(unsigned int value) #define DP_AST_HASH_LOAD_MULT 2 #define DP_AST_HASH_LOAD_SHIFT 0 +#ifdef WLAN_FEATURE_11BE_MLO /* * dp_peer_find_hash_attach() - allocate memory for peer_hash table * @soc: soc handle @@ -261,6 +246,327 @@ static QDF_STATUS dp_peer_find_hash_attach(struct dp_soc *soc) log2 = dp_log2_ceil(hash_elems); hash_elems = 1 << log2; + soc->peer_hash.mask = hash_elems - 1; + soc->peer_hash.idx_bits = log2; + soc->mld_peer_hash.mask = hash_elems - 1; + soc->mld_peer_hash.idx_bits = log2; + /* allocate an array of TAILQ peer object lists */ + soc->peer_hash.bins = qdf_mem_malloc( + hash_elems * sizeof(TAILQ_HEAD(anonymous_tail_q, dp_peer))); + if (!soc->peer_hash.bins) + return QDF_STATUS_E_NOMEM; + + soc->mld_peer_hash.bins = qdf_mem_malloc( + hash_elems * sizeof(TAILQ_HEAD(anonymous_tail_q1, dp_peer))); + if (!soc->mld_peer_hash.bins) { + qdf_mem_free(soc->peer_hash.bins); + return QDF_STATUS_E_NOMEM; + } + + for (i = 0; i < hash_elems; i++) { + TAILQ_INIT(&soc->peer_hash.bins[i]); + TAILQ_INIT(&soc->mld_peer_hash.bins[i]); + } + + qdf_spinlock_create(&soc->peer_hash_lock); + qdf_spinlock_create(&soc->mld_peer_hash_lock); + + return QDF_STATUS_SUCCESS; +} + +/* + * dp_peer_find_hash_detach() - cleanup memory for peer_hash table + * @soc: soc handle + * + * return: none + */ +static void dp_peer_find_hash_detach(struct dp_soc *soc) +{ + if (soc->peer_hash.bins) { + qdf_mem_free(soc->peer_hash.bins); + soc->peer_hash.bins = NULL; + qdf_spinlock_destroy(&soc->peer_hash_lock); + } + + if (soc->mld_peer_hash.bins) { + qdf_mem_free(soc->mld_peer_hash.bins); + soc->mld_peer_hash.bins = NULL; + qdf_spinlock_destroy(&soc->mld_peer_hash_lock); + } +} + +static inline unsigned dp_peer_find_hash_index(struct dp_soc *soc, + union dp_align_mac_addr *mac_addr, + enum cdp_peer_type peer_type) +{ + unsigned index; + + index = + mac_addr->align2.bytes_ab ^ + mac_addr->align2.bytes_cd ^ + mac_addr->align2.bytes_ef; + if (peer_type == CDP_LINK_PEER_TYPE) { + index ^= index >> soc->peer_hash.idx_bits; + index &= soc->peer_hash.mask; + } else if (peer_type == CDP_MLD_PEER_TYPE) { + index ^= index >> soc->mld_peer_hash.idx_bits; + index &= soc->mld_peer_hash.mask; + } else { + dp_err("unknown peer type %d", peer_type); + } + + return index; +} + +/* + * dp_peer_find_hash_add() - add peer to peer_hash_table + * @soc: soc handle + * @peer: peer handle + * @peer_type: link or mld peer + * + * return: none + */ +void dp_peer_find_hash_add(struct dp_soc *soc, struct dp_peer *peer) +{ + unsigned index; + + index = dp_peer_find_hash_index(soc, &peer->mac_addr, + peer->peer_type); + if (peer->peer_type == CDP_LINK_PEER_TYPE) { + qdf_spin_lock_bh(&soc->peer_hash_lock); + + if (QDF_IS_STATUS_ERROR(dp_peer_get_ref(soc, peer, + DP_MOD_ID_CONFIG))) { + dp_err("fail to get peer ref:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer->mac_addr.raw)); + qdf_spin_unlock_bh(&soc->peer_hash_lock); + return; + } + + /* + * It is important to add the new peer at the tail of + * peer list with the bin index. Together with having + * the hash_find function search from head to tail, + * this ensures that if two entries with the same MAC address + * are stored, the one added first will be found first. + */ + TAILQ_INSERT_TAIL(&soc->peer_hash.bins[index], peer, + hash_list_elem); + + qdf_spin_unlock_bh(&soc->peer_hash_lock); + } else if (peer->peer_type == CDP_MLD_PEER_TYPE) { + qdf_spin_lock_bh(&soc->mld_peer_hash_lock); + + if (QDF_IS_STATUS_ERROR(dp_peer_get_ref(soc, peer, + DP_MOD_ID_CONFIG))) { + dp_err("fail to get peer ref:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer->mac_addr.raw)); + qdf_spin_unlock_bh(&soc->mld_peer_hash_lock); + return; + } + TAILQ_INSERT_TAIL(&soc->mld_peer_hash.bins[index], peer, + hash_list_elem); + qdf_spin_unlock_bh(&soc->mld_peer_hash_lock); + } else { + dp_err("unknown peer type %d", peer->peer_type); + } +} + +/* + * dp_peer_find_hash_find() - returns peer from peer_hash_table matching + * vdev_id and mac_address + * @soc: soc handle + * @peer_mac_addr: peer mac address + * @mac_addr_is_aligned: is mac addr alligned + * @vdev_id: vdev_id + * @mod_id: id of module requesting reference + * + * return: peer in sucsess + * NULL in failure + */ +struct dp_peer *dp_peer_find_hash_find(struct dp_soc *soc, + uint8_t *peer_mac_addr, + int mac_addr_is_aligned, + uint8_t vdev_id, + enum dp_mod_id mod_id) +{ + union dp_align_mac_addr local_mac_addr_aligned, *mac_addr; + unsigned index; + struct dp_peer *peer; + + if (!soc->peer_hash.bins || !soc->mld_peer_hash.bins) + return NULL; + + if (mac_addr_is_aligned) { + mac_addr = (union dp_align_mac_addr *)peer_mac_addr; + } else { + qdf_mem_copy( + &local_mac_addr_aligned.raw[0], + peer_mac_addr, QDF_MAC_ADDR_SIZE); + mac_addr = &local_mac_addr_aligned; + } + /* search link peer table firstly */ + index = dp_peer_find_hash_index(soc, mac_addr, CDP_LINK_PEER_TYPE); + qdf_spin_lock_bh(&soc->peer_hash_lock); + TAILQ_FOREACH(peer, &soc->peer_hash.bins[index], hash_list_elem) { + if (dp_peer_find_mac_addr_cmp(mac_addr, &peer->mac_addr) == 0 && + ((peer->vdev->vdev_id == vdev_id) || + (vdev_id == DP_VDEV_ALL))) { + /* take peer reference before returning */ + if (dp_peer_get_ref(soc, peer, mod_id) != + QDF_STATUS_SUCCESS) + peer = NULL; + + qdf_spin_unlock_bh(&soc->peer_hash_lock); + return peer; + } + } + qdf_spin_unlock_bh(&soc->peer_hash_lock); + + /* search mld peer table if no link peer for given mac address */ + index = dp_peer_find_hash_index(soc, mac_addr, CDP_MLD_PEER_TYPE); + qdf_spin_lock_bh(&soc->mld_peer_hash_lock); + TAILQ_FOREACH(peer, &soc->mld_peer_hash.bins[index], hash_list_elem) { + /* do not check vdev ID for MLD peer */ + if (dp_peer_find_mac_addr_cmp(mac_addr, &peer->mac_addr) == 0) { + /* take peer reference before returning */ + if (dp_peer_get_ref(soc, peer, mod_id) != + QDF_STATUS_SUCCESS) + peer = NULL; + + qdf_spin_unlock_bh(&soc->mld_peer_hash_lock); + return peer; + } + } + qdf_spin_unlock_bh(&soc->mld_peer_hash_lock); + + return NULL; /* failure */ +} + +qdf_export_symbol(dp_peer_find_hash_find); + +/* + * dp_peer_find_hash_remove() - remove peer from peer_hash_table + * @soc: soc handle + * @peer: peer handle + * + * return: none + */ +void dp_peer_find_hash_remove(struct dp_soc *soc, struct dp_peer *peer) +{ + unsigned index; + struct dp_peer *tmppeer = NULL; + int found = 0; + + index = dp_peer_find_hash_index(soc, &peer->mac_addr, peer->peer_type); + + if (peer->peer_type == CDP_LINK_PEER_TYPE) { + /* Check if tail is not empty before delete*/ + QDF_ASSERT(!TAILQ_EMPTY(&soc->peer_hash.bins[index])); + + qdf_spin_lock_bh(&soc->peer_hash_lock); + TAILQ_FOREACH(tmppeer, &soc->peer_hash.bins[index], + hash_list_elem) { + if (tmppeer == peer) { + found = 1; + break; + } + } + QDF_ASSERT(found); + TAILQ_REMOVE(&soc->peer_hash.bins[index], peer, + hash_list_elem); + + dp_peer_unref_delete(peer, DP_MOD_ID_CONFIG); + qdf_spin_unlock_bh(&soc->peer_hash_lock); + } else if (peer->peer_type == CDP_MLD_PEER_TYPE) { + QDF_ASSERT(!TAILQ_EMPTY(&soc->mld_peer_hash.bins[index])); + + qdf_spin_lock_bh(&soc->mld_peer_hash_lock); + TAILQ_FOREACH(tmppeer, &soc->mld_peer_hash.bins[index], + hash_list_elem) { + if (tmppeer == peer) { + found = 1; + break; + } + } + QDF_ASSERT(found); + TAILQ_REMOVE(&soc->mld_peer_hash.bins[index], peer, + hash_list_elem); + + dp_peer_unref_delete(peer, DP_MOD_ID_CONFIG); + qdf_spin_unlock_bh(&soc->mld_peer_hash_lock); + } else { + dp_err("unknown peer type %d", peer->peer_type); + } +} + +/* + * dp_peer_exist_on_pdev - check if peer with mac address exist on pdev + * + * @soc: Datapath SOC handle + * @peer_mac_addr: peer mac address + * @mac_addr_is_aligned: is mac address aligned + * @pdev: Datapath PDEV handle + * + * Return: true if peer found else return false + */ +static bool dp_peer_exist_on_pdev(struct dp_soc *soc, + uint8_t *peer_mac_addr, + int mac_addr_is_aligned, + struct dp_pdev *pdev) +{ + union dp_align_mac_addr local_mac_addr_aligned, *mac_addr; + unsigned int index; + struct dp_peer *peer; + bool found = false; + + if (mac_addr_is_aligned) { + mac_addr = (union dp_align_mac_addr *)peer_mac_addr; + } else { + qdf_mem_copy( + &local_mac_addr_aligned.raw[0], + peer_mac_addr, QDF_MAC_ADDR_SIZE); + mac_addr = &local_mac_addr_aligned; + } + index = dp_peer_find_hash_index(soc, mac_addr, CDP_LINK_PEER_TYPE); + qdf_spin_lock_bh(&soc->peer_hash_lock); + TAILQ_FOREACH(peer, &soc->peer_hash.bins[index], hash_list_elem) { + if (dp_peer_find_mac_addr_cmp(mac_addr, &peer->mac_addr) == 0 && + (peer->vdev->pdev == pdev)) { + found = true; + break; + } + } + qdf_spin_unlock_bh(&soc->peer_hash_lock); + + if (found) + return found; + + index = dp_peer_find_hash_index(soc, mac_addr, CDP_MLD_PEER_TYPE); + qdf_spin_lock_bh(&soc->mld_peer_hash_lock); + TAILQ_FOREACH(peer, &soc->mld_peer_hash.bins[index], hash_list_elem) { + if (dp_peer_find_mac_addr_cmp(mac_addr, &peer->mac_addr) == 0 && + (peer->vdev->pdev == pdev)) { + found = true; + break; + } + } + qdf_spin_unlock_bh(&soc->mld_peer_hash_lock); + + return found; +} +#else +static QDF_STATUS dp_peer_find_hash_attach(struct dp_soc *soc) +{ + int i, hash_elems, log2; + + /* allocate the peer MAC address -> peer object hash table */ + hash_elems = soc->max_peers; + hash_elems *= DP_PEER_HASH_LOAD_MULT; + hash_elems >>= DP_PEER_HASH_LOAD_SHIFT; + log2 = dp_log2_ceil(hash_elems); + hash_elems = 1 << log2; + soc->peer_hash.mask = hash_elems - 1; soc->peer_hash.idx_bits = log2; /* allocate an array of TAILQ peer object lists */ @@ -276,12 +582,6 @@ static QDF_STATUS dp_peer_find_hash_attach(struct dp_soc *soc) return QDF_STATUS_SUCCESS; } -/* - * dp_peer_find_hash_detach() - cleanup memory for peer_hash table - * @soc: soc handle - * - * return: none - */ static void dp_peer_find_hash_detach(struct dp_soc *soc) { if (soc->peer_hash.bins) { @@ -291,8 +591,9 @@ static void dp_peer_find_hash_detach(struct dp_soc *soc) } } -static inline unsigned dp_peer_find_hash_index(struct dp_soc *soc, - union dp_align_mac_addr *mac_addr) +static inline unsigned dp_peer_find_hash_index( + struct dp_soc *soc, + union dp_align_mac_addr *mac_addr) { unsigned index; @@ -305,13 +606,6 @@ static inline unsigned dp_peer_find_hash_index(struct dp_soc *soc, return index; } -/* - * dp_peer_find_hash_add() - add peer to peer_hash_table - * @soc: soc handle - * @peer: peer handle - * - * return: none - */ void dp_peer_find_hash_add(struct dp_soc *soc, struct dp_peer *peer) { unsigned index; @@ -338,6 +632,103 @@ void dp_peer_find_hash_add(struct dp_soc *soc, struct dp_peer *peer) qdf_spin_unlock_bh(&soc->peer_hash_lock); } +struct dp_peer *dp_peer_find_hash_find( + struct dp_soc *soc, uint8_t *peer_mac_addr, + int mac_addr_is_aligned, uint8_t vdev_id, + enum dp_mod_id mod_id) +{ + union dp_align_mac_addr local_mac_addr_aligned, *mac_addr; + unsigned index; + struct dp_peer *peer; + + if (!soc->peer_hash.bins) + return NULL; + + if (mac_addr_is_aligned) { + mac_addr = (union dp_align_mac_addr *)peer_mac_addr; + } else { + qdf_mem_copy( + &local_mac_addr_aligned.raw[0], + peer_mac_addr, QDF_MAC_ADDR_SIZE); + mac_addr = &local_mac_addr_aligned; + } + index = dp_peer_find_hash_index(soc, mac_addr); + qdf_spin_lock_bh(&soc->peer_hash_lock); + TAILQ_FOREACH(peer, &soc->peer_hash.bins[index], hash_list_elem) { + if (dp_peer_find_mac_addr_cmp(mac_addr, &peer->mac_addr) == 0 && + ((peer->vdev->vdev_id == vdev_id) || + (vdev_id == DP_VDEV_ALL))) { + /* take peer reference before returning */ + if (dp_peer_get_ref(soc, peer, mod_id) != + QDF_STATUS_SUCCESS) + peer = NULL; + + qdf_spin_unlock_bh(&soc->peer_hash_lock); + return peer; + } + } + qdf_spin_unlock_bh(&soc->peer_hash_lock); + return NULL; /* failure */ +} + +qdf_export_symbol(dp_peer_find_hash_find); + +void dp_peer_find_hash_remove(struct dp_soc *soc, struct dp_peer *peer) +{ + unsigned index; + struct dp_peer *tmppeer = NULL; + int found = 0; + + index = dp_peer_find_hash_index(soc, &peer->mac_addr); + /* Check if tail is not empty before delete*/ + QDF_ASSERT(!TAILQ_EMPTY(&soc->peer_hash.bins[index])); + + qdf_spin_lock_bh(&soc->peer_hash_lock); + TAILQ_FOREACH(tmppeer, &soc->peer_hash.bins[index], hash_list_elem) { + if (tmppeer == peer) { + found = 1; + break; + } + } + QDF_ASSERT(found); + TAILQ_REMOVE(&soc->peer_hash.bins[index], peer, hash_list_elem); + + dp_peer_unref_delete(peer, DP_MOD_ID_CONFIG); + qdf_spin_unlock_bh(&soc->peer_hash_lock); +} + +static bool dp_peer_exist_on_pdev(struct dp_soc *soc, + uint8_t *peer_mac_addr, + int mac_addr_is_aligned, + struct dp_pdev *pdev) +{ + union dp_align_mac_addr local_mac_addr_aligned, *mac_addr; + unsigned int index; + struct dp_peer *peer; + bool found = false; + + if (mac_addr_is_aligned) { + mac_addr = (union dp_align_mac_addr *)peer_mac_addr; + } else { + qdf_mem_copy( + &local_mac_addr_aligned.raw[0], + peer_mac_addr, QDF_MAC_ADDR_SIZE); + mac_addr = &local_mac_addr_aligned; + } + index = dp_peer_find_hash_index(soc, mac_addr); + qdf_spin_lock_bh(&soc->peer_hash_lock); + TAILQ_FOREACH(peer, &soc->peer_hash.bins[index], hash_list_elem) { + if (dp_peer_find_mac_addr_cmp(mac_addr, &peer->mac_addr) == 0 && + (peer->vdev->pdev == pdev)) { + found = true; + break; + } + } + qdf_spin_unlock_bh(&soc->peer_hash_lock); + return found; +} +#endif/* WLAN_FEATURE_11BE_MLO */ + /* * dp_peer_vdev_list_add() - add peer into vdev's peer list * @soc: soc handle @@ -349,6 +740,10 @@ void dp_peer_find_hash_add(struct dp_soc *soc, struct dp_peer *peer) void dp_peer_vdev_list_add(struct dp_soc *soc, struct dp_vdev *vdev, struct dp_peer *peer) { + /* only link peer will be added to vdev peer list */ + if (IS_MLO_DP_MLD_PEER(peer)) + return; + qdf_spin_lock_bh(&vdev->peer_list_lock); if (QDF_IS_STATUS_ERROR(dp_peer_get_ref(soc, peer, DP_MOD_ID_CONFIG))) { dp_err("unable to get peer ref at MAP mac: "QDF_MAC_ADDR_FMT, @@ -381,6 +776,10 @@ void dp_peer_vdev_list_remove(struct dp_soc *soc, struct dp_vdev *vdev, uint8_t found = 0; struct dp_peer *tmppeer = NULL; + /* only link peer will be added to vdev peer list */ + if (IS_MLO_DP_MLD_PEER(peer)) + return; + qdf_spin_lock_bh(&vdev->peer_list_lock); TAILQ_FOREACH(tmppeer, &peer->vdev->peer_list, peer_list_elem) { if (tmppeer == peer) { @@ -456,47 +855,6 @@ void dp_peer_find_id_to_obj_remove(struct dp_soc *soc, qdf_spin_unlock_bh(&soc->peer_map_lock); } -/* - * dp_peer_exist_on_pdev - check if peer with mac address exist on pdev - * - * @soc: Datapath SOC handle - * @peer_mac_addr: peer mac address - * @mac_addr_is_aligned: is mac address aligned - * @pdev: Datapath PDEV handle - * - * Return: true if peer found else return false - */ -static bool dp_peer_exist_on_pdev(struct dp_soc *soc, - uint8_t *peer_mac_addr, - int mac_addr_is_aligned, - struct dp_pdev *pdev) -{ - union dp_align_mac_addr local_mac_addr_aligned, *mac_addr; - unsigned int index; - struct dp_peer *peer; - bool found = false; - - if (mac_addr_is_aligned) { - mac_addr = (union dp_align_mac_addr *)peer_mac_addr; - } else { - qdf_mem_copy( - &local_mac_addr_aligned.raw[0], - peer_mac_addr, QDF_MAC_ADDR_SIZE); - mac_addr = &local_mac_addr_aligned; - } - index = dp_peer_find_hash_index(soc, mac_addr); - qdf_spin_lock_bh(&soc->peer_hash_lock); - TAILQ_FOREACH(peer, &soc->peer_hash.bins[index], hash_list_elem) { - if (dp_peer_find_mac_addr_cmp(mac_addr, &peer->mac_addr) == 0 && - (peer->vdev->pdev == pdev)) { - found = true; - break; - } - } - qdf_spin_unlock_bh(&soc->peer_hash_lock); - return found; -} - #ifdef FEATURE_MEC /** * dp_peer_mec_hash_attach() - Allocate and initialize MEC Hash Table @@ -1965,89 +2323,6 @@ static int dp_peer_ast_free_entry_by_mac(struct dp_soc *soc, return QDF_STATUS_SUCCESS; } -/* - * dp_peer_find_hash_find() - returns peer from peer_hash_table matching - * vdev_id and mac_address - * @soc: soc handle - * @peer_mac_addr: peer mac address - * @mac_addr_is_aligned: is mac addr alligned - * @vdev_id: vdev_id - * @mod_id: id of module requesting reference - * - * return: peer in sucsess - * NULL in failure - */ -struct dp_peer *dp_peer_find_hash_find(struct dp_soc *soc, - uint8_t *peer_mac_addr, int mac_addr_is_aligned, uint8_t vdev_id, - enum dp_mod_id mod_id) -{ - union dp_align_mac_addr local_mac_addr_aligned, *mac_addr; - unsigned index; - struct dp_peer *peer; - - if (!soc->peer_hash.bins) - return NULL; - - if (mac_addr_is_aligned) { - mac_addr = (union dp_align_mac_addr *) peer_mac_addr; - } else { - qdf_mem_copy( - &local_mac_addr_aligned.raw[0], - peer_mac_addr, QDF_MAC_ADDR_SIZE); - mac_addr = &local_mac_addr_aligned; - } - index = dp_peer_find_hash_index(soc, mac_addr); - qdf_spin_lock_bh(&soc->peer_hash_lock); - TAILQ_FOREACH(peer, &soc->peer_hash.bins[index], hash_list_elem) { - if (dp_peer_find_mac_addr_cmp(mac_addr, &peer->mac_addr) == 0 && - ((peer->vdev->vdev_id == vdev_id) || - (vdev_id == DP_VDEV_ALL))) { - /* take peer reference before returning */ - if (dp_peer_get_ref(soc, peer, mod_id) != - QDF_STATUS_SUCCESS) - peer = NULL; - - qdf_spin_unlock_bh(&soc->peer_hash_lock); - return peer; - } - } - qdf_spin_unlock_bh(&soc->peer_hash_lock); - return NULL; /* failure */ -} - -qdf_export_symbol(dp_peer_find_hash_find); - -/* - * dp_peer_find_hash_remove() - remove peer from peer_hash_table - * @soc: soc handle - * @peer: peer handle - * - * return: none - */ -void dp_peer_find_hash_remove(struct dp_soc *soc, struct dp_peer *peer) -{ - unsigned index; - struct dp_peer *tmppeer = NULL; - int found = 0; - - index = dp_peer_find_hash_index(soc, &peer->mac_addr); - /* Check if tail is not empty before delete*/ - QDF_ASSERT(!TAILQ_EMPTY(&soc->peer_hash.bins[index])); - - qdf_spin_lock_bh(&soc->peer_hash_lock); - TAILQ_FOREACH(tmppeer, &soc->peer_hash.bins[index], hash_list_elem) { - if (tmppeer == peer) { - found = 1; - break; - } - } - QDF_ASSERT(found); - TAILQ_REMOVE(&soc->peer_hash.bins[index], peer, hash_list_elem); - - dp_peer_unref_delete(peer, DP_MOD_ID_CONFIG); - qdf_spin_unlock_bh(&soc->peer_hash_lock); -} - void dp_peer_find_hash_erase(struct dp_soc *soc) { int i; @@ -2573,6 +2848,149 @@ static bool dp_get_peer_vdev_roaming_in_progress(struct dp_peer *peer) return is_roaming; } +#ifdef WLAN_FEATURE_11BE_MLO +/** + * dp_rx_tid_setup_allow() - check if rx_tid and reo queue desc + setup is necessary + * @peer: DP peer handle + * + * Return: true - allow, false - disallow + */ +static inline +bool dp_rx_tid_setup_allow(struct dp_peer *peer) +{ + if (IS_MLO_DP_LINK_PEER(peer) && !peer->assoc_link) + return false; + + return true; +} + +/** + * dp_rx_tid_update_allow() - check if rx_tid update needed + * @peer: DP peer handle + * + * Return: true - allow, false - disallow + */ +static inline +bool dp_rx_tid_update_allow(struct dp_peer *peer) +{ + /* not as expected for MLO connection link peer */ + if (IS_MLO_DP_LINK_PEER(peer)) { + QDF_BUG(0); + return false; + } + + return true; +} + +/** + * dp_peer_rx_reorder_queue_setup() - Send reo queue setup wmi cmd to FW + per peer type + * @soc: DP Soc handle + * @peer: dp peer to operate on + * @tid: TID + * @ba_window_size: BlockAck window size + * + * Return: 0 - success, others - failure + */ +static QDF_STATUS dp_peer_rx_reorder_queue_setup(struct dp_soc *soc, + struct dp_peer *peer, + int tid, + uint32_t ba_window_size) +{ + uint8_t i; + struct dp_mld_link_peers link_peers_info; + struct dp_peer *link_peer; + struct dp_rx_tid *rx_tid; + + if (IS_MLO_DP_MLD_PEER(peer)) { + /* get link peers with reference */ + dp_get_link_peers_ref_from_mld_peer(soc, peer, + &link_peers_info, + DP_MOD_ID_CDP); + /* send WMI cmd to each link peers */ + for (i = 0; i < link_peers_info.num_links; i++) { + link_peer = link_peers_info.link_peers[i]; + rx_tid = &link_peer->rx_tid[tid]; + if (soc->cdp_soc.ol_ops->peer_rx_reorder_queue_setup) { + if (soc->cdp_soc.ol_ops-> + peer_rx_reorder_queue_setup( + soc->ctrl_psoc, + link_peer->vdev->pdev->pdev_id, + link_peer->vdev->vdev_id, + link_peer->mac_addr.raw, + rx_tid->hw_qdesc_paddr, + tid, tid, + 1, ba_window_size)) { + dp_peer_err("%pK: Failed to send reo queue setup to FW - tid %d\n", + soc, tid); + return QDF_STATUS_E_FAILURE; + } + } + } + /* release link peers reference */ + dp_release_link_peers_ref(&link_peers_info, DP_MOD_ID_CDP); + } else if (peer->peer_type == CDP_LINK_PEER_TYPE) { + rx_tid = &peer->rx_tid[tid]; + if (soc->cdp_soc.ol_ops->peer_rx_reorder_queue_setup) { + if (soc->cdp_soc.ol_ops-> + peer_rx_reorder_queue_setup( + soc->ctrl_psoc, + peer->vdev->pdev->pdev_id, + peer->vdev->vdev_id, + peer->mac_addr.raw, + rx_tid->hw_qdesc_paddr, + tid, tid, + 1, ba_window_size)) { + dp_peer_err("%pK: Failed to send reo queue setup to FW - tid %d\n", + soc, tid); + return QDF_STATUS_E_FAILURE; + } + } + } else { + dp_peer_err("invalid peer type %d", peer->peer_type); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} +#else +static inline +bool dp_rx_tid_setup_allow(struct dp_peer *peer) +{ + return true; +} + +static inline +bool dp_rx_tid_update_allow(struct dp_peer *peer) +{ + return true; +} + +static QDF_STATUS dp_peer_rx_reorder_queue_setup(struct dp_soc *soc, + struct dp_peer *peer, + int tid, + uint32_t ba_window_size) +{ + struct dp_rx_tid *rx_tid = &peer->rx_tid[tid]; + + if (soc->cdp_soc.ol_ops->peer_rx_reorder_queue_setup) { + if (soc->cdp_soc.ol_ops->peer_rx_reorder_queue_setup( + soc->ctrl_psoc, + peer->vdev->pdev->pdev_id, + peer->vdev->vdev_id, + peer->mac_addr.raw, rx_tid->hw_qdesc_paddr, tid, tid, + 1, ba_window_size)) { + dp_peer_err("%pK: Failed to send reo queue setup to FW - tid %d\n", + soc, tid); + return QDF_STATUS_E_FAILURE; + } + } + + return QDF_STATUS_SUCCESS; +} +#endif + QDF_STATUS dp_rx_tid_update_wifi3(struct dp_peer *peer, int tid, uint32_t ba_window_size, uint32_t start_seq, bool bar_update) @@ -2581,6 +2999,12 @@ QDF_STATUS dp_rx_tid_update_wifi3(struct dp_peer *peer, int tid, uint32_t struct dp_soc *soc = peer->vdev->pdev->soc; struct hal_reo_cmd_params params; + if (!dp_rx_tid_update_allow(peer)) { + dp_peer_err("skip tid update for peer:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer->mac_addr.raw)); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_zero(¶ms, sizeof(params)); params.std.need_status = 1; @@ -2607,11 +3031,9 @@ QDF_STATUS dp_rx_tid_update_wifi3(struct dp_peer *peer, int tid, uint32_t if (dp_get_peer_vdev_roaming_in_progress(peer)) return QDF_STATUS_E_PERM; - if (soc->cdp_soc.ol_ops->peer_rx_reorder_queue_setup && !bar_update) - soc->cdp_soc.ol_ops->peer_rx_reorder_queue_setup( - soc->ctrl_psoc, peer->vdev->pdev->pdev_id, - peer->vdev->vdev_id, peer->mac_addr.raw, - rx_tid->hw_qdesc_paddr, tid, tid, 1, ba_window_size); + if (!bar_update) + dp_peer_rx_reorder_queue_setup(soc, peer, + tid, ba_window_size); return QDF_STATUS_SUCCESS; } @@ -2766,7 +3188,6 @@ static inline int dp_reo_desc_addr_chk(qdf_dma_addr_t dma_addr) } #endif - /* * dp_rx_tid_setup_wifi3() – Setup receive TID state * @peer: Datapath peer handle @@ -2787,11 +3208,17 @@ QDF_STATUS dp_rx_tid_setup_wifi3(struct dp_peer *peer, int tid, int hal_pn_type; void *hw_qdesc_vaddr; uint32_t alloc_tries = 0; - QDF_STATUS err = QDF_STATUS_SUCCESS; + QDF_STATUS status = QDF_STATUS_SUCCESS; if (!qdf_atomic_read(&peer->is_default_route_set)) return QDF_STATUS_E_FAILURE; + if (!dp_rx_tid_setup_allow(peer)) { + dp_peer_info("skip rx tid setup for peer" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer->mac_addr.raw)); + goto send_wmi_reo_cmd; + } + rx_tid->ba_win_size = ba_window_size; if (rx_tid->hw_qdesc_vaddr_unaligned) return dp_rx_tid_update_wifi3(peer, tid, ba_window_size, @@ -2906,30 +3333,22 @@ try_desc_alloc: } else { dp_peer_err("%pK: Rx tid HW desc alloc failed (lowmem): tid %d", soc, tid); - err = QDF_STATUS_E_NOMEM; + status = QDF_STATUS_E_NOMEM; goto error; } } if (dp_get_peer_vdev_roaming_in_progress(peer)) { - err = QDF_STATUS_E_PERM; + status = QDF_STATUS_E_PERM; goto error; } - if (soc->cdp_soc.ol_ops->peer_rx_reorder_queue_setup) { - if (soc->cdp_soc.ol_ops->peer_rx_reorder_queue_setup( - soc->ctrl_psoc, - peer->vdev->pdev->pdev_id, - peer->vdev->vdev_id, - peer->mac_addr.raw, rx_tid->hw_qdesc_paddr, tid, tid, - 1, ba_window_size)) { - dp_peer_err("%pK: Failed to send reo queue setup to FW - tid %d\n", - soc, tid); - err = QDF_STATUS_E_FAILURE; - goto error; - } - } - return 0; +send_wmi_reo_cmd: + status = dp_peer_rx_reorder_queue_setup(soc, peer, + tid, ba_window_size); + if (QDF_IS_STATUS_SUCCESS(status)) + return status; + error: if (rx_tid->hw_qdesc_vaddr_unaligned) { if (dp_reo_desc_addr_chk(rx_tid->hw_qdesc_paddr) == @@ -2942,7 +3361,7 @@ error: qdf_mem_free(rx_tid->hw_qdesc_vaddr_unaligned); rx_tid->hw_qdesc_vaddr_unaligned = NULL; } - return err; + return status; } #ifdef REO_DESC_DEFER_FREE @@ -3280,6 +3699,64 @@ static void dp_peer_setup_remaining_tids(struct dp_peer *peer) static void dp_peer_setup_remaining_tids(struct dp_peer *peer) {}; #endif +#ifdef WLAN_FEATURE_11BE_MLO +/** + * dp_peer_rx_tids_init() - initialize each tids in peer + * @peer: peer pointer + * + * Return: None + */ +static void dp_peer_rx_tids_init(struct dp_peer *peer) +{ + int tid; + struct dp_rx_tid *rx_tid; + + /* if not first assoc link peer or MLD peer, + * not to initialize rx_tids again. + */ + if ((IS_MLO_DP_LINK_PEER(peer) && !peer->assoc_link) || + IS_MLO_DP_MLD_PEER(peer)) + return; + + for (tid = 0; tid < DP_MAX_TIDS; tid++) { + rx_tid = &peer->rx_tid[tid]; + rx_tid->array = &rx_tid->base; + rx_tid->base.head = NULL; + rx_tid->base.tail = NULL; + rx_tid->tid = tid; + rx_tid->defrag_timeout_ms = 0; + rx_tid->ba_win_size = 0; + rx_tid->ba_status = DP_RX_BA_INACTIVE; + + rx_tid->defrag_waitlist_elem.tqe_next = NULL; + rx_tid->defrag_waitlist_elem.tqe_prev = NULL; + rx_tid->defrag_peer = + IS_MLO_DP_LINK_PEER(peer) ? peer->mld_peer : peer; + } +} +#else +static void dp_peer_rx_tids_init(struct dp_peer *peer) +{ + int tid; + struct dp_rx_tid *rx_tid; + + for (tid = 0; tid < DP_MAX_TIDS; tid++) { + rx_tid = &peer->rx_tid[tid]; + rx_tid->array = &rx_tid->base; + rx_tid->base.head = NULL; + rx_tid->base.tail = NULL; + rx_tid->tid = tid; + rx_tid->defrag_timeout_ms = 0; + rx_tid->ba_win_size = 0; + rx_tid->ba_status = DP_RX_BA_INACTIVE; + + rx_tid->defrag_waitlist_elem.tqe_next = NULL; + rx_tid->defrag_waitlist_elem.tqe_prev = NULL; + rx_tid->defrag_peer = peer; + } +} +#endif + /* * dp_peer_rx_init() – Initialize receive TID state * @pdev: Datapath pdev @@ -3288,20 +3765,7 @@ static void dp_peer_setup_remaining_tids(struct dp_peer *peer) {}; */ void dp_peer_rx_init(struct dp_pdev *pdev, struct dp_peer *peer) { - int tid; - struct dp_rx_tid *rx_tid; - for (tid = 0; tid < DP_MAX_TIDS; tid++) { - rx_tid = &peer->rx_tid[tid]; - rx_tid->array = &rx_tid->base; - rx_tid->base.head = rx_tid->base.tail = NULL; - rx_tid->tid = tid; - rx_tid->defrag_timeout_ms = 0; - rx_tid->ba_win_size = 0; - rx_tid->ba_status = DP_RX_BA_INACTIVE; - - rx_tid->defrag_waitlist_elem.tqe_next = NULL; - rx_tid->defrag_waitlist_elem.tqe_prev = NULL; - } + dp_peer_rx_tids_init(peer); peer->active_ba_session_cnt = 0; peer->hw_buffer_size = 0; @@ -3341,6 +3805,9 @@ void dp_peer_rx_cleanup(struct dp_vdev *vdev, struct dp_peer *peer) uint32_t tid_delete_mask = 0; dp_info("Remove tids for peer: %pK", peer); + if (IS_MLO_DP_LINK_PEER(peer)) + return; + for (tid = 0; tid < DP_MAX_TIDS; tid++) { struct dp_rx_tid *rx_tid = &peer->rx_tid[tid]; @@ -3390,6 +3857,13 @@ void dp_peer_cleanup(struct dp_vdev *vdev, struct dp_peer *peer) /* cleanup the Rx reorder queues for this peer */ dp_peer_rx_cleanup(vdev, peer); + dp_peer_rx_tids_destroy(peer); + + if (IS_MLO_DP_LINK_PEER(peer)) + dp_link_peer_del_mld_peer(peer); + if (IS_MLO_DP_MLD_PEER(peer)) + dp_mld_peer_deinit_link_peers_info(peer); + qdf_mem_copy(vdev_mac_addr, vdev->mac_addr.raw, QDF_MAC_ADDR_SIZE); @@ -3472,9 +3946,10 @@ int dp_addba_resp_tx_completion_wifi3(struct cdp_soc_t *cdp_soc, uint16_t vdev_id, uint8_t tid, int status) { - struct dp_peer *peer = dp_peer_find_hash_find((struct dp_soc *)cdp_soc, - peer_mac, 0, vdev_id, - DP_MOD_ID_CDP); + struct dp_peer *peer = dp_peer_get_tgt_peer_hash_find( + (struct dp_soc *)cdp_soc, + peer_mac, 0, vdev_id, + DP_MOD_ID_CDP); struct dp_rx_tid *rx_tid = NULL; if (!peer) { @@ -3666,9 +4141,9 @@ int dp_addba_requestprocess_wifi3(struct cdp_soc_t *cdp_soc, QDF_STATUS status = QDF_STATUS_SUCCESS; struct dp_rx_tid *rx_tid = NULL; struct dp_soc *soc = (struct dp_soc *)cdp_soc; - struct dp_peer *peer = dp_peer_find_hash_find(soc, - peer_mac, 0, vdev_id, - DP_MOD_ID_CDP); + struct dp_peer *peer = dp_peer_get_tgt_peer_hash_find(soc, peer_mac, + 0, vdev_id, + DP_MOD_ID_CDP); if (!peer) { dp_peer_debug("%pK: Peer is NULL!\n", cdp_soc); @@ -3756,9 +4231,10 @@ QDF_STATUS dp_set_addba_response(struct cdp_soc_t *cdp_soc, uint8_t *peer_mac, uint16_t vdev_id, uint8_t tid, uint16_t statuscode) { - struct dp_peer *peer = dp_peer_find_hash_find((struct dp_soc *)cdp_soc, - peer_mac, 0, vdev_id, - DP_MOD_ID_CDP); + struct dp_peer *peer = dp_peer_get_tgt_peer_hash_find( + (struct dp_soc *)cdp_soc, + peer_mac, 0, vdev_id, + DP_MOD_ID_CDP); struct dp_rx_tid *rx_tid; if (!peer) { @@ -3790,9 +4266,10 @@ int dp_delba_process_wifi3(struct cdp_soc_t *cdp_soc, uint8_t *peer_mac, { QDF_STATUS status = QDF_STATUS_SUCCESS; struct dp_rx_tid *rx_tid; - struct dp_peer *peer = dp_peer_find_hash_find((struct dp_soc *)cdp_soc, - peer_mac, 0, vdev_id, - DP_MOD_ID_CDP); + struct dp_peer *peer = dp_peer_get_tgt_peer_hash_find( + (struct dp_soc *)cdp_soc, + peer_mac, 0, vdev_id, + DP_MOD_ID_CDP); if (!peer) { dp_peer_debug("%pK: Peer is NULL!\n", cdp_soc); @@ -3840,9 +4317,10 @@ int dp_delba_tx_completion_wifi3(struct cdp_soc_t *cdp_soc, uint8_t *peer_mac, { QDF_STATUS ret = QDF_STATUS_SUCCESS; struct dp_rx_tid *rx_tid = NULL; - struct dp_peer *peer = dp_peer_find_hash_find((struct dp_soc *)cdp_soc, - peer_mac, 0, vdev_id, - DP_MOD_ID_CDP); + struct dp_peer *peer = dp_peer_get_tgt_peer_hash_find( + (struct dp_soc *)cdp_soc, + peer_mac, 0, vdev_id, + DP_MOD_ID_CDP); if (!peer) { dp_peer_debug("%pK: Peer is NULL!", cdp_soc); @@ -4252,6 +4730,77 @@ dp_rx_delba_ind_handler(void *soc_handle, uint16_t peer_id, } #ifdef DP_PEER_EXTENDED_API +#ifdef WLAN_FEATURE_11BE_MLO +QDF_STATUS dp_register_peer(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + struct ol_txrx_desc_type *sta_desc) +{ + struct dp_peer *peer; + struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl); + + peer = dp_peer_find_hash_find(soc, sta_desc->peer_addr.bytes, + 0, DP_VDEV_ALL, DP_MOD_ID_CDP); + + if (!peer) + return QDF_STATUS_E_FAULT; + + qdf_spin_lock_bh(&peer->peer_info_lock); + peer->state = OL_TXRX_PEER_STATE_CONN; + qdf_spin_unlock_bh(&peer->peer_info_lock); + + /* For MLO connection, no RX packet to link peer */ + if (!IS_MLO_DP_LINK_PEER(peer)) + dp_rx_flush_rx_cached(peer, false); + + if (IS_MLO_DP_LINK_PEER(peer) && peer->assoc_link) { + dp_peer_info("register for mld peer" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer->mld_peer->mac_addr.raw)); + qdf_spin_lock_bh(&peer->mld_peer->peer_info_lock); + peer->mld_peer->state = peer->state; + qdf_spin_unlock_bh(&peer->mld_peer->peer_info_lock); + dp_rx_flush_rx_cached(peer->mld_peer, false); + } + + dp_peer_unref_delete(peer, DP_MOD_ID_CDP); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS dp_peer_state_update(struct cdp_soc_t *soc_hdl, uint8_t *peer_mac, + enum ol_txrx_peer_state state) +{ + struct dp_peer *peer; + struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl); + + peer = dp_peer_find_hash_find(soc, peer_mac, 0, DP_VDEV_ALL, + DP_MOD_ID_CDP); + if (!peer) { + dp_peer_err("%pK: Failed to find peer[" QDF_MAC_ADDR_FMT "]", + soc, QDF_MAC_ADDR_REF(peer_mac)); + return QDF_STATUS_E_FAILURE; + } + peer->state = state; + peer->authorize = (state == OL_TXRX_PEER_STATE_AUTH) ? 1 : 0; + + dp_peer_info("peer" QDF_MAC_ADDR_FMT "state %d", + QDF_MAC_ADDR_REF(peer->mac_addr.raw), + peer->state); + + if (IS_MLO_DP_LINK_PEER(peer) && peer->assoc_link) { + peer->mld_peer->state = peer->state; + peer->mld_peer->authorize = peer->authorize; + dp_peer_info("mld peer" QDF_MAC_ADDR_FMT "state %d", + QDF_MAC_ADDR_REF(peer->mld_peer->mac_addr.raw), + peer->mld_peer->state); + } + + /* ref_cnt is incremented inside dp_peer_find_hash_find(). + * Decrement it here. + */ + dp_peer_unref_delete(peer, DP_MOD_ID_CDP); + + return QDF_STATUS_SUCCESS; +} +#else QDF_STATUS dp_register_peer(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, struct ol_txrx_desc_type *sta_desc) { @@ -4275,23 +4824,6 @@ QDF_STATUS dp_register_peer(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, return QDF_STATUS_SUCCESS; } -QDF_STATUS -dp_clear_peer(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, - struct qdf_mac_addr peer_addr) -{ - struct dp_peer *peer; - struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl); - - peer = dp_peer_find_hash_find(soc, peer_addr.bytes, - 0, DP_VDEV_ALL, DP_MOD_ID_CDP); - if (!peer || !peer->valid) - return QDF_STATUS_E_FAULT; - - dp_clear_peer_internal(soc, peer); - dp_peer_unref_delete(peer, DP_MOD_ID_CDP); - return QDF_STATUS_SUCCESS; -} - QDF_STATUS dp_peer_state_update(struct cdp_soc_t *soc_hdl, uint8_t *peer_mac, enum ol_txrx_peer_state state) { @@ -4306,7 +4838,6 @@ QDF_STATUS dp_peer_state_update(struct cdp_soc_t *soc_hdl, uint8_t *peer_mac, return QDF_STATUS_E_FAILURE; } peer->state = state; - peer->authorize = (state == OL_TXRX_PEER_STATE_AUTH) ? 1 : 0; dp_info("peer %pK state %d", peer, peer->state); @@ -4317,6 +4848,24 @@ QDF_STATUS dp_peer_state_update(struct cdp_soc_t *soc_hdl, uint8_t *peer_mac, return QDF_STATUS_SUCCESS; } +#endif + +QDF_STATUS +dp_clear_peer(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + struct qdf_mac_addr peer_addr) +{ + struct dp_peer *peer; + struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl); + + peer = dp_peer_find_hash_find(soc, peer_addr.bytes, + 0, DP_VDEV_ALL, DP_MOD_ID_CDP); + if (!peer || !peer->valid) + return QDF_STATUS_E_FAULT; + + dp_clear_peer_internal(soc, peer); + dp_peer_unref_delete(peer, DP_MOD_ID_CDP); + return QDF_STATUS_SUCCESS; +} QDF_STATUS dp_get_vdevid(struct cdp_soc_t *soc_hdl, uint8_t *peer_mac, uint8_t *vdev_id) diff --git a/dp/wifi3.0/dp_peer.h b/dp/wifi3.0/dp_peer.h index 8d21dbd830..9def21faae 100644 --- a/dp/wifi3.0/dp_peer.h +++ b/dp/wifi3.0/dp_peer.h @@ -62,6 +62,11 @@ struct ast_del_ctxt { typedef void dp_peer_iter_func(struct dp_soc *soc, struct dp_peer *peer, void *arg); void dp_peer_unref_delete(struct dp_peer *peer, enum dp_mod_id id); +struct dp_peer *dp_peer_find_hash_find(struct dp_soc *soc, + uint8_t *peer_mac_addr, + int mac_addr_is_aligned, + uint8_t vdev_id, + enum dp_mod_id id); /** * dp_peer_get_ref() - Returns peer object given the peer id @@ -968,4 +973,462 @@ static inline void dp_get_rx_reo_queue_info( { } #endif /* DUMP_REO_QUEUE_INFO_IN_DDR */ + +static inline int dp_peer_find_mac_addr_cmp( + union dp_align_mac_addr *mac_addr1, + union dp_align_mac_addr *mac_addr2) +{ + /* + * Intentionally use & rather than &&. + * because the operands are binary rather than generic boolean, + * the functionality is equivalent. + * Using && has the advantage of short-circuited evaluation, + * but using & has the advantage of no conditional branching, + * which is a more significant benefit. + */ + return !((mac_addr1->align4.bytes_abcd == mac_addr2->align4.bytes_abcd) + & (mac_addr1->align4.bytes_ef == mac_addr2->align4.bytes_ef)); +} + +/** + * dp_peer_delete() - delete DP peer + * + * @soc: Datatpath soc + * @peer: Datapath peer + * @arg: argument to iter function + * + * Return: void + */ +void dp_peer_delete(struct dp_soc *soc, + struct dp_peer *peer, + void *arg); + +#ifdef WLAN_FEATURE_11BE_MLO +/* set peer type */ +#define DP_PEER_SET_TYPE(_peer, _type_val) \ + ((_peer)->peer_type = (_type_val)) +/* is MLO connection link peer */ +#define IS_MLO_DP_LINK_PEER(_peer) \ + ((_peer)->peer_type == CDP_LINK_PEER_TYPE && (_peer)->mld_peer) +/* is MLO connection mld peer */ +#define IS_MLO_DP_MLD_PEER(_peer) \ + ((_peer)->peer_type == CDP_MLD_PEER_TYPE) + +/** + * dp_link_peer_add_mld_peer() - add mld peer pointer to link peer, + increase mld peer ref_cnt + * @link_peer: link peer pointer + * @mld_peer: mld peer pointer + * + * Return: none + */ +static inline +void dp_link_peer_add_mld_peer(struct dp_peer *link_peer, + struct dp_peer *mld_peer) +{ + /* increase mld_peer ref_cnt */ + dp_peer_get_ref(NULL, mld_peer, DP_MOD_ID_CDP); + link_peer->mld_peer = mld_peer; +} + +/** + * dp_link_peer_del_mld_peer() - delete mld peer pointer from link peer, + decrease mld peer ref_cnt + * @link_peer: link peer pointer + * + * Return: None + */ +static inline +void dp_link_peer_del_mld_peer(struct dp_peer *link_peer) +{ + dp_peer_unref_delete(link_peer->mld_peer, DP_MOD_ID_CDP); + link_peer->mld_peer = NULL; +} + +/** + * dp_mld_peer_init_link_peers_info() - init link peers info in mld peer + * @mld_peer: mld peer pointer + * + * Return: None + */ +static inline +void dp_mld_peer_init_link_peers_info(struct dp_peer *mld_peer) +{ + int i; + + qdf_spinlock_create(&mld_peer->link_peers_info_lock); + mld_peer->num_links = 0; + for (i = 0; i < DP_MAX_MLO_LINKS; i++) + mld_peer->link_peers[i].is_valid = false; +} + +/** + * dp_mld_peer_deinit_link_peers_info() - Deinit link peers info in mld peer + * @mld_peer: mld peer pointer + * + * Return: None + */ +static inline +void dp_mld_peer_deinit_link_peers_info(struct dp_peer *mld_peer) +{ + qdf_spinlock_destroy(&mld_peer->link_peers_info_lock); +} + +/** + * dp_mld_peer_add_link_peer() - add link peer info to mld peer + * @mld_peer: mld dp peer pointer + * @link_peer: link dp peer pointer + * + * Return: None + */ +static inline +void dp_mld_peer_add_link_peer(struct dp_peer *mld_peer, + struct dp_peer *link_peer) +{ + int i; + struct dp_peer_link_info *link_peer_info; + + qdf_spin_lock_bh(&mld_peer->link_peers_info_lock); + for (i = 0; i < DP_MAX_MLO_LINKS; i++) { + link_peer_info = &mld_peer->link_peers[i]; + if (!link_peer_info->is_valid) { + qdf_mem_copy(link_peer_info->mac_addr.raw, + link_peer->mac_addr.raw, + QDF_MAC_ADDR_SIZE); + link_peer_info->is_valid = true; + link_peer_info->vdev_id = link_peer->vdev->vdev_id; + mld_peer->num_links++; + break; + } + } + qdf_spin_unlock_bh(&mld_peer->link_peers_info_lock); + + if (i == DP_MAX_MLO_LINKS) + dp_err("fail to add link peer" QDF_MAC_ADDR_FMT "to mld peer", + QDF_MAC_ADDR_REF(link_peer->mac_addr.raw)); +} + +/** + * dp_mld_peer_del_link_peer() - Delete link peer info from MLD peer + * @mld_peer: MLD dp peer pointer + * @link_peer: link dp peer pointer + * + * Return: number of links left after deletion + */ +static inline +uint8_t dp_mld_peer_del_link_peer(struct dp_peer *mld_peer, + struct dp_peer *link_peer) +{ + int i; + struct dp_peer_link_info *link_peer_info; + uint8_t num_links; + + qdf_spin_lock_bh(&mld_peer->link_peers_info_lock); + for (i = 0; i < DP_MAX_MLO_LINKS; i++) { + link_peer_info = &mld_peer->link_peers[i]; + if (link_peer_info->is_valid && + !dp_peer_find_mac_addr_cmp(&link_peer->mac_addr, + &link_peer_info->mac_addr)) { + link_peer_info->is_valid = false; + mld_peer->num_links--; + break; + } + } + num_links = mld_peer->num_links; + qdf_spin_unlock_bh(&mld_peer->link_peers_info_lock); + + if (i == DP_MAX_MLO_LINKS) + dp_err("fail to del link peer" QDF_MAC_ADDR_FMT "to mld peer", + QDF_MAC_ADDR_REF(link_peer->mac_addr.raw)); + + return num_links; +} + +/** + * dp_get_link_peers_ref_from_mld_peer() - get link peers pointer and + increase link peers ref_cnt + * @soc: dp_soc handle + * @mld_peer: dp mld peer pointer + * @mld_link_peers: structure that hold links peers ponter array and number + * @mod_id: id of module requesting reference + * + * Return: None + */ +static inline +void dp_get_link_peers_ref_from_mld_peer( + struct dp_soc *soc, + struct dp_peer *mld_peer, + struct dp_mld_link_peers *mld_link_peers, + enum dp_mod_id mod_id) +{ + struct dp_peer *peer; + uint8_t i = 0, j = 0; + struct dp_peer_link_info *link_peer_info; + + qdf_mem_zero(mld_link_peers, sizeof(*mld_link_peers)); + qdf_spin_lock_bh(&mld_peer->link_peers_info_lock); + for (i = 0; i < DP_MAX_MLO_LINKS; i++) { + link_peer_info = &mld_peer->link_peers[i]; + if (link_peer_info->is_valid) { + peer = dp_peer_find_hash_find( + soc, + link_peer_info->mac_addr.raw, + true, + link_peer_info->vdev_id, + mod_id); + if (peer) + mld_link_peers->link_peers[j++] = peer; + } + } + qdf_spin_unlock_bh(&mld_peer->link_peers_info_lock); + + mld_link_peers->num_links = j; +} + +/** + * dp_release_link_peers_ref() - release all link peers reference + * @mld_link_peers: structure that hold links peers ponter array and number + * @mod_id: id of module requesting reference + * + * Return: None. + */ +static inline +void dp_release_link_peers_ref( + struct dp_mld_link_peers *mld_link_peers, + enum dp_mod_id mod_id) +{ + struct dp_peer *peer; + uint8_t i; + + for (i = 0; i < mld_link_peers->num_links; i++) { + peer = mld_link_peers->link_peers[i]; + if (peer) + dp_peer_unref_delete(peer, mod_id); + mld_link_peers->link_peers[i] = NULL; + } + + mld_link_peers->num_links = 0; +} + +/** + * dp_peer_get_tgt_peer_hash_find() - get MLD dp_peer handle + for processing + * @soc: soc handle + * @peer_mac_addr: peer mac address + * @mac_addr_is_aligned: is mac addr alligned + * @vdev_id: vdev_id + * @mod_id: id of module requesting reference + * + * for MLO connection, get corresponding MLD peer, + * otherwise get link peer for non-MLO case. + * + * return: peer in success + * NULL in failure + */ +static inline +struct dp_peer *dp_peer_get_tgt_peer_hash_find(struct dp_soc *soc, + uint8_t *peer_mac, + int mac_addr_is_aligned, + uint8_t vdev_id, + enum dp_mod_id mod_id) +{ + struct dp_peer *ta_peer = NULL; + struct dp_peer *peer = dp_peer_find_hash_find(soc, + peer_mac, 0, vdev_id, + mod_id); + + if (peer) { + /* mlo connection link peer, get mld peer with reference */ + if (IS_MLO_DP_LINK_PEER(peer)) { + /* increase mld peer ref_cnt */ + if (QDF_STATUS_SUCCESS == + dp_peer_get_ref(soc, peer->mld_peer, mod_id)) + ta_peer = peer->mld_peer; + else + ta_peer = NULL; + + /* relese peer reference that added by hash find */ + dp_peer_unref_delete(peer, mod_id); + } else { + /* mlo MLD peer or non-mlo link peer */ + ta_peer = peer; + } + } + + return ta_peer; +} + +/** + * dp_peer_get_tgt_peer_by_id() - Returns target peer object given the peer id + * @soc : core DP soc context + * @peer_id : peer id from peer object can be retrieved + * @mod_id : ID ot module requesting reference + * + * for MLO connection, get corresponding MLD peer, + * otherwise get link peer for non-MLO case. + * + * return: peer in success + * NULL in failure + */ +static inline +struct dp_peer *dp_peer_get_tgt_peer_by_id(struct dp_soc *soc, + uint16_t peer_id, + enum dp_mod_id mod_id) +{ + struct dp_peer *ta_peer = NULL; + struct dp_peer *peer = dp_peer_get_ref_by_id(soc, peer_id, mod_id); + + if (peer) { + /* mlo connection link peer, get mld peer with reference */ + if (IS_MLO_DP_LINK_PEER(peer)) { + /* increase mld peer ref_cnt */ + if (QDF_STATUS_SUCCESS == + dp_peer_get_ref(soc, peer->mld_peer, mod_id)) + ta_peer = peer->mld_peer; + else + ta_peer = NULL; + + /* relese peer reference that added by hash find */ + dp_peer_unref_delete(peer, mod_id); + } else { + /* mlo MLD peer or non-mlo link peer */ + ta_peer = peer; + } + } + + return ta_peer; +} + +/** + * dp_peer_mlo_delete() - peer MLO related delete operation + * @soc: Soc handle + * @peer: DP peer handle + * Return: None + */ +static inline +void dp_peer_mlo_delete(struct dp_soc *soc, + struct dp_peer *peer) +{ + /* MLO connection link peer */ + if (IS_MLO_DP_LINK_PEER(peer)) { + /* if last link peer deletion, delete MLD peer */ + if (dp_mld_peer_del_link_peer(peer->mld_peer, peer) == 0) + dp_peer_delete(soc, peer->mld_peer, NULL); + } +} + +/** + * dp_peer_mlo_setup() - create MLD peer and MLO related initialization + * @soc: Soc handle + * @vdev_id: Vdev ID + * @peer_setup_info: peer setup information for MLO + */ +QDF_STATUS dp_peer_mlo_setup( + struct dp_soc *soc, + struct dp_peer *peer, + uint8_t vdev_id, + struct cdp_peer_setup_info *setup_info); +#else +#define DP_PEER_SET_TYPE(_peer, _type_val) /* no op */ +#define IS_MLO_DP_LINK_PEER(_peer) false +#define IS_MLO_DP_MLD_PEER(_peer) false + +static inline +struct dp_peer *dp_peer_get_tgt_peer_hash_find(struct dp_soc *soc, + uint8_t *peer_mac, + int mac_addr_is_aligned, + uint8_t vdev_id, + enum dp_mod_id mod_id) +{ + return dp_peer_find_hash_find(soc, peer_mac, + mac_addr_is_aligned, vdev_id, + mod_id); +} + +static inline +struct dp_peer *dp_peer_get_tgt_peer_by_id(struct dp_soc *soc, + uint16_t peer_id, + enum dp_mod_id mod_id) +{ + return dp_peer_get_ref_by_id(soc, peer_id, mod_id); +} + +static inline +QDF_STATUS dp_peer_mlo_setup( + struct dp_soc *soc, + struct dp_peer *peer, + uint8_t vdev_id, + struct cdp_peer_setup_info *setup_info) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void dp_mld_peer_init_link_peers_info(struct dp_peer *mld_peer) +{ +} + +static inline +void dp_mld_peer_deinit_link_peers_info(struct dp_peer *mld_peer) +{ +} + +static inline +void dp_link_peer_del_mld_peer(struct dp_peer *link_peer) +{ +} + +static inline +void dp_peer_mlo_delete(struct dp_soc *soc, + struct dp_peer *peer) +{ +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +static inline +QDF_STATUS dp_peer_rx_tids_create(struct dp_peer *peer) +{ + uint8_t i; + + if (IS_MLO_DP_MLD_PEER(peer)) { + dp_peer_info("skip for mld peer"); + return QDF_STATUS_SUCCESS; + } + + if (peer->rx_tid) { + QDF_BUG(0); + dp_peer_err("peer rx_tid mem already exist"); + return QDF_STATUS_E_FAILURE; + } + + peer->rx_tid = qdf_mem_malloc(DP_MAX_TIDS * + sizeof(struct dp_rx_tid)); + + if (!peer->rx_tid) { + dp_err("fail to alloc tid for peer" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer->mac_addr.raw)); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_zero(peer->rx_tid, DP_MAX_TIDS * sizeof(struct dp_rx_tid)); + for (i = 0; i < DP_MAX_TIDS; i++) + qdf_spinlock_create(&peer->rx_tid[i].tid_lock); + + return QDF_STATUS_SUCCESS; +} + +static inline +void dp_peer_rx_tids_destroy(struct dp_peer *peer) +{ + uint8_t i; + + if (!IS_MLO_DP_LINK_PEER(peer)) { + for (i = 0; i < DP_MAX_TIDS; i++) + qdf_spinlock_destroy(&peer->rx_tid[i].tid_lock); + + qdf_mem_free(peer->rx_tid); + } + + peer->rx_tid = NULL; +} #endif /* _DP_PEER_H_ */ diff --git a/dp/wifi3.0/dp_rx_defrag.c b/dp/wifi3.0/dp_rx_defrag.c index f73c705537..28797f8136 100644 --- a/dp/wifi3.0/dp_rx_defrag.c +++ b/dp/wifi3.0/dp_rx_defrag.c @@ -222,9 +222,7 @@ void dp_rx_defrag_waitlist_flush(struct dp_soc *soc) TAILQ_REMOVE(&temp_list, rx_reorder, defrag_waitlist_elem); /* get address of current peer */ - peer = - container_of(rx_reorder, struct dp_peer, - rx_tid[rx_reorder->tid]); + peer = rx_reorder->defrag_peer; qdf_spin_unlock_bh(&rx_reorder->tid_lock); temp_peer = dp_peer_get_ref_by_id(soc, peer->peer_id, @@ -298,9 +296,7 @@ void dp_rx_defrag_waitlist_remove(struct dp_peer *peer, unsigned tid) struct dp_peer *peer_on_waitlist; /* get address of current peer */ - peer_on_waitlist = - container_of(rx_reorder, struct dp_peer, - rx_tid[rx_reorder->tid]); + peer_on_waitlist = rx_reorder->defrag_peer; /* Ensure it is TID for same peer */ if (peer_on_waitlist == peer && rx_reorder->tid == tid) { diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index f41ae43c7a..c79d80e8e4 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -628,7 +628,7 @@ _dp_rx_bar_frame_handle(struct dp_soc *soc, qdf_nbuf_t nbuf, struct dp_peer *peer; peer_id = DP_PEER_METADATA_PEER_ID_GET(mpdu_desc_info->peer_meta_data); - peer = dp_peer_get_ref_by_id(soc, peer_id, DP_MOD_ID_RX_ERR); + peer = dp_peer_get_tgt_peer_by_id(soc, peer_id, DP_MOD_ID_RX_ERR); if (!peer) return; diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 10e892bdf9..5a8e73fbc5 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -810,6 +810,9 @@ struct dp_rx_tid { /* Peer TID statistics */ struct cdp_peer_tid_stats stats; + + /* defrag usage only, dp_peer pointer related with this tid */ + struct dp_peer *defrag_peer; }; /** @@ -1905,6 +1908,15 @@ struct dp_soc { TAILQ_HEAD(, dp_peer) * bins; } peer_hash; +#ifdef WLAN_FEATURE_11BE_MLO + /* Protect mld peer hash table */ + DP_MUTEX_TYPE mld_peer_hash_lock; + struct { + unsigned mask; + unsigned idx_bits; + TAILQ_HEAD(, dp_peer) * bins; + } mld_peer_hash; +#endif /* rx defrag state – TBD: do we need this per radio? */ struct { struct { @@ -3122,6 +3134,34 @@ struct dp_peer_mesh_latency_parameter { }; #endif +#ifdef WLAN_FEATURE_11BE_MLO +/* Max number of links for MLO connection */ +#define DP_MAX_MLO_LINKS 3 + +/** + * struct dp_peer_link_info - link peer information for MLO + * @mac_add: Mac address + * @vdev_id: Vdev ID for current link peer + * @is_valid: flag for link peer info valid or not + */ +struct dp_peer_link_info { + union dp_align_mac_addr mac_addr; + uint8_t vdev_id; + uint8_t is_valid; +}; + +/** + * struct dp_mld_link_peers - this structure is used to get link peers + pointer from mld peer + * @link_peers: link peers pointer array + * @num_links: number of link peers fetched + */ +struct dp_mld_link_peers { + struct dp_peer *link_peers[DP_MAX_MLO_LINKS]; + uint8_t num_links; +}; +#endif + /* Peer structure for data path state */ struct dp_peer { /* VDEV to which this peer is associated */ @@ -3141,8 +3181,8 @@ struct dp_peer { /* node in the hash table bin's list of peers */ TAILQ_ENTRY(dp_peer) hash_list_elem; - /* TID structures */ - struct dp_rx_tid rx_tid[DP_MAX_TIDS]; + /* TID structures pointer */ + struct dp_rx_tid *rx_tid; /* TBD: No transmit TID state required? */ @@ -3164,6 +3204,11 @@ struct dp_peer { delete_in_progress:1, /* Indicate kickout sent */ sta_self_peer:1; /* Indicate STA self peer */ +#ifdef WLAN_FEATURE_11BE_MLO + uint8_t assoc_link:1, /* first assoc link peer for MLO */ + primary_link:1; /* primary link for MLO */ +#endif + #ifdef QCA_SUPPORT_PEER_ISOLATION bool isolation; /* enable peer isolation for this peer */ #endif @@ -3248,6 +3293,17 @@ struct dp_peer { #ifdef WIFI_MONITOR_SUPPORT struct dp_mon_peer *monitor_peer; #endif +#ifdef WLAN_FEATURE_11BE_MLO + /* peer type */ + enum cdp_peer_type peer_type; + /*---------for link peer---------*/ + struct dp_peer *mld_peer; + + /*---------for mld peer----------*/ + struct dp_peer_link_info link_peers[DP_MAX_MLO_LINKS]; + uint8_t num_links; + DP_MUTEX_TYPE link_peers_info_lock; +#endif }; /*