diff --git a/dp/inc/cdp_txrx_cmn_struct.h b/dp/inc/cdp_txrx_cmn_struct.h index 48d0b837bb..9f1011e911 100644 --- a/dp/inc/cdp_txrx_cmn_struct.h +++ b/dp/inc/cdp_txrx_cmn_struct.h @@ -485,6 +485,7 @@ enum cdp_vdev_param_type { CDP_ENABLE_WDS, CDP_ENABLE_PROXYSTA, CDP_UPDATE_TDLS_FLAGS, + CDP_CFG_WDS_AGING_TIMER, }; #define TXRX_FW_STATS_TXSTATS 1 diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 89dbd251b8..33bfde183a 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -40,6 +40,7 @@ #include "qdf_mem.h" /* qdf_mem_malloc,free */ #define DP_INTR_POLL_TIMER_MS 10 +#define DP_WDS_AGING_TIMER_DEFAULT_MS 6000 #define DP_MCS_LENGTH (6*MAX_MCS) #define DP_NSS_LENGTH (6*SS_COUNT) #define DP_RXDMA_ERR_LENGTH (6*MAX_RXDMA_ERRORS) @@ -877,6 +878,97 @@ static void dp_hw_link_desc_pool_cleanup(struct dp_soc *soc) #define RXDMA_MONITOR_DESC_RING_SIZE 1024 #define RXDMA_ERR_DST_RING_SIZE 1024 +/* + * dp_wds_aging_timer_fn() - Timer callback function for WDS aging + * @soc: Datapath SOC handle + * + * This is a timer function used to age out stale WDS nodes from + * AST table + */ +#ifdef FEATURE_WDS +static void dp_wds_aging_timer_fn(void *soc_hdl) +{ + struct dp_soc *soc = (struct dp_soc *) soc_hdl; + struct dp_pdev *pdev; + struct dp_vdev *vdev; + struct dp_peer *peer; + struct dp_ast_entry *ase; + int i; + + qdf_spin_lock_bh(&soc->ast_lock); + + for (i = 0; i < MAX_PDEV_CNT && soc->pdev_list[i]; i++) { + pdev = soc->pdev_list[i]; + DP_PDEV_ITERATE_VDEV_LIST(pdev, vdev) { + DP_VDEV_ITERATE_PEER_LIST(vdev, peer) { + DP_PEER_ITERATE_ASE_LIST(peer, ase) { + /* + * Do not expire static ast entries + */ + if (ase->is_static) + continue; + + if (ase->is_active) { + ase->is_active = FALSE; + continue; + } + + soc->cdp_soc.ol_ops->peer_del_wds_entry( + pdev->osif_pdev, + ase->mac_addr.raw); + + dp_peer_del_ast(soc, ase); + } + } + } + + } + + qdf_spin_unlock_bh(&soc->ast_lock); + + if (qdf_atomic_read(&soc->cmn_init_done)) + qdf_timer_mod(&soc->wds_aging_timer, DP_WDS_AGING_TIMER_DEFAULT_MS); +} + +/* + * dp_soc_wds_attach() - Setup WDS timer and AST table + * @soc: Datapath SOC handle + * + * Return: None + */ +static void dp_soc_wds_attach(struct dp_soc *soc) +{ + qdf_spinlock_create(&soc->ast_lock); + + qdf_timer_init(soc->osdev, &soc->wds_aging_timer, + dp_wds_aging_timer_fn, (void *)soc, + QDF_TIMER_TYPE_WAKE_APPS); + + qdf_timer_mod(&soc->wds_aging_timer, DP_WDS_AGING_TIMER_DEFAULT_MS); +} + +/* + * dp_soc_wds_detach() - Detach WDS data structures and timers + * @txrx_soc: DP SOC handle + * + * Return: None + */ +static void dp_soc_wds_detach(struct dp_soc *soc) +{ + qdf_timer_stop(&soc->wds_aging_timer); + qdf_timer_free(&soc->wds_aging_timer); + qdf_spinlock_destroy(&soc->ast_lock); +} +#else +static void dp_soc_wds_attach(struct dp_soc *soc) +{ +} + +static void dp_soc_wds_detach(struct dp_soc *soc) +{ +} +#endif + /* * dp_soc_cmn_setup() - Common SoC level initializion * @soc: Datapath SOC handle @@ -1035,6 +1127,8 @@ static int dp_soc_cmn_setup(struct dp_soc *soc) goto fail1; } + dp_soc_wds_attach(soc); + /* Setup HW REO */ qdf_mem_zero(&reo_params, sizeof(reo_params)); @@ -1578,6 +1672,9 @@ static void dp_soc_detach_wifi3(void *txrx_soc) dp_reo_desc_freelist_destroy(soc); wlan_cfg_soc_detach(soc->wlan_cfg_ctx); + + dp_soc_wds_detach(soc); + qdf_mem_free(soc); } @@ -1960,11 +2057,8 @@ static void *dp_peer_create_wifi3(struct cdp_vdev *vdev_handle, qdf_mem_zero(peer, sizeof(struct dp_peer)); TAILQ_INIT(&peer->ast_entry_list); - qdf_mem_copy(&peer->self_ast_entry.mac_addr, peer_mac_addr, - DP_MAC_ADDR_LEN); - peer->self_ast_entry.peer = peer; - TAILQ_INSERT_TAIL(&peer->ast_entry_list, &peer->self_ast_entry, - ast_entry_elem); + + dp_peer_add_ast(soc, peer, peer_mac_addr, 1); qdf_spinlock_create(&peer->peer_info_lock); @@ -2008,6 +2102,7 @@ static void *dp_peer_create_wifi3(struct cdp_vdev *vdev_handle, vdev->vap_bss_peer = peer; } + #ifndef CONFIG_WIN dp_local_peer_id_alloc(pdev, peer); #endif @@ -2257,8 +2352,6 @@ void dp_peer_unref_delete(void *peer_handle) struct dp_peer *tmppeer; int found = 0; uint16_t peer_id; - uint16_t hw_peer_id; - struct dp_ast_entry *ast_entry; /* * Hold the lock all the way from checking if the peer ref count @@ -2342,17 +2435,6 @@ void dp_peer_unref_delete(void *peer_handle) #ifdef notyet qdf_mempool_free(soc->osdev, soc->mempool_ol_ath_peer, peer); #else - TAILQ_FOREACH(ast_entry, &peer->ast_entry_list, - ast_entry_elem) { - hw_peer_id = ast_entry->ast_idx; - if (peer->self_ast_entry.ast_idx != hw_peer_id) - qdf_mem_free(ast_entry); - else - peer->self_ast_entry.ast_idx = - HTT_INVALID_PEER; - - soc->ast_table[hw_peer_id] = NULL; - } qdf_mem_free(peer); #endif if (soc->cdp_soc.ol_ops->peer_unref_delete) { @@ -3584,6 +3666,14 @@ static void dp_set_vdev_param(struct cdp_vdev *vdev_handle, case CDP_UPDATE_TDLS_FLAGS: vdev->tdls_link_connected = val; break; + case CDP_CFG_WDS_AGING_TIMER: + if (val == 0) + qdf_timer_stop(&vdev->pdev->soc->wds_aging_timer); + else if (val != vdev->wds_aging_timer_val) + qdf_timer_mod(&vdev->pdev->soc->wds_aging_timer, val); + + vdev->wds_aging_timer_val = val; + break; default: break; } @@ -3913,6 +4003,48 @@ static struct cdp_wds_ops dp_ops_wds = { .vdev_set_wds = dp_vdev_set_wds, }; +/* + * dp_peer_delete_ast_entries(): Delete all AST entries for a peer + * @soc - datapath soc handle + * @peer - datapath peer handle + * + * Delete the AST entries belonging to a peer + */ +#ifdef FEATURE_WDS +static inline void dp_peer_delete_ast_entries(struct dp_soc *soc, + struct dp_peer *peer) +{ + struct dp_ast_entry *ast_entry; + qdf_spin_lock_bh(&soc->ast_lock); + DP_PEER_ITERATE_ASE_LIST(peer, ast_entry) { + if (ast_entry->next_hop) { + soc->cdp_soc.ol_ops->peer_del_wds_entry( + soc->osif_soc, + ast_entry->mac_addr.raw); + } + + dp_peer_del_ast(soc, ast_entry); + } + qdf_spin_unlock_bh(&soc->ast_lock); +} +#else +static inline void dp_peer_delete_ast_entries(struct dp_soc *soc, + struct dp_peer *peer) +{ +} +#endif + +#ifdef CONFIG_WIN +static void dp_peer_teardown_wifi3(struct cdp_vdev *vdev_hdl, void *peer_hdl) +{ + struct dp_vdev *vdev = (struct dp_vdev *) vdev_hdl; + struct dp_peer *peer = (struct dp_peer *) peer_hdl; + struct dp_soc *soc = (struct dp_soc *) vdev->pdev->soc; + + dp_peer_delete_ast_entries(soc, peer); +} +#endif + static struct cdp_cmn_ops dp_ops_cmn = { .txrx_soc_attach_target = dp_soc_attach_target_wifi3, .txrx_vdev_attach = dp_vdev_attach_wifi3, @@ -3921,7 +4053,11 @@ static struct cdp_cmn_ops dp_ops_cmn = { .txrx_pdev_detach = dp_pdev_detach_wifi3, .txrx_peer_create = dp_peer_create_wifi3, .txrx_peer_setup = dp_peer_setup_wifi3, +#ifdef CONFIG_WIN + .txrx_peer_teardown = dp_peer_teardown_wifi3, +#else .txrx_peer_teardown = NULL, +#endif .txrx_peer_delete = dp_peer_delete_wifi3, .txrx_vdev_register = dp_vdev_register_wifi3, .txrx_soc_detach = dp_soc_detach_wifi3, diff --git a/dp/wifi3.0/dp_peer.c b/dp/wifi3.0/dp_peer.c index 4900e0f936..9a33589998 100644 --- a/dp/wifi3.0/dp_peer.c +++ b/dp/wifi3.0/dp_peer.c @@ -124,6 +124,9 @@ static int dp_peer_find_add_id_to_obj( #define DP_PEER_HASH_LOAD_MULT 2 #define DP_PEER_HASH_LOAD_SHIFT 0 +#define DP_AST_HASH_LOAD_MULT 2 +#define DP_AST_HASH_LOAD_SHIFT 0 + static int dp_peer_find_hash_attach(struct dp_soc *soc) { int i, hash_elems, log2; @@ -186,6 +189,300 @@ void dp_peer_find_hash_add(struct dp_soc *soc, struct dp_peer *peer) qdf_spin_unlock_bh(&soc->peer_ref_mutex); } +#ifdef FEATURE_WDS +/* + * dp_peer_ast_hash_attach() - Allocate and initialize AST Hash Table + * @soc: SoC handle + * + * Return: None + */ +static int dp_peer_ast_hash_attach(struct dp_soc *soc) +{ + int i, hash_elems, log2; + + hash_elems = ((WLAN_UMAC_PSOC_MAX_PEERS * DP_AST_HASH_LOAD_MULT) >> + DP_AST_HASH_LOAD_SHIFT); + + log2 = dp_log2_ceil(hash_elems); + hash_elems = 1 << log2; + + soc->ast_hash.mask = hash_elems - 1; + soc->ast_hash.idx_bits = log2; + + /* allocate an array of TAILQ peer object lists */ + soc->ast_hash.bins = qdf_mem_malloc( + hash_elems * sizeof(TAILQ_HEAD(anonymous_tail_q, + dp_ast_entry))); + + if (!soc->ast_hash.bins) + return QDF_STATUS_E_NOMEM; + + for (i = 0; i < hash_elems; i++) + TAILQ_INIT(&soc->ast_hash.bins[i]); + + return 0; +} + +/* + * dp_peer_ast_hash_detach() - Free AST Hash table + * @soc: SoC handle + * + * Return: None + */ +static void dp_peer_ast_hash_detach(struct dp_soc *soc) +{ + qdf_mem_free(soc->ast_hash.bins); +} + +/* + * dp_peer_ast_hash_index() - Compute the AST hash from MAC address + * @soc: SoC handle + * + * Return: AST hash + */ +static inline uint32_t dp_peer_ast_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->ast_hash.idx_bits; + index &= soc->ast_hash.mask; + return index; +} + +/* + * dp_peer_ast_hash_add() - Add AST entry into hash table + * @soc: SoC handle + * + * This function adds the AST entry into SoC AST hash table + * It assumes caller has taken the ast lock to protect the access to this table + * + * Return: None + */ +static inline void dp_peer_ast_hash_add(struct dp_soc *soc, + struct dp_ast_entry *ase) +{ + uint32_t index; + + index = dp_peer_ast_hash_index(soc, &ase->mac_addr); + TAILQ_INSERT_TAIL(&soc->ast_hash.bins[index], ase, hash_list_elem); +} + +/* + * dp_peer_ast_hash_remove() - Look up and remove AST entry from hash table + * @soc: SoC handle + * + * This function removes the AST entry from soc AST hash table + * It assumes caller has taken the ast lock to protect the access to this table + * + * Return: None + */ +static inline void dp_peer_ast_hash_remove(struct dp_soc *soc, + struct dp_ast_entry *ase) +{ + unsigned index; + struct dp_ast_entry *tmpase; + int found = 0; + + index = dp_peer_ast_hash_index(soc, &ase->mac_addr); + /* Check if tail is not empty before delete*/ + QDF_ASSERT(!TAILQ_EMPTY(&soc->ast_hash.bins[index])); + + TAILQ_FOREACH(tmpase, &soc->ast_hash.bins[index], hash_list_elem) { + if (tmpase == ase) { + found = 1; + break; + } + } + + QDF_ASSERT(found); + TAILQ_REMOVE(&soc->ast_hash.bins[index], ase, hash_list_elem); +} + +/* + * dp_peer_ast_hash_find() - Find AST entry by MAC address + * @soc: SoC handle + * + * It assumes caller has taken the ast lock to protect the access to + * AST hash table + * + * Return: AST entry + */ +struct dp_ast_entry *dp_peer_ast_hash_find(struct dp_soc *soc, + uint8_t *ast_mac_addr, int mac_addr_is_aligned) +{ + union dp_align_mac_addr local_mac_addr_aligned, *mac_addr; + unsigned index; + struct dp_ast_entry *ase; + + if (mac_addr_is_aligned) { + mac_addr = (union dp_align_mac_addr *) ast_mac_addr; + } else { + qdf_mem_copy( + &local_mac_addr_aligned.raw[0], + ast_mac_addr, DP_MAC_ADDR_LEN); + mac_addr = &local_mac_addr_aligned; + } + + index = dp_peer_ast_hash_index(soc, mac_addr); + TAILQ_FOREACH(ase, &soc->ast_hash.bins[index], hash_list_elem) { + if (dp_peer_find_mac_addr_cmp(mac_addr, &ase->mac_addr) == 0) { + return ase; + } + } + + return NULL; +} + +/* + * dp_peer_map_ast() - Map the ast entry with HW AST Index + * @soc: SoC handle + * @peer: peer to which ast node belongs + * @mac_addr: MAC address of ast node + * @hw_peer_id: HW AST Index returned by target in peer map event + * @vdev_id: vdev id for VAP to which the peer belongs to + * + * Return: None + */ +static inline void dp_peer_map_ast(struct dp_soc *soc, + struct dp_peer *peer, uint8_t *mac_addr, uint16_t hw_peer_id, + uint8_t vdev_id) +{ + struct dp_ast_entry *ast_entry; + + if (!peer) { + return; + } + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: peer %p ID %d vid %d mac %02x:%02x:%02x:%02x:%02x:%02x\n", + __func__, peer, hw_peer_id, vdev_id, mac_addr[0], + mac_addr[1], mac_addr[2], mac_addr[3], + mac_addr[4], mac_addr[5]); + + qdf_spin_lock_bh(&soc->ast_lock); + TAILQ_FOREACH(ast_entry, &peer->ast_entry_list, ase_list_elem) { + if (!(qdf_mem_cmp(mac_addr, ast_entry->mac_addr.raw, + DP_MAC_ADDR_LEN))) { + qdf_spin_unlock_bh(&soc->ast_lock); + ast_entry->ast_idx = hw_peer_id; + soc->ast_table[hw_peer_id] = ast_entry; + ast_entry->is_active = TRUE; + return; + } + } + qdf_spin_unlock_bh(&soc->ast_lock); + + if (soc->cdp_soc.ol_ops->peer_map_event) { + soc->cdp_soc.ol_ops->peer_map_event(soc->osif_soc, + peer->peer_ids[0], hw_peer_id, vdev_id, + mac_addr); + } + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "AST entry not found\n"); + return; +} + +/* + * dp_peer_add_ast() - Allocate and add AST entry into peer list + * @soc: SoC handle + * @peer: peer to which ast node belongs + * @mac_addr: MAC address of ast node + * @is_self: Is this base AST entry with peer mac address + * + * This API is used by WDS source port learning funtion to + * add a new AST entry into peer AST list + * + * Return: 0 if new entry is allocated, + * 1 if entry already exists or if allocation has failed + */ +int dp_peer_add_ast(struct dp_soc *soc, struct dp_peer *peer, + uint8_t *mac_addr, bool is_self) +{ + struct dp_ast_entry *ast_entry; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: peer %p mac %02x:%02x:%02x:%02x:%02x:%02x\n", + __func__, peer, mac_addr[0], mac_addr[1], mac_addr[2], + mac_addr[3], mac_addr[4], mac_addr[5]); + + qdf_spin_lock_bh(&soc->ast_lock); + + /* If AST entry already exists , just return from here */ + if (dp_peer_ast_hash_find(soc, mac_addr, 0)) { + qdf_spin_unlock_bh(&soc->ast_lock); + return 1; + } + + ast_entry = (struct dp_ast_entry *) + qdf_mem_malloc(sizeof(struct dp_ast_entry)); + + if (!ast_entry) { + qdf_spin_unlock_bh(&soc->ast_lock); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + FL("fail to allocate ast_entry")); + QDF_ASSERT(0); + return 1; + } + + qdf_mem_copy(&ast_entry->mac_addr.raw[0], mac_addr, DP_MAC_ADDR_LEN); + ast_entry->peer = peer; + + if (is_self) { + peer->self_ast_entry = ast_entry; + ast_entry->is_static = TRUE; + } else { + ast_entry->next_hop = 1; + ast_entry->is_static = FALSE; + } + + ast_entry->is_active = TRUE; + TAILQ_INSERT_TAIL(&peer->ast_entry_list, ast_entry, ase_list_elem); + dp_peer_ast_hash_add(soc, ast_entry); + qdf_spin_unlock_bh(&soc->ast_lock); + return 0; +} + +/* + * dp_peer_del_ast() - Delete and free AST entry + * @soc: SoC handle + * @ast_entry: AST entry of the node + * + * This function removes the AST entry from peer and soc tables + * It assumes caller has taken the ast lock to protect the access to these + * tables + * + * Return: None + */ +void dp_peer_del_ast(struct dp_soc *soc, + struct dp_ast_entry *ast_entry) +{ + struct dp_peer *peer = ast_entry->peer; + soc->ast_table[ast_entry->ast_idx] = NULL; + TAILQ_REMOVE(&peer->ast_entry_list, ast_entry, ase_list_elem); + dp_peer_ast_hash_remove(soc, ast_entry); + qdf_mem_free(ast_entry); +} +#else +static int dp_peer_ast_hash_attach(struct dp_soc *soc) +{ + return 0; +} +static void dp_peer_ast_hash_detach(struct dp_soc *soc) +{ +} +static inline void dp_peer_map_ast(struct dp_soc *soc, struct dp_peer *peer, + uint8_t *mac_addr, uint16_t hw_peer_id, uint8_t vdev_id) +{ +} + +#endif + #if ATH_SUPPORT_WRAP static 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) @@ -315,6 +612,12 @@ int dp_peer_find_attach(struct dp_soc *soc) dp_peer_find_map_detach(soc); return 1; } + + if (dp_peer_ast_hash_attach(soc)) { + dp_peer_find_hash_detach(soc); + dp_peer_find_map_detach(soc); + return 1; + } return 0; /* success */ } @@ -383,7 +686,7 @@ static void dp_rx_tid_stats_cb(struct dp_soc *soc, void *cb_ctxt, queue_status->hole_cnt); } -static inline void dp_peer_find_add_id(struct dp_soc *soc, +static inline struct dp_peer *dp_peer_find_add_id(struct dp_soc *soc, uint8_t *peer_mac_addr, uint16_t peer_id, uint16_t hw_peer_id, uint8_t vdev_id) { @@ -411,55 +714,16 @@ static inline void dp_peer_find_add_id(struct dp_soc *soc, "%s: ref_cnt: %d", __func__, qdf_atomic_read(&peer->ref_cnt)); soc->peer_id_to_obj_map[peer_id] = peer; - peer->self_ast_entry.ast_idx = hw_peer_id; - soc->ast_table[hw_peer_id] = &peer->self_ast_entry; if (dp_peer_find_add_id_to_obj(peer, peer_id)) { /* TBDXXX: assert for now */ QDF_ASSERT(0); } - return; - } -} - -static inline void dp_peer_add_ast(struct dp_soc *soc, - struct dp_peer *peer, uint8_t *peer_mac_addr, uint16_t hw_peer_id, - uint8_t vdev_id) -{ - struct dp_ast_entry *ast_entry; - - QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "%s: peer %p ID %d vid %d mac %02x:%02x:%02x:%02x:%02x:%02x\n", - __func__, peer, hw_peer_id, vdev_id, peer_mac_addr[0], - peer_mac_addr[1], peer_mac_addr[2], peer_mac_addr[3], - peer_mac_addr[4], peer_mac_addr[5]); - - TAILQ_FOREACH(ast_entry, &peer->ast_entry_list, ast_entry_elem) { - if (!(qdf_mem_cmp(peer_mac_addr, ast_entry->mac_addr, - DP_MAC_ADDR_LEN))) { - soc->ast_table[ast_entry->ast_idx] = NULL; - ast_entry->ast_idx = hw_peer_id; - soc->ast_table[hw_peer_id] = ast_entry; - return; - } + return peer; } - ast_entry = (struct dp_ast_entry *) - qdf_mem_malloc(sizeof(struct dp_ast_entry)); - - if (!ast_entry) { - QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - FL("fail to allocate ast_entry for: %d"), hw_peer_id); - QDF_ASSERT(0); - } - - qdf_mem_copy(&ast_entry->mac_addr, peer_mac_addr, DP_MAC_ADDR_LEN); - ast_entry->peer = peer; - ast_entry->next_hop = 1; - TAILQ_INSERT_TAIL(&peer->ast_entry_list, ast_entry, ast_entry_elem); - soc->ast_table[hw_peer_id] = ast_entry; - return; + return NULL; } /** @@ -483,7 +747,6 @@ dp_rx_peer_map_handler(void *soc_handle, uint16_t peer_id, uint16_t hw_peer_id, struct dp_soc *soc = (struct dp_soc *)soc_handle; struct dp_peer *peer = NULL; - QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, "peer_map_event (soc:%p): peer_id %di, hw_peer_id %d, peer_mac " "%02x:%02x:%02x:%02x:%02x:%02x, vdev_id %d\n", soc, peer_id, @@ -506,18 +769,12 @@ dp_rx_peer_map_handler(void *soc_handle, uint16_t peer_id, uint16_t hw_peer_id, * in this case just add the ast entry to the existing * peer ast_list. */ - if (!peer) { - dp_peer_find_add_id(soc, peer_mac_addr, peer_id, - hw_peer_id, vdev_id); - if (soc->cdp_soc.ol_ops->peer_map_event) { - soc->cdp_soc.ol_ops->peer_map_event(soc->osif_soc, - peer_id, hw_peer_id, vdev_id, peer_mac_addr); - } + if (!peer) + peer = dp_peer_find_add_id(soc, peer_mac_addr, peer_id, + hw_peer_id, vdev_id); - } else { - dp_peer_add_ast(soc, peer, peer_mac_addr, - hw_peer_id, vdev_id); - } + dp_peer_map_ast(soc, peer, peer_mac_addr, + hw_peer_id, vdev_id); } void @@ -565,6 +822,7 @@ dp_peer_find_detach(struct dp_soc *soc) { dp_peer_find_map_detach(soc); dp_peer_find_hash_detach(soc); + dp_peer_ast_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 64fb8f915d..b93229b382 100644 --- a/dp/wifi3.0/dp_peer.h +++ b/dp/wifi3.0/dp_peer.h @@ -54,6 +54,23 @@ void dp_rx_sec_ind_handler(void *soc_handle, uint16_t peer_id, uint8_t dp_get_peer_mac_addr_frm_id(struct cdp_soc_t *soc_handle, uint16_t peer_id, uint8_t *peer_mac); +#ifdef FEATURE_WDS +int dp_peer_add_ast(struct dp_soc *soc, struct dp_peer *peer, + uint8_t *mac_addr, bool is_self); +void dp_peer_del_ast(struct dp_soc *soc, + struct dp_ast_entry *ast_entry); +#else +static inline int dp_peer_add_ast(struct dp_soc *soc, struct dp_peer *peer, + uint8_t *mac_addr, bool is_self) +{ + return 0; +} +static inline void dp_peer_del_ast(struct dp_soc *soc, + struct dp_ast_entry *ast_entry) +{ +} +#endif + #ifdef DP_LFR /* * dp_get_vdev_from_soc_vdev_id_wifi3() - diff --git a/dp/wifi3.0/dp_rx.h b/dp/wifi3.0/dp_rx.h index f97fe57315..82ec30a719 100644 --- a/dp/wifi3.0/dp_rx.h +++ b/dp/wifi3.0/dp_rx.h @@ -344,7 +344,7 @@ void dp_rx_add_to_free_desc_list(union dp_rx_desc_list_elem_t **head, * * Return: void: */ -#ifndef CONFIG_MCL +#ifdef FEATURE_WDS static inline void dp_rx_wds_srcport_learn(struct dp_soc *soc, uint8_t *rx_tlv_hdr, @@ -359,40 +359,61 @@ dp_rx_wds_srcport_learn(struct dp_soc *soc, memcpy(wds_src_mac, (qdf_nbuf_data(nbuf) + IEEE80211_ADDR_LEN), IEEE80211_ADDR_LEN); - if (!hal_rx_msdu_end_sa_is_valid_get(rx_tlv_hdr)) { - ret = soc->cdp_soc.ol_ops->peer_add_wds_entry( - ta_peer->vdev->pdev->osif_pdev, - wds_src_mac, - ta_peer->mac_addr.raw, - flags); - } else if (sa_sw_peer_id != ta_peer->peer_ids[0]) { - ret = soc->cdp_soc.ol_ops->peer_update_wds_entry( - ta_peer->vdev->pdev->osif_pdev, - wds_src_mac, - ta_peer->mac_addr.raw, - flags); + if (qdf_unlikely(!hal_rx_msdu_end_sa_is_valid_get(rx_tlv_hdr))) { + if (!dp_peer_add_ast(soc, ta_peer, wds_src_mac, 0)) { + ret = soc->cdp_soc.ol_ops->peer_add_wds_entry( + ta_peer->vdev->pdev->osif_pdev, + wds_src_mac, + ta_peer->mac_addr.raw, + flags); + } + } else { + /* + * Get the AST entry from HW SA index and mark it as active + */ + struct dp_ast_entry *ast; + uint16_t sa_idx = hal_rx_msdu_end_sa_idx_get(rx_tlv_hdr); + ast = soc->ast_table[sa_idx]; + + /* + * Ensure we are updating the right AST entry by + * validating ast_idx. + * There is a possibility we might arrive here without + * AST MAP event , so this check is mandatory + */ + if (ast && (ast->ast_idx == sa_idx)) { + ast->is_active = TRUE; + } + + if (sa_sw_peer_id != ta_peer->peer_ids[0]) { + ret = soc->cdp_soc.ol_ops->peer_update_wds_entry( + ta_peer->vdev->pdev->osif_pdev, + wds_src_mac, + ta_peer->mac_addr.raw, + flags); + } } return; } #else -static inline void + static inline void dp_rx_wds_srcport_learn(struct dp_soc *soc, - uint8_t *rx_tlv_hdr, - struct dp_peer *ta_peer, - qdf_nbuf_t nbuf) + uint8_t *rx_tlv_hdr, + struct dp_peer *ta_peer, + qdf_nbuf_t nbuf) { } #endif uint8_t dp_rx_process_invalid_peer(struct dp_soc *soc, qdf_nbuf_t nbuf); #define DP_RX_LIST_APPEND(head, tail, elem) \ -do { \ - if (!(head)) { \ - (head) = (elem); \ - } else { \ - qdf_nbuf_set_next((tail), (elem)); \ - } \ - (tail) = (elem); \ + do { \ + if (!(head)) { \ + (head) = (elem); \ + } else { \ + qdf_nbuf_set_next((tail), (elem)); \ + } \ + (tail) = (elem); \ qdf_nbuf_set_next((tail), NULL); \ } while (0) diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index f08940158f..c54260a8cb 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -104,6 +104,15 @@ union dp_tx_desc_list_elem_t; struct dp_soc; union dp_rx_desc_list_elem_t; +#define DP_PDEV_ITERATE_VDEV_LIST(_pdev, _vdev) \ + TAILQ_FOREACH((_vdev), &(_pdev)->vdev_list, vdev_list_elem) + +#define DP_VDEV_ITERATE_PEER_LIST(_vdev, _peer) \ + TAILQ_FOREACH((_peer), &(_vdev)->peer_list, peer_list_elem) + +#define DP_PEER_ITERATE_ASE_LIST(_peer, _ase) \ + TAILQ_FOREACH((_ase), &peer->ast_entry_list, ase_list_elem) + #define DP_MUTEX_TYPE qdf_spinlock_t #define DP_FRAME_IS_MULTICAST(_a) (*(_a) & 0x01) @@ -380,12 +389,48 @@ struct reo_desc_list_node { struct dp_rx_tid rx_tid; }; +#define DP_MAC_ADDR_LEN 6 +union dp_align_mac_addr { + uint8_t raw[DP_MAC_ADDR_LEN]; + struct { + uint16_t bytes_ab; + uint16_t bytes_cd; + uint16_t bytes_ef; + } align2; + struct { + uint32_t bytes_abcd; + uint16_t bytes_ef; + } align4; + struct { + uint16_t bytes_ab; + uint32_t bytes_cdef; + } align4_2; +}; + +/* + * dp_ast_entry + * + * @ast_idx: Hardware AST Index + * @mac_addr: MAC Address for this AST entry + * @peer: Next Hop peer (for non-WDS nodes, this will be point to + * associated peer with this MAC address) + * @next_hop: Set to 1 if this is for a WDS node + * @is_active: flag to indicate active data traffic on this node + * (used for aging out/expiry) + * @is_static: flag to indicate static entry (should not be expired) + * @ase_list_elem: node in peer AST list + * @hash_list_elem: node in soc AST hash list (mac address used as hash) + */ struct dp_ast_entry { uint16_t ast_idx; - uint8_t mac_addr[DP_MAC_ADDR_LEN]; - uint8_t next_hop; + /* MAC address */ + union dp_align_mac_addr mac_addr; struct dp_peer *peer; - TAILQ_ENTRY(dp_ast_entry) ast_entry_elem; + bool next_hop; + bool is_active; + bool is_static; + TAILQ_ENTRY(dp_ast_entry) ase_list_elem; + TAILQ_ENTRY(dp_ast_entry) hash_list_elem; }; struct mect_entry { @@ -617,6 +662,14 @@ struct dp_soc { bool process_tx_status; struct dp_ast_entry *ast_table[WLAN_UMAC_PSOC_MAX_PEERS]; + struct { + unsigned mask; + unsigned idx_bits; + TAILQ_HEAD(, dp_ast_entry) * bins; + } ast_hash; + + qdf_spinlock_t ast_lock; + qdf_timer_t wds_aging_timer; #ifdef DP_INTR_POLL_BASED /*interrupt timer*/ @@ -668,19 +721,6 @@ enum dp_nac_param_cmd { /* IEEE80211_NAC_PARAM_LIST */ DP_NAC_PARAM_LIST, }; -#define DP_MAC_ADDR_LEN 6 -union dp_align_mac_addr { - uint8_t raw[DP_MAC_ADDR_LEN]; - struct { - uint16_t bytes_ab; - uint16_t bytes_cd; - uint16_t bytes_ef; - } align2; - struct { - uint32_t bytes_abcd; - uint16_t bytes_ef; - } align4; -}; /** * struct dp_neighbour_peer - neighbour peer list type for smart mesh @@ -920,6 +960,9 @@ struct dp_vdev { /* WDS enabled */ bool wds_enabled; + /* WDS Aging timer period */ + uint32_t wds_aging_timer_val; + /* NAWDS enabled */ bool nawds_enabled; @@ -968,7 +1011,7 @@ struct dp_peer { /* VDEV to which this peer is associated */ struct dp_vdev *vdev; - struct dp_ast_entry self_ast_entry; + struct dp_ast_entry *self_ast_entry; qdf_atomic_t ref_cnt; diff --git a/dp/wifi3.0/hal_rx.h b/dp/wifi3.0/hal_rx.h index af8d7d721c..3f8e4e6bda 100644 --- a/dp/wifi3.0/hal_rx.h +++ b/dp/wifi3.0/hal_rx.h @@ -813,6 +813,31 @@ hal_rx_msdu_end_l3_hdr_padding_get(uint8_t *buf) return l3_header_padding; } +#define HAL_RX_MSDU_END_SA_IDX_GET(_rx_msdu_end) \ + (_HAL_MS((*_OFFSET_TO_WORD_PTR(_rx_msdu_end, \ + RX_MSDU_END_13_SA_IDX_OFFSET)), \ + RX_MSDU_END_13_SA_IDX_MASK, \ + RX_MSDU_END_13_SA_IDX_LSB)) + + /** + * hal_rx_msdu_end_sa_idx_get(): API to get the + * sa_idx from rx_msdu_end TLV + * + * @ buf: pointer to the start of RX PKT TLV headers + * Return: sa_idx (SA AST index) + */ +static inline uint16_t +hal_rx_msdu_end_sa_idx_get(uint8_t *buf) +{ + struct rx_pkt_tlvs *pkt_tlvs = (struct rx_pkt_tlvs *)buf; + struct rx_msdu_end *msdu_end = &pkt_tlvs->msdu_end_tlv.rx_msdu_end; + uint8_t sa_idx; + + sa_idx = HAL_RX_MSDU_END_SA_IDX_GET(msdu_end); + + return sa_idx; +} + #define HAL_RX_MSDU_END_SA_IS_VALID_GET(_rx_msdu_end) \ (_HAL_MS((*_OFFSET_TO_WORD_PTR(_rx_msdu_end, \ RX_MSDU_END_5_SA_IS_VALID_OFFSET)), \