mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-07-16 12:46:59 +08:00
679 lines
18 KiB
Diff
679 lines
18 KiB
Diff
From 7b0c70d92a435913f6e11d6a248b935697e8a3eb Mon Sep 17 00:00:00 2001
|
|
From: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
|
|
Date: Wed, 23 Mar 2022 11:14:17 +0200
|
|
Subject: [PATCH] ath11k: Add peer rhash table support
|
|
|
|
When more clients (128) are connected, the UL data traffic
|
|
KPI measurement is low compared to single client. This issue
|
|
is due to more CPU cycles spent on the peer lookup operation
|
|
with more clients. So reduce the peer lookup operation by
|
|
modifying the linear based lookup operation into the rhash
|
|
based lookup operation. This improve the peak throughput
|
|
measurement. Since this is a software algorithm change, it is
|
|
applicable for all the platforms.
|
|
|
|
TCP UL 128 Clients test case Observation (64bit system):
|
|
Previous: ~550 Mbps
|
|
Now : ~860 Mbps
|
|
|
|
Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01067-QCAHKSWPL_SILICONZ-1
|
|
|
|
Signed-off-by: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
|
|
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
|
|
Link: https://lore.kernel.org/r/1644036628-5334-1-git-send-email-quic_periyasa@quicinc.com
|
|
---
|
|
drivers/net/wireless/ath/ath11k/core.c | 3 +-
|
|
drivers/net/wireless/ath/ath11k/core.h | 14 +
|
|
drivers/net/wireless/ath/ath11k/mac.c | 16 +-
|
|
drivers/net/wireless/ath/ath11k/peer.c | 344 +++++++++++++++++++++++--
|
|
drivers/net/wireless/ath/ath11k/peer.h | 10 +-
|
|
5 files changed, 363 insertions(+), 24 deletions(-)
|
|
|
|
--- a/drivers/net/wireless/ath/ath11k/core.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/core.c
|
|
@@ -1,7 +1,7 @@
|
|
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
|
/*
|
|
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
|
- * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
@@ -1680,6 +1680,7 @@ struct ath11k_base *ath11k_core_alloc(st
|
|
goto err_free_wq;
|
|
|
|
mutex_init(&ab->core_lock);
|
|
+ mutex_init(&ab->tbl_mtx_lock);
|
|
spin_lock_init(&ab->base_lock);
|
|
mutex_init(&ab->vdev_id_11d_lock);
|
|
init_completion(&ab->reset_complete);
|
|
--- a/drivers/net/wireless/ath/ath11k/core.h
|
|
+++ b/drivers/net/wireless/ath/ath11k/core.h
|
|
@@ -1,6 +1,7 @@
|
|
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
|
/*
|
|
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
|
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
*/
|
|
|
|
#ifndef ATH11K_CORE_H
|
|
@@ -12,6 +13,7 @@
|
|
#include <linux/bitfield.h>
|
|
#include <linux/dmi.h>
|
|
#include <linux/ctype.h>
|
|
+#include <linux/rhashtable.h>
|
|
#include "qmi.h"
|
|
#include "htc.h"
|
|
#include "wmi.h"
|
|
@@ -803,6 +805,18 @@ struct ath11k_base {
|
|
struct ath11k_pdev __rcu *pdevs_active[MAX_RADIOS];
|
|
struct ath11k_hal_reg_capabilities_ext hal_reg_cap[MAX_RADIOS];
|
|
unsigned long long free_vdev_map;
|
|
+
|
|
+ /* To synchronize rhash tbl write operation */
|
|
+ struct mutex tbl_mtx_lock;
|
|
+
|
|
+ /* The rhashtable containing struct ath11k_peer keyed by mac addr */
|
|
+ struct rhashtable *rhead_peer_addr;
|
|
+ struct rhashtable_params rhash_peer_addr_param;
|
|
+
|
|
+ /* The rhashtable containing struct ath11k_peer keyed by id */
|
|
+ struct rhashtable *rhead_peer_id;
|
|
+ struct rhashtable_params rhash_peer_id_param;
|
|
+
|
|
struct list_head peers;
|
|
wait_queue_head_t peer_mapping_wq;
|
|
u8 mac_addr[ETH_ALEN];
|
|
--- a/drivers/net/wireless/ath/ath11k/mac.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/mac.c
|
|
@@ -1,7 +1,7 @@
|
|
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
|
/*
|
|
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
|
- * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include <net/mac80211.h>
|
|
@@ -875,13 +875,16 @@ void ath11k_mac_peer_cleanup_all(struct
|
|
|
|
lockdep_assert_held(&ar->conf_mutex);
|
|
|
|
+ mutex_lock(&ab->tbl_mtx_lock);
|
|
spin_lock_bh(&ab->base_lock);
|
|
list_for_each_entry_safe(peer, tmp, &ab->peers, list) {
|
|
ath11k_peer_rx_tid_cleanup(ar, peer);
|
|
+ ath11k_peer_rhash_delete(ab, peer);
|
|
list_del(&peer->list);
|
|
kfree(peer);
|
|
}
|
|
spin_unlock_bh(&ab->base_lock);
|
|
+ mutex_unlock(&ab->tbl_mtx_lock);
|
|
|
|
ar->num_peers = 0;
|
|
ar->num_stations = 0;
|
|
@@ -4554,6 +4557,7 @@ static int ath11k_mac_op_sta_state(struc
|
|
}
|
|
|
|
ath11k_mac_dec_num_stations(arvif, sta);
|
|
+ mutex_lock(&ar->ab->tbl_mtx_lock);
|
|
spin_lock_bh(&ar->ab->base_lock);
|
|
peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr);
|
|
if (skip_peer_delete && peer) {
|
|
@@ -4561,12 +4565,14 @@ static int ath11k_mac_op_sta_state(struc
|
|
} else if (peer && peer->sta == sta) {
|
|
ath11k_warn(ar->ab, "Found peer entry %pM n vdev %i after it was supposedly removed\n",
|
|
vif->addr, arvif->vdev_id);
|
|
+ ath11k_peer_rhash_delete(ar->ab, peer);
|
|
peer->sta = NULL;
|
|
list_del(&peer->list);
|
|
kfree(peer);
|
|
ar->num_peers--;
|
|
}
|
|
spin_unlock_bh(&ar->ab->base_lock);
|
|
+ mutex_unlock(&ar->ab->tbl_mtx_lock);
|
|
|
|
kfree(arsta->tx_stats);
|
|
arsta->tx_stats = NULL;
|
|
@@ -8574,6 +8580,8 @@ void ath11k_mac_unregister(struct ath11k
|
|
|
|
__ath11k_mac_unregister(ar);
|
|
}
|
|
+
|
|
+ ath11k_peer_rhash_tbl_destroy(ab);
|
|
}
|
|
|
|
static int __ath11k_mac_register(struct ath11k *ar)
|
|
@@ -8802,6 +8810,10 @@ int ath11k_mac_register(struct ath11k_ba
|
|
ab->cc_freq_hz = IPQ8074_CC_FREQ_HERTZ;
|
|
ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS(ab))) - 1;
|
|
|
|
+ ret = ath11k_peer_rhash_tbl_init(ab);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
for (i = 0; i < ab->num_radios; i++) {
|
|
pdev = &ab->pdevs[i];
|
|
ar = pdev->ar;
|
|
@@ -8831,6 +8843,8 @@ err_cleanup:
|
|
__ath11k_mac_unregister(ar);
|
|
}
|
|
|
|
+ ath11k_peer_rhash_tbl_destroy(ab);
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
--- a/drivers/net/wireless/ath/ath11k/peer.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/peer.c
|
|
@@ -1,23 +1,22 @@
|
|
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
|
/*
|
|
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
|
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include "core.h"
|
|
#include "peer.h"
|
|
#include "debug.h"
|
|
|
|
-struct ath11k_peer *ath11k_peer_find(struct ath11k_base *ab, int vdev_id,
|
|
- const u8 *addr)
|
|
+static struct ath11k_peer *ath11k_peer_find_list_by_id(struct ath11k_base *ab,
|
|
+ int peer_id)
|
|
{
|
|
struct ath11k_peer *peer;
|
|
|
|
lockdep_assert_held(&ab->base_lock);
|
|
|
|
list_for_each_entry(peer, &ab->peers, list) {
|
|
- if (peer->vdev_id != vdev_id)
|
|
- continue;
|
|
- if (!ether_addr_equal(peer->addr, addr))
|
|
+ if (peer->peer_id != peer_id)
|
|
continue;
|
|
|
|
return peer;
|
|
@@ -26,15 +25,15 @@ struct ath11k_peer *ath11k_peer_find(str
|
|
return NULL;
|
|
}
|
|
|
|
-static struct ath11k_peer *ath11k_peer_find_by_pdev_idx(struct ath11k_base *ab,
|
|
- u8 pdev_idx, const u8 *addr)
|
|
+struct ath11k_peer *ath11k_peer_find(struct ath11k_base *ab, int vdev_id,
|
|
+ const u8 *addr)
|
|
{
|
|
struct ath11k_peer *peer;
|
|
|
|
lockdep_assert_held(&ab->base_lock);
|
|
|
|
list_for_each_entry(peer, &ab->peers, list) {
|
|
- if (peer->pdev_idx != pdev_idx)
|
|
+ if (peer->vdev_id != vdev_id)
|
|
continue;
|
|
if (!ether_addr_equal(peer->addr, addr))
|
|
continue;
|
|
@@ -52,14 +51,13 @@ struct ath11k_peer *ath11k_peer_find_by_
|
|
|
|
lockdep_assert_held(&ab->base_lock);
|
|
|
|
- list_for_each_entry(peer, &ab->peers, list) {
|
|
- if (!ether_addr_equal(peer->addr, addr))
|
|
- continue;
|
|
+ if (!ab->rhead_peer_addr)
|
|
+ return NULL;
|
|
|
|
- return peer;
|
|
- }
|
|
+ peer = rhashtable_lookup_fast(ab->rhead_peer_addr, addr,
|
|
+ ab->rhash_peer_addr_param);
|
|
|
|
- return NULL;
|
|
+ return peer;
|
|
}
|
|
|
|
struct ath11k_peer *ath11k_peer_find_by_id(struct ath11k_base *ab,
|
|
@@ -69,11 +67,13 @@ struct ath11k_peer *ath11k_peer_find_by_
|
|
|
|
lockdep_assert_held(&ab->base_lock);
|
|
|
|
- list_for_each_entry(peer, &ab->peers, list)
|
|
- if (peer_id == peer->peer_id)
|
|
- return peer;
|
|
+ if (!ab->rhead_peer_id)
|
|
+ return NULL;
|
|
|
|
- return NULL;
|
|
+ peer = rhashtable_lookup_fast(ab->rhead_peer_id, &peer_id,
|
|
+ ab->rhash_peer_id_param);
|
|
+
|
|
+ return peer;
|
|
}
|
|
|
|
struct ath11k_peer *ath11k_peer_find_by_vdev_id(struct ath11k_base *ab,
|
|
@@ -99,7 +99,7 @@ void ath11k_peer_unmap_event(struct ath1
|
|
|
|
spin_lock_bh(&ab->base_lock);
|
|
|
|
- peer = ath11k_peer_find_by_id(ab, peer_id);
|
|
+ peer = ath11k_peer_find_list_by_id(ab, peer_id);
|
|
if (!peer) {
|
|
ath11k_warn(ab, "peer-unmap-event: unknown peer id %d\n",
|
|
peer_id);
|
|
@@ -167,6 +167,76 @@ static int ath11k_wait_for_peer_common(s
|
|
return 0;
|
|
}
|
|
|
|
+static inline int ath11k_peer_rhash_insert(struct ath11k_base *ab,
|
|
+ struct rhashtable *rtbl,
|
|
+ struct rhash_head *rhead,
|
|
+ struct rhashtable_params *params,
|
|
+ void *key)
|
|
+{
|
|
+ struct ath11k_peer *tmp;
|
|
+
|
|
+ lockdep_assert_held(&ab->tbl_mtx_lock);
|
|
+
|
|
+ tmp = rhashtable_lookup_get_insert_fast(rtbl, rhead, *params);
|
|
+
|
|
+ if (!tmp)
|
|
+ return 0;
|
|
+ else if (IS_ERR(tmp))
|
|
+ return PTR_ERR(tmp);
|
|
+ else
|
|
+ return -EEXIST;
|
|
+}
|
|
+
|
|
+static inline int ath11k_peer_rhash_remove(struct ath11k_base *ab,
|
|
+ struct rhashtable *rtbl,
|
|
+ struct rhash_head *rhead,
|
|
+ struct rhashtable_params *params)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ lockdep_assert_held(&ab->tbl_mtx_lock);
|
|
+
|
|
+ ret = rhashtable_remove_fast(rtbl, rhead, *params);
|
|
+ if (ret && ret != -ENOENT)
|
|
+ return ret;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int ath11k_peer_rhash_add(struct ath11k_base *ab, struct ath11k_peer *peer)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ lockdep_assert_held(&ab->base_lock);
|
|
+ lockdep_assert_held(&ab->tbl_mtx_lock);
|
|
+
|
|
+ if (!ab->rhead_peer_id || !ab->rhead_peer_addr)
|
|
+ return -EPERM;
|
|
+
|
|
+ ret = ath11k_peer_rhash_insert(ab, ab->rhead_peer_id, &peer->rhash_id,
|
|
+ &ab->rhash_peer_id_param, &peer->peer_id);
|
|
+ if (ret) {
|
|
+ ath11k_warn(ab, "failed to add peer %pM with id %d in rhash_id ret %d\n",
|
|
+ peer->addr, peer->peer_id, ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = ath11k_peer_rhash_insert(ab, ab->rhead_peer_addr, &peer->rhash_addr,
|
|
+ &ab->rhash_peer_addr_param, &peer->addr);
|
|
+ if (ret) {
|
|
+ ath11k_warn(ab, "failed to add peer %pM with id %d in rhash_addr ret %d\n",
|
|
+ peer->addr, peer->peer_id, ret);
|
|
+ goto err_clean;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+err_clean:
|
|
+ ath11k_peer_rhash_remove(ab, ab->rhead_peer_id, &peer->rhash_id,
|
|
+ &ab->rhash_peer_id_param);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
void ath11k_peer_cleanup(struct ath11k *ar, u32 vdev_id)
|
|
{
|
|
struct ath11k_peer *peer, *tmp;
|
|
@@ -174,6 +244,7 @@ void ath11k_peer_cleanup(struct ath11k *
|
|
|
|
lockdep_assert_held(&ar->conf_mutex);
|
|
|
|
+ mutex_lock(&ab->tbl_mtx_lock);
|
|
spin_lock_bh(&ab->base_lock);
|
|
list_for_each_entry_safe(peer, tmp, &ab->peers, list) {
|
|
if (peer->vdev_id != vdev_id)
|
|
@@ -182,12 +253,14 @@ void ath11k_peer_cleanup(struct ath11k *
|
|
ath11k_warn(ab, "removing stale peer %pM from vdev_id %d\n",
|
|
peer->addr, vdev_id);
|
|
|
|
+ ath11k_peer_rhash_delete(ab, peer);
|
|
list_del(&peer->list);
|
|
kfree(peer);
|
|
ar->num_peers--;
|
|
}
|
|
|
|
spin_unlock_bh(&ab->base_lock);
|
|
+ mutex_unlock(&ab->tbl_mtx_lock);
|
|
}
|
|
|
|
static int ath11k_wait_for_peer_deleted(struct ath11k *ar, int vdev_id, const u8 *addr)
|
|
@@ -220,14 +293,35 @@ int ath11k_wait_for_peer_delete_done(str
|
|
static int __ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, const u8 *addr)
|
|
{
|
|
int ret;
|
|
+ struct ath11k_peer *peer;
|
|
+ struct ath11k_base *ab = ar->ab;
|
|
|
|
lockdep_assert_held(&ar->conf_mutex);
|
|
|
|
+ mutex_lock(&ab->tbl_mtx_lock);
|
|
+ spin_lock_bh(&ab->base_lock);
|
|
+
|
|
+ peer = ath11k_peer_find_by_addr(ab, addr);
|
|
+ if (!peer) {
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+ mutex_unlock(&ab->tbl_mtx_lock);
|
|
+
|
|
+ ath11k_warn(ab,
|
|
+ "failed to find peer vdev_id %d addr %pM in delete\n",
|
|
+ vdev_id, addr);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ ath11k_peer_rhash_delete(ab, peer);
|
|
+
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+ mutex_unlock(&ab->tbl_mtx_lock);
|
|
+
|
|
reinit_completion(&ar->peer_delete_done);
|
|
|
|
ret = ath11k_wmi_send_peer_delete_cmd(ar, addr, vdev_id);
|
|
if (ret) {
|
|
- ath11k_warn(ar->ab,
|
|
+ ath11k_warn(ab,
|
|
"failed to delete peer vdev_id %d addr %pM ret %d\n",
|
|
vdev_id, addr, ret);
|
|
return ret;
|
|
@@ -276,7 +370,7 @@ int ath11k_peer_create(struct ath11k *ar
|
|
}
|
|
|
|
spin_lock_bh(&ar->ab->base_lock);
|
|
- peer = ath11k_peer_find_by_pdev_idx(ar->ab, ar->pdev_idx, param->peer_addr);
|
|
+ peer = ath11k_peer_find_by_addr(ar->ab, param->peer_addr);
|
|
if (peer) {
|
|
spin_unlock_bh(&ar->ab->base_lock);
|
|
return -EINVAL;
|
|
@@ -296,11 +390,13 @@ int ath11k_peer_create(struct ath11k *ar
|
|
if (ret)
|
|
return ret;
|
|
|
|
+ mutex_lock(&ar->ab->tbl_mtx_lock);
|
|
spin_lock_bh(&ar->ab->base_lock);
|
|
|
|
peer = ath11k_peer_find(ar->ab, param->vdev_id, param->peer_addr);
|
|
if (!peer) {
|
|
spin_unlock_bh(&ar->ab->base_lock);
|
|
+ mutex_unlock(&ar->ab->tbl_mtx_lock);
|
|
ath11k_warn(ar->ab, "failed to find peer %pM on vdev %i after creation\n",
|
|
param->peer_addr, param->vdev_id);
|
|
|
|
@@ -308,6 +404,13 @@ int ath11k_peer_create(struct ath11k *ar
|
|
goto cleanup;
|
|
}
|
|
|
|
+ ret = ath11k_peer_rhash_add(ar->ab, peer);
|
|
+ if (ret) {
|
|
+ spin_unlock_bh(&ar->ab->base_lock);
|
|
+ mutex_unlock(&ar->ab->tbl_mtx_lock);
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
peer->pdev_idx = ar->pdev_idx;
|
|
peer->sta = sta;
|
|
|
|
@@ -332,6 +435,7 @@ int ath11k_peer_create(struct ath11k *ar
|
|
ar->num_peers++;
|
|
|
|
spin_unlock_bh(&ar->ab->base_lock);
|
|
+ mutex_unlock(&ar->ab->tbl_mtx_lock);
|
|
|
|
return 0;
|
|
|
|
@@ -343,3 +447,201 @@ cleanup:
|
|
|
|
return ret;
|
|
}
|
|
+
|
|
+int ath11k_peer_rhash_delete(struct ath11k_base *ab, struct ath11k_peer *peer)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ lockdep_assert_held(&ab->base_lock);
|
|
+ lockdep_assert_held(&ab->tbl_mtx_lock);
|
|
+
|
|
+ if (!ab->rhead_peer_id || !ab->rhead_peer_addr)
|
|
+ return -EPERM;
|
|
+
|
|
+ ret = ath11k_peer_rhash_remove(ab, ab->rhead_peer_addr, &peer->rhash_addr,
|
|
+ &ab->rhash_peer_addr_param);
|
|
+ if (ret) {
|
|
+ ath11k_warn(ab, "failed to remove peer %pM id %d in rhash_addr ret %d\n",
|
|
+ peer->addr, peer->peer_id, ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = ath11k_peer_rhash_remove(ab, ab->rhead_peer_id, &peer->rhash_id,
|
|
+ &ab->rhash_peer_id_param);
|
|
+ if (ret) {
|
|
+ ath11k_warn(ab, "failed to remove peer %pM id %d in rhash_id ret %d\n",
|
|
+ peer->addr, peer->peer_id, ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int ath11k_peer_rhash_id_tbl_init(struct ath11k_base *ab)
|
|
+{
|
|
+ struct rhashtable_params *param;
|
|
+ struct rhashtable *rhash_id_tbl;
|
|
+ int ret;
|
|
+ size_t size;
|
|
+
|
|
+ lockdep_assert_held(&ab->tbl_mtx_lock);
|
|
+
|
|
+ if (ab->rhead_peer_id)
|
|
+ return 0;
|
|
+
|
|
+ size = sizeof(*ab->rhead_peer_id);
|
|
+ rhash_id_tbl = kzalloc(size, GFP_KERNEL);
|
|
+ if (!rhash_id_tbl) {
|
|
+ ath11k_warn(ab, "failed to init rhash id table due to no mem (size %zu)\n",
|
|
+ size);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ param = &ab->rhash_peer_id_param;
|
|
+
|
|
+ param->key_offset = offsetof(struct ath11k_peer, peer_id);
|
|
+ param->head_offset = offsetof(struct ath11k_peer, rhash_id);
|
|
+ param->key_len = sizeof_field(struct ath11k_peer, peer_id);
|
|
+ param->automatic_shrinking = true;
|
|
+ param->nelem_hint = ab->num_radios * TARGET_NUM_PEERS_PDEV(ab);
|
|
+
|
|
+ ret = rhashtable_init(rhash_id_tbl, param);
|
|
+ if (ret) {
|
|
+ ath11k_warn(ab, "failed to init peer id rhash table %d\n", ret);
|
|
+ goto err_free;
|
|
+ }
|
|
+
|
|
+ spin_lock_bh(&ab->base_lock);
|
|
+
|
|
+ if (!ab->rhead_peer_id) {
|
|
+ ab->rhead_peer_id = rhash_id_tbl;
|
|
+ } else {
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+ goto cleanup_tbl;
|
|
+ }
|
|
+
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+cleanup_tbl:
|
|
+ rhashtable_destroy(rhash_id_tbl);
|
|
+err_free:
|
|
+ kfree(rhash_id_tbl);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int ath11k_peer_rhash_addr_tbl_init(struct ath11k_base *ab)
|
|
+{
|
|
+ struct rhashtable_params *param;
|
|
+ struct rhashtable *rhash_addr_tbl;
|
|
+ int ret;
|
|
+ size_t size;
|
|
+
|
|
+ lockdep_assert_held(&ab->tbl_mtx_lock);
|
|
+
|
|
+ if (ab->rhead_peer_addr)
|
|
+ return 0;
|
|
+
|
|
+ size = sizeof(*ab->rhead_peer_addr);
|
|
+ rhash_addr_tbl = kzalloc(size, GFP_KERNEL);
|
|
+ if (!rhash_addr_tbl) {
|
|
+ ath11k_warn(ab, "failed to init rhash addr table due to no mem (size %zu)\n",
|
|
+ size);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ param = &ab->rhash_peer_addr_param;
|
|
+
|
|
+ param->key_offset = offsetof(struct ath11k_peer, addr);
|
|
+ param->head_offset = offsetof(struct ath11k_peer, rhash_addr);
|
|
+ param->key_len = sizeof_field(struct ath11k_peer, addr);
|
|
+ param->automatic_shrinking = true;
|
|
+ param->nelem_hint = ab->num_radios * TARGET_NUM_PEERS_PDEV(ab);
|
|
+
|
|
+ ret = rhashtable_init(rhash_addr_tbl, param);
|
|
+ if (ret) {
|
|
+ ath11k_warn(ab, "failed to init peer addr rhash table %d\n", ret);
|
|
+ goto err_free;
|
|
+ }
|
|
+
|
|
+ spin_lock_bh(&ab->base_lock);
|
|
+
|
|
+ if (!ab->rhead_peer_addr) {
|
|
+ ab->rhead_peer_addr = rhash_addr_tbl;
|
|
+ } else {
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+ goto cleanup_tbl;
|
|
+ }
|
|
+
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+cleanup_tbl:
|
|
+ rhashtable_destroy(rhash_addr_tbl);
|
|
+err_free:
|
|
+ kfree(rhash_addr_tbl);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static inline void ath11k_peer_rhash_id_tbl_destroy(struct ath11k_base *ab)
|
|
+{
|
|
+ lockdep_assert_held(&ab->tbl_mtx_lock);
|
|
+
|
|
+ if (!ab->rhead_peer_id)
|
|
+ return;
|
|
+
|
|
+ rhashtable_destroy(ab->rhead_peer_id);
|
|
+ kfree(ab->rhead_peer_id);
|
|
+ ab->rhead_peer_id = NULL;
|
|
+}
|
|
+
|
|
+static inline void ath11k_peer_rhash_addr_tbl_destroy(struct ath11k_base *ab)
|
|
+{
|
|
+ lockdep_assert_held(&ab->tbl_mtx_lock);
|
|
+
|
|
+ if (!ab->rhead_peer_addr)
|
|
+ return;
|
|
+
|
|
+ rhashtable_destroy(ab->rhead_peer_addr);
|
|
+ kfree(ab->rhead_peer_addr);
|
|
+ ab->rhead_peer_addr = NULL;
|
|
+}
|
|
+
|
|
+int ath11k_peer_rhash_tbl_init(struct ath11k_base *ab)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ mutex_lock(&ab->tbl_mtx_lock);
|
|
+
|
|
+ ret = ath11k_peer_rhash_id_tbl_init(ab);
|
|
+ if (ret)
|
|
+ goto out;
|
|
+
|
|
+ ret = ath11k_peer_rhash_addr_tbl_init(ab);
|
|
+ if (ret)
|
|
+ goto cleanup_tbl;
|
|
+
|
|
+ mutex_unlock(&ab->tbl_mtx_lock);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+cleanup_tbl:
|
|
+ ath11k_peer_rhash_id_tbl_destroy(ab);
|
|
+out:
|
|
+ mutex_unlock(&ab->tbl_mtx_lock);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+void ath11k_peer_rhash_tbl_destroy(struct ath11k_base *ab)
|
|
+{
|
|
+ mutex_lock(&ab->tbl_mtx_lock);
|
|
+
|
|
+ ath11k_peer_rhash_addr_tbl_destroy(ab);
|
|
+ ath11k_peer_rhash_id_tbl_destroy(ab);
|
|
+
|
|
+ mutex_unlock(&ab->tbl_mtx_lock);
|
|
+}
|
|
--- a/drivers/net/wireless/ath/ath11k/peer.h
|
|
+++ b/drivers/net/wireless/ath/ath11k/peer.h
|
|
@@ -1,6 +1,7 @@
|
|
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
|
/*
|
|
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
|
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
*/
|
|
|
|
#ifndef ATH11K_PEER_H
|
|
@@ -20,6 +21,11 @@ struct ath11k_peer {
|
|
struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
|
|
struct dp_rx_tid rx_tid[IEEE80211_NUM_TIDS + 1];
|
|
|
|
+ /* peer id based rhashtable list pointer */
|
|
+ struct rhash_head rhash_id;
|
|
+ /* peer addr based rhashtable list pointer */
|
|
+ struct rhash_head rhash_addr;
|
|
+
|
|
/* Info used in MMIC verification of
|
|
* RX fragments
|
|
*/
|
|
@@ -47,5 +53,7 @@ int ath11k_wait_for_peer_delete_done(str
|
|
const u8 *addr);
|
|
struct ath11k_peer *ath11k_peer_find_by_vdev_id(struct ath11k_base *ab,
|
|
int vdev_id);
|
|
-
|
|
+int ath11k_peer_rhash_tbl_init(struct ath11k_base *ab);
|
|
+void ath11k_peer_rhash_tbl_destroy(struct ath11k_base *ab);
|
|
+int ath11k_peer_rhash_delete(struct ath11k_base *ab, struct ath11k_peer *peer);
|
|
#endif /* _PEER_H_ */
|