diff --git a/dp/inc/cdp_txrx_cmn_struct.h b/dp/inc/cdp_txrx_cmn_struct.h index e135a0d6aa..23b5badf89 100644 --- a/dp/inc/cdp_txrx_cmn_struct.h +++ b/dp/inc/cdp_txrx_cmn_struct.h @@ -402,7 +402,6 @@ enum cdp_txrx_ast_entry_type { CDP_TXRX_AST_TYPE_STATIC, /* static ast entry for connected peer */ CDP_TXRX_AST_TYPE_SELF, /* static ast entry for self peer (STA mode) */ CDP_TXRX_AST_TYPE_WDS, /* WDS peer ast entry type*/ - CDP_TXRX_AST_TYPE_MEC, /* Multicast echo ast entry type */ CDP_TXRX_AST_TYPE_WDS_HM, /* HM WDS entry */ CDP_TXRX_AST_TYPE_STA_BSS, /* BSS entry(STA mode) */ CDP_TXRX_AST_TYPE_DA, /* AST entry based on Destination address */ diff --git a/dp/wifi3.0/dp_internal.h b/dp/wifi3.0/dp_internal.h index a2151b0294..aa7d5ba158 100644 --- a/dp/wifi3.0/dp_internal.h +++ b/dp/wifi3.0/dp_internal.h @@ -1016,7 +1016,13 @@ static inline void dp_update_vdev_stats(struct dp_soc *soc, DP_STATS_AGGR(_tgtobj, _srcobj, rx.multipass_rx_pkt_drop); \ } while (0) -extern int dp_peer_find_attach(struct dp_soc *soc); +/** + * dp_peer_find_attach() - Allocates memory for peer objects + * @soc: SoC handle + * + * Return: QDF_STATUS + */ +QDF_STATUS dp_peer_find_attach(struct dp_soc *soc); extern void dp_peer_find_detach(struct dp_soc *soc); extern void dp_peer_find_hash_add(struct dp_soc *soc, struct dp_peer *peer); extern void dp_peer_find_hash_remove(struct dp_soc *soc, struct dp_peer *peer); diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 7c7e2cc4d7..0c532143d6 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -652,6 +652,103 @@ static void dp_service_lmac_rings(void *arg) #endif +#ifdef FEATURE_MEC +void dp_peer_mec_flush_entries(struct dp_soc *soc) +{ + unsigned int index; + struct dp_mec_entry *mecentry, *mecentry_next; + + TAILQ_HEAD(, dp_mec_entry) free_list; + TAILQ_INIT(&free_list); + + if (!soc->mec_hash.mask) + return; + + if (!soc->mec_hash.bins) + return; + + if (!qdf_atomic_read(&soc->mec_cnt)) + return; + + qdf_spin_lock_bh(&soc->mec_lock); + for (index = 0; index <= soc->mec_hash.mask; index++) { + if (!TAILQ_EMPTY(&soc->mec_hash.bins[index])) { + TAILQ_FOREACH_SAFE(mecentry, &soc->mec_hash.bins[index], + hash_list_elem, mecentry_next) { + dp_peer_mec_detach_entry(soc, mecentry, &free_list); + } + } + } + qdf_spin_unlock_bh(&soc->mec_lock); + + dp_peer_mec_free_list(soc, &free_list); +} + +/** + * dp_print_mec_entries() - Dump MEC entries in table + * @soc: Datapath soc handle + * + * Return: none + */ +static void dp_print_mec_stats(struct dp_soc *soc) +{ + int i; + uint32_t index; + struct dp_mec_entry *mecentry = NULL, *mec_list; + uint32_t num_entries = 0; + + DP_PRINT_STATS("MEC Stats:"); + DP_PRINT_STATS(" Entries Added = %d", soc->stats.mec.added); + DP_PRINT_STATS(" Entries Deleted = %d", soc->stats.mec.deleted); + + if (!qdf_atomic_read(&soc->mec_cnt)) + return; + + mec_list = qdf_mem_malloc(sizeof(*mecentry) * DP_PEER_MAX_MEC_ENTRY); + if (!mec_list) { + dp_peer_warn("%pK: failed to allocate mec_list", soc); + return; + } + + DP_PRINT_STATS("MEC Table:"); + for (index = 0; index <= soc->mec_hash.mask; index++) { + qdf_spin_lock_bh(&soc->mec_lock); + if (TAILQ_EMPTY(&soc->mec_hash.bins[index])) { + qdf_spin_unlock_bh(&soc->mec_lock); + continue; + } + + TAILQ_FOREACH(mecentry, &soc->mec_hash.bins[index], + hash_list_elem) { + qdf_mem_copy(&mec_list[num_entries], mecentry, + sizeof(*mecentry)); + num_entries++; + } + qdf_spin_unlock_bh(&soc->mec_lock); + } + + if (!num_entries) { + qdf_mem_free(mec_list); + return; + } + + for (i = 0; i < num_entries; i++) { + DP_PRINT_STATS("%6d mac_addr = " QDF_MAC_ADDR_FMT + " is_active = %d pdev_id = %d vdev_id = %d", + i, + QDF_MAC_ADDR_REF(mec_list[i].mac_addr.raw), + mec_list[i].is_active, + mec_list[i].pdev_id, + mec_list[i].vdev_id); + } + qdf_mem_free(mec_list); +} +#else +static void dp_print_mec_stats(struct dp_soc *soc) +{ +} +#endif + static int dp_peer_add_ast_wifi3(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, uint8_t *peer_mac, @@ -862,6 +959,7 @@ static void dp_wds_flush_ast_table_wifi3(struct cdp_soc_t *soc_hdl) DP_MOD_ID_CDP); qdf_spin_unlock_bh(&soc->ast_lock); + dp_peer_mec_flush_entries(soc); } /** @@ -1275,7 +1373,7 @@ dp_print_peer_ast_entries(struct dp_soc *soc, struct dp_peer *peer, void *arg) struct dp_ast_entry *ase, *tmp_ase; uint32_t num_entries = 0; char type[CDP_TXRX_AST_TYPE_MAX][10] = { - "NONE", "STATIC", "SELF", "WDS", "MEC", "HMWDS", "BSS", + "NONE", "STATIC", "SELF", "WDS", "HMWDS", "BSS", "DA", "HMWDS_SEC"}; DP_PEER_ITERATE_ASE_LIST(peer, ase, tmp_ase) { @@ -4803,6 +4901,8 @@ static void dp_soc_deinit(void *txrx_soc) qdf_spinlock_destroy(&soc->ast_lock); + dp_peer_mec_spinlock_destroy(soc); + qdf_nbuf_queue_free(&soc->htt_stats.msg); qdf_nbuf_queue_free(&soc->invalid_buf_queue); @@ -8459,6 +8559,7 @@ dp_print_host_stats(struct dp_vdev *vdev, break; case TXRX_AST_STATS: dp_print_ast_stats(pdev->soc); + dp_print_mec_stats(pdev->soc); dp_print_peer_table(vdev); break; case TXRX_SRNG_PTR_STATS: @@ -12526,6 +12627,7 @@ void *dp_soc_init(struct dp_soc *soc, HTC_HANDLE htc_handle, qdf_nbuf_queue_init(&soc->htt_stats.msg); qdf_spinlock_create(&soc->ast_lock); + dp_peer_mec_spinlock_create(soc); qdf_spinlock_create(&soc->reo_desc_freelist_lock); qdf_list_create(&soc->reo_desc_freelist, REO_DESC_FREELIST_SIZE); diff --git a/dp/wifi3.0/dp_peer.c b/dp/wifi3.0/dp_peer.c index 54f5fb62f0..7cfa59730a 100644 --- a/dp/wifi3.0/dp_peer.c +++ b/dp/wifi3.0/dp_peer.c @@ -103,7 +103,7 @@ static inline int dp_peer_find_mac_addr_cmp( & (mac_addr1->align4.bytes_ef == mac_addr2->align4.bytes_ef)); } -static int dp_peer_ast_table_attach(struct dp_soc *soc) +static QDF_STATUS dp_peer_ast_table_attach(struct dp_soc *soc) { uint32_t max_ast_index; @@ -116,16 +116,16 @@ static int dp_peer_ast_table_attach(struct dp_soc *soc) dp_peer_err("%pK: ast_table memory allocation failed", soc); return QDF_STATUS_E_NOMEM; } - return 0; /* success */ + return QDF_STATUS_SUCCESS; /* success */ } /* * dp_peer_find_map_attach() - allocate memory for peer_id_to_obj_map * @soc: soc handle * - * return: none + * return: QDF_STATUS */ -static int dp_peer_find_map_attach(struct dp_soc *soc) +static QDF_STATUS dp_peer_find_map_attach(struct dp_soc *soc) { uint32_t max_peers, peer_map_size; @@ -149,7 +149,7 @@ static int dp_peer_find_map_attach(struct dp_soc *soc) qdf_mem_zero(soc->peer_id_to_obj_map, peer_map_size); qdf_spinlock_create(&soc->peer_map_lock); - return 0; /* success */ + return QDF_STATUS_SUCCESS; /* success */ } static int dp_log2_ceil(unsigned int value) @@ -176,9 +176,9 @@ static int dp_log2_ceil(unsigned int value) * dp_peer_find_hash_attach() - allocate memory for peer_hash table * @soc: soc handle * - * return: none + * return: QDF_STATUS */ -static int dp_peer_find_hash_attach(struct dp_soc *soc) +static QDF_STATUS dp_peer_find_hash_attach(struct dp_soc *soc) { int i, hash_elems, log2; @@ -201,7 +201,7 @@ static int dp_peer_find_hash_attach(struct dp_soc *soc) TAILQ_INIT(&soc->peer_hash.bins[i]); qdf_spinlock_create(&soc->peer_hash_lock); - return 0; + return QDF_STATUS_SUCCESS; } /* @@ -425,14 +425,228 @@ static bool dp_peer_exist_on_pdev(struct dp_soc *soc, return found; } +#ifdef FEATURE_MEC +/** + * dp_peer_mec_hash_attach() - Allocate and initialize MEC Hash Table + * @soc: SoC handle + * + * Return: QDF_STATUS + */ +static QDF_STATUS dp_peer_mec_hash_attach(struct dp_soc *soc) +{ + int log2, hash_elems, i; + + log2 = dp_log2_ceil(DP_PEER_MAX_MEC_IDX); + hash_elems = 1 << log2; + + soc->mec_hash.mask = hash_elems - 1; + soc->mec_hash.idx_bits = log2; + + dp_peer_info("%pK: max mec index: %d", + soc, DP_PEER_MAX_MEC_IDX); + + /* allocate an array of TAILQ mec object lists */ + soc->mec_hash.bins = qdf_mem_malloc(hash_elems * + sizeof(TAILQ_HEAD(anonymous_tail_q, + dp_mec_entry))); + + if (!soc->mec_hash.bins) + return QDF_STATUS_E_NOMEM; + + for (i = 0; i < hash_elems; i++) + TAILQ_INIT(&soc->mec_hash.bins[i]); + + return QDF_STATUS_SUCCESS; +} + +/** + * dp_peer_mec_hash_index() - Compute the MEC hash from MAC address + * @soc: SoC handle + * + * Return: MEC hash + */ +static inline uint32_t dp_peer_mec_hash_index(struct dp_soc *soc, + union dp_align_mac_addr *mac_addr) +{ + uint32_t index; + + index = + mac_addr->align2.bytes_ab ^ + mac_addr->align2.bytes_cd ^ + mac_addr->align2.bytes_ef; + index ^= index >> soc->mec_hash.idx_bits; + index &= soc->mec_hash.mask; + return index; +} + +struct dp_mec_entry *dp_peer_mec_hash_find_by_pdevid(struct dp_soc *soc, + uint8_t pdev_id, + uint8_t *mec_mac_addr) +{ + union dp_align_mac_addr local_mac_addr_aligned, *mac_addr; + uint32_t index; + struct dp_mec_entry *mecentry; + + qdf_mem_copy(&local_mac_addr_aligned.raw[0], + mec_mac_addr, QDF_MAC_ADDR_SIZE); + mac_addr = &local_mac_addr_aligned; + + index = dp_peer_mec_hash_index(soc, mac_addr); + TAILQ_FOREACH(mecentry, &soc->mec_hash.bins[index], hash_list_elem) { + if ((pdev_id == mecentry->pdev_id) && + !dp_peer_find_mac_addr_cmp(mac_addr, &mecentry->mac_addr)) + return mecentry; + } + + return NULL; +} + +/** + * dp_peer_mec_hash_add() - Add MEC entry into hash table + * @soc: SoC handle + * + * This function adds the MEC entry into SoC MEC hash table + * + * Return: None + */ +static inline void dp_peer_mec_hash_add(struct dp_soc *soc, + struct dp_mec_entry *mecentry) +{ + uint32_t index; + + index = dp_peer_mec_hash_index(soc, &mecentry->mac_addr); + qdf_spin_lock_bh(&soc->mec_lock); + TAILQ_INSERT_TAIL(&soc->mec_hash.bins[index], mecentry, hash_list_elem); + qdf_spin_unlock_bh(&soc->mec_lock); +} + +QDF_STATUS dp_peer_mec_add_entry(struct dp_soc *soc, + struct dp_vdev *vdev, + uint8_t *mac_addr) +{ + struct dp_mec_entry *mecentry = NULL; + struct dp_pdev *pdev = NULL; + + if (!vdev) { + dp_peer_err("%pK: Peers vdev is NULL", soc); + return QDF_STATUS_E_INVAL; + } + + pdev = vdev->pdev; + + if (qdf_unlikely(qdf_atomic_read(&soc->mec_cnt) >= + DP_PEER_MAX_MEC_ENTRY)) { + dp_peer_warn("%pK: max MEC entry limit reached mac_addr: " + QDF_MAC_ADDR_FMT, soc, QDF_MAC_ADDR_REF(mac_addr)); + return QDF_STATUS_E_NOMEM; + } + + qdf_spin_lock_bh(&soc->mec_lock); + mecentry = dp_peer_mec_hash_find_by_pdevid(soc, pdev->pdev_id, + mac_addr); + if (qdf_likely(mecentry)) { + mecentry->is_active = TRUE; + qdf_spin_unlock_bh(&soc->mec_lock); + return QDF_STATUS_E_ALREADY; + } + + qdf_spin_unlock_bh(&soc->mec_lock); + + dp_peer_debug("%pK: pdevid: %u vdev: %u type: MEC mac_addr: " + QDF_MAC_ADDR_FMT, + soc, pdev->pdev_id, vdev->vdev_id, + QDF_MAC_ADDR_REF(mac_addr)); + + mecentry = (struct dp_mec_entry *) + qdf_mem_malloc(sizeof(struct dp_mec_entry)); + + if (qdf_unlikely(!mecentry)) { + dp_peer_err("%pK: fail to allocate mecentry", soc); + return QDF_STATUS_E_NOMEM; + } + + qdf_copy_macaddr((struct qdf_mac_addr *)&mecentry->mac_addr.raw[0], + (struct qdf_mac_addr *)mac_addr); + mecentry->pdev_id = pdev->pdev_id; + mecentry->vdev_id = vdev->vdev_id; + mecentry->is_active = TRUE; + dp_peer_mec_hash_add(soc, mecentry); + + qdf_atomic_inc(&soc->mec_cnt); + DP_STATS_INC(soc, mec.added, 1); + + return QDF_STATUS_SUCCESS; +} + +void dp_peer_mec_detach_entry(struct dp_soc *soc, struct dp_mec_entry *mecentry, + void *ptr) +{ + uint32_t index = dp_peer_mec_hash_index(soc, &mecentry->mac_addr); + + TAILQ_HEAD(, dp_mec_entry) * free_list = ptr; + + TAILQ_REMOVE(&soc->mec_hash.bins[index], mecentry, + hash_list_elem); + TAILQ_INSERT_TAIL(free_list, mecentry, hash_list_elem); +} + +void dp_peer_mec_free_list(struct dp_soc *soc, void *ptr) +{ + struct dp_mec_entry *mecentry, *mecentry_next; + + TAILQ_HEAD(, dp_mec_entry) * free_list = ptr; + + TAILQ_FOREACH_SAFE(mecentry, free_list, hash_list_elem, + mecentry_next) { + dp_peer_debug("%pK: MEC delete for mac_addr " QDF_MAC_ADDR_FMT, + soc, QDF_MAC_ADDR_REF(&mecentry->mac_addr)); + qdf_mem_free(mecentry); + qdf_atomic_dec(&soc->mec_cnt); + DP_STATS_INC(soc, mec.deleted, 1); + } +} + +/** + * dp_peer_mec_hash_detach() - Free MEC Hash table + * @soc: SoC handle + * + * Return: None + */ +static void dp_peer_mec_hash_detach(struct dp_soc *soc) +{ + dp_peer_mec_flush_entries(soc); + qdf_mem_free(soc->mec_hash.bins); + soc->mec_hash.bins = NULL; +} + +void dp_peer_mec_spinlock_destroy(struct dp_soc *soc) +{ + qdf_spinlock_destroy(&soc->mec_lock); +} + +void dp_peer_mec_spinlock_create(struct dp_soc *soc) +{ + qdf_spinlock_create(&soc->mec_lock); +} +#else +static QDF_STATUS dp_peer_mec_hash_attach(struct dp_soc *soc) +{ + return QDF_STATUS_SUCCESS; +} + +static void dp_peer_mec_hash_detach(struct dp_soc *soc) +{ +} +#endif + #ifdef FEATURE_AST /* * dp_peer_ast_hash_attach() - Allocate and initialize AST Hash Table * @soc: SoC handle * - * Return: None + * Return: QDF_STATUS */ -static int dp_peer_ast_hash_attach(struct dp_soc *soc) +static QDF_STATUS dp_peer_ast_hash_attach(struct dp_soc *soc) { int i, hash_elems, log2; unsigned int max_ast_idx = wlan_cfg_get_max_ast_idx(soc->wlan_cfg_ctx); @@ -460,7 +674,7 @@ static int dp_peer_ast_hash_attach(struct dp_soc *soc) for (i = 0; i < hash_elems; i++) TAILQ_INIT(&soc->ast_hash.bins[i]); - return 0; + return QDF_STATUS_SUCCESS; } /* @@ -911,13 +1125,10 @@ QDF_STATUS dp_peer_add_ast(struct dp_soc *soc, ast_entry = dp_peer_ast_hash_find_by_pdevid(soc, mac_addr, pdev->pdev_id); if (ast_entry) { - if ((type == CDP_TXRX_AST_TYPE_MEC) && - (ast_entry->type == CDP_TXRX_AST_TYPE_MEC)) - ast_entry->is_active = TRUE; - qdf_spin_unlock_bh(&soc->ast_lock); return QDF_STATUS_E_ALREADY; } + if (is_peer_found) { /* During WDS to static roaming, peer is added * to the list before static AST entry create. @@ -939,10 +1150,6 @@ QDF_STATUS dp_peer_add_ast(struct dp_soc *soc, ast_entry = dp_peer_ast_hash_find_soc(soc, mac_addr); if (ast_entry) { - if ((type == CDP_TXRX_AST_TYPE_MEC) && - (ast_entry->type == CDP_TXRX_AST_TYPE_MEC)) - ast_entry->is_active = TRUE; - if ((ast_entry->type == CDP_TXRX_AST_TYPE_WDS_HM) && !ast_entry->delete_in_progress) { qdf_spin_unlock_bh(&soc->ast_lock); @@ -1006,22 +1213,6 @@ QDF_STATUS dp_peer_add_ast(struct dp_soc *soc, return QDF_STATUS_E_AGAIN; } - /* Modify an already existing AST entry from type - * WDS to MEC on promption. This serves as a fix when - * backbone of interfaces are interchanged wherein - * wds entr becomes its own MEC. The entry should be - * replaced only when the ast_entry peer matches the - * peer received in mec event. This additional check - * is needed in wds repeater cases where a multicast - * packet from station to the root via the repeater - * should not remove the wds entry. - */ - if ((ast_entry->type == CDP_TXRX_AST_TYPE_WDS) && - (type == CDP_TXRX_AST_TYPE_MEC) && - (ast_entry->peer_id == peer->peer_id)) { - ast_entry->is_active = FALSE; - dp_peer_del_ast(soc, ast_entry); - } qdf_spin_unlock_bh(&soc->ast_lock); return QDF_STATUS_E_ALREADY; } @@ -1072,10 +1263,6 @@ add_ast_entry: TAILQ_INSERT_TAIL(&peer->ast_entry_list, ast_entry, ase_list_elem); break; - case CDP_TXRX_AST_TYPE_MEC: - ast_entry->next_hop = 1; - ast_entry->type = CDP_TXRX_AST_TYPE_MEC; - break; case CDP_TXRX_AST_TYPE_DA: vap_bss_peer = dp_vdev_bss_peer_ref_n_get(soc, vdev, DP_MOD_ID_AST); @@ -1097,10 +1284,8 @@ add_ast_entry: soc->num_ast_entries++; dp_peer_ast_hash_add(soc, ast_entry); - if (type == CDP_TXRX_AST_TYPE_MEC) - qdf_mem_copy(next_node_mac, peer->vdev->mac_addr.raw, 6); - else - qdf_mem_copy(next_node_mac, peer->mac_addr.raw, 6); + qdf_copy_macaddr((struct qdf_mac_addr *)next_node_mac, + (struct qdf_mac_addr *)peer->mac_addr.raw); if ((ast_entry->type != CDP_TXRX_AST_TYPE_STATIC) && (ast_entry->type != CDP_TXRX_AST_TYPE_SELF) && @@ -1431,9 +1616,9 @@ struct dp_ast_entry *dp_peer_ast_hash_find_by_pdevid(struct dp_soc *soc, return NULL; } -static int dp_peer_ast_hash_attach(struct dp_soc *soc) +static QDF_STATUS dp_peer_ast_hash_attach(struct dp_soc *soc) { - return 0; + return QDF_STATUS_SUCCESS; } static inline QDF_STATUS dp_peer_map_ast(struct dp_soc *soc, @@ -1816,31 +2001,41 @@ static void dp_peer_find_map_detach(struct dp_soc *soc) } } -int dp_peer_find_attach(struct dp_soc *soc) +QDF_STATUS dp_peer_find_attach(struct dp_soc *soc) { - if (dp_peer_find_map_attach(soc)) - return 1; + QDF_STATUS status; - if (dp_peer_find_hash_attach(soc)) { - dp_peer_find_map_detach(soc); - return 1; + status = dp_peer_find_map_attach(soc); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + + status = dp_peer_find_hash_attach(soc); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto map_detach; + + status = dp_peer_ast_table_attach(soc); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto hash_detach; + + status = dp_peer_ast_hash_attach(soc); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto ast_table_detach; + + status = dp_peer_mec_hash_attach(soc); + if (QDF_IS_STATUS_SUCCESS(status)) { + dp_soc_wds_attach(soc); + return status; } - if (dp_peer_ast_table_attach(soc)) { - dp_peer_find_hash_detach(soc); - dp_peer_find_map_detach(soc); - return 1; - } + dp_peer_ast_hash_detach(soc); +ast_table_detach: + dp_peer_ast_table_detach(soc); +hash_detach: + dp_peer_find_hash_detach(soc); +map_detach: + dp_peer_find_map_detach(soc); - if (dp_peer_ast_hash_attach(soc)) { - dp_peer_ast_table_detach(soc); - dp_peer_find_hash_detach(soc); - dp_peer_find_map_detach(soc); - return 1; - } - - dp_soc_wds_attach(soc); - return 0; /* success */ + return status; } void dp_rx_tid_stats_cb(struct dp_soc *soc, void *cb_ctxt, @@ -2180,6 +2375,7 @@ dp_peer_find_detach(struct dp_soc *soc) dp_peer_find_hash_detach(soc); dp_peer_ast_hash_detach(soc); dp_peer_ast_table_detach(soc); + dp_peer_mec_hash_detach(soc); } static void dp_rx_tid_update_cb(struct dp_soc *soc, void *cb_ctxt, diff --git a/dp/wifi3.0/dp_peer.h b/dp/wifi3.0/dp_peer.h index 9b66985d54..5365d7499a 100644 --- a/dp/wifi3.0/dp_peer.h +++ b/dp/wifi3.0/dp_peer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -24,6 +24,9 @@ #define DP_INVALID_PEER_ID 0xffff +#define DP_PEER_MAX_MEC_IDX 1024 /* maximum index for MEC table */ +#define DP_PEER_MAX_MEC_ENTRY 4096 /* maximum MEC entries in MEC table */ + #define DP_FW_PEER_STATS_CMP_TIMEOUT_MSEC 5000 #define dp_peer_alert(params...) QDF_TRACE_FATAL(QDF_MODULE_ID_DP_PEER, params) @@ -601,6 +604,59 @@ void dp_peer_unlink_ast_entry(struct dp_soc *soc, struct dp_ast_entry *ast_entry, struct dp_peer *peer); +/** + * dp_peer_mec_detach_entry() - Detach the MEC entry + * @soc: SoC handle + * @mecentry: MEC entry of the node + * @ptr: pointer to free list + * + * The MEC entry is detached from MEC table and added to free_list + * to free the object outside lock + * + * Return: None + */ +void dp_peer_mec_detach_entry(struct dp_soc *soc, struct dp_mec_entry *mecentry, + void *ptr); + +/** + * dp_peer_mec_free_list() - free the MEC entry from free_list + * @soc: SoC handle + * @ptr: pointer to free list + * + * Return: None + */ +void dp_peer_mec_free_list(struct dp_soc *soc, void *ptr); + +/** + * dp_peer_mec_add_entry() + * @soc: SoC handle + * @vdev: vdev to which mec node belongs + * @mac_addr: MAC address of mec node + * + * This function allocates and adds MEC entry to MEC table. + * It assumes caller has taken the mec lock to protect the access to these + * tables + * + * Return: QDF_STATUS + */ +QDF_STATUS dp_peer_mec_add_entry(struct dp_soc *soc, + struct dp_vdev *vdev, + uint8_t *mac_addr); + +/** + * dp_peer_mec_hash_find_by_pdevid() - Find MEC entry by MAC address + * within pdev + * @soc: SoC handle + * + * It assumes caller has taken the mec_lock to protect the access to + * MEC hash table + * + * Return: MEC entry + */ +struct dp_mec_entry *dp_peer_mec_hash_find_by_pdevid(struct dp_soc *soc, + uint8_t pdev_id, + uint8_t *mec_mac_addr); + #define DP_AST_ASSERT(_condition) \ do { \ if (!(_condition)) { \ @@ -850,4 +906,42 @@ static inline void dp_peer_delete_ast_entries(struct dp_soc *soc, { } #endif + +#ifdef FEATURE_MEC +/** + * dp_peer_mec_spinlock_create() - Create the MEC spinlock + * @soc: SoC handle + * + * Return: none + */ +void dp_peer_mec_spinlock_create(struct dp_soc *soc); + +/** + * dp_peer_mec_spinlock_destroy() - Destroy the MEC spinlock + * @soc: SoC handle + * + * Return: none + */ +void dp_peer_mec_spinlock_destroy(struct dp_soc *soc); + +/** + * dp_peer_mec_flush_entries() - Delete all mec entries in table + * @soc: Datapath SOC + * + * Return: None + */ +void dp_peer_mec_flush_entries(struct dp_soc *soc); +#else +static inline void dp_peer_mec_spinlock_create(struct dp_soc *soc) +{ +} + +static inline void dp_peer_mec_spinlock_destroy(struct dp_soc *soc) +{ +} + +static inline void dp_peer_mec_flush_entries(struct dp_soc *soc) +{ +} +#endif #endif /* _DP_PEER_H_ */ diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index ef129aa49c..bc1d471505 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -45,6 +45,7 @@ /* Max buffer in invalid peer SG list*/ #define DP_MAX_INVALID_BUFFERS 10 +#ifdef FEATURE_MEC /** * dp_rx_mcast_echo_check() - check if the mcast pkt is a loop * back on same vap or a different vap. @@ -58,13 +59,13 @@ * */ static inline bool dp_rx_mcast_echo_check(struct dp_soc *soc, - struct dp_peer *peer, - uint8_t *rx_tlv_hdr, - qdf_nbuf_t nbuf) + struct dp_peer *peer, + uint8_t *rx_tlv_hdr, + qdf_nbuf_t nbuf) { struct dp_vdev *vdev = peer->vdev; - struct dp_ast_entry *ase = NULL; - uint16_t sa_idx = 0; + struct dp_pdev *pdev = vdev->pdev; + struct dp_mec_entry *mecentry = NULL; uint8_t *data; /* @@ -102,67 +103,30 @@ static inline bool dp_rx_mcast_echo_check(struct dp_soc *soc, * wireless STAs MAC addr which are behind the Repeater, * then drop the pkt as it is looped back */ - qdf_spin_lock_bh(&soc->ast_lock); - if (hal_rx_msdu_end_sa_is_valid_get(soc->hal_soc, rx_tlv_hdr)) { - sa_idx = hal_rx_msdu_end_sa_idx_get(soc->hal_soc, rx_tlv_hdr); + qdf_spin_lock_bh(&soc->mec_lock); - if ((sa_idx < 0) || - (sa_idx >= wlan_cfg_get_max_ast_idx(soc->wlan_cfg_ctx))) { - qdf_spin_unlock_bh(&soc->ast_lock); - QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "invalid sa_idx: %d", sa_idx); - qdf_assert_always(0); - } - - ase = soc->ast_table[sa_idx]; - if (!ase) { - /* We do not get a peer map event for STA and without - * this event we don't know what is STA's sa_idx. - * For this reason the AST is still not associated to - * any index postion in ast_table. - * In these kind of scenarios where sa is valid but - * ast is not in ast_table, we use the below API to get - * AST entry for STA's own mac_address. - */ - ase = dp_peer_ast_hash_find_by_vdevid - (soc, &data[QDF_MAC_ADDR_SIZE], - peer->vdev->vdev_id); - if (ase) { - ase->ast_idx = sa_idx; - soc->ast_table[sa_idx] = ase; - ase->is_mapped = TRUE; - } - } - } else { - ase = dp_peer_ast_hash_find_by_pdevid(soc, - &data[QDF_MAC_ADDR_SIZE], - vdev->pdev->pdev_id); + mecentry = dp_peer_mec_hash_find_by_pdevid(soc, pdev->pdev_id, + &data[QDF_MAC_ADDR_SIZE]); + if (!mecentry) { + qdf_spin_unlock_bh(&soc->mec_lock); + return false; } - if (ase) { + qdf_spin_unlock_bh(&soc->mec_lock); - if (ase->pdev_id != vdev->pdev->pdev_id) { - qdf_spin_unlock_bh(&soc->ast_lock); - dp_rx_err_info("%pK: Detected DBDC Root AP "QDF_MAC_ADDR_FMT", %d %d", - soc, QDF_MAC_ADDR_REF(&data[QDF_MAC_ADDR_SIZE]), - vdev->pdev->pdev_id, - ase->pdev_id); - return false; - } - - if ((ase->type == CDP_TXRX_AST_TYPE_MEC) || - (ase->peer_id != peer->peer_id)) { - qdf_spin_unlock_bh(&soc->ast_lock); - dp_rx_err_info("%pK: received pkt with same src mac "QDF_MAC_ADDR_FMT, - soc, QDF_MAC_ADDR_REF(&data[QDF_MAC_ADDR_SIZE])); - - return true; - } - } - qdf_spin_unlock_bh(&soc->ast_lock); + dp_rx_err_info("%pK: received pkt with same src mac " QDF_MAC_ADDR_FMT, + soc, QDF_MAC_ADDR_REF(&data[QDF_MAC_ADDR_SIZE])); + return true; +} +#else +static inline bool dp_rx_mcast_echo_check(struct dp_soc *soc, + struct dp_peer *peer, + uint8_t *rx_tlv_hdr, + qdf_nbuf_t nbuf) +{ return false; } - +#endif #endif /* QCA_HOST_MODE_WIFI_DISABLED */ void dp_rx_link_desc_refill_duplicate_check( diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index d540c0a667..8dca7698c0 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -851,6 +851,11 @@ struct dp_soc_stats { uint32_t ast_mismatch; } ast; + struct { + uint32_t added; + uint32_t deleted; + } mec; + /* SOC level TX stats */ struct { /* Total packets transmitted */ @@ -1085,6 +1090,25 @@ struct dp_ast_entry { TAILQ_ENTRY(dp_ast_entry) hash_list_elem; }; +/* + * dp_mec_entry + * + * @mac_addr: MAC Address for this MEC entry + * @is_active: flag to indicate active data traffic on this node + * (used for aging out/expiry) + * @pdev_id: pdev ID + * @vdev_id: vdev ID + * @hash_list_elem: node in soc MEC hash list (mac address used as hash) + */ +struct dp_mec_entry { + union dp_align_mac_addr mac_addr; + bool is_active; + uint8_t pdev_id; + uint8_t vdev_id; + + TAILQ_ENTRY(dp_mec_entry) hash_list_elem; +}; + /* SOC level htt stats */ struct htt_t2h_stats { /* lock to protect htt_stats_msg update */ @@ -1545,7 +1569,6 @@ struct dp_soc { unsigned idx_bits; TAILQ_HEAD(, dp_ast_entry) * bins; } ast_hash; - struct dp_rx_history *rx_ring_history[MAX_REO_DEST_RINGS]; struct dp_rx_err_history *rx_err_ring_history; struct dp_rx_reinject_history *rx_reinject_ring_history; @@ -1725,6 +1748,21 @@ struct dp_soc { #endif /* Invalid buffer that allocated for RX buffer */ qdf_nbuf_queue_t invalid_buf_queue; + +#ifdef FEATURE_MEC + /** @mec_lock: spinlock for MEC table */ + qdf_spinlock_t mec_lock; + /** @mec_cnt: number of active mec entries */ + qdf_atomic_t mec_cnt; + struct { + /** @mask: mask bits */ + uint32_t mask; + /** @idx_bits: index to shift bits */ + uint32_t idx_bits; + /** @bins: MEC table */ + TAILQ_HEAD(, dp_mec_entry) * bins; + } mec_hash; +#endif }; #ifdef IPA_OFFLOAD