[PATCH ath12k-ng 01/12] wifi: ath12k: Move monitor ring processing to Wi-Fi 7 module
Alok Singh
quic_aloksing at quicinc.com
Mon Nov 10 02:37:02 PST 2025
Separate Wi-Fi 7-specific monitor-mode processing from common
ath12k data path code to improve modularity.
Move monitor status ring processing to wifi7/dp_mon.c:
- ath12k_dp_mon_srng_process()
- __ath12k_dp_mon_process_ring()
- ath12k_dp_mon_process_ring()
Rename the above to use the ath12k_wifi7_ prefix and
export helper functions required by the ath12k_wifi7 module.
Update the Wi-Fi 7 module Makefile to build dp_mon.o.
No functional changes are intended; this is preparatory refactoring
to isolate Wi-Fi 7 monitor-mode code from shared ath12k code.
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.5-01651-QCAHKSWPL_SILICONZ-1
Signed-off-by: Alok Singh <quic_aloksing at quicinc.com>
---
drivers/net/wireless/ath/ath12k/dp_mon.c | 256 ++----------------
drivers/net/wireless/ath/ath12k/dp_mon.h | 19 +-
.../net/wireless/ath/ath12k/wifi7/Makefile | 1 +
drivers/net/wireless/ath/ath12k/wifi7/dp.c | 16 +-
drivers/net/wireless/ath/ath12k/wifi7/dp.h | 1 +
.../net/wireless/ath/ath12k/wifi7/dp_mon.c | 244 +++++++++++++++++
.../net/wireless/ath/ath12k/wifi7/dp_mon.h | 17 ++
7 files changed, 305 insertions(+), 249 deletions(-)
create mode 100644 drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c
create mode 100644 drivers/net/wireless/ath/ath12k/wifi7/dp_mon.h
diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c
index 0533d8bf9c1c..5e2bf24d6b7e 100644
--- a/drivers/net/wireless/ath/ath12k/dp_mon.c
+++ b/drivers/net/wireless/ath/ath12k/dp_mon.c
@@ -2541,7 +2541,7 @@ ath12k_dp_mon_parse_rx_dest_tlv(struct ath12k_pdev_dp *dp_pdev,
return 0;
}
-static enum hal_rx_mon_status
+enum hal_rx_mon_status
ath12k_dp_mon_parse_rx_dest(struct ath12k_pdev_dp *dp_pdev, struct ath12k_mon_data *pmon,
struct sk_buff *skb)
{
@@ -2592,6 +2592,7 @@ ath12k_dp_mon_parse_rx_dest(struct ath12k_pdev_dp *dp_pdev, struct ath12k_mon_da
return hal_status;
}
+EXPORT_SYMBOL(ath12k_dp_mon_parse_rx_dest);
enum hal_rx_mon_status
ath12k_dp_mon_rx_parse_mon_status(struct ath12k_pdev_dp *dp_pdev,
@@ -2619,6 +2620,7 @@ ath12k_dp_mon_rx_parse_mon_status(struct ath12k_pdev_dp *dp_pdev,
return hal_status;
}
+EXPORT_SYMBOL(ath12k_dp_mon_rx_parse_mon_status);
int ath12k_dp_mon_buf_replenish(struct ath12k_base *ab,
struct dp_rxdma_mon_ring *buf_ring,
@@ -2694,6 +2696,7 @@ int ath12k_dp_mon_buf_replenish(struct ath12k_base *ab,
spin_unlock_bh(&srng->lock);
return -ENOMEM;
}
+EXPORT_SYMBOL(ath12k_dp_mon_buf_replenish);
int ath12k_dp_mon_status_bufs_replenish(struct ath12k_base *ab,
struct dp_rxdma_mon_ring *rx_ring,
@@ -3490,8 +3493,8 @@ ath12k_dp_mon_rx_update_peer_rate_table_stats(struct ath12k_rx_peer_stats *rx_st
stats->rx_rate[bw_idx][gi_idx][nss_idx][mcs_idx] += len;
}
-static void ath12k_dp_mon_rx_update_peer_su_stats(struct ath12k_dp_link_peer *peer,
- struct hal_rx_mon_ppdu_info *ppdu_info)
+void ath12k_dp_mon_rx_update_peer_su_stats(struct ath12k_dp_link_peer *peer,
+ struct hal_rx_mon_ppdu_info *ppdu_info)
{
struct ath12k_rx_peer_stats *rx_stats = peer->peer_stats.rx_stats;
u32 num_msdu;
@@ -3598,6 +3601,7 @@ static void ath12k_dp_mon_rx_update_peer_su_stats(struct ath12k_dp_link_peer *pe
ath12k_dp_mon_rx_update_peer_rate_table_stats(rx_stats, ppdu_info,
NULL, num_msdu);
}
+EXPORT_SYMBOL(ath12k_dp_mon_rx_update_peer_su_stats);
void ath12k_dp_mon_rx_process_ulofdma(struct hal_rx_mon_ppdu_info *ppdu_info)
{
@@ -3646,6 +3650,7 @@ void ath12k_dp_mon_rx_process_ulofdma(struct hal_rx_mon_ppdu_info *ppdu_info)
}
ppdu_info->ldpc = 1;
}
+EXPORT_SYMBOL(ath12k_dp_mon_rx_process_ulofdma);
static void
ath12k_dp_mon_rx_update_user_stats(struct ath12k_base *ab,
@@ -3746,7 +3751,7 @@ ath12k_dp_mon_rx_update_user_stats(struct ath12k_base *ab,
user_stats, num_msdu);
}
-static void
+void
ath12k_dp_mon_rx_update_peer_mu_stats(struct ath12k_base *ab,
struct hal_rx_mon_ppdu_info *ppdu_info)
{
@@ -3759,169 +3764,18 @@ ath12k_dp_mon_rx_update_peer_mu_stats(struct ath12k_base *ab,
for (i = 0; i < num_users; i++)
ath12k_dp_mon_rx_update_user_stats(ab, ppdu_info, i);
}
+EXPORT_SYMBOL(ath12k_dp_mon_rx_update_peer_mu_stats);
-static void
+void
ath12k_dp_mon_rx_memset_ppdu_info(struct hal_rx_mon_ppdu_info *ppdu_info)
{
memset(ppdu_info, 0, sizeof(*ppdu_info));
ppdu_info->peer_id = HAL_INVALID_PEERID;
}
+EXPORT_SYMBOL(ath12k_dp_mon_rx_memset_ppdu_info);
-int ath12k_dp_mon_srng_process(struct ath12k_pdev_dp *pdev_dp, int *budget,
- struct napi_struct *napi)
-{
- struct ath12k_dp *dp = pdev_dp->dp;
- struct ath12k_base *ab = dp->ab;
- struct ath12k_mon_data *pmon = (struct ath12k_mon_data *)&pdev_dp->mon_data;
- struct hal_rx_mon_ppdu_info *ppdu_info = &pmon->mon_ppdu_info;
- struct hal_mon_dest_desc *mon_dst_desc;
- struct sk_buff *skb;
- struct ath12k_skb_rxcb *rxcb;
- struct dp_srng *mon_dst_ring;
- struct hal_srng *srng;
- struct dp_rxdma_mon_ring *buf_ring;
- struct ath12k_dp_link_peer *peer;
- struct sk_buff_head skb_list;
- u64 cookie;
- int num_buffs_reaped = 0, srng_id, buf_id;
- u32 hal_status, end_offset, info0, end_reason;
- u8 pdev_idx = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, pdev_dp->mac_id);
-
- __skb_queue_head_init(&skb_list);
- srng_id = ath12k_hw_mac_id_to_srng_id(ab->hw_params, pdev_idx);
- mon_dst_ring = &pdev_dp->rxdma_mon_dst_ring[srng_id];
- buf_ring = &dp->rxdma_mon_buf_ring;
-
- srng = &ab->hal.srng_list[mon_dst_ring->ring_id];
- spin_lock_bh(&srng->lock);
- ath12k_hal_srng_access_begin(ab, srng);
-
- while (likely(*budget)) {
- mon_dst_desc = ath12k_hal_srng_dst_peek(ab, srng);
- if (unlikely(!mon_dst_desc))
- break;
-
- /* In case of empty descriptor, the cookie in the ring descriptor
- * is invalid. Therefore, this entry is skipped, and ring processing
- * continues.
- */
- info0 = le32_to_cpu(mon_dst_desc->info0);
- if (u32_get_bits(info0, HAL_MON_DEST_INFO0_EMPTY_DESC))
- goto move_next;
-
- cookie = le32_to_cpu(mon_dst_desc->cookie);
- buf_id = u32_get_bits(cookie, DP_RXDMA_BUF_COOKIE_BUF_ID);
-
- spin_lock_bh(&buf_ring->idr_lock);
- skb = idr_remove(&buf_ring->bufs_idr, buf_id);
- spin_unlock_bh(&buf_ring->idr_lock);
-
- if (unlikely(!skb)) {
- ath12k_warn(ab, "monitor destination with invalid buf_id %d\n",
- buf_id);
- goto move_next;
- }
-
- rxcb = ATH12K_SKB_RXCB(skb);
- dma_unmap_single(ab->dev, rxcb->paddr,
- skb->len + skb_tailroom(skb),
- DMA_FROM_DEVICE);
-
- end_reason = u32_get_bits(info0, HAL_MON_DEST_INFO0_END_REASON);
-
- /* HAL_MON_FLUSH_DETECTED implies that an rx flush received at the end of
- * rx PPDU and HAL_MON_PPDU_TRUNCATED implies that the PPDU got
- * truncated due to a system level error. In both the cases, buffer data
- * can be discarded
- */
- if ((end_reason == HAL_MON_FLUSH_DETECTED) ||
- (end_reason == HAL_MON_PPDU_TRUNCATED)) {
- ath12k_dbg(ab, ATH12K_DBG_DATA,
- "Monitor dest descriptor end reason %d", end_reason);
- dev_kfree_skb_any(skb);
- goto move_next;
- }
-
- /* Calculate the budget when the ring descriptor with the
- * HAL_MON_END_OF_PPDU to ensure that one PPDU worth of data is always
- * reaped. This helps to efficiently utilize the NAPI budget.
- */
- if (end_reason == HAL_MON_END_OF_PPDU) {
- *budget -= 1;
- rxcb->is_end_of_ppdu = true;
- }
-
- end_offset = u32_get_bits(info0, HAL_MON_DEST_INFO0_END_OFFSET);
- if (likely(end_offset <= DP_RX_BUFFER_SIZE)) {
- skb_put(skb, end_offset);
- } else {
- ath12k_warn(ab,
- "invalid offset on mon stats destination %u\n",
- end_offset);
- skb_put(skb, DP_RX_BUFFER_SIZE);
- }
-
- __skb_queue_tail(&skb_list, skb);
-
-move_next:
- ath12k_dp_mon_buf_replenish(ab, buf_ring, 1);
- ath12k_hal_srng_dst_get_next_entry(ab, srng);
- num_buffs_reaped++;
- }
-
- ath12k_hal_srng_access_end(ab, srng);
- spin_unlock_bh(&srng->lock);
-
- if (!num_buffs_reaped)
- return 0;
-
- /* In some cases, one PPDU worth of data can be spread across multiple NAPI
- * schedules, To avoid losing existing parsed ppdu_info information, skip
- * the memset of the ppdu_info structure and continue processing it.
- */
- if (!ppdu_info->ppdu_continuation)
- ath12k_dp_mon_rx_memset_ppdu_info(ppdu_info);
-
- while ((skb = __skb_dequeue(&skb_list))) {
- hal_status = ath12k_dp_mon_rx_parse_mon_status(pdev_dp, pmon, skb, napi);
- if (hal_status != HAL_RX_MON_STATUS_PPDU_DONE) {
- ppdu_info->ppdu_continuation = true;
- dev_kfree_skb_any(skb);
- continue;
- }
-
- if (ppdu_info->peer_id == HAL_INVALID_PEERID)
- goto free_skb;
-
- rcu_read_lock();
- peer = ath12k_dp_link_peer_find_by_peerid(pdev_dp, ppdu_info->peer_id);
- if (!peer || !peer->sta) {
- ath12k_dbg(ab, ATH12K_DBG_DATA,
- "failed to find the peer with monitor peer_id %d\n",
- ppdu_info->peer_id);
- goto next_skb;
- }
-
- if (ppdu_info->reception_type == HAL_RX_RECEPTION_TYPE_SU) {
- ath12k_dp_mon_rx_update_peer_su_stats(peer, ppdu_info);
- } else if ((ppdu_info->fc_valid) &&
- (ppdu_info->ast_index != HAL_AST_IDX_INVALID)) {
- ath12k_dp_mon_rx_process_ulofdma(ppdu_info);
- ath12k_dp_mon_rx_update_peer_mu_stats(ab, ppdu_info);
- }
-
-next_skb:
- rcu_read_unlock();
-free_skb:
- dev_kfree_skb_any(skb);
- ath12k_dp_mon_rx_memset_ppdu_info(ppdu_info);
- }
-
- return num_buffs_reaped;
-}
-
-static int ath12k_dp_rx_reap_mon_status_ring(struct ath12k_base *ab, int mac_id,
- int *budget, struct sk_buff_head *skb_list)
+int ath12k_dp_rx_reap_mon_status_ring(struct ath12k_base *ab, int mac_id,
+ int *budget, struct sk_buff_head *skb_list)
{
const struct ath12k_hw_hal_params *hal_params;
int buf_id, srng_id, num_buffs_reaped = 0;
@@ -4064,6 +3918,7 @@ static int ath12k_dp_rx_reap_mon_status_ring(struct ath12k_base *ab, int mac_id,
return num_buffs_reaped;
}
+EXPORT_SYMBOL(ath12k_dp_rx_reap_mon_status_ring);
static u32
ath12k_dp_rx_mon_mpdu_pop(struct ath12k *ar, int mac_id,
@@ -4259,8 +4114,8 @@ ath12k_dp_rx_mon_mpdu_pop(struct ath12k *ar, int mac_id,
*/
#define MON_DEST_RING_STUCK_MAX_CNT 16
-static void ath12k_dp_rx_mon_dest_process(struct ath12k *ar, int mac_id,
- u32 quota, struct napi_struct *napi)
+void ath12k_dp_rx_mon_dest_process(struct ath12k *ar, int mac_id,
+ u32 quota, struct napi_struct *napi)
{
struct ath12k_mon_data *pmon = (struct ath12k_mon_data *)&ar->dp.mon_data;
struct ath12k_pdev_mon_stats *rx_mon_stats;
@@ -4361,79 +4216,4 @@ static void ath12k_dp_rx_mon_dest_process(struct ath12k *ar, int mac_id,
rx_bufs_used);
}
}
-
-static int
-__ath12k_dp_mon_process_ring(struct ath12k *ar, int mac_id,
- struct napi_struct *napi, int *budget)
-{
- struct ath12k_mon_data *pmon = (struct ath12k_mon_data *)&ar->dp.mon_data;
- struct ath12k_pdev_mon_stats *rx_mon_stats = &pmon->rx_mon_stats;
- struct hal_rx_mon_ppdu_info *ppdu_info = &pmon->mon_ppdu_info;
- enum hal_rx_mon_status hal_status;
- struct sk_buff_head skb_list;
- int num_buffs_reaped;
- struct sk_buff *skb;
-
- __skb_queue_head_init(&skb_list);
-
- num_buffs_reaped = ath12k_dp_rx_reap_mon_status_ring(ar->ab, mac_id,
- budget, &skb_list);
- if (!num_buffs_reaped)
- goto exit;
-
- while ((skb = __skb_dequeue(&skb_list))) {
- memset(ppdu_info, 0, sizeof(*ppdu_info));
- ppdu_info->peer_id = HAL_INVALID_PEERID;
-
- hal_status = ath12k_dp_mon_parse_rx_dest(&ar->dp, pmon, skb);
-
- if (ar->monitor_started &&
- pmon->mon_ppdu_status == DP_PPDU_STATUS_START &&
- hal_status == HAL_TLV_STATUS_PPDU_DONE) {
- rx_mon_stats->status_ppdu_done++;
- pmon->mon_ppdu_status = DP_PPDU_STATUS_DONE;
- ath12k_dp_rx_mon_dest_process(ar, mac_id, *budget, napi);
- pmon->mon_ppdu_status = DP_PPDU_STATUS_START;
- }
-
- dev_kfree_skb_any(skb);
- }
-
-exit:
- return num_buffs_reaped;
-}
-
-int ath12k_dp_mon_process_ring(struct ath12k_dp *dp, int mac_id,
- struct napi_struct *napi, int budget,
- enum dp_monitor_mode monitor_mode)
-{
- u8 pdev_idx = ath12k_hw_mac_id_to_pdev_id(dp->hw_params, mac_id);
- struct ath12k_pdev_dp *dp_pdev;
- struct ath12k *ar;
- int num_buffs_reaped = 0;
-
- rcu_read_lock();
-
- dp_pdev = ath12k_dp_to_pdev_dp(dp, pdev_idx);
- if (!dp_pdev) {
- rcu_read_unlock();
- return 0;
- }
-
- if (dp->hw_params->rxdma1_enable) {
- if (monitor_mode == ATH12K_DP_RX_MONITOR_MODE)
- num_buffs_reaped = ath12k_dp_mon_srng_process(dp_pdev, &budget,
- napi);
- } else {
- ar = ath12k_pdev_dp_to_ar(dp_pdev);
-
- if (ar->monitor_started)
- num_buffs_reaped =
- __ath12k_dp_mon_process_ring(ar, mac_id, napi, &budget);
- }
-
- rcu_read_unlock();
-
- return num_buffs_reaped;
-}
-EXPORT_SYMBOL(ath12k_dp_mon_process_ring);
+EXPORT_SYMBOL(ath12k_dp_rx_mon_dest_process);
diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.h b/drivers/net/wireless/ath/ath12k/dp_mon.h
index 3e6ff4b0a6d9..689d7a0fff5c 100644
--- a/drivers/net/wireless/ath/ath12k/dp_mon.h
+++ b/drivers/net/wireless/ath/ath12k/dp_mon.h
@@ -89,9 +89,6 @@ int ath12k_dp_mon_buf_replenish(struct ath12k_base *ab,
int ath12k_dp_mon_status_bufs_replenish(struct ath12k_base *ab,
struct dp_rxdma_mon_ring *rx_ring,
int req_entries);
-int ath12k_dp_mon_process_ring(struct ath12k_dp *dp, int mac_id,
- struct napi_struct *napi, int budget,
- enum dp_monitor_mode monitor_mode);
struct sk_buff *ath12k_dp_mon_tx_alloc_skb(void);
enum dp_mon_tx_tlv_status
ath12k_dp_mon_tx_status_get_num_user(u16 tlv_tag,
@@ -104,6 +101,18 @@ ath12k_dp_mon_tx_parse_mon_status(struct ath12k_pdev_dp *dp_pdev,
struct napi_struct *napi,
u32 ppdu_id);
void ath12k_dp_mon_rx_process_ulofdma(struct hal_rx_mon_ppdu_info *ppdu_info);
-int ath12k_dp_mon_srng_process(struct ath12k_pdev_dp *pdev_dp, int *budget,
- struct napi_struct *napi);
+enum hal_rx_mon_status
+ath12k_dp_mon_parse_rx_dest(struct ath12k_pdev_dp *dp_pdev, struct ath12k_mon_data *pmon,
+ struct sk_buff *skb);
+int ath12k_dp_rx_reap_mon_status_ring(struct ath12k_base *ab, int mac_id,
+ int *budget, struct sk_buff_head *skb_list);
+void ath12k_dp_rx_mon_dest_process(struct ath12k *ar, int mac_id,
+ u32 quota, struct napi_struct *napi);
+void
+ath12k_dp_mon_rx_update_peer_mu_stats(struct ath12k_base *ab,
+ struct hal_rx_mon_ppdu_info *ppdu_info);
+void ath12k_dp_mon_rx_update_peer_su_stats(struct ath12k_dp_link_peer *peer,
+ struct hal_rx_mon_ppdu_info *ppdu_info);
+void
+ath12k_dp_mon_rx_memset_ppdu_info(struct hal_rx_mon_ppdu_info *ppdu_info);
#endif
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/Makefile b/drivers/net/wireless/ath/ath12k/wifi7/Makefile
index 30258a1b313d..dcfa732bb95b 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/Makefile
+++ b/drivers/net/wireless/ath/ath12k/wifi7/Makefile
@@ -11,6 +11,7 @@ ath12k_wifi7-y += core.o \
dp_rx.o \
dp_tx.o \
dp.o \
+ dp_mon.o \
hal.o \
hal_qcn9274.o \
hal_wcn7850.o
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp.c b/drivers/net/wireless/ath/ath12k/wifi7/dp.c
index 30c27e005ed8..0b2c7f37c756 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/dp.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp.c
@@ -9,6 +9,7 @@
#include "../dp_tx.h"
#include "hal_desc.h"
#include "../dp_mon.h"
+#include "dp_mon.h"
#include "../dp_cmn.h"
#include "dp_rx.h"
#include "dp.h"
@@ -66,8 +67,9 @@ static int ath12k_wifi7_dp_service_srng(struct ath12k_dp *dp,
if (ring_mask & BIT(id)) {
work_done =
- ath12k_dp_mon_process_ring(dp, id, napi, budget,
- 0);
+ ath12k_wifi7_dp_mon_process_ring(dp, id, napi,
+ budget,
+ 0);
budget -= work_done;
tot_work_done += work_done;
if (budget <= 0)
@@ -86,8 +88,9 @@ static int ath12k_wifi7_dp_service_srng(struct ath12k_dp *dp,
if (ring_mask & BIT(id)) {
work_done =
- ath12k_dp_mon_process_ring(dp, id, napi, budget,
- monitor_mode);
+ ath12k_wifi7_dp_mon_process_ring(dp, id, napi,
+ budget,
+ monitor_mode);
budget -= work_done;
tot_work_done += work_done;
@@ -107,8 +110,9 @@ static int ath12k_wifi7_dp_service_srng(struct ath12k_dp *dp,
if (ring_mask & BIT(id)) {
work_done =
- ath12k_dp_mon_process_ring(dp, id, napi, budget,
- monitor_mode);
+ ath12k_wifi7_dp_mon_process_ring(dp, id,
+ napi, budget,
+ monitor_mode);
budget -= work_done;
tot_work_done += work_done;
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp.h b/drivers/net/wireless/ath/ath12k/wifi7/dp.h
index 72fdfb368c99..a5f0941d34e2 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/dp.h
+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp.h
@@ -12,6 +12,7 @@
struct ath12k_base;
struct ath12k_dp;
+enum dp_monitor_mode;
struct ath12k_dp *ath12k_wifi7_dp_device_alloc(struct ath12k_base *ab);
void ath12k_wifi7_dp_device_free(struct ath12k_dp *dp);
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c
new file mode 100644
index 000000000000..4135ff5e8759
--- /dev/null
+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include "hal_desc.h"
+#include "../dp_mon.h"
+#include "dp_mon.h"
+#include "../debug.h"
+#include "hal_qcn9274.h"
+#include "dp_rx.h"
+#include "../peer.h"
+
+static int
+__ath12k_wifi7_dp_mon_process_ring(struct ath12k *ar, int mac_id,
+ struct napi_struct *napi, int *budget)
+{
+ struct ath12k_mon_data *pmon = (struct ath12k_mon_data *)&ar->dp.mon_data;
+ struct ath12k_pdev_mon_stats *rx_mon_stats = &pmon->rx_mon_stats;
+ struct hal_rx_mon_ppdu_info *ppdu_info = &pmon->mon_ppdu_info;
+ enum hal_rx_mon_status hal_status;
+ struct sk_buff_head skb_list;
+ int num_buffs_reaped;
+ struct sk_buff *skb;
+
+ __skb_queue_head_init(&skb_list);
+
+ num_buffs_reaped = ath12k_dp_rx_reap_mon_status_ring(ar->ab, mac_id,
+ budget, &skb_list);
+ if (!num_buffs_reaped)
+ goto exit;
+
+ while ((skb = __skb_dequeue(&skb_list))) {
+ memset(ppdu_info, 0, sizeof(*ppdu_info));
+ ppdu_info->peer_id = HAL_INVALID_PEERID;
+
+ hal_status = ath12k_dp_mon_parse_rx_dest(&ar->dp, pmon, skb);
+
+ if (ar->monitor_started &&
+ pmon->mon_ppdu_status == DP_PPDU_STATUS_START &&
+ hal_status == HAL_TLV_STATUS_PPDU_DONE) {
+ rx_mon_stats->status_ppdu_done++;
+ pmon->mon_ppdu_status = DP_PPDU_STATUS_DONE;
+ ath12k_dp_rx_mon_dest_process(ar, mac_id, *budget, napi);
+ pmon->mon_ppdu_status = DP_PPDU_STATUS_START;
+ }
+
+ dev_kfree_skb_any(skb);
+ }
+
+exit:
+ return num_buffs_reaped;
+}
+
+static int
+ath12k_wifi7_dp_mon_srng_process(struct ath12k_pdev_dp *pdev_dp, int *budget,
+ struct napi_struct *napi)
+{
+ struct ath12k_dp *dp = pdev_dp->dp;
+ struct ath12k_base *ab = dp->ab;
+ struct ath12k_mon_data *pmon = (struct ath12k_mon_data *)&pdev_dp->mon_data;
+ struct hal_rx_mon_ppdu_info *ppdu_info = &pmon->mon_ppdu_info;
+ struct hal_mon_dest_desc *mon_dst_desc;
+ struct sk_buff *skb;
+ struct ath12k_skb_rxcb *rxcb;
+ struct dp_srng *mon_dst_ring;
+ struct hal_srng *srng;
+ struct dp_rxdma_mon_ring *buf_ring;
+ struct ath12k_dp_link_peer *peer;
+ struct sk_buff_head skb_list;
+ u64 cookie;
+ int num_buffs_reaped = 0, srng_id, buf_id;
+ u32 hal_status, end_offset, info0, end_reason;
+ u8 pdev_idx = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, pdev_dp->mac_id);
+
+ __skb_queue_head_init(&skb_list);
+ srng_id = ath12k_hw_mac_id_to_srng_id(ab->hw_params, pdev_idx);
+ mon_dst_ring = &pdev_dp->rxdma_mon_dst_ring[srng_id];
+ buf_ring = &dp->rxdma_mon_buf_ring;
+
+ srng = &ab->hal.srng_list[mon_dst_ring->ring_id];
+ spin_lock_bh(&srng->lock);
+ ath12k_hal_srng_access_begin(ab, srng);
+
+ while (likely(*budget)) {
+ mon_dst_desc = ath12k_hal_srng_dst_peek(ab, srng);
+ if (unlikely(!mon_dst_desc))
+ break;
+
+ /* In case of empty descriptor, the cookie in the ring descriptor
+ * is invalid. Therefore, this entry is skipped, and ring processing
+ * continues.
+ */
+ info0 = le32_to_cpu(mon_dst_desc->info0);
+ if (u32_get_bits(info0, HAL_MON_DEST_INFO0_EMPTY_DESC))
+ goto move_next;
+
+ cookie = le32_to_cpu(mon_dst_desc->cookie);
+ buf_id = u32_get_bits(cookie, DP_RXDMA_BUF_COOKIE_BUF_ID);
+
+ spin_lock_bh(&buf_ring->idr_lock);
+ skb = idr_remove(&buf_ring->bufs_idr, buf_id);
+ spin_unlock_bh(&buf_ring->idr_lock);
+
+ if (unlikely(!skb)) {
+ ath12k_warn(ab, "monitor destination with invalid buf_id %d\n",
+ buf_id);
+ goto move_next;
+ }
+
+ rxcb = ATH12K_SKB_RXCB(skb);
+ dma_unmap_single(ab->dev, rxcb->paddr,
+ skb->len + skb_tailroom(skb),
+ DMA_FROM_DEVICE);
+
+ end_reason = u32_get_bits(info0, HAL_MON_DEST_INFO0_END_REASON);
+
+ /* HAL_MON_FLUSH_DETECTED implies that an rx flush received at the end of
+ * rx PPDU and HAL_MON_PPDU_TRUNCATED implies that the PPDU got
+ * truncated due to a system level error. In both the cases, buffer data
+ * can be discarded
+ */
+ if ((end_reason == HAL_MON_FLUSH_DETECTED) ||
+ (end_reason == HAL_MON_PPDU_TRUNCATED)) {
+ ath12k_dbg(ab, ATH12K_DBG_DATA,
+ "Monitor dest descriptor end reason %d", end_reason);
+ dev_kfree_skb_any(skb);
+ goto move_next;
+ }
+
+ /* Calculate the budget when the ring descriptor with the
+ * HAL_MON_END_OF_PPDU to ensure that one PPDU worth of data is always
+ * reaped. This helps to efficiently utilize the NAPI budget.
+ */
+ if (end_reason == HAL_MON_END_OF_PPDU) {
+ *budget -= 1;
+ rxcb->is_end_of_ppdu = true;
+ }
+
+ end_offset = u32_get_bits(info0, HAL_MON_DEST_INFO0_END_OFFSET);
+ if (likely(end_offset <= DP_RX_BUFFER_SIZE)) {
+ skb_put(skb, end_offset);
+ } else {
+ ath12k_warn(ab,
+ "invalid offset on mon stats destination %u\n",
+ end_offset);
+ skb_put(skb, DP_RX_BUFFER_SIZE);
+ }
+
+ __skb_queue_tail(&skb_list, skb);
+
+move_next:
+ ath12k_dp_mon_buf_replenish(ab, buf_ring, 1);
+ ath12k_hal_srng_dst_get_next_entry(ab, srng);
+ num_buffs_reaped++;
+ }
+
+ ath12k_hal_srng_access_end(ab, srng);
+ spin_unlock_bh(&srng->lock);
+
+ if (!num_buffs_reaped)
+ return 0;
+
+ /* In some cases, one PPDU worth of data can be spread across multiple NAPI
+ * schedules, To avoid losing existing parsed ppdu_info information, skip
+ * the memset of the ppdu_info structure and continue processing it.
+ */
+ if (!ppdu_info->ppdu_continuation)
+ ath12k_dp_mon_rx_memset_ppdu_info(ppdu_info);
+
+ while ((skb = __skb_dequeue(&skb_list))) {
+ hal_status = ath12k_dp_mon_rx_parse_mon_status(pdev_dp, pmon, skb, napi);
+ if (hal_status != HAL_RX_MON_STATUS_PPDU_DONE) {
+ ppdu_info->ppdu_continuation = true;
+ dev_kfree_skb_any(skb);
+ continue;
+ }
+
+ if (ppdu_info->peer_id == HAL_INVALID_PEERID)
+ goto free_skb;
+
+ rcu_read_lock();
+ peer = ath12k_dp_link_peer_find_by_peerid(pdev_dp, ppdu_info->peer_id);
+ if (!peer || !peer->sta) {
+ ath12k_dbg(ab, ATH12K_DBG_DATA,
+ "failed to find the peer with monitor peer_id %d\n",
+ ppdu_info->peer_id);
+ goto next_skb;
+ }
+
+ if (ppdu_info->reception_type == HAL_RX_RECEPTION_TYPE_SU) {
+ ath12k_dp_mon_rx_update_peer_su_stats(peer, ppdu_info);
+ } else if ((ppdu_info->fc_valid) &&
+ (ppdu_info->ast_index != HAL_AST_IDX_INVALID)) {
+ ath12k_dp_mon_rx_process_ulofdma(ppdu_info);
+ ath12k_dp_mon_rx_update_peer_mu_stats(ab, ppdu_info);
+ }
+
+next_skb:
+ rcu_read_unlock();
+free_skb:
+ dev_kfree_skb_any(skb);
+ ath12k_dp_mon_rx_memset_ppdu_info(ppdu_info);
+ }
+
+ return num_buffs_reaped;
+}
+
+int ath12k_wifi7_dp_mon_process_ring(struct ath12k_dp *dp, int mac_id,
+ struct napi_struct *napi, int budget,
+ enum dp_monitor_mode monitor_mode)
+{
+ u8 pdev_idx = ath12k_hw_mac_id_to_pdev_id(dp->hw_params, mac_id);
+ struct ath12k_pdev_dp *dp_pdev;
+ struct ath12k *ar;
+ int num_buffs_reaped = 0;
+
+ rcu_read_lock();
+
+ dp_pdev = ath12k_dp_to_pdev_dp(dp, pdev_idx);
+ if (!dp_pdev) {
+ rcu_read_unlock();
+ return 0;
+ }
+
+ if (dp->hw_params->rxdma1_enable) {
+ if (monitor_mode == ATH12K_DP_RX_MONITOR_MODE)
+ num_buffs_reaped = ath12k_wifi7_dp_mon_srng_process(dp_pdev,
+ &budget,
+ napi);
+ } else {
+ ar = ath12k_pdev_dp_to_ar(dp_pdev);
+
+ if (ar->monitor_started)
+ num_buffs_reaped =
+ __ath12k_wifi7_dp_mon_process_ring(ar, mac_id, napi,
+ &budget);
+ }
+
+ rcu_read_unlock();
+
+ return num_buffs_reaped;
+}
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.h b/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.h
new file mode 100644
index 000000000000..3cf82864c41c
--- /dev/null
+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef ATH12K_DP_MON_WIFI7_H
+#define ATH12K_DP_MON_WIFI7_H
+
+#include "hw.h"
+
+enum dp_monitor_mode;
+
+int ath12k_wifi7_dp_mon_process_ring(struct ath12k_dp *dp, int mac_id,
+ struct napi_struct *napi, int budget,
+ enum dp_monitor_mode monitor_mode);
+#endif
--
2.34.1
More information about the ath12k
mailing list