mirror of
https://github.com/breeze303/openwrt-ipq.git
synced 2025-12-17 08:52:53 +00:00
ath11k_nss: fix build for 256/1G mem, and ath10k
ath11k_nss: bump release version '8'
mac80211: refactor NSS patches
Since NSS requires patches to subsys, and ath*k directories. Move
patches into a subset of nss for better tracking against QSDK,
and modularization.
ath11k_nss: rename patches
ath11k_nss: clean up optional patches
To reduce bug tracking headaches, I've remove the following patches, as
they are not required for NSS offload and have been around the last 2-3
years without ever being upstreamed.
nss/ath11k/235-001-ath11k-Add-support-for-beacon-tx-mode.patch
nss/ath11k/237-002-ath11k-Add-provision-to-configure-rx-hashmap.patch
nss/ath11k/902-020-ath11k-add-btcoex-config.patch
nss/ath11k/902-022-ath11k-add-ap-ps-support.patch
nss/ath11k/907-068-ath11k-add-rx-histogram-stats.patch
nss/ath11k/907-108-ath11k-enable-ul-ofdma-ru-allocation-in-peer-stats.patch
nss/ath11k/911-373-ath11k-Add-retry-mechanism-for-update_rx_qu.patch
nss/ath11k/913-353-ath11k-ignore-frags-from-uninitialized-peer-in-dp.patch
nss/ath11k/913-356-ath11k-invalid-desc-sanity-check.patch
nss/ath11k/913-374-ath11k-Check-skb_headroom-before-using-skb_push.patch
nss/ath11k/913-830-ath11k-Avoiding-memset-of-ppdu-info-for-next-skb.patch
nss/subsys/235-002-mac80211-Add-support-for-beacon-tx-mode.patch
nss/subsys/913-726-mac80211-fix-crash-when-accessing-null-pointer.patch
ath11k_nss: Remove superfluous patches
Remove patches unrelated to NSS offloading to minimize bloat and better
track NSS related issues.
ath11k_nss: Refactor patches to use upstream names
Reworked patches to use upstream QSDK names. Allows for better tracking
ath11k_nss: align wifi offload with qca-nss-drv
The option in qca-nss-drv is actually 'NSS_DRV_WIFIOFFLOAD_ENABLE' use
the same syntax.
ath10k-ct: fix compile with NSS wifi
ath11k_nss: Merge every NSS related feature + more
* Added macro to disable NSS mesh offload
* Added menuconfig option "ATH11K_NSS_MESH_SUPPORT" to selectivley build mesh support,
as well it's depenacndy on nss-drv-wifimeshmgr.
* Added option to disable HTT Stats, and STA stats (stations).
* Reducing footprint by ~210KB. Debugfs minimal is still enabled.
* Reworked a TON of patches, some my own, hopefully there should be a far less amount of WOA2/WPA3 connection issues.
* Updated the /etc/init.d/pbuf script to be more robust. (handles tweaking ath11k and NSS settings better)
NOTES: Although mesh package builds (nss-drv-wifimeshmgr), ath11k doesn't seem to support it yet.
Not sure if NSS requires 3 radios to work, I'm at a dead end currently with that route.
ATTENTION:
the ptch `37-006-ath11k-Allow-fast-rx-by-bypassing-stats-update.patch`
works well on nss with frame_mode=2.
And on `ath11k frame_mode=1 nss_offload=0`
And on `ath11k frame_mode=2 nss_offload=1`
if you set nss_offload=off and frame_mode=2, it will CRASH
if you set nss_offload=on and frame_mode=2, it will RUN
if you set nss_offload=off and frame_mode=1, it will RUN
ath11k_nss: fix n2h high_water_core0/wifi_pool_buf
These were commented out, but looks like they are needed to prevent lock
ups with heavy usage apps (users report in torrenting)
ath11k_nss: Renumber ath11k patches in the range
commit 3c7cc4b725ea406f19b736427034e3bdb436aedc
Author: Yuvasree Sivasankaran <quic_ysivasan@quicinc.com>
AuthorDate: Thu Jan 4 11:25:56 2024 +0530
Commit: Yuvasree Sivasankaran <quic_ysivasan@quicinc.com>
CommitDate: Wed Jan 3 22:53:51 2024 -0800
wifi: ath11k: Renumber ath11k patches in the range
In ath11k, patches are not maintained in the range and not sequential.
Renumber the patches sequential and in the range.
Change-Id: I77c51c0f5bf9f94863db4ef364b156e14465a60c
Signed-off-by: Yuvasree Sivasankaran <quic_ysivasan@quicinc.com>
ath11k_nss: Add mac hw flag to avoid tx queue in mac80211
commit 4e9b5f7f0d1ed40dbf3208f7ed4448e49b4a4ac1
Author: Yuvasree Sivasankaran <quic_ysivasan@quicinc.com>
AuthorDate: Wed Dec 6 12:20:59 2023 +0530
Commit: Yuvasree Sivasankaran <quic_ysivasan@quicinc.com>
CommitDate: Mon Dec 18 12:52:33 2023 +0530
wifi: mac80211: Add mac hw flag to avoid tx queue in mac80211
Queue SKB in mac80211 become mandatory from latest 6.1 kernel. Because of
this queuing, there will be performance degradation. Add hw flag option
to enable tx queue in Driver/Hardware.
Driver/hardware can register for HAS_TX_QUEUE HW flag and avoid tx queuing
in mac80211.
Add same HW flag checks to avoid accessing skb queues which will be
NULL or invalid and also NULL checks for sta txqs for NULL or invalid
access.
ath11k_nss: add the HTC+ / iPhone fix
commit ccdca73cd65723c3cb63c17edc95c4c43318cb38
Author: John Crispin <john@phrozen.org>
AuthorDate: Sun Jul 9 17:12:34 2023 +0200
Commit: John Crispin <john@phrozen.org>
CommitDate: Thu Aug 31 16:08:34 2023 +0200
mac80211: add the HTC+ / iPhone fix
Signed-off-by: John Crispin <john@phrozen.org>
ath11k_nss: ath-next fix connection failure due to unexpected peer delete
Currently ath11k_mac_op_unassign_vif_chanctx() deletes peer but
ath11k_mac_op_assign_vif_chanctx() doesn't create it. This results in
connection failure if MAC80211 calls drv_unassign_vif_chanctx() and
drv_assign_vif_chanctx() during AUTH and ASSOC, see below log:
[ 102.372431] wlan0: authenticated
[ 102.372585] ath11k_pci 0000:01:00.0: wlan0: disabling HT/VHT/HE as WMM/QoS is not supported by the AP
[ 102.372593] ath11k_pci 0000:01:00.0: mac chanctx unassign ptr ffff895084638598 vdev_id 0
[ 102.372808] ath11k_pci 0000:01:00.0: WMI vdev stop id 0x0
[ 102.383114] ath11k_pci 0000:01:00.0: vdev stopped for vdev id 0
[ 102.384689] ath11k_pci 0000:01:00.0: WMI peer delete vdev_id 0 peer_addr 20:e5:2a:21:c4:51
[ 102.396676] ath11k_pci 0000:01:00.0: htt peer unmap vdev 0 peer 20:e5:2a:21:c4:51 id 3
[ 102.396711] ath11k_pci 0000:01:00.0: peer delete resp for vdev id 0 addr 20:e5:2a:21:c4:51
[ 102.396722] ath11k_pci 0000:01:00.0: mac removed peer 20:e5:2a:21:c4:51 vdev 0 after vdev stop
[ 102.396780] ath11k_pci 0000:01:00.0: mac chanctx assign ptr ffff895084639c18 vdev_id 0
[ 102.400628] wlan0: associate with 20:e5:2a:21:c4:51 (try 1/3)
[ 102.508864] wlan0: associate with 20:e5:2a:21:c4:51 (try 2/3)
[ 102.612815] wlan0: associate with 20:e5:2a:21:c4:51 (try 3/3)
[ 102.720846] wlan0: association with 20:e5:2a:21:c4:51 timed out
The peer delete logic in ath11k_mac_op_unassign_vif_chanctx() is
introduced by commit b4a0f54156ac ("ath11k: move peer delete after
vdev stop of station for QCA6390 and WCN6855") to fix firmware
crash issue caused by unexpected vdev stop/peer delete sequence.
Actually for a STA interface peer should be deleted in
ath11k_mac_op_sta_state() when STA's state changes from
IEEE80211_STA_NONE to IEEE80211_STA_NOTEXIST, which also coincides
with current peer creation design that peer is created during
IEEE80211_STA_NOTEXIST -> IEEE80211_STA_NONE transition. So move
peer delete back to ath11k_mac_op_sta_state(), also stop vdev before
deleting peer to fix the firmware crash issue mentioned there. In
this way the connection failure mentioned here is also fixed.
Also do some cleanups in patch "wifi: ath11k: remove invalid peer
create logic", and refactor in patches "wifi: ath11k: rename
ath11k_start_vdev_delay()" and "wifi: ath11k: avoid forward declaration
of ath11k_mac_start_vdev_delay()".
Tested this patch set using QCA6390 and WCN6855 on both STA and SAP
interfaces. Basic connection and ping work well.
Baochen Qiang (4):
wifi: ath11k: remove invalid peer create logic
wifi: ath11k: rename ath11k_start_vdev_delay()
wifi: ath11k: avoid forward declaration of
ath11k_mac_start_vdev_delay()
wifi: ath11k: fix connection failure due to unexpected peer delete
drivers/net/wireless/ath/ath11k/mac.c | 564 +++++++++++++-------------
1 file changed, 288 insertions(+), 276 deletions(-)
ath11k_nss: Revert support for beacon_tx_mode
ath11k_nss: Update release fix dependancies
ath11k_nss: mgmt and data ack rssi update
Data ACK RSSI :
Advertise NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT feature support
for accounting and notifying "last ack signal" and "avg ack signal" to
user space through NL interface.
Enabled data ack rssi support for ethernet mode.
Mgmt ACK RSSI:
Enabled support for Tx-ACK RSSI in HTT over Management packets.
ath11k_nss: add missing support to enable/disable bss color collision detection
ath11k_nss: FW Initiated Dynamic MU-EDCA
Implementing the updating of firmware initiated dynamic MU-EDCA
parameters in Beacon IE. Firmware routinely checks its clients and
updates its MU-EDCA values every 3 seconds. Firmware is tuning
MU-EDCA parameters to improve performance. As part of this process,
the firmware informs host about new MU-EDCA values utilizing
WMI_MUEDCA_PARAMS_CONFIG_EVENTID. FW expectation is that host will
update MU-EDCA parameters in the Beacon IE.
ath11k_nss: refresh patches + cleanup Makefile
ath11k_nss: Set correct pbufs for 1GB profile
ath11k_nss: Revert setting fw_mem_mode for IPQ807x
Leave it set to '0', as it will kernel panic with 2K skb patch. This
flag was incorrectly assumed to save memory on 1G platforms.
ath11k_nss: remove leftover max_tx_ring
it was not removed when applying patch to replace it with 'max_tx_ring =
DP_TCL_NUM_RING_MAX +1'
ath11k_nss: Import bugfix patches
ath11k_nss: Experimental build for IPQ6018
This will require setting the correct `ATH11K_MEM_PROFILE_XXX` for your
platform. Setting it to value lower/higher than physically available
will cause NULL virtual address kernel panics.
I believe this setting was not originally meant to reduce memory
footprint of 1G+ platforms, but to account for platforms that were
512M or less.
Will require tweaking to allow for the old behvaior on 1G+ IPQ807x,
while still saving memory for platforms <= 512M.
commit d2d5a0d1f9ce668f92a22eb45279c6c4c3bf7a4f
Author: Qosmio <datapronix@protonmail.com>
AuthorDate: Sat Mar 9 11:59:20 2024 -0500
Commit: Sean Khan <datapronix@protonmail.com>
CommitDate: Fri Oct 11 11:13:03 2024 -0400
ath11k_nss: fix typo in 512M memory profile
ath11k_nss: remove SFE patch 718-e-mac80211-Deliver-the-frame-to-driver-tx-ops-directly
It is not relevant to NSS builds and only meant for SFE.
ath11k_nss: remove unecessary patches
Color collision should be left on by default, as it's a primary feature
of 802.11AX.
ath11k_nss: fix spacing
ath11k_nss: Remove unnecessary TKIP bloat
Remove TKIP patches that are not being used as 99% of folks are running
modern encryption (AES-CCMP,SAE,etc).
ath11k_nss: parameterize DP_RXDMA_REFILL_RING_SIZE memory profile
ath11k_nss: Remove SFE related code
Cleanup SFE (shortcut fe) related code as we're not using it on NSS
ath11k_nss: idr, ampdu, and skb headroom check optimizations
ath11k_nss: get valid last_rate for rx_bitrate from cpu stats
ath11k_nss: Fix BCCA counter for EMA
Currently BCCA counter is updated to FW via csa counter offs and
beacon with new countdown is updated for every beacon tx completion event.
For EMA, all EMA beacons are updated in one shot, and counter update for
every tx event will mess up the actual sequence of countdown sent over the air.
Allow FW to update the countdown till 1 and finalize the color
change.
ath11k_nss: Fix compile for TRACE feature
974 lines
29 KiB
Diff
974 lines
29 KiB
Diff
From e6ecf9e1cc115b5821a880c6dccc5d8c9cd76fbd Mon Sep 17 00:00:00 2001
|
|
From: Sathishkumar Muruganandam <murugana@codeaurora.org>
|
|
Date: Tue, 15 Sep 2020 21:12:37 +0530
|
|
Subject: [PATCH] ath11k: add WDS offload support on NSS offload for STA mode
|
|
|
|
When 4addr is set ON for STA interface along with NSS enabled case, WDS
|
|
offload is enabled for ethernet mode.
|
|
|
|
STA mode uses MEC (Multicast Echo Check) AST (Address Search Table) entry
|
|
to update the bridge MAC address from NSS to drop the locally generated
|
|
multicast/broadcast frames as multicast echo frames.
|
|
|
|
AST handling and callbacks to NSS WDS APIs are added.
|
|
|
|
Signed-off-by: Sathishkumar Muruganandam <murugana@codeaurora.org>
|
|
---
|
|
drivers/net/wireless/ath/ath11k/core.h | 8 +-
|
|
drivers/net/wireless/ath/ath11k/dp.h | 6 +-
|
|
drivers/net/wireless/ath/ath11k/dp_rx.c | 18 +-
|
|
drivers/net/wireless/ath/ath11k/dp_tx.c | 2 +-
|
|
drivers/net/wireless/ath/ath11k/peer.c | 389 +++++++++++++++++++++++++++++++-
|
|
drivers/net/wireless/ath/ath11k/peer.h | 117 ++++++++++
|
|
drivers/net/wireless/ath/ath11k/wmi.c | 99 +++++++-
|
|
drivers/net/wireless/ath/ath11k/wmi.h | 33 +++
|
|
8 files changed, 658 insertions(+), 14 deletions(-)
|
|
|
|
--- a/drivers/net/wireless/ath/ath11k/core.h
|
|
+++ b/drivers/net/wireless/ath/ath11k/core.h
|
|
@@ -642,6 +642,7 @@ struct ath11k {
|
|
struct ath11k_pdev_wmi *wmi;
|
|
#ifdef CPTCFG_ATH11K_NSS_SUPPORT
|
|
struct ath11k_nss nss;
|
|
+ struct ath11k_peer *bss_peer;
|
|
#endif
|
|
struct ath11k_pdev_dp dp;
|
|
u8 mac_addr[ETH_ALEN];
|
|
@@ -1047,6 +1048,9 @@ struct ath11k_base {
|
|
} testmode;
|
|
#endif
|
|
|
|
+ u32 max_ast_index;
|
|
+ u32 num_ast_entries;
|
|
+
|
|
/* must be last */
|
|
u8 drv_priv[] __aligned(sizeof(void *));
|
|
};
|
|
--- a/drivers/net/wireless/ath/ath11k/dp.h
|
|
+++ b/drivers/net/wireless/ath/ath11k/dp.h
|
|
@@ -1105,13 +1105,16 @@ struct htt_t2h_peer_map_event {
|
|
#define HTT_T2H_PEER_UNMAP_INFO_PEER_ID HTT_T2H_PEER_MAP_INFO_PEER_ID
|
|
#define HTT_T2H_PEER_UNMAP_INFO1_MAC_ADDR_H16 \
|
|
HTT_T2H_PEER_MAP_INFO1_MAC_ADDR_H16
|
|
-#define HTT_T2H_PEER_MAP_INFO1_NEXT_HOP_M HTT_T2H_PEER_MAP_INFO2_NEXT_HOP_M
|
|
-#define HTT_T2H_PEER_MAP_INFO1_NEXT_HOP_S HTT_T2H_PEER_MAP_INFO2_NEXT_HOP_S
|
|
+#define HTT_T2H_PEER_UNMAP_INFO1_NEXT_HOP_M HTT_T2H_PEER_MAP_INFO2_NEXT_HOP_M
|
|
+#define HTT_T2H_PEER_UNMAP_INFO1_NEXT_HOP_S HTT_T2H_PEER_MAP_INFO2_NEXT_HOP_S
|
|
+#define HTT_T2H_PEER_UNMAP_INFO3_WDS_FREE_COUNT GENMASK(15, 0)
|
|
|
|
struct htt_t2h_peer_unmap_event {
|
|
u32 info;
|
|
u32 mac_addr_l32;
|
|
u32 info1;
|
|
+ u32 info2;
|
|
+ u32 info3;
|
|
} __packed;
|
|
|
|
struct htt_resp_msg {
|
|
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
|
|
@@ -1857,6 +1857,8 @@ void ath11k_dp_htt_htc_t2h_msg_handler(s
|
|
u16 peer_mac_h16;
|
|
u16 ast_hash;
|
|
u16 hw_peer_id;
|
|
+ u32 free_wds_count;
|
|
+ bool is_wds = false;
|
|
|
|
ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "dp_htt rx msg type :0x%0x\n", type);
|
|
|
|
@@ -1892,15 +1894,29 @@ void ath11k_dp_htt_htc_t2h_msg_handler(s
|
|
resp->peer_map_ev.info2);
|
|
hw_peer_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO1_HW_PEER_ID,
|
|
resp->peer_map_ev.info1);
|
|
- ath11k_peer_map_event(ab, vdev_id, peer_id, mac_addr, ast_hash,
|
|
- hw_peer_id);
|
|
+ is_wds = FIELD_GET(HTT_T2H_PEER_MAP_INFO2_NEXT_HOP_M,
|
|
+ resp->peer_map_ev.info2);
|
|
+ ath11k_peer_map_v2_event(ab, vdev_id, peer_id, mac_addr, ast_hash,
|
|
+ hw_peer_id, is_wds);
|
|
break;
|
|
case HTT_T2H_MSG_TYPE_PEER_UNMAP:
|
|
- case HTT_T2H_MSG_TYPE_PEER_UNMAP2:
|
|
peer_id = FIELD_GET(HTT_T2H_PEER_UNMAP_INFO_PEER_ID,
|
|
resp->peer_unmap_ev.info);
|
|
ath11k_peer_unmap_event(ab, peer_id);
|
|
break;
|
|
+ case HTT_T2H_MSG_TYPE_PEER_UNMAP2:
|
|
+ peer_id = FIELD_GET(HTT_T2H_PEER_UNMAP_INFO_PEER_ID,
|
|
+ resp->peer_unmap_ev.info);
|
|
+ peer_mac_h16 = FIELD_GET(HTT_T2H_PEER_UNMAP_INFO1_MAC_ADDR_H16,
|
|
+ resp->peer_unmap_ev.info1);
|
|
+ ath11k_dp_get_mac_addr(resp->peer_map_ev.mac_addr_l32,
|
|
+ peer_mac_h16, mac_addr);
|
|
+ is_wds = FIELD_GET(HTT_T2H_PEER_UNMAP_INFO1_NEXT_HOP_M,
|
|
+ resp->peer_unmap_ev.info1);
|
|
+ free_wds_count = FIELD_GET(HTT_T2H_PEER_UNMAP_INFO3_WDS_FREE_COUNT,
|
|
+ resp->peer_unmap_ev.info3);
|
|
+ ath11k_peer_unmap_v2_event(ab, peer_id, mac_addr, is_wds, free_wds_count);
|
|
+ break;
|
|
case HTT_T2H_MSG_TYPE_PPDU_STATS_IND:
|
|
ath11k_htt_pull_ppdu_stats(ab, skb);
|
|
break;
|
|
--- a/drivers/net/wireless/ath/ath11k/dp_tx.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/dp_tx.c
|
|
@@ -495,7 +495,7 @@ ath11k_dp_tx_process_htt_tx_complete(str
|
|
break;
|
|
case HAL_WBM_REL_HTT_TX_COMP_STATUS_MEC_NOTIFY:
|
|
/* This event is to be handled only when the driver decides to
|
|
- * use WDS offload functionality.
|
|
+ * use WDS offload functionality on NSS disabled case.
|
|
*/
|
|
break;
|
|
default:
|
|
--- a/drivers/net/wireless/ath/ath11k/peer.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/peer.c
|
|
@@ -108,6 +108,287 @@ struct ath11k_peer *ath11k_peer_find_by_
|
|
return NULL;
|
|
}
|
|
|
|
+#ifdef CPTCFG_ATH11K_NSS_SUPPORT
|
|
+struct ath11k_ast_entry *ath11k_peer_ast_find_by_peer(struct ath11k_base *ab,
|
|
+ struct ath11k_peer *peer,
|
|
+ u8* addr)
|
|
+{
|
|
+ struct ath11k_ast_entry *ast_entry;
|
|
+
|
|
+ lockdep_assert_held(&ab->base_lock);
|
|
+
|
|
+ list_for_each_entry(ast_entry, &peer->ast_entry_list, ase_list)
|
|
+ if (ether_addr_equal(ast_entry->addr, addr))
|
|
+ return ast_entry;
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+struct ath11k_ast_entry *ath11k_peer_ast_find_by_addr(struct ath11k_base *ab,
|
|
+ u8* addr)
|
|
+{
|
|
+ struct ath11k_ast_entry *ast_entry;
|
|
+ struct ath11k_peer *peer;
|
|
+
|
|
+ lockdep_assert_held(&ab->base_lock);
|
|
+
|
|
+ list_for_each_entry(peer, &ab->peers, list)
|
|
+ list_for_each_entry(ast_entry, &peer->ast_entry_list, ase_list)
|
|
+ if (ether_addr_equal(ast_entry->addr, addr))
|
|
+ return ast_entry;
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+void ath11k_peer_ast_wds_wmi_wk(struct work_struct *wk)
|
|
+{
|
|
+ struct ath11k_ast_entry *ast_entry = container_of(wk,
|
|
+ struct ath11k_ast_entry,
|
|
+ wds_wmi_wk);
|
|
+ struct ath11k *ar;
|
|
+ struct ath11k_peer *peer;
|
|
+ int ret;
|
|
+
|
|
+ if (!ast_entry)
|
|
+ return;
|
|
+
|
|
+ ar = ast_entry->ar;
|
|
+ peer = ast_entry->peer;
|
|
+
|
|
+ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "ath11k_peer_ast_wds_wmi_wk action %d ast_entry %pM next_node %pM vdev %d\n",
|
|
+ ast_entry->action, ast_entry->addr, ast_entry->next_node_mac,
|
|
+ ast_entry->vdev_id);
|
|
+
|
|
+ if (ast_entry->action == ATH11K_WDS_WMI_ADD) {
|
|
+ ret = ath11k_wmi_send_add_update_wds_entry_cmd(ar,
|
|
+ ast_entry->next_node_mac,
|
|
+ ast_entry->addr,
|
|
+ ast_entry->vdev_id,
|
|
+ true);
|
|
+ if (ret) {
|
|
+ ath11k_warn(ar->ab, "add wds_entry_cmd failed %d for %pM next_node %pM\n",
|
|
+ ret, ast_entry->addr,
|
|
+ ast_entry->next_node_mac);
|
|
+ if (peer)
|
|
+ ath11k_nss_del_wds_peer(ar, peer,
|
|
+ ast_entry->addr);
|
|
+ }
|
|
+ } else if (ast_entry->action == ATH11K_WDS_WMI_UPDATE) {
|
|
+ if (!peer)
|
|
+ return;
|
|
+
|
|
+ ret = ath11k_wmi_send_add_update_wds_entry_cmd(ar, peer->addr,
|
|
+ ast_entry->addr,
|
|
+ ast_entry->vdev_id,
|
|
+ false);
|
|
+ if (ret)
|
|
+ ath11k_warn(ar->ab, "update wds_entry_cmd failed %d for %pM on peer %pM\n",
|
|
+ ret, ast_entry->addr, peer->addr);
|
|
+ }
|
|
+}
|
|
+
|
|
+int ath11k_peer_add_ast(struct ath11k *ar, struct ath11k_peer *peer,
|
|
+ u8* mac_addr, enum ath11k_ast_entry_type type)
|
|
+{
|
|
+ struct ath11k_ast_entry *ast_entry = NULL;
|
|
+ struct ath11k_base *ab = ar->ab;
|
|
+
|
|
+ if (ab->num_ast_entries == ab->max_ast_index) {
|
|
+ ath11k_warn(ab, "failed to add ast for %pM due to insufficient ast entry resource %d in target\n",
|
|
+ mac_addr, ab->max_ast_index);
|
|
+ return -ENOBUFS;
|
|
+ }
|
|
+
|
|
+ if (type != ATH11K_AST_TYPE_STATIC) {
|
|
+ ast_entry = ath11k_peer_ast_find_by_addr(ab, mac_addr);
|
|
+ if (ast_entry) {
|
|
+ ath11k_dbg(ab, ATH11K_DBG_MAC, "ast_entry %pM already present on peer %pM\n",
|
|
+ mac_addr, ast_entry->peer->addr);
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ast_entry = kzalloc(sizeof(*ast_entry), GFP_ATOMIC);
|
|
+ if (!ast_entry) {
|
|
+ ath11k_warn(ab, "failed to alloc ast_entry for %pM\n",
|
|
+ mac_addr);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ switch (type) {
|
|
+ case ATH11K_AST_TYPE_STATIC:
|
|
+ peer->self_ast_entry = ast_entry;
|
|
+ ast_entry->type = ATH11K_AST_TYPE_STATIC;
|
|
+ break;
|
|
+ case ATH11K_AST_TYPE_SELF:
|
|
+ peer->self_ast_entry = ast_entry;
|
|
+ ast_entry->type = ATH11K_AST_TYPE_SELF;
|
|
+ break;
|
|
+ case ATH11K_AST_TYPE_WDS:
|
|
+ ast_entry->type = ATH11K_AST_TYPE_WDS;
|
|
+ ast_entry->next_hop = 1;
|
|
+ break;
|
|
+ case ATH11K_AST_TYPE_MEC:
|
|
+ ast_entry->type = ATH11K_AST_TYPE_MEC;
|
|
+ ast_entry->next_hop = 1;
|
|
+ break;
|
|
+ default:
|
|
+ ath11k_warn(ab, "unsupported ast_type %d", type);
|
|
+ kfree(ast_entry);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ INIT_LIST_HEAD(&ast_entry->ase_list);
|
|
+ INIT_WORK(&ast_entry->wds_wmi_wk, ath11k_peer_ast_wds_wmi_wk);
|
|
+ ast_entry->vdev_id = peer->vdev_id;
|
|
+ ast_entry->pdev_idx = peer->pdev_idx;
|
|
+ ast_entry->is_mapped = false;
|
|
+ ast_entry->is_active = true;
|
|
+ ast_entry->peer = peer;
|
|
+ ast_entry->ar = ar;
|
|
+ ether_addr_copy(ast_entry->addr, mac_addr);
|
|
+
|
|
+ list_add_tail(&ast_entry->ase_list, &peer->ast_entry_list);
|
|
+
|
|
+ ath11k_dbg(ab, ATH11K_DBG_MAC, "ath11k_peer_add_ast peer %pM ast_entry %pM, ast_type %d\n",
|
|
+ peer->addr, mac_addr, ast_entry->type);
|
|
+
|
|
+ if (type == ATH11K_AST_TYPE_MEC)
|
|
+ ether_addr_copy(ast_entry->next_node_mac, ar->mac_addr);
|
|
+ else if (type == ATH11K_AST_TYPE_WDS)
|
|
+ ether_addr_copy(ast_entry->next_node_mac, peer->addr);
|
|
+
|
|
+ if ((ast_entry->type == ATH11K_AST_TYPE_WDS) ||
|
|
+ (ast_entry->type == ATH11K_AST_TYPE_MEC)) {
|
|
+ ath11k_nss_add_wds_peer(ar, peer, mac_addr, ast_entry->type);
|
|
+ ast_entry->action = ATH11K_WDS_WMI_ADD;
|
|
+ ieee80211_queue_work(ar->hw, &ast_entry->wds_wmi_wk);
|
|
+ }
|
|
+
|
|
+ ab->num_ast_entries++;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int ath11k_peer_update_ast(struct ath11k *ar, struct ath11k_peer *peer,
|
|
+ struct ath11k_ast_entry *ast_entry)
|
|
+{
|
|
+ struct ath11k_peer *old_peer = ast_entry->peer;
|
|
+ struct ath11k_base *ab = ar->ab;
|
|
+
|
|
+ if (!ast_entry->is_mapped) {
|
|
+ ath11k_warn(ab, "ath11k_peer_update_ast: ast_entry %pM not mapped yet\n",
|
|
+ ast_entry->addr);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (ether_addr_equal(old_peer->addr, peer->addr) &&
|
|
+ (ast_entry->type == ATH11K_AST_TYPE_WDS) &&
|
|
+ (ast_entry->vdev_id == peer->vdev_id) &&
|
|
+ (ast_entry->is_active))
|
|
+ return 0;
|
|
+
|
|
+ ast_entry->vdev_id = peer->vdev_id;
|
|
+ ast_entry->pdev_idx = peer->pdev_idx;
|
|
+ ast_entry->type = ATH11K_AST_TYPE_WDS;
|
|
+ ast_entry->is_active = true;
|
|
+ ast_entry->peer = peer;
|
|
+
|
|
+ list_move_tail(&ast_entry->ase_list, &peer->ast_entry_list);
|
|
+
|
|
+ ath11k_dbg(ab, ATH11K_DBG_MAC, "ath11k_peer_update_ast old peer %pM new peer %pM ast_entry %pM\n",
|
|
+ old_peer->addr, peer->addr, ast_entry->addr);
|
|
+
|
|
+ flush_work(&ast_entry->wds_wmi_wk);
|
|
+ ast_entry->action = ATH11K_WDS_WMI_UPDATE;
|
|
+ ieee80211_queue_work(ar->hw, &ast_entry->wds_wmi_wk);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void ath11k_peer_map_ast(struct ath11k *ar, struct ath11k_peer *peer,
|
|
+ u8* mac_addr, u16 hw_peer_id, u16 ast_hash)
|
|
+{
|
|
+ struct ath11k_ast_entry *ast_entry = NULL;
|
|
+ struct ath11k_base *ab = ar->ab;
|
|
+
|
|
+ if (!peer)
|
|
+ return;
|
|
+
|
|
+ ast_entry = ath11k_peer_ast_find_by_peer(ab, peer, mac_addr);
|
|
+
|
|
+ if (ast_entry) {
|
|
+ ast_entry->ast_idx = hw_peer_id;
|
|
+ ast_entry->is_active = true;
|
|
+ ast_entry->is_mapped = true;
|
|
+ ast_entry->ast_hash_value = ast_hash;
|
|
+
|
|
+ if ((ast_entry->type == ATH11K_AST_TYPE_WDS) ||
|
|
+ (ast_entry->type == ATH11K_AST_TYPE_MEC))
|
|
+ ath11k_nss_map_wds_peer(ar, peer, mac_addr,
|
|
+ ast_entry->type);
|
|
+
|
|
+ ath11k_dbg(ab, ATH11K_DBG_MAC, "ath11k_peer_map_ast peer %pM ast_entry %pM\n",
|
|
+ peer->addr, ast_entry->addr);
|
|
+ }
|
|
+
|
|
+}
|
|
+
|
|
+void ath11k_peer_del_ast(struct ath11k *ar, struct ath11k_ast_entry *ast_entry)
|
|
+{
|
|
+ struct ath11k_peer *peer;
|
|
+ struct ath11k_base *ab = ar->ab;
|
|
+
|
|
+ if (!ast_entry || !ast_entry->peer)
|
|
+ return;
|
|
+
|
|
+ peer = ast_entry->peer;
|
|
+
|
|
+ ath11k_dbg(ab, ATH11K_DBG_MAC, "ath11k_peer_del_ast peer %pM ast_entry %pM\n",
|
|
+ peer->addr, ast_entry->addr);
|
|
+
|
|
+ if (ast_entry->is_mapped)
|
|
+ list_del(&ast_entry->ase_list);
|
|
+
|
|
+ /* WDS, MEC type AST entries need to be deleted on NSS */
|
|
+ if (ast_entry->next_hop)
|
|
+ ath11k_nss_del_wds_peer(ar, peer, ast_entry->addr);
|
|
+
|
|
+ cancel_work_sync(&ast_entry->wds_wmi_wk);
|
|
+ kfree(ast_entry);
|
|
+
|
|
+ ab->num_ast_entries--;
|
|
+}
|
|
+
|
|
+void ath11k_peer_ast_cleanup(struct ath11k *ar, struct ath11k_peer *peer,
|
|
+ bool is_wds, u32 free_wds_count)
|
|
+{
|
|
+ struct ath11k_ast_entry *ast_entry, *tmp;
|
|
+ u32 ast_deleted_count = 0;
|
|
+
|
|
+ if (peer->self_ast_entry) {
|
|
+ ath11k_peer_del_ast(ar, peer->self_ast_entry);
|
|
+ peer->self_ast_entry = NULL;
|
|
+ }
|
|
+
|
|
+ list_for_each_entry_safe(ast_entry, tmp, &peer->ast_entry_list,
|
|
+ ase_list) {
|
|
+ if ((ast_entry->type == ATH11K_AST_TYPE_WDS) ||
|
|
+ (ast_entry->type == ATH11K_AST_TYPE_MEC))
|
|
+ ast_deleted_count++;
|
|
+ ath11k_peer_del_ast(ar, ast_entry);
|
|
+ }
|
|
+
|
|
+ if (!is_wds) {
|
|
+ if (ast_deleted_count != free_wds_count)
|
|
+ ath11k_warn(ar->ab, "ast_deleted_count (%d) mismatch on peer %pM free_wds_count (%d)!\n",
|
|
+ ast_deleted_count, peer->addr, free_wds_count);
|
|
+ else
|
|
+ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "ast_deleted_count (%d) on peer %pM free_wds_count (%d)\n",
|
|
+ ast_deleted_count, peer->addr, free_wds_count);
|
|
+ }
|
|
+}
|
|
+#endif
|
|
+
|
|
void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id)
|
|
{
|
|
struct ath11k_peer *peer;
|
|
@@ -132,11 +413,67 @@ exit:
|
|
spin_unlock_bh(&ab->base_lock);
|
|
}
|
|
|
|
+void ath11k_peer_unmap_v2_event(struct ath11k_base *ab, u16 peer_id, u8 *mac_addr,
|
|
+ bool is_wds, u32 free_wds_count)
|
|
+{
|
|
+ struct ath11k_peer *peer;
|
|
+ struct ath11k *ar;
|
|
+
|
|
+ spin_lock_bh(&ab->base_lock);
|
|
+
|
|
+ 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);
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ rcu_read_lock();
|
|
+ ar = ath11k_mac_get_ar_by_vdev_id(ab, peer->vdev_id);
|
|
+ if (!ar) {
|
|
+ ath11k_warn(ab, "peer-unmap-event: unknown peer vdev id %d\n",
|
|
+ peer->vdev_id);
|
|
+ goto free_peer;
|
|
+ }
|
|
+
|
|
+ ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "htt peer unmap vdev %d peer %pM id %d is_wds %d free_wds_count %d\n",
|
|
+ peer->vdev_id, peer->addr, peer_id, is_wds, free_wds_count);
|
|
+
|
|
+ if (ab->nss.enabled) {
|
|
+ if (is_wds) {
|
|
+ struct ath11k_ast_entry *ast_entry =
|
|
+ ath11k_peer_ast_find_by_peer(ab, peer, mac_addr);
|
|
+
|
|
+ if (ast_entry)
|
|
+ ath11k_peer_del_ast(ar, ast_entry);
|
|
+ rcu_read_unlock();
|
|
+ goto exit;
|
|
+ } else
|
|
+ ath11k_peer_ast_cleanup(ar, peer, is_wds, free_wds_count);
|
|
+ }
|
|
+
|
|
+#ifdef CPTCFG_ATH11K_NSS_SUPPORT
|
|
+ if (ar->bss_peer && ether_addr_equal(ar->bss_peer->addr, peer->addr))
|
|
+ ar->bss_peer = NULL;
|
|
+#endif
|
|
+free_peer:
|
|
+ rcu_read_unlock();
|
|
+ list_del(&peer->list);
|
|
+ kfree(peer);
|
|
+ wake_up(&ab->peer_mapping_wq);
|
|
+
|
|
+exit:
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+}
|
|
+
|
|
void ath11k_peer_map_event(struct ath11k_base *ab, u8 vdev_id, u16 peer_id,
|
|
u8 *mac_addr, u16 ast_hash, u16 hw_peer_id)
|
|
{
|
|
struct ath11k_peer *peer;
|
|
+ struct ath11k *ar = NULL;
|
|
|
|
+ rcu_read_lock();
|
|
+ ar = ath11k_mac_get_ar_by_vdev_id(ab, vdev_id);
|
|
spin_lock_bh(&ab->base_lock);
|
|
peer = ath11k_peer_find(ab, vdev_id, mac_addr);
|
|
if (!peer) {
|
|
@@ -151,8 +488,8 @@ void ath11k_peer_map_event(struct ath11k
|
|
ether_addr_copy(peer->addr, mac_addr);
|
|
list_add(&peer->list, &ab->peers);
|
|
wake_up(&ab->peer_mapping_wq);
|
|
- if (ab->nss.enabled)
|
|
- ath11k_nss_peer_create(ab, peer);
|
|
+ if (ab->nss.enabled && ar)
|
|
+ ath11k_nss_peer_create(ar, peer);
|
|
}
|
|
|
|
ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "peer map vdev %d peer %pM id %d\n",
|
|
@@ -160,6 +497,69 @@ void ath11k_peer_map_event(struct ath11k
|
|
|
|
exit:
|
|
spin_unlock_bh(&ab->base_lock);
|
|
+ rcu_read_unlock();
|
|
+}
|
|
+
|
|
+void ath11k_peer_map_v2_event(struct ath11k_base *ab, u8 vdev_id, u16 peer_id,
|
|
+ u8 *mac_addr, u16 ast_hash, u16 hw_peer_id,
|
|
+ bool is_wds)
|
|
+{
|
|
+ struct ath11k_peer *peer;
|
|
+ struct ath11k *ar = NULL;
|
|
+ int ret;
|
|
+
|
|
+ rcu_read_lock();
|
|
+ ar = ath11k_mac_get_ar_by_vdev_id(ab, vdev_id);
|
|
+ spin_lock_bh(&ab->base_lock);
|
|
+ peer = ath11k_peer_find(ab, vdev_id, mac_addr);
|
|
+ if (!peer && !is_wds) {
|
|
+ peer = kzalloc(sizeof(*peer), GFP_ATOMIC);
|
|
+ if (!peer) {
|
|
+ ath11k_warn(ab, "failed to allocated peer for %pM vdev_id %d\n",
|
|
+ mac_addr, vdev_id);
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ peer->vdev_id = vdev_id;
|
|
+ peer->peer_id = peer_id;
|
|
+ peer->ast_hash = ast_hash;
|
|
+ peer->hw_peer_id = hw_peer_id;
|
|
+ ether_addr_copy(peer->addr, mac_addr);
|
|
+ list_add(&peer->list, &ab->peers);
|
|
+#ifdef CPTCFG_ATH11K_NSS_SUPPORT
|
|
+ INIT_LIST_HEAD(&peer->ast_entry_list);
|
|
+#endif
|
|
+ if (ab->nss.enabled && ar) {
|
|
+ ret = ath11k_nss_peer_create(ar, peer);
|
|
+ if (ret) {
|
|
+ ath11k_warn(ab, "failed to do nss peer create: %d\n",
|
|
+ ret);
|
|
+ goto peer_free;
|
|
+ }
|
|
+ }
|
|
+ wake_up(&ab->peer_mapping_wq);
|
|
+ }
|
|
+
|
|
+ if (is_wds)
|
|
+ peer = ath11k_peer_find_by_id(ab, peer_id);
|
|
+
|
|
+ if (ab->nss.enabled && ar)
|
|
+ ath11k_peer_map_ast(ar, peer, mac_addr, hw_peer_id, ast_hash);
|
|
+
|
|
+ ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "htt peer map vdev %d peer %pM id %d is_wds %d\n",
|
|
+ vdev_id, mac_addr, peer_id, is_wds);
|
|
+
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+ goto exit;
|
|
+
|
|
+peer_free:
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+ mutex_lock(&ar->conf_mutex);
|
|
+ ath11k_peer_delete(ar, vdev_id, mac_addr);
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
+exit:
|
|
+ rcu_read_unlock();
|
|
}
|
|
|
|
static int ath11k_wait_for_peer_common(struct ath11k_base *ab, int vdev_id,
|
|
@@ -256,20 +656,34 @@ err_clean:
|
|
|
|
void ath11k_peer_cleanup(struct ath11k *ar, u32 vdev_id)
|
|
{
|
|
- struct ath11k_peer *peer, *tmp;
|
|
+ struct ath11k_peer *peer, *tmp_peer;
|
|
struct ath11k_base *ab = ar->ab;
|
|
+#ifdef CPTCFG_ATH11K_NSS_SUPPORT
|
|
+ struct ath11k_ast_entry *ast_entry, *tmp_ast;
|
|
+#endif
|
|
|
|
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) {
|
|
+ list_for_each_entry_safe(peer, tmp_peer, &ab->peers, list) {
|
|
if (peer->vdev_id != vdev_id)
|
|
continue;
|
|
|
|
ath11k_warn(ab, "removing stale peer %pM from vdev_id %d\n",
|
|
peer->addr, vdev_id);
|
|
|
|
+#ifdef CPTCFG_ATH11K_NSS_SUPPORT
|
|
+ if (peer->self_ast_entry) {
|
|
+ ath11k_peer_del_ast(ar, peer->self_ast_entry);
|
|
+ peer->self_ast_entry = NULL;
|
|
+ }
|
|
+
|
|
+ list_for_each_entry_safe(ast_entry, tmp_ast,
|
|
+ &peer->ast_entry_list, ase_list)
|
|
+ ath11k_peer_del_ast(ar, ast_entry);
|
|
+#endif
|
|
+
|
|
ath11k_peer_rhash_delete(ab, peer);
|
|
list_del(&peer->list);
|
|
kfree(peer);
|
|
@@ -316,7 +730,7 @@ static int __ath11k_peer_delete(struct a
|
|
lockdep_assert_held(&ar->conf_mutex);
|
|
|
|
reinit_completion(&ar->peer_delete_done);
|
|
- ath11k_nss_peer_delete(ar->ab, addr);
|
|
+ ath11k_nss_peer_delete(ar->ab, vdev_id, addr);
|
|
|
|
mutex_lock(&ab->tbl_mtx_lock);
|
|
spin_lock_bh(&ab->base_lock);
|
|
@@ -391,6 +805,7 @@ int ath11k_peer_create(struct ath11k *ar
|
|
struct ieee80211_sta *sta, struct peer_create_params *param)
|
|
{
|
|
struct ath11k_peer *peer;
|
|
+ struct ieee80211_vif *vif = arvif->vif;
|
|
struct ath11k_sta *arsta;
|
|
int ret, fbret;
|
|
|
|
@@ -466,6 +881,13 @@ int ath11k_peer_create(struct ath11k *ar
|
|
peer->sec_type_grp = HAL_ENCRYPT_TYPE_OPEN;
|
|
peer->vif = arvif->vif;
|
|
|
|
+#ifdef CPTCFG_ATH11K_NSS_SUPPORT
|
|
+ if (vif->type == NL80211_IFTYPE_STATION && ar->ab->nss.enabled)
|
|
+ ar->bss_peer = peer;
|
|
+ else
|
|
+ ar->bss_peer = NULL;
|
|
+#endif
|
|
+
|
|
if (sta) {
|
|
arsta = ath11k_sta_to_arsta(sta);
|
|
arsta->tcl_metadata |= FIELD_PREP(HTT_TCL_META_DATA_TYPE, 0) |
|
|
--- a/drivers/net/wireless/ath/ath11k/peer.h
|
|
+++ b/drivers/net/wireless/ath/ath11k/peer.h
|
|
@@ -18,6 +18,47 @@ struct ppdu_user_delayba {
|
|
u32 resp_rate_flags;
|
|
};
|
|
|
|
+enum ath11k_ast_entry_type {
|
|
+ ATH11K_AST_TYPE_NONE, /* static ast entry for connected peer */
|
|
+ ATH11K_AST_TYPE_STATIC, /* static ast entry for connected peer */
|
|
+ ATH11K_AST_TYPE_SELF, /* static ast entry for self peer (STA mode) */
|
|
+ ATH11K_AST_TYPE_WDS, /* WDS peer ast entry type*/
|
|
+ ATH11K_AST_TYPE_MEC, /* Multicast echo ast entry type */
|
|
+ ATH11K_AST_TYPE_WDS_HM, /* HM WDS entry */
|
|
+ ATH11K_AST_TYPE_STA_BSS, /* BSS entry(STA mode) */
|
|
+ ATH11K_AST_TYPE_DA, /* AST entry based on Destination address */
|
|
+ ATH11K_AST_TYPE_WDS_HM_SEC, /* HM WDS entry for secondary radio */
|
|
+ ATH11K_AST_TYPE_MAX
|
|
+};
|
|
+
|
|
+enum ath11k_wds_wmi_action {
|
|
+ ATH11K_WDS_WMI_ADD = 1,
|
|
+ ATH11K_WDS_WMI_UPDATE,
|
|
+
|
|
+ ATH11K_WDS_WMI_MAX
|
|
+};
|
|
+
|
|
+struct ath11k_ast_entry {
|
|
+ u16 ast_idx;
|
|
+ u8 addr[ETH_ALEN];
|
|
+ u8 next_node_mac[ETH_ALEN];
|
|
+ enum ath11k_wds_wmi_action action;
|
|
+ struct work_struct wds_wmi_wk;
|
|
+ struct ath11k_peer *peer;
|
|
+ struct ath11k *ar;
|
|
+ bool next_hop;
|
|
+ bool is_active;
|
|
+ bool is_mapped;
|
|
+ u8 pdev_idx;
|
|
+ u8 vdev_id;
|
|
+ u16 ast_hash_value;
|
|
+ int ref_cnt;
|
|
+ enum ath11k_ast_entry_type type;
|
|
+ bool delete_in_progress;
|
|
+ void *cookie;
|
|
+ struct list_head ase_list;
|
|
+};
|
|
+
|
|
struct ath11k_peer {
|
|
struct list_head list;
|
|
struct ieee80211_sta *sta;
|
|
@@ -29,6 +70,10 @@ struct ath11k_peer {
|
|
u8 pdev_idx;
|
|
u16 hw_peer_id;
|
|
struct ath11k_nss_peer nss;
|
|
+#ifdef CPTCFG_ATH11K_NSS_SUPPORT
|
|
+ struct ath11k_ast_entry *self_ast_entry;
|
|
+ struct list_head ast_entry_list;
|
|
+#endif
|
|
|
|
/* protected by ab->data_lock */
|
|
struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
|
|
@@ -54,8 +99,13 @@ struct ath11k_peer {
|
|
};
|
|
|
|
void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id);
|
|
+void ath11k_peer_unmap_v2_event(struct ath11k_base *ab, u16 peer_id, u8 *mac_addr,
|
|
+ bool is_wds, u32 free_wds_count);
|
|
void ath11k_peer_map_event(struct ath11k_base *ab, u8 vdev_id, u16 peer_id,
|
|
u8 *mac_addr, u16 ast_hash, u16 hw_peer_id);
|
|
+void ath11k_peer_map_v2_event(struct ath11k_base *ab, u8 vdev_id, u16 peer_id,
|
|
+ u8 *mac_addr, u16 ast_hash, u16 hw_peer_id,
|
|
+ bool is_wds);
|
|
struct ath11k_peer *ath11k_peer_find(struct ath11k_base *ab, int vdev_id,
|
|
const u8 *addr);
|
|
struct ath11k_peer *ath11k_peer_find_by_addr(struct ath11k_base *ab,
|
|
@@ -73,4 +123,71 @@ struct ath11k_peer *ath11k_peer_find_by_
|
|
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);
|
|
+
|
|
+#ifdef CPTCFG_ATH11K_NSS_SUPPORT
|
|
+struct ath11k_ast_entry *ath11k_peer_ast_find_by_addr(struct ath11k_base *ab,
|
|
+ u8* addr);
|
|
+int ath11k_peer_add_ast(struct ath11k *ar, struct ath11k_peer *peer,
|
|
+ u8* mac_addr, enum ath11k_ast_entry_type type);
|
|
+int ath11k_peer_update_ast(struct ath11k *ar, struct ath11k_peer *peer,
|
|
+ struct ath11k_ast_entry *ast_entry);
|
|
+void ath11k_peer_map_ast(struct ath11k *ar, struct ath11k_peer *peer,
|
|
+ u8* mac_addr, u16 hw_peer_id, u16 ast_hash);
|
|
+void ath11k_peer_del_ast(struct ath11k *ar, struct ath11k_ast_entry *ast_entry);
|
|
+void ath11k_peer_ast_cleanup(struct ath11k *ar, struct ath11k_peer *peer,
|
|
+ bool is_wds, u32 free_wds_count);
|
|
+void ath11k_peer_ast_wds_wmi_wk(struct work_struct *wk);
|
|
+struct ath11k_ast_entry *ath11k_peer_ast_find_by_peer(struct ath11k_base *ab,
|
|
+ struct ath11k_peer *peer,
|
|
+ u8* addr);
|
|
+#else
|
|
+static inline struct ath11k_ast_entry *ath11k_peer_ast_find_by_addr(struct ath11k_base *ab,
|
|
+ u8* addr)
|
|
+{
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static inline int ath11k_peer_add_ast(struct ath11k *ar, struct ath11k_peer *peer,
|
|
+ u8* mac_addr, enum ath11k_ast_entry_type type)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static inline int ath11k_peer_update_ast(struct ath11k *ar, struct ath11k_peer *peer,
|
|
+ struct ath11k_ast_entry *ast_entry)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static inline void ath11k_peer_map_ast(struct ath11k *ar, struct ath11k_peer *peer,
|
|
+ u8* mac_addr, u16 hw_peer_id, u16 ast_hash)
|
|
+{
|
|
+ return;
|
|
+}
|
|
+
|
|
+static inline void ath11k_peer_del_ast(struct ath11k *ar,
|
|
+ struct ath11k_ast_entry *ast_entry)
|
|
+{
|
|
+ return;
|
|
+}
|
|
+
|
|
+static inline void ath11k_peer_ast_cleanup(struct ath11k *ar,
|
|
+ struct ath11k_peer *peer,
|
|
+ bool is_wds, u32 free_wds_count)
|
|
+{
|
|
+ return;
|
|
+}
|
|
+
|
|
+static inline void ath11k_peer_ast_wds_wmi_wk(struct work_struct *wk)
|
|
+{
|
|
+ return;
|
|
+}
|
|
+
|
|
+static inline struct ath11k_ast_entry *ath11k_peer_ast_find_by_peer(struct ath11k_base *ab,
|
|
+ struct ath11k_peer *peer,
|
|
+ u8* addr)
|
|
+{
|
|
+ return NULL;
|
|
+}
|
|
+#endif /* CPTCFG_ATH11K_NSS_SUPPORT */
|
|
#endif /* _PEER_H_ */
|
|
--- a/drivers/net/wireless/ath/ath11k/wmi.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
|
|
@@ -156,6 +156,8 @@ static const struct wmi_tlv_policy wmi_t
|
|
.min_len = sizeof(struct wmi_per_chain_rssi_stats) },
|
|
[WMI_TAG_TWT_ADD_DIALOG_COMPLETE_EVENT] = {
|
|
.min_len = sizeof(struct wmi_twt_add_dialog_event) },
|
|
+ [WMI_TAG_WDS_ADDR_EVENT] = {
|
|
+ .min_len = sizeof(struct wmi_wds_addr_event) },
|
|
};
|
|
|
|
#define PRIMAP(_hw_mode_) \
|
|
@@ -1126,6 +1128,51 @@ int ath11k_wmi_send_peer_delete_cmd(stru
|
|
return ret;
|
|
}
|
|
|
|
+int ath11k_wmi_send_add_update_wds_entry_cmd(struct ath11k *ar,
|
|
+ const u8 *peer_addr,
|
|
+ const u8 *wds_addr, u8 vdev_id,
|
|
+ bool add_wds)
|
|
+{
|
|
+ struct ath11k_pdev_wmi *wmi = ar->wmi;
|
|
+ struct wmi_add_wds_entry_cmd *cmd;
|
|
+ struct sk_buff *skb;
|
|
+ int ret;
|
|
+
|
|
+ skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
|
|
+ if (!skb)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ cmd = (struct wmi_add_wds_entry_cmd *)skb->data;
|
|
+ if (add_wds)
|
|
+ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PEER_ADD_WDS_ENTRY_CMD) |
|
|
+ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
|
|
+ else
|
|
+ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PEER_UPDATE_WDS_ENTRY_CMD) |
|
|
+ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
|
|
+
|
|
+ ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
|
|
+ ether_addr_copy(cmd->wds_macaddr.addr, wds_addr);
|
|
+ cmd->vdev_id = vdev_id;
|
|
+ cmd->flags = WMI_WDS_FLAG_STATIC;
|
|
+
|
|
+ ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
|
|
+ "WMI add WDS entry vdev_id %d peer_addr %pM, wds_addr %pM flags %x\n",
|
|
+ vdev_id, peer_addr, wds_addr, cmd->flags);
|
|
+
|
|
+ if (add_wds)
|
|
+ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PEER_ADD_WDS_ENTRY_CMDID);
|
|
+ else
|
|
+ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PEER_UPDATE_WDS_ENTRY_CMDID);
|
|
+
|
|
+ if (ret) {
|
|
+ ath11k_warn(ar->ab, "failed to send WMI_PEER_%s_WDS_ENTRY cmd\n",
|
|
+ add_wds ? "ADD" : "UPDATE");
|
|
+ dev_kfree_skb(skb);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
int ath11k_wmi_send_pdev_set_regdomain(struct ath11k *ar,
|
|
struct pdev_set_regdomain_params *param)
|
|
{
|
|
@@ -6363,6 +6410,36 @@ static int ath11k_pull_peer_assoc_conf_e
|
|
return 0;
|
|
}
|
|
|
|
+static int ath11k_pull_wds_addr_ev(struct ath11k_base *ab, struct sk_buff *skb,
|
|
+ struct wmi_wds_addr_arg *wds_addr_arg)
|
|
+{
|
|
+ const void **tb;
|
|
+ const struct wmi_wds_addr_event *ev;
|
|
+ int ret;
|
|
+
|
|
+ tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
|
|
+ if (IS_ERR(tb)) {
|
|
+ ret = PTR_ERR(tb);
|
|
+ ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ev = tb[WMI_TAG_WDS_ADDR_EVENT];
|
|
+ if (!ev) {
|
|
+ ath11k_warn(ab, "failed to fetch wds peer ev");
|
|
+ kfree(tb);
|
|
+ return -EPROTO;
|
|
+ }
|
|
+
|
|
+ memcpy(wds_addr_arg->event_type, ev->event_type, WMI_NUM_WDS_EVENTS);
|
|
+ wds_addr_arg->vdev_id = ev->vdev_id;
|
|
+ wds_addr_arg->peer_macaddr = ev->peer_macaddr.addr;
|
|
+ wds_addr_arg->dst_macaddr = ev->dst_macaddr.addr;
|
|
+
|
|
+ kfree(tb);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static void ath11k_wmi_pull_pdev_stats_base(const struct wmi_pdev_stats_base *src,
|
|
struct ath11k_fw_stats_pdev *dst)
|
|
{
|
|
@@ -7278,6 +7355,7 @@ static int ath11k_wmi_tlv_rdy_parse(stru
|
|
|
|
ether_addr_copy(ab->mac_addr,
|
|
fixed_param.ready_event_min.mac_addr.addr);
|
|
+ ab->max_ast_index = fixed_param.max_ast_index + 1;
|
|
ab->pktlog_defs_checksum = fixed_param.pktlog_defs_checksum;
|
|
break;
|
|
case WMI_TAG_ARRAY_FIXED_STRUCT:
|
|
@@ -8797,6 +8875,22 @@ exit:
|
|
kfree(tb);
|
|
}
|
|
|
|
+static void ath11k_wmi_wds_peer_event(struct ath11k_base *ab,
|
|
+ struct sk_buff *skb)
|
|
+{
|
|
+ struct wmi_wds_addr_arg wds_addr_arg = {0};
|
|
+
|
|
+ if (ath11k_pull_wds_addr_ev(ab, skb, &wds_addr_arg) != 0) {
|
|
+ ath11k_warn(ab, "failed to extract wds addr event");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ath11k_dbg(ab, ATH11K_DBG_WMI,
|
|
+ "wds addr event vdev id %d peer macaddr %pM dst macaddr %pM\n",
|
|
+ wds_addr_arg.vdev_id, wds_addr_arg.peer_macaddr,
|
|
+ wds_addr_arg.dst_macaddr);
|
|
+}
|
|
+
|
|
static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)
|
|
{
|
|
struct wmi_cmd_hdr *cmd_hdr;
|
|
@@ -8927,6 +9021,9 @@ static void ath11k_wmi_tlv_op_rx(struct
|
|
case WMI_GTK_OFFLOAD_STATUS_EVENTID:
|
|
ath11k_wmi_gtk_offload_status_event(ab, skb);
|
|
break;
|
|
+ case WMI_WDS_PEER_EVENTID:
|
|
+ ath11k_wmi_wds_peer_event(ab, skb);
|
|
+ break;
|
|
default:
|
|
ath11k_dbg(ab, ATH11K_DBG_WMI, "unsupported event id 0x%x\n", id);
|
|
break;
|
|
--- a/drivers/net/wireless/ath/ath11k/wmi.h
|
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
|
|
@@ -3011,6 +3011,21 @@ struct wmi_peer_delete_cmd {
|
|
struct wmi_mac_addr peer_macaddr;
|
|
} __packed;
|
|
|
|
+#define WMI_WDS_FLAG_STATIC 0x1 /* Disable aging & learning */
|
|
+struct wmi_add_wds_entry_cmd {
|
|
+ u32 tlv_header;
|
|
+ struct wmi_mac_addr peer_macaddr;
|
|
+ struct wmi_mac_addr wds_macaddr;
|
|
+ u32 flags;
|
|
+ u32 vdev_id;
|
|
+} __packed;
|
|
+
|
|
+struct wmi_remove_wds_entry_cmd {
|
|
+ u32 tlv_header;
|
|
+ struct wmi_mac_addr wds_macaddr;
|
|
+ u32 vdev_id;
|
|
+} __packed;
|
|
+
|
|
struct wmi_peer_reorder_queue_setup_cmd {
|
|
u32 tlv_header;
|
|
u32 vdev_id;
|
|
@@ -4613,6 +4628,21 @@ struct wmi_probe_resp_tx_status_event {
|
|
u32 tx_status;
|
|
} __packed;
|
|
|
|
+#define WMI_NUM_WDS_EVENTS 4
|
|
+struct wmi_wds_addr_arg {
|
|
+ u32 event_type[WMI_NUM_WDS_EVENTS];
|
|
+ const u8 *peer_macaddr;
|
|
+ const u8 *dst_macaddr;
|
|
+ u32 vdev_id;
|
|
+};
|
|
+
|
|
+struct wmi_wds_addr_event {
|
|
+ u32 event_type[WMI_NUM_WDS_EVENTS];
|
|
+ struct wmi_mac_addr peer_macaddr;
|
|
+ struct wmi_mac_addr dst_macaddr;
|
|
+ u32 vdev_id;
|
|
+} __packed;
|
|
+
|
|
/*
|
|
* PDEV statistics
|
|
*/
|
|
@@ -6412,6 +6442,9 @@ int ath11k_wmi_set_sta_ps_param(struct a
|
|
int ath11k_wmi_force_fw_hang_cmd(struct ath11k *ar, u32 type, u32 delay_time_ms);
|
|
int ath11k_wmi_send_peer_delete_cmd(struct ath11k *ar,
|
|
const u8 *peer_addr, u8 vdev_id);
|
|
+int ath11k_wmi_send_add_update_wds_entry_cmd(struct ath11k *ar,
|
|
+ const u8 *peer_addr, const u8 *wds_addr,
|
|
+ u8 vdev_id, bool add_wds);
|
|
int ath11k_wmi_vdev_delete(struct ath11k *ar, u8 vdev_id);
|
|
void ath11k_wmi_start_scan_init(struct ath11k *ar, struct scan_req_params *arg);
|
|
int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar,
|