]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: ath12k: Move monitor ring processing to Wi-Fi 7 module
authorAlok Singh <quic_aloksing@quicinc.com>
Mon, 10 Nov 2025 10:37:02 +0000 (16:07 +0530)
committerJeff Johnson <jeff.johnson@oss.qualcomm.com>
Tue, 11 Nov 2025 15:21:32 +0000 (07:21 -0800)
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@quicinc.com>
Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Link: https://patch.msgid.link/20251110103713.3484779-2-quic_aloksing@quicinc.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
drivers/net/wireless/ath/ath12k/dp_mon.c
drivers/net/wireless/ath/ath12k/dp_mon.h
drivers/net/wireless/ath/ath12k/wifi7/Makefile
drivers/net/wireless/ath/ath12k/wifi7/dp.c
drivers/net/wireless/ath/ath12k/wifi7/dp.h
drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c [new file with mode: 0644]
drivers/net/wireless/ath/ath12k/wifi7/dp_mon.h [new file with mode: 0644]

index 0533d8bf9c1ce30ca9d1bb9aaabf7c475efa2b10..5e2bf24d6b7ee2fcdcbf78de59ca23d88e38bc19 100644 (file)
@@ -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 @@ fail_alloc_skb:
        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 @@ move_next:
 
        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 @@ next_msdu:
  */
 #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);
index 3e6ff4b0a6d9e17bb37c0ce804540d780ae85a1c..689d7a0fff5c13cef789597240f91e10c0477786 100644 (file)
@@ -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
index 30258a1b313de2ee9b608e01772b4a7eeec7aee0..dcfa732bb95bcb52b8fe3453aa84758deb6b0f47 100644 (file)
@@ -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
index 30c27e005ed8f1bfcf2e7812539b565970061c38..0b2c7f37c7566f010381a0343e59275d19a9a5af 100644 (file)
@@ -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;
 
index 72fdfb368c994ebe605473aec3914eacc3fa7611..a5f0941d34e2f9f467d81b7765eb4d2205dd211b 100644 (file)
@@ -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 (file)
index 0000000..4135ff5
--- /dev/null
@@ -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 (file)
index 0000000..3cf8286
--- /dev/null
@@ -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