struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
int i;
+ ath12k_dp_link_peer_rhash_tbl_destroy(dp);
+
if (!dp->ab)
return;
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];
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;
}
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);
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);
{
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);
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);
}
}
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);
+}