diff options
| -rw-r--r-- | drivers/net/wireless/ath/ath12k/dp.c | 14 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath12k/dp.h | 10 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath12k/dp_peer.c | 138 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath12k/dp_peer.h | 9 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath12k/mac.c | 2 |
5 files changed, 160 insertions, 13 deletions
diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index 40057df4cd66..676af752f069 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -1122,6 +1122,8 @@ static void ath12k_dp_cleanup(struct ath12k_base *ab) struct ath12k_dp *dp = ath12k_ab_to_dp(ab); int i; + ath12k_dp_link_peer_rhash_tbl_destroy(dp); + if (!dp->ab) return; @@ -1487,14 +1489,22 @@ static int ath12k_dp_setup(struct ath12k_base *ab) spin_lock_init(&dp->dp_lock); INIT_LIST_HEAD(&dp->peers); + mutex_init(&dp->link_peer_rhash_tbl_lock); + dp->reo_cmd_cache_flush_count = 0; dp->idle_link_rbm = ath12k_hal_get_idle_link_rbm(&ab->hal, ab->device_id); + ret = ath12k_dp_link_peer_rhash_tbl_init(dp); + if (ret) { + ath12k_warn(ab, "failed to init link_peer rhash table: %d\n", ret); + return ret; + } + ret = ath12k_wbm_idle_ring_setup(ab, &n_link_desc); if (ret) { ath12k_warn(ab, "failed to setup wbm_idle_ring: %d\n", ret); - return ret; + goto rhash_destroy; } srng = &ab->hal.srng_list[dp->wbm_idle_ring.ring_id]; @@ -1575,6 +1585,8 @@ fail_hw_cc_cleanup: fail_link_desc_cleanup: ath12k_dp_link_desc_cleanup(ab, dp->link_desc_banks, HAL_WBM_IDLE_LINK, &dp->wbm_idle_ring); +rhash_destroy: + ath12k_dp_link_peer_rhash_tbl_destroy(dp); return ret; } diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index fc87b749a040..b90725094111 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -10,6 +10,7 @@ #include "hw.h" #include "dp_htt.h" #include "dp_cmn.h" +#include <linux/rhashtable.h> #define MAX_RXDMA_PER_PDEV 2 @@ -471,13 +472,20 @@ struct ath12k_dp { struct ath12k_hw_group *ag; u8 device_id; - /* Lock for protection of peers */ + /* Lock for protection of peers and rhead_peer_addr */ spinlock_t dp_lock; struct ath12k_dp_arch_ops *ops; /* Linked list of struct ath12k_dp_link_peer */ struct list_head peers; + + /* For rhash table init and deinit protection */ + struct mutex link_peer_rhash_tbl_lock; + + /* The rhashtable containing struct ath12k_link_peer keyed by mac addr */ + struct rhashtable *rhead_peer_addr; + struct rhashtable_params rhash_peer_addr_param; }; static inline void ath12k_dp_get_mac_addr(u32 addr_l32, u16 addr_h16, u8 *addr) diff --git a/drivers/net/wireless/ath/ath12k/dp_peer.c b/drivers/net/wireless/ath/ath12k/dp_peer.c index 0267f68f8573..0cf28791568e 100644 --- a/drivers/net/wireless/ath/ath12k/dp_peer.c +++ b/drivers/net/wireless/ath/ath12k/dp_peer.c @@ -51,18 +51,10 @@ ath12k_dp_link_peer_find_by_pdev_and_addr(struct ath12k_dp *dp, u8 pdev_idx, struct ath12k_dp_link_peer * ath12k_dp_link_peer_find_by_addr(struct ath12k_dp *dp, const u8 *addr) { - struct ath12k_dp_link_peer *peer; - lockdep_assert_held(&dp->dp_lock); - list_for_each_entry(peer, &dp->peers, list) { - if (!ether_addr_equal(peer->addr, addr)) - continue; - - return peer; - } - - return NULL; + return rhashtable_lookup_fast(dp->rhead_peer_addr, addr, + dp->rhash_peer_addr_param); } EXPORT_SYMBOL(ath12k_dp_link_peer_find_by_addr); @@ -147,6 +139,7 @@ void ath12k_dp_link_peer_unmap_event(struct ath12k_base *ab, u16 peer_id) ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "htt peer unmap vdev %d peer %pM id %d\n", peer->vdev_id, peer->addr, peer_id); + ath12k_dp_link_peer_rhash_delete(dp, peer); list_del(&peer->list); kfree(peer); wake_up(&ab->peer_mapping_wq); @@ -160,6 +153,7 @@ void ath12k_dp_link_peer_map_event(struct ath12k_base *ab, u8 vdev_id, u16 peer_ { struct ath12k_dp_link_peer *peer; struct ath12k_dp *dp = ath12k_ab_to_dp(ab); + int ret; spin_lock_bh(&dp->dp_lock); peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, mac_addr); @@ -173,7 +167,11 @@ void ath12k_dp_link_peer_map_event(struct ath12k_base *ab, u8 vdev_id, u16 peer_ peer->ast_hash = ast_hash; peer->hw_peer_id = hw_peer_id; ether_addr_copy(peer->addr, mac_addr); - list_add(&peer->list, &dp->peers); + ret = ath12k_dp_link_peer_rhash_add(dp, peer); + if (!ret) + list_add(&peer->list, &dp->peers); + else + kfree(peer); wake_up(&ab->peer_mapping_wq); } @@ -209,3 +207,121 @@ struct ath12k_link_sta *ath12k_dp_link_peer_to_link_sta(struct ath12k_base *ab, } return arsta; } + +static int ath12k_dp_link_peer_rhash_addr_tbl_init(struct ath12k_dp *dp) +{ + struct ath12k_base *ab = dp->ab; + struct rhashtable_params *param; + struct rhashtable *rhash_addr_tbl; + int ret; + + lockdep_assert_held(&dp->link_peer_rhash_tbl_lock); + + rhash_addr_tbl = kzalloc(sizeof(*dp->rhead_peer_addr), GFP_KERNEL); + if (!rhash_addr_tbl) + return -ENOMEM; + + param = &dp->rhash_peer_addr_param; + + param->key_offset = offsetof(struct ath12k_dp_link_peer, addr); + param->head_offset = offsetof(struct ath12k_dp_link_peer, rhash_addr); + param->key_len = sizeof_field(struct ath12k_dp_link_peer, addr); + param->automatic_shrinking = true; + param->nelem_hint = ab->num_radios * ath12k_core_get_max_peers_per_radio(ab); + + ret = rhashtable_init(rhash_addr_tbl, param); + if (ret) { + ath12k_warn(ab, "failed to init peer addr rhash table %d\n", ret); + goto err_free; + } + + dp->rhead_peer_addr = rhash_addr_tbl; + + return 0; + +err_free: + kfree(rhash_addr_tbl); + + return ret; +} + +int ath12k_dp_link_peer_rhash_tbl_init(struct ath12k_dp *dp) +{ + int ret; + + mutex_lock(&dp->link_peer_rhash_tbl_lock); + ret = ath12k_dp_link_peer_rhash_addr_tbl_init(dp); + mutex_unlock(&dp->link_peer_rhash_tbl_lock); + + return ret; +} + +void ath12k_dp_link_peer_rhash_tbl_destroy(struct ath12k_dp *dp) +{ + mutex_lock(&dp->link_peer_rhash_tbl_lock); + rhashtable_destroy(dp->rhead_peer_addr); + kfree(dp->rhead_peer_addr); + dp->rhead_peer_addr = NULL; + mutex_unlock(&dp->link_peer_rhash_tbl_lock); +} + +static int ath12k_dp_link_peer_rhash_insert(struct ath12k_dp *dp, + struct ath12k_dp_link_peer *peer) +{ + struct ath12k_dp_link_peer *tmp; + + lockdep_assert_held(&dp->dp_lock); + + tmp = rhashtable_lookup_get_insert_fast(dp->rhead_peer_addr, &peer->rhash_addr, + dp->rhash_peer_addr_param); + if (!tmp) + return 0; + else if (IS_ERR(tmp)) + return PTR_ERR(tmp); + else + return -EEXIST; +} + +static int ath12k_dp_link_peer_rhash_remove(struct ath12k_dp *dp, + struct ath12k_dp_link_peer *peer) +{ + int ret; + + lockdep_assert_held(&dp->dp_lock); + + ret = rhashtable_remove_fast(dp->rhead_peer_addr, &peer->rhash_addr, + dp->rhash_peer_addr_param); + if (ret && ret != -ENOENT) + return ret; + + return 0; +} + +int ath12k_dp_link_peer_rhash_add(struct ath12k_dp *dp, + struct ath12k_dp_link_peer *peer) +{ + int ret; + + lockdep_assert_held(&dp->dp_lock); + + ret = ath12k_dp_link_peer_rhash_insert(dp, peer); + if (ret) + ath12k_warn(dp, "failed to add peer %pM with id %d in rhash_addr ret %d\n", + peer->addr, peer->peer_id, ret); + + return ret; +} + +void ath12k_dp_link_peer_rhash_delete(struct ath12k_dp *dp, + struct ath12k_dp_link_peer *peer) +{ + /* No failure handling and hence return type is void */ + int ret; + + lockdep_assert_held(&dp->dp_lock); + + ret = ath12k_dp_link_peer_rhash_remove(dp, peer); + if (ret) + ath12k_warn(dp, "failed to remove peer %pM with id %d in rhash_addr ret %d\n", + peer->addr, peer->peer_id, ret); +} diff --git a/drivers/net/wireless/ath/ath12k/dp_peer.h b/drivers/net/wireless/ath/ath12k/dp_peer.h index ecc90df05b44..b94a9a5cb311 100644 --- a/drivers/net/wireless/ath/ath12k/dp_peer.h +++ b/drivers/net/wireless/ath/ath12k/dp_peer.h @@ -63,6 +63,9 @@ struct ath12k_dp_link_peer { /* for reference to ath12k_link_sta */ u8 link_id; bool ucast_ra_only; + + /* peer addr based rhashtable list pointer */ + struct rhash_head rhash_addr; }; void ath12k_dp_link_peer_unmap_event(struct ath12k_base *ab, u16 peer_id); @@ -83,4 +86,10 @@ ath12k_dp_link_peer_find_by_pdev_and_addr(struct ath12k_dp *dp, u8 pdev_idx, const u8 *addr); struct ath12k_link_sta *ath12k_dp_link_peer_to_link_sta(struct ath12k_base *ab, struct ath12k_dp_link_peer *peer); +int ath12k_dp_link_peer_rhash_tbl_init(struct ath12k_dp *dp); +void ath12k_dp_link_peer_rhash_tbl_destroy(struct ath12k_dp *dp); +int ath12k_dp_link_peer_rhash_add(struct ath12k_dp *dp, + struct ath12k_dp_link_peer *peer); +void ath12k_dp_link_peer_rhash_delete(struct ath12k_dp *dp, + struct ath12k_dp_link_peer *peer); #endif diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index fd6819ec390c..c7eeaf586b83 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -1188,6 +1188,8 @@ void ath12k_mac_peer_cleanup_all(struct ath12k *ar) if (peer->sta) ath12k_dp_rx_peer_tid_cleanup(ar, peer); + ath12k_dp_link_peer_rhash_delete(dp, peer); + list_del(&peer->list); kfree(peer); } |
